Distribute 101As Cosmologicon mentioned a way of packaging - a bunch of files in a directory - that certainly works, I thought I'd discuss the way the Python community has built for packaging and installing software, including Pyweek games.
You probably know about pip. pip is the current system of choice for installing packages, and is more powerful than easy_install.Well, distribute is the current system of choice for packaging. It's largely backwards-compatible with previous systems setuptools and distutils. In fact, the Python package is called setuptools! Distribute gives you tons of features, but here are a few:
- Automatically package your project (to .tar.gz - what is called a source distribution, sdist)
- Installing the package installs dependencies from PyPI or other sources
- Packages can be installed with pip from a URL, such as the Pyweek project page, with all required dependencies
- You can upload your project to PyPI
- You can build other targets, including Windows Installer (for if you have Python pre-installed), Windows Executable (for those who don't), Debian, Redhat and so on. Some of these require plugins.
You're probably thinking "Man, I have to go through all the hassle of packaging this properly? Too much effort!" But really, it's just a copy-and-paste (and fill in the blanks) job.
First, structure your app right, something like
│ ├── data
│ ├── __init__.py
│ └── __main__.py
My preference is to not use holder directories like "gamelib" or "lib" or "src". But your game must be a package, not a bunch of modules in a directory. That's to say, all your Python source must be in a directory with a sensible name, with an __init__.py. And the data files must be within that directory too.
There's something else - run_game.py can go into your source distribution, but it won't be installed. Don't put functionality into it, or that functionality won't be available to your game once installed. run_game.py should contain just this:
from gamename.__main__ import main
And __main__.py should be the place where your game logic starts:
print "Your game starts here"
if __name__ == '__main__':
(You'll notice you can now run your game without run_game.py, by just running "python gamename"!)
The last thing you need is to be able to access files in data. This is rather easy now, just use pkg_resources (no os.path.join() - it's forward slashes all the way here):
from pkg_resources import resource_stream, resource_string
levels = resource_string(__name__, 'data/levels.txt')
sprite = pygame.image.load(resource_stream(__name__, 'data/sprite.png'))
So far, this is all standard Python trickery. Now comes distribute. All we do is create a setup.py in the root that describes some metadata about the game:
from setuptools import setup, find_packages
'gamename = gamename.__main__:main',
- packages are all the packages in your distribution. find_packages() walks the tree to find them for you, but you can also list them explicitly.
- install_requires are dependencies. These are downloaded from PyPI when the package is installed.
- package_data are the files your game needs.
- entry_points is used to install a script called gamename that just runs the main() function in __main__.py.
You also need to write a MANIFEST.in that states what files go into the sdist:
recursive-include gamename/data *
You can write this however you like - all you need to ensure is that your development crap doesn't go in, and all the files you want to distribute do go in.
And that's a wrap!
Building the source package:
python setup.py sdist
Installing the package (either directly or having downloaded it):
python setup.py install
Running the game, having installed the package :-D:
Installing the package directly from the intertubes:
pip install http://example.com/downloads/gamename-1.0.tar.gz
And this also works with virtualenv, so that you don't need to install the package system-wide:
python setup.py install
(log in to comment)