From 06a54200851dc2aa2e6f7697d672c86b631b4cdb Mon Sep 17 00:00:00 2001 From: Frank Hoffmann <15r10nk-git@polarbit.de> Date: Mon, 30 Dec 2024 22:02:26 +0100 Subject: [PATCH] build: switch to uv --- .github/actions/setup/action.yml | 21 ++++++++ .github/workflows/ci.yml | 46 ++++++++--------- .pre-commit-config.yaml | 2 +- CONTRIBUTING.md | 13 +++-- pyproject.toml | 65 ++++++++++++++++--------- src/inline_snapshot/pydantic_fix.py | 2 +- src/inline_snapshot/testing/_example.py | 8 --- tests/adapter/test_dataclass.py | 24 ++------- tests/conftest.py | 17 ------- tests/test_pydantic.py | 9 ++-- 10 files changed, 101 insertions(+), 106 deletions(-) create mode 100644 .github/actions/setup/action.yml diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml new file mode 100644 index 00000000..40cb42a4 --- /dev/null +++ b/.github/actions/setup/action.yml @@ -0,0 +1,21 @@ +name: General Setup +description: checkout & setup python +inputs: + python-version: # id of input + description: the python version to use + required: false + default: '3.12' +runs: + using: composite + steps: + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + python-version: ${{inputs.python-version}} + + - name: Set up Python + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + with: + python-version: ${{inputs.python-version}} + architecture: x64 + allow-prereleases: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4977942f..d8000b35 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,13 +14,10 @@ jobs: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + - uses: ./.github/actions/setup with: python-version: ${{matrix.python-version}} - architecture: x64 - allow-prereleases: true - - run: pip install hatch - - run: hatch run +py=${{matrix.python-version}} types:check + - run: uvx hatch run +py=${{matrix.python-version}} types:check test: runs-on: ubuntu-latest @@ -28,27 +25,27 @@ jobs: matrix: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13', pypy3.9, pypy3.10] os: [ubuntu-latest, windows-latest, macos-13] + extra_deps: ['"--with=pytest==8.3.3" "--with=pydantic<2"', '"--with=pytest>=8.3.4" "--with=pydantic>2"'] + env: + TOP: ${{github.workspace}} + COVERAGE_PROCESS_START: ${{github.workspace}}/pyproject.toml steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + - uses: ./.github/actions/setup with: python-version: ${{matrix.python-version}} - architecture: x64 - allow-prereleases: true - - run: pip install hatch - run: | - hatch test -cp -py ${{matrix.python-version}} - mv .coverage .coverage.${{ matrix.python-version }}.${{matrix.os}} + uv run ${{matrix.extra_deps}} -m ${{ matrix.os == 'ubuntu-latest' && 'coverage run -m' || '' }} pytest -n=auto + - run: | + uv run -m coverage combine + mv .coverage .coverage.${{ matrix.python-version }}-${{matrix.os}}-${{strategy.job-index}} if: matrix.os == 'ubuntu-latest' - - run: hatch test -p -py ${{matrix.python-version}} - if: matrix.os != 'ubuntu-latest' - - name: Upload coverage data uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 with: - name: coverage-data-${{ matrix.python-version }}-${{matrix.os}} + name: coverage-data-${{ matrix.python-version }}-${{matrix.os}}-${{strategy.job-index}} path: .coverage.* include-hidden-files: true if-no-files-found: ignore @@ -63,10 +60,7 @@ jobs: steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 - with: - # Use latest Python, so it understands all syntax. - python-version: '3.12' + - uses: ./.github/actions/setup - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: @@ -75,16 +69,16 @@ jobs: - name: Combine coverage & fail if it's <100% run: | - python -Im pip install --upgrade coverage[toml] + uv pip install --upgrade coverage[toml] - python -Im coverage combine - python -Im coverage html --skip-covered --skip-empty + coverage combine + coverage html --skip-covered --skip-empty # Report and write to summary. - python -Im coverage report --format=markdown >> $GITHUB_STEP_SUMMARY + coverage report --format=markdown >> $GITHUB_STEP_SUMMARY # Report again and fail if under 100%. - python -Im coverage report --fail-under=100 + coverage report --fail-under=100 - name: Upload HTML report if check failed uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 @@ -98,7 +92,6 @@ jobs: name: Publish new release runs-on: ubuntu-latest needs: [test, coverage] - environment: pypi permissions: # IMPORTANT: this permission is mandatory for Trusted Publishing id-token: write @@ -110,6 +103,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 + - uses: ./.github/actions/setup - name: Check if the commit has a vx.y.z tag id: check-version @@ -122,7 +116,7 @@ jobs: echo "should_continue=false" >> "$GITHUB_OUTPUT" fi - - run: pip install hatch scriv + - run: uv pip install hatch scriv - name: build package run: hatch build diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2dde2d74..9a05e291 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -75,7 +75,7 @@ repos: # - id: docformatter - repo: https://github.com/abravalheri/validate-pyproject - rev: v0.18 + rev: v0.23 hooks: - id: validate-pyproject # Optional extra validations from SchemaStore: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5b1eb156..a2b2ba09 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,13 +3,18 @@ Contributions are welcome. Please create an issue before writing a pull request so we can discuss what needs to be changed. # Testing -The code can be tested with [nox](https://nox.thea.codes/en/stable/) +The code can be tested with [hatch](https://hatch.pypa.io/latest/tutorials/testing/overview/) + +* `hatch test` can be used to test all supported python versions and to check for coverage. +* `hatch test -py 3.10 -- --sw` runs pytest for python 3.10 with the `--sw` argument. + +The preferred way to test inline-snapshot is by using [`inline-snapshot.texting.Example`](https://15r10nk.github.io/inline-snapshot/latest/testing/). +You will see some other fixtures which are used inside the tests, but these are old ways to write the tests and I try to use the new `Example` class to write new tests. -* `nox` can be used to test all supported python versions and to check for coverage. -* `nox -e test-3.10 -- --sw` runs pytest for python 3.10 with the `--sw` argument. # Coverage -This project has a hard coverage requirement of 100%. +This project has a hard coverage requirement of 100% (which is checked in CI). +You can also check the coverage locally with `hatch test -acp`. The goal here is to find different edge cases which might have bugs. However, it is possible to exclude some code from the coverage. diff --git a/pyproject.toml b/pyproject.toml index 93ab8ee6..0c5e5fcf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,23 @@ readme = "README.md" requires-python = ">=3.8" version = "0.18.1" +[dependency-groups] +dev = [ + "hypothesis>=6.75.5", + "mypy>=1.2.0", + "pyright>=1.1.359", + "pytest-subtests>=0.11.0", + "pytest-freezer>=0.4.8", + "pytest-mock>=3.14.0", + "pytest-xdist>=3.6.1", + "coverage[toml]>=7.6.1", + "coverage-enable-subprocess>=1.0", + "pytest>=8", + "dirty-equals>=0.7.0", + "attrs>=24.3.0", + "pydantic>=1", +] + [project.entry-points.pytest11] inline_snapshot = "inline_snapshot.pytest_plugin" @@ -86,6 +103,8 @@ dependencies = [ "pytest", "black" ] +[tool.hatch.envs.default] +installer="uv" [tool.hatch.envs.docs.scripts] build = "mkdocs build --strict" @@ -99,23 +118,17 @@ scripts.update="cog -r docs/**.md" [[tool.hatch.envs.hatch-test.matrix]] python = ["3.13", "3.12", "3.11", "3.10", "3.9", "3.8","pypy3.9","pypy3.10"] -pytest=["8.3.3","8.3.4"] +extra-deps=["low","hight"] [tool.hatch.envs.hatch-test.overrides] -matrix.pytest.dependencies = [ - { value = "pytest==8.3.3", if = ["8.3.3"] }, - { value = "pytest>=8.3.4", if = ["8.3.4"] }, +matrix.extra-deps.dependencies = [ + { value = "pytest==8.3.3", if = ["low"] }, + { value = "pytest>=8.3.4", if = ["hight"] }, + { value = "pydantic<2", if = ["low"] }, + { value = "pydantic>=2", if = ["hight"] }, ] - [tool.hatch.envs.hatch-test] -# Info for everyone who packages this library: -# The following dependencies are installed with uv if you run `pytest --use-uv` -# and used for specific tests in specific versions: -# - pydantic v1 & v2 -# - attrs -# But you dont have to use uv to test this library. -# You can also just install the dependencies and use `pytest` normally extra-dependencies = [ "dirty-equals>=0.7.0", "hypothesis>=6.75.5", @@ -142,18 +155,34 @@ extra-dependencies = [ "attrs" ] +[[tool.hatch.envs.types.matrix]] +python = ["3.8", "3.9", "3.10", "3.11", "3.12","3.13"] + +[tool.hatch.envs.types.scripts] +check = "mypy --install-types --non-interactive {args:src/inline_snapshot tests}" + +[tool.mypy] +exclude = "tests/.*_samples" + +[tool.pyright] +venv = "test-3-12" +venvPath = ".nox" + + [tool.hatch.envs.release] detached=true dependencies=[ "scriv", "commitizen" ] + [tool.hatch.envs.release.scripts] create=[ "scriv collect", "- pre-commit run -a", "cz bump" ] + publish=[ "git push --force-with-lease", "git push --tags", @@ -167,18 +196,6 @@ publish-package=[ "scriv github-release" ] -[[tool.hatch.envs.types.matrix]] -python = ["3.8", "3.9", "3.10", "3.11", "3.12","3.13"] - -[tool.hatch.envs.types.scripts] -check = "mypy --install-types --non-interactive {args:src/inline_snapshot tests}" - -[tool.mypy] -exclude = "tests/.*_samples" - -[tool.pyright] -venv = "test-3-12" -venvPath = ".nox" [tool.scriv] diff --git a/src/inline_snapshot/pydantic_fix.py b/src/inline_snapshot/pydantic_fix.py index ce019ec4..ef0ed6ac 100644 --- a/src/inline_snapshot/pydantic_fix.py +++ b/src/inline_snapshot/pydantic_fix.py @@ -11,7 +11,7 @@ def pydantic_fix(): try: from pydantic import BaseModel - except ImportError: + except ImportError: # pragma: no cover return import pydantic diff --git a/src/inline_snapshot/testing/_example.py b/src/inline_snapshot/testing/_example.py index 60d3b557..c1b25cb4 100644 --- a/src/inline_snapshot/testing/_example.py +++ b/src/inline_snapshot/testing/_example.py @@ -235,7 +235,6 @@ def run_pytest( self, args: list[str] = [], *, - extra_dependencies: list[str] = [], env: dict[str, str] = {}, changed_files: Snapshot[dict[str, str]] | None = None, report: Snapshot[str] | None = None, @@ -276,13 +275,6 @@ def run_pytest( command_env.update(env) - if extra_dependencies: - uv_cmd = ["uv", "run"] - for dependency in extra_dependencies: - uv_cmd.append(f"--with={dependency}") - - cmd = uv_cmd + cmd - result = sp.run(cmd, cwd=tmp_path, capture_output=True, env=command_env) print("run>", *cmd) diff --git a/tests/adapter/test_dataclass.py b/tests/adapter/test_dataclass.py index 0059eadb..da2eedce 100644 --- a/tests/adapter/test_dataclass.py +++ b/tests/adapter/test_dataclass.py @@ -1,4 +1,3 @@ -import pytest from inline_snapshot import snapshot from inline_snapshot.extra import warns from inline_snapshot.testing._example import Example @@ -120,12 +119,7 @@ def test_something(): ) -@pytest.fixture -def attrs_deps(use_uv): - yield (["attrs"] if use_uv else []) - - -def test_attrs_default_value(attrs_deps): +def test_attrs_default_value(): Example( """\ from inline_snapshot import snapshot,Is @@ -144,7 +138,6 @@ def test_something(): """ ).run_pytest( ["--inline-snapshot=fix"], - extra_dependencies=attrs_deps, changed_files=snapshot( { "test_something.py": """\ @@ -166,7 +159,6 @@ def test_something(): ), ).run_pytest( ["--inline-snapshot=update"], - extra_dependencies=attrs_deps, changed_files=snapshot( { "test_something.py": """\ @@ -189,7 +181,7 @@ def test_something(): ) -def test_attrs_field_repr(attrs_deps): +def test_attrs_field_repr(): Example( """\ @@ -205,7 +197,6 @@ class container: """ ).run_pytest( ["--inline-snapshot=create"], - extra_dependencies=attrs_deps, changed_files=snapshot( { "test_something.py": """\ @@ -221,12 +212,10 @@ class container: """ } ), - ).run_pytest( - extra_dependencies=attrs_deps, - ) + ).run_pytest() -def test_attrs_unmanaged(attrs_deps): +def test_attrs_unmanaged(): Example( """\ import datetime as dt @@ -252,11 +241,8 @@ def test(): """ ).run_pytest( ["--inline-snapshot=create,fix"], - extra_dependencies=attrs_deps, changed_files=snapshot({}), - ).run_pytest( - extra_dependencies=attrs_deps, - ) + ).run_pytest() def test_disabled(executing_used): diff --git a/tests/conftest.py b/tests/conftest.py index c05f77d3..2159aa85 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -52,23 +52,6 @@ def pytest_addoption(parser): ) -@pytest.fixture -def use_uv(request): - yield request.config.getoption("--use-uv") - - -@pytest.fixture(params=["pydantic>=2.0.0", "pydantic<2.0.0"]) -def pydantic_version(request): - use_uv = request.config.getoption("--use-uv") - - if use_uv: - yield [request.param] - else: # pragma: no cover - if request.param == "pydantic<2.0.0": - pytest.skip() - yield [] - - @pytest.fixture() def check_update(source): def w(source_code, *, flags="", reported_flags=None, number=1): diff --git a/tests/test_pydantic.py b/tests/test_pydantic.py index 570af74f..fd96e9c2 100644 --- a/tests/test_pydantic.py +++ b/tests/test_pydantic.py @@ -2,7 +2,7 @@ from inline_snapshot.testing import Example -def test_pydantic_create_snapshot(pydantic_version): +def test_pydantic_create_snapshot(): Example( """ @@ -22,7 +22,6 @@ def test_pydantic(): """ ).run_pytest( ["--inline-snapshot=create"], - extra_dependencies=pydantic_version, changed_files=snapshot( { "test_something.py": """\ @@ -49,7 +48,7 @@ def test_pydantic(): ) -def test_pydantic_field_repr(pydantic_version): +def test_pydantic_field_repr(): Example( """\ @@ -64,7 +63,6 @@ class container(BaseModel): """ ).run_pytest( ["--inline-snapshot=create"], - extra_dependencies=pydantic_version, changed_files=snapshot( { "test_something.py": """\ @@ -84,7 +82,7 @@ class container(BaseModel): ) -def test_pydantic_default_value(pydantic_version): +def test_pydantic_default_value(): Example( """\ from inline_snapshot import snapshot,Is @@ -101,7 +99,6 @@ def test_something(): """ ).run_pytest( ["--inline-snapshot=update"], - extra_dependencies=pydantic_version, changed_files=snapshot( { "test_something.py": """\