progfiguration.progfigbuild

Support for building pip and zipapp progfigsite packages

Classes

InjectedFile

A file to inject into the built package

ProgfigsitePythonPackagePreparer

A context manager which prepares for building a Python package.

Functions

generate_builddata_version_py(→ str)

Generate the contents of builddata_version.py

find_pyproject_root_from_package_path(→ pathlib.Path)

Find the project root containing a pyproject.toml from a package path

build_progfigsite_zipapp(progfigsite_filesystem_path, ...)

Build a .pyz zipapp progfigsite package

build_progfigsite_pip(→ pathlib.Path)

Build a pip package

Package Contents

class progfiguration.progfigbuild.InjectedFile

A file to inject into the built package

path: pathlib.Path

The path to the file relative to the package root.

contents: str

The contents of the file.

progfiguration.progfigbuild.generate_builddata_version_py(version: str, build_date: datetime.datetime) str

Generate the contents of builddata_version.py

progfiguration.progfigbuild.find_pyproject_root_from_package_path(package_path: progfiguration.progfigtypes.PathOrStr, traverse_max: int = 10) pathlib.Path

Find the project root containing a pyproject.toml from a package path

Look in the parent directories of the package path for a pyproject.toml file, and return the path to the directory containing it.

We assume that the project is using pyproject.toml rather than setup.py or setup.cfg.

Parameters:
  • package_path – The path to the package, eg “/path/to/progfigsite/src/progfigsite”

  • traverse_max – The maximum number of directories to traverse before giving up

Returns:

The path to the project root, eg “/path/to/progfigsite”

progfiguration.progfigbuild.build_progfigsite_zipapp(progfigsite_filesystem_path: pathlib.Path, progfigsite_modname: str, package_out_path: pathlib.Path, build_date: datetime.datetime | None = None, progfiguration_package_path: pathlib.Path | None = None, compression: int = zipfile.ZIP_STORED)

Build a .pyz zipapp progfigsite package

Parameters:
  • progfigsite_filesystem_path – The path to the progfigsite package, eg “/path/to/progfigsite”.

  • package_out_path – The path where the zipfile will be written.

  • build_date – The build date to embed in the zipapp. If None, the current UTC time will be used.

  • progfiguration_package_path – The path to the progfiguration package, eg “/path/to/progfiguration”. If None, the progfiguration package will be copied from the Python path. This will only work if progfiguration is installed via pip (probably in a venv, possibly editable with ‘pip install -e’)… it won’t work if you’re running progfiguration itself from a zipapp for some reason.

  • compression – The compression level to use for the zipapp file. This can be zipfile.ZIP_STORED (no compression) or zipfile.ZIP_DEFLATED (deflate compression). ZIP_STORED (the default) is faster.

Returns:

The path to the zipapp file, eg “/path/to/my_progfigsite.pyz”.

What this function does:

  • Zip up the contents of the site package.

  • Place them inside a subdirectory called ‘progfigsite’.

  • Add a __main__.py file to the root of the zip file.

  • Add the progfiguration package to the zip file.

  • Add a shebang to the beginning of the zip file.

Inspired by the zipapp module code <https://github.com/python/cpython/blob/3.11/Lib/zipapp.py>

We don’t use the zipapp code itself because we want more control over what goes into the zipfile, like ignoring __pycache__, *.dist-info, etc.

We don’t need the ProgfigsitePythonPackagePreparer context manager here, because we don’t need to inject build data into the filesystem before building the zipapp. We can inject the build data directly into the zipapp file.

class progfiguration.progfigbuild.ProgfigsitePythonPackagePreparer(progfigsite_filesystem_path: pathlib.Path, progfigsite_modname: str, build_date: datetime.datetime | None = None, progfiguration_package_path: pathlib.Path | None = None, injections: List[InjectedFile] | None = None, keep_injected_files: bool = False)

A context manager which prepares for building a Python package.

Preparation consists of finding the project path from the package path (see progfigsite_project_path and progfigsite_filesystem_path properties), and injecting build data into the filesystem like a version from progfigsite’s mint_version() and the build date. When the context manager exits, the injected files are removed.

You can use this to build a pip package with build and setuptools like this:

with ProgfigsitePythonPackagePreparer("/path/to/mysite", "mysite") as preparer:
    result = subprocess.run(
        ["python", "-m", "build", "-s", "-o", preparer.package_out_path.as_posix(), preparer.progfigsite_project_path.as_posix()],
        check=True,
        capture_output=True,
        cwd=preparer.progfigsite_project_path,
    )
built_package_path = result.stdout.read()

See the implementation of build_progfigsite_pip() for a more complete example.

If you want to modify the build in some way, or build another kind of package after we prepare the filesystem and inject build data, you can do that instead.

Can be used by progfigsite to do something with the result of python -m build, like build a package for another package manager.

progfigsite_filesystem_path

The filesystem path to the progfigsite package, eg /path/to/progfigsite/src/progfigsite

This PACKAGE directory should be the path to the Python package itself with an __init__.py. It should usually be inside the “src” subfolder of the PROJECT directory, which is the directory containing a pyproject.toml file.

See also: progfigsite_project_path.

progfiguration_package_path

The filesystem path to the progfiguration package, eg /path/to/progfiguration

build_date

The build date to inject into the package version metadata

keep_injected_files

If True, the injected files will be kept after the package is built.

progfigsite

The progfigsite module

progfigsite_modname

The name of the progfigsite module

inventory

The inventory submodule

minted_version: str

The version of the package we are building, generated by a call to the progfigsite’s mint_version()

progfigsite_project_path

The filesystem path to the progfigsite project, eg /path/to/progfigsite

This PROJECT directory should be the directory containing a pyproject.toml file. It should usually contain a “src” subfolder which contains a folder like “progfigsite” containing the Python PACKAGE itself.

This is the directory you should run python -m build from.

See also: progfigsite_filesystem_path.

progfiguration_staticinclude_path

The filesystem path to the progfiguration core package inside the progfigsite package

We inject a symlink to the progfiguration package into the progfigsite package so that progfiguration can find it when run from the pip package. (python -m build will dereference the symlink and include the actual progfiguration package in the pip package.)

injections

Build data we will inject into the filesystem before building the pip package

We always inject a version.py file containing the version and build date. We have to do this on disk before building the pip package; we can’t inject version metadata into the package after it’s built, because we need to know the version before we build the package.

Users may also inject other files if they want to with the injections argument.

__enter__()
__exit__(type, value, traceback)
progfiguration.progfigbuild.build_progfigsite_pip(progfigsite_filesystem_path: pathlib.Path, progfigsite_modname: str, package_out_path: pathlib.Path, build_date: datetime.datetime | None = None, progfiguration_package_path: pathlib.Path | None = None, keep_injected_files: bool = False) pathlib.Path

Build a pip package

Parameters:
  • progfigsite_filesystem_path – The path to the progfigsite package, eg “/path/to/progfigsite”.

  • package_out_path – The path where the zipfile will be written.

  • build_date – The build date to inject into the package. If None, the current date will be used.

  • progfiguration_package_path – The path to the progfiguration package, eg “/path/to/progfiguration”. If None, the progfiguration package will be copied from the Python path. This will only work if progfiguration is installed via pip (probably in a venv, possibly editable with ‘pip install -e’)… it won’t work if you’re running progfiguration itself from a zipapp for some reason.

  • keep_injected_files – If True, the injected files will be kept after the package is built. You will need to remove them manually. Intended for debugging.

Returns:

The path to the pip package, eg “/path/to/my_progfigsite/dist/my_progfigsite-0.1.0.tar.gz”