python projects to use pyproject.toml (in detail)
@all In python 3.12 distutils is being removed and using pyproject.toml is
the modern way to specify a project - you can still have a setup.py as a
configuration file but pretty much any use of python setup.py ... has
apparently been deprecated for some time.
To learn about this I’ve updated the hatherleigh project (on a branch) to
use a pyproject.toml. I’ve done it in a way that is compatible with running
pip install -r requirements/local.txt or
pip install -r requirements/production.txt but the contents of those files
have changed a bit.
pyproject.toml is the only file needed to specify a distribution but you can
specify that it use requirements files for the dependencies - they have a
restricted syntax - no -e or -r lines and git repos and local apps must
have the <app name> @ <url to app> syntax.
Essentially what that means is I’ve made the production.txt and local.txt
files simply stubs that read other files and for the reasons outlined are
ignored by the pyproject.toml setup.
I’ve created a dev.txt (for development dependencies excluding the apps) and
a release.txt (for the apps used in production), the local apps which need
to be editable installs (the -e option) are read from a requirements file
called apps.txt but this needs the full path to the app (and have the syntax
<app-name> @ <full path to app> which we can’t put in the repo as that would
make it difficult to share projects.
My solution is create a apps.txt from the release.txt (that also has the
advantage that we only need to specify the apps once. I’ve created a branch
on toolbox make-scss-test-optional…
BTW: the branch started out as just a way to remove the new scss prompt when
using my release script as that script processes the scss and less scripts.
Hence the obscure name) that adds an option --create-apps-txt to kb.py to
create this file (and added requirements/apps.txt to .gitignore in the
hatherleigh project), I’ve also amended the create-venv script in
dev-scripts to create this file too if the project has a release.txt file.
I’ve amended the checks on the project to check if the project uses the
pyproject.toml file and in that case check the release.txt file rather
than production.txt. and since the local apps file is created from that it
does not check the local apps.
The production.txt file now looks like::
-r base.txt
-r release.txt
local.txt file now looks like::
-e .[dev]
-e.[dev] installs the project using the development dependencies specified
in the pyproject.toml file, which reads the dev dependencies from
requirements/base.txt, requirements/apps.txt and requirements/dev.txt.
The new files are - release.txt::
kb-base==0.3.37
kb-block==0.2.11
kb-login==0.2.34
kb-mail==0.1.87
dev.txt::
beautifulsoup4
black
django-debug-toolbar
django-extensions
factory-boy
freezegun
GitPython
pyOpenSSL
pytest-cov
pytest-django
pytest-mock
redis-dump-load
rich
semantic-version
walkdir
Werkzeug
apps.txt (generated using ~/dev/modules/toolbox/kb.py --create-apps-txt)
kb-base @ file:///home/patrick/dev/app/base
kb-block @ file:///home/patrick/dev/app/block
kb-login @ file:///home/patrick/dev/app/login
kb-mail @ file:///home/patrick/dev/app/mail
The pyproject.toml already existed in the hatherleigh project to configure
black. Setuptools will use this file if it exists and creates the
distribution slightly differently but does not use the modern config without
a [project] section. This parts of this file that are used by setuptools
now look like this:
[project]
name = "kb-hatherleigh"
description = "go.hatherleigh website"
dynamic = ["version", "dependencies", "readme", "authors", "classifiers", "optional-dependencies"]
[build-system]
requires = ["setuptools >= 61.0"]
build-backend = "setuptools.build_meta"
[tool.setuptools.dynamic]
dependencies = {file = ["requirements/base.txt"]}
optional-dependencies = {dev = {file = ["requirements/apps.txt", "requirements/dev.txt"]},production = {file = ["requirements/release.txt"]}}
The [build-system] specifies setuptools needs to be greater than 61, I’m not
exactly sure that that means when using on older versions of Ubuntu. I don’t
think it is an issue because you can install the latest version of setuptools
using pip install --upgrade setuptools. The dynamic list in the project
section essentially means those sections are created from the setup.py or as
specified in the [tools.setuptools.dynamic] section.
To install a project for development you can use pip install -e .[dev] or the
conventional method of pip install -r requirements/local.txt
To install in production you should be able to use
pip install <project name>[production]`
pip install -r requirements/production.txt`
We will need to change the commands that are run when we invoke
toolbox/kb.py --release as that makes some calls to
python setup.py ... see modernize-setup-py-project…
the changes I’ve made simply allow for the new requirements structure.
There are probably some changes we need to make to fabric as well.
I cannot see a way to make local dependencies (e.g. KB apps) editable installs
within a project using setuptools. If changes are made to an app the only
way I can see to incorporate these is to remove the build directory in the app
and run pip install -e .[dev](or pip install -r requirements/local.txt)
on the project. I’ve amended my set-branches script to remove the build
directory from the app if the branch would be checked out.
I’ve not deployed using this yet but hopefully it should still work with the current fabric setup.
I’ll obviously test that before and wait for your feedback before merging it into the main branch.