You should write a Python package

William E Fondrie, PhD

2021-03-04

View online: https://git.io/python-packaging

CC-BY

Outline

  • Why you should write a Python package.
  • How to write a Python package.
  • Ways to make your package better.

Why should you write a Python package?

To learn more about Python

Coming from R, I learned Python by translating a simple R package to Python.

To easily reuse code for multiple projects

I keep useful things in my personal wispy package.
https://github.com/wfondrie/wispy

For a talk:

import numpy as np
import matplotlib.pyplot as plt
from wispy import theme

pal = theme.talk(dark=True)

np.random.seed(42)
plt.figure()
plt.plot(np.random.randn(10))
plt.plot(np.random.randn(10) + np.arange(10))
plt.show()

theme.png

To easily reuse code for multiple projects

I keep useful things in my personal wispy package.
https://github.com/wfondrie/wispy

For a paper:

import numpy as np
import matplotlib.pyplot as plt
from wispy import theme

pal = theme.paper()

np.random.seed(42)
plt.figure()
plt.plot(np.random.randn(10))
plt.plot(np.random.randn(10) + np.arange(10))
plt.show()

theme.png

To easily reuse code for multiple projects

I keep useful things in my personal wispy package.
https://github.com/wfondrie/wispy

For a paper:

import numpy as np
import matplotlib.pyplot as plt
from wispy import theme

pal = theme.paper()

np.random.seed(42)
plt.figure()
plt.plot(np.random.randn(10))
plt.plot(np.random.randn(10) + np.arange(10))
plt.show()

theme_paper.png

To distribute software, so that folks can use it

  • Python packages are easy to install… most of the time.
  • A recent example for me is mokapot: https://github.com/wfondrie/mokapot
  • Install with pip or conda:

      # With conda:
      conda install -c bioconda mokapot
    
      # With pip:
      pip install mokapot
    

How do you write a Python package?

Let’s make a package together

  • We’ll make a package called inspired.
  • It will provide random inspirational messages on demand (for error and progress messages):

      import inspired
    
      try:
          assert 1 == 2
      except AssertionError:
          raise AssertionError(inspired.by_yoda())
    
      # AssertionError: Do or do not. There is no try.
    

The structure of our package

  • A package is little more than a collection of python scripts:

      inspired
      |- LICENSE
      |- README.md
      |- inspired
      |  |- __init__.py
      |  |- yoda.py
      |  `- (*.py files for other messages)
      |- pyproject.toml
      |- setup.cfg
      `- setup.py
    
  • Many details at https://packaging.python.org/tutorials/packaging-projects/

The README

  • Describes the package to whatever level of detail we want.
  • We’ll keep ours simple:

      # inspired
      Effortlessly inject inspirational messages into your Python code.
    

The LICENSE

  • There are a few open-source license to choose from.
  • Check out https://choosealicense.com/ for help.
  • We’ll use the MIT license for inspired.

The MIT License is short and to the point. It lets people do almost anything they want with your project, like making and distributing closed source versions.

pyproject.toml specifies configurations for build tools

setup.cfg defines your package metadata

setup.py is no longer necessary

  • setup.py is the legacy way to define what we did in pyproject.toml and setup.cfg.
  • However, it is needed to create editable installs, which are super useful!

      pip install -e .
    
  • Ours will be:

      import setuptools
    
      setuptools.setup()
    

__init__.py tells Python that a directory is a package

  • Things that are imported into __init__.py are easily available to users.
  • __init__.py can be empty.
  • Ours will be:

      from .yoda import by_yoda
    
  • Now we need to create a by_yoda() function in yoda.py

The other Python files define the package functionality

  • Each is referred to as a module.
  • Functions, classes, constants, etc that are imported by __init__.py are
    available at the top level of the package.
  • Others can be reached through their respective modules.

      import os
      os.path.isfile("blah.txt")
    

Let’s finish our package and see if it works.

https://github.com/wfondrie/inspired

How can you make your package better?

Documentation makes your package usable

  • Create beautiful docs: sphinx https://www.sphinx-doc.org/en/master/
  • Sphinx can generate documentation automatically from your Python docstrings!

      def add(x, y):
          """Add x and y.
    
          Calculate a simple sum between two numbers.
    
          Parameters
          ----------
          x : float
              The first number to add.
          y : float
              The second number to add.
    
          Returns
          -------
          float
              The sum of x and y.
          """
          return x + y
    

Tests verify that your package works

Linters standardize code style (and find problems)

Publish your package, so folks can use it!

Questions?