From c4cf8fb259eeac1d99a29f5e06bebb684e3efd66 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 15 Jan 2025 13:41:30 +0100 Subject: [PATCH 1/5] Update pytest.yaml - Set up python with astral-sh/setup-uv instead of actions/setup-python. - Add --durations=20 -ra to pytest options. - Drop CODECOV_TOKEN. --- .github/workflows/pytest.yaml | 37 ++++++++++++++++------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index 7c4e9b23..92886402 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -8,8 +8,7 @@ on: schedule: - cron: "0 5 * * *" -# Cancel previous runs that have not completed -concurrency: +concurrency: # Cancel previous runs that have not completed group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true @@ -51,31 +50,30 @@ jobs: with: fetch-depth: ${{ env.depth }} - - uses: actions/setup-python@v5 + - name: Set up uv, Python + uses: astral-sh/setup-uv@v5 with: + cache-dependency-glob: "**/pyproject.toml" python-version: ${{ matrix.python.version }} - cache: pip - cache-dependency-path: "**/pyproject.toml" - uses: ts-graphviz/setup-graphviz@v2 with: macos-skip-brew-update: true - - name: Install the Python package and dependencies - run: pip install --upgrade --upgrade-strategy=eager .[tests] ${{ matrix.python.extras }} + - name: Install the package and dependencies + run: uv pip install .[tests] ${{ matrix.python.extras }} - - name: Run test suite using pytest + - name: Run tests run: | - pytest genno \ - --trace-config --color=yes --verbose \ + uv run --no-sync \ + pytest \ + --trace-config --color=yes --durations=20 -ra --verbose \ --cov-report=xml --cov-report=term \ - --numprocesses auto + --numprocesses=auto shell: bash - name: Upload test coverage to Codecov.io uses: codecov/codecov-action@v5 - with: - token: ${{ secrets.CODECOV_TOKEN }} pre-commit: name: Code quality @@ -84,14 +82,13 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: { python-version: 3.x } - - run: python -m pip install pre-commit && python -m pip freeze --local + - uses: astral-sh/setup-uv@v5 + with: + cache-dependency-glob: "**/pyproject.toml" + python-version: "3.12" # TEMPORARY work around https://github.com/python/mypy/issues/18216 - uses: actions/cache@v4 with: path: ~/.cache/pre-commit key: pre-commit|${{ env.pythonLocation }}|${{ hashFiles('.pre-commit-config.yaml') }} - - name: Force recreation of pre-commit virtual environment for mypy - if: github.event_name == 'schedule' # Comment this line to run on a PR - run: pre-commit clean - - run: pre-commit run --all-files --color=always --show-diff-on-failure + lookup-only: ${{ github.event_name == 'schedule' }} # Set 'true' to recreate cache + - run: uvx pre-commit run --all-files --color=always --show-diff-on-failure From d0f41e37b8617889a9d6a0c52d9db74a60dc0371 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 15 Jan 2025 13:47:25 +0100 Subject: [PATCH 2/5] Bump mypy, ruff versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - mypy v1.11.1 → v1.14.1 - Use config suggested at python/mypy#13916 - ruff v0.5.7 → v0.9.1 - Format 5 files. --- .pre-commit-config.yaml | 6 +++--- genno/config.py | 6 +++--- genno/core/quantity.py | 2 +- genno/core/sparsedataarray.py | 6 +++--- genno/testing/__init__.py | 6 +++--- genno/tests/core/test_exceptions.py | 7 ++++--- genno/tests/data/exceptions.ipynb | 8 +++++--- pyproject.toml | 7 +++++++ 8 files changed, 29 insertions(+), 19 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 33bc5448..c2e64b7d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,8 +1,9 @@ repos: - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.1 + rev: v1.14.1 hooks: - id: mypy + pass_filenames: false additional_dependencies: - importlib_resources - lxml-stubs @@ -18,9 +19,8 @@ repos: - types-python-dateutil - types-requests - xarray - args: [] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.7 + rev: v0.9.1 hooks: - id: ruff - id: ruff-format diff --git a/genno/config.py b/genno/config.py index 716943b5..540d3678 100644 --- a/genno/config.py +++ b/genno/config.py @@ -249,7 +249,7 @@ def _log_or_raise(exc: Exception, default_level: str, message: str): _log_or_raise(e, "warning", repr(e)) else: if keys := list(iter_keys(result)): - log.info(f"Add {repr(keys[0])} + {len(keys)-1} partial sums") + log.info(f"Add {repr(keys[0])} + {len(keys) - 1} partial sums") @handles("alias") @@ -288,7 +288,7 @@ def combine(c: Computer, info): added = iter_keys(c.add(key, task, strict=True, sums=True)) - log.info(f"Add {repr(key)} + {len(list(added))-1} partial sums") + log.info(f"Add {repr(key)} + {len(list(added)) - 1} partial sums") log.debug(" as combination of") log.debug(f" {repr(quantities)}") @@ -354,7 +354,7 @@ def general(c: Computer, info): added = c.add(key, _seq(task), strict=True, sums=info.get("sums", False)) if isinstance(added, tuple): - log.info(f" + {len(added)-1} partial sums") + log.info(f" + {len(added) - 1} partial sums") @handles("report") diff --git a/genno/core/quantity.py b/genno/core/quantity.py index d6716507..7490ae48 100644 --- a/genno/core/quantity.py +++ b/genno/core/quantity.py @@ -20,7 +20,7 @@ def assert_quantity(*args): for i, arg in enumerate(args): if not isinstance(arg, BaseQuantity): raise TypeError( - f"arg #{i+1} ({repr(arg)[:20]}) is not Quantity; likely an incorrect key" + f"arg #{i + 1} ({repr(arg)[:20]}) is not Quantity; likely an incorrect key" ) diff --git a/genno/core/sparsedataarray.py b/genno/core/sparsedataarray.py index 695a2328..3dfe9d49 100644 --- a/genno/core/sparsedataarray.py +++ b/genno/core/sparsedataarray.py @@ -139,9 +139,9 @@ def __init__( attrs = collect_attrs(data, attrs, kwargs) - assert 0 == len( - kwargs - ), f"Unrecognized kwargs {kwargs.keys()} to SparseDataArray()" + assert 0 == len(kwargs), ( + f"Unrecognized kwargs {kwargs.keys()} to SparseDataArray()" + ) if isinstance(data, int): data = float(data) diff --git a/genno/testing/__init__.py b/genno/testing/__init__.py index 1f3cac13..862ffa91 100644 --- a/genno/testing/__init__.py +++ b/genno/testing/__init__.py @@ -412,9 +412,9 @@ def assert_qty_allclose( def assert_units(qty: "AnyQuantity", exp: str) -> None: """Assert that `qty` has units `exp`.""" - assert ( - qty.units / qty.units._REGISTRY(exp) - ).dimensionless, f"Units '{qty.units:~}'; expected {repr(exp)}" + assert (qty.units / qty.units._REGISTRY(exp)).dimensionless, ( + f"Units '{qty.units:~}'; expected {repr(exp)}" + ) def random_qty(shape: dict[str, int], **kwargs) -> "AnyQuantity": diff --git a/genno/tests/core/test_exceptions.py b/genno/tests/core/test_exceptions.py index 207c1d0a..21eb8579 100644 --- a/genno/tests/core/test_exceptions.py +++ b/genno/tests/core/test_exceptions.py @@ -48,9 +48,10 @@ def test_computationerror_format(caplog): Use Computer.describe\(...\) to trace the computation\. Computation traceback: - File ".*", line 4, in fail - 'x' \+ 3.4 # Raises TypeError(\n.*)? -TypeError: can only concatenate str \(not "float"\) to str.*""" + File ".*", line 5, in fail + "x" \+ 3.4 # Raises TypeError.* +TypeError: can only concatenate str \(not "float"\) to str.*""", + re.DOTALL, ) diff --git a/genno/tests/data/exceptions.ipynb b/genno/tests/data/exceptions.ipynb index b61784fa..d385b539 100644 --- a/genno/tests/data/exceptions.ipynb +++ b/genno/tests/data/exceptions.ipynb @@ -8,12 +8,14 @@ "source": [ "import genno\n", "\n", + "\n", "def fail():\n", - " 'x' + 3.4 # Raises TypeError\n", + " \"x\" + 3.4 # Raises TypeError\n", + "\n", "\n", "c = genno.Computer()\n", - "c.add('test', (fail,))\n", - "c.get('test')" + "c.add(\"test\", (fail,))\n", + "c.get(\"test\")" ] } ], diff --git a/pyproject.toml b/pyproject.toml index 7275eea8..3b6b7c9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,6 +75,13 @@ exclude_also = [ "return NotImplemented", ] +[tool.mypy] +files = [ + "conftest.py", + "doc", + "genno", +] + [[tool.mypy.overrides]] # Packages/modules for which no type hints are available module = [ From 98799f2ad31d172d26e6772f9fee5a2fffba2eaf Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 15 Jan 2025 13:52:40 +0100 Subject: [PATCH 3/5] Use `uv`, PyPI trusted publishing in CI workflow Switch build backend to hatchling. --- .github/workflows/publish.yaml | 33 +++++++++++++++++++++++++++------ pyproject.toml | 12 +++++++----- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 6c096e52..b79a97fc 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -1,21 +1,42 @@ name: Build package / publish on: + pull_request: + branches: [ main ] push: branches: [ main ] tags: [ "v*" ] release: types: [ published ] - # Check that package can be built even on PRs - pull_request: - branches: [ main ] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +env: + python-version: "3.13" + # Uncomment for testing + # UV_PUBLISH_URL: https://test.pypi.org/legacy/ + + jobs: publish: - uses: iiasa/actions/.github/workflows/publish.yaml@main - secrets: - PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} + environment: + name: publish + permissions: + id-token: write + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v5 + with: + cache-dependency-glob: "**/pyproject.toml" + python-version: ${{ env.python-version }} + - run: uv build + - run: uv publish --trusted-publishing=always + if: >- + github.event_name == 'release' || ( + github.event_name == 'push' + && startsWith(github.ref, 'refs/tags') + ) diff --git a/pyproject.toml b/pyproject.toml index 3b6b7c9a..8bd611a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,6 @@ [build-system] -requires = ["build", "setuptools-scm"] +requires = ["hatchling", "versioningit"] +build-backend = "hatchling.build" [project] dynamic = ["version"] @@ -75,6 +76,9 @@ exclude_also = [ "return NotImplemented", ] +[tool.hatch] +version.source = "versioningit" + [tool.mypy] files = [ "conftest.py", @@ -118,7 +122,5 @@ ignore = ["E501", "W191"] # - .core.computer.add_queue: 11 mccabe.max-complexity = 10 -[tool.setuptools.packages] -find = {} - -[tool.setuptools_scm] +[tool.versioningit] +default-version = "0.1.dev1" # Match setuptools-scm From 79feac2d5a1a7bfe47bd0611a1d8ab4e3ab65ba3 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 15 Jan 2025 13:53:36 +0100 Subject: [PATCH 4/5] Bump copyright year to 2025 --- README.rst | 2 +- doc/conf.py | 2 +- doc/index.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 2a04bb7d..0d751c2b 100644 --- a/README.rst +++ b/README.rst @@ -13,7 +13,7 @@ The package name is warning, by reference, to the adage “When you hold a hamme License ======= -Copyright © 2018–2024 genno contributors. +Copyright © 2018–2025 genno contributors. Licensed under the GNU General Public License, version 3.0. diff --git a/doc/conf.py b/doc/conf.py index d039c188..910fcf5d 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -7,7 +7,7 @@ # -- Project information --------------------------------------------------------------- project = "genno" -copyright = "2018–2024, Genno contributors" +copyright = "2018–%Y, Genno contributors" author = "Genno contributors" diff --git a/doc/index.rst b/doc/index.rst index 8f4a1809..b004c5e0 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -60,7 +60,7 @@ Packages that extend :mod:`genno` include: License ======= -Copyright © 2018–2024 genno contributors. +Copyright © 2018–2025 genno contributors. Licensed under the GNU General Public License, version 3.0. From d3d4215143fc2d830566a439d06c8f2be1763693 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 15 Jan 2025 14:47:51 +0100 Subject: [PATCH 5/5] =?UTF-8?q?Add=20numba=20=E2=89=A5=200.54=20to=20spars?= =?UTF-8?q?e=20dependencies=20group?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid uv resolving to 0.53 on Python 3.10–3.12. --- pyproject.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 8bd611a6..b5429d5b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,10 @@ tests = [ "pytest-rerunfailures", "pytest-xdist", ] -sparse = ["sparse >= 0.12"] +sparse = [ + "numba >= 0.54", # Override >= 0.49 as of sparse 0.15.4 + "sparse >= 0.12", +] [project.urls] homepage = "https://github.com/khaeru/genno"