Compiling python project with Cx-Freeze - python

I'm trying to make and executable from a project I'm working on, to test it on a different computer, without requiring python installed.
I want to use cx freeze to build and exe file, and this is my project tree:
- Project
- objects
blocks.py
enemy.py
item.py
player.py
__init__.py
- scripts
camera.py
chunk_manager.py
__init__.py
- textures
- items
- player
- terrain
- UI
- void
index.py
__init__.py
main.py
settings.py
setup.py
map.json
As you can probably tell, this is a game.
Anyways, what I have done is executing just cxfreeze main.py --target-dir=./ dist and it generated a build directory with a lot of stuff in it.
It generated a linux executable, but thats fine, I want to test if I can make it python-independent first, and I'll solve the .exe part later.
So, I executed the file, and nothing happened. Then I tried running from the terminal and it said that it was missing the camera.py file. I went into the generated directory and I found out that cxfreeze had not copied that file. I tried moving in in there myself, but it did not work.
I started checking for other files, and I found out that only the textures had been copied.
I thought this was just because of the one line command I used, so I am now trying to make a setup.py file (as you can see in the file tree) but I am lost in how to import my custom packages (objects, scripts, and textures) and the files in the same directory as main.py
This is how my setup.py file looks like:
import sys
from cx_Freeze import setup, Executable
options = {
'build_exe': {
'includes': ['camera', 'chunk_manager'], 'path': sys.path + ['scripts']
}
}
setup(
name = "Void Boats",
version = "alpha0.1",
options = options,
executables = [Executable("main.py")])
I am not sure how would I put all the packages in the 'include' section, and I can't find anything on the internet that uses more than a simple file like helloworld.py, and the samples of cxfreeze on their github only show how to import files from one directory. Do I have to move everything into one single package and put all the files in the same 'include'? Or can I have one include for each package I have? Any help would be pretty much appreciated.
Edit: I'm running on ParrotSec 4.9 (Debian based)

Use "python -m setup.py build" on cmd, that will build exe.
Example setup with extra folders:
from cx_Freeze import setup, Executable
import sys
version = "0.0.6"
build_options = {
"packages": [],
"excludes": [],
"build_exe": "X:\\builds\\",
"include_files": ["Sequence_Sample/", "icons/"],
}
base = "Win32GUI" if sys.platform == "win32" else None
executables = [Executable("MainUIController.py", base=base, targetName="pym")]
setup(
name="Python Image Macro Project",
version=version,
description="Image Based macro project.",
options={"build_exe": build_options},
executables=executables,
)
Python 3.8 and later has problem with cx_freeze 6.1 - not copying python dll.
cx_freeze 6.2 is strongly recommended if that's the case.
You'll have to clone cx_freeze and build it, then install it to use 6.2.

Related

Error when trying to turn a python script using ursina into an executable

So I was using cx_Freeze in order to turn my python script using ursina into an executable but then this happened : Error
What am I supposed to do?
This is what my folder content and setup.py file looked like when I had the error : Content
Try to add 'ursina' to the packages list of the build_exe_options in the setup.py script.
EDIT: try also to add src to the include_files list of the build_exe_options:
build_exe_options = {'packages': ['ursina'], 'include_files': ['src']}
# ...
setup( name = ..., # complete!
...
options = {'build_exe': build_exe_options},
executables = [Executable(...)])
See the cx_Freeze documentation for further details.
From the original Ursina engine's folder copy the application.py file and in the build folder, you will find exe.win-amd64-3.9 folder , inside that there will be a folder named lib, inside that there will be ursina folder you have to paste it here (if you are using default download location then this is the application.py's path: C:\Users\welcome\AppData\Local\Programs\Python\Python39\lib\site-packages\ursina\application.py)

How to include only needed modules in pyinstaller?

