Skip to content

Commit

Permalink
Upgrade pyright to 1.1.384 (pydantic#10620)
Browse files Browse the repository at this point in the history
Change tests to align with removal of PEP 746 support.
Move Pyright tests out of the mypy CI job.
  • Loading branch information
Viicos authored Oct 14, 2024
1 parent 9ef4637 commit 60f7047
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 29 deletions.
37 changes: 25 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -267,26 +267,39 @@ jobs:
COVERAGE_FILE: coverage/.coverage.linux-py${{ matrix.python-version }}-mypy${{ matrix.mypy-version }}
CONTEXT: linux-py${{ matrix.python-version }}-mypy${{ matrix.mypy-version }}

- name: store coverage files
uses: actions/upload-artifact@v4
with:
name: coverage-${{ matrix.python-version }}-mypy${{ matrix.mypy-version }}
path: coverage
include-hidden-files: true

test-pyright:
name: Pyright tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: install node for pyright
uses: actions/setup-node@v4
with:
node-version: '18'
node-version: '20'

- uses: pdm-project/setup-pdm@v4
with:
python-version: '3.12'
cache: true

- name: install deps
run: |
pdm venv create --force $PYTHON
pdm install
- name: install pyright
run: npm install -g [email protected].369 # try to keep this in sync with .pre-commit-config.yaml
run: npm install -g [email protected].384 # keep this in sync with .pre-commit-config.yaml

- name: run pyright tests
run: make test-pyright
env:
COVERAGE_FILE: coverage/.coverage.linux-py${{ matrix.python-version }}-pyright
CONTEXT: linux-py${{ matrix.python-version }}-pyright

- name: store coverage files
uses: actions/upload-artifact@v4
with:
name: coverage-${{ matrix.python-version }}-mypy${{ matrix.mypy-version }}
path: coverage
include-hidden-files: true

coverage-combine:
needs: [test, test-mypy]
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ repos:
types: [python]
language: node
pass_filenames: false
additional_dependencies: ["[email protected].369"] # try to keep this in sync with .github/workflows/ci.yml
additional_dependencies: ["[email protected].384"] # keep this in sync with .github/workflows/ci.yml
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ test-mypy-update-all: .pdm

.PHONY: test-pyright ## Run the pyright integration tests
test-pyright: .pdm
pdm run bash -c 'cd tests/pyright && pyright'
pdm run bash -c 'cd tests/pyright && pyright --version && pyright -p pyproject.toml'

.PHONY: test ## Run all tests, skipping the type-checker integration tests
test: .pdm
Expand Down
2 changes: 1 addition & 1 deletion pydantic/_internal/_generate_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -1535,7 +1535,7 @@ def _namedtuple_schema(self, namedtuple_cls: Any, origin: Any) -> core_schema.Co
raise PydanticUndefinedAnnotation.from_name_error(e) from e
if not annotations:
# annotations is empty, happens if namedtuple_cls defined via collections.namedtuple(...)
annotations = {k: Any for k in namedtuple_cls._fields}
annotations: dict[str, Any] = {k: Any for k in namedtuple_cls._fields}

if typevars_map:
annotations = {
Expand Down
13 changes: 7 additions & 6 deletions pydantic/_internal/_model_construction.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from abc import ABCMeta
from functools import lru_cache, partial
from types import FunctionType
from typing import Any, Callable, Generic, Literal, NoReturn
from typing import Any, Callable, Generic, Literal, NoReturn, cast

import typing_extensions
from pydantic_core import PydanticUndefined, SchemaSerializer
Expand Down Expand Up @@ -136,12 +136,11 @@ def wrapped_model_post_init(self: BaseModel, context: Any, /) -> None:
if __pydantic_generic_metadata__:
namespace['__pydantic_generic_metadata__'] = __pydantic_generic_metadata__

cls: type[BaseModel] = super().__new__(mcs, cls_name, bases, namespace, **kwargs) # type: ignore

BaseModel = import_cached_base_model()
cls = cast('type[BaseModel]', super().__new__(mcs, cls_name, bases, namespace, **kwargs))
BaseModel_ = import_cached_base_model()

mro = cls.__mro__
if Generic in mro and mro.index(Generic) < mro.index(BaseModel):
if Generic in mro and mro.index(Generic) < mro.index(BaseModel_):
warnings.warn(
GenericBeforeBaseModelWarning(
'Classes should inherit from `BaseModel` before generic classes (e.g. `typing.Generic[T]`) '
Expand All @@ -151,7 +150,9 @@ def wrapped_model_post_init(self: BaseModel, context: Any, /) -> None:
)

cls.__pydantic_custom_init__ = not getattr(cls.__init__, '__pydantic_base_init__', False)
cls.__pydantic_post_init__ = None if cls.model_post_init is BaseModel.model_post_init else 'model_post_init'
cls.__pydantic_post_init__ = (
None if cls.model_post_init is BaseModel_.model_post_init else 'model_post_init'
)

cls.__pydantic_decorators__ = DecoratorInfos.build(cls)

Expand Down
25 changes: 25 additions & 0 deletions tests/pyright/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Pyright test suite

Use [`assert_type`](https://docs.python.org/3/library/typing.html#typing.assert_type) to make assertions:

```python
from typing_extensions import assert_type

from pydantic import TypeAdapter

ta1 = TypeAdapter(int)
assert_type(ta1, TypeAdapter[int])
```

To assert on invalid cases, add a `pyright: ignore` comment:

```python
from pydantic import BaseModel


class Model(BaseModel):
a: int


Model() # pyright: ignore[reportCallIssue]
```
17 changes: 9 additions & 8 deletions tests/pyright/pipeline_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@

from pydantic.experimental.pipeline import validate_as

# this test works by adding type ignores and having pyright fail with
# an unused type ignore error if the type checking isn't working
Annotated[str, validate_as(int)] # type: ignore
Annotated[str, validate_as(str).transform(lambda x: int(x))] # type: ignore
Annotated[float, validate_as(float).gt(0)] # should be able to compare float to int
Annotated[datetime.datetime, validate_as(datetime.datetime).datetime_tz_naive()]
Annotated[datetime.datetime, validate_as(str).datetime_tz_naive()] # type: ignore
Annotated[
# TODO: since Pyright 1.1.384, support for PEP 746 was disabled.
# `a1` and `a2` should have a `pyright: ignore[reportInvalidTypeArguments]` comment.
a1 = Annotated[str, validate_as(int)]
a2 = Annotated[str, validate_as(str).transform(lambda x: int(x))]
a3 = Annotated[float, validate_as(float).gt(0)] # should be able to compare float to int

a4 = Annotated[datetime.datetime, validate_as(datetime.datetime).datetime_tz_naive()]
a5 = Annotated[datetime.datetime, validate_as(str).datetime_tz_naive()] # pyright: ignore[reportAttributeAccessIssue]
a6 = Annotated[
datetime.datetime,
(
validate_as(str).transform(str.strip).validate_as(datetime.datetime).datetime_tz_naive()
Expand Down

0 comments on commit 60f7047

Please sign in to comment.