-
Notifications
You must be signed in to change notification settings - Fork 243
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TypingError: type checker will emit error with a message specified in typing stubs #1043
Comments
How common is this use case? Have you seen more than just this one case? |
Here are two other places in typeshed where we have
I'm sure there are yet more examples, but these two are just off the top of my head. |
A couple more examples where unreachable code warnings don't do a good job of explaining what's wrong:
|
Thanks for the additional examples. That's really helpful. If we were to add support for this, I'd prefer not to model it as a return type annotation for a couple of reasons. First, I want to avoid adding more type annotations that accept string literals as type arguments but do not expect the string to be treated as a quoted type expression. Both Second, the return type seems like it should be independent of any special error message that is emitted. In some cases, I think a decorator is a better option for this particular use case. There have been some good discussions around a standardized decorator for Here's a rough idea of what that might look like. from typing import overload, deprecated, runtime_error
# Use of "runtime_error" decorator, always emits error diagnostic
@overload
@runtime_error("Calling pow() with a mod of 0 will result in a runtime exception")
def pow(base: int, exp: int, mod: Literal[0]) -> NoReturn: ...
@overload
def pow(base: int, exp: int, mod: int) -> int: ...
@overload
def pow(base: int, exp: _PositiveInteger, mod: None = ...) -> int: ...
# Use of "deprecated" decorator; this can be presented differently if
# desired (e.g. crossed-out text at the call site)
@overload
def foo(x: int) -> int: ...
@overload
@deprecated("Option value of 'old' is deprecated")
def foo(x: int, *, option: Literal["old"]) -> int: ...
@overload
def foo(x: int, *, option: str) -> int: ... Thoughts? |
I like the idea of using a decorator, and also adding a similar I don't think |
I also like the idea of a decorator. How about |
asyncio's |
And yet another use case:
Same goes to |
I will start preparing a PEP to propose the |
Firstly a bit of bikeshedding: I think Secondly: I think it would be nice to additionally have a def open_db(mode: str):
return open('example.db', mode) # potential type error: cannot statically determine that the mode is valid It would be great if we could annotate overloads such as this one as follows: # Fallback if mode is not specified
@overload
@potential_type_error('cannot statically determine that the mode is valid')
def open(
file: _OpenFile,
mode: str,
buffering: int = ...,
encoding: str | None = ...,
errors: str | None = ...,
newline: str | None = ...,
closefd: bool = ...,
opener: _Opener | None = ...,
) -> IO[Any]: ... The difference between @JelleZijlstra I'd be happy to provide early feedback for the PEP. |
An AlternativeI want to propose an idea that is somewhat different to what is discussed here, both can exist somewhat in parallel. It consists of 2 changes: ① Make Never generic to allow more descriptive exceptions (Never[SystemExit], Never[ZeroDivisionError], etc.).A return hint of @overload
def divide(a, b: Literal[0]) -> Never[ZeroDivisionError]: ...
@overload
def divide(a: int, b: int) -> float: ... ② Change Type-Checkers behavior to raise an error whenever an instance of generic `Never` is created outside an appropriate `try`-`except` block.@overload
def divide(a, b: Literal[0]) -> Never[ZeroDivisionError]:...
@overload
def divide(a: int, b: int) -> float: ...
def divide(a, b) : return a/b
try:
divide(5, 0) # ✔ raises a ZeroDivisionError but is wrapped in a correct try-except block
except ZeroDivisionError:
...
try:
divide(5, 0) # ✘ ValueError does not cover ZeroDivisionError
except ValueError:
...
divide(5, 0) # ✘ raises ZeroDivisionError Advantages compared to
|
Calling functions that return |
@TeamSpen210 For a genuine infinite loop, I'd imagine simply non-generic |
My point is that such calls are entirely valid code, where you don't necessarily want to even catch the exception at all. Type checkers flagging the calls would simply be wrong. When you use |
@TeamSpen210 You're right, it would make more sense if only generic - |
Some ways to call certain functions are just wrong, and are known to be a bug. For example, passing type=bool to argparse's add_argument method doesn't work. To make type checkers warn about this, typeshed can currently do something like this:
When add_argument is used wrongly, you would then get errors:
This approach has a couple problems:
--strict
.The solution I would like: if you declare the return type as
TypingError["foo bar"]
, the type checker will display an error messagefoo bar
. This is similar to how#error
works in the C preprocessor.Stub:
Python file:
The text was updated successfully, but these errors were encountered: