Project

General

Profile

Support #924

Updated by Daniel Curtis almost 7 years ago

I recently developed a Python 3.6 app and wanted to package it for distribution to other users. This is a guide on packaging a python app using setuptools. This project uses twisted as an example dependency and include additional folders inside the python module. 

 This guide uses Arch Linux as its development environment, use the appropriate package manager for your distribution.  

 For the purpose of this guide, the folder structure of the example app is as follows: 
 <pre> 
 /example-app 
  |__ /example-app 
       |-- __init__.py 
       |__ /main 
            |-- __init__.py 
            |-- main.py 
       |__ /templates 
            |-- main 
                  |-- index.html 
       |__ .. 
       |__ . 
  |-- setup.py 
  |-- README.txt 
 </pre> 

 h2. Prepare the Environment 

 * Since this requires setuptools, add it along with a couple other dependencies: 
 <pre> 
 pacman -S python3 python3-{pip,pkgconfig,setuptools,virtualenv} 
 </pre> 

 h2. Packaging the App 

 * First get a list of all the dependent modules for the app: 
 <pre> 
 pip freeze > requirements.txt 
 </pre> 

 * Then display the module depenencies for the next step: 
 <pre> 
 cat requirements.txt 
 </pre> 
 #* _Example_: 
 <pre> 
 attrs==17.4.0 
 Automat==0.6.0 
 constantly==15.1.0 
 hyperlink==17.3.1 
 incremental==17.5.0 
 six==1.11.0 
 Twisted==17.9.0 
 zope.interface==4.4.3 
 </pre> 

 * Then add the setup.py file if it does not already exist: 
 <pre> 
 vi setup.py 
 </pre> 
 #* And add the following, adjusting the package dependencies as necessary: 
 <pre><code class="python"> <pre> 
 from setuptools import setup 

 setup( 
     name='example-app', 
     version='0.1', 
     description='Just another example app', 
     author='Daniel Curtis', 
     author_email='support@example.com', 
     license='BSD-2-Clause', 
     packages=['example-app'], 
     install_requires=[ 
         'attrs==17.4.0', 
         'Automat==0.6.0', 
         'constantly==15.1.0', 
         'hyperlink==17.3.1', 
         'incremental==17.5.0', 
         'six==1.11.0', 
         'Twisted==17.9.0', 
         'zope.interface==4.4.3' 
     ], 
     zip_safe=False 
 ) 
 </code></pre> </pre> 

 * Create the source distribution file: 
 <pre> 
 python setup.py sdist 
 </pre> 

 Now a tar.gz file of the app has been created in the @dist/@ folder. 

 *WARNING*: By default the sdist function will not add files recursively. So when the app is installed via pip, the only files available will be python files in the example-app module folder, no subdirectories. 

 h2. Packaging Recursive Directories 

 Since this project has files in the @main@ and @templates@ subdirectories, having setuptools recurse through the module directory would be helpful. 

 * Edit the setup.py file: 
 <pre> 
 vi setup.py 
 </pre> 
 #* And add the @package_files()@ function and add the @package_data@ parameter to the @setup()@: 
 <pre><code class="python"> <pre> 
 from setuptools import setup 
 import os 


 def package_files(directory): 
     paths = [] 
     for (path, directories, filenames) in os.walk(directory): 
         for filename in filenames: 
             paths.append(os.path.join('..', path, filename)) 

     return paths 


 extra_files = [] 
 extra_files += package_files('example-app') 

 setup( 
     name='example-app', 
     version='0.1', 
     description='Just another example app.', 
     author='Daniel Curtis', 
     author_email='support@example.com', 
     license='BSD-2-Clause', 
     packages=['example-app'], 
     package_data={'': extra_files}, 
     install_requires=[ 
         'attrs==17.4.0', 
         'Automat==0.6.0', 
         'constantly==15.1.0', 
         'crc16==0.1.1', 
         'hyperlink==17.3.1', 
         'incremental==17.5.0', 
         'numpy==1.14.1', 
         'pyserial==3.4', 
         'six==1.11.0', 
         'Twisted==17.9.0', 
         'zope.interface==4.4.3' 
     ], 
     zip_safe=False 
 ) 
 </code></pre> </pre> 

 * Recreate the source distribution file: 
 <pre> 
 python setup.py sdist 
 </pre> 

 h2. Test Installing 

 * Create a virtualenv: 
 <pre> 
 mkdir -p ~/venv 
 virtualenv ~/venv/example-app 
 </pre> 

 * Activate the virtualenv: 
 <pre> 
 source ~/venv/example-app/bin/activate 
 </pre> 

 * Install the source distribution file: 
 <pre> 
 pip install dist/example-app-0.1.tar.gz 
 </pre> 

 h2. Uploading to PyPI 

 * Register an account with Python Packaging Index, following the instructions at the prompt: 
 <pre> 
 python setup.py register 
 </pre> 

 * Once registered, login to upload the source distribution file: 
 <pre> 
 python setup.py sdist upload 
 </pre> 

 h2. Resources 

 * https://marthall.github.io/blog/how-to-package-a-python-app/ 
 * http://docs.python-guide.org/en/latest/shipping/packaging/ 
 * https://www.digitalocean.com/community/tutorials/how-to-package-and-distribute-python-applications 
 * https://stackoverflow.com/questions/27664504/how-to-add-package-data-recursively-in-python-setup-py/27664856

Back