mypy
mypy copied to clipboard
sys.exit() is not considered as noreturn
https://mypy-play.net/?mypy=latest&python=3.10&flags=strict%2Cstrict-equality&gist=e86aa52c05acd36b6c04067cb6f44ce1
import sys
def main() -> int:
return sys.exit(42)
MyPy finds nothing wrong here.
Anyway, this should be valid:
try:
sys.exit(42)
except SystemExit:
print('xxx') # this line IS reachable.
i.e. this function either raises specific exception or noreturn.
Can you clarify what you think the bug is? Mypy is correct when it doesn't produce any errors on your first sample, because a function that never returns is a valid Callable[[], int].
Looks like sys.exit is indeed recognised as returning NoReturn: https://mypy-play.net/?mypy=latest&python=3.10&flags=strict%2Cstrict-equality%2Cwarn-unreachable&gist=ef39ea5ba16960f2dd4274349a2c142d
So, it looks fine to me!
Using return value of noreturn function is an error, indeed.
Feel free to reopen if you have other questions / problems :)
@sobolevn please reopen. It's not fixed actually.
Can you please specify what example is not fixed?
The first one. Mypy does not see any errors in using value of noreturn function.
The first code sample is not a bug. Mypy is correct in not emitting an error here. NoReturn (which is equivalent to the recently-introduced typing.Never type) is a bottom type in the Python type system, and it is is compatible with all other types. A return value of type NoReturn is compatible with the declared return type int.
I think, Noreturn must not be compatible with any other type. What the case when it should be compatible ?
Should be def sys.exit(arg: int) -> Never. Does not it ? That is the same as -> NoReturn here. Both must be incompatible with any other type, like int.
NoReturn is another name for Never. It is the "bottom type" in Python type system. You can think of it as equivalent to an empty union. NoReturn is compatible with all other types. No other type (other than NoReturn itself) is compatible with NoReturn.
Thanks for verbose explanation. I checked TypeScript:
const sys_exit: (code: number) => never = (code: number) => {
throw new Error('message');
};
const x: number = sys_exit(42);
It also sees nothing wrong here.

I still don't understand why NoReturn / Never should be compatible with all types. For me, it must not by definition. Seems I don't understand something important in typing system. Will be great if you provide a link.
Because a value of Never can not exist, it is safe to use as a value of any type.
https://en.wikipedia.org/wiki/Bottom_type
def n() -> Never: raise Exception
print(n() + 1)
At runtime, this will not produce a TypeError, because the + will never be executed.
Why not make it incompatible with any type to detect obvious errors such as trying to use return value of noreturn functions ?
Why not make it incompatible with any type to detect obvious errors such as trying to use return value of noreturn functions ?
I think what you are asking for is more in the realm of a linting rule*: NoReturn is perfectly type-safe, but using the value of a function that does not return is a code smell and indicative of a potential bug / misunderstanding of the developer about what a function does.
I like the idea for that reason, idk if it belongs in mypy / pyright (maybe as an optional setting?). But few python linters are type-aware. I would personally turn on that rule if I had the option.
* It wouldn't the be the first time a type-checker has a rule that's not specific to typing (pyright has a few I like).
@Avasam Mypy complains on usages of functions that return None, so I think it would be make sense if this was included in mypy.
def foo() -> None:
return
a: int | None = foo() # error: "foo" does not return a value [func-returns-value]
https://mypy-play.net/?mypy=latest&python=3.11&gist=e15787211c8a4115c82687bc15fee244
Perhaps the title of this issue could be updated to be something like "Warn on usage of Never/NoReturn result"
Mypy is working correctly here. This isn't a bug. I recommend closing.