pydantic / pydantic

Data validation using Python type hints
https://docs.pydantic.dev
MIT License
21.29k stars 1.92k forks source link

`__pydantic_extra__` override triggers error in `pyright` #10758

Open awgymer opened 3 weeks ago

awgymer commented 3 weeks ago

Initial Checks

Description

Overriding __pyright_extra__ causes a pyright typing error because the type is not the same as the base declaration.

Example Code

from pydantic import BaseModel, ConfigDict

ExtraDict = dict[str, int | str]

class ModelExtra(BaseModel):
    model_config = ConfigDict(extra="allow")
    __pydantic_extra__: ExtraDict = Field(init=False)

## Gives pyright error
#error: "__pydantic_extra__" overrides symbol of same name in class "BaseModel"
#    Variable is mutable so its type is invariant
#      Override type "ExtraDict" is not the same as base type "dict[str, Any] | None" (reportIncompatibleVariableOverride)

## BUT THIS ALSO BREAKS

class ModelExtra(BaseModel):
    model_config = ConfigDict(extra="allow")
    __pydantic_extra__: ExtraDict | None = Field(init=False)

## ERROR
# pydantic.errors.PydanticSchemaGenerationError: The type annotation for `__pydantic_extra__` must be `Dict[str, ...]`

Python, Pydantic & OS Version

pydantic version: 2.9.2
        pydantic-core version: 2.23.4
          pydantic-core build: profile=release pgo=false
               python version: 3.10.4 (main, Oct 26 2022, 13:07:52) [Clang 13.0.0 (clang-1300.0.29.30)]
                     platform: macOS-15.0.1-arm64-arm-64bit
             related packages: mypy-1.6.1 pyright-1.1.385 typing_extensions-4.8.0
                       commit: unknown
Viicos commented 2 weeks ago

I think the API to specify validation for extra fields is a bit flawed. While specifying it as an annotation is beneficial as you can then easily type check attribute accesses to __pydantic_extra__, there's a couple issues arising from this:

I can't come up with a good API immediately, however one thing that is certain is that we will have to break the existing API if we ever want to make changes here. As such, marking this issue as https://github.com/pydantic/pydantic/labels/v3.

In the meanwhile, you can add a pyright: ignore[reportIncompatibleVariableOverride] comment or disable the error code at the project level (enabling this error code is debatable, see https://github.com/microsoft/pyright/issues/5933).