You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
mypy fails to narrow Union[float,int] to float after isinstance(x, float) #6060
fromtypingimportUniondefmaybe_convert_to_int(x: Union[float,int]) ->Union[float,int]:
'''Convert x from float to int if it can be done losslessly.'''ifisinstance(x, float):
# x must be a float here, so this is a legal operation, but# mypy still thinks its type is Union[float,int]assertisinstance(x, float)
ifx.is_integer():
x=int(x)
returnx
When I run mypy on it, I get:
$ mypy ~/temp/test_mypy.py
temp/test_mypy.py:8: error: Item "int" of "Union[float, int]" has no attribute "is_integer"
$ python --version
Python 3.7.1
$ mypy --version
mypy 0.650
I would expect this program to pass the type checker, since I am using isinstance to narrow the type to float before performing the float-specific operation float.is_integer. If I replace the assertion with x = float(x), that satisfies the type checker.
This is because some special-casing in mypy called "type promotions". The point is that int is not a subclass of float at runtime, but mypy considers int a subtype of float. Because of this, int sneaks into the if statement, where mypy complains about the missing method.
We try to ignore the type promotions while working with isinstance(), but it looks like there is a bug and type promotions are still used. Another possible workaround (apart from the one you mentioned) for you would be to just annotate the functions as (float) -> float. You can probably also change the logic to
I discovered a workaround that eliminated this code entirely for my specific use case. The reason for this code was to ensure that a float like 1.0 would print as an integer (with no decimal point), but I figured out that '{:g}'.format(x) does that without having to check the type of x.
However, I guess this is still a bug in the general case.
processed_corpus: Dict[str, Dict[str, Union[List[Dict[Any, Any]], float]]] = {}
# bunch of code removed
if sentence not in processed_corpus:
processed_corpus[sentence] = {"extra": extra}
# satisfying mypy due to Union in type hinting
elif sentence in processed_corpus and isinstance(processed_corpus[sentence]["extra"], list):
processed_corpus[sentence]["extra"].extend(extra)
Still getting a mypy error of
error: Item "float" of "Union[List[Dict[Any, Any]], float]" has no attribute "extend"
I can also reproduce this, or a similar issue having to do with statement reachability, both on mypy 0.740 and master (mypy 0.750+dev.e97377c454a1d5c019e9c56871d5f229db6b47b2)
Activity
ilevkivskyi commentedon Dec 12, 2018
This is because some special-casing in mypy called "type promotions". The point is that
intis not a subclass offloatat runtime, but mypy considersinta subtype offloat. Because of this,intsneaks into theifstatement, where mypy complains about the missing method.We try to ignore the type promotions while working with
isinstance(), but it looks like there is a bug and type promotions are still used. Another possible workaround (apart from the one you mentioned) for you would be to just annotate the functions as(float) -> float. You can probably also change the logic toilevkivskyi commentedon Dec 12, 2018
@Michael0x2a was among the last who worked with this code, so probably he has the most context.
DarwinAwardWinner commentedon Dec 12, 2018
I discovered a workaround that eliminated this code entirely for my specific use case. The reason for this code was to ensure that a float like
1.0would print as an integer (with no decimal point), but I figured out that'{:g}'.format(x)does that without having to check the type ofx.However, I guess this is still a bug in the general case.
Replace NumericType with float
Disable promotions in isinstance checks
Disable promotions in isinstance checks (#6114)
GregHilston commentedon Aug 26, 2019
I believe I'm still experiencing this issue:
Still getting a mypy error of
syastrov commentedon Nov 14, 2019
I can also reproduce this, or a similar issue having to do with statement reachability, both on mypy 0.740 and master (mypy 0.750+dev.e97377c454a1d5c019e9c56871d5f229db6b47b2)
Changing the order of the isinstance checks makes the error go away.
Ignore promotions when simplifying unions (#13781)