How to import *.pyc file from different version of python? - python

I used python 2.5 and imported a file named "irit.py" from C:\util\Python25\Lib\site-packages directory. This files imports the file "_irit.pyc which is in the same directory. It worked well and did what I wanted.
Than, I tried the same thing with python version 2.6.4. "irit.py" which is in C:\util\Python26\Lib\site-packages was imported, but "_irit.pyc" (which is in the same directory of 26, like before) hasn't been found. I got the error message:
File "C:\util\Python26\lib\site-packages\irit.py", line 5, in
import _irit
ImportError: DLL load failed: The specified module could not be found.
Can someone help me understand the problem and how to fix it??
Thanks, Almog.

"DLL load failed" can't directly refer to the .pyc, since that's a bytecode file, not a DLL; a DLL would be .pyd on Windows. So presumably that _irit.pyc bytecode file tries to import some .pyd and that .pyd is not available in a 2.6-compatible version in the appropriate directory. Unfortunately it also appears that the source file _irit.py isn't around either, so the error messages end up less informative that they could be. I'd try to run python -v, which gives verbose messages on all module loading and unloading actions -- maybe that will let you infer the name of the missing .pyd when you compare its behavior in 2.5 and 2.6.

Pyc files are not guaranteed to be compatible across python versions, so even if you fix the missing dll, you could still run in to problems.

Related

Using embedded python, loading a *.pyd outside of DLLs directory fails

