From 5635a937a844d89a248dfa29b4a237338b70a69f 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/workflows/ci.yml | 44 +++++++++------ .pre-commit-config.yaml | 2 +- duties.py | 71 +++++++++++++++++++++++++ pyproject.toml | 19 +++++++ 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 ++-- 9 files changed, 129 insertions(+), 67 deletions(-) create mode 100644 duties.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4977942f..24de2eb7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,12 +14,18 @@ jobs: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + python-version: ${{matrix.python-version}} + - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: ${{matrix.python-version}} architecture: x64 allow-prereleases: true - - run: pip install hatch + - run: uv pip install hatch - run: hatch run +py=${{matrix.python-version}} types:check test: @@ -28,27 +34,30 @@ 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"'] steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + python-version: ${{matrix.python-version}} + + - name: Set up Python + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 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}} - if: matrix.os == 'ubuntu-latest' - - - run: hatch test -p -py ${{matrix.python-version}} - if: matrix.os != 'ubuntu-latest' + uv run ${{matrix.extra_deps}} --group=optional duty test ${{ matrix.os == 'ubuntu-latest' && 'coverage=True' }} + mv .coverage .coverage.${{ matrix.python-version }}-${{matrix.os}}-${{strategy.job-index}} - 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,6 +72,11 @@ jobs: steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + python-version: '3.12' + - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: # Use latest Python, so it understands all syntax. @@ -75,16 +89,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 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/duties.py b/duties.py new file mode 100644 index 00000000..6978584a --- /dev/null +++ b/duties.py @@ -0,0 +1,71 @@ +import os +from pathlib import Path + +from duty import duty + +root = Path(__file__).resolve().parent + + +@duty +def test(ctx, coverage=False, parallel=True, coverage_name=None, review=False): + cmd = ["pytest"] + if review: + parallel = False + cmd += ["--inline-snapshot=review"] + + if parallel: + cmd += ["-n=auto"] + if coverage: + cmd = ["python", "-m", "coverage", "run", "-m", *cmd] + os.environ["TOP"] = str(root) + os.environ["COVERAGE_PROCESS_START"] = str(root / "pyproject.toml") + else: + cmd = ["python", "-Im", *cmd] + + ctx.run(cmd, title="Run tests", capture=False) + + if coverage: + ctx.run("python -Im coverage combine", title="combine coverage") + + if coverage_name is None: + ctx.run( + "python -Im coverage html --skip-empty", + title="generate html report htmlcov/index.html", + ) + else: + ctx.run(f"mv .coverage .coverage.{coverage_name}") + + +@duty +def test_all(ctx): + for python in ["3.12", "3.8", "3.11", "pypy3.10"]: + for deps_n, extra_args in enumerate( + [ + ("--with=pytest==8.3.3", "--with=pydantic<2"), + ("--with=pytest>=8.3.4", "--with=pydantic>2"), + ] + ): + coverage_name = python.replace(".", "") + "_" + str(deps_n) + ctx.run( + [ + "uv", + "run", + "-p", + python, + *extra_args, + "duty", + "test", + "coverage=True", + f"coverage_name={coverage_name}", + ] + ) + + os.environ["TOP"] = str(Path.cwd()) + print("TOP:", os.environ["TOP"]) + ctx.run("python -Im coverage combine", title="combine coverage") + ctx.run( + "python -Im coverage html --skip-empty", + title="generate coverage report", + ) + + ctx.run("coverage report") diff --git a/pyproject.toml b/pyproject.toml index 93ab8ee6..63972836 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -187,3 +187,22 @@ version = "command: cz bump --get-next" [tool.pytest.ini_options] markers=["no_rewriting: marks tests which need no code rewriting and can be used with pypy"] + +[dependency-groups] +dev = [ + "duty>=1.4.2", + "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.3.4", + "dirty-equals>=0.7.0", + "attrs>=24.3.0", + "pydantic>=1", + +] 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": """\