-
Notifications
You must be signed in to change notification settings - Fork 2
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
Fix implementation checks on generic interfaces #109
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -2,6 +2,28 @@ | |||||
------------------ | ||||||
|
||||||
* Added support for Python 3.10. | ||||||
* #109: Non-generic implementers of generic interfaces are now correctly checked. | ||||||
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.
Suggested change
|
||||||
|
||||||
Previously checking if a non-generic class implements a generic interface always used to fail, as | ||||||
the latter has a special method (``__class_getitem__``) that the former does't have, which led to | ||||||
false negatives. | ||||||
|
||||||
.. code-block:: python | ||||||
|
||||||
class IFoo(Interface, typing.Generic[T]): | ||||||
def Bar(self) -> T: | ||||||
... | ||||||
|
||||||
|
||||||
@ImplementsInterface(IFoo, no_check=True) | ||||||
class Foo: | ||||||
@Implements(IFoo.Bar) | ||||||
def Bar(self) -> str: | ||||||
return "baz" | ||||||
|
||||||
|
||||||
AssertImplements(Foo, IFoo) # Ok now. | ||||||
Comment on lines
+13
to
+25
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. And without the To appease mypy do we still have to declare 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, it does complain.
Yeah we still have to. 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.
Why? How? |
||||||
|
||||||
|
||||||
2.1.0 (2021-03-19) | ||||||
------------------ | ||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -1077,3 +1077,39 @@ def AfterCaption(*args): | |||||||||||
|
||||||||||||
assert Foo.GetCaption() == "Foo" | ||||||||||||
assert Foo().GetValues("m") == [0.1, 10.0] | ||||||||||||
|
||||||||||||
|
||||||||||||
def testGenericInterface() -> None: | ||||||||||||
"""Generic interfaces need to support checking on both generic and non-generic implementers""" | ||||||||||||
from typing import FrozenSet, Generic, TypeVar | ||||||||||||
|
||||||||||||
T = TypeVar("T", covariant=True) | ||||||||||||
|
||||||||||||
class IFoo(Interface, Generic[T], TypeCheckingSupport): | ||||||||||||
# Class instance defined here as a workaround for this class to work in Python 3.6. | ||||||||||||
__abstractmethods__: FrozenSet = frozenset() | ||||||||||||
Comment on lines
+1088
to
+1090
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. @nicoddemus 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. Definitely, IMO we can do this for all of our OS projects, supporting >=3.7 or even >=3.10 only, if the former is too much work.
Comment on lines
+1089
to
+1090
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. Let's drop Python 3.6 first.
Suggested change
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. To drop Python 3.6:
|
||||||||||||
|
||||||||||||
def GetOutput(self) -> T: # type:ignore[empty-body] | ||||||||||||
... | ||||||||||||
Comment on lines
+1092
to
+1093
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. To solve this new warning we are decorating interface methods with
Suggested change
|
||||||||||||
|
||||||||||||
@ImplementsInterface(IFoo, no_check=True) # Will check later. | ||||||||||||
class GenericFoo(Generic[T]): | ||||||||||||
def __init__(self, output: T) -> None: | ||||||||||||
self.output = output | ||||||||||||
|
||||||||||||
@Implements(IFoo.GetOutput) | ||||||||||||
def GetOutput(self) -> T: | ||||||||||||
return self.output | ||||||||||||
|
||||||||||||
@ImplementsInterface(IFoo, no_check=True) | ||||||||||||
class NonGenericFoo: | ||||||||||||
@Implements(IFoo.GetOutput) | ||||||||||||
def GetOutput(self) -> int: | ||||||||||||
return 1 | ||||||||||||
|
||||||||||||
# This works out of the box. | ||||||||||||
AssertImplements(GenericFoo, IFoo) | ||||||||||||
AssertImplements(GenericFoo[str](output="foo"), IFoo) | ||||||||||||
|
||||||||||||
# This only works if we skip the verification of `__class_getitem__` method. | ||||||||||||
AssertImplements(NonGenericFoo, IFoo) | ||||||||||||
Comment on lines
+1111
to
+1115
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. Just a question. What about 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 makes it raise an AssertionError with the following error:
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. Don't we want to handle that?
|
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 changelog entry. 👍