Skip to content
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

Funny behaviour with Union[Decimal, int] #1442

Closed
admirabilis opened this issue Apr 26, 2016 · 11 comments
Closed

Funny behaviour with Union[Decimal, int] #1442

admirabilis opened this issue Apr 26, 2016 · 11 comments
Labels
bug mypy got something wrong false-positive mypy gave an error on correct code priority-1-normal topic-union-types

Comments

@admirabilis
Copy link

Considering the following program:

from decimal import Decimal
from typing import Union

def foo(bar: Union[Decimal, int]):
    print(Decimal(1) + bar)
    print(bar + Decimal(1))

Why does mypy complain in the second print()?

$ mypy foo.py
foo.py: note: In function "foo":
foo.py:6: error: Unsupported operand types for + ("Union[Decimal, int]" and "Decimal")

I'm using mypy 0.3.1 on Python 3.5.1, Ubuntu 16.04.

@gvanrossum
Copy link
Member

I'm not sure. I can repro this with the latest mypy from the repo.

@refi64
Copy link
Contributor

refi64 commented Apr 26, 2016

@gvanrossum Is this a typeshed bug? Note that Decimal.__add__ is defined with rhs as _Decimal (or Union[Decimal, int]), but __radd__ expects just a normal int.

@gvanrossum
Copy link
Member

But I can't repro it without using a Union.

@refi64
Copy link
Contributor

refi64 commented Apr 26, 2016

@gvanrossum Exactly, because __radd__ expects just an int, not a union. Here's an example outside of Decimal:

from typing import Union

class Dec:
    def __add__(self, x: Union['Dec', int]) -> 'Dec': pass # This accepts another Dec.
    def __radd__(self, x: int) -> 'Dec': pass # But this does NOT!

def foo(bar: Union[Dec, int]):
    d = None # type: Dec
    print(d + bar)
    print(bar + d) # Error, since Dec.__radd__ wants `int` for its lhs, but `bar` is `Union[Dec, int]`

@gvanrossum
Copy link
Member

gvanrossum commented Apr 26, 2016 via email

@refi64
Copy link
Contributor

refi64 commented Apr 26, 2016

So then the general issue is binary operators, I guess. It seems Mypy sees this:

x + y # where x's type is Union[A,B], and y's type is C

and tries to look for either Union[A,B].__add__(C) or C.__radd__, but it should instead look for both A and B separately. So it would insteas check for one of the following:

  • A.__add__(C) and B.__add__(C)
  • C.__radd__(A) and C.__radd__(B)

This is mostly a guess, though...

@JukkaL
Copy link
Collaborator

JukkaL commented Apr 27, 2016

@kirbyfan64 I believe that you are right. The logic for checking binary operations should probably decompose union types early and process each union item independently (and finally combine the results, possibly resulting in another union type).

@gvanrossum
Copy link
Member

gvanrossum commented Apr 27, 2016 via email

@JukkaL
Copy link
Collaborator

JukkaL commented Apr 27, 2016

That may be relevant, but this may also be a separate issue/bug.

@JukkaL JukkaL added the bug mypy got something wrong label Apr 27, 2016
@gvanrossum gvanrossum added this to the 0.5 milestone Apr 28, 2016
mkurek pushed a commit to mkurek/typeshed that referenced this issue Dec 21, 2016
Improve operator methods for dateutil.relativedelta stubs:
* `__add__` operator method could return other types than `relativedelta` (`datetime.date` or `datetime.datetime`)
* use specific types of operators args instead of Any
* mypy currently does not handle `Union` in op methods (see python/mypy#2129, python/mypy#1442, python/mypy#1264 for details), so I've overloaded it directly
ambv pushed a commit to python/typeshed that referenced this issue Dec 28, 2016
Improve operator methods for dateutil.relativedelta stubs:
* `__add__` operator method could return other types than `relativedelta` (`datetime.date` or `datetime.datetime`)
* use specific types of operators args instead of Any
* mypy currently does not handle `Union` in op methods (see python/mypy#2129, python/mypy#1442, python/mypy#1264 for details), so I've overloaded it directly
@gvanrossum gvanrossum removed this from the 0.5 milestone Mar 29, 2017
@ilevkivskyi ilevkivskyi added the false-positive mypy gave an error on correct code label May 18, 2018
@ilevkivskyi
Copy link
Member

FWIW this particular example works correctly on master (due to a recent operator overhaul by @Michael0x2a ). We have a separate issue for general union destructuring in operator checks.

@ilevkivskyi
Copy link
Member

Just for reference, the main issue is #2128

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong false-positive mypy gave an error on correct code priority-1-normal topic-union-types
Projects
None yet
Development

No branches or pull requests

5 participants