From 61dcc06b7102b3bd997bdc12bdfb18e37415f4bb Mon Sep 17 00:00:00 2001 From: Jay Bazuzi Date: Sun, 1 Mar 2026 19:00:23 +0000 Subject: [PATCH 1/9] . e migrate from setup.py to build Co-Authored-By: Llewellyn Falco --- .github/workflows/publish_to_pypi.yml | 2 +- .gitignore | 2 ++ .mise.toml | 2 +- mypy.ini | 1 + pyproject.toml | 3 +++ requirements.dev.txt | 1 + setup/publish_approval_utilities.sh | 4 +++- setup/publish_approvaltests.sh | 6 ++++-- setup/publish_minimal.sh | 6 ++++-- setup/setup.approval_utilities.py | 5 +++++ setup/setup.minimal.py | 6 ++++++ setup/setup.publish.py | 8 ++++++-- setup/setup.py | 6 ++++++ test__mypy_accepts_our_packages.py | 29 ++++++++++++++------------- 14 files changed, 58 insertions(+), 23 deletions(-) create mode 100644 pyproject.toml diff --git a/.github/workflows/publish_to_pypi.yml b/.github/workflows/publish_to_pypi.yml index 09b2c0e2..01a0a846 100644 --- a/.github/workflows/publish_to_pypi.yml +++ b/.github/workflows/publish_to_pypi.yml @@ -20,7 +20,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install setuptools wheel twine + pip install build setuptools wheel twine - name: Determine version from git tag id: version run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT diff --git a/.gitignore b/.gitignore index 91d94902..cb13f8bf 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,5 @@ tests/approved_files/VerifyTests.test_verify_automatic_approval.approved.txt junit-reports/TEST-results.xml .ignore/ + +/setup.py diff --git a/.mise.toml b/.mise.toml index 297fc9c7..c601dadb 100644 --- a/.mise.toml +++ b/.mise.toml @@ -24,7 +24,7 @@ depends = ["pip-install"] [tasks.integration] run = "python test__mypy_accepts_our_packages.py" -depends = ["pip-install"] +depends = ["pip-install", "mypy", "lint"] [tasks.tidy_code] run = [ diff --git a/mypy.ini b/mypy.ini index 1e082493..ef1a27ff 100644 --- a/mypy.ini +++ b/mypy.ini @@ -15,6 +15,7 @@ exclude = (?x)( ^build/ | ^dist/ | ^setup/ | + ^setup\.py$ | ^\.tox/ | ^\.venv/ | ^venv.*/ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..9787c3bd --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" diff --git a/requirements.dev.txt b/requirements.dev.txt index 91eb4796..fd282d51 100644 --- a/requirements.dev.txt +++ b/requirements.dev.txt @@ -1,5 +1,6 @@ -r requirements.prod.txt -r requirements.test.txt +build ruff setuptools mypy diff --git a/setup/publish_approval_utilities.sh b/setup/publish_approval_utilities.sh index 4711d4a9..96a1a42f 100755 --- a/setup/publish_approval_utilities.sh +++ b/setup/publish_approval_utilities.sh @@ -1,5 +1,7 @@ #!/bin/sh -python setup/setup.approval_utilities.py sdist bdist_wheel +cp setup/setup.approval_utilities.py setup.py +python -m build . +rm setup.py twine upload --repository-url ${TWINE_REPOSITORY_URL} dist/* rm -r dist diff --git a/setup/publish_approvaltests.sh b/setup/publish_approvaltests.sh index e3bf217e..82b931f6 100755 --- a/setup/publish_approvaltests.sh +++ b/setup/publish_approvaltests.sh @@ -1,5 +1,7 @@ -#! /bin/sh +#!/bin/sh -python setup/setup.publish.py sdist bdist_wheel +cp setup/setup.publish.py setup.py +python -m build . +rm setup.py twine upload --repository-url ${TWINE_REPOSITORY_URL} dist/* rm -r dist diff --git a/setup/publish_minimal.sh b/setup/publish_minimal.sh index 28ddee00..60897c41 100755 --- a/setup/publish_minimal.sh +++ b/setup/publish_minimal.sh @@ -1,5 +1,7 @@ -#! /bin/sh +#!/bin/sh -python setup/setup.minimal.py sdist bdist_wheel +cp setup/setup.minimal.py setup.py +python -m build . +rm setup.py twine upload --repository-url ${TWINE_REPOSITORY_URL} dist/* rm -r dist diff --git a/setup/setup.approval_utilities.py b/setup/setup.approval_utilities.py index ac16bf75..2d8e9698 100644 --- a/setup/setup.approval_utilities.py +++ b/setup/setup.approval_utilities.py @@ -1,5 +1,10 @@ +import sys +from pathlib import Path from typing import Any, Dict +_setup_dir = Path(__file__).resolve().parent / "setup" +if _setup_dir.is_dir(): + sys.path.insert(0, str(_setup_dir)) from setup_utils import get_version from setuptools import find_packages, setup diff --git a/setup/setup.minimal.py b/setup/setup.minimal.py index 920b4542..497d69f1 100644 --- a/setup/setup.minimal.py +++ b/setup/setup.minimal.py @@ -1,3 +1,9 @@ +import sys +from pathlib import Path + +_setup_dir = Path(__file__).resolve().parent / "setup" +if _setup_dir.is_dir(): + sys.path.insert(0, str(_setup_dir)) from setup_utils import do_the_setup, get_requirements_from_file required = get_requirements_from_file("../requirements.prod.required.txt") diff --git a/setup/setup.publish.py b/setup/setup.publish.py index 12255b2d..74d25e35 100644 --- a/setup/setup.publish.py +++ b/setup/setup.publish.py @@ -1,6 +1,10 @@ -from setup_utils import get_requirements_from_file, get_version +import sys +from pathlib import Path -from setup import do_the_setup +_setup_dir = Path(__file__).resolve().parent / "setup" +if _setup_dir.is_dir(): + sys.path.insert(0, str(_setup_dir)) +from setup_utils import do_the_setup, get_requirements_from_file, get_version required = get_requirements_from_file("../requirements.prod.required.txt") required += get_requirements_from_file("../requirements.prod.extras.txt") diff --git a/setup/setup.py b/setup/setup.py index 898b464f..7ba8e48e 100644 --- a/setup/setup.py +++ b/setup/setup.py @@ -1,3 +1,9 @@ +import sys +from pathlib import Path + +_setup_dir = Path(__file__).resolve().parent / "setup" +if _setup_dir.is_dir(): + sys.path.insert(0, str(_setup_dir)) from setup_utils import do_the_setup, get_requirements_from_file required = get_requirements_from_file("../requirements.prod.required.txt") diff --git a/test__mypy_accepts_our_packages.py b/test__mypy_accepts_our_packages.py index 8d01e931..c15fb85a 100644 --- a/test__mypy_accepts_our_packages.py +++ b/test__mypy_accepts_our_packages.py @@ -1,35 +1,36 @@ +import glob import pathlib +import shutil import subprocess import sys import tempfile -import time import typing -from version import version_number - def main() -> None: for package_name, setup_file in [ ("approval_utilities", "setup/setup.approval_utilities.py"), ("approvaltests", "setup/setup.py"), ]: - build_number = str(int(time.time())) - _run_python_checked( - [ - setup_file, - "--quiet", - "bdist_wheel", - "--build-number", - build_number, - ] - ) + dist_dir = pathlib.Path("dist") + if dist_dir.exists(): + shutil.rmtree(dist_dir) + + shutil.copy2(setup_file, "setup.py") + try: + _run_python_checked(["-m", "build", "--wheel", "."]) + finally: + pathlib.Path("setup.py").unlink(missing_ok=True) + + wheel_files = glob.glob("dist/*.whl") + assert len(wheel_files) == 1, f"Expected 1 wheel, found {wheel_files}" _run_python_checked( [ "-m", "pip", "install", "--force-reinstall", - f"dist/{package_name}-{version_number}-{build_number}-py3-none-any.whl", + wheel_files[0], "--quiet", "--no-warn-script-location", ] From 15f3d179ae0f50b22ea5e8abba7bdc3144223fd5 Mon Sep 17 00:00:00 2001 From: Jay Bazuzi Date: Sun, 1 Mar 2026 19:04:33 +0000 Subject: [PATCH 2/9] . e clean mise Co-Authored-By: Llewellyn Falco --- .mise.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mise.toml b/.mise.toml index c601dadb..297fc9c7 100644 --- a/.mise.toml +++ b/.mise.toml @@ -24,7 +24,7 @@ depends = ["pip-install"] [tasks.integration] run = "python test__mypy_accepts_our_packages.py" -depends = ["pip-install", "mypy", "lint"] +depends = ["pip-install"] [tasks.tidy_code] run = [ From 61fc715e59bee2cb56c7d090496810c1d477ecfe Mon Sep 17 00:00:00 2001 From: Jay Bazuzi Date: Sun, 1 Mar 2026 19:08:41 +0000 Subject: [PATCH 3/9] . e quiet build Co-Authored-By: Llewellyn Falco --- test__mypy_accepts_our_packages.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test__mypy_accepts_our_packages.py b/test__mypy_accepts_our_packages.py index c15fb85a..9a491185 100644 --- a/test__mypy_accepts_our_packages.py +++ b/test__mypy_accepts_our_packages.py @@ -18,7 +18,7 @@ def main() -> None: shutil.copy2(setup_file, "setup.py") try: - _run_python_checked(["-m", "build", "--wheel", "."]) + _run_python_checked(["-m", "build", "--wheel", "."], quiet=True) finally: pathlib.Path("setup.py").unlink(missing_ok=True) @@ -48,12 +48,16 @@ def main() -> None: def _run_python_checked( - args: typing.List[str], cwd: typing.Optional[pathlib.Path] = None + args: typing.List[str], + cwd: typing.Optional[pathlib.Path] = None, + quiet: bool = False, ) -> None: subprocess.run( [sys.executable, *args], check=True, cwd=cwd, + stdout=subprocess.DEVNULL if quiet else None, + stderr=subprocess.DEVNULL if quiet else None, ) From 7e44494e561247721753cc81052e81e961ba442e Mon Sep 17 00:00:00 2001 From: Jay Bazuzi Date: Sun, 1 Mar 2026 19:19:54 +0000 Subject: [PATCH 4/9] . e tidy code Co-Authored-By: Llewellyn Falco --- tidy_code.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tidy_code.sh b/tidy_code.sh index b040afdf..aa82da00 100755 --- a/tidy_code.sh +++ b/tidy_code.sh @@ -2,3 +2,4 @@ set -euo pipefail mise task --quiet run tidy_code +git add --renormalize . \ No newline at end of file From d788396ffc4a2ab655a4079d194b6361ddb62ac8 Mon Sep 17 00:00:00 2001 From: Jay Bazuzi Date: Sun, 1 Mar 2026 19:20:25 +0000 Subject: [PATCH 5/9] . e tidy Co-Authored-By: Llewellyn Falco --- tidy_code.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tidy_code.sh b/tidy_code.sh index aa82da00..aba3c914 100755 --- a/tidy_code.sh +++ b/tidy_code.sh @@ -2,4 +2,4 @@ set -euo pipefail mise task --quiet run tidy_code -git add --renormalize . \ No newline at end of file +git add --renormalize . From dc9a126004fb5d2ab2c889a9177431469d1553f4 Mon Sep 17 00:00:00 2001 From: Jay Bazuzi Date: Sun, 1 Mar 2026 19:30:01 +0000 Subject: [PATCH 6/9] . t better progress message Co-Authored-By: Llewellyn Falco --- test__mypy_accepts_our_packages.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test__mypy_accepts_our_packages.py b/test__mypy_accepts_our_packages.py index 9a491185..50a39607 100644 --- a/test__mypy_accepts_our_packages.py +++ b/test__mypy_accepts_our_packages.py @@ -12,6 +12,7 @@ def main() -> None: ("approval_utilities", "setup/setup.approval_utilities.py"), ("approvaltests", "setup/setup.py"), ]: + print(f"Testing build {package_name} ...") dist_dir = pathlib.Path("dist") if dist_dir.exists(): shutil.rmtree(dist_dir) From 81c1ed646a1493e2fbf8ae922c4482626f5d2732 Mon Sep 17 00:00:00 2001 From: Jay Bazuzi Date: Sun, 1 Mar 2026 19:38:56 +0000 Subject: [PATCH 7/9] . t prevent file locking of setup.py workaround Co-Authored-By: Llewellyn Falco --- test__mypy_accepts_our_packages.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/test__mypy_accepts_our_packages.py b/test__mypy_accepts_our_packages.py index 50a39607..e6bc2066 100644 --- a/test__mypy_accepts_our_packages.py +++ b/test__mypy_accepts_our_packages.py @@ -4,6 +4,7 @@ import subprocess import sys import tempfile +import time import typing @@ -21,7 +22,7 @@ def main() -> None: try: _run_python_checked(["-m", "build", "--wheel", "."], quiet=True) finally: - pathlib.Path("setup.py").unlink(missing_ok=True) + _unlink_with_retry(pathlib.Path("setup.py")) wheel_files = glob.glob("dist/*.whl") assert len(wheel_files) == 1, f"Expected 1 wheel, found {wheel_files}" @@ -62,5 +63,19 @@ def _run_python_checked( ) +def _unlink_with_retry( + path: pathlib.Path, retries: int = 5, delay: float = 1.0 +) -> None: + for attempt in range(retries): + try: + path.unlink(missing_ok=True) + return + except PermissionError: + if attempt < retries - 1: + time.sleep(delay) + else: + raise + + if __name__ == "__main__": main() From 7cd1ba9c3a3faed84e68de7fba5c6bd119427205 Mon Sep 17 00:00:00 2001 From: Jay Bazuzi Date: Sun, 1 Mar 2026 19:45:50 +0000 Subject: [PATCH 8/9] . e linting error Co-Authored-By: Llewellyn Falco --- setup/setup.approval_utilities.py | 4 ++-- setup/setup.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/setup/setup.approval_utilities.py b/setup/setup.approval_utilities.py index 2d8e9698..948ccd0a 100644 --- a/setup/setup.approval_utilities.py +++ b/setup/setup.approval_utilities.py @@ -1,12 +1,12 @@ import sys from pathlib import Path from typing import Any, Dict +from setuptools import find_packages, setup _setup_dir = Path(__file__).resolve().parent / "setup" if _setup_dir.is_dir(): sys.path.insert(0, str(_setup_dir)) -from setup_utils import get_version -from setuptools import find_packages, setup +from setup_utils import get_version # pylint: disable=wrong-import-position requires: Dict[str, Any] = {} setup( diff --git a/setup/setup.py b/setup/setup.py index 7ba8e48e..9086aa53 100644 --- a/setup/setup.py +++ b/setup/setup.py @@ -4,7 +4,7 @@ _setup_dir = Path(__file__).resolve().parent / "setup" if _setup_dir.is_dir(): sys.path.insert(0, str(_setup_dir)) -from setup_utils import do_the_setup, get_requirements_from_file +from setup_utils import do_the_setup, get_requirements_from_file # pylint: disable=wrong-import-position required = get_requirements_from_file("../requirements.prod.required.txt") required += get_requirements_from_file("../requirements.prod.extras.txt") From 6a2c03b76e3f2f1a35e21d3d15c7f67cfd66eb38 Mon Sep 17 00:00:00 2001 From: Jay Bazuzi Date: Sun, 1 Mar 2026 19:51:33 +0000 Subject: [PATCH 9/9] . e cleanup so test mypi is actually the code we use Co-Authored-By: Llewellyn Falco --- setup/setup.py | 17 ----------------- test__mypy_accepts_our_packages.py | 2 +- 2 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 setup/setup.py diff --git a/setup/setup.py b/setup/setup.py deleted file mode 100644 index 9086aa53..00000000 --- a/setup/setup.py +++ /dev/null @@ -1,17 +0,0 @@ -import sys -from pathlib import Path - -_setup_dir = Path(__file__).resolve().parent / "setup" -if _setup_dir.is_dir(): - sys.path.insert(0, str(_setup_dir)) -from setup_utils import do_the_setup, get_requirements_from_file # pylint: disable=wrong-import-position - -required = get_requirements_from_file("../requirements.prod.required.txt") -required += get_requirements_from_file("../requirements.prod.extras.txt") - -do_the_setup( - package_name="approvaltests", - package_description="Assertion/verification library to aid testing", - required=required, - extra_requires={}, -) diff --git a/test__mypy_accepts_our_packages.py b/test__mypy_accepts_our_packages.py index e6bc2066..ec46ddb7 100644 --- a/test__mypy_accepts_our_packages.py +++ b/test__mypy_accepts_our_packages.py @@ -11,7 +11,7 @@ def main() -> None: for package_name, setup_file in [ ("approval_utilities", "setup/setup.approval_utilities.py"), - ("approvaltests", "setup/setup.py"), + ("approvaltests", "setup/setup.publish.py"), ]: print(f"Testing build {package_name} ...") dist_dir = pathlib.Path("dist")