Repository navigation
Protocols in typing extensions #464
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
Changes from 1 commit
1ebd3f5
37b6a7b
bb3a8a9
d8ae30e
a4e68ff
c8076ee
80e8014
a6a631a
5913fe6
faf4ff0
c7f6b68
8151355
76a7ecd
95faebe
04f1c51
ce4e04f
a7cf2fb
8b50c60
1dc1971
e25077f
1c1d9fe
9b22594
458b232
dbc6def
31cbe0d
171b1e5
fc0ec94
f1f478a
8652ced
8f0a778
23e80da
dc01948
733016d
8f12689
a4d397e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -187,7 +187,8 @@ def __init__(cls, *args, **kwargs): | |
| isinstance(base, GenericMeta) and base.__origin__ is Generic): | ||
| raise TypeError('Protocols can only inherit from other protocols,' | ||
| ' got %r' % base) | ||
|
|
||
| cls._callable_members_only = all(callable(getattr(cls, attr)) | ||
| for attr in cls._get_protocol_attrs()) | ||
| def _no_init(self, *args, **kwargs): | ||
| if type(self)._is_protocol: | ||
| raise TypeError('Protocols cannot be instantiated') | ||
|
|
@@ -219,12 +220,16 @@ def __instancecheck__(self, instance): | |
| # It cannot support runtime protocol metaclasses, On Python 2 classes | ||
| # cannot be correctly inspected as instances of protocols. | ||
| return False | ||
| if issubclass(instance.__class__, self): | ||
| if ((not getattr(self, '_is_protocol', False) or | ||
| self._callable_members_only) and | ||
| issubclass(instance.__class__, self)): | ||
| return True | ||
| if self._is_protocol: | ||
| return all(hasattr(instance, attr) and getattr(instance, attr) is not None | ||
| for attr in self._get_protocol_attrs()) | ||
| return False | ||
| if all(hasattr(instance, attr) and | ||
| (not callable(getattr(self, attr)) or getattr(instance, attr) is not None) | ||
| for attr in self._get_protocol_attrs()): | ||
| return True | ||
| return super(GenericMeta, self).__instancecheck__(instance) | ||
|
|
||
| def __subclasscheck__(self, cls): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This fails with from typing_extensions import Protocol, runtime
@runtime
class P(Protocol):
def f(self): pass
class A: pass # Note: no explicit object base class
print issubclass(A, P) # ErrorAn explicit More generally, I'm not sure if subclass checks are well-defined if a protocol has non-method attributes, since they could well be initialized in
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's an old-style class in Python 2; I'm not sure we should care about support for old-style classes for Protocols in Python 2 (since they are deprecated and a lot of the class machinery works differently for them).
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, old-stye classes are problematic, I will check if it is possible to do something reasonable with them, if not, then I will add a more meaningful error message like "Old style classes (not inheriting from object) are not supported with protocols". |
||
| if (self.__dict__.get('_is_protocol', None) and | ||
|
|
@@ -233,6 +238,11 @@ def __subclasscheck__(self, cls): | |
| return False | ||
| raise TypeError("Instance and class checks can only be used with" | ||
| " @runtime protocols") | ||
| if (self.__dict__.get('_is_runtime_protocol', None) and | ||
| not self._callable_members_only): | ||
| if sys._getframe(1).f_globals['__name__'] in ['abc', 'functools']: | ||
| return super(GenericMeta, self).__subclasscheck__(cls) | ||
| raise TypeError("Protocols with non-method members don't support issubclass()") | ||
| return super(_ProtocolMeta, self).__subclasscheck__(cls) | ||
|
|
||
| def _get_protocol_attrs(self): | ||
|
|
@@ -250,7 +260,7 @@ def _get_protocol_attrs(self): | |
| '__orig_bases__', '__extra__', '__tree_hash__', | ||
| '__doc__', '__subclasshook__', '__init__', '__new__', | ||
| '__module__', '_MutableMapping__marker', | ||
| '__metaclass__', '_gorg')): | ||
| '__metaclass__', '_gorg', '_callable_members_only')): | ||
| attrs.add(attr) | ||
| return attrs | ||
|
|
||
|
|
||
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.
Do you test the variants where
xis defined for the instance ofB(None/ notNone) or wherexhas valueNone/ notNonein the body ofB?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 think I test only few variants/combinations. I will add more tests.