-
Notifications
You must be signed in to change notification settings - Fork 237
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
Literal for sentinel values #689
Comments
It would be nice if this could be written using
If you're willing to rewrite the code some more (beyond adding type annotations), you can usually solve this with an enum, since enums are allowed in Literal:
(Alas, I haven't found a way to alias |
You can use ...
A: Final = AA.A
def f(a: AA):
...
f(A) This mypy issue has related discussion: python/mypy#7642 |
Yeah it would be good to have some special-casing for ad-hoc sentinels. One of the main downsides I see for enum solution is that error messages if making a stub for existing library (as in original message) can be cryptic. |
What about having a naming convention for sentinel enums in stubs? Maybe something like this: class _Sentinel(Enum):
_SENTINEL = 0 This way even if the type leaks out of the stub, at least there is a hint about what it means, and the underscore prefix suggests that this is something internal to the module/stub. |
Yes, I was also thinking about this as a "quick fix". |
Good idea for a quick fix. |
Speaking about adding embedded annotations (not type stubs) I can say that I like @gvanrossum proposal (a combination of |
Here's another possible solution using _MaxLengthSentinel = NewType("_MaxLengthSentinel", object)
class PSS(AsymmetricPadding):
MAX_LENGTH: _MaxLengthSentinel
def __init__(self, mgf: MGF1, salt_length: Union[int, _MaxLengthSentinel]) -> None:
... By naming the sentinel with an underscore, it will be considered private, so the only way to get to its instance is through the MAX_LENGTH class variable. This solution appears to work fine with existing standards and type checker implementations. |
The recipe with
|
Yeah, the implementation would need to include an additional check, something like this: def f(arg: Union[str, SENTINEL_TYPE]) -> None:
if arg is SENTINEL:
arg = "default"
else:
assert isinstance(arg, str)
reveal_type(arg) |
Related: PEP 661 -- Sentinel Values |
If I read this pep correctly it would not cover the classic usage of sentinel flags, that are checked with def foo(value: int | Sentinel = MISSING) -> int:
if value is MISSING:
return 0
else:
return value + 1 would fail type checkers without special support Sentinels them since |
In the Discourse thread the author said that they've "decided to forego type signatures specific to each sentinel". Could you please comment there if you believe |
Thanks for pointing to the discussion As per https://discuss.python.org/t/pep-661-sentinel-values/9126/44 the proposed solution seem to implement The above function would be typed as |
No, the latest version of the PEP does not support sentinel literals. See https://github.com/taleinat/python-stdlib-sentinels/blob/main/pep-0661.rst#specific-type-signatures-for-each-sentinel-value. |
Understood. That's a shame, since it makes |
I think it was probably the correct decision for the PEP, since the PEP wasn't primarily typing-focused. I don't think this rules out the possibility of adding special-casing to type checkers in the future to better handle PEP 661 sentinel values. That could always be proposed in a future PEP. |
Sure, but at that point I don't understand what's the point of adding Sentinel. |
(The discuss.python.org thread is the better place to discuss that, and I see you've already posted there :) |
I needed to add type hints to a function with a default sentinel object idiom, i.e. RAISE_ERROR = object()
def get_something(name, default=RAISE_ERROR):
... I solved it by using RAISE_ERROR = object()
import typing
@typing.overload
def get_something(name: str) -> str: ...
@typing.overload
def get_something(name: str, default: str) -> str: ...
def get_something(name, default=RAISE_ERROR):
... It doesn't type check the function body but this was fine in my case since the function itself was trivial and I was mostly interested in adding type hints to the signature! |
See python/typing#689 and PEP 661 which look related. But really I still want my plugin that lets me separate between public API types and private API types.
This came up python/typeshed#3521: Currently I can't think of a way to type sentinel values that are often constructed by allowing a certain instance of
object
as the argument. For the example above it would be useful to be able to do something like this:Alternatively we could add a type like
Singleton
type to typing:The text was updated successfully, but these errors were encountered: