From 593eab8618ec1c1868186db510de2ef8b106692f Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Sat, 4 Feb 2023 15:04:03 +0100 Subject: [PATCH 1/2] Export DataclassInstance protocol --- stdlib/_typeshed/dataclasses.pyi | 7 +++++++ stdlib/dataclasses.pyi | 24 +++++++++++------------- 2 files changed, 18 insertions(+), 13 deletions(-) create mode 100644 stdlib/_typeshed/dataclasses.pyi diff --git a/stdlib/_typeshed/dataclasses.pyi b/stdlib/_typeshed/dataclasses.pyi new file mode 100644 index 000000000000..ede41feaca6c --- /dev/null +++ b/stdlib/_typeshed/dataclasses.pyi @@ -0,0 +1,7 @@ +# See the README.md file in this directory for more information. + +from dataclasses import Field +from typing import Any, ClassVar, Protocol + +class DataclassInstance(Protocol): + __dataclass_fields__: ClassVar[dict[str, Field[Any]]] diff --git a/stdlib/dataclasses.pyi b/stdlib/dataclasses.pyi index 3b7327137ec5..68e2bffdac86 100644 --- a/stdlib/dataclasses.pyi +++ b/stdlib/dataclasses.pyi @@ -1,9 +1,10 @@ import enum import sys import types +from _typeshed.dataclasses import DataclassInstance from builtins import type as Type # alias to avoid name clashes with fields named "type" from collections.abc import Callable, Iterable, Mapping -from typing import Any, ClassVar, Generic, Protocol, TypeVar, overload +from typing import Any, Generic, Protocol, TypeVar, overload from typing_extensions import Literal, TypeAlias, TypeGuard if sys.version_info >= (3, 9): @@ -30,10 +31,7 @@ __all__ = [ if sys.version_info >= (3, 10): __all__ += ["KW_ONLY"] -class _DataclassInstance(Protocol): - __dataclass_fields__: ClassVar[dict[str, Field[Any]]] - -_DataclassT = TypeVar("_DataclassT", bound=_DataclassInstance) +_DataclassT = TypeVar("_DataclassT", bound=DataclassInstance) # define _MISSING_TYPE as an enum within the type stubs, # even though that is not really its type at runtime @@ -49,13 +47,13 @@ if sys.version_info >= (3, 10): class KW_ONLY: ... @overload -def asdict(obj: _DataclassInstance) -> dict[str, Any]: ... +def asdict(obj: DataclassInstance) -> dict[str, Any]: ... @overload -def asdict(obj: _DataclassInstance, *, dict_factory: Callable[[list[tuple[str, Any]]], _T]) -> _T: ... +def asdict(obj: DataclassInstance, *, dict_factory: Callable[[list[tuple[str, Any]]], _T]) -> _T: ... @overload -def astuple(obj: _DataclassInstance) -> tuple[Any, ...]: ... +def astuple(obj: DataclassInstance) -> tuple[Any, ...]: ... @overload -def astuple(obj: _DataclassInstance, *, tuple_factory: Callable[[list[Any]], _T]) -> _T: ... +def astuple(obj: DataclassInstance, *, tuple_factory: Callable[[list[Any]], _T]) -> _T: ... if sys.version_info >= (3, 8): # cls argument is now positional-only @@ -223,13 +221,13 @@ else: metadata: Mapping[Any, Any] | None = None, ) -> Any: ... -def fields(class_or_instance: _DataclassInstance | type[_DataclassInstance]) -> tuple[Field[Any], ...]: ... +def fields(class_or_instance: DataclassInstance | type[DataclassInstance]) -> tuple[Field[Any], ...]: ... @overload -def is_dataclass(obj: _DataclassInstance | type[_DataclassInstance]) -> Literal[True]: ... +def is_dataclass(obj: DataclassInstance | type[DataclassInstance]) -> Literal[True]: ... @overload -def is_dataclass(obj: type) -> TypeGuard[type[_DataclassInstance]]: ... +def is_dataclass(obj: type) -> TypeGuard[type[DataclassInstance]]: ... @overload -def is_dataclass(obj: object) -> TypeGuard[_DataclassInstance | type[_DataclassInstance]]: ... +def is_dataclass(obj: object) -> TypeGuard[DataclassInstance | type[DataclassInstance]]: ... class FrozenInstanceError(AttributeError): ... From 34f49c7896bf41c0337dea84ccd482dda07a93bf Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Sat, 4 Feb 2023 16:47:04 +0100 Subject: [PATCH 2/2] Move to __init__.pyi + add comment --- stdlib/_typeshed/__init__.pyi | 10 +++++++++- stdlib/_typeshed/dataclasses.pyi | 7 ------- stdlib/dataclasses.pyi | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) delete mode 100644 stdlib/_typeshed/dataclasses.pyi diff --git a/stdlib/_typeshed/__init__.pyi b/stdlib/_typeshed/__init__.pyi index 68ac2a9b1900..33af534311d1 100644 --- a/stdlib/_typeshed/__init__.pyi +++ b/stdlib/_typeshed/__init__.pyi @@ -8,9 +8,10 @@ import mmap import pickle import sys from collections.abc import Awaitable, Callable, Iterable, Set as AbstractSet +from dataclasses import Field from os import PathLike from types import FrameType, TracebackType -from typing import Any, AnyStr, Generic, Protocol, TypeVar, Union +from typing import Any, AnyStr, ClassVar, Generic, Protocol, TypeVar, Union from typing_extensions import Final, Literal, LiteralString, TypeAlias, final _KT = TypeVar("_KT") @@ -304,3 +305,10 @@ ProfileFunction: TypeAlias = Callable[[FrameType, str, Any], object] # Objects suitable to be passed to sys.settrace, threading.settrace, and similar TraceFunction: TypeAlias = Callable[[FrameType, str, Any], TraceFunction | None] + +# experimental +# Might not work as expected for pyright, see +# https://github.com/python/typeshed/pull/9362 +# https://github.com/microsoft/pyright/issues/4339 +class DataclassInstance(Protocol): + __dataclass_fields__: ClassVar[dict[str, Field[Any]]] diff --git a/stdlib/_typeshed/dataclasses.pyi b/stdlib/_typeshed/dataclasses.pyi deleted file mode 100644 index ede41feaca6c..000000000000 --- a/stdlib/_typeshed/dataclasses.pyi +++ /dev/null @@ -1,7 +0,0 @@ -# See the README.md file in this directory for more information. - -from dataclasses import Field -from typing import Any, ClassVar, Protocol - -class DataclassInstance(Protocol): - __dataclass_fields__: ClassVar[dict[str, Field[Any]]] diff --git a/stdlib/dataclasses.pyi b/stdlib/dataclasses.pyi index 68e2bffdac86..797093895bc9 100644 --- a/stdlib/dataclasses.pyi +++ b/stdlib/dataclasses.pyi @@ -1,7 +1,7 @@ import enum import sys import types -from _typeshed.dataclasses import DataclassInstance +from _typeshed import DataclassInstance from builtins import type as Type # alias to avoid name clashes with fields named "type" from collections.abc import Callable, Iterable, Mapping from typing import Any, Generic, Protocol, TypeVar, overload