How to Package Your Python Code Without Setting Your Hair on Fire

Dorian Puła

Software Development Engineer @ Points

@dorianpula

The Problem

You want to:

The Promise

pip + virtualenv = ☺ + success!

mkvirtualenv venv
pip install my_cool_library

The Reality

Python packaging = ☹ + heartache

Here Be Dragons

_images/madhi_yusuf_packaging_talk.jpg

A Twisted History of Python Packaging - PyCon CA 2012 http://pyvideo.org/video/1601/twisted-history-of-python-packaging

Packaging Made Simple

A Simple Setup.py

from setuptools import setup, find_packages
setup(
    name='justcheckers',
    version='0.5.0',
    url='http://justcheckers.org/',
    license='GPL v3',
    author='Dorian Pula',
    author_email='dorian.pula@gmail.com',
    description='An advanced cross-platform checkers game.',

    install_requires=gather_requirements(),

    packages=find_packages(exclude=['tests']),
    include_package_data=True,

    classifiers=[ 'Development Status :: 3 - Alpha', ..., ],
)

Requirements

Use a requirements.txt

# User interface
PySide==1.2.2
Markdown==2.4.1
PyOpenGL>=3.0.0

# Core logic
enum34==0.9.19

Parsing Requirements

Homegrown

def gather_requirements():
    with open('requirements.txt') as req_file:
        raw_requirements = req_file.readlines()

    return [req.strip()
            for req in raw_requirements
            if req.strip() and not re.match('#|-(?!e)', req)]

Using PIP's API

import pip
def gather_requirements():
    return pip.req.parse_requirements('requirements.txt')

Manifests

Remember to include and check your MANIFEST.in

include requirements.txt
include assets
include setup.py
include docs/*.rst
exclude docs/*.html

Advanced Package & Tricks

Testing Packages

The Quick and Dirty Way

pip install -e .

The Proper Way

python setup.py sdist

mkdir dist/my_library && cp dist/my_library*.tar.gz dist/my_library

python -m SimpleHTTPServer 9000

mkvirtualenv new_venv

pip install --index-url=http://127.0.0.1:9000/dist my_library==0.1.2.3

Console Scripts

Adding a console command

entry_points={
    'console_scripts': [
        'justcheckers = justcheckers.app:main',
    ]
},

Packaging in Scripts

bin=['scripts/deploy.sh']

Advice On Using PIP and Setuptools APIs

Advice On Extending setup.py

More About Python Packaging

Thank You!