I'm using pyinstaller to generate an .exe file for my single python file, but the size is more than 30MB and the startup is very slow. From what I have gathered is that pyinstaller by default bundles a lot of stuff that are not needed. Is there a way to make sure that pyinstaller figures out what is only needed and bundles only them? My import section on my script looks like this:
import datetime
import os
import numpy as np
import pandas as pd
import xlsxwriter
from tkinter import *
EDIT:
Or is there also a way to see the list of all modules it has bundled? So I can go through them and exclude the ones I don’t need.
For this you need to create a separate environment, because currently you are reading all the modules you have installed on your computer.
To create environment run commands
1 - if you don't have one, create a requirements.txt file that holds all packages that you are using, you could create one with:
pip freeze > requirements.txt
2 - create env folder:
python -m venv projectName
3 - activate the environment:
source projectName/bin/activate
4 - install them:
pip install -r requirements.txt
alternatively if you know you are using only wxpython you could just pip install wxpython
5 - then finally you can run pyinstaller on your main script with the --path arg as explained in this answer:
pyinstaller --paths projectName/lib/python3.7/site-packages script.py
I ended up using cx_Freeze in the end. It seems to work much better than py2exe or pyinstaller. I wrote setup.py file that looks like this:
import os
import shutil
import sys
from cx_Freeze import setup, Executable
os.environ['TCL_LIBRARY'] = r'C:\bin\Python37-32\tcl\tcl8.6'
os.environ['TK_LIBRARY'] = r'C:\bin\Python37-32\tcl\tk8.6'
__version__ = '1.0.0'
base = None
if sys.platform == 'win32':
base = 'Win32GUI'
include_files = ['am.png']
includes = ['tkinter']
excludes = ['matplotlib', 'sqlite3']
packages = ['numpy', 'pandas', 'xlsxwriter']
setup(
name='TestApp',
description='Test App',
version=__version__,
executables=[Executable('test.py', base=base)],
options = {'build_exe': {
'packages': packages,
'includes': includes,
'include_files': include_files,
'include_msvcr': True,
'excludes': excludes,
}},
)
path = os.path.abspath(os.path.join(os.path.realpath(__file__), os.pardir))
build_path = os.path.join(path, 'build', 'exe.win32-3.7')
shutil.copy(r'C:\bin\Python37-32\DLLs\tcl86t.dll', build_path)
shutil.copy(r'C:\bin\Python37-32\DLLs\tk86t.dll', build_path)
Any then one can either run python setup.py build_exe to generate an executable or python setup.py bdist_msi to generate an installer.
I don't think it can figure that out for you. If there are any specific modules taking a while to load, use the --exclude-module flag to list all the modules you want to exclude.
edit: this answer may have some more helpful info

CX_freeze with ruamel.yaml

I can't get CX_Freeze to include the package ruamel.yaml with the build_exe.
I've also tried adding it to the "packages" option like
build_exe_options = {
...
"packages": [
...
"ruamel.yaml",
...
]
...
}
cx_Freeze.setup(
...
executables=[cx_Freeze.Executable("pyhathiprep/__main__.py",
targetName="pyhathiprep.exe", base="Console")],
)
and I get
File "C:\Users\hborcher\PycharmProjects\pyhathiprep\.env\lib\site-packages\cx_Freeze\finder.py", line 350, in _ImportModule
raise ImportError("No module named %r" % name)
ImportError: No module named 'ruamel.yaml'
I've tried adding it to the "namespace_packages" like
build_exe_options = {
...
"namespace_packages": ["ruamel.yaml"]
...
}
cx_Freeze.setup(
...
executables=[cx_Freeze.Executable("pyhathiprep/__main__.py",
targetName="pyhathiprep.exe", base="Console")],
)
and I get
File "C:\Users\hborcher\PycharmProjects\pyhathiprep\.env\lib\site-packages\cx_Freeze\finder.py", line 221, in _FindModule
return None, module.__path__[0], info
TypeError: '_NamespacePath' object does not support indexing
What am I doing wrong?
The doc for ruamel.yaml clearly states that you have to use a recent version of pip and setuptools to install ruamel.yaml.
CX_Freeze is not calling pip, nor does it support installing from the (correctly pre-configured) .whl files. Instead it does seem to call setup() in a way of its own.
What you can try to do is create a ruamel directory in your source directory, then in that directory create an empty __init__.py file and yaml directory. In that yaml directory copy all of the .py files from an unpacked latest version of ruamel.yaml skipping setup.py and all of the other install cruft. Alternatively you can check those files out from Bitbucket, but then there is even more unnecessary cruft to deal with, and you run the slight risk of having a non-released intermediate version if you don't check out by release tag.
Once that works you'll have a "pure" Python version of ruamel.yaml in your frozen application.
If you are using yaml = YAML(typ='safe') or yaml = YAML(typ='unsafe') and you expect the speed up from the C based loader and dumper, then you should look at using the Windows .whl files provided on PyPI. They include the _ruamel_yaml.cpXY-win_NNN.pyd files. If you don't know your target (python and/or win32|win_amd64 you should be able to include all of them and ruamel.yaml will pick the right one when it starts (actually it only does from _ruamel_yaml import CParser, CEmitter and assumes the Python interpreter knows what to do).
Okay I figured out a solution. I think it might be a bug in CX_Freeze. If I pip install ruamel.base and ruamel.yaml cx_freeze seems to install everything correctly. This is true, even if I ask it to only include ruamel.yaml.
If I have both ruamel.base and ruamel.yaml installed, then this works...
build_exe_options = {
...
"namespace_packages": ["ruamel.yaml"]
...
}
cx_Freeze.setup(
...
executables=[cx_Freeze.Executable("pyhathiprep/__main__.py",
targetName="pyhathiprep.exe", base="Console")],
)
I had this same problem with azure. The issue is the way microsoft structured the azure package - you can import azure.something.something_else.module, but you can't import azure directly. cx_freeze needs to be able to find the folder azure (or in your case, the folder ruamel) directly, not just the subfolders.
I had to go to each directory under the azure folder that I was accessing and ensure there was an init.py file there. After that, cx_freeze was able to find it perfectly.
Another option would be to just directly copy the folder from a path that you know (direct link to your site-packages, or copy the ruamel directory into your program directory and copy it from there) into the build folder as part of your setup. I do this for things like my data files:
import shutil
shutil.copytree("icons","build/exe.win32-3.6/icons")

