Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pyinstaller with relative imports

I'm attempting to make a Pyinstaller build for Windows 7 using Pyinstaller 2.1. The module uses relative imports because the package is typically used in Linux as a 'regular' Python package. Is there a way to create a spec file to handle this type of setup? Ideally I would like to have a Python package that I can make a Pyinstaller exe with for Windows and have a 'regular' pip-installable Python package in Linux/OS X.

I was thinking of maybe using hidden imports or something to achieve this.

I've tried using the default Pyinstaller settings and pointing it at my 'main' python script. I get the following from the resulting exe:

'Attempted relative import in non-package'

This makes sense because I'm pointing Pyinstaller at my main.py file in the package and Pyinstaller is NOT picking up my entire package. This is just the starting point for using the module from the command-line. However, you can import it and use it in your own code as well.

Sidenote:

The reasoning is this package requires numpy and scipy. Yes, I know there are good ways to get these working in Windows with Anaconda, etc. However, I'm stuck with an exe setup now for legacy reasons.

like image 884
durden2.0 Avatar asked Mar 17 '14 15:03

durden2.0


People also ask

Does PyInstaller include imports?

python - PyInstaller does not include imports - Stack Overflow. Stack Overflow for Teams – Start collaborating and sharing organizational knowledge.

Does PyInstaller include all dependencies?

PyInstaller can bundle your script and all its dependencies into a single executable named myscript ( myscript.exe in Windows). The advantage is that your users get something they understand, a single executable to launch.

How do I use PyInstaller hidden import?

The simpler solution is to use --hidden-import=modulename along with the PyInstaller script. It will add modulename as import statement silently. Hooks are better if you want to specify which import needs what additional modules. --hidden-import is simpler as a one-shot or for debugging.

Does Python do relative import?

Here is the solution which works for me: I do the relative imports as from .. sub2 import mod2 and then, if I want to run mod1.py then I go to the parent directory of app and run the module using the python -m switch as python -m app. sub1.


1 Answers

I can't find a way to get Pyinstaller to do this. However, I don't think it's the fault of Pyinstaller. It's more of a problem with the way I structured my package.

I was passing a script to Pyinstaller that was a part of my package. The better way to do that would be to provide a simple Python script outside of the package that serves as the cli front-end to the package.

For example, consider a package layout like this (assume files use relative imports):

repo_dir/
    setup.py
    README.md
    package_a/
        main.py
        support_module.py
        __init__.py

My previous attempt was trying to build main.py by passing it to Pyinstaller. This resulted in the error mentioned in the above question.

However, I later added a cli.py script that does something like this:

from package_a.main import main
if __name__ == '__main__':
    main()

Now, I can pass cli.py to Pyinstaller and my explicit relative imports are only used inside of the package. So, it all works. Here's a sample directory layout that works just for reference:

repo_dir/
    setup.py
    cli.py
    README.md
    package_a/
        main.py
        support_module.py
        __init__.py
like image 144
durden2.0 Avatar answered Sep 22 '22 09:09

durden2.0