summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/typing.rst44
-rw-r--r--Lib/test/test_typing.py49
-rw-r--r--Lib/typing.py52
-rw-r--r--Misc/NEWS.d/next/Library/2019-05-25-18-36-50.bpo-37045.suHdVJ.rst1
4 files changed, 142 insertions, 4 deletions
diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst
index 86a3db8..8362f1d 100644
--- a/Doc/library/typing.rst
+++ b/Doc/library/typing.rst
@@ -940,6 +940,31 @@ The module defines the following classes, functions and decorators:
See :pep:`484` for details and comparison with other typing semantics.
+.. decorator:: final
+
+ A decorator to indicate to type checkers that the decorated method
+ cannot be overridden, and the decorated class cannot be subclassed.
+ For example::
+
+ class Base:
+ @final
+ def done(self) -> None:
+ ...
+ class Sub(Base):
+ def done(self) -> None: # Error reported by type checker
+ ...
+
+ @final
+ class Leaf:
+ ...
+ class Other(Leaf): # Error reported by type checker
+ ...
+
+ There is no runtime checking of these properties. See :pep:`591` for
+ more details.
+
+ .. versionadded:: 3.8
+
.. decorator:: no_type_check
Decorator to indicate that annotations are not type hints.
@@ -1104,6 +1129,25 @@ The module defines the following classes, functions and decorators:
.. versionadded:: 3.5.3
+.. data:: Final
+
+ A special typing construct to indicate to type checkers that a name
+ cannot be re-assigned or overridden in a subclass. For example::
+
+ MAX_SIZE: Final = 9000
+ MAX_SIZE += 1 # Error reported by type checker
+
+ class Connection:
+ TIMEOUT: Final[int] = 10
+
+ class FastConnector(Connection):
+ TIMEOUT = 1 # Error reported by type checker
+
+ There is no runtime checking of these properties. See :pep:`591` for
+ more details.
+
+ .. versionadded:: 3.8
+
.. data:: AnyStr
``AnyStr`` is a type variable defined as
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index c9bfd0c..3d93eb3 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -12,7 +12,7 @@ from typing import T, KT, VT # Not in __all__.
from typing import Union, Optional
from typing import Tuple, List, MutableMapping
from typing import Callable
-from typing import Generic, ClassVar
+from typing import Generic, ClassVar, Final, final
from typing import cast
from typing import get_type_hints
from typing import no_type_check, no_type_check_decorator
@@ -1438,6 +1438,53 @@ class ClassVarTests(BaseTestCase):
issubclass(int, ClassVar)
+class FinalTests(BaseTestCase):
+
+ def test_basics(self):
+ Final[int] # OK
+ with self.assertRaises(TypeError):
+ Final[1]
+ with self.assertRaises(TypeError):
+ Final[int, str]
+ with self.assertRaises(TypeError):
+ Final[int][str]
+ with self.assertRaises(TypeError):
+ Optional[Final[int]]
+
+ def test_repr(self):
+ self.assertEqual(repr(Final), 'typing.Final')
+ cv = Final[int]
+ self.assertEqual(repr(cv), 'typing.Final[int]')
+ cv = Final[Employee]
+ self.assertEqual(repr(cv), 'typing.Final[%s.Employee]' % __name__)
+
+ def test_cannot_subclass(self):
+ with self.assertRaises(TypeError):
+ class C(type(Final)):
+ pass
+ with self.assertRaises(TypeError):
+ class C(type(Final[int])):
+ pass
+
+ def test_cannot_init(self):
+ with self.assertRaises(TypeError):
+ Final()
+ with self.assertRaises(TypeError):
+ type(Final)()
+ with self.assertRaises(TypeError):
+ type(Final[Optional[int]])()
+
+ def test_no_isinstance(self):
+ with self.assertRaises(TypeError):
+ isinstance(1, Final[int])
+ with self.assertRaises(TypeError):
+ issubclass(int, Final)
+
+ def test_final_unmodified(self):
+ def func(x): ...
+ self.assertIs(func, final(func))
+
+
class CastTests(BaseTestCase):
def test_basics(self):
diff --git a/Lib/typing.py b/Lib/typing.py
index 7aab162..06a7eb0 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -35,6 +35,7 @@ __all__ = [
'Any',
'Callable',
'ClassVar',
+ 'Final',
'Generic',
'Optional',
'Tuple',
@@ -92,6 +93,7 @@ __all__ = [
# One-off things.
'AnyStr',
'cast',
+ 'final',
'get_type_hints',
'NewType',
'no_type_check',
@@ -121,7 +123,7 @@ def _type_check(arg, msg, is_argument=True):
"""
invalid_generic_forms = (Generic, _Protocol)
if is_argument:
- invalid_generic_forms = invalid_generic_forms + (ClassVar, )
+ invalid_generic_forms = invalid_generic_forms + (ClassVar, Final)
if arg is None:
return type(None)
@@ -336,8 +338,8 @@ class _SpecialForm(_Final, _Immutable, _root=True):
@_tp_cache
def __getitem__(self, parameters):
- if self._name == 'ClassVar':
- item = _type_check(parameters, 'ClassVar accepts only single type.')
+ if self._name in ('ClassVar', 'Final'):
+ item = _type_check(parameters, f'{self._name} accepts only single type.')
return _GenericAlias(self, (item,))
if self._name == 'Union':
if parameters == ():
@@ -398,6 +400,24 @@ ClassVar = _SpecialForm('ClassVar', doc=
be used with isinstance() or issubclass().
""")
+Final = _SpecialForm('Final', doc=
+ """Special typing construct to indicate final names to type checkers.
+
+ A final name cannot be re-assigned or overridden in a subclass.
+ For example:
+
+ MAX_SIZE: Final = 9000
+ MAX_SIZE += 1 # Error reported by type checker
+
+ class Connection:
+ TIMEOUT: Final[int] = 10
+
+ class FastConnector(Connection):
+ TIMEOUT = 1 # Error reported by type checker
+
+ There is no runtime checking of these properties.
+ """)
+
Union = _SpecialForm('Union', doc=
"""Union type; Union[X, Y] means either X or Y.
@@ -1085,6 +1105,32 @@ def overload(func):
return _overload_dummy
+def final(f):
+ """A decorator to indicate final methods and final classes.
+
+ Use this decorator to indicate to type checkers that the decorated
+ method cannot be overridden, and decorated class cannot be subclassed.
+ For example:
+
+ class Base:
+ @final
+ def done(self) -> None:
+ ...
+ class Sub(Base):
+ def done(self) -> None: # Error reported by type checker
+ ...
+
+ @final
+ class Leaf:
+ ...
+ class Other(Leaf): # Error reported by type checker
+ ...
+
+ There is no runtime checking of these properties.
+ """
+ return f
+
+
class _ProtocolMeta(type):
"""Internal metaclass for _Protocol.
diff --git a/Misc/NEWS.d/next/Library/2019-05-25-18-36-50.bpo-37045.suHdVJ.rst b/Misc/NEWS.d/next/Library/2019-05-25-18-36-50.bpo-37045.suHdVJ.rst
new file mode 100644
index 0000000..001529e
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-05-25-18-36-50.bpo-37045.suHdVJ.rst
@@ -0,0 +1 @@
+PEP 591: Add ``Final`` qualifier and ``@final`` decorator to the ``typing`` module. \ No newline at end of file