Skip to content

Commit 08cffdb

Browse files
committed
Change PEP 746 to use an attribute instead of a method
1 parent 2eb4fe5 commit 08cffdb

File tree

1 file changed

+27
-33
lines changed

1 file changed

+27
-33
lines changed

peps/pep-0746.rst

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -45,62 +45,47 @@ Specification
4545
=============
4646
This PEP introduces a protocol that can be used by static and runtime type checkers to validate
4747
the consistency between ``Annotated`` metadata and a given type.
48-
Objects that implement this protocol have a method named ``__supports_type__``
49-
that takes a single positional argument and returns ``bool``::
48+
Objects that implement this protocol have a property, attribute called ``__supports_type__``
49+
that specifies whether the metadata is valid for a given type.
5050

5151
class Int64:
52-
def __supports_type__(self, obj: int) -> bool:
53-
return isinstance(obj, int)
52+
__supports_type__: int
5453

55-
The protocol being introduced would be defined as follows if it were to be defined in code form::
54+
The attribute may also be marked as a ``ClassVar`` to avoid interaction with dataclasses:
55+
56+
from dataclasses import dataclass
57+
from typing import ClassVar
5658

57-
from typing import Protocol
58-
59-
class SupportsType[T](Protocol):
60-
def __supports_type__(self, obj: T, /) -> bool:
61-
...
59+
@dataclass
60+
class Gt:
61+
value: int
62+
__supports_type__: ClassVar[int]
6263

6364
When a static type checker encounters a type expression of the form ``Annotated[T, M1, M2, ...]``,
6465
it should enforce that for each metadata element in ``M1, M2, ...``, one of the following is true:
6566

6667
* The metadata element evaluates to an object that does not have a ``__supports_type__`` attribute; or
67-
* The metadata element evaluates to an object ``M`` that implements the ``SupportsType`` protocol;
68-
and, with ``T`` instantiated to a value ``v``, a call to ``M.__supports_type__(v)`` type checks without errors;
69-
and that call does not evaluate to ``Literal[False]``.
68+
* The metadata element evaluates to an object ``M`` that has a the ``__supports_type__`` attribute;
69+
and, with ``T`` instantiated to a value ``v``, ``v`` can be assigned to ``M.__supports_type__`` without error.
7070

71-
The body of the ``__supports_type__`` method is not used to check the validity of the metadata
72-
and static type checkers can ignore it. However, tools that use the annotation at
73-
runtime may call the method to check that a particular value is valid.
74-
75-
For example, to support a generic ``Gt`` metadata, one might write::
71+
To support a generic ``Gt`` metadata, one might write::
7672

7773
from typing import Protocol
7874

7975
class SupportsGt[T](Protocol):
8076
def __gt__(self, __other: T) -> bool:
8177
...
82-
78+
8379
class Gt[T]:
80+
__supports_type__: ClassVar[SupportsGt[T]]
81+
8482
def __init__(self, value: T) -> None:
8583
self.value = value
8684

87-
def __supports_type__(self, obj: SupportsGt[T], /) -> bool:
88-
return obj > self.value
89-
9085
x1: Annotated[int, Gt(0)] = 1 # OK
9186
x2: Annotated[str, Gt(0)] = 0 # type checker error: str is not assignable to SupportsGt[int]
9287
x3: Annotated[int, Gt(1)] = 0 # OK for static type checkers; runtime type checkers may flag this
9388

94-
Implementations may be generic and may use overloads that return ``Literal[True]`` or ``Literal[False]``
95-
to indicate if the metadata is valid for the given type.
96-
97-
Implementations may raise a NotImplementedError if they cannot determine if the metadata is valid for the given type.
98-
Tools calling ``__supports_type__`` at runtime should catch this exception and treat it as if ``__supports_type__``
99-
was not present; they should not take this as an indication that the metadata is invalid for the type.
100-
101-
Tools that use the metadata at runtime may choose to ignore the implementation of ``__supports_type__``; this PEP does not
102-
specify how the method should be used at runtime, only that it may be available for use.
103-
10489
Backwards Compatibility
10590
=======================
10691

@@ -150,10 +135,19 @@ does not generally use marker base classes. In addition, it provides less flexib
150135
the current proposal: it would not allow overloads, and it would require metadata objects
151136
to add a new base class, which may make their runtime implementation more complex.
152137

138+
Using a method instead of an attribute for ``__supports_type__``
139+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
140+
141+
We considered using a method instead of an attribute for the protocol, so that this method can be used
142+
at runtime to check the validity of the metadata and to support overloads or returning boolean literals.
143+
However using a method adds boilerplate to the implementation and the value of the runtime use cases or
144+
more complex scenarios involving overloads and returning boolean literals was not clear.
145+
153146
Acknowledgments
154147
===============
155148

156-
We thank Eric Traut for suggesting the idea of using a protocol.
149+
We thank Eric Traut for suggesting the idea of using a protocol and implementing provisional support in Pyright.
150+
Thank you to Jelle Zijlstra for sponsoring this PEP.
157151

158152
Copyright
159153
=========

0 commit comments

Comments
 (0)