ARROW-2145/ARROW-2157: [Python] Decimal conversion not working for NaN values - #1610

Closed
cpcloud wants to merge 3 commits into
apache:masterfrom
cpcloud:ARROW-2157
Closed

ARROW-2145/ARROW-2157: [Python] Decimal conversion not working for NaN values#1610
cpcloud wants to merge 3 commits into
apache:masterfrom
cpcloud:ARROW-2157

Conversation

@cpcloud

Copy link
Copy Markdown
Contributor

No description provided.

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

Restarted the travis jobs, they seemed to be failing during apt-get

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually required? You are only using the decimal type below.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be misunderstanding the use case for OwnedRefNoGIL.

My understanding is that if we're Py_XDECREFing something and we do not hold then GIL then we need to acquire it.

The GIL is released in Cython before the function that instantiates this class is called (and isn't subsequently acquired in that function). Assuming my understanding is correct then we need to acquire the GIL before calling Py_XDECREF on this.

Are you suggesting that because the order of destruction here is guaranteed to be the reverse of initialization order that we don't need to care that decimal_module_ holds the GIL because we'll never decref decimal_module_ before we decref decimal_type_?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean is that you don't care about keeping a reference to the decimal module if you only need to use the decimal type:

>>> D = __import__('decimal').Decimal
>>> sys.modules['decimal'] = None
>>> D(100)
Decimal('100')

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, awesome. There are a few places that we have unnecessary refs to the decimal module. I'll open a JIRA to clean those up (and remove this one). Thanks for the review.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work with Python Decimal nans, right? Try decimal.Decimal('nan').

Comment threadcpp/src/arrow/python/python-test.cc Outdated

@pitroupitrouFeb 15, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the policy for adding tests here rather than in pyarrow/tests? It seems writing tests in pure Python is generally easier :-)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's funny you mention that. I agree, but I wanted to be able to step through C++ code in the CLion IDE so I wrote the test here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me add Decimal('nan') to this list.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wesm@pitrou is there any reason we shouldn't make these static global variables, so we don't have to call these APIs all over the place and inside of loops?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it's fine to make it a static global (or a singleton, etc.), as long as we don't want to support subinterpreters perhaps.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way the nested block above doesn't seem needed.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, okay I'll refactor and make those static

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm so it appears that string interning of module names doesn't play well with C++ globals. I'll leave these as they are for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, you probably can't use OwnedRef here since the destructor would trigger too late. But you could have a PyObject*. The only downside is that it would make the object eternal.

Comment threadcpp/src/arrow/python/helpers.h Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the consts? I don't think it makes sense, and you're bound to do a lot of casts as soon as you call the Python C API.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note PyObject is non-const pretty much by construction, as it has a reference count that can be mutated by any operation.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I was following convention in the file. I can adjust.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been removing all the instances of const PyObject* after having a compiler warning from an internal Py-API, so happy to see them all go

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last argument can simply be the empty string AFAIR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should call PyDecimal_Checkbefore calling the method. Also you should check if the method raises. And it's better to use PyObject_IsTrue rather than compare against Py_True.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, not sure how I missed that :)

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

@pitrou any more comments here?

@pitroupitrou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments below. Also it seems that the AppVeyor build has failed, though it may be unrelated?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This member doesn't seem used actually. Were you planning to use it with PyObject_IsInstance instead of the costlier call to internal::PyDecimal_Check?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks. Will fix.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to add a comment motivating the algorithm here (why compare the absolute values but then memorize the original value)?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, reconsidering this based on your comment this really should be just the max scale. Negative scale should contribute to precision only if it would increase precision. The goal here is to "cast the widest net", ie the max precision and max scale. Negative scale complicates things a tiny bit. I'll add some commentary.

Comment threadcpp/src/arrow/python/common.h Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a C++ expert, so I'm curious why this is necessary?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constructors are not inherited by default. I'm not actually using this, so it should cost nothing at runtime. If we ever wanted to construct one of these with a pointer as it's first argument we'd have to define it anyway. I can remove it if you'd like.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem with me. I had forgotten about non-inheritance of constructors.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can PandasObjectIsNull return true on a Decimal instance?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I'll fix that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also check that the Arrow type was inferred correctly?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep will do.

@wesm

wesm commented Feb 21, 2018

Copy link
Copy Markdown
Member

needs rebase

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

Closed in favor of #1651

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@cpcloud@wesm@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

