Regression with PyInstaller (1.0.1 compared to 1.0)
Closed this issue ยท 11 comments
Trying to use PyInstaller to package https://github.com/etesync/etesync-dav I'm getting failures with 1.0.1 but not with 1.0. The error (when running the binary) is:
[Errno 2] No such file or directory: '/tmp/_MEIjeDGjU/orderedmultidict/__version__.py'
So essentially PyInstaller can't find the version.py file which usually means it was being imported in some magical way rather than explicitly. Usually just adding import version to init.py fixes such issues (not sure if it is the case here or not).
For people coming across this issue, a workaround to this is creating a custom PyInstaller hook with the following contents:
from PyInstaller.utils.hooks import get_package_paths
datas = [(get_package_paths('orderedmultidict')[1] + "/__version__.py", 'orderedmultidict')]
This will force PyInstaller to load the __version__.py
file and resolve the error.
The issue, as @tasn suggested, is that __version__.py
is not explicitly imported anywhere but rather used only as a file in setup.py
, without actually importing the module: https://github.com/gruns/orderedmultidict/blob/master/setup.py#L21.
imported anywhere but rather used only as a file in setup.py
Seems that it's not the case anymore, since __init__
is importing it. Is there any reason we can't import version explicitly?
@igortg Didn't notice that __init__.py
was doing the same thing as setup.py
but the issue still stands, PyInstaller doesn't import as it is not being imported implicitly.
Is there any reason we can't import version explicitly?
I can't answer this...I haven't tested making the change it, to be honest.
It's imported in a weird way (why not a normal import?) that's maybe why it's PyInstaller can't catch it.
This also breaks PyOxidizer, and possibly also Nuitka.
I'm also using PyInstaller and hit this issue. I worked around it with a runtime hook:
import importlib
import sys
try:
import orderedmultidict # NOQA
except FileNotFoundError:
pass
sys.modules["orderedmultidict"] = importlib.import_module("orderedmultidict.orderedmultidict")
@bryan-koroleski-fivestars thank you for posting your workaround ๐
i want to resolve this but, sadly, i dont have the time to fully chase this down right now
requests does the same trick, exec()
ing a __version__.py
file full of metadata. see https://github.com/psf/requests/blob/master/setup.py#L61-L63
this begs the question: what else does requests do so it doesnt break PyOxidizer, Nuitka, and PyInstaller?
It looks like the difference here is that requests imports the members of __version__.py
instead of exec()
ing in __init__.py
: https://github.com/psf/requests/blob/master/requests/__init__.py#L129-L131
I should have time to put together a quick PR for this tomorrow if it would help.
yep. and indeed orderedmultidict uses exec()
in __init__.py
:
# Import all variables in __version__.py without explicit imports.
meta = {} # type: Dict
with open(pjoin(dirname(__file__), '__version__.py')) as f:
exec(f.read(), meta)
https://github.com/gruns/orderedmultidict/blob/master/orderedmultidict/__init__.py#L22-L26
I should have time to put together a quick PR for this tomorrow if it would help.
thank you! ๐
version 1.0.1 Pyinstaller 4.10
File "orderedmultidict\__init__.py", line 19, in <module> FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\User\\AppData\\Local\\Temp\\_MEI149122\\orderedmultidict\\__version__.py' [5644] Failed to execute script 'main' due to unhandled exception!