py2exe is not properly including project submodules - python

I am using py2exe to package a wxPython GUI for distribution on Windows. This is a simple version of my directory structure:
\project
my_gui.py
setup.py
\submodule1
__init__.py
one.py
\submodule2
__init__.py
two.py
My GUI imports submodule1 and submodule2, yet when I run my setup script they do not show up in the distribution, and the GUI quits with errors (ImportError: No module named submodule.one).
I'm thoroughly confused. The documentation says that py2exe should automatically discover imported modules and add them to the frozen binary. Since this doesn't seem to be happening, how can I explicitly force py2exe to include those submodules?
When I add submodule1 to the "includes" list in my setup.py file, the build breaks with this error: Import Error: "No module named submodule".
Any suggestions?
Update:
It looks like the problem was that I was actually keeping my setup script in a subdirectory, so I was running python scripts/setup.py. That seems to be what broke the imports. Oops.

Related

How do I use a setup.py entry point in my Python project with a subpackage?

So I'm working on a project (let's call it MyProject) which has a package (named "src") and a subpackage (let's call it ProjectData) within my src package. The project I'm working on is supposed to be a desktop application for a debain machine. The project tree looks like this:
MyProject/
setup.py
MyProject.desktop
src/
__init__.py
main.py
ProjectData/
__init__.py
module1.py
module2.py
module3.py
README.txt
My main.py file looks roughly like this:
from ProjectData.module1 import *
from ProjectData.module2 import *
from ProjectData.module3 import *
def main():
module1func()
module2func()
module3func()
if __name__ == "__main__":
main()
My setup.py file looks something like this:
from setuptools import setup
setup(
name='MyProject',
packages=['src','src.ProjectData'],
entry_points={'console_scripts':['MyCommand=src.main:main']},
...
along with arbitrary metadata like version, author, classifiers, etc. My MyProject.desktop file also lists "MyCommand" as its exec command, and I've had no issues with that. I've already tested the program a dozen times, and it works flawlessly when I run main.py.
My problem is, whenever I compile the project to a debian source file (.deb, using stdeb bdist_deb; no issues with that compilation either) and install it, the icon shows up on my desktop sure enough, but the program never launches, and when i run "MyCommand" in the terminal, I'm met with an error which eventually reaches:
...
from ProjectData.module1 import *
ModuleNotFoundError: no module named 'ProjectData'
I've tried everything I could think of, from specifying the package directory using
...
package_dir = {'src':'src/', 'src.ProjectData':'src/ProjectData/},
...
in my setup.py file, to importing the modules directly within main.py, but I always get the same ModuleNotFoundError (refering to my subpackage ProjectData).
I think it might have something to do with my entry point being specified in setup.py as the "main" function in main.py, but the function being called in some other program outside of the file structure, which throws off my calls to "ProjectData", but I'm not totally sure this is the case.
Can anyone help me with this? I've scoured the internet for answers but so far I've turned up empty-handed.

ModuleNotFoundError: No module named with virtualenv and need understanding how to structure it for production

I am trying to understand how python packages/modules work in virtualenv and how I can structure it for distribution .. I have getting this error: ModuleNotFoundError: No module named lib. I have a very simple project
Project/lib
- __init__.py
- calc.py
Project/tests
- __init__.py
- test_calc.py
I need to be able to access calc.py from the tests and it gives me this error when I import. I understand I should add the Project dir into the sys.path (I have also read the python docs). If I were to distribute this project what do I need to do to make sure the paths are added and the packages are ready to be consumed ?
do I need a Makefile or setup.py. There is so many things I am seeing and its a bit confusing. What is the best approach for production?
You are correct in saying that you should add the directory to the sys.path variable. Now, all you need to do is, depending on how your code is set up, import the main folder (lib), or import the calc file from lib

Module not found in same directory as running script when installed as a package

I have installed a custom package I made called pytable using python setup.py develop in the package folder. The package hierarchy looks like this:
pytable/
__pycache__/
MANIFEST.in
pytable/
__init__.py
__pycache__/
pytable.py (main module)
tableError.py (class with custom errors)
testScript.py (imports pytable.py)
README.md
setup.py
The tableError.py module is imported into the pytable.py module and works fine when running testScript.py without having pytable installed with python, but when I install it with the above command and run import pytable from pytable anywhere else it errors.
ModuleNotFoundError: No module named 'tableError'
The problem was after the package was installed Python did not know where to look to find depending modules. Adding...
import os
import sys
dir_path = os.path.dirname(os.path.realpath(__file__))
sys.path.append(dir_path)
...to the top of pytable.py tells Python to look in the same directory where it is installed for tableError.py.

Python3 relative imports failing in package

I've been reading tons of questions related to this matter but none of the has help me so far. I'm currently using the Python click library to execute scripts as commands.
The current command that I'm trying to execute is placed inside a Python Package which has a __main__.py file, like the parent dir has. The current project structure is the following one.
/myproject
/foo_one
__init__.py
foo_one.py
/foo_two
__init__.py
foo_two.py
/foo_three
__init__.py
foo_three.py
/foo_four
__init__.py
foo_four.py
/foo_five
__init__.py
foo_five.py
/foo_six
__init__.py
foo_six.py
__init__.py
__main__.py
foo_seven.py
Whenever I try to run the __main__.py script located in the project folder, the following error comes up.
ModuleNotFoundError: No module named '__main__.foo_two'; '__main__' is not a package
However, if I try to execute that same script from a folder above with the -m option like this python3 myproject -m, the following is shown up.
ImportError: attempted relative import with no known parent package
The __main__.py has 2 imports like this... The __init__.py is empty.
from .foo_two.foo_two import AClass, AnotherClass, OtherClass
from .foo_three.foo_three import AnotherClassMore
UPDATE: Correcting the syntax error in a previous command, while calling python -m myproject gives me a ModuleNotFoundError because of a module that isn't my responsibility, which is basically a library that is used in the project.
Hopefully, this will be of value to someone out there - I went through half a dozen stackoverflow posts trying to figure out relative imports similar to whats posted above here. I set up everything as suggested but I was still hitting ModuleNotFoundError: No module named 'my_module_name'
Since I was just developing locally and playing around, I hadn't created/run a setup.py file. I also hadn't apparently set my PYTHONPATH.
I realized that when I ran my code as I had been when the tests were in the same directory as the module, I couldn't find my module:
$ python3 test/my_module/module_test.py 2.4.0
Traceback (most recent call last):
File "test/my_module/module_test.py", line 6, in <module>
from my_module.module import *
ModuleNotFoundError: No module named 'my_module'
However, when I explicitly specified the path things started to work:
$ PYTHONPATH=. python3 test/my_module/module_test.py 2.4.0
...........
----------------------------------------------------------------------
Ran 11 tests in 0.001s
OK
So, in the event that anyone has tried a few suggestions, believes their code is structured correctly and still finds themselves in a similar situation as myself try either of the following if you don't just add your export the current directory to your PYTHONPATH:
Run your code and explicitly include the path like so:
$ PYTHONPATH=. python3 test/my_module/module_test.py
To avoid calling PYTHONPATH=., create a setup.py file with contents like the following and run python setup.py development to add packages to the path:
# setup.py
from setuptools import setup, find_packages
setup(
name='sample',
packages=find_packages()
)
The correct syntax would be
python -m myproject
This should execute __main__ in the top-level package.
You need to have __init__.py in each sub folder with python code to tell the interpreter to treat the folder as a module
/myproject
/foo_one
__init__.py # add this
foo_one.py
/foo_two
__init__.py # add this
foo_two.py
/foo_three
__init__.py # add this
foo_three.py
/foo_four
__init__.py # add this
foo_four.py
/foo_five
__init__.py # add this
foo_five.py
/foo_six
__init__.py # add this
foo_six.py
__init__.py
__main__.py
foo_seven.py
the __init__.py is telling the interpreter to treat sub folders as python modules / packages and you should be able to import
The __init__.py file can be empty but needs to be present in the sub folders to be able to import that module / package

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.
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
In my case, MacOS 12.x, I had some relative imports similar to this
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from utils import *
and I had a structure like this
dirA
utils.py
dirB
my_app.py
and the created .app file didn't work. The problem was that I was running pyinstaller from w/in dirB, where, the utils.py module couldn't be found by pyinstaller. The solution was to specify any paths from which my_app.py imported modules. This is possible either explicitly w/ option/flag -p of pyinstaller or implicitly, by running pyinstaller from dirA and adding __init__.py(empty) in dirB. Adding the __init__.py "forces" pyinstaller to extend PYTHONPATH by dirA and not dirB.

Categories

Resources