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

Singleton as enum doesn't work as expected #7279

Closed
lmazuel opened this issue Aug 1, 2019 · 5 comments · Fixed by #7693
Closed

Singleton as enum doesn't work as expected #7279

lmazuel opened this issue Aug 1, 2019 · 5 comments · Fixed by #7693

Comments

@lmazuel
Copy link

lmazuel commented Aug 1, 2019

Hello,

Based on the tag in the commit e818a96 that is the merge commit of #7000, that is declared to fix #1803, the singleton scenario as described in https://www.python.org/dev/peps/pep-0484/#support-for-singleton-types-in-unions should be supported in 0.720.

However, it's still not the case:

from typing import Union
from enum import Enum

class Empty(Enum):
    token = 0
_empty = Empty.token

def func(x: Union[int, None, Empty] = _empty) -> int:

    if x is _empty:
        return 0
    elif x is None:
        return 1
    else:  # At this point typechecker knows that x can only have type int
        return x * 2

does:

singleton.py:15: error: Unsupported operand types for * ("Empty" and "int")
singleton.py:15: note: Left operand is of type "Union[int, Empty]"

Have I misunderstood something?

Thank you!

@Michael0x2a
Copy link
Collaborator

Michael0x2a commented Aug 2, 2019

You'll need to annotate _empty as being Final. For example, see this test case.

Without it, mypy thinks that it's possible for _empty to be later reassigned to some other variant of the Empty enum, in which case it'd be unsafe to narrow x to int within the else block. (Of course, that's impossible in this case since Empty contains only a single variant, but mypy doesn't treat single-variant enums any differently from other enums and so won't special-case this particular interaction.)

@lmazuel
Copy link
Author

lmazuel commented Aug 2, 2019

Gotcha. I have what I need then, thank you!
Out of curiosity, does it mean PEP484 would need an update (I literally just copied/pasted it to follow the recommendation here)?

@JukkaL
Copy link
Collaborator

JukkaL commented Aug 6, 2019

I wonder if we should special case this in mypy. @Michael0x2a What do you think about this?

@Michael0x2a
Copy link
Collaborator

Yeah, I think special-casing could be reasonable, though probably it's not a big priority given that there's an easy workaround.

Actually, now that I'm thinking about it, I wonder if it might be as easy as just adding another case to the is_singleton_type and coerce_to_literal functions at the bottom of https://github.com/python/mypy/blob/master/mypy/checker.py. I'll try following up on this idea later this weekend. (@lmazuel -- or do you maybe want to try taking a stab at this?)

@lmazuel
Copy link
Author

lmazuel commented Aug 22, 2019

Hi @Michael0x2a sorry for the late answer, was in vacation :).
I don't know if I have the skills to do that honestly, so please assume I don't (that's safer :)) but I will try to find time to understand this (maybe :))
Thanks!

Michael0x2a pushed a commit that referenced this issue Oct 12, 2019
This PR adds supports for singleton types in unions using `Enum`s as described
in [PEP 484][0] (without using `Final`).

As suggested by @Michael0x2a in [the corresponding issue][1], adding another
case to the `is_singleton_type` and `coerce_to_literal`functions allows mypy
to recognize an `Enum` with 1 value as a singleton type.

Fixes #7279

  [0]: https://www.python.org/dev/peps/pep-0484/#support-for-singleton-types-in-unions
  [1]: #7279 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants