Multiple packages from same src using pyproject.toml

At $work, I played around with a very simple idea for building multiple different distribution packages from a single monorepo source. While I can’t share the code, I can explain it pretty easily. It’s just a PoC, and it’s really simple, but maybe it will be a workable solution while we figure out a better way. I built this on tox and pdm.

  • I created a subdirectory called scripts/ [1] and inside there I put multiple pyproject-{envname}.toml files. An example might be scripts/pyproject-build-foo.toml.
  • I added a top-level toxfile.py file and a simple tox plugin that implements a tox_on_install() hook [2].
  • Inside this hook, I dig out the environment name from toxenv.name. I look for a scripts/pyproject-{envname}.toml file that matches.
  • If found, I symlink the top-level pyproject.toml file to this environment-specific file [3].
  • I create a [testenv:build-foo] section that just called pdm build.

Now, all I have to do is run tox -e build-foo and it symlinks in the proper pyproject.toml file and builds the package quite nicely.

One downside is that you have to repeat a bunch of metadata in each pyproject-{envname}.toml file, but oh well. The nice thing is that I can say build a namespace distribution package that contains no code but only dependencies that all get installed when I install the namespace package. And I can build whatever collection of distribution packages from a single repo by just fiddling with pdm.build.excludes and pdm.build.includes and such.


  1. the name is unimportant ↩︎

  2. I originally tried tox_before_run_commands() hook but that does not get executed if you run tox with the -n flag ↩︎

  3. with some caveats, like top-level pyproject.toml must not exist or it must already be a symlink into scripts/, and if that does not exist, it falls back to symlinking to pyproject-default.toml ↩︎

2 Likes