You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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:
Reacted by Joshua Bronson, Max Marrone, Conchylicultor, Pavel Perestoronin, Kevin M Granger, Gram, Christian Ciach, herr kaste, amgg, Wojtek Ruszczewski and 6 more
It would be nice if this could be written using Final and Literal:
# Does not work (yet)
A: Final = object()
def f(a: Literal[A]): ...
f(A)
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:
# This does work
class AA(Enum):
A = 0
A: Final = AA.A
def f(a: Literal[AA.A]):
...
f(A)
(Alas, I haven't found a way to alias A = AA.A and be able to write Literal[A].)
Reacted by Andrew Svetlov, Mikhail Golubev, Conchylicultor, Tushar Sadhwani, Kevin M Granger, Nyuan Zhang, Christian Ciach, Max Marrone, Jason-jw-lin and Roman
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.
Speaking about adding embedded annotations (not type stubs) I can say that I like @gvanrossum proposal (a combination of Final and Literal) very much.
It naturally reflects what is going on in the Python runtime.
Reacted by Mikhail Golubev, Guido van Rossum and Christian Ciach
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.
Reacted by Andrew Svetlov, decorator-factory, Max Marrone, Ivailo Karamanolev and nathan lodge
If I read this pep correctly it would not cover the classic usage of sentinel flags, that are checked with is
Implementing the example given using the classic is check
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 is comparisons are vital?
Understood. That's a shame, since it makes Sentinel use very cumbersome when using type checkers
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.
If we don't care about type checking support I think the classic flag = object() (or the flag = type('flag', (), {})() works fine enough
Sure, but at that point I don't understand what's the point of adding Signature. If we don't care about type checking support I think the classic flag = object() (or the flag = type('flag', (), {})() works fine enough
(The discuss.python.org thread is the better place to discuss that, and I see you've already posted there :)
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!
Reacted by Max Marrone, Kevin M Granger, amgg and Jason-jw-lin
Activity
gvanrossum commentedon Dec 4, 2019
It would be nice if this could be written using
FinalandLiteral: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
A = AA.Aand be able to writeLiteral[A].)JukkaL commentedon Dec 4, 2019
You can use
AAas the type instead ofListeral[AA.A]:This mypy issue has related discussion: python/mypy#7642
ilevkivskyi commentedon Dec 4, 2019
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.
JukkaL commentedon Dec 4, 2019
What about having a naming convention for sentinel enums in stubs? Maybe something like this:
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.
ilevkivskyi commentedon Dec 4, 2019
Yes, I was also thinking about this as a "quick fix".
srittau commentedon Dec 4, 2019
Good idea for a quick fix.
asvetlov commentedon Nov 24, 2020
Speaking about adding embedded annotations (not type stubs) I can say that I like @gvanrossum proposal (a combination of
FinalandLiteral) very much.It naturally reflects what is going on in the Python runtime.
erictraut commentedon Nov 24, 2020
Here's another possible solution using
NewType.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.
asvetlov commentedon Nov 25, 2020
The recipe with
NewTypehas flaws:isdoesn't removeSENTINELtype asarg is Nonedoes inmypy.erictraut commentedon Nov 25, 2020
Yeah, the implementation would need to include an additional check, something like this:
srittau commentedon Nov 4, 2021
Related: PEP 661 -- Sentinel Values
CaselIT commentedon Sep 14, 2022
If I read this pep correctly it would not cover the classic usage of sentinel flags, that are checked with
isImplementing the example given using the classic
ischeckwould fail type checkers without special support Sentinels them since
valuewould still have typeint | Sentinellayday commentedon Sep 14, 2022
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
iscomparisons are vital?CaselIT commentedon Sep 14, 2022
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
Literal[MISSING]. So the Pep text seems outdated. That's unless I haven't missed anything in the discussionThe above function would be typed as
def foo(value: int | Literal[MISSING]= MISSING) -> int:makingiswork with type checkerslayday commentedon Sep 14, 2022
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.
CaselIT commentedon Sep 14, 2022
Understood. That's a shame, since it makes
Sentineluse very cumbersome when using type checkersAlexWaygood commentedon Sep 14, 2022
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.
CaselIT commentedon Sep 14, 2022
Sure, but at that point I don't understand what's the point of adding Sentinel.
If we don't care about type checking support I think the classic
flag = object()(or theflag = type('flag', (), {})()works fine enoughAlexWaygood commentedon Sep 14, 2022
(The discuss.python.org thread is the better place to discuss that, and I see you've already posted there :)
pelme commentedon Nov 17, 2022
I needed to add type hints to a function with a default sentinel object idiom, i.e.
I solved it by using
@overload: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!
Do more silly things to pepper over type checking nonsense.
some workarounds for using ... as sentinel until python/typing#689 is…
Do more silly things to pepper over type checking nonsense.
Do more silly things to pepper over type checking nonsense.