Module-level code (e.g. attribute initialization) is not re-executed when re-importing a module through importlib.reload().
print("Module test1 loading...")
my_attribute = "<Default value>"
test2.py:
import sys
sys.path.append('.')
import test1
import importlib
print(test1.my_attribute)
test1.my_attribute = "<Modified value>"
print(test1.my_attribute)
importlib.reload(test1)
print(test1.my_attribute)
Output before cythonizing is:
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32
>>> import test2
Module test1 loading...
<Default value>
<Modified value>
Module test1 loading...
<Default value>
Output after cythonizing is:
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32
>>> import test2
Module test1 loading...
<Default value>
<Modified value>
<Modified value>
The importlib documentation at https://docs.python.org/3/library/importlib.html specifies:
When reload() is executed:
Python module’s code is recompiled and the module-level code re-executed, defining a new set of objects which are bound to names in the module’s dictionary by reusing the loader which originally loaded the module.
In the case of a cythonized module, recompiling the code is obviously not necessary; however, the module-level code should be re-executed to retain the runtime semantics.
In my case, there is a unit test; each test method reads and modifies a module-level attribute. In the setUp() method, I reload the module so that the test methods don't influence each other. This unit test fails after cythonizing the module.
Used compiler directive: "always_allow_keywords": True
Used Cython version 0.28.5 on Windows 7
Workaround: Create a "reinit()" method which does the same as the module-level code; call that method instead of reloading the module. This workaround is not very elegant, as it forces me to change my module code just to make it unit-testable.