7

I am currently writing a command line application in Python, which needs to be made available to end users in such a way that it is very easy to download and run. For those on Windows, who may not have Python (2.7) installed, I intend to use PyInstaller to generate a self-contained Windows executable. Users will then be able to simply download "myapp.exe" and run myapp.exe [ARGUMENTS].

I would also like to provide a (smaller) download for users (on various platforms) who already have Python installed. One option is to put all of my code into a single .py file, "myapp.py" (beginning with #! /usr/bin/env python), and make this available. This could be downloaded, then run using myapp.py [ARGUMENTS] or python myapp.py [ARGUMENTS]. However, restricting my application to a single .py file has several downsides, including limiting my ability to organize the code and making it difficult to use third-party dependencies.

Instead I would like to distribute the contents of several files of my own code, plus some (pure Python) dependencies. Are there any tools which can package all of this into a single file, which can easily be downloaded and run using an existing Python installation?

Edit: Note that I need these applications to be easy for end users to run. They are not likely to have pip installed, nor anything else which is outside the Python core. Using PyInstaller, I can generate a file which these users can download from the web and run with one command (or, if there are no arguments, simply by double-clicking). Is there a way to achieve this ease-of-use without using PyInstaller (i.e. without redundantly bundling the Python runtime)?

user200783
  • 13,722
  • 12
  • 69
  • 135
  • 3
    for the second (small) solution, why not use pip? – Janus Troelsen Jun 10 '14 at 14:25
  • 1
    You have very similar questions [here about Windows](http://stackoverflow.com/questions/2136837/process-to-convert-simple-python-script-into-windows-executable?rq=1) and [here in general](http://stackoverflow.com/questions/7156333/packaging-a-python-application?rq=1) – logc Jun 10 '14 at 14:28
  • You mention various platforms, but don't mention what they are. Is "sudo apt-get install package" easy enough for your end users? – berto Jun 14 '14 at 20:33
  • @berto: Ideally I would like to support all platforms on which Python itself is supported. – user200783 Jun 15 '14 at 06:09
  • 1
    "Are there any tools which can package all of this into a single file, which can easily be downloaded and run using an existing Python installation?" - Take the sources and zip them. You get a single file which can easily be downloaded and which runs in any existing compatible Python installation. :) – NoDataDumpNoContribution Jun 16 '14 at 12:23
  • How many complications and variants are you trying to solve? What if they have Python 2.6? 2.5? 3.4? 32-bit? 64-bit python? MacOS? HPUX? WinXP? Vista? Win8? Win3.1? WinServer without UI? Android? python installed for single user (instead of all users)? only platforms that PyInstaller supports? what kind of end users- power users? computer illiterate users? users that do or don't know how to install an app or how to install python? There's thousands of scenarios. What scenarios/people/environments/OS's do you want to target besides "all platforms"? – snapshoe Jun 18 '14 at 03:34
  • @Trilarion: Thank you for your comment. I found some more information about Python's ability to execute a zip file [here](http://bugs.python.org/issue1739468). Using a zip file in this way seems to work if I name my main module `__main__` and include my other files and dependencies. This can then be downloaded and run on any Python 2.7 installation using `python myapp.zip [ARGUMENTS]`. – user200783 Jun 18 '14 at 10:45
  • @Trilarion: Also, I see that it is possible to get `myapp.zip [ARGUMENTS]` to work on *nix by prepending `#! /usr/bin/env python` to the zip file (assuming the file has executable permission). It looks as though once [PEP 441](http://legacy.python.org/dev/peps/pep-0441/) is implemented, a command similar to `myapp.zip [ARGUMENTS]` will also work on Windows. (As an aside, Windows (7) Explorer seems unable to open zip files which have prepended data). – user200783 Jun 18 '14 at 10:46
  • 1
    @snapshoe: Assume end users have Python installed (perhaps it came with their system, perhaps they installed it themselves), and that they are sufficiently confident to run `python myapp.py [ARGUMENTS]` from the command line. In terms of environments, all I am looking for is a way to run a set of Python files (my own and third-party dependencies) as easily as if all of the files were concatenated into a single huge script. If a system can run the latter, I would like it to be able to run the former. – user200783 Jun 18 '14 at 13:17

2 Answers2

7

I don't like the single file idea because it becomes a maintenance burden. I would explore an approach like the one below.

I've become a big fan of Python's virtual environments because it allows you to silo your application dependencies from the OS's installation. Imagine a scenario where the application you are currently looking to distribute uses a Python package requests v1.0. Some time later you create another application you want to distribute that uses requests v2.3. You may end up with version conflicts on a system where you want to install both applications side-by-side. Virtual environments solve this problem as each application would have its own package location.

Creating a virtual environment is easy. Once you have virtualenv installed, it's simply a matter of running, for example, virtualenv /opt/application/env. Now you have an isolated python environment for your application. Additionally, virtual environments are very easy to clean up, simply remove the env directory and you're done.

You'll need a setup.py file to install your application into the environment. Say your application uses requests v2.3.0, your custom code is in a package called acme, and your script is called phone_home. Your directory structure looks like this:

acme/
    __init__.py
    models.py
    actions.py
scripts/
    phone_home
setup.py

The setup.py would look something like this:

from distutils.core import setup


install_requires = [
    'requests==2.3.0',
]

setup(name='phone_home',
      version='0.0.1',
      description='Sample application to phone home',
      author='John Doe',
      author_email='john@doe.com',
      packages=['acme'],
      scripts=['scripts/phone_home'],
      url='http://acme.com/phone_home',
      install_requires=install_requires,
)

You can now make a tarball out of your project and host it however you wish (your own web server, S3, etc.):

tar cvzf phone_home-0.0.1.tar.gz .

Finally, you can use pip to install your package into the virtual environment you created:

/opt/application/env/bin/pip install http://acme.com/phone_home-0.0.1.tar.gz

You can then run phone_home with:

/opt/application/env/bin/phone_home

Or create a symlink in /usr/local/bin to simply call the script using phone_home:

ln -s /opt/application/env/bin/phone_home /usr/local/bin/phone_home

All of the steps above can be put in a shell script, which would make the process a single-command install.

And with slight modification this approach works really well for development environments; i.e. using pip to install / reference your development directory: pip install -e . where . refers to the current directory and you should be in your project directory alongside setup.py.

Hope this helps!

berto
  • 8,215
  • 4
  • 25
  • 21
5

You could use pip as suggested in the comments. You need to create a MANIFEST.in and setup.py in your project to make it installable. You can also add modules as prerequisites. More info can be found in this question (not specific to Django):

How do I package a python application to make it pip-installable?

This will make your module available in Python. You can then have users run a file that runs your module, by either python path/run.py, ./path/run.py (with +x permission) or python -c "some code here" (e.g. for an alias).

You can even have users install from a git public reporitory, like this

pip install git+https://bitbucket.org/yourname/projectname.git

...in which case they also need git.

Community
  • 1
  • 1
Mark
  • 18,730
  • 7
  • 107
  • 130
  • 1
    You can also install a tarball of the application with pip; this eliminates the git requirement. For example: `pip install https://yourdomain.com/application.tar.gz` – berto Jun 13 '14 at 22:49