Personally, what I would do is modify my imports to do:
from tags import Tags
..which would let me refer to the enum items by doing just Tags.A everywhere with minimal fuss.
But if you really want to continue referring to these items from the module namespace instead, one approach is to define a __getattr__ function within tags.py:
class Tags(enum.Flag):
NONE = 0
A = enum.auto()
B = enum.auto()
C = enum.auto()
def __getattr__(name: str) -> Tags:
return Tags[name]
At runtime, Python will try calling this function if you try accessing some attribute that wasn't directly defined in the tags module object. Mypy understands this convention and assumes that if __getattr__ is defined, the module is "incomplete". So, it'll use the return type as the type for any missing attributes you try accessing.
You may still want to do globals().update(Tags.__members__) mostly as a performance optimization though, to skip having to actually call __getattr__ function at runtime.
This strategy only really works if tags.py only contains one enum though -- otherwise, you'd need to make the return type something like Union[Tags, MyOtherEnum] (which is unwieldy) or even just Any (which loses the benefits of using a type checker).
This strategy also means mypy won't be able to do more sophisticated type inference and narrowing by taking into account the actual enum value. This is mostly only relevant if you're using Literal enums though.
If these are concerns, you might have to resort to a more brute force approach, like so:
from typing import TYPE_CHECKING
class Tags(enum.Flag):
NONE = 0
A = enum.auto()
B = enum.auto()
C = enum.auto()
globals().update(Tags.__members__)
if TYPE_CHECKING:
NONE = Tags.NONE
A = Tags.A
B = Tags.B
C = Tags.C
The TYPE_CHECKING constant is always false at runtime, but is considered to be always true by type checkers.
But if you're going to go to the expense of directly telling mypy about each of these variants, you might as well just skip trying to automatically update the globals and do this instead:
class Tags(enum.Flag):
NONE = 0
A = enum.auto()
B = enum.auto()
C = enum.auto()
NONE = Tags.NONE
A = Tags.A
B = Tags.B
C = Tags.C
Obviously, having to repeat yourself twice like this is pretty suboptimal, but I don't think there's an easy way around it. You could perhaps mitigate this by creating a script that auto-generates tags.py for you, but that's also fairly suboptimal, just for different reasons.