ARROW-2145/ARROW-2157: [Python] Decimal conversion not working for NaN values - #1610

Closed
cpcloud wants to merge 3 commits into
apache:masterfrom
cpcloud:ARROW-2157
Closed

ARROW-2145/ARROW-2157: [Python] Decimal conversion not working for NaN values#1610
cpcloud wants to merge 3 commits into
apache:masterfrom
cpcloud:ARROW-2157

Conversation

@cpcloud

Copy link
Copy Markdown
Contributor

No description provided.

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

Restarted the travis jobs, they seemed to be failing during apt-get

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually required? You are only using the decimal type below.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be misunderstanding the use case for OwnedRefNoGIL.

My understanding is that if we're Py_XDECREFing something and we do not hold then GIL then we need to acquire it.

The GIL is released in Cython before the function that instantiates this class is called (and isn't subsequently acquired in that function). Assuming my understanding is correct then we need to acquire the GIL before calling Py_XDECREF on this.

Are you suggesting that because the order of destruction here is guaranteed to be the reverse of initialization order that we don't need to care that decimal_module_ holds the GIL because we'll never decref decimal_module_ before we decref decimal_type_?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean is that you don't care about keeping a reference to the decimal module if you only need to use the decimal type:

>>> D = __import__('decimal').Decimal
>>> sys.modules['decimal'] = None
>>> D(100)
Decimal('100')

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, awesome. There are a few places that we have unnecessary refs to the decimal module. I'll open a JIRA to clean those up (and remove this one). Thanks for the review.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work with Python Decimal nans, right? Try decimal.Decimal('nan').

Comment threadcpp/src/arrow/python/python-test.cc Outdated

@pitroupitrouFeb 15, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the policy for adding tests here rather than in pyarrow/tests? It seems writing tests in pure Python is generally easier :-)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's funny you mention that. I agree, but I wanted to be able to step through C++ code in the CLion IDE so I wrote the test here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me add Decimal('nan') to this list.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wesm@pitrou is there any reason we shouldn't make these static global variables, so we don't have to call these APIs all over the place and inside of loops?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it's fine to make it a static global (or a singleton, etc.), as long as we don't want to support subinterpreters perhaps.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way the nested block above doesn't seem needed.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, okay I'll refactor and make those static

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm so it appears that string interning of module names doesn't play well with C++ globals. I'll leave these as they are for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, you probably can't use OwnedRef here since the destructor would trigger too late. But you could have a PyObject*. The only downside is that it would make the object eternal.

Comment threadcpp/src/arrow/python/helpers.h Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the consts? I don't think it makes sense, and you're bound to do a lot of casts as soon as you call the Python C API.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note PyObject is non-const pretty much by construction, as it has a reference count that can be mutated by any operation.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I was following convention in the file. I can adjust.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been removing all the instances of const PyObject* after having a compiler warning from an internal Py-API, so happy to see them all go

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last argument can simply be the empty string AFAIR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should call PyDecimal_Checkbefore calling the method. Also you should check if the method raises. And it's better to use PyObject_IsTrue rather than compare against Py_True.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, not sure how I missed that :)

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

@pitrou any more comments here?

@pitroupitrou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments below. Also it seems that the AppVeyor build has failed, though it may be unrelated?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This member doesn't seem used actually. Were you planning to use it with PyObject_IsInstance instead of the costlier call to internal::PyDecimal_Check?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks. Will fix.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to add a comment motivating the algorithm here (why compare the absolute values but then memorize the original value)?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, reconsidering this based on your comment this really should be just the max scale. Negative scale should contribute to precision only if it would increase precision. The goal here is to "cast the widest net", ie the max precision and max scale. Negative scale complicates things a tiny bit. I'll add some commentary.

Comment threadcpp/src/arrow/python/common.h Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a C++ expert, so I'm curious why this is necessary?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constructors are not inherited by default. I'm not actually using this, so it should cost nothing at runtime. If we ever wanted to construct one of these with a pointer as it's first argument we'd have to define it anyway. I can remove it if you'd like.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem with me. I had forgotten about non-inheritance of constructors.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can PandasObjectIsNull return true on a Decimal instance?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I'll fix that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also check that the Arrow type was inferred correctly?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep will do.

@wesm

wesm commented Feb 21, 2018

Copy link
Copy Markdown
Member

needs rebase

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

Closed in favor of #1651

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@cpcloud@wesm@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ARROW-2145/ARROW-2157: [Python] Decimal conversion not working for NaN values - #1610