Create multiplatform installer in python

My project in python has many scripts in many files. General structure is
:
Project/
|-- bin/
|-- project
|--calculations
|--some scripts
|--mainApp
|--some scripts
|--interpolations
|--some scripts
|--more files
|--other scripts
|
|-- tests
|-- setup.py
|-- README
I have many imports like this
import bin.project.mainApp.MainAppFrame
My setup.py file is
from setuptools import setup, find_packages
setup(
name = 'Application to orifices',
version = '1.0',
author = "Michał Walkowiak",
author_email = "michal.walkowiak93#gmail.com",
description = "Application in python 3.4 with noSQL BerkleyDB",
packages = find_packages(),
entry_points={
'console_scripts': [
'PracaInzynierska = bin.project.mainApp.MainApp:__init__'
]
},
scripts = [
'bin/project/mainApp/__init__.py',
'bin/project/mainApp/MainApp.py',
'bin/project/mainApp/MainAppFrame.py',
'bin/project/informations/__init__.py',
'bin/project/informations/DisplayInformations.py',
'bin/project/informations/InformationsFrame.py',
'bin/project/calculations/Calculate.py',
'bin/project/calculations/UnitConversion.py',
'bin/project/databaseHandler/__init__.py',
'bin/project/databaseHandler/databaseHandler.py',
'bin/project/databaseMonitoring/__init__.py',
'bin/project/databaseMonitoring/DatabaseFrame.py',
'bin/project/databaseMonitoring/DisplayDatabase.py',
'bin/project/initializeGUI/__init__.py',
'bin/project/initializeGUI/CalculationsFrame.py',
'bin/project/initializeGUI/initGui.py',
'bin/project/interpolation/__init__.py',
'bin/project/interpolation/Interpolate.py',
'bin/project/orificeMethods/__init__.py',
'bin/project/orificeMethods/methodsToCountOrifice.py',
'bin/project/steamMethods/__init__.py',
'bin/project/steamMethods/methodToCountParamsSteam.py',
'bin/project/waterMethods/__init__.py',
'bin/project/waterMethods/methodsToCountParamsWater.py'
]
)
I use setup.py with
python3 setup.py bdist --formats=gztar
It's generate dist folder with tar.gz file but when I unpack it every script is in /bin folder. When I try to run MainApp.py by
python3 MainApp.py
I receive an error:
Traceback (most recent call last):
File "MainApp.py", line 7, in <module>
import bin.project.mainApp.MainAppFrame
ImportError: No module named 'bin'
When I change
import bin.project.mainApp.MainAppFrame
to
import MainAppFrame
it works but it doesn't in Pycharm where localy there are paths to every file.
Is there any option to generate istaller, which after unpack would have the same paths as the orginal project, or it always add all files to one folder?
Here is a solution I used, for a simple GUI (tkinter) program:
Windows: copy the Python folder and create a portable version, then launch the program by creating a shortcut i.e. python.exe ../foo/start.py. Use Nullsoft Installer to create the installation file that will take care of the links, directories and uninstall steps on Windows systems.
Linux: distribute the code, specify the dependencies, create a script that creates links for an executable. Of course, you can browse info on how to create your own package, i.e. for Debian.
All other: similar as for Linux.
That's one of the beauties of Python.

Making a standalone .exe file of a python script

I have a python script which contains:
tempBook = temp.Workbooks.Open("c:\users\CNAME\desktop\Template.xlsx")
Everything works fine but when I create a .exe of my script the Template.xlsx is not included in its 'build' folder, it needs Template.xlsx to be present on the desktop. I want to make a portable exe.
Is there any way so that it can be included in the build, and make a standalone exe without any dependencies?
You need to move the file to your package, and list it in your setup.py:
setup(
# ...
data_files = [('', ['Tempate.xlsx',])],
)
See the data_files documentation for py2exe, which includes a utility function for automating adding data files.
The files will be added in your app root. From your main script, you can determine your app root by using:
import os
try:
approot = os.path.dirname(os.path.abspath(__file__))
except NameError: # We are the main py2exe script, not a module
import sys
approot = os.path.dirname(os.path.abspath(sys.argv[0]))

Categories