Can't use PyInstaller to bundle a script that uses arcade-curtains with Python 3.7
Closed this issue · 6 comments
I've hit a bit of an esoteric issue here...
I'm trying to bundle Python scripts that use Arcade
into a an .exe with PyInstaller. Works great. But, if I have a script that also includes arcade-curtains, PyInstaller has a problem. I worked on getting a pretty simple reproduction case together, though it still is unfortunately lengthy. I've only tested this on Windows 10 with Python 3.7:
Create a directory to hold an app that relies on arcade-curtains
mkdir curtains_app
cd curtains_app
Create two files in curtains_app/ directory
setup.py:
import setuptools
setuptools.setup(
name="curtains_app",
version="0.0.0",
packages=setuptools.find_packages(),
py_modules=['myapp'],
install_requires=[
"arcade-curtains>=0.2.1",
"pyinstaller==4.0",
],
)
myapp.py:
import arcade
if __name__ == "__main__":
print("running myapp.py")
Note: Notice the app doesn't even import arcade-curtains, but arcade-curtains is installed into the venv because it is in the list of dependencies in install_requires
.
Create directory (myenv/) to hold virtual environment and PyInstaller artifacts
Create and activate fresh venv
cd ..
mkdir myenv
cd myenv
py -3.7 -m venv venv # could probably use `python -m venv venv`
venv\Scripts\activate
Use pip to install curtains_app project into active venv
pip install ..\curtains_app
Run manually to ensure app executes:
python -m myapp
(it runs fine)
Bundle app with PyInstaller and run it
pyinstaller venv\Lib\site-packages\myapp.py
dist\myapp\myapp.exe
When the app is run, it fails with:
<...snip...>
File "arcade\sprite.py", line 1058, in <module>
File "dataclasses.py", line 958, in dataclass
File "dataclasses.py", line 950, in wrap
File "dataclasses.py", line 801, in _process_class
File "dataclasses.py", line 801, in <listcomp>
File "dataclasses.py", line 659, in _get_field
File "dataclasses.py", line 550, in _is_classvar
AttributeError: module 'typing' has no attribute '_ClassVar'
[16064] Failed to execute script myapp
Clear out PyInstaller artifacts and manually uninstall dataclasses package to try again
rmdir /s /q build dist
del *.spec
pip uninstall dataclasses
pyinstaller venv\Lib\site-packages\myapp.py
dist\myapp\myapp.exe
With dataclasses
uninstalled, the PyInstaller bundle of the app now runs fine.
Summary
I'm not an expert on PyInstaller, but I'm guessing that the explicit dependency arcade-curtains has on dataclasses
(https://github.com/maarten-dp/arcade-curtains/blob/master/requirements.txt#L2) is what is causing this issue with Python 3.7. I think this extra dependency was a backport necessary for Python 3.6 (https://pypi.org/project/dataclasses/), but it seems to get in the way with Python 3.7? Odd that Python itself runs the script, but when bundled with PyInstaller it has an issue.
Any way to make this dependency conditional on what version of Python a client is using?
Hey SirGnip,
I can't tell you how happy I am someone is taking curtains for a thorough spin :)
Actually, curtains doesn't need a dependency on dataclasses, I've only added it because it's not a requirement in arcade itself. I've removed the dependency, as it's clearly doing more harm than good.
Thank you for bringing this to my attention as well as building a testcase to reproduce.
I'll try to take some time in the near future to actually try to reproduce and validate the removal of the dependency fixes the issue.
EDIT: I spoke too soon, will have to look into this a bit deeper :)
0.2.2 removes dataclasses as a dependency, and adds it to the dev dependencies only for python versions lower than 3.7
Thanks for the fix. I'll give it a whirl and report back.
Side question... I've not seen a repo before that has a requirements.txt file that is used at install time (when doing a pip install of arcacde-curtains). Is this standard setuptools behavior? I always thought dependencies had to be in install_requires
of setup.py (or use a special build tool). Is there any special config you had to do to set this up?
I'm using pbr. Packaging in python is still a painpoint in the language, but pbr comes very close to providing something sustainable.
I tried re-running my repro steps with 0.2.2 and the pyinstaller bundle ran properly! Thanks for the fix!
Regarding pbr, I recognized or googled everything in your setup.cfg, but just blew past "pbr" in setup.py somehow... and of course that was the important bit. Thanks for the pointer! Looks interesting...
Thank you for all your efforts!