Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f367242

Browse files
authored
bpo-37045: PEP 591: Add final qualifiers to typing module (GH-13571)
The implementation is straightforward, it just mimics `ClassVar` (since the latter is also a name/access qualifier, not really a type). Also it is essentially copied from `typing_extensions`.
1 parent 47dd2f9 commit f367242

4 files changed

Lines changed: 142 additions & 4 deletions

File tree

Doc/library/typing.rst

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,31 @@ The module defines the following classes, functions and decorators:
940940

941941
See :pep:`484` for details and comparison with other typing semantics.
942942

943+
.. decorator:: final
944+
945+
A decorator to indicate to type checkers that the decorated method
946+
cannot be overridden, and the decorated class cannot be subclassed.
947+
For example::
948+
949+
class Base:
950+
@final
951+
def done(self) -> None:
952+
...
953+
class Sub(Base):
954+
def done(self) -> None: # Error reported by type checker
955+
...
956+
957+
@final
958+
class Leaf:
959+
...
960+
class Other(Leaf): # Error reported by type checker
961+
...
962+
963+
There is no runtime checking of these properties. See :pep:`591` for
964+
more details.
965+
966+
.. versionadded:: 3.8
967+
943968
.. decorator:: no_type_check
944969

945970
Decorator to indicate that annotations are not type hints.
@@ -1104,6 +1129,25 @@ The module defines the following classes, functions and decorators:
11041129

11051130
.. versionadded:: 3.5.3
11061131

1132+
.. data:: Final
1133+
1134+
A special typing construct to indicate to type checkers that a name
1135+
cannot be re-assigned or overridden in a subclass. For example::
1136+
1137+
MAX_SIZE: Final = 9000
1138+
MAX_SIZE += 1 # Error reported by type checker
1139+
1140+
class Connection:
1141+
TIMEOUT: Final[int] = 10
1142+
1143+
class FastConnector(Connection):
1144+
TIMEOUT = 1 # Error reported by type checker
1145+
1146+
There is no runtime checking of these properties. See :pep:`591` for
1147+
more details.
1148+
1149+
.. versionadded:: 3.8
1150+
11071151
.. data:: AnyStr
11081152

11091153
``AnyStr`` is a type variable defined as

Lib/test/test_typing.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from typing import Union, Optional
1313
from typing import Tuple, List, MutableMapping
1414
from typing import Callable
15-
from typing import Generic, ClassVar
15+
from typing import Generic, ClassVar, Final, final
1616
from typing import cast
1717
from typing import get_type_hints
1818
from typing import no_type_check, no_type_check_decorator
@@ -1438,6 +1438,53 @@ def test_no_isinstance(self):
14381438
issubclass(int, ClassVar)
14391439

14401440

1441+
class FinalTests(BaseTestCase):
1442+
1443+
def test_basics(self):
1444+
Final[int] # OK
1445+
with self.assertRaises(TypeError):
1446+
Final[1]
1447+
with self.assertRaises(TypeError):
1448+
Final[int, str]
1449+
with self.assertRaises(TypeError):
1450+
Final[int][str]
1451+
with self.assertRaises(TypeError):
1452+
Optional[Final[int]]
1453+
1454+
def test_repr(self):
1455+
self.assertEqual(repr(Final), 'typing.Final')
1456+
cv = Final[int]
1457+
self.assertEqual(repr(cv), 'typing.Final[int]')
1458+
cv = Final[Employee]
1459+
self.assertEqual(repr(cv), 'typing.Final[%s.Employee]' % __name__)
1460+
1461+
def test_cannot_subclass(self):
1462+
with self.assertRaises(TypeError):
1463+
class C(type(Final)):
1464+
pass
1465+
with self.assertRaises(TypeError):
1466+
class C(type(Final[int])):
1467+
pass
1468+
1469+
def test_cannot_init(self):
1470+
with self.assertRaises(TypeError):
1471+
Final()
1472+
with self.assertRaises(TypeError):
1473+
type(Final)()
1474+
with self.assertRaises(TypeError):
1475+
type(Final[Optional[int]])()
1476+
1477+
def test_no_isinstance(self):
1478+
with self.assertRaises(TypeError):
1479+
isinstance(1, Final[int])
1480+
with self.assertRaises(TypeError):
1481+
issubclass(int, Final)
1482+
1483+
def test_final_unmodified(self):
1484+
def func(x): ...
1485+
self.assertIs(func, final(func))
1486+
1487+
14411488
class CastTests(BaseTestCase):
14421489

14431490
def test_basics(self):

Lib/typing.py

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
'Any',
3636
'Callable',
3737
'ClassVar',
38+
'Final',
3839
'Generic',
3940
'Optional',
4041
'Tuple',
@@ -92,6 +93,7 @@
9293
# One-off things.
9394
'AnyStr',
9495
'cast',
96+
'final',
9597
'get_type_hints',
9698
'NewType',
9799
'no_type_check',
@@ -121,7 +123,7 @@ def _type_check(arg, msg, is_argument=True):
121123
"""
122124
invalid_generic_forms = (Generic, _Protocol)
123125
if is_argument:
124-
invalid_generic_forms = invalid_generic_forms + (ClassVar, )
126+
invalid_generic_forms = invalid_generic_forms + (ClassVar, Final)
125127

126128
if arg is None:
127129
return type(None)
@@ -336,8 +338,8 @@ def __subclasscheck__(self, cls):
336338

337339
@_tp_cache
338340
def __getitem__(self, parameters):
339-
if self._name == 'ClassVar':
340-
item = _type_check(parameters, 'ClassVar accepts only single type.')
341+
if self._name in ('ClassVar', 'Final'):
342+
item = _type_check(parameters, f'{self._name} accepts only single type.')
341343
return _GenericAlias(self, (item,))
342344
if self._name == 'Union':
343345
if parameters == ():
@@ -398,6 +400,24 @@ class Starship:
398400
be used with isinstance() or issubclass().
399401
""")
400402

403+
Final = _SpecialForm('Final', doc=
404+
"""Special typing construct to indicate final names to type checkers.
405+
406+
A final name cannot be re-assigned or overridden in a subclass.
407+
For example:
408+
409+
MAX_SIZE: Final = 9000
410+
MAX_SIZE += 1 # Error reported by type checker
411+
412+
class Connection:
413+
TIMEOUT: Final[int] = 10
414+
415+
class FastConnector(Connection):
416+
TIMEOUT = 1 # Error reported by type checker
417+
418+
There is no runtime checking of these properties.
419+
""")
420+
401421
Union = _SpecialForm('Union', doc=
402422
"""Union type; Union[X, Y] means either X or Y.
403423
@@ -1085,6 +1105,32 @@ def utf8(value):
10851105
return _overload_dummy
10861106

10871107

1108+
def final(f):
1109+
"""A decorator to indicate final methods and final classes.
1110+
1111+
Use this decorator to indicate to type checkers that the decorated
1112+
method cannot be overridden, and decorated class cannot be subclassed.
1113+
For example:
1114+
1115+
class Base:
1116+
@final
1117+
def done(self) -> None:
1118+
...
1119+
class Sub(Base):
1120+
def done(self) -> None: # Error reported by type checker
1121+
...
1122+
1123+
@final
1124+
class Leaf:
1125+
...
1126+
class Other(Leaf): # Error reported by type checker
1127+
...
1128+
1129+
There is no runtime checking of these properties.
1130+
"""
1131+
return f
1132+
1133+
10881134
class _ProtocolMeta(type):
10891135
"""Internal metaclass for _Protocol.
10901136
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PEP 591: Add ``Final`` qualifier and ``@final`` decorator to the ``typing`` module.

0 commit comments

Comments
 (0)