Python Type Hints - What’s the point of NoReturn?

2021-05-20 Hey, who did a no return of half my letters!?

Sometimes functions never return, for example by always raising an exception. For such functions’ return types, we can “get away” with using None, but it’s best to use the special NoReturn type). This allows Mypy to better find unreachable code (as covered previously). It also shows future readers that the lack of return is intentional.

For example, take this code:

def always_raise() -> None:
    raise RuntimeError("Uh oh")

def main() -> None:

Calling always_raise() means that we’ll have a RuntimeError, and print("Ok!") cannot be reached. But if we check with Mypy, it cannot detect this:

$ mypy --warn-unreachable
Success: no issues found in 1 source file

Let’s update the code to instead use NoReturn:

from typing import NoReturn

def always_raise() -> NoReturn:
    raise RuntimeError("Uh oh")

def main() -> None:

Now Mypy tells us the print() will never run:

$ mypy --warn-unreachable error: Statement is unreachable
Found 1 error in 1 file (checked 1 source file)


It’s best to use NoReturn for any function that never returns. These includes functions with infinite loops or use of OS API’s that end the process:

import os
from typing import NoReturn

def loop_forever() -> NoReturn:
    while True:
        ...  # loop never exits with 'break'

def abruptly_die() -> NoReturn:


We are now past the point of NoReturn,


🎉 My book Speed Up Your Django Tests is now up to date for Django 3.2. 🎉
Buy now on Gumroad

Subscribe via RSS, Twitter, or email:

One summary email a week, no spam, I pinky promise.

Related posts:

Tags: mypy, python