Skip to content

Commit 094e28d

Browse files
committed
Merge branch 'development' of https://github.com/pythonarcade/arcade into development
2 parents e45a756 + 070c7e8 commit 094e28d

File tree

1 file changed

+47
-20
lines changed
  • doc/tutorials/bundling_with_pyinstaller

1 file changed

+47
-20
lines changed

doc/tutorials/bundling_with_pyinstaller/index.rst

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Bundling a Game with PyInstaller
66
.. note::
77

88
You must have Arcade version 2.4.3 or greater and Pymunk 5.7.0 or greater
9-
for the instructions below to work.*
9+
for the instructions below to work.
1010

1111
You've written your game using Arcade_ and it is a masterpiece! Congrats! Now
1212
you want to share it with others. That usually means helping people install
@@ -64,7 +64,7 @@ Handling Data Files
6464

6565
When creating a bundle, PyInstaller first examines your project and automatically identifies nearly everything your project needs (a Python interpreter,
6666
installed modules, etc). But, it can't automatically determine what data files your game is loading from disk (images, sounds,
67-
maps). So, you must explicitly tell PyInstaller about these files and where they should put them in the bundle.
67+
maps). So, you must explicitly tell PyInstaller about these files and where it should put them in the bundle.
6868
This is done with PyInstaller's ``--add-data`` flag:
6969

7070
.. code-block:: bash
@@ -76,14 +76,34 @@ PyInstaller should include in the bundle. The item after the semicolon is the "d
7676
specifies where files should be placed in the bundle, relative to the bundle's root. In the example
7777
above, the ``stripes.jpg`` image is copied to the root of the bundle ("``.``").
7878

79-
One thing to keep in mind. When you are packaging your game in a PyInstaller bundle,
80-
you do not have control over what directory your executable will be run from. Therefore,
81-
it is best to use relative path names in your Python code when loading data files. That
82-
way your game will work no matter where people run the bundled executable from.
79+
After instructing PyInstaller to include data files in a bundle, you must make sure your code loads
80+
the data files from the correct directory. When you share your game's bundle, you have no control over what directory
81+
the user will run your bundle from. This is complicated by the fact that a one-file PyInstaller
82+
bundle is uncompressed at runtime to a random temporary directory and then executed from there. This document describes
83+
one simple approach that allows your code to execute and load files when running in a PyInstaller bundle AND also be
84+
able to run when not bundled.
8385

84-
Below are some examples that show a few common patterns of how data files can be bundled.
85-
The examples first show a code snippet that demonstrates how data is loaded, followed by the PyInstaller
86-
command to bundle it up.
86+
You need to do two things. First, the snippet below must be placed at the beginning of your script:
87+
88+
.. code-block:: python
89+
90+
if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
91+
os.chdir(sys._MEIPASS)
92+
93+
This snippet uses ``sys.frozen`` and ``sys._MEIPASS``, which are both set by PyInstaller. The ``sys.frozen`` setting
94+
indicates whether code is running from a bundle ("frozen"). If the code is "frozen", the working
95+
directory is changed to the root of where the bundle has been uncompressed to (``sys._MEIPASS``). PyInstaller often
96+
uncompresses its one-file bundles to a directory named something like: ``C:\Users\user\AppData\Local\Temp\_MEI123456``.
97+
98+
Second, once the code above has set the current working directory, all file paths in your code can be relative
99+
paths (ex: ``resources\images\stripes.jpg``) as opposed to absolute paths (ex:
100+
``C:\projects\mygame\resources\images\stripes.jpg``). If you do these two things and add data files to
101+
your package as demonstrated below, your code will be able to run "normally" as well as running in a bundle.
102+
103+
Below are some examples that show a few common patterns of how data files can be included in a PyInstaller bundle.
104+
The examples first show a code snippet that demonstrates how data is loaded (relative path names), followed by the
105+
PyInstaller command to copy data files into the bundle. They all assume that the ``os.chdir()`` snippet
106+
of code listed above is being used.
87107

88108
One Data File
89109
~~~~~~~~~~~~~
@@ -134,17 +154,19 @@ Although you can include every data file and directory with separate ``--add-dat
134154
that you write your game so that all of your data files are under one root directory, often named ``resources``. You
135155
can use subdirectories to help organize everything. An example directory tree could look like::
136156

137-
resources/
138-
|--- images/
139-
| |--- enemy.jpg
140-
| |--- player.jpg
141-
|--- sound/
142-
| |--- game_over.wav
143-
| |--- laser.wav
144-
|--- text/
145-
|--- names.txt
146-
147-
With this approach, it becomes easy to bundle all your data with just a single ``--add-data`` flag. You're code
157+
project/
158+
|--- game.py
159+
|--- resources/
160+
|--- images/
161+
| |--- enemy.jpg
162+
| |--- player.jpg
163+
|--- sound/
164+
| |--- game_over.wav
165+
| |--- laser.wav
166+
|--- text/
167+
|--- names.txt
168+
169+
With this approach, it becomes easy to bundle all your data with just a single ``--add-data`` flag. Your code
148170
would use relative pathnames to load resources, something like this:
149171

150172
.. code-block:: python
@@ -161,6 +183,11 @@ And, you would include this entire directory tree into the bundle like this:
161183
It is worth spending a bit of time to plan out how you will layout and load your data files in order to keep
162184
the bundling process simple.
163185

186+
The technique of handling data files described above is just one approach. If you want more control and flexibility
187+
in handling data files, learn about the different path information that is available by reading the
188+
`PyInstaller Run-Time Information <https://pyinstaller.readthedocs.io/en/stable/runtime-information.html>`_
189+
documentation.
190+
164191
Now that you know how to install PyInstaller, include data files, and bundle your game into an executable, you
165192
have what you need to bundle your game and share it with your new fans!
166193

0 commit comments

Comments
 (0)