Skip to content

Commit 397786b

Browse files
committed
Use enum trick for dataclasses.MISSING
The goal of this change is to fix the behavior of `dataclasses.Field`. Several attributes of a `Field` may have a value of `MISSING` (a sentinel value). As a result, attributes of Field may be checked against `MISSING` as in [f for f in fields(obj) if f.default is MISSING] `default`, `default_factory`, and `kw_only` are the attributes which may have a value of `MISSING`. This workaround of defining `_MISSING_TYPE` as an enum, and `MISSING` as its only member, allows `... | Literal[MISSING]` to be used in type annotations for these attributes. This is very slightly inaccurate -- primarily in that `_MISSING_TYPE` isn't really an enum -- but this allows for use in `Literal`. After PEP 661 (Sentinel Values), there may be a more accurate way of writing this, but for now this works. This adjustment is only applied to the attributes of Field, not the arguments to functions and methods.
1 parent 4d21d5a commit 397786b

File tree

1 file changed

+13
-5
lines changed

1 file changed

+13
-5
lines changed

stdlib/dataclasses.pyi

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
1+
import enum
12
import sys
23
import types
34
from builtins import type as Type # alias to avoid name clashes with fields named "type"
45
from typing import Any, Callable, Generic, Iterable, Mapping, Protocol, TypeVar, overload
6+
from typing_extensions import Literal
57

68
if sys.version_info >= (3, 9):
79
from types import GenericAlias
810

911
_T = TypeVar("_T")
1012
_T_co = TypeVar("_T_co", covariant=True)
1113

12-
class _MISSING_TYPE: ...
14+
# define _MISSING_TYPE as an enum within the type stubs,
15+
# even though that is not really its type at runtime
16+
# this allows us to use Literal[MISSING]
17+
# for background, see:
18+
# https://github.com/python/typeshed/pull/5900#issuecomment-895513797
19+
class _MISSING_TYPE(enum.Enum):
20+
MISSING = enum.auto()
1321

14-
MISSING: _MISSING_TYPE
22+
MISSING = _MISSING_TYPE.MISSING
1523

1624
if sys.version_info >= (3, 10):
1725
class KW_ONLY: ...
@@ -72,15 +80,15 @@ class _DefaultFactory(Protocol[_T_co]):
7280
class Field(Generic[_T]):
7381
name: str
7482
type: Type[_T]
75-
default: _T
76-
default_factory: _DefaultFactory[_T]
83+
default: _T | Literal[_MISSING_TYPE.MISSING]
84+
default_factory: _DefaultFactory[_T] | Literal[_MISSING_TYPE.MISSING]
7785
repr: bool
7886
hash: bool | None
7987
init: bool
8088
compare: bool
8189
metadata: types.MappingProxyType[Any, Any]
8290
if sys.version_info >= (3, 10):
83-
kw_only: bool
91+
kw_only: bool | Literal[_MISSING_TYPE.MISSING]
8492
def __init__(
8593
self,
8694
default: _T,

0 commit comments

Comments
 (0)