-
Notifications
You must be signed in to change notification settings - Fork 11
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
InterfaceClass subclass not recognized as interface #21
Comments
Mainly because mypy-zope is simply don't know how What is supported is class declarations, like: class RemoteInterface(interface.Interface):
pass
class Api(RemoteInterface):
def open():
"open something" I'm not completely sure that is equivalent to your case though. I can't give you a recipe how to implement the support for this use case, but perhaps it would involve adding a special case in Another hack to try is to add a special |
But the same is true of Oh, maybe I know - since I'm only running I'll try your recommendations for addressing the foolscap RemoteInterface. |
This approach doesn't have any effect in the foolscap case, so I'm not sure it's relevant.
I explored this approach, but quickly realized that there's no suitable return type for class InterfaceClass(type, Element, InterfaceBase, Specification):
....
def __new__(self, name: Any, bases: Any = ..., attrs: Optional[Any] = ..., __doc__: Optional[Any] = ..., __module__: Optional[Any] = ...) -> Interface: ... I tried that line, but at the point where I did try an alternative syntax for the RemoteInterfaceClass creation: from zope.interface import interface
class RemoteInterfaceClass(interface.InterfaceClass):
pass
class RemoteInterface(metaclass=RemoteInterfaceClass):
pass
class Api(RemoteInterface):
def open():
"open something" Running mypy-zope on this produces:
This error seems to capture the limitation without foolscap. Do you have any suggestions for addressing this limitation? |
An even simpler implementation triggers the same error: from zope.interface import interface
class RemoteInterface(metaclass=interface.InterfaceClass):
pass
class Api(RemoteInterface):
def open():
"open something" |
I've found with this diff: mypy-zope master $ git diff
diff --git a/src/mypy_zope/plugin.py b/src/mypy_zope/plugin.py
index 6a28b5c..2d8bdd7 100644
--- a/src/mypy_zope/plugin.py
+++ b/src/mypy_zope/plugin.py
@@ -258,7 +258,11 @@ class ZopeInterfacePlugin(Plugin):
self, fullname: str
) -> Optional[Callable[[ClassDefContext], None]]:
# print(f"get_metaclass_hook: {fullname}")
- return None
+ def analyze_metaclass(ctx: ClassDefContext) -> Callable[[ClassDefContext], None]:
+ if ctx.cls.metaclass.name == 'InterfaceClass':
+ md = self._get_metadata(ctx.cls.info)
+ md["is_interface"] = True
+ return analyze_metaclass
def get_base_class_hook(
self, fullname: str Running the checks against that example no longer fail. It's not a proper fix, but starts to work toward a solution. I couldn't figure out how to resolve that ctx.cls.metaclass to Any help you can lend in filling in the gaps and adding support for this use case would be most appreciated. |
"Method must have at least one argument" error indicates that the interface is not recognized as interface. There is a hack that adds "self" argument to all the methods of the interface, so that further mypy checks would not emit this error. See Currently the plugin has a special treatment for However, class Interface(metaclass=InterfaceClass): ... So perhaps it is possible to generalize this so that. And actually your patch makes sense from that point of view. The only thing is missing here: the base |
I'm no longer able to replicate this observation. I think the observation I'd encountered may have been due to a false negative from a cached result. |
Aha. I had forgotten to enable the plugin. Enabling the plugin (which apparently can only be done by creating a config file), I can once again replicate the success. |
* Indicate any instance whose class type is named InterfaceClass is an interface. * Rely on fullname to more precisely detect an InterfaceClass instance. * Apply black style to patch * Inline the check. Avoids need to define types for a function. * Satisfy type checks through casting. * Remove analyze_direct, no longer needed now that the metaclass is handled. * Add test capturing failed expectation. Ref #21.
Closing after merging of #24 |
The project foolscap relies on
zope.interface
and creates a RemoteInterface as an instance of a subclass ofzope.interface.interface.InterfaceClass
. When tested against mypy with this plugin, the interface isn't recognized as such an results in "Method must have at least one argument" failed validations.As an example:
I've attempted to create an even more minimal example that doesn't involve foolscap, but I've been unsuccessful:
I don't understand why
The note there isn't particularly helpful, as I'm creating neither an alias nor a variable. I'm creating a proper type and in the same way that foolscap does, so why does this example error where foolscap doesn't?
And surely the example error isn't valid until mypy recogognizes RemoteInterface correctly.
Can you help to determine a solution here to support
foolscap.api.RemoteInterface
subclasses within mypy?The text was updated successfully, but these errors were encountered: