diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 63a8da48da..bec2ddaa51 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,6 +31,56 @@ jobs: - name: Execute Pre-Commit run: pre-commit run --show-diff-on-failure --color=always --all-files + mypy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v4 + with: + python-version: "3.12" + allow-prereleases: true + + - uses: pdm-project/setup-pdm@v3 + name: Set up PDM + with: + python-version: "3.12" + allow-python-prereleases: false + cache: true + cache-dependency-path: | + ./pdm.lock + + - name: Install dependencies + run: pdm install -G:all + + - name: Run mypy + run: pdm run mypy + + pyright: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v4 + with: + python-version: "3.12" + allow-prereleases: true + + - uses: pdm-project/setup-pdm@v3 + name: Set up PDM + with: + python-version: "3.12" + allow-python-prereleases: false + cache: true + cache-dependency-path: | + ./pdm.lock + + - name: Install dependencies + run: pdm install -G:all + + - name: Run pyright + run: pdm run pyright + test: name: "test (${{ matrix.python-version }}, pydantic@${{ matrix.pydantic-version }})" strategy: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dbdc9c9823..b6f088e27e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -57,138 +57,6 @@ repos: hooks: - id: slotscheck exclude: "test_*|docs" - - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.6.0" - hooks: - - id: mypy - exclude: "docs.*|test_apps.*|tests/examples.*" - files: "^litestar/.*|^tests/.*" - additional_dependencies: - [ - "advanced_alchemy>=0.2.2,<0.4.0", - aiosqlite, - annotated_types, - anyio>=3, - asyncpg, - asyncpg_stubs, - attrs, - beanie>=1.21.0, - beautifulsoup4, - brotli, - click, - cryptography, - fast-query-parsers>=1.0.2, - fsspec, - greenlet, - httpx>=0.22, - httpx_sse, - hypothesis, - jinja2>=3.1.2, - jsbeautifier, - mako>=1.2.4, - minijinja>=1.0.0, - msgspec>=0.18.2, - multidict>=6.0.2, - opentelemetry-instrumentation-asgi, - opentelemetry-sdk, - piccolo, - picologging, - polyfactory>=2.6.3, - prometheus_client, - "pydantic[email]>=2", - pydantic-extra-types, - pytest, - pytest-asyncio, - pytest-cov, - pytest-lazy-fixture, - pytest-mock, - pytest-rerunfailures, - pytest-timeout, - pytest-xdist, - python-dotenv, - python-jose, - pyyaml, - "redis[hiredis]>=4.4.4", - rich-click, - rich>=13.0.0, - starlette, - structlog, - time-machine, - trio, - types-beautifulsoup4, - types-pytest-lazy-fixture, - types-python-jose, - types-pyyaml, - types-redis, - typing-extensions, - "uvicorn[standard]", - uvloop>=0.18.0, - ] - - repo: https://github.com/RobertCraigie/pyright-python - rev: v1.1.331 - hooks: - - id: pyright - additional_dependencies: - [ - "advanced_alchemy>=0.2.2,<0.4.0", - aiosqlite, - annotated_types, - anyio>=3, - asyncpg, - asyncpg_stubs, - attrs, - beanie>=1.21.0, - beautifulsoup4, - brotli, - click, - cryptography, - fast-query-parsers>=1.0.2, - fsspec, - greenlet, - httpx>=0.22, - httpx_sse, - hypothesis, - jinja2>=3.1.2, - jsbeautifier, - mako>=1.2.4, - minijinja>=1.0.0, - msgspec>=0.18.2, - multidict>=6.0.2, - opentelemetry-instrumentation-asgi, - opentelemetry-sdk, - piccolo, - picologging, - polyfactory>=2.6.3, - prometheus_client, - "pydantic[email]>=2", - pydantic-extra-types, - pytest, - pytest-asyncio, - pytest-cov, - pytest-lazy-fixture, - pytest-mock, - pytest-rerunfailures, - pytest-timeout, - pytest-xdist, - python-dotenv, - python-jose, - pyyaml, - "redis[hiredis]>=4.4.4", - rich-click, - rich>=13.0.0, - starlette, - structlog, - time-machine, - trio, - types-beautifulsoup4, - types-pytest-lazy-fixture, - types-python-jose, - types-pyyaml, - types-redis, - typing-extensions, - "uvicorn[standard]", - uvloop>=0.18.0, - ] - repo: https://github.com/sphinx-contrib/sphinx-lint rev: "v0.6.8" hooks: diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 777056fce1..a2d7389a95 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -91,6 +91,18 @@ or ``make coverage``. Due to the nature of pytest-xdist, attaching a debugger is straightforward. For debugging, it's recommended to run the tests individually with ``pytest `` or via an IDE, which will skip pytest-xdist. +Running type checkers ++++++++++++++++++++++ + +We use `mypy `_ and `pyright `_ to +enforce type safety. You can run them with: + +- ``make mypy`` +- ``make pyright`` +- ``make typecheck`` to run both +- ``make lint`` to run pre-commit hooks and type checkers. + +Our type checkers are run on Python 3.12 in CI, so you should make sure to run them on the same version locally as well. Project documentation --------------------- diff --git a/Makefile b/Makefile index 6af3540075..259e7f0ddb 100644 --- a/Makefile +++ b/Makefile @@ -74,12 +74,30 @@ lock: ## Rebuild lockfiles from scra # ============================================================================= # Tests, Linting, Coverage # ============================================================================= -.PHONY: lint -lint: ## Runs pre-commit hooks; includes ruff linting, codespell, black +.PHONY: mypy +mypy: ## Run mypy + @echo "=> Running mypy" + @$(ENV_PREFIX)mypy + @echo "=> mypy complete" + +.PHONY: pyright +pyright: ## Run pyright + @echo "=> Running pyright" + @$(ENV_PREFIX)pyright + @echo "=> pyright complete" + +.PHONY: type-check +type-check: mypy pyright ## Run all type checking + +.PHONY: pre-commit +pre-commit: ## Runs pre-commit hooks; includes ruff linting, codespell, black @echo "=> Running pre-commit process" @$(ENV_PREFIX)pre-commit run --all-files @echo "=> Pre-commit complete" +.PHONY: lint +lint: pre-commit type-check ## Run all linting + .PHONY: coverage coverage: ## Run the tests and generate coverage report @echo "=> Running tests with coverage" diff --git a/tests/helpers.py b/tests/helpers.py index bcd9e12c92..06f9461752 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -58,6 +58,6 @@ def get_exception_group() -> type[BaseException]: try: return ExceptionGroup except NameError: - from exceptiongroup import ExceptionGroup as _ExceptionGroup # pyright: ignore[reportMissingImports] + from exceptiongroup import ExceptionGroup as _ExceptionGroup # type: ignore[import-not-found] return cast("type[BaseException]", _ExceptionGroup)