Repository navigation
build(python): evaluate uv_build as the build backend #3887
Description
Activity
- addedenhancementNew feature or requestNew feature or requesttriageMore information is neededMore information is needed
on Sep 17, 2026 This is a well-researched proposal and matches what's in the repo today. A few observations, plus a suggested path forward:
Confirmed current state
pyproject.tomlhas exactly the setuptools bits described:[build-system]→setuptools.build_meta,[tool.setuptools] py-modules = ["openc3pycli"], and[tool.setuptools.packages.find] include = ["openc3*"].setup.cfgis only theuniversal=0flag, as you said.MANIFEST.inonly addsLICENSE.mdandrecursive-include examples *.openc3pycli.pydeliberately lives outside theopenc3package — its docstring explains this is intentional, so thatOPENC3_NO_STOREcan be set beforeopenc3/__init__.py(and thereforeopenc3.environment) is imported. That constraint matters for your migration decision.
On the openc3pycli decision
Given that comment, moving
openc3pycli.pyunderopenc3/would need care — ifopenc3.pycli(or wherever it lands) is imported, Python will still executeopenc3/__init__.pyfirst as part of package initialization, which is exactly the ordering problem the current top-level placement avoids.The "make it a package" option (
openc3pycli/__init__.pyat the top level, sibling toopenc3/) preserves the existing import-order guarantee without changing behavior, and is likely the lower-risk choice. It only changes packaging layout (single-file module → package with one__init__.py), not where it lives relative toopenc3/__init__.py.If moving under
openc3/is still desired, theOPENC3_NO_STOREguard would need to move somewhere that runs beforeopenc3/__init__.py's side effects — that's a separate design question worth its own discussion, not something to fold into this ticket.Not verified (tool limit reached)
I wasn't able to read
.github/workflows/release.ymlin this pass to confirm the exactsetup-python/python -m buildblock, so I can't give you a verified diff for that file right now. The described change (dropsetup-python, replacepython -m buildwithuv build) is consistent with how the rest of the workflows useuv, but please have a maintainer confirm the exact YAML before merging.Suggested sequencing, matching your writeup:
- Land the
openc3pyclipackaging change (package-style, keeping it top-level) as its own PR. - Do the real sdist diff for
examples/**undersource-includevs.MANIFEST.in'srecursive-include examples *— don't skip this, since sdist contents affect what installs from source distributions. - Switch
pyproject.tomltouv_build, deletesetup.cfg, deleteMANIFEST.in, updaterelease.yml.
Given the level of detail already here, I'd suggest opening the PR with these steps — it looks like solid, self-contained work that an engineer can review quickly.
- addedpython:uvPull requests that update python:uv codePull requests that update python:uv code
on Sep 17, 2026
What is the use case or problem this feature would solve?
openc3/pythonbuilds with setuptools while the rest of its own toolchain is uv: the images runuv sync --frozen, CI runsuv run, anduv.lockis committed. The release job at.github/workflows/release.yml:62-69therefore sets up a second toolchain —setup-pythonpluspip install build— only to produce the wheel.Three files exist solely to serve that backend:
setup.cfg(which holds nothing but[bdist_wheel] universal=0, a Python 2 era flag),MANIFEST.in, and the[tool.setuptools]tables inpyproject.toml.Describe the solution you'd like
Move the build backend to uv_build. This config builds the package today, verified against uv 0.12.15:
One change has to land first. uv_build has no equivalent of setuptools
py-modules, soopenc3pycli.pycannot ship as a top-level single-file module. Naming it explicitly fails the build:Leaving it out builds cleanly but omits the file, so the
openc3pycli = "openc3pycli:main"console script installs and then fails on import. Either make it a package (openc3pycli/__init__.py) or move it underopenc3/. Both change the published module layout, so it wants its own decision rather than riding along with the backend swap.Then, with the switch:
MANIFEST.in'srecursive-include examples *tosource-include; uv_build ignoresMANIFEST.in.setup.cfg.python -m buildwithuv buildinrelease.yml, dropping thesetup-pythonstep.Additional context
Diffing the two wheels built from the same tree, the only content differences are
openc3pycli.pyand the legacytop_level.txt, both absent from the uv_build wheel. The remaining 28 differing entries are directory records uv_build writes and setuptools does not. The package is pure Python with no tracked data files underopenc3/, so nothing else depends on setuptools behavior.The sdists differ slightly around
examples/and need a real comparison before the switch, not a spot check.Two other pyprojects declare the setuptools backend:
openc3-cosmos-init/plugins/packages/openc3-cosmos-demo/pyproject.tomlandplaywright/fixtures/pw-test-pyproject.toml. Both setpackages = []because they exist only to declare dependencies, so neither needs a build backend at all —[tool.uv] package = falsewith no[build-system]covers that case. Out of scope here: howopenc3/bin/uvinstallconsumes those files has to be checked first.