Closed
cpcloud wants to merge 3 commits into
apache:masterfrom
cpcloud:ARROW-2157
Closed

ARROW-2145/ARROW-2157: [Python] Decimal conversion not working for NaN values#1610
cpcloud wants to merge 3 commits into
apache:masterfrom
cpcloud:ARROW-2157

Conversation

@cpcloud

Copy link
Copy Markdown
Contributor

No description provided.

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

Restarted the travis jobs, they seemed to be failing during apt-get

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually required? You are only using the decimal type below.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be misunderstanding the use case for OwnedRefNoGIL.

My understanding is that if we're Py_XDECREFing something and we do not hold then GIL then we need to acquire it.

The GIL is released in Cython before the function that instantiates this class is called (and isn't subsequently acquired in that function). Assuming my understanding is correct then we need to acquire the GIL before calling Py_XDECREF on this.

Are you suggesting that because the order of destruction here is guaranteed to be the reverse of initialization order that we don't need to care that decimal_module_ holds the GIL because we'll never decref decimal_module_ before we decref decimal_type_?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean is that you don't care about keeping a reference to the decimal module if you only need to use the decimal type:

>>> D = __import__('decimal').Decimal
>>> sys.modules['decimal'] = None
>>> D(100)
Decimal('100')

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, awesome. There are a few places that we have unnecessary refs to the decimal module. I'll open a JIRA to clean those up (and remove this one). Thanks for the review.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work with Python Decimal nans, right? Try decimal.Decimal('nan').

Comment threadcpp/src/arrow/python/python-test.cc Outdated

@pitroupitrouFeb 15, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the policy for adding tests here rather than in pyarrow/tests? It seems writing tests in pure Python is generally easier :-)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's funny you mention that. I agree, but I wanted to be able to step through C++ code in the CLion IDE so I wrote the test here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me add Decimal('nan') to this list.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wesm@pitrou is there any reason we shouldn't make these static global variables, so we don't have to call these APIs all over the place and inside of loops?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it's fine to make it a static global (or a singleton, etc.), as long as we don't want to support subinterpreters perhaps.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way the nested block above doesn't seem needed.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, okay I'll refactor and make those static

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm so it appears that string interning of module names doesn't play well with C++ globals. I'll leave these as they are for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, you probably can't use OwnedRef here since the destructor would trigger too late. But you could have a PyObject*. The only downside is that it would make the object eternal.

Comment threadcpp/src/arrow/python/helpers.h Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the consts? I don't think it makes sense, and you're bound to do a lot of casts as soon as you call the Python C API.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note PyObject is non-const pretty much by construction, as it has a reference count that can be mutated by any operation.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I was following convention in the file. I can adjust.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been removing all the instances of const PyObject* after having a compiler warning from an internal Py-API, so happy to see them all go

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last argument can simply be the empty string AFAIR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should call PyDecimal_Checkbefore calling the method. Also you should check if the method raises. And it's better to use PyObject_IsTrue rather than compare against Py_True.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, not sure how I missed that :)

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

@pitrou any more comments here?

@pitroupitrou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments below. Also it seems that the AppVeyor build has failed, though it may be unrelated?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This member doesn't seem used actually. Were you planning to use it with PyObject_IsInstance instead of the costlier call to internal::PyDecimal_Check?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks. Will fix.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to add a comment motivating the algorithm here (why compare the absolute values but then memorize the original value)?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, reconsidering this based on your comment this really should be just the max scale. Negative scale should contribute to precision only if it would increase precision. The goal here is to "cast the widest net", ie the max precision and max scale. Negative scale complicates things a tiny bit. I'll add some commentary.

Comment threadcpp/src/arrow/python/common.h Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a C++ expert, so I'm curious why this is necessary?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constructors are not inherited by default. I'm not actually using this, so it should cost nothing at runtime. If we ever wanted to construct one of these with a pointer as it's first argument we'd have to define it anyway. I can remove it if you'd like.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem with me. I had forgotten about non-inheritance of constructors.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can PandasObjectIsNull return true on a Decimal instance?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I'll fix that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also check that the Arrow type was inferred correctly?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep will do.

@wesm

wesm commented Feb 21, 2018

Copy link
Copy Markdown
Member

needs rebase

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

Closed in favor of #1651

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@cpcloud@wesm@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ARROW-2145/ARROW-2157: [Python] Decimal conversion not working for NaN values - #1610

