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

Use EnumMeta instead of Enum to mark enum classes #4319

Merged
merged 10 commits into from Apr 10, 2018

Conversation

Projects
None yet
5 participants
@elazarg
Contributor

elazarg commented Dec 4, 2017

Implement #4311.

The tests will fail until python/typeshed#1770 is synched.

@ethanhs ethanhs referenced this pull request Dec 4, 2017

Merged

Sync typeshed #4320

@elazarg elazarg referenced this pull request Dec 17, 2017

Closed

Enum-like user classes #4311

elazarg and others added some commits Jan 6, 2018

@ethanhs

Looks good, just a couple of requests.

main:7: error: Incompatible types in assignment (expression has type "int", variable has type "Medal")
m = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "Medal")
[case testEnumFromEnumMetaBasics]

This comment has been minimized.

@ethanhs

ethanhs Feb 25, 2018

Collaborator

I think it would be helpful to have a testcase for something that inherits from a class that has EnumMeta as a metaclass, to check those classes are still found to be Enums for all intents and purposes.

Also perhaps a test of a EnumMeta deriving class that tries to use generics?

This comment has been minimized.

@elazarg

elazarg Feb 25, 2018

Contributor

I think it would be helpful to have a testcase for something that inherits from a class that has EnumMeta as a metaclass, to check those classes are still found to be Enums for all intents and purposes.

Will do, but note that this is already handled by classes that inherit Enum itself.

I'm not sure I understand the second suggestion. Should mypy support something like that?

This comment has been minimized.

@ethanhs

ethanhs Feb 25, 2018

Collaborator

Good point on the first, but just to be safe. Also on the second, I mean to check that it fails correctly :)

@ethanhs

This comment has been minimized.

Collaborator

ethanhs commented Feb 25, 2018

Hm, I think you need to git submodule update to pull the latest changes from typeshed.

@elazarg

This comment has been minimized.

Contributor

elazarg commented Feb 25, 2018

git submodule update doesn't do the trick for some reason. I tried git checkout upstream/master typeshed which feels horribly wrong, but seems to work.

bronze = None
reveal_type(Medal.bronze) # E: Revealed type is '__main__.Medal'
m = Medal.gold
m = 1 # E: Incompatible types inassignment (expression has type "int", variable has type "Medal")

This comment has been minimized.

@ethanhs

ethanhs Feb 25, 2018

Collaborator

Needs a space between "in" and "assignment"

This comment has been minimized.

@elazarg

elazarg Feb 25, 2018

Contributor

Yep. Sorry about that.

@ethanhs

LGTM. Thanks for the fast fixes.

@gvanrossum

Pretty cool how much code can be deleted!

@@ -1275,6 +1273,11 @@ def analyze_metaclass(self, defn: ClassDef) -> None:
# do not declare explicit metaclass, but it's harder to catch at this stage
if defn.metaclass is not None:
self.fail("Inconsistent metaclass structure for '%s'" % defn.name, defn)
else:
if defn.info.metaclass_type.type.fullname() == 'enum.EnumMeta':

This comment has been minimized.

@gvanrossum

gvanrossum Feb 26, 2018

Member

So if the metaclass is a subclass of EnumMeta, it's not an enum? (I'm not sure I care, but I wonder if this is an intentional choice.)

[case testEnumFromEnumMetaBasics]
from enum import EnumMeta
class Medal(metaclass=EnumMeta):

This comment has been minimized.

@gvanrossum

gvanrossum Feb 26, 2018

Member

This code doesn't actually work -- you need to also inherit from enum.Enum, else the class definition fails at runtime with

TypeError: Medal().__init__() takes no arguments

(Note: I'm not asking that mypy enforce this -- but I still think the test should work as an example.)

This comment has been minimized.

@elazarg

elazarg Mar 1, 2018

Contributor

I'm not sure what to do about it. If Medal inherits from Enum, the test doesn't check for what I want it to check. We might as well drop it.

This comment has been minimized.

@elazarg

elazarg Mar 1, 2018

Contributor

I can add a def __init__(self, *args): pass constructor, if you deem it better. It works, though might be considered an implementation detail.

This comment has been minimized.

@msullivan

msullivan Apr 5, 2018

Collaborator

I'd say add a comment explaining that it doesn't work at runtime and what you are testing for.

[case testEnumFromEnumMetaSubclass]
from enum import EnumMeta
class Achievement(metaclass=EnumMeta): pass

This comment has been minimized.

@gvanrossum

gvanrossum Feb 26, 2018

Member

This must also inherit from enum.Enum.

@msullivan msullivan merged commit 6f11f35 into python:master Apr 10, 2018

2 checks passed

continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
@JelleZijlstra

This comment has been minimized.

Collaborator

JelleZijlstra commented Apr 11, 2018

This seems to have broken typeshed CI. https://travis-ci.org/python/typeshed/jobs/364931878 I'll look into it now.

JelleZijlstra added a commit to JelleZijlstra/typeshed that referenced this pull request Apr 11, 2018

fix third_party/2/enum.pyi
This fixes an error in Travis that seems to have been caused by python/mypy#4319.

The fix was taken from the stdlib/3.4/enum.pyi stub. Mypy no longer assumes
that classes whose metaclass is EnumMeta are subclasses of Enum, so we can't
bound the typevar on Enum.

JelleZijlstra added a commit to python/typeshed that referenced this pull request Apr 11, 2018

fix third_party/2/enum.pyi (#2039)
This fixes an error in Travis that seems to have been caused by python/mypy#4319.

The fix was taken from the stdlib/3.4/enum.pyi stub. Mypy no longer assumes
that classes whose metaclass is EnumMeta are subclasses of Enum, so we can't
bound the typevar on Enum.

gvanrossum added a commit to python/typeshed that referenced this pull request Apr 11, 2018

fix third_party/2/enum.pyi (#2039)
This fixes an error in Travis that seems to have been caused by python/mypy#4319.

The fix was taken from the stdlib/3.4/enum.pyi stub. Mypy no longer assumes
that classes whose metaclass is EnumMeta are subclasses of Enum, so we can't
bound the typevar on Enum.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment