A Python Package
- Creating an installable package is the best way to share your code with other people.
- Python’s packaging tools are a complex mess.
- The first step in creating a package is to write a manifest describing its contents and how to build it.
- Packages can be installed locally for testing purposes before being distributed.
- Always use virtual environments when building and using packages.
Terms defined: boilerplate, semantic versioning, TOML
- Best way to distribute software and data is as a package someone can install
- Sadly, there still isn’t support for distributing lessons that way…
- Python’s packaging tools are a complex mess
- That was true over a decade ago and has only gotten worse
-
Show how to write a basic package
-
Boilerplate files
- Create
README
file explaining what the package is - Choose
LICENSE
that describes who can use it how - Use upper case names by convention so that case-sensitive
ls
will show them first
- Create
-
Create the source code
- Subdirectory called
invperc
contains all source code files - For us,
invperc/invperc.py
is invasion percolation andinvperc/grid.py
is the lazy grid - In a subdirectory so that tests, documentation, etc. can be in the repo beside it
- Subdirectory called
-
Make this a Python module
- Contains
__init__.py
to tell Python this is a module - That file defines
__version__
variable using semantic versioning - And imports things from other files in the directory that we want available to users as top-level imports
- Contains
"""Package file for invasion percolation."""
from .invperc import invperc # noqa: F401
__version__ = "0.2.0"
- Make it runnable
- Create
__main__.py
as command-line script return 0
tells the operating system there were no errors- Non-zero return code means something went wrong
- Create
"""Entry point for command-line execution."""
import argparse
import random
from . import invperc
DEPTH = 10 # default range of random values in grid
HEIGHT = 15 # default Y dimension of grid
WIDTH = 15 # default X dimension of grid
def main():
"""Main command-line driver for invasion percolation."""
parser = argparse.ArgumentParser()
parser.add_argument("--depth", type=int, default=DEPTH, help="random depth")
parser.add_argument("--height", type=int, default=HEIGHT, help="grid height")
parser.add_argument("--seed", type=int, required=True, help="RNG seed")
parser.add_argument("--width", type=int, default=WIDTH, help="grid width")
args = parser.parse_args()
random.seed(args.seed)
grid = invperc(args.width, args.height, args.depth)
print(grid)
return 0
if __name__ == "__main__":
main()
- Create
pyproject.toml
in root directory- TOML is yet another “human-readable” configuration file format
[project]
name = "invperc"
description = "Invasion Percolation"
readme = "README.md"
authors = [
{ name = "Greg Wilson", email = "gvwilson@third-bit.com" }
]
license = { text = "Hippocratic License" }
dependencies = ["pandas", "numpy"]
dynamic = ["version"]
[project.urls]
homepage = "https://third-bit.com/rsdx/"
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[tool.setuptools.dynamic]
version = {attr = "invperc.__version__"}
project
sectionname
of packagedescription
is short titlereadme
is the source of the README fileauthors
have names and email addresseslicense
is the name of the license, not the full textdependencies
is the packages this one needsdynamic
says “get this value from the code itself”
project.urls
sectionhomepage
is where to find documentation
build-system
(yes, hyphenated rather than.
-based subname)requires
is the tools needed to build (not to install)build-backend
is the tool used to create the package- Copy and paste
tool.setuptools.dynamic
is:- A tool-specific subsection…
- …for the
setuptools
tool… - …that provides a dynamic value flagged earlier
- That value is
invperc.__version__
- Originally wrote
[tool.setuptools.dynamic]
as[tools.setuptools.dynamic]
- Failed, but didn’t produce an error message
- Half of Python’s packaging tools are there to make up for shortcomings in the other half
- To build the package
python -m build
- Lots of output
-
Produces:
invperc.egg-info
with information about packagedist/invperc-0.2.0-py3-none-any.whl
anddist/invperc-0.2.0.tar.gz
for distribution
-
To build documentation from docstrings
pdoc --docformat google -o ./html invperc
- Note: please use
pdoc
rather thanpdoc3
- See this comment by the author of
pdoc
for the reasons
- See this comment by the author of