Closed
cpcloud wants to merge 3 commits into
apache:masterfrom
cpcloud:ARROW-2157
Closed

ARROW-2145/ARROW-2157: [Python] Decimal conversion not working for NaN values#1610
cpcloud wants to merge 3 commits into
apache:masterfrom
cpcloud:ARROW-2157

Conversation

@cpcloud

Copy link
Copy Markdown
Contributor

No description provided.

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

Restarted the travis jobs, they seemed to be failing during apt-get

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually required? You are only using the decimal type below.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be misunderstanding the use case for OwnedRefNoGIL.

My understanding is that if we're Py_XDECREFing something and we do not hold then GIL then we need to acquire it.

The GIL is released in Cython before the function that instantiates this class is called (and isn't subsequently acquired in that function). Assuming my understanding is correct then we need to acquire the GIL before calling Py_XDECREF on this.

Are you suggesting that because the order of destruction here is guaranteed to be the reverse of initialization order that we don't need to care that decimal_module_ holds the GIL because we'll never decref decimal_module_ before we decref decimal_type_?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean is that you don't care about keeping a reference to the decimal module if you only need to use the decimal type:

>>> D = __import__('decimal').Decimal
>>> sys.modules['decimal'] = None
>>> D(100)
Decimal('100')

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, awesome. There are a few places that we have unnecessary refs to the decimal module. I'll open a JIRA to clean those up (and remove this one). Thanks for the review.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work with Python Decimal nans, right? Try decimal.Decimal('nan').

Comment threadcpp/src/arrow/python/python-test.cc Outdated

@pitroupitrouFeb 15, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the policy for adding tests here rather than in pyarrow/tests? It seems writing tests in pure Python is generally easier :-)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's funny you mention that. I agree, but I wanted to be able to step through C++ code in the CLion IDE so I wrote the test here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me add Decimal('nan') to this list.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wesm@pitrou is there any reason we shouldn't make these static global variables, so we don't have to call these APIs all over the place and inside of loops?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it's fine to make it a static global (or a singleton, etc.), as long as we don't want to support subinterpreters perhaps.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way the nested block above doesn't seem needed.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, okay I'll refactor and make those static

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm so it appears that string interning of module names doesn't play well with C++ globals. I'll leave these as they are for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, you probably can't use OwnedRef here since the destructor would trigger too late. But you could have a PyObject*. The only downside is that it would make the object eternal.

Comment threadcpp/src/arrow/python/helpers.h Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the consts? I don't think it makes sense, and you're bound to do a lot of casts as soon as you call the Python C API.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note PyObject is non-const pretty much by construction, as it has a reference count that can be mutated by any operation.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I was following convention in the file. I can adjust.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been removing all the instances of const PyObject* after having a compiler warning from an internal Py-API, so happy to see them all go

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last argument can simply be the empty string AFAIR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should call PyDecimal_Checkbefore calling the method. Also you should check if the method raises. And it's better to use PyObject_IsTrue rather than compare against Py_True.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, not sure how I missed that :)

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

@pitrou any more comments here?

@pitroupitrou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments below. Also it seems that the AppVeyor build has failed, though it may be unrelated?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This member doesn't seem used actually. Were you planning to use it with PyObject_IsInstance instead of the costlier call to internal::PyDecimal_Check?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks. Will fix.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to add a comment motivating the algorithm here (why compare the absolute values but then memorize the original value)?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, reconsidering this based on your comment this really should be just the max scale. Negative scale should contribute to precision only if it would increase precision. The goal here is to "cast the widest net", ie the max precision and max scale. Negative scale complicates things a tiny bit. I'll add some commentary.

Comment threadcpp/src/arrow/python/common.h Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a C++ expert, so I'm curious why this is necessary?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constructors are not inherited by default. I'm not actually using this, so it should cost nothing at runtime. If we ever wanted to construct one of these with a pointer as it's first argument we'd have to define it anyway. I can remove it if you'd like.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem with me. I had forgotten about non-inheritance of constructors.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can PandasObjectIsNull return true on a Decimal instance?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I'll fix that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also check that the Arrow type was inferred correctly?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep will do.

@wesm

wesm commented Feb 21, 2018

Copy link
Copy Markdown
Member

needs rebase

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

Closed in favor of #1651

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@cpcloud@wesm@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

ARROW-2145/ARROW-2157: [Python] Decimal conversion not working for NaN values - #1610

