Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Package a command line application for distribution?

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)?

like image 892
user200783 Avatar asked Jun 10 '14 14:06

user200783


People also ask

How do I package a command line?

Create your Command Line Script. Set-up files and folder structure for Packaging. Modify your setup.py file to incorporate your CLI scripts. Test your package before publishing and then Build.


2 Answers

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='[email protected]',
      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!

like image 166
berto Avatar answered Oct 17 '22 08:10

berto


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.

like image 28
Mark Avatar answered Oct 17 '22 06:10

Mark