- Notifications
You must be signed in to change notification settings - Fork 280
Fix subclassing builtin protocols on older Python versions #650
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
Conversation
| for base in cls.__mro__[1:]: | ||
| if not (base in (object, Generic, Callable) or | ||
| if not (base in (object, Generic) or | ||
| base.__module__ == 'collections.abc' and |
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 believe there's a bug here because _PROTO_WHITELIST contains ContextManager and AsyncContextManager but neither of those come from the collections.abc module. This makes code like the following fail:
In [24]: from typing import ContextManager ...: from typing_extensions import Protocol ...: ...: class Foobar(ContextManager, Protocol): ...: pass ...: --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-24-fa1f28400733> in <module> 1 from typing import ContextManager 2 ----> 3 class Foobar(ContextManager, Protocol): 4 pass 5 /mnt/xarfuse/uid-4861/0260e378-ns-4026531840/typing_extensions.py in __init__(cls, *args, **kwargs) 1201 base.__origin__ is Generic): 1202 raise TypeError('Protocols can only inherit from other' -> 1203 ' protocols, got %r' % base) 1204 1205 def _no_init(self, *args, **kwargs): TypeError: Protocols can only inherit from other protocols, got typing.ContextManagerIs there something I'm missing here, or is there genuinely an issue that needs to be fixed by maintaining a map of module -> class name for everything in the _PROTO_WHITELIST list?
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.
Does this happen on all Python versions? I think it may be relevant only for 3.5, if not however it makes sense to fix this by making whitelisting more precise.
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'll see if I can repro in 2.7 as well, my error is from 3.6.
If it is 3.5+ only, would you have an alternate suggestion apart from having a more explicit module -> class name whitelist?
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 can repro this in 2.7 as well:
In [4]: from typing import ContextManager ...: from typing_extensions import Protocol ...: ...: class Foobar(ContextManager, Protocol): ...: pass ...: --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-4-b18f9414f140> in <module>() 2 from typing_extensions import Protocol 3 ----> 4 class Foobar(ContextManager, Protocol): 5 pass /data/users/divij/fbsource/fbcode/buck-out/dev/gen/experimental/divij/test_smc_db_types-ipython#link-tree/typing_extensions.py in __init__(cls, *args, **kwargs) 187 isinstance(base, GenericMeta) and base.__origin__ is Generic): 188 raise TypeError('Protocols can only inherit from other protocols,' --> 189 ' got %r' % base) 190 cls._callable_members_only = all(callable(getattr(cls, attr)) 191 for attr in cls._get_protocol_attrs()) TypeError: Protocols can only inherit from other protocols, got typing.ContextManager In [5]: import sys In [6]: sys.version Out[6]: '2.7.14 (default, May 13 2019, 13:45:19) \n[GCC 7.x 20190403 (Facebook) 8.x]' 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.
It looks like there is a bigger problem. I can reproduce this also in Python 3.8 (beta) and Protocol imported from typing. I think we need to fix it there first, and then apply the fix to this backport. The simplest fix may be indeed to keep the mapping. Could you please open an issue on https://bugs.python.org?
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.
Sure, I'll do that right now. Thanks for following up @ilevkivskyi!
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.
Created https://bugs.python.org/issue38008, I'll move the discussion there
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.
@jivid Now that this is fixed upstream, would you like to work on a backport?
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.
@ilevkivskyi yes! Is it enough for me to make a similar change to the original PR in this repo, or do I need to do something else for backporting?
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.
Is it enough for me to make a similar change to the original PR in this repo, or do I need to do something else for backporting?
I don't remember for sure TBH, but most likely yes. Note however that you might need to add this change to more than one place. There are four places that might need to be updated: typing_extensions/src_py2, typing_extensions/src_py3, src, and python2. Also you would need to add tests for all of these versions (even if some of them already work).
This was recently fixed in CPython repo (while adding
Protocolthere). This PR backports the fix to all the older versions including now Python 2 version intyping.I also removed the unnecessary conditional import in Python 2 tests since I stumbled at it while adding the test.