Skip to content

additional issue in recently fixed pep-681 fix discovered #15020

Closed
@zzzeek

Description

@zzzeek

hi, this is continuing from #14868, a user found another variant which points to something that likely needs to be adjusted in the fix just made in #15006.

same test case as #14868, but we add an additional alternative input type for the setter; the new logic does not interpret "optional" correctly (pyright works):

from __future__ import annotations

from typing import Any
from typing import Generic
from typing import Optional
from typing import overload
from typing import TYPE_CHECKING
from typing import TypeVar
from typing import Union

from typing_extensions import dataclass_transform

_T = TypeVar("_T")


def model_field(
    *,
    default: Optional[Any] = None,
    init: bool = True,
) -> Any:
    raise NotImplementedError()


@dataclass_transform(
    eq_default=True, order_default=True, field_specifiers=(model_field,)
)
class ModelBase:
    def __init_subclass__(
        cls,
        *,
        init: bool = True,
        frozen: bool = False,
        eq: bool = True,
        order: bool = True,
    ):
        ...


class SpecialWrapper(Generic[_T]):
    """some special kind of type that is generic around a _T"""

class Mapped(Generic[_T]):
    if TYPE_CHECKING:

        @overload
        def __get__(self, instance: None, owner: Any) -> Mapped[_T]:
            ...

        @overload
        def __get__(self, instance: object, owner: Any) -> _T:
            ...

        def __get__(
            self, instance: Optional[object], owner: Any
        ) -> Union[Mapped[_T], _T]:
            ...

        def __set__(self, instance: Any, value: Union[SpecialWrapper[_T], _T]) -> None:
            """the set method can accept values that are wrapped in the
            SpecialWrapper as well as the value directly.  this is what
            causes the mypy issue.

            """
            ...

        def __delete__(self, instance: Any) -> None:
            ...


class Customer(ModelBase):
    a: Mapped[Optional[str]] = model_field(default=None)

# works
c1 = Customer(a='asdf')

# fails
c2 = Customer(a=None)

where the second case, Optional is not unwrapping the inner type correctly:

$ mypy test4.py 
test4.py:77: error: Argument "a" to "Customer" has incompatible type "None"; expected "Union[SpecialWrapper[Optional[str]], str]"  [arg-type]
Found 1 error in 1 file (checked 1 source file)

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions