Switch Djblets's packaging to pyproject.toml.
Review Request #14137 — Created Sept. 3, 2024 and submitted
Djblets has historically been a setuptools-based project, relying
heavily on the dynamic ability ofsetup.py
. Over the years, the Python
ecosystem has moved topyproject.toml
files, with pluggable build
backends. This has reached a point of maturity, andpip
will soon
remove support for installing either production or editable installs
from a legacy source tree.In theory, modernization requires just providing a
pyproject.toml
that
specifiessetuptools
as a build backend. A project can still use
setup.py
for the project definition and dynamic capabilities. However,
since packages are also now built in a virtualenv, it's become clear
that we needed to address about our packaging.We now use
pyproject.toml
to define most of the metadata of the
package. The build backend is then a specialization of
setuptools.build_meta
, living inbuild-backend.py
at the root of the
tree. This specializes a few things about our build process:
It uses all of Djblets's dependencies as build-system dependencies,
needed in order to build static media for the package.It builds the static media, including them in both sdist and wheel
distributions.It writes out a
package-requirements.txt
at build time with the
dependencies fromdjblets/dependencies.py
, which setuptools can
then consume. This is also bundled in the sdist.With this, we no longer need
setup.py
, and constrain all custom logic
tobuild-backend.py
.Some things to note:
python -m build .
will default to building an sdist and then a
wheel from that sdist, whereasbuild . -w
will build a wheel
straight from the tree. Due to differences in the prep stages, and
what's built from what, we need to micromanage some state (like
package-requirements.txt
) in different places.Other build backends (hatch, PDM, flit, and poetry) were evaluated
and discarded. These are great backends, but don't solve the core
problems we've had to work around out of the box, and sort of want to
manage more of the development and build process.setuptools
is a
known entity for us, and will be needed for extension packaging
anyway, so we're sticking with it.
Makefile
installs the package in editable-compat mode. This uses
standard.pth
files instead of newersetuptools
-based import
hooks, in order to allowmypy
andpyright
to find type
definitions. See https://github.com/python/mypy/issues/13392 and
https://github.com/pypa/setuptools/issues/3518.
Tested isolated builds in the following setups:
python -m build .
(builds sdist, then a wheel from the sdist)python -m build . -s
(builds sdist)python -m build . -w
(builds wheel)
Tested isolated editable installs using pip install -e .
and
non-isolated editable installs using pip install -e --no-build-isolation
and with make develop
.
Performed full tree diffs of generated wheels from ./setup.py bdist_wheel
(prior to this change) and both wheel-producing python -m build
methods.
Verified that all content was identical, with the exception of differences
in source map paths and some modern metadata for the package.
Summary | ID |
---|---|
47577360a1a78dbbb25249f077410668dfbc3372 |
Description | From | Last Updated |
---|---|---|
'from setuptools.build_meta import *' used; unable to detect undefined names Column: 1 Error code: F403 |
reviewbot | |
'setuptools.build_meta.*' imported but unused Column: 1 Error code: F401 |
reviewbot | |
'from setuptools.build_meta import *' used; unable to detect undefined names Column: 1 Error code: F403 |
reviewbot | |
'setuptools.build_meta.*' imported but unused Column: 1 Error code: F401 |
reviewbot |
- Change Summary:
-
- Added some better dependency checking in
build-media.py
. - Updated
Makefile
for Python version flexibility and to remove the--no-build-ioslation
. Thenode_modules
path being thrown away wasn't correct. It lives in the tree even for isolated builds.
- Added some better dependency checking in
- Description:
-
Djblets has historically been a setuptools-based project, relying
heavily on the dynamic ability of setup.py
. Over the years, the Pythonecosystem has moved to pyproject.toml
files, with pluggable buildbackends. This has reached a point of maturity, and pip
will soonremove support for installing either production or editable installs from a legacy source tree. In theory, modernization requires just providing a
pyproject.toml
thatspecifies setuptools
as a build backend. A project can still usesetup.py
for the project definition and dynamic capabilities. However,since packages are also now built in a virtualenv, it's become clear that we needed to address about our packaging. We now use
pyproject.toml
to define most of the metadata of thepackage. The build backend is then a specialization of setuptools.build_meta
, living inbuild-backend.py
at the root of thetree. This specializes a few things about our build process: -
It uses all of Djblets's dependencies as build-system dependencies,
needed in order to build static media for the package.
-
It builds the static media, including them in both sdist and wheel
distributions.
-
It writes out a
package-requirements.txt
at build time with the
dependencies fromdjblets/dependencies.py
, which setuptools can
then consume. This is also bundled in the sdist.
With this, we no longer need
setup.py
, and constrain all custom logicto build-backend.py
.Some things to note:
-
python -m build .
will default to building an sdist and then a
wheel from that sdist, whereasbuild . -w
will build a wheel
straight from the tree. Due to differences in the prep stages, and
what's built from what, we need to micromanage some state (like
package-requirements.txt
) in different places.
~ -
Editable installs (
pip install -e .
) default to being built in a
virtualenv and then installed. This means thatnode_modules
would
be created and thrown away, which isn't ideal. We can now do the
steps needed with amake develop
.
~ -
Other build backends (hatch, PDM, flit, and poetry) were evaluated
and discarded. These are great backends, but don't solve the core
problems we've had to work around out of the box, and sort of want to
manage more of the development and build process.setuptools
is a
known entity for us, and will be needed for extension packaging
anyway, so we're sticking with it.
- -
Other build backends (hatch, PDM, flit, and poetry) were evaluated
and discarded. These are great backends, but don't solve the core
problems we've had to work around out of the box, and sort of want to
manage more of the development and build process.setuptools
is a
known entity for us, and will be needed for extension packaging
anyway, so we're sticking with it.
-
- Commits:
-
Summary ID d403966b7a060a1dc15c7e15b45f8b49359a0911 89218a25e8f0fcbb508f9767c09c43fd74f9458c
- Change Summary:
-
pip install -e .
once again installs node dependencies, but won't build static media files. - Commits:
-
Summary ID 89218a25e8f0fcbb508f9767c09c43fd74f9458c df6333e4fc21e477910c8ec23adcc700407d2599
Checks run (2 succeeded)
- Change Summary:
-
Remove an
assert
that snuck in. - Commits:
-
Summary ID df6333e4fc21e477910c8ec23adcc700407d2599 c80f60e84f90cf9135837dcde4e2310e9ff1fee0
Checks run (2 succeeded)
- Change Summary:
-
Updated
Makefile
to install in compat editable mode, in order to allowmypy
andpyright
to work. - Description:
-
Djblets has historically been a setuptools-based project, relying
heavily on the dynamic ability of setup.py
. Over the years, the Pythonecosystem has moved to pyproject.toml
files, with pluggable buildbackends. This has reached a point of maturity, and pip
will soonremove support for installing either production or editable installs from a legacy source tree. In theory, modernization requires just providing a
pyproject.toml
thatspecifies setuptools
as a build backend. A project can still usesetup.py
for the project definition and dynamic capabilities. However,since packages are also now built in a virtualenv, it's become clear that we needed to address about our packaging. We now use
pyproject.toml
to define most of the metadata of thepackage. The build backend is then a specialization of setuptools.build_meta
, living inbuild-backend.py
at the root of thetree. This specializes a few things about our build process: -
It uses all of Djblets's dependencies as build-system dependencies,
needed in order to build static media for the package.
-
It builds the static media, including them in both sdist and wheel
distributions.
-
It writes out a
package-requirements.txt
at build time with the
dependencies fromdjblets/dependencies.py
, which setuptools can
then consume. This is also bundled in the sdist.
With this, we no longer need
setup.py
, and constrain all custom logicto build-backend.py
.Some things to note:
-
python -m build .
will default to building an sdist and then a
wheel from that sdist, whereasbuild . -w
will build a wheel
straight from the tree. Due to differences in the prep stages, and
what's built from what, we need to micromanage some state (like
package-requirements.txt
) in different places.
-
Other build backends (hatch, PDM, flit, and poetry) were evaluated
and discarded. These are great backends, but don't solve the core
problems we've had to work around out of the box, and sort of want to
manage more of the development and build process.setuptools
is a
known entity for us, and will be needed for extension packaging
anyway, so we're sticking with it.
+ -
Makefile
installs the package in editable-compat mode. This uses
standard.pth
files instead of newersetuptools
-based import
hooks, in order to allowmypy
andpyright
to find type
definitions. See https://github.com/python/mypy/issues/13392 and
https://github.com/pypa/setuptools/issues/3518.
-
- Commits:
-
Summary ID c80f60e84f90cf9135837dcde4e2310e9ff1fee0 47577360a1a78dbbb25249f077410668dfbc3372