Closed
cpcloud wants to merge 3 commits into
apache:masterfrom
cpcloud:ARROW-2157
Closed

ARROW-2145/ARROW-2157: [Python] Decimal conversion not working for NaN values#1610
cpcloud wants to merge 3 commits into
apache:masterfrom
cpcloud:ARROW-2157

Conversation

@cpcloud

Copy link
Copy Markdown
Contributor

No description provided.

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

Restarted the travis jobs, they seemed to be failing during apt-get

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually required? You are only using the decimal type below.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be misunderstanding the use case for OwnedRefNoGIL.

My understanding is that if we're Py_XDECREFing something and we do not hold then GIL then we need to acquire it.

The GIL is released in Cython before the function that instantiates this class is called (and isn't subsequently acquired in that function). Assuming my understanding is correct then we need to acquire the GIL before calling Py_XDECREF on this.

Are you suggesting that because the order of destruction here is guaranteed to be the reverse of initialization order that we don't need to care that decimal_module_ holds the GIL because we'll never decref decimal_module_ before we decref decimal_type_?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean is that you don't care about keeping a reference to the decimal module if you only need to use the decimal type:

>>> D = __import__('decimal').Decimal
>>> sys.modules['decimal'] = None
>>> D(100)
Decimal('100')

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, awesome. There are a few places that we have unnecessary refs to the decimal module. I'll open a JIRA to clean those up (and remove this one). Thanks for the review.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work with Python Decimal nans, right? Try decimal.Decimal('nan').

Comment threadcpp/src/arrow/python/python-test.cc Outdated

@pitroupitrouFeb 15, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the policy for adding tests here rather than in pyarrow/tests? It seems writing tests in pure Python is generally easier :-)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's funny you mention that. I agree, but I wanted to be able to step through C++ code in the CLion IDE so I wrote the test here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me add Decimal('nan') to this list.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wesm@pitrou is there any reason we shouldn't make these static global variables, so we don't have to call these APIs all over the place and inside of loops?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it's fine to make it a static global (or a singleton, etc.), as long as we don't want to support subinterpreters perhaps.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way the nested block above doesn't seem needed.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, okay I'll refactor and make those static

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm so it appears that string interning of module names doesn't play well with C++ globals. I'll leave these as they are for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, you probably can't use OwnedRef here since the destructor would trigger too late. But you could have a PyObject*. The only downside is that it would make the object eternal.

Comment threadcpp/src/arrow/python/helpers.h Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the consts? I don't think it makes sense, and you're bound to do a lot of casts as soon as you call the Python C API.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note PyObject is non-const pretty much by construction, as it has a reference count that can be mutated by any operation.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I was following convention in the file. I can adjust.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been removing all the instances of const PyObject* after having a compiler warning from an internal Py-API, so happy to see them all go

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last argument can simply be the empty string AFAIR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should call PyDecimal_Checkbefore calling the method. Also you should check if the method raises. And it's better to use PyObject_IsTrue rather than compare against Py_True.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, not sure how I missed that :)

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

@pitrou any more comments here?

@pitroupitrou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments below. Also it seems that the AppVeyor build has failed, though it may be unrelated?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This member doesn't seem used actually. Were you planning to use it with PyObject_IsInstance instead of the costlier call to internal::PyDecimal_Check?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks. Will fix.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to add a comment motivating the algorithm here (why compare the absolute values but then memorize the original value)?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, reconsidering this based on your comment this really should be just the max scale. Negative scale should contribute to precision only if it would increase precision. The goal here is to "cast the widest net", ie the max precision and max scale. Negative scale complicates things a tiny bit. I'll add some commentary.

Comment threadcpp/src/arrow/python/common.h Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a C++ expert, so I'm curious why this is necessary?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constructors are not inherited by default. I'm not actually using this, so it should cost nothing at runtime. If we ever wanted to construct one of these with a pointer as it's first argument we'd have to define it anyway. I can remove it if you'd like.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem with me. I had forgotten about non-inheritance of constructors.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can PandasObjectIsNull return true on a Decimal instance?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I'll fix that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also check that the Arrow type was inferred correctly?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep will do.

@wesm

wesm commented Feb 21, 2018

Copy link
Copy Markdown
Member

needs rebase

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

Closed in favor of #1651

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@cpcloud@wesm@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ARROW-2145/ARROW-2157: [Python] Decimal conversion not working for NaN values - #1610

