Skip to content

Commit 1ac0d00

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 1ac0d00

File tree

1 file changed

+13
-6
lines changed

1 file changed

+13
-6
lines changed

stdlib/dataclasses.pyi

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
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"
4-
from typing import Any, Callable, Generic, Iterable, Mapping, Protocol, TypeVar, overload
5+
from typing import Any, Callable, Generic, Iterable, Literal, Mapping, Protocol, TypeVar, overload
56

67
if sys.version_info >= (3, 9):
78
from types import GenericAlias
89

910
_T = TypeVar("_T")
1011
_T_co = TypeVar("_T_co", covariant=True)
1112

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

14-
MISSING: _MISSING_TYPE
21+
MISSING = _MISSING_TYPE.MISSING
1522

1623
if sys.version_info >= (3, 10):
1724
class KW_ONLY: ...
@@ -72,15 +79,15 @@ class _DefaultFactory(Protocol[_T_co]):
7279
class Field(Generic[_T]):
7380
name: str
7481
type: Type[_T]
75-
default: _T
76-
default_factory: _DefaultFactory[_T]
82+
default: _T | Literal[MISSING]
83+
default_factory: _DefaultFactory[_T] | Literal[MISSING]
7784
repr: bool
7885
hash: bool | None
7986
init: bool
8087
compare: bool
8188
metadata: types.MappingProxyType[Any, Any]
8289
if sys.version_info >= (3, 10):
83-
kw_only: bool
90+
kw_only: bool | Literal[MISSING]
8491
def __init__(
8592
self,
8693
default: _T,

0 commit comments

Comments
 (0)