I have a C++ application (X-Plane) for which there is a plugin which permits the use of python scripts (XPPython3 plugin). The plugin is written in C, using python CAPI, and works great, allowing me to write python scripts which get executed within the C++ application.
On Windows 10, I want to extend my python features by importing imgui. I have a python cython-built pyd file (_imgui.cp39-win_amd64.pyd).
If I place the pyd file in C\Program Files\Python39\DLLs, it works as expected: C++ application calls CAPI to python, which loads script which imports and executes imgui code.
If I place the pyd file anywhere else, embedded python either reports "module not found" -- if the pyd isn't on sys.path(), or if it is on sys.path():
ImportError: DLL load failed while importing _imgui: The parameter is incorrect.'
Changes using: os.add_dll_directory(r'D:\somewhere\else')
Does not effect whether the module is found or not, nor does it change the 'parameter incorrect' error. (see https://bugs.python.org/issue36085 for details on this change. -- my guess is add_dll_directory changes lookup for DLLs, but not for pyd?) sys.path appears to be used for locating pyd.
Yes, the pyd is compiled with python3.9: I've compiled it both with mingw and with visual studio toolchains, in case that might be a difference.
For fun, I moved python-standard _zoneinfo.pyd from Python39\DLLs and it fails in the same way in embedded python: "The parameter is incorrect". So, that would appear to rule out my specific pyd file.
The key question is/are:
Other than placing a pyd file under PythonXX\DLLs, is there a way to load a PYD in an embedded python implementation? (I want to avoid having to tell users to move my pyd file into the Python39\DLLs directory... because they'll forget.)
Note that using IDLE or python.exe, I can load pyds without error -- anywhere on sys.path -- so they don't have to be under Python39\DLLs. It's only when trying to load from embedded python that the "Parameter is incorrect" appears. And of course, this works flawlessly on Mac.
(Bonus question: what parameter? It appears to be python passing through a windows error.)
There seems to be a simple answer, though I suspect it's better characterized as a python bug.
There is nothing magical about Python39\DLLs directory.
The problem is using absolute vs relative paths in sys.path.
Python can find modules using absolute or relative paths. So if zippy.py is in folder foobar,
sys.path.append('foobar')
import zippy
# Success
Python and find, BUT NOT LOAD pyd files using relative paths. For example, move _zoneinfo.pyd from PythonXX\LDDs to foobar
sys.path.append('foobar')
import _zoneinfo
# ImportError: DLL load failed while importing _zoneinfo: The parameter is incorrect.'
Instead, use absolute path, and it will find and load PYD:
sys.path.append(r'c:\MyTest\foobar')
import _zoneinfo
# Success
So, there is actually a way to do this—that is, ship your application with the desired libraries. The solution is to use an embedded distribution and ship this with your application. You can find the correct distribution on the official Python download page corresponding to your desired version (here's the link to the lastest 3.9 release which seems to be what you're using: https://www.python.org/downloads/release/python-392/). Look for the Windows Embeddable Package.
You can then simply drop in your .pyd file alongside the standard library files (note that if your third-party library is dependent on any other libraries, you will have to include them, as well). Shipping your application with an embeddable distribution should not only solve your current issue, but will also mean that your application will work regardless of which version of Python a user has installed (or without having Python installed at all).

How to find which DLL failed in "ImportError: DLL load failed while importing" in python?

Context
Are there commands to enhance the error message that is received such that python displays which .dll file it cannot find?
For error:
python test_cv2.py
Traceback (most recent call last):
File "test_cv2.py", line 1, in <module>
import cv2
File "E:\Anaconda3\envs\py38\lib\site-packages\cv2\__init__.py", line 5, in <module>
from .cv2 import *
ImportError: DLL load failed while importing cv2: The specified module could not be found.
(py38) E:\somepath>
I would like to determine which .dll file is actually not being found. To do so, I downloaded and run DependenciesGui.exe from this repository.. Next I fed the DependenciesGui.exe the cv2.cp38-win_amd64.pyd which indicates api-ms-win-core-wow64-l1-1-1.dll is missing, amongst others.
I currently do not have a way to verify that the .dll files that are reported missing by dependenciesGUI.exe are also the files that python 3.8 is not finding in the anaconda environment.
A way to implicitly verify that the python 3.8 missing .dll files are the same as the same files reported missing by dependenciesGUI.exe would be to download and paste all the missing .dll files into ../system32/. Followed by inspecting if the error message dissapears/changes. However one of the .dll files reported missing is: api-ms-win-core-wow64-l1-1-1.dll which I am not yet able to find (online). Also I tried to cheat to copy and rename api-ms-win-core-wow64-l1-1-0.dll to api-ms-win-core-wow64-l1-1-1.dll but that (luckily) doesn't enable the dpendenciesGUI.exe to recognize the .dll file as found.
Question
How can I make the error message/traceback of python explicitly mention which .dll file is (the first .dll file that is) not found?
Note
This is not about solving the xy-problem of installing opencv.
Short answer: No.
Although it is probably not completely impossible, it would require to bind a tool like dependenciesGUI in Python, in order to be able to call it in that given context (namely taking into account the actually search path for dll in Python and already loaded dynamics libraries). It would be quite a lot of work for little gain. Indeed, the default search path in Python>=3.8 on Windows should be very similar to the one of dependenciesGUI, so that the missing dll should be the same. Personally, I'm developing pre-compiled binary distributions for Python, and so far dependenciesGUI was enough to identify the missing libraries at Python import.

Script made compiled with pyinstaller DLL load fail

I have compiled a script with pyinstaller and it compiles fine but when I run the program I get the following error in the console window.
ImportError: DLL load failed: The specified module could not be found.
I am trying to import Crypto when I get this error. Why does this happen and how can I fix it?
According to the pyinstaller manual:
You can verify that hidden import is the problem by using Python's verbose imports flag. If the import messages say "module not found", but the warnproject.txt file has no "no module named..." message for the same module, then the problem is a hidden import.
Hidden imports are handled by hooking the module (the one doing the hidden imports) at Analysis time. Do this as follows:
Create a file named hook-module.py (where module is the fully-qualified Python name, eg, hook-xml.dom.py) and place it somewhere. Remember the place as your private hooks directory.
In the .spec file, pass your private hooks directory as hookspath argument to Analysis so will be searched. Example:
a = Analysis(['myscript.py'], hookspath='/my/priv/hooks')
In most cases the hook module will have only one line:
hiddenimports = ['module1', 'module2']
When the Analysis finds this file, it will proceed exactly as though the module explicitly imported module1 and module2.
This question seems related, the answers might also be useful for you.
Finally, this report seems to contain a similar problem. The user seemingly was able to fix it by updating to pyinstaller 2.1, so you might want to give that a try if you haven't already.

Error importing .pyd, works if it is renamed to .so

I'm creating a Python library file from C++ using Boost::Python, and I'm trying to import it from the Python command line to test it.
The module seems to work correctly when imported, but only if it is named .so. If the same exact file is renamed to .pyd, in the same directory, the console replies with an
ImportError: No module named Test
I have also tried to rename it with a trailing _d in case the console was in debug mode, but that does not seem to be the case.
What could be the problem?

*.pyd file fails to load, but DependancyWalker comes up clean, and ProcMon shows it loaded

I am trying to load a *.pyd with Python, but I receive the well known "Import Error: DLL load failed: the specified procedure can not be found." error.
I have already done the following:
1.) Investigated the *.pyd with Dependency Walker. GPSVC.DLL and IESHIMS.DLL came up as missing, but delay loaded, IEFRAME.DLL aslo came up as missing an export, but was also delay-loaded. It's my understanding that these are not used, and are delay load anyway, so they should not be the problem.
2.) Did an "import foo" on foo.pyd in the python command window, with ProcMon watching. ProcMon shows event "LoadImage" on "foo.pyd" with result SUCCESS.
This seems to imply that the *.pyd file loaded correctly.
So what am I missing. My windows diagnostics are telling me all is well, but python is telling me the thing cannot be loaded (usually due to a missing dll or symbol).
Ideas?
Thanks!
Is the .pyd file for the same version of Python you're using? Loading a .pyd file for the wrong Python version can produce that error message.
Dependency Walker can show you which pythonNN.dll it links to.
If you have a file foo.pyd, for import foo to succeed, there must be an externally accessible function named initfoo. Dependency Walker will show this (typically the ONLY function) if it exists. initfoo needs to be called by Python to initialise the foo module.
Note: I would expect a more explicit error message if this were the problem:
>>> import fubar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: dynamic module does not define init function (initfubar)
>>>
You say that you are "trying to load a *.pyd file". Is that just a strange way of describing import foo or is it something else?
Did you create the pyd? If not, who did? Have you asked them? Is this pyd available on the web so that others could try to load/import it?
Ok here is the answer:
The windows diagnostics (depends, procmon, etc) were showing the DLL (or pyd) loading fine.
Python was showing that it was not loading fine.
I found that the windows tools were referring to a different Python26.dll hiding in my C:\Window\SysWOW64 folder.
This second Python26.dll (found in SysWOW64) has a symbol that is missing in the primary python26.dll (installed by the windows python installer, found in C:\Python26).
This symbol "_PyByteArray_empty_string", was apparently needed by my *.pyd file.
So when loading via windows diagnostics, the SysWOW64 dll was found, and the *.pyd loaded properly. When loading from python, the dll in C:\Python26\ was found, the symbol was missing, and load failed.
So that is WHY the problem manifested. The question now is: Why are there two versions of Python26.dll floating around, one with _PyByteArray_empty_string, and one without?
I'm using Python 2.6.6. Perhaps this symbol is removed in 2.6.6 but present in some older 2.6.x release?

Categories