Closed
cpcloud wants to merge 3 commits into
apache:masterfrom
cpcloud:ARROW-2157
Closed

ARROW-2145/ARROW-2157: [Python] Decimal conversion not working for NaN values#1610
cpcloud wants to merge 3 commits into
apache:masterfrom
cpcloud:ARROW-2157

Conversation

@cpcloud

Copy link
Copy Markdown
Contributor

No description provided.

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

Restarted the travis jobs, they seemed to be failing during apt-get

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually required? You are only using the decimal type below.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be misunderstanding the use case for OwnedRefNoGIL.

My understanding is that if we're Py_XDECREFing something and we do not hold then GIL then we need to acquire it.

The GIL is released in Cython before the function that instantiates this class is called (and isn't subsequently acquired in that function). Assuming my understanding is correct then we need to acquire the GIL before calling Py_XDECREF on this.

Are you suggesting that because the order of destruction here is guaranteed to be the reverse of initialization order that we don't need to care that decimal_module_ holds the GIL because we'll never decref decimal_module_ before we decref decimal_type_?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean is that you don't care about keeping a reference to the decimal module if you only need to use the decimal type:

>>> D = __import__('decimal').Decimal
>>> sys.modules['decimal'] = None
>>> D(100)
Decimal('100')

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, awesome. There are a few places that we have unnecessary refs to the decimal module. I'll open a JIRA to clean those up (and remove this one). Thanks for the review.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work with Python Decimal nans, right? Try decimal.Decimal('nan').

Comment threadcpp/src/arrow/python/python-test.cc Outdated

@pitroupitrouFeb 15, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the policy for adding tests here rather than in pyarrow/tests? It seems writing tests in pure Python is generally easier :-)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's funny you mention that. I agree, but I wanted to be able to step through C++ code in the CLion IDE so I wrote the test here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me add Decimal('nan') to this list.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wesm@pitrou is there any reason we shouldn't make these static global variables, so we don't have to call these APIs all over the place and inside of loops?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it's fine to make it a static global (or a singleton, etc.), as long as we don't want to support subinterpreters perhaps.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way the nested block above doesn't seem needed.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, okay I'll refactor and make those static

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm so it appears that string interning of module names doesn't play well with C++ globals. I'll leave these as they are for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, you probably can't use OwnedRef here since the destructor would trigger too late. But you could have a PyObject*. The only downside is that it would make the object eternal.

Comment threadcpp/src/arrow/python/helpers.h Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the consts? I don't think it makes sense, and you're bound to do a lot of casts as soon as you call the Python C API.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note PyObject is non-const pretty much by construction, as it has a reference count that can be mutated by any operation.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I was following convention in the file. I can adjust.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been removing all the instances of const PyObject* after having a compiler warning from an internal Py-API, so happy to see them all go

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last argument can simply be the empty string AFAIR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should call PyDecimal_Checkbefore calling the method. Also you should check if the method raises. And it's better to use PyObject_IsTrue rather than compare against Py_True.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, not sure how I missed that :)

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

@pitrou any more comments here?

@pitroupitrou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments below. Also it seems that the AppVeyor build has failed, though it may be unrelated?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This member doesn't seem used actually. Were you planning to use it with PyObject_IsInstance instead of the costlier call to internal::PyDecimal_Check?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks. Will fix.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to add a comment motivating the algorithm here (why compare the absolute values but then memorize the original value)?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, reconsidering this based on your comment this really should be just the max scale. Negative scale should contribute to precision only if it would increase precision. The goal here is to "cast the widest net", ie the max precision and max scale. Negative scale complicates things a tiny bit. I'll add some commentary.

Comment threadcpp/src/arrow/python/common.h Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a C++ expert, so I'm curious why this is necessary?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constructors are not inherited by default. I'm not actually using this, so it should cost nothing at runtime. If we ever wanted to construct one of these with a pointer as it's first argument we'd have to define it anyway. I can remove it if you'd like.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem with me. I had forgotten about non-inheritance of constructors.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can PandasObjectIsNull return true on a Decimal instance?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I'll fix that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also check that the Arrow type was inferred correctly?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep will do.

@wesm

wesm commented Feb 21, 2018

Copy link
Copy Markdown
Member

needs rebase

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

Closed in favor of #1651

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@cpcloud@wesm@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ARROW-2145/ARROW-2157: [Python] Decimal conversion not working for NaN values - #1610

