From adfd21d14a5b5e049a7caa94ac7546cf0dbb5ff5 Mon Sep 17 00:00:00 2001 From: Mynhardt Burger Date: Mon, 9 Mar 2026 09:08:04 -0400 Subject: [PATCH 1/4] build: Replace setup.py with pyproject.toml using hatchling Replace the legacy setup.py/requirements.txt/Docker-based build and release pipeline with a modern pyproject.toml (PEP 621) configuration using hatchling as the build backend and uv as the package manager. Key changes: - pyproject.toml is the Python standard for declarative project metadata, replacing the imperative setup.py. It provides a single file for build system config, metadata, dependencies, and tool settings. - hatchling is used as the build backend with hatch-vcs for dynamic versioning derived from git tags, eliminating the RELEASE_VERSION env var. hatch-vcs wraps setuptools-scm under the hood: https://github.com/pypa/setuptools-scm - Dependencies are consolidated into pyproject.toml using dependency groups: runtime deps under [project.dependencies] and test tooling under [project.optional-dependencies] test. This replaces the separate requirements.txt and requirements_test.txt files and enables `uv sync --extra test` or `pip install .[test]`. - GitHub Actions workflows modernized to use uv directly instead of Docker multi-stage builds. Tests now run across a Python 3.9-3.13 matrix. Release workflow uses `uv build` (sdist + wheel) and `uv publish`. - Deleted obsolete files: setup.py, requirements.txt, requirements_test.txt, Dockerfile, ci/Dockerfile, ci/publish.sh, ci/release.sh. Co-Authored-By: Claude Opus 4.6 rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED Signed-off-by: Mynhardt Burger --- .github/workflows/release.yml | 16 ++++++---- .github/workflows/tests.yml | 22 ++++++++++---- .gitignore | 6 ++++ CONTRIBUTING.md | 9 ++---- Dockerfile | 56 ----------------------------------- ci/Dockerfile | 47 ----------------------------- ci/publish.sh | 24 --------------- ci/release.sh | 19 ------------ pyproject.toml | 36 ++++++++++++++++++++++ requirements.txt | 1 - requirements_test.txt | 2 -- setup.py | 35 ---------------------- 12 files changed, 71 insertions(+), 202 deletions(-) delete mode 100644 Dockerfile delete mode 100644 ci/Dockerfile delete mode 100755 ci/publish.sh delete mode 100755 ci/release.sh create mode 100644 pyproject.toml delete mode 100644 requirements.txt delete mode 100644 requirements_test.txt delete mode 100644 setup.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ccb14d4..79ebe7e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,15 +1,19 @@ -# This workflow runs the typescript implementation unit tests name: release on: release: types: [published] workflow_dispatch: {} jobs: - build: + publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Run release + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: astral-sh/setup-uv@v5 + - name: Build sdist and wheel + run: uv build + - name: Publish to PyPI + run: uv publish env: - PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} - run: REF="${{ github.ref }}" ./ci/release.sh + UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 783dea1..33f56f7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,15 +1,25 @@ -# This workflow runs the typescript implementation unit tests name: tests on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] workflow_dispatch: {} jobs: - build: + test: runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: astral-sh/setup-uv@v5 - name: Run unit tests - run: docker build . --target=test + run: > + uv run --python ${{ matrix.python-version }} --extra test + pytest + --cov=aconfig + --cov-report=term + --disable-pytest-warnings diff --git a/.gitignore b/.gitignore index 894a44c..c635ff6 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,9 @@ venv.bak/ # mypy .mypy_cache/ + +# uv +uv.lock + +# claude code +.claude/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2124d4a..c60d4f4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -46,21 +46,18 @@ Improvements to existing functionality are tracked as [GitHub issues using the U ## Development -### Set up your dev environments +### Set up your dev environment ```sh -pip install -r requirements.txt -pip install -r requirements_test.txt -python setup.py develop +uv sync --extra test ``` ### Run unit tests ```sh -./ci/run_tests.sh +uv run pytest ``` - ## Your First Code Contribution Unsure where to begin contributing? You can start by looking through these issues: diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 407efc4..0000000 --- a/Dockerfile +++ /dev/null @@ -1,56 +0,0 @@ -## Base ######################################################################## -# -# This phase sets up dependencies for the other phases -## -FROM python:3.6-slim as base - -# This image is only for building, so we run as root -WORKDIR /src - -# Install build, test, andn publish dependencies -COPY requirements*.txt /src/ -RUN true && \ - pip install pip --upgrade && \ - pip install twine && \ - pip install -r /src/requirements.txt && \ - pip install -r /src/requirements_test.txt && \ - true - -## Test ######################################################################## -# -# This phase runs the unit tests for the library -## -FROM base as test -COPY . /src -RUN true && \ - ./ci/run-tests.sh && \ - RELEASE_DRY_RUN=true RELEASE_VERSION=0.0.0 \ - ./ci/publish.sh && \ - true - -## Release ##################################################################### -# -# This phase builds the release and publishes it to pypi -## -FROM test as release -ARG PYPI_TOKEN -ARG RELEASE_VERSION -ARG RELEASE_DRY_RUN -RUN ./ci/publish.sh - -## Release Test ################################################################ -# -# This phase installs the indicated version from PyPi and runs the unit tests -# against the installed version. -## -FROM base as release_test -ARG RELEASE_VERSION -ARG RELEASE_DRY_RUN -COPY ./test /src/test -COPY ./ci/run-tests.sh /src/ci/run-tests.sh -RUN true && \ - ([ "$RELEASE_DRY_RUN" != "true" ] && sleep 30 || true) && \ - pip cache purge && \ - pip install alchemy-config==${RELEASE_VERSION} && \ - ./ci/run-tests.sh && \ - true diff --git a/ci/Dockerfile b/ci/Dockerfile deleted file mode 100644 index 1489adf..0000000 --- a/ci/Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -FROM python:3.7-slim as base - -#-- Wheel ---------------------------------------------------------------------- -FROM base as wheel - -COPY aconfig /src/aconfig -COPY setup.py /src/ -COPY README.md /src/ -COPY LICENSE /src/ -COPY requirements.txt /src/ -WORKDIR /src - -RUN python3 setup.py bdist_wheel - -#-- Test ----------------------------------------------------------------------- -FROM base as test - -COPY requirements_test.txt /src/requirements_test.txt -COPY --from=wheel /src/dist/aconfig-*-py3-none-any.whl /src/dist/ -RUN pip3 install /src/dist/aconfig-*-py3-none-any.whl \ - && pip3 install -r /src/requirements_test.txt - -COPY test/* /src/test/ -COPY ci/run-tests.sh /src/ci/run-tests.sh - -RUN /src/ci/run-tests.sh - -#-- Publish -------------------------------------------------------------------- -FROM wheel as publish - -# Set up the env to publish to the local artifactory repo -ARG ARTIFACTORY_REPOSITORY=https://na.artifactory.swg-devops.com/artifactory/api/pypi/wcp-nlp-pypi-virtual -ARG ARTIFACTORY_USERNAME -ARG ARTIFACTORY_API_KEY - -# Create the .pypirc file to allow remote pushes -# -# NOTE: This build target should NEVER be pushed to a registry since it contains -# personal credentials -RUN echo "[distutils]\n\ -index-servers = local\n\ -[local]\n\ -repository: ${ARTIFACTORY_REPOSITORY}\n\ -username: ${ARTIFACTORY_USERNAME}\n\ -password: ${ARTIFACTORY_API_KEY}\n\ -" > $HOME/.pypirc -RUN python3 setup.py sdist bdist_wheel upload -r local diff --git a/ci/publish.sh b/ci/publish.sh deleted file mode 100755 index 87805fa..0000000 --- a/ci/publish.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -# Run from the base of the python directory -cd $(dirname ${BASH_SOURCE[0]})/.. - -# Clear out old publication files in case they're still around -rm -rf build dist alchemy_config.egg-info/ - -# Build -python setup.py sdist bdist_wheel - -# Publish to PyPi -if [ "${RELEASE_DRY_RUN}" != "true" ] -then - twine upload \ - --username "__token__" \ - --password "$PYPI_TOKEN" \ - dist/* -else - echo "Release DRY RUN" -fi - -# Clean up -rm -rf build dist alchemy_config.egg-info/ diff --git a/ci/release.sh b/ci/release.sh deleted file mode 100755 index 1cb5ec6..0000000 --- a/ci/release.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -# Run from the project root -cd $(dirname ${BASH_SOURCE[0]})/.. - -# Get the tag for this release -tag=$(echo $REF | cut -d'/' -f3-) - -# We explicitly don't want to run with buildkit so that the docker builds happen -# in a linear fashion since our `release_test` stages intentionally don't -# inherit from the stages where the publication happens. -export DOCKER_BUILDKIT=0 - -# Build the docker phase that will release and then test it -docker build . \ - --target=release_test \ - --build-arg RELEASE_VERSION=$tag \ - --build-arg PYPI_TOKEN=${PYPI_TOKEN:-""} \ - --build-arg RELEASE_DRY_RUN=${RELEASE_DRY_RUN:-"false"} diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b4b2564 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,36 @@ +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" + +[project] +name = "alchemy-config" +dynamic = ["version"] +description = "Configuration framework in Python for general configuration use." +readme = "README.md" +license = "MIT" +requires-python = ">=3.9" +authors = [ + { name = "Gabe Goodhart", email = "gabe.l.hart@gmail.com" }, +] +keywords = ["config"] +dependencies = [ + "PyYAML>=5.3.1", +] + +[project.urls] +Homepage = "https://github.com/IBM/alchemy-config" + +[project.optional-dependencies] +test = [ + "pytest>=5.3.2", + "pytest-cov>=2.9.0", +] + +[tool.hatch.version] +source = "vcs" + +[tool.hatch.build.targets.sdist] +include = ["aconfig/", "LICENSE", "README.md"] + +[tool.hatch.build.targets.wheel] +packages = ["aconfig"] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 1bae8cc..0000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -PyYAML>=5.3.1 diff --git a/requirements_test.txt b/requirements_test.txt deleted file mode 100644 index 5d5c861..0000000 --- a/requirements_test.txt +++ /dev/null @@ -1,2 +0,0 @@ -pytest>=5.3.2 -pytest-cov>=2.9.0 diff --git a/setup.py b/setup.py deleted file mode 100644 index 53c0a64..0000000 --- a/setup.py +++ /dev/null @@ -1,35 +0,0 @@ -#*****************************************************************# -# (C) Copyright IBM Corporation 2020. # -# # -# The source code for this program is not published or otherwise # -# divested of its trade secrets, irrespective of what has been # -# deposited with the U.S. Copyright Office. # -#*****************************************************************# - -import os -from setuptools import setup, find_packages - -with open(os.path.join(os.path.abspath(os.path.dirname(__file__)), "README.md")) as f: - long_description = f.read() - -with open(os.path.join(os.path.abspath(os.path.dirname(__file__)), "requirements.txt")) as f: - requirements = f.readlines() - -# Read version from the env -version = os.environ.get("RELEASE_VERSION") -assert version is not None, "Must set RELEASE_VERSION" - -setup( - name="alchemy-config", - version=version, - description="Configuration framework in Python for general configuration use.", - long_description_content_type="text/markdown", - long_description=long_description, - url="https://github.com/IBM/alchemy-config", - author="Gabe Goodhart", - author_email="gabe.l.hart@gmail.com", - license="MIT", - keywords="config", - packages=["aconfig"], - install_requires=requirements, -) From 416543a6ed9330d533a4bb636fa1ba178f3d543e Mon Sep 17 00:00:00 2001 From: Mynhardt Burger Date: Mon, 9 Mar 2026 09:15:35 -0400 Subject: [PATCH 2/4] build: Remove unused ci/run-tests.sh No longer referenced by any workflow or Dockerfile. Local testing is done with `uv run pytest`. Co-Authored-By: Claude Opus 4.6 rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED Signed-off-by: Mynhardt Burger --- ci/run-tests.sh | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100755 ci/run-tests.sh diff --git a/ci/run-tests.sh b/ci/run-tests.sh deleted file mode 100755 index 2a0332b..0000000 --- a/ci/run-tests.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -set -e -BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -cd "$BASE_DIR" - -python3 -m pytest \ - --cov=aconfig \ - --cov-report=term \ - --cov-report=html \ - --disable-pytest-warnings "$@" From 84a0ebaa1b92b383af60ef3a980f7987b77dce22 Mon Sep 17 00:00:00 2001 From: Mynhardt Burger Date: Mon, 9 Mar 2026 11:04:46 -0400 Subject: [PATCH 3/4] implement review comments Signed-off-by: Mynhardt Burger rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED --- .github/workflows/tests.yml | 7 +------ pyproject.toml | 10 +++++++++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 33f56f7..019c949 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,9 +17,4 @@ jobs: fetch-depth: 0 - uses: astral-sh/setup-uv@v5 - name: Run unit tests - run: > - uv run --python ${{ matrix.python-version }} --extra test - pytest - --cov=aconfig - --cov-report=term - --disable-pytest-warnings + run: uv run --python ${{ matrix.python-version }} --extra test pytest diff --git a/pyproject.toml b/pyproject.toml index b4b2564..7981b0b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ readme = "README.md" license = "MIT" requires-python = ">=3.9" authors = [ - { name = "Gabe Goodhart", email = "gabe.l.hart@gmail.com" }, + { name = "Gabe Goodhart", email = "ghart@us.ibm.com" }, ] keywords = ["config"] dependencies = [ @@ -26,6 +26,14 @@ test = [ "pytest-cov>=2.9.0", ] +[tool.pytest.ini_options] +addopts = [ + "--cov=aconfig", + "--cov-report=term", + "--cov-report=html", + "--disable-pytest-warnings", +] + [tool.hatch.version] source = "vcs" From 92d743341e449a755094cf1d0915cab92d1e2707 Mon Sep 17 00:00:00 2001 From: Mynhardt Burger Date: Mon, 9 Mar 2026 11:22:17 -0400 Subject: [PATCH 4/4] Include python 3.14 for tests Signed-off-by: Mynhardt Burger rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 019c949..fe1ad7a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] steps: - uses: actions/checkout@v4 with: