Why can in Python 3 enum equality not be checked correctly across module boundaries if the enum has been defined in the main module? Here is an example:
moduleA.py:
#!/usr/bin/python3
import moduleB
from enum import Enum, unique
@unique
class MyEnum(Enum):
A = 1
B = 2
# def __eq__(self,other):
# assert isinstance(other,self.__class__)
# return self.value == other.value
if __name__ == "__main__":
myVar = MyEnum.B
moduleB.doStuff(myVar)
moduleB.py:
#!/usr/bin/python3
import moduleA
def doStuff(aVariable):
bVariable = moduleA.MyEnum.B
assert aVariable == bVariable
Calling "./moduleA.py" on the command line yields:
Traceback (most recent call last):
File "./moduleA.py", line 17, in <module>
moduleB.doStuff(myVar)
File "/home/myuser/testing/moduleB.py", line 7, in doStuff
assert aVariable == bVariable
AssertionError
Uncommenting the custom equality operator in the enum leads to an assertion failure there. I've found that the class module is not the same in both cases, as it is "__main__" in one case.
What is the most "Pythonic way" to fix this problem (other than moving the enum to its own module)?
EDIT: Switching to "aVariable is bVariable" does not work either:
Traceback (most recent call last):
File "./moduleA.py", line 17, in <module>
moduleB.doStuff(myVar)
File "/home/myuser/testing/moduleB.py", line 7, in doStuff
assert aVariable is bVariable
AssertionError
As far as Python is concerned, you have three modules here:
__main__
moduleA
moduleB
The file you run from the command line, the main entry point, is always stored as the __main__
module. If you import moduleA
anywhere in the code, Python sees that as separate from the __main__
module and creates instead a new module object. You thus have two separate MyEnum
classes:
__main__.MyEnum
moduleA.MyEnum
Their members are distinct and thus cannot be equal.
Your test passes if instead of using import moduleA
you used import __main__ as moduleA
, or used a separate script file to drive the test; that separate file would become __main__
:
#!/usr/bin/python3
# test.py, separate from moduleA.py and moduleB.py
import moduleA
import moduleB
if __name__ == "__main__":
myVar = moduleA.MyEnum.B
moduleB.doStuff(myVar)
Another workaround would be to tell Python that __main__
and moduleA
are the same thing; before importing moduleA
(or moduleB
, which imports moduleA
) you can add another entry to sys.modules
:
if __name__ == '__main__':
import sys
sys.modules['moduleA'] = sys.modules['__main__']
import moduleB
I'd not consider this very Pythonic.