Closed
cpcloud wants to merge 3 commits into
apache:masterfrom
cpcloud:ARROW-2157
Closed

ARROW-2145/ARROW-2157: [Python] Decimal conversion not working for NaN values#1610
cpcloud wants to merge 3 commits into
apache:masterfrom
cpcloud:ARROW-2157

Conversation

@cpcloud

Copy link
Copy Markdown
Contributor

No description provided.

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

Restarted the travis jobs, they seemed to be failing during apt-get

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually required? You are only using the decimal type below.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be misunderstanding the use case for OwnedRefNoGIL.

My understanding is that if we're Py_XDECREFing something and we do not hold then GIL then we need to acquire it.

The GIL is released in Cython before the function that instantiates this class is called (and isn't subsequently acquired in that function). Assuming my understanding is correct then we need to acquire the GIL before calling Py_XDECREF on this.

Are you suggesting that because the order of destruction here is guaranteed to be the reverse of initialization order that we don't need to care that decimal_module_ holds the GIL because we'll never decref decimal_module_ before we decref decimal_type_?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean is that you don't care about keeping a reference to the decimal module if you only need to use the decimal type:

>>> D = __import__('decimal').Decimal
>>> sys.modules['decimal'] = None
>>> D(100)
Decimal('100')

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, awesome. There are a few places that we have unnecessary refs to the decimal module. I'll open a JIRA to clean those up (and remove this one). Thanks for the review.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work with Python Decimal nans, right? Try decimal.Decimal('nan').

Comment threadcpp/src/arrow/python/python-test.cc Outdated

@pitroupitrouFeb 15, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the policy for adding tests here rather than in pyarrow/tests? It seems writing tests in pure Python is generally easier :-)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's funny you mention that. I agree, but I wanted to be able to step through C++ code in the CLion IDE so I wrote the test here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me add Decimal('nan') to this list.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wesm@pitrou is there any reason we shouldn't make these static global variables, so we don't have to call these APIs all over the place and inside of loops?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it's fine to make it a static global (or a singleton, etc.), as long as we don't want to support subinterpreters perhaps.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way the nested block above doesn't seem needed.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, okay I'll refactor and make those static

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm so it appears that string interning of module names doesn't play well with C++ globals. I'll leave these as they are for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, you probably can't use OwnedRef here since the destructor would trigger too late. But you could have a PyObject*. The only downside is that it would make the object eternal.

Comment threadcpp/src/arrow/python/helpers.h Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the consts? I don't think it makes sense, and you're bound to do a lot of casts as soon as you call the Python C API.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note PyObject is non-const pretty much by construction, as it has a reference count that can be mutated by any operation.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I was following convention in the file. I can adjust.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been removing all the instances of const PyObject* after having a compiler warning from an internal Py-API, so happy to see them all go

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last argument can simply be the empty string AFAIR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should call PyDecimal_Checkbefore calling the method. Also you should check if the method raises. And it's better to use PyObject_IsTrue rather than compare against Py_True.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, not sure how I missed that :)

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

@pitrou any more comments here?

@pitroupitrou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments below. Also it seems that the AppVeyor build has failed, though it may be unrelated?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This member doesn't seem used actually. Were you planning to use it with PyObject_IsInstance instead of the costlier call to internal::PyDecimal_Check?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks. Will fix.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to add a comment motivating the algorithm here (why compare the absolute values but then memorize the original value)?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, reconsidering this based on your comment this really should be just the max scale. Negative scale should contribute to precision only if it would increase precision. The goal here is to "cast the widest net", ie the max precision and max scale. Negative scale complicates things a tiny bit. I'll add some commentary.

Comment threadcpp/src/arrow/python/common.h Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a C++ expert, so I'm curious why this is necessary?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constructors are not inherited by default. I'm not actually using this, so it should cost nothing at runtime. If we ever wanted to construct one of these with a pointer as it's first argument we'd have to define it anyway. I can remove it if you'd like.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem with me. I had forgotten about non-inheritance of constructors.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can PandasObjectIsNull return true on a Decimal instance?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I'll fix that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also check that the Arrow type was inferred correctly?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep will do.

@wesm

wesm commented Feb 21, 2018

Copy link
Copy Markdown
Member

needs rebase

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

Closed in favor of #1651

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@cpcloud@wesm@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

ARROW-2145/ARROW-2157: [Python] Decimal conversion not working for NaN values - #1610

