I have a project that I built for it a Class in C (python c-api) which I extended more in the python project. The project's purpose is to provide a test framework for a C library. The test is mainly executed for each pull request of the C library.
The project needs to download form a Nexus server the relevant build of the C library, Compile the python class that is dependent on the C library, then to perform the tests.
The Problem: import / reload the project modules after the compilation of C code.
The Question: In my opinion, it's not that elegant to do import in each function that depends on the C library, So I tried to invoke reload, but it seems that it doesn't work, or at least not as I expecting.
Code The code is super-simplified to illustrate the issue, you can check this thread history to see the previous code.
main.py
from utils.my_custom_py import MyCustomExtended
from importlib.util import find_spec
from importlib import reload
from os import system, stat
import weakref
import sys
def setup():
if system('./setup.py clean build install') > 0:
raise SystemError("Failed to setup python c-api extention class")
def main():
if find_spec('custom2') is None:
setup()
for module_name in list(sys.modules.keys()):
m = sys.modules.get(module_name)
if not hasattr(m, '__file__'):
continue
if getattr(m, '__name__', None) in [None, '__mp_main__', '__main__']:
continue
try:
# superreload(m) # from ==> IPython.extensions
# sys.modules[module_name] = reload(m)
reload(m)
except Exception as e:
...
MyCustomExtended(1, 2, 3)
print("COOL")
if __name__ == "__main__":
main()
utils.my_custom_py.py
from importlib.util import find_spec
if find_spec('custom2'):
import custom2
else:
class custom2:
class Custom:
...
class MyCustomExtended(custom2.Custom):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
setup.py
from distutils.core import Extension, setup
custom_ext = Extension("custom2", ["src/custom.c"])
setup(name="custom2", version="1.0", ext_modules=[custom_ext])
src.custom.c
is taken from: docs.python.org
The error output:
running clean
running build
running build_ext
building 'custom2' extension
creating build
creating build/temp.linux-x86_64-3.6
creating build/temp.linux-x86_64-3.6/src
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/tmp/PlayAround/.venv/include -I/usr/include/python3.6m -c src/custom.c -o build/temp.linux-x86_64-3.6/src/custom.o
creating build/lib.linux-x86_64-3.6
x86_64-linux-gnu-gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-Bsymbolic-functions -Wl,-z,relro -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 build/temp.linux-x86_64-3.6/src/custom.o -o build/lib.linux-x86_64-3.6/custom2.cpython-36m-x86_64-linux-gnu.so
running install
running install_lib
copying build/lib.linux-x86_64-3.6/custom2.cpython-36m-x86_64-linux-gnu.so -> /tmp/PlayAround/.venv/lib/python3.6/site-packages
running install_egg_info
Removing /tmp/PlayAround/.venv/lib/python3.6/site-packages/custom2-1.0.egg-info
Writing /tmp/PlayAround/.venv/lib/python3.6/site-packages/custom2-1.0.egg-info
Traceback (most recent call last):
File "./main.py", line 38, in <module>
main()
File "./main.py", line 33, in main
MyCustomExtended(1, 2, 3)
File "/tmp/PlayAround/utils/my_custom_py.py", line 12, in __init__
super().__init__(*args, **kwargs)
TypeError: object.__init__() takes no parameters
main that work:
from importlib.util import find_spec
from importlib import reload
from os import system, stat
import weakref
import sys
def setup():
if system('./setup.py clean build install') > 0:
raise SystemError("Failed to setup python c-api extention class")
def main():
if find_spec('custom2') is None:
setup()
from utils.my_custom_py import MyCustomExtended
MyCustomExtended(1, 2, 3)
print("COOL")
if __name__ == "__main__":
main()
In Python 3, reload was moved from builtins to imp. So to use reload in Python 3, you'd have to write imp. reload(moduleName) and not just reload(moduleName).
The reload() is used to reload a previously imported module or loaded module. This comes handy in a situation where you repeatedly run a test script during an interactive session, it always uses the first version of the modules we are developing, even we have made changes to the code.
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.
Finally, I found the solution by trial and error. for this example code id did the following:
from utils.my_custom_py import MyCustomExtended
from importlib.util import find_spec
from importlib import reload
from sys import modules
from os import system
def setup():
if system('./setup.py clean build install') > 0:
raise SystemError("Failed to setup python c-api extention class")
def reload_my_libs():
global MyCustomExtended
reload(modules['utils'])
reload(modules['utils.my_custom_py'])
from utils.my_custom_py import MyCustomExtended
def main():
if find_spec('custom2') is None:
setup()
reload_my_libs()
MyCustomExtended(1, 2, 3)
print("COOL")
if __name__ == "__main__":
main()
as a result, I got:
running clean
running build
running build_ext
building 'custom2' extension
creating build
creating build/temp.linux-x86_64-3.6
creating build/temp.linux-x86_64-3.6/src
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/tmp/PlayAround/.venv/include -I/usr/include/python3.6m -c src/custom.c -o build/temp.linux-x86_64-3.6/src/custom.o
creating build/lib.linux-x86_64-3.6
x86_64-linux-gnu-gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-Bsymbolic-functions -Wl,-z,relro -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 build/temp.linux-x86_64-3.6/src/custom.o -o build/lib.linux-x86_64-3.6/custom2.cpython-36m-x86_64-linux-gnu.so
running install
running install_lib
copying build/lib.linux-x86_64-3.6/custom2.cpython-36m-x86_64-linux-gnu.so -> /tmp/PlayAround/.venv/lib/python3.6/site-packages
running install_egg_info
Removing /tmp/PlayAround/.venv/lib/python3.6/site-packages/custom2-1.0.egg-info
Writing /tmp/PlayAround/.venv/lib/python3.6/site-packages/custom2-1.0.egg-info
COOL
It also worked for my previous question version, which was way more complicated.
regardless, thanks for the effort to help :)
Besides the various minor issues in your code, you are also trying to reload all the modules in existence while silently swallowing errors. Reloading the utils module works as expected:
import utils
from importlib.util import find_spec
from importlib import reload
from os import system, stat
import weakref
import sys
def setup():
if system('python3 setup.py clean build install') > 0:
raise SystemError("Failed to setup python c-api extention class")
def main():
if find_spec('custom2') is None:
setup()
for module_name in list(sys.modules.keys()):
m = sys.modules.get(module_name)
if not hasattr(m, '__file__'):
continue
if getattr(m, '__name__', None) in [None, '__mp_main__', '__main__']:
continue
reload(utils)
MyCustomExtended = utils.MyCustomExtended
print(MyCustomExtended)
MyCustomExtended(1, 2, 3)
print("COOL")
if __name__ == "__main__":
main()
I suggest you only reload modules that are part of your application.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With