Skip to content

Commit

Permalink
Added support for typing.NoReturn
Browse files Browse the repository at this point in the history
Fixes #131.
  • Loading branch information
agronholm committed Jun 3, 2020
1 parent cfb06d8 commit eda2c32
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/userguide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ Type Notes
``List`` Contents are typechecked
``Literal``
``NamedTuple`` Field values are typechecked
``NoReturn``
``Protocol`` Value type checked with ``issubclass()`` against the protocol
``Set`` Contents are typechecked
``Sequence`` Contents are typechecked
Expand Down
4 changes: 4 additions & 0 deletions docs/versionhistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ Version history

This library adheres to `Semantic Versioning 2.0 <https://semver.org/#semantic-versioning-200>`_.

**UNRELEASED**

- Added support for ``typing.NoReturn``

**2.8.0** (2020-06-02)

- Added support for the ``Mock`` and ``MagicMock`` types (PR by prescod)
Expand Down
8 changes: 8 additions & 0 deletions tests/test_typeguard.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
Container, Generic, BinaryIO, TextIO, Generator, Iterator, SupportsInt, AbstractSet, AnyStr)

import pytest
from typing_extensions import NoReturn

from typeguard import (
typechecked, check_argument_types, qualified_name, TypeChecker, TypeWarning, function_name,
Expand Down Expand Up @@ -1156,6 +1157,13 @@ def foo(arg: SupportsInt):
else:
foo(value)

def test_noreturn(self):
@typechecked
def foo() -> NoReturn:
pass

pytest.raises(TypeError, foo).match(r'foo\(\) was declared never to return but it did')


class TestTypeChecker:
@pytest.fixture
Expand Down
11 changes: 11 additions & 0 deletions typeguard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@
from typing import _ForwardRef as ForwardRef # Python < 3.8
evaluate_forwardref = ForwardRef._eval_type

try:
from typing import NoReturn
except ImportError:
try:
from typing_extensions import NoReturn
except ImportError:
NoReturn = None

try:
from inspect import isasyncgenfunction, isasyncgen
except ImportError:
Expand Down Expand Up @@ -641,6 +649,9 @@ def check_return_type(retval, memo: Optional[_CallMemo] = None) -> bool:
memo = _CallMemo(func, frame.f_locals)

if 'return' in memo.type_hints:
if memo.type_hints['return'] is NoReturn:
raise TypeError('{}() was declared never to return but it did'.format(memo.func_name))

try:
check_type('the return value', retval, memo.type_hints['return'], memo)
except TypeError as exc: # suppress unnecessarily long tracebacks
Expand Down

0 comments on commit eda2c32

Please sign in to comment.