-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix decimal #2323
Fix decimal #2323
Conversation
mypy crash reported as python/mypy#5347. |
Crash is now fixed in mypy master. |
Thanks! I restarted Travis, will take another look after it passes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Left a few comments.
stdlib/2and3/decimal.pyi
Outdated
_ComparableNum = Union[Decimal, int, float] | ||
_DecimalNew = Union[Decimal, int, float, Text, Tuple[int, Sequence[int], int]] | ||
if sys.version_info >= (3,): | ||
_ComparableNum = Union[Decimal, numbers.Rational, float] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This conditional definition makes it look confusingly like int
is not supported in Python 3. In fact, it is redundant in Python 2 too, because it's automatically promoted to float
. It would be clearer to have int
either in both or in neither of the branches.
stdlib/2and3/decimal.pyi
Outdated
def __delattr__(self, name): ... | ||
def __reduce__(self): ... | ||
def clear_flags(self): ... | ||
def __setattr__(self, name: str, value: Any) -> Any: ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should actually be omitted because the effect of having it is that the type checker will think setting any attribute is allowed. However, the implementation actually only allows the attributes that are known to exist on the class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I replaced it with a comment saying so, for future reference.
stdlib/2and3/decimal.pyi
Outdated
def is_canonical(self, a: _Decimal) -> Decimal: ... | ||
def is_finite(self, a: _Decimal) -> Decimal: ... | ||
def is_infinite(self, a: _Decimal) -> Decimal: ... | ||
def is_nan(self, a: _Decimal) -> Decimal: ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of these return bool
, although I haven't checked all of those. I'm guessing divmod
returns a Tuple[Decimal, Decimal]
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. I am rechecking the return values of all Context
methods.
I am not sure why the travis build does not start automatically after the latest patches. |
I closed and reopened, and now Travis seems to be running. |
I wonder if this broke something. I've got code that's essentially (though not quite)
(Though that example doesn't provoke it.) The if/else expression's type is revealed as object, and I kind of suspect #2323, since |
I think it's reasonable to assume that this change triggered the problem, although I suspect a bug in mypy. Since SupportsAbs and SupportsFloat are protocols, they should not be needed as base classes. The following test cast demonstrates the problem: from typing import SupportsFloat
class Floaty:
def __float__(self): ...
class Supporter(SupportsFloat):
def __float__(self): ...
reveal_type(Floaty() if bool() else 0)
reveal_type(Supporter() if bool() else 0) The former is revealed as |
@srittau Mypy works like by design, though it's clearly suboptimal in this case. It's not clear how this should be fixed in mypy. It's easy to imagine how this could work in simple cases, but a general solution seems difficult to define -- so that it's both practical and has the desired theoretical properties. Luckily the problems seem to arise pretty infrequently, and they can often be worked around by adding an explicit protocol base class. Can we add the base classes back? We should probably add a comment explaining why they are there so that they won't be removed again in the future. If you want to propose a mypy fix, I'm happy to discuss it. I've looked into this a bit but gave up as it didn't seem worth the effort at the time. |
The problem I have with that is that it basically makes protocols useless, because the |
This is the first time I've seen this cause problems, so it's a bit unfair to say that it makes protocols basically useless. I proposed a potential mypy improvement in python/mypy#5392 (comment), which could partially address the issue. |
Well, useless in the sense that whenever someone comes up with a case where a protocol is used in an But just implementing the suggestion from typing/issues#564 would likely make this problem more pronounced. |
* Use Tuple field in DecimalTuple * Remove unnecessary base classes from Decimal * Decimal.__init__ -> __new__ * Decimal.__ne__ is not defined in Python 3 * Add Decimal.as_integer_ratio() * Annotate DecimalException.handle() * Correct types of Decimal method arguments * Add missing arguments and optional markers to Decimal * Add missing arguments to Context * Remove spurious int from Unions with float * Remove Context.__setattr__() * Fix return types of Context methods
Fix various problems with decimal and add missing annotations.