Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support method plugin hooks on unions (#6560)
Fixes #6117 Fixes #5930 Currently both our plugin method hooks don't work with unions. This PR fixes this with three things: * Moves a bit of logic from `visit_call_expr_inner()` (which is a long method already) to `check_call_expr_with_callee_type()` (which is a short method). * Special-cases unions in `check_call_expr_with_callee_type()` (normal method calls) and `check_method_call_by_name()` (dunder/operator method calls). * Adds some clarifying comments and a docstring. The week point is interaction with binder, but IMO this is the best we can have for now. I left a comment mentioning that check for overlap should be consistent in two functions. In general, I don't like special-casing, but I spent several days thinking of other solutions, and it looks like special-casing unions in couple more places is the only reasonable way to fix unions-vs-plugins interactions. This PR may interfere with #6558 that fixes an "opposite" problem, hopefully they will work together unmodified, so that accessing union of literals on union of typed dicts works. Whatever PR lands second, should add a test for this.
- Loading branch information
1 parent
b724cca
commit 72734f2
Showing
5 changed files
with
273 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
from mypy.plugin import ( | ||
CallableType, CheckerPluginInterface, MethodSigContext, MethodContext, Plugin | ||
) | ||
from mypy.types import Instance, Type | ||
|
||
|
||
class MethodPlugin(Plugin): | ||
def get_method_signature_hook(self, fullname): | ||
if fullname.startswith('__main__.Foo.'): | ||
return my_meth_sig_hook | ||
return None | ||
|
||
def get_method_hook(self, fullname): | ||
if fullname.startswith('__main__.Bar.'): | ||
return my_meth_hook | ||
return None | ||
|
||
|
||
def _str_to_int(api: CheckerPluginInterface, typ: Type) -> Type: | ||
if isinstance(typ, Instance): | ||
if typ.type.fullname() == 'builtins.str': | ||
return api.named_generic_type('builtins.int', []) | ||
elif typ.args: | ||
return typ.copy_modified(args=[_str_to_int(api, t) for t in typ.args]) | ||
return typ | ||
|
||
|
||
def _float_to_int(api: CheckerPluginInterface, typ: Type) -> Type: | ||
if isinstance(typ, Instance): | ||
if typ.type.fullname() == 'builtins.float': | ||
return api.named_generic_type('builtins.int', []) | ||
elif typ.args: | ||
return typ.copy_modified(args=[_float_to_int(api, t) for t in typ.args]) | ||
return typ | ||
|
||
|
||
def my_meth_sig_hook(ctx: MethodSigContext) -> CallableType: | ||
return ctx.default_signature.copy_modified( | ||
arg_types=[_str_to_int(ctx.api, t) for t in ctx.default_signature.arg_types], | ||
ret_type=_str_to_int(ctx.api, ctx.default_signature.ret_type), | ||
) | ||
|
||
|
||
def my_meth_hook(ctx: MethodContext) -> Type: | ||
return _float_to_int(ctx.api, ctx.default_return_type) | ||
|
||
|
||
def plugin(version): | ||
return MethodPlugin |