summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_typing.py51
-rw-r--r--Lib/typing.py35
-rw-r--r--Misc/NEWS4
3 files changed, 81 insertions, 9 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 20fc2219f7..33d553ed6e 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -6,7 +6,7 @@ import sys
from unittest import TestCase, main, skipUnless, SkipTest
from copy import copy, deepcopy
-from typing import Any
+from typing import Any, NoReturn
from typing import TypeVar, AnyStr
from typing import T, KT, VT # Not in __all__.
from typing import Union, Optional
@@ -102,10 +102,6 @@ class AnyTests(BaseTestCase):
with self.assertRaises(TypeError):
type(Any)()
- def test_cannot_subscript(self):
- with self.assertRaises(TypeError):
- Any[int]
-
def test_any_works_with_alias(self):
# These expressions must simply not fail.
typing.Match[Any]
@@ -113,6 +109,40 @@ class AnyTests(BaseTestCase):
typing.IO[Any]
+class NoReturnTests(BaseTestCase):
+
+ def test_noreturn_instance_type_error(self):
+ with self.assertRaises(TypeError):
+ isinstance(42, NoReturn)
+
+ def test_noreturn_subclass_type_error(self):
+ with self.assertRaises(TypeError):
+ issubclass(Employee, NoReturn)
+ with self.assertRaises(TypeError):
+ issubclass(NoReturn, Employee)
+
+ def test_repr(self):
+ self.assertEqual(repr(NoReturn), 'typing.NoReturn')
+
+ def test_not_generic(self):
+ with self.assertRaises(TypeError):
+ NoReturn[int]
+
+ def test_cannot_subclass(self):
+ with self.assertRaises(TypeError):
+ class A(NoReturn):
+ pass
+ with self.assertRaises(TypeError):
+ class A(type(NoReturn)):
+ pass
+
+ def test_cannot_instantiate(self):
+ with self.assertRaises(TypeError):
+ NoReturn()
+ with self.assertRaises(TypeError):
+ type(NoReturn)()
+
+
class TypeVarTests(BaseTestCase):
def test_basic_plain(self):
@@ -2273,6 +2303,14 @@ class XMethBad(NamedTuple):
return 'no chance for this'
""")
+ with self.assertRaises(AttributeError):
+ exec("""
+class XMethBad2(NamedTuple):
+ x: int
+ def _source(self):
+ return 'no chance for this as well'
+""")
+
@skipUnless(PY36, 'Python 3.6 required')
def test_namedtuple_keyword_usage(self):
LocalEmployee = NamedTuple("LocalEmployee", name=str, age=int)
@@ -2420,6 +2458,9 @@ class AllTests(BaseTestCase):
self.assertNotIn('sys', a)
# Check that Text is defined.
self.assertIn('Text', a)
+ # Check previously missing classes.
+ self.assertIn('SupportsBytes', a)
+ self.assertIn('SupportsComplex', a)
if __name__ == '__main__':
diff --git a/Lib/typing.py b/Lib/typing.py
index 9a0f49099a..645bc6f8ae 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -11,9 +11,9 @@ try:
except ImportError:
import collections as collections_abc # Fallback for PY3.2.
try:
- from types import SlotWrapperType, MethodWrapperType, MethodDescriptorType
+ from types import WrapperDescriptorType, MethodWrapperType, MethodDescriptorType
except ImportError:
- SlotWrapperType = type(object.__init__)
+ WrapperDescriptorType = type(object.__init__)
MethodWrapperType = type(object().__str__)
MethodDescriptorType = type(str.join)
@@ -63,6 +63,8 @@ __all__ = [
# Structural checks, a.k.a. protocols.
'Reversible',
'SupportsAbs',
+ 'SupportsBytes',
+ 'SupportsComplex',
'SupportsFloat',
'SupportsInt',
'SupportsRound',
@@ -420,6 +422,31 @@ class _Any(_FinalTypingBase, _root=True):
Any = _Any(_root=True)
+class _NoReturn(_FinalTypingBase, _root=True):
+ """Special type indicating functions that never return.
+ Example::
+
+ from typing import NoReturn
+
+ def stop() -> NoReturn:
+ raise Exception('no way')
+
+ This type is invalid in other positions, e.g., ``List[NoReturn]``
+ will fail in static type checkers.
+ """
+
+ __slots__ = ()
+
+ def __instancecheck__(self, obj):
+ raise TypeError("NoReturn cannot be used with isinstance().")
+
+ def __subclasscheck__(self, cls):
+ raise TypeError("NoReturn cannot be used with issubclass().")
+
+
+NoReturn = _NoReturn(_root=True)
+
+
class TypeVar(_TypingBase, _root=True):
"""Type variable.
@@ -1450,7 +1477,7 @@ def _get_defaults(func):
_allowed_types = (types.FunctionType, types.BuiltinFunctionType,
types.MethodType, types.ModuleType,
- SlotWrapperType, MethodWrapperType, MethodDescriptorType)
+ WrapperDescriptorType, MethodWrapperType, MethodDescriptorType)
def get_type_hints(obj, globalns=None, localns=None):
@@ -2051,7 +2078,7 @@ _PY36 = sys.version_info[:2] >= (3, 6)
# attributes prohibited to set in NamedTuple class syntax
_prohibited = ('__new__', '__init__', '__slots__', '__getnewargs__',
'_fields', '_field_defaults', '_field_types',
- '_make', '_replace', '_asdict')
+ '_make', '_replace', '_asdict', '_source')
_special = ('__module__', '__name__', '__qualname__', '__annotations__')
diff --git a/Misc/NEWS b/Misc/NEWS
index c3eaaf2d4d..c041d6185d 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -317,6 +317,10 @@ Extension Modules
Library
-------
+- bpo-28556: Various updates to typing module: add typing.NoReturn type, use
+ WrapperDescriptorType, minor bug-fixes. Original PRs by
+ Jim Fasarakis-Hilliard and Ivan Levkivskyi.
+
- bpo-30205: Fix getsockname() for unbound AF_UNIX sockets on Linux.
- bpo-30228: The seek() and tell() methods of io.FileIO now set the internal