Closed
cpcloud wants to merge 3 commits into
apache:masterfrom
cpcloud:ARROW-2157
Closed

ARROW-2145/ARROW-2157: [Python] Decimal conversion not working for NaN values#1610
cpcloud wants to merge 3 commits into
apache:masterfrom
cpcloud:ARROW-2157

Conversation

@cpcloud

Copy link
Copy Markdown
Contributor

No description provided.

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

Restarted the travis jobs, they seemed to be failing during apt-get

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually required? You are only using the decimal type below.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be misunderstanding the use case for OwnedRefNoGIL.

My understanding is that if we're Py_XDECREFing something and we do not hold then GIL then we need to acquire it.

The GIL is released in Cython before the function that instantiates this class is called (and isn't subsequently acquired in that function). Assuming my understanding is correct then we need to acquire the GIL before calling Py_XDECREF on this.

Are you suggesting that because the order of destruction here is guaranteed to be the reverse of initialization order that we don't need to care that decimal_module_ holds the GIL because we'll never decref decimal_module_ before we decref decimal_type_?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean is that you don't care about keeping a reference to the decimal module if you only need to use the decimal type:

>>> D = __import__('decimal').Decimal
>>> sys.modules['decimal'] = None
>>> D(100)
Decimal('100')

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, awesome. There are a few places that we have unnecessary refs to the decimal module. I'll open a JIRA to clean those up (and remove this one). Thanks for the review.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work with Python Decimal nans, right? Try decimal.Decimal('nan').

Comment threadcpp/src/arrow/python/python-test.cc Outdated

@pitroupitrouFeb 15, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the policy for adding tests here rather than in pyarrow/tests? It seems writing tests in pure Python is generally easier :-)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's funny you mention that. I agree, but I wanted to be able to step through C++ code in the CLion IDE so I wrote the test here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me add Decimal('nan') to this list.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wesm@pitrou is there any reason we shouldn't make these static global variables, so we don't have to call these APIs all over the place and inside of loops?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it's fine to make it a static global (or a singleton, etc.), as long as we don't want to support subinterpreters perhaps.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way the nested block above doesn't seem needed.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, okay I'll refactor and make those static

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm so it appears that string interning of module names doesn't play well with C++ globals. I'll leave these as they are for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, you probably can't use OwnedRef here since the destructor would trigger too late. But you could have a PyObject*. The only downside is that it would make the object eternal.

Comment threadcpp/src/arrow/python/helpers.h Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the consts? I don't think it makes sense, and you're bound to do a lot of casts as soon as you call the Python C API.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note PyObject is non-const pretty much by construction, as it has a reference count that can be mutated by any operation.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I was following convention in the file. I can adjust.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been removing all the instances of const PyObject* after having a compiler warning from an internal Py-API, so happy to see them all go

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last argument can simply be the empty string AFAIR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool

Comment threadcpp/src/arrow/python/helpers.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should call PyDecimal_Checkbefore calling the method. Also you should check if the method raises. And it's better to use PyObject_IsTrue rather than compare against Py_True.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, not sure how I missed that :)

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

@pitrou any more comments here?

@pitroupitrou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments below. Also it seems that the AppVeyor build has failed, though it may be unrelated?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This member doesn't seem used actually. Were you planning to use it with PyObject_IsInstance instead of the costlier call to internal::PyDecimal_Check?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks. Will fix.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to add a comment motivating the algorithm here (why compare the absolute values but then memorize the original value)?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, reconsidering this based on your comment this really should be just the max scale. Negative scale should contribute to precision only if it would increase precision. The goal here is to "cast the widest net", ie the max precision and max scale. Negative scale complicates things a tiny bit. I'll add some commentary.

Comment threadcpp/src/arrow/python/common.h Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a C++ expert, so I'm curious why this is necessary?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constructors are not inherited by default. I'm not actually using this, so it should cost nothing at runtime. If we ever wanted to construct one of these with a pointer as it's first argument we'd have to define it anyway. I can remove it if you'd like.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem with me. I had forgotten about non-inheritance of constructors.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can PandasObjectIsNull return true on a Decimal instance?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I'll fix that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also check that the Arrow type was inferred correctly?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep will do.

@wesm

wesm commented Feb 21, 2018

Copy link
Copy Markdown
Member

needs rebase

@cpcloud

Copy link
Copy Markdown
ContributorAuthor

Closed in favor of #1651

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@cpcloud@wesm@pitrou