gruns/orderedmultidict

Regression with PyInstaller (1.0.1 compared to 1.0)

Closed this issue ยท 11 comments

tasn commented

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.

tasn commented

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")
gruns commented

@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.

gruns commented

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!

gruns commented

closing

this was fixed with 6d66993 and subsequent commits

thank you everyone for weighing in here! ๐Ÿ™