-
-
Notifications
You must be signed in to change notification settings - Fork 592
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nuitka extension file loader needs to load extension modules in "create_module" not only "exec_module" was (Pymongo lazy import) #2833
Comments
I have the nuitka-crash-report.xml file, but github gives me an error when I try to attach it. |
Example code: import importlib.util
import sys
def lazy_import(name):
spec = importlib.util.find_spec(name)
loader = importlib.util.LazyLoader(spec.loader)
spec.loader = loader
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
loader.exec_module(module)
return module
lazy_zlib = lazy_import("zlib")
print(lazy_zlib.crc32) $ python3 hello.py
<built-in function crc32>
$ python3 -m nuitka --onefile hello.py
$ ./hello.bin
Traceback (most recent call last):
File "/tmp/onefile_6892_1714611657_437491/hello.py", line 12, in <module>
print(lazy_zlib.crc32)
File "/tmp/onefile_6892_1714611657_437491/importlib/util.py", line 250, in __getattribute__
ValueError: module object for 'zlib' substituted in sys.modules during a lazy load Is there a way we can detect that we are running under Nuitka and eagerly import instead? |
Another aspect of the problem is the handling of $ cat hello.py
e = ModuleNotFoundError(name="foo")
print(e.name)
$ python3 hello.py
foo
$ python3 -m nuitka --onefile hello.py
$ ./hello.bin
Traceback (most recent call last):
File "/tmp/onefile_7078_1714612025_862116/hello.py", line 1, in <module>
e = ModuleNotFoundError(name="foo")
TypeError: exceptions.ModuleNotFoundError does not take keyword arguments |
@blink1073 if you'd like to add in nuitka support from within pymongo, then it'd look like something like this if spec is None:
cond = "__compiled__" in globals()
if cond:
sys.exit(f"Nuitka: For this environment to load, need to use this as an option to compile with --include-module={name}` with Nuitka to include it")
raise ModuleNotFoundError(name=name) |
@kayhayen class ModuleNotFoundError(
*args: object,
name: str | None = ...,
path: str | None = ...
) so it needs to accept those. |
There is special handling for I also never saw I don't want there to be a need to change the code for Nuitka of course. Compiled modules interact themselves with |
I will start to add support for the |
Thanks all, here is what I have for now as a workaround: def lazy_import(name: str) -> ModuleType:
"""Lazily import a module by name
From https://docs.python.org/3/library/importlib.html#implementing-lazy-imports
"""
# Eagerly import on Nuitka
if "__compiled__" in globals():
return importlib.import_module(name)
try:
spec = importlib.util.find_spec(name)
except ValueError:
raise ImportError(name) from None # use ImportError instead of ModuleNotFoundError
if spec is None:
raise ImportError(name)
... @sullivan50909, I'll update my PR accordingly |
Thanks for your report, this is worked on the factory branch, which is a development version under rapid development. You can try it out by going here: https://nuitka.net/doc/factory.html Feedback on whether this is working is very welcome. Please do not share plans to do it; only confirm or deny that it is working. |
So, it seems lazy loader for the example code is working as expected. As for lazy loading, I would normally recommend to use the |
Yes, being built-in, means Nuitka doesn't step it, trying with my badly self-compiled 3.9 now, that probably doesn't do it, since it's an extension module there. Extension module loading will also be different from compiled module loading. |
Yeah, I managed to reproduce it, checking the source code now, I came across this:
Seriously? |
if you keep the snippet i have, it'll be true lazy loading and will also help with exe's debloat, snappy i found to be a large dependency which is why i did it that way. |
So, it seems there is an incompatibility between the meta path-based loader of Nuitka and the one of Python3.9 or higher. Nuitka loads the extension module and executes a "def" if found (not the case for zlib) during Somehow, |
So, this can be distilled down to this:
Basically, |
This is an invasive change, but not too bad, I will try and tackle it for the next round of hotfixes, 2.2.1 has to go out now, 2.2.2 will be a week later likely. |
@blink1073 created a workaround: mongodb/mongo-python-driver@ff950f0 |
python3 -m nuitka --version
2.2
Commercial: None
Python: 3.9.18 (main, Jan 24 2024, 00:00:00)
Flavor: Fedora Python
Executable: /usr/bin/python3
OS: Linux
Arch: x86_64
Distribution: Rhel (based on Fedora) 9.3
Version C compiler: /usr/bin/gcc (gcc 11)
How did you install Nuitka and Python
Started from clean ubi9 docker container which has python pre-installed. No virtualenv.
yum install gcc python3-devel
pip3 install nuitka
pip3 install patchelf
The specific PyPI names and versions
The problem is with pymongo.
This works:
pymongo==4.6.3
Any newer version fails (4.7, 4.7.1 and their factory branch)
Also supply a Short, Self Contained, Correct, Example
Start from clean ubi9 docker container (I don't think there is anything special about ubi9 or docker, but it is how I tested it)
Yum install pip
Option1: Working Version:
pip install pymongo==4.6.3
Option2: Non-working Version:
pip install pymongo==4.7.0
create hello.py with the following content:
Demonstrate that it works without compilation:
python3 hello.py
Compile
At this point, what happens depends on the version of pymongo. Hello.bin replies as expected for version 4.6.3. With pymongo's factory branch, it errors out during compilation. With version 4.7, it errors when attempting to run hello.bin.
I know that this example makes it apperar that the problem is with pymongo, but I think there are a few issues going on. I'm working the pymongo root-cause issues separately. Note that before compilation, both versions of pymongo work.
The reason I am contacting you is that I think Nuitka is having trouble with the lazy import features that pymongo added in version 4.7. I think that Nuitka is failing to include a module, and then pymongo is having trouble reporting the error.
No
The text was updated successfully, but these errors were encountered: