Description
I'm afraid I'm not sure whether I'm reporting a bug or requesting a feature. I'm happy to leave that up for you all to triage. I'll start with what I'm seeing and what I'd like to see, and then get a little bit into the why.
Here's a minimal reproduction:
from decimal import Decimal
from typing import Union
def check(x: Decimal, y: Union[Decimal, int]) -> bool:
return x < -abs(y)
With Python 3.7.3 (from Debian buster) and mypy 0.770 (from PyPI), checking this code returns an error:
deccomp.py:6: error: Unsupported operand type for unary - ("object") [operator]
Found 1 error in 1 file (checked 1 source file)
The return type of abs
is inferred as object, I think because that's the common supertype of int and Decimal. It would be nice if, one way or another, the return type of abs
could be inferred as some higher numeric type.
The context here is I'm working on accounting software where I want to be careful to do decimal math throughout. In other words, I never want to deal with the decimal.FloatOperation signal. For functions that do basic arithmetic or comparisons across numbers, it's fine to accept arguments that are either int or Decimal, and it's convenient for callers if I can annotate that argument type rather than requiring them to convert their integer arguments to Decimal all the time.
Activity
JelleZijlstra commentedon Mar 30, 2020
For context, the definition of
abs
in typeshed isConsidering the definition of
SupportsAbs
, this means thatabs
returns whatever the__abs__
method on its argument type returns.int.__abs__
is declared as returningint
in typeshed, andDecimal.__abs__
returnsDecimal
.I feel like mypy should be able to use these stubs to infer that
abs(Union[int, Decimal])
returnsUnion[int, Decimal]
, but the current type inference isn't up to the task. There are probably already some similar issues.msullivan commentedon Apr 3, 2020
Yeah, I agree that would probably be a better type in this case. But whether to infer a union type or a join is tricky and changing behavior will break code in places; not sure if this one has a fix that would be better.
Fix for your particular issue might be to write a wrapper with a better type.
brettcs commentedon Apr 8, 2020
I ended up just casting
y
toDecimal
at the top of the function. I thinky = Decimal(y)
should always work given these types, so the cast let me tell mypy that with less runtime overhead.jvdwetering commentedon Apr 21, 2020
I think the following is a related example:
This gives the error on the last line:
Incompatible return value type (got "Union[Any, float]", expected "Union[Fraction, int]")
EDIT: to be clear, there is supposed to be an error, but I feel mypy should infer the type
float
instead ofUnion[Any, float]
zormit commentedon May 3, 2021
It seems to me that python/typeshed#5275 is related too. There, @erictraut describes:
Are there any plans to fix this and change the way the constraint solver works?
PS: This is the first issue that I dug up trough the search that seems to be related and I am new to this project. As was said here, there are probably related issues. Feel free to refer me to a more relevant issue/feature if this has been discussed.
hauntsaninja commentedon May 3, 2021
#5392 and #9264 are related, I think
slafs commentedon Jun 28, 2023
Run into this bug today too.
This snippet:
produces:
using
mypy 1.4.1 (compiled: yes)
and Python 3.10.9.I've also read python/typeshed#5275 and it looks that this is fine with Pyright. Relevant quotes from that issue seem to be:
and