Skip to content

Commit 48082ad

Browse files
authored
Add NoReturn type (#397)
* Add NoReturn type * Simplify NoReturn checks
1 parent c5f842d commit 48082ad

File tree

4 files changed

+129
-2
lines changed

4 files changed

+129
-2
lines changed

python2/test_typing.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from unittest import TestCase, main, SkipTest
88
from copy import copy, deepcopy
99

10-
from typing import Any
10+
from typing import Any, NoReturn
1111
from typing import TypeVar, AnyStr
1212
from typing import T, KT, VT # Not in __all__.
1313
from typing import Union, Optional
@@ -106,6 +106,40 @@ def test_any_is_subclass(self):
106106
typing.IO[Any]
107107

108108

109+
class NoReturnTests(BaseTestCase):
110+
111+
def test_noreturn_instance_type_error(self):
112+
with self.assertRaises(TypeError):
113+
isinstance(42, NoReturn)
114+
115+
def test_noreturn_subclass_type_error(self):
116+
with self.assertRaises(TypeError):
117+
issubclass(Employee, NoReturn)
118+
with self.assertRaises(TypeError):
119+
issubclass(NoReturn, Employee)
120+
121+
def test_repr(self):
122+
self.assertEqual(repr(NoReturn), 'typing.NoReturn')
123+
124+
def test_not_generic(self):
125+
with self.assertRaises(TypeError):
126+
NoReturn[int]
127+
128+
def test_cannot_subclass(self):
129+
with self.assertRaises(TypeError):
130+
class A(NoReturn):
131+
pass
132+
with self.assertRaises(TypeError):
133+
class A(type(NoReturn)):
134+
pass
135+
136+
def test_cannot_instantiate(self):
137+
with self.assertRaises(TypeError):
138+
NoReturn()
139+
with self.assertRaises(TypeError):
140+
type(NoReturn)()
141+
142+
109143
class TypeVarTests(BaseTestCase):
110144

111145
def test_basic_plain(self):

python2/typing.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,40 @@ def __subclasscheck__(self, cls):
478478
Any = _Any(_root=True)
479479

480480

481+
class NoReturnMeta(TypingMeta):
482+
"""Metaclass for NoReturn."""
483+
484+
def __new__(cls, name, bases, namespace):
485+
cls.assert_no_subclassing(bases)
486+
self = super(NoReturnMeta, cls).__new__(cls, name, bases, namespace)
487+
return self
488+
489+
490+
class _NoReturn(_FinalTypingBase):
491+
"""Special type indicating functions that never return.
492+
Example::
493+
494+
from typing import NoReturn
495+
496+
def stop() -> NoReturn:
497+
raise Exception('no way')
498+
499+
This type is invalid in other positions, e.g., ``List[NoReturn]``
500+
will fail in static type checkers.
501+
"""
502+
__metaclass__ = NoReturnMeta
503+
__slots__ = ()
504+
505+
def __instancecheck__(self, obj):
506+
raise TypeError("NoReturn cannot be used with isinstance().")
507+
508+
def __subclasscheck__(self, cls):
509+
raise TypeError("NoReturn cannot be used with issubclass().")
510+
511+
512+
NoReturn = _NoReturn(_root=True)
513+
514+
481515
class TypeVarMeta(TypingMeta):
482516
def __new__(cls, name, bases, namespace):
483517
cls.assert_no_subclassing(bases)

src/test_typing.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from unittest import TestCase, main, skipUnless, SkipTest
77
from copy import copy, deepcopy
88

9-
from typing import Any
9+
from typing import Any, NoReturn
1010
from typing import TypeVar, AnyStr
1111
from typing import T, KT, VT # Not in __all__.
1212
from typing import Union, Optional
@@ -109,6 +109,40 @@ def test_any_works_with_alias(self):
109109
typing.IO[Any]
110110

111111

112+
class NoReturnTests(BaseTestCase):
113+
114+
def test_noreturn_instance_type_error(self):
115+
with self.assertRaises(TypeError):
116+
isinstance(42, NoReturn)
117+
118+
def test_noreturn_subclass_type_error(self):
119+
with self.assertRaises(TypeError):
120+
issubclass(Employee, NoReturn)
121+
with self.assertRaises(TypeError):
122+
issubclass(NoReturn, Employee)
123+
124+
def test_repr(self):
125+
self.assertEqual(repr(NoReturn), 'typing.NoReturn')
126+
127+
def test_not_generic(self):
128+
with self.assertRaises(TypeError):
129+
NoReturn[int]
130+
131+
def test_cannot_subclass(self):
132+
with self.assertRaises(TypeError):
133+
class A(NoReturn):
134+
pass
135+
with self.assertRaises(TypeError):
136+
class A(type(NoReturn)):
137+
pass
138+
139+
def test_cannot_instantiate(self):
140+
with self.assertRaises(TypeError):
141+
NoReturn()
142+
with self.assertRaises(TypeError):
143+
type(NoReturn)()
144+
145+
112146
class TypeVarTests(BaseTestCase):
113147

114148
def test_basic_plain(self):

src/typing.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,31 @@ def __subclasscheck__(self, cls):
420420
Any = _Any(_root=True)
421421

422422

423+
class _NoReturn(_FinalTypingBase, _root=True):
424+
"""Special type indicating functions that never return.
425+
Example::
426+
427+
from typing import NoReturn
428+
429+
def stop() -> NoReturn:
430+
raise Exception('no way')
431+
432+
This type is invalid in other positions, e.g., ``List[NoReturn]``
433+
will fail in static type checkers.
434+
"""
435+
436+
__slots__ = ()
437+
438+
def __instancecheck__(self, obj):
439+
raise TypeError("NoReturn cannot be used with isinstance().")
440+
441+
def __subclasscheck__(self, cls):
442+
raise TypeError("NoReturn cannot be used with issubclass().")
443+
444+
445+
NoReturn = _NoReturn(_root=True)
446+
447+
423448
class TypeVar(_TypingBase, _root=True):
424449
"""Type variable.
425450

0 commit comments

Comments
 (0)