generics support for Enum
Greetings! I'd like to add Generics support for Enum... at least I think I do. :-/ The magic seems to happen in `SomeMetaClass.__getitem__`, and it should be doable as `EnumType.__getitem__` currently only accepts strings, so types could easily take a different branch in the code, but I am entirely unsure of what that separate branch should do, what it should return, etc. Are there any pure-python classes in the stdlib (besides Generics) that I could use for inspiration? Or some documentation somewhere I could use? A basic tutorial so I can get a grip on all the terminology? Any and all help appreciated! -- ~Ethan~
Welcome!
The first question I have is: what is the use case you are trying to
support here? The ones that comes to mind for me is making it explicit to
the type checker what the value type of an enum is:
class StringEnum(Enum[str]):
a = "a string"
b = "another string"
class TupleEnum(Enum[tuple[int, int]]):
a = (1, 2)
b = (2, 3)
That seems useful, but it's not too important as type checkers can already
infer the value type from the class body.
Or is there some other use case I am missing?
El dom, 23 ene 2022 a las 9:47, Ethan Furman (
Greetings!
I'd like to add Generics support for Enum... at least I think I do. :-/
The magic seems to happen in `SomeMetaClass.__getitem__`, and it should be doable as `EnumType.__getitem__` currently only accepts strings
Note though that strings can be valid types (for forward annotations), so if SomeEnum[T] meant something related to generics, it may be difficult to distinguish it from the current support for SomeEnum[name] == getattr(SomeEnum, name).
, so types could easily take a different branch in the code, but I am entirely unsure of what that separate branch should do, what it should return, etc.
Are there any pure-python classes in the stdlib (besides Generics) that I could use for inspiration? Or some documentation somewhere I could use? A basic tutorial so I can get a grip on all the terminology?
Any and all help appreciated!
-- ~Ethan~ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: jelle.zijlstra@gmail.com
Are there any pure-python classes in the stdlib (besides Generics)
Hi Ethan, that I could use for inspiration? A search for `__class_getitem__` (`metaclass.__getitem__` but allows generics to work with ABCs) shows a number of places use: ``` GenericAlias = type(list[int]) __class_getitem__ = classmethod(GenericAlias) ``` And the only other place (except Generic) seems to be `dataclasses.InitVar`, with a very simple method: [0] ``` def __class_getitem__(cls, type): return InitVar(type) ``` [0]: https://github.com/python/cpython/blob/e029c53e1a408b89a4e3edf30a9b38b094f9c... The `InitVar` class is really quite basic and shows you only really need to return something which makes sense at runtime. Basically does `print(Enum[int])` make sense. Assuming the (possibly problematic) branching is resolved, you can pretty much just follow suit and return a `GenericAlias`. ``` from typing import _GenericAlias def __getitem__(cls, name): if ???: return cls._member_map_[name] else: return _GenericAlias(cls, name) ``` However as soon as you inherit from the `_GenericAlias` the parameters are lost. So it could make sense to just return `cls`. I think python/typing #629 is somewhat related. [1] I'll show the problem with `enum` regardless: ```
import enum from typing import _GenericAlias
_GenericAlias(enum.Enum, str) enum.Enum[str] class Test(_GenericAlias(enum.Enum, str)): ... FOO = 1 ... ... # all information is lost Test
Test.__mro__ ( , , )
[1]: https://github.com/python/typing/issues/629
TL;DR, if you can resolve Jelle's concern with strings and parameters,
then whatever you return (`cls` or `_GenericAlias`) is probably not
going to matter much at runtime.
FWIW, yes the type info is lost to normal-ish inspection cause typing._GenericAlias and types.GenericAlias implement __mro_entries__ which is what sets the __mro__, but the original bases are still available using __orig_bases__ and so I'd advise using those as tools do use it for inspection at runtime. On another note I think using types.GenericAlias is a much better idea than typing._GenericAlias just cause it's faster and the latter might be removed one day (purely speculation)
participants (4)
-
Ethan Furman
-
James H-B
-
Jelle Zijlstra
-
Peilonrayz