|
1 | 1 | """Plugin system for extending mypy."""
|
2 | 2 |
|
| 3 | +import types |
| 4 | + |
3 | 5 | from abc import abstractmethod
|
4 | 6 | from functools import partial
|
5 | 7 | from typing import Callable, List, Tuple, Optional, NamedTuple, TypeVar, Dict
|
|
16 | 18 | )
|
17 | 19 | from mypy.messages import MessageBuilder
|
18 | 20 | from mypy.options import Options
|
| 21 | +import mypy.interpreted_plugin |
19 | 22 |
|
20 | 23 |
|
21 | 24 | @trait
|
@@ -222,6 +225,58 @@ def get_customize_class_mro_hook(self, fullname: str
|
222 | 225 | T = TypeVar('T')
|
223 | 226 |
|
224 | 227 |
|
| 228 | +class WrapperPlugin(Plugin): |
| 229 | + """A plugin that wraps an interpreted plugin. |
| 230 | +
|
| 231 | + This is a ugly workaround the limitation that mypyc-compiled |
| 232 | + classes can't be subclassed by interpreted ones, so instead we |
| 233 | + create a new class for interpreted clients to inherit from and |
| 234 | + dispatch to it from here. |
| 235 | +
|
| 236 | + Eventually mypyc ought to do something like this automatically. |
| 237 | + """ |
| 238 | + |
| 239 | + def __init__(self, plugin: mypy.interpreted_plugin.InterpretedPlugin) -> None: |
| 240 | + super().__init__(plugin.options) |
| 241 | + self.plugin = plugin |
| 242 | + |
| 243 | + def get_type_analyze_hook(self, fullname: str |
| 244 | + ) -> Optional[Callable[[AnalyzeTypeContext], Type]]: |
| 245 | + return self.plugin.get_type_analyze_hook(fullname) |
| 246 | + |
| 247 | + def get_function_hook(self, fullname: str |
| 248 | + ) -> Optional[Callable[[FunctionContext], Type]]: |
| 249 | + return self.plugin.get_function_hook(fullname) |
| 250 | + |
| 251 | + def get_method_signature_hook(self, fullname: str |
| 252 | + ) -> Optional[Callable[[MethodSigContext], CallableType]]: |
| 253 | + return self.plugin.get_method_signature_hook(fullname) |
| 254 | + |
| 255 | + def get_method_hook(self, fullname: str |
| 256 | + ) -> Optional[Callable[[MethodContext], Type]]: |
| 257 | + return self.plugin.get_method_hook(fullname) |
| 258 | + |
| 259 | + def get_attribute_hook(self, fullname: str |
| 260 | + ) -> Optional[Callable[[AttributeContext], Type]]: |
| 261 | + return self.plugin.get_attribute_hook(fullname) |
| 262 | + |
| 263 | + def get_class_decorator_hook(self, fullname: str |
| 264 | + ) -> Optional[Callable[[ClassDefContext], None]]: |
| 265 | + return self.plugin.get_class_decorator_hook(fullname) |
| 266 | + |
| 267 | + def get_metaclass_hook(self, fullname: str |
| 268 | + ) -> Optional[Callable[[ClassDefContext], None]]: |
| 269 | + return self.plugin.get_metaclass_hook(fullname) |
| 270 | + |
| 271 | + def get_base_class_hook(self, fullname: str |
| 272 | + ) -> Optional[Callable[[ClassDefContext], None]]: |
| 273 | + return self.plugin.get_base_class_hook(fullname) |
| 274 | + |
| 275 | + def get_customize_class_mro_hook(self, fullname: str |
| 276 | + ) -> Optional[Callable[[ClassDefContext], None]]: |
| 277 | + return self.plugin.get_customize_class_mro_hook(fullname) |
| 278 | + |
| 279 | + |
225 | 280 | class ChainedPlugin(Plugin):
|
226 | 281 | """A plugin that represents a sequence of chained plugins.
|
227 | 282 |
|
@@ -444,3 +499,14 @@ def int_pow_callback(ctx: MethodContext) -> Type:
|
444 | 499 | else:
|
445 | 500 | return ctx.api.named_generic_type('builtins.float', [])
|
446 | 501 | return ctx.default_return_type
|
| 502 | + |
| 503 | + |
| 504 | +# This is an incredibly frumious hack. If this module is compiled by mypyc, |
| 505 | +# set the module 'Plugin' attribute to point to InterpretedPlugin. This means |
| 506 | +# that anything interpreted that imports Plugin will get InterpretedPlugin |
| 507 | +# while anything compiled alongside this module will get the real Plugin. |
| 508 | +if isinstance(int_pow_callback, types.BuiltinFunctionType): |
| 509 | + plugin_types = (Plugin, mypy.interpreted_plugin.InterpretedPlugin) # type: Tuple[type, ...] |
| 510 | + globals()['Plugin'] = mypy.interpreted_plugin.InterpretedPlugin |
| 511 | +else: |
| 512 | + plugin_types = (Plugin,) |
0 commit comments