smallest python package stub for modern packaging (post-PEP517/8) that allows for editable installs with setuptools sans setup.py
Go to file
grym 0ee8e1c92d Formatting 2023-12-08 09:35:33 -05:00
template Include test example. Update docs. Improve makefile 2023-12-08 09:30:15 -05:00
tests Include test example. Update docs. Improve makefile 2023-12-08 09:30:15 -05:00
.gitignore First commit 2022-02-19 11:48:02 -05:00
.pre-commit-config.yaml Include test example. Update docs. Improve makefile 2023-12-08 09:30:15 -05:00
Makefile Include test example. Update docs. Improve makefile 2023-12-08 09:30:15 -05:00
README.org Formatting 2023-12-08 09:35:33 -05:00
pyproject.toml Include test example. Update docs. Improve makefile 2023-12-08 09:30:15 -05:00

README.org

MWE Modern Python Projects

This is the minimum working example that I know of for a python package structure post-PEP517/8 and with pip/setuptools now allowing editable installs without a setup.py.

Motivation

Python packaging can get very complicated. Sometimes it's easier to just have a working example you can copy from.

Do you have one or more python files that you've written and would sure like to use, but also find that:

  • "It works" in your IDE but when you run python elsewhere you get ModuleNotFound errors?
  • Someone has told you that your code "should be a package" so that "i can pip install it"?

and you're at loose ends about what to do next?

This worked example of a repo might help.

TL;DR

  • Put package information, build information, and entry points in pyproject.toml
  • You can now install (and in editable mode even!) your code and its python dependencies with pip.
  • You can make CLI entry points that act like normal programs
  • You can share your code with others, or include it as a dependency in other projects.

So what are these files?

convenience boilerplate

.gitignore
Makefile
.pre-commit-config.yaml
README.org

These files are optional: they are not required as far as python is concerned. They are conveniences for the developer that I have come around over the years to converging on. I develop almost exclusively on linux (distro largely agnostic) and macOS.

  • Using the lovely gitignore.io collection of recommended ignores, I've populated a .gitignore for python and common editors.
  • If you like to automate the creation of venvs and installation and whatnot with make, as I do, then the included Makefile may be useful.
  • Automatic code formatting with black and isort can be accomplished with .pre-commit-config.yaml if pre-commit is used.
  • And this file is Readme.org; choose a markup language of your preference.

package files

├── pyproject.toml
├── template
│   ├── __main__.py
│   └── __init__.py

pyproject.toml specifies everything pip needs to install a package, including its name and metadata, what dependencies it requires, what entry points to create, what extras may be available, and how it should be built. This information has historically (and may still be, if you like) spread across some combination of {pyproject.toml, setup.cfg, setup.py}. Following adoption of PEP517/517 by setuptools, though, you can ram it all into pyproject.toml.

template/ is the directory of the python package. The name of the package is template, it has two modules __init__ and __main__, and __main__ has one function main, which is configured as the entry point, and simply prints "Hello,world!".

  • __init__.py flags the directory template/ as a python package. You need to have this file in any package (read: directory) or sub-package.
  • __main__.py permits callers to invoke your code with python -m template; when that is done, the __main__.py module is executed. Consequently, it contains an if __name__ = "main"= test, which calls the same callable (the function main()) that the entrypoint specified in pyproject.toml does. Add as many other modules, packages, etc. as you like under template/.

tests

├── tests
│   ├── __init__.py
│   └── test_template.py

pytest is my preferred testing framework for python. It's listed as a development dependency in pyproject.toml.

  • tests live in a directory called tests
  • invoking ./venv/bin/pytest ./tests runs all python files inside tests whose filenames start with test_.
  • each function inside those files whose name begins with test_ is treated as an independent unit test and is run.
  • see ned batchelder's excellent pytest primer for more detail.