-
-
Notifications
You must be signed in to change notification settings - Fork 31k
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
bpo-43453: Update and re-add example to typing runtime_checkable #27013
bpo-43453: Update and re-add example to typing runtime_checkable #27013
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the docs improvement. The example looks good, I just have a few questions below.
Doc/library/typing.rst
Outdated
not their type signatures. | ||
:func:`runtime_checkable` will check only the presence of the required | ||
methods, not their type signatures. For example, :class:`ssl.SSLObject` | ||
implements :func:`__init__`, therefore it passes an :func:`issubclass` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Runtime protocol checking is an area which I'm not too familiar with so I may be wrong here, but isn't the requirement for Callable
to define __call__
, not __init__
?
https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
__call__
makes the instances callable, not the class itself. In my testing, a class meets the Callable check if it doesn't have __call__
defined, and it works if init is either explicitly defined or implicitly inherited from object
. However, this class -- SSLObject -- cannot be called because init raises an exception. So this example illustrates that check for callable will tell you SSLObject is callable when in fact it's not callable in practice due to the dunder method raising an exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[ins] In [89]: class A:
...: def __init__(self):0
...:
[ins] In [90]: isinstance(A,Callable)
Out[90]: True
[ins] In [91]: class B:pass
[ins] In [92]: isinstance(B,Callable)
Out[92]: True
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, interesting sleuthing. Thanks for investigating!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this has anything to play in it, but a class implicitly has __call__
from the type object:
>>> class A: ...
>>> A.__call__
<method-wrapper '__call__' of type object at 0x0000028F6E186DE0>
>>> type(A).__call__
<slot wrapper '__call__' of 'type' objects>
>>> type(A).__call__(A)
<__main__.A object at 0x0000028F6DE94280>
>>> A()
<__main__.A object at 0x0000028F6DE8BED0>
As you can see, the last two are equivalent. This corresponds to what the docs say about callables https://docs.python.org/3/reference/datamodel.html#object.__call__. Also mentioned here for callable()
https://docs.python.org/3/library/functions.html#callable
The part I'm nitpicky about is saying ssl.SSLObject
passes the issubclass
check because it defines __init__
. I think that's untrue -- it passes the check because all classes are callable (as mentioned in the docs for callable()
above). I completely agree with the part about __init__
being used for raising exceptions.
I think the phrasing would be better if it became this:
:func:`runtime_checkable` will check only the presence of the required
methods, not their type signatures. For example, :class:`ssl.SSLObject`
is a class, therefore it passes an :func:`issubclass`
check against :data:`Callable`. However, the
:meth:`ssl.SSLObject.__init__` method exists only to raise a
:exc:`TypeError` with a more informative message.
Sorry about the bikshedding!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, good catch! I think your edit is good, but I want to highlight the fact that init as implemented makes this class uncallable, maybe something like this:
:func:`runtime_checkable` will check only the presence of the required
methods, not their type signatures. For example, :class:`ssl.SSLObject`
is a class, therefore it passes an :func:`issubclass`
check against :data:`Callable`. However, the
:meth:`ssl.SSLObject.__init__` method exists only to raise a
:exc:`TypeError` with a more informative message, therefore making
it impossible to call (instantiate) :class:`ssl.SSLObject`.
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great!
Co-authored-by: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
@gvanrossum: Please replace |
Does this need backports? |
I believe it does - but only to 3.10, not to 3.9. |
@Fidget-Spinner thanks for the review :) |
Thanks @akulakov for the PR, and @gvanrossum for merging it 🌮🎉.. I'm working now to backport this PR to: 3.10. |
GH-27036 is a backport of this pull request to the 3.10 branch. |
…honGH-27013) Co-authored-by: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> (cherry picked from commit 17f94e2) Co-authored-by: andrei kulakov <andrei.avk@gmail.com>
This example was outdated and removed in 3.10, I've found a similar example that can be used to clarify this function.
https://bugs.python.org/issue43453