|
1 |
| -from typing import Callable, Dict, Optional, Sequence |
| 1 | +from typing import Callable, Dict, Optional |
2 | 2 |
|
3 | 3 | from mypy.nodes import TypeInfo
|
4 | 4 | from mypy.options import Options
|
5 |
| -from mypy.plugin import AttributeContext, ClassDefContext, FunctionContext, MethodContext, Plugin |
6 |
| -from mypy.types import Instance, Type |
| 5 | +from mypy.plugin import ClassDefContext, Plugin |
| 6 | +from mypy_django_plugin import main as mypy_django_main |
| 7 | +from mypy_django_plugin.django.context import DjangoContext |
7 | 8 |
|
8 |
| -from mypy_drf_plugin import helpers, monkeypatch |
9 |
| -from mypy_drf_plugin.transformers import fields, serializers, validation |
| 9 | +from mypy_drf_plugin.lib import fullnames, helpers |
| 10 | +from mypy_drf_plugin.transformers import serializers |
10 | 11 |
|
11 | 12 |
|
12 |
| -def extract_base_model_fullname(serializer_type: Type) -> Optional[str]: |
13 |
| - if not isinstance(serializer_type, Instance): |
14 |
| - return None |
15 |
| - |
16 |
| - base_model_fullname = helpers.get_drf_metadata(serializer_type.type).get('base_model') |
17 |
| - if not base_model_fullname: |
18 |
| - return None |
19 |
| - |
20 |
| - return base_model_fullname |
21 |
| - |
22 |
| - |
23 |
| -def get_instance_of_model_bound_to_serializer(ctx: MethodContext) -> Type: |
24 |
| - base_model_fullname = extract_base_model_fullname(ctx.type) |
25 |
| - if not base_model_fullname: |
26 |
| - return ctx.default_return_type |
27 |
| - |
28 |
| - try: |
29 |
| - return ctx.api.named_generic_type(base_model_fullname, []) |
30 |
| - except AssertionError: # cannot find a model with name |
31 |
| - return ctx.default_return_type |
| 13 | +def transform_serializer_class(ctx: ClassDefContext) -> None: |
| 14 | + sym = ctx.api.lookup_fully_qualified_or_none(fullnames.BASE_SERIALIZER_FULLNAME) |
| 15 | + if sym is not None and isinstance(sym.node, TypeInfo): |
| 16 | + helpers.get_drf_metadata(sym.node)['serializer_bases'][ctx.cls.fullname] = 1 |
32 | 17 |
|
| 18 | + serializers.make_meta_nested_class_inherit_from_any(ctx) |
33 | 19 |
|
34 |
| -class BaseClassTransformers: |
35 |
| - def __init__(self, hooks: Sequence[Callable]): |
36 |
| - self.hooks = hooks |
37 | 20 |
|
38 |
| - def __call__(self, ctx: ClassDefContext) -> None: |
39 |
| - for hook in self.hooks: |
40 |
| - hook(ctx) |
41 |
| - |
42 |
| - |
43 |
| -class DRFPlugin(Plugin): |
| 21 | +class NewSemanalDRFPlugin(Plugin): |
44 | 22 | def __init__(self, options: Options) -> None:
|
45 | 23 | super().__init__(options)
|
46 |
| - monkeypatch.make_field_repr_not_return_any_generics() |
| 24 | + |
| 25 | + django_settings_module = mypy_django_main.extract_django_settings_module(options.config_file) |
| 26 | + self.django_context = DjangoContext(django_settings_module) |
47 | 27 |
|
48 | 28 | def _get_currently_defined_serializers(self) -> Dict[str, int]:
|
49 |
| - base_serializer_sym = self.lookup_fully_qualified(helpers.BASE_SERIALIZER_FULLNAME) |
| 29 | + base_serializer_sym = self.lookup_fully_qualified(fullnames.BASE_SERIALIZER_FULLNAME) |
50 | 30 | if base_serializer_sym is not None and isinstance(base_serializer_sym.node, TypeInfo):
|
51 | 31 | return (base_serializer_sym.node.metadata
|
52 | 32 | .setdefault('drf', {})
|
53 |
| - .setdefault('serializer_bases', {helpers.BASE_SERIALIZER_FULLNAME: 1, |
54 |
| - helpers.MODEL_SERIALIZER_FULLNAME: 1, |
55 |
| - helpers.SERIALIZER_FULLNAME: 1})) |
56 |
| - else: |
57 |
| - return {} |
58 |
| - |
59 |
| - def _get_currently_defined_list_serializers(self) -> Dict[str, int]: |
60 |
| - list_serializer_sym = self.lookup_fully_qualified(helpers.LIST_SERIALIZER_FULLNAME) |
61 |
| - if list_serializer_sym is not None and isinstance(list_serializer_sym.node, TypeInfo): |
62 |
| - return (helpers.get_drf_metadata(list_serializer_sym.node) |
63 |
| - .setdefault('list_serializer_bases', {helpers.LIST_SERIALIZER_FULLNAME: 1})) |
| 33 | + .setdefault('serializer_bases', {fullnames.BASE_SERIALIZER_FULLNAME: 1})) |
64 | 34 | else:
|
65 | 35 | return {}
|
66 | 36 |
|
67 |
| - def _get_defined_serializer_base_classes(self) -> Dict[str, int]: |
68 |
| - return {**self._get_currently_defined_serializers(), **self._get_currently_defined_list_serializers()} |
69 |
| - |
70 |
| - def _get_defined_field_base_classes(self) -> Dict[str, int]: |
71 |
| - base_field_sym = self.lookup_fully_qualified(helpers.FIELD_FULLNAME) |
72 |
| - if base_field_sym is not None and isinstance(base_field_sym.node, TypeInfo): |
73 |
| - return (helpers.get_drf_metadata(base_field_sym.node) |
74 |
| - .setdefault('field_bases', {helpers.FIELD_FULLNAME: 1})) |
75 |
| - else: |
76 |
| - return {} |
77 |
| - |
78 |
| - def get_function_hook(self, fullname: str |
79 |
| - ) -> Optional[Callable[[FunctionContext], Type]]: |
80 |
| - sym = self.lookup_fully_qualified(fullname) |
81 |
| - if sym is not None and isinstance(sym.node, TypeInfo): |
82 |
| - if sym.node.has_base(helpers.FIELD_FULLNAME): |
83 |
| - return fields.set_generic_parameters_for_field |
84 |
| - |
85 |
| - def get_method_hook(self, fullname: str |
86 |
| - ) -> Optional[Callable[[MethodContext], Type]]: |
87 |
| - class_name, _, method_name = fullname.rpartition('.') |
88 |
| - if method_name == 'to_representation': |
89 |
| - if class_name in self._get_currently_defined_serializers(): |
90 |
| - return validation.return_typeddict_from_to_representation |
91 |
| - |
92 |
| - if class_name in self._get_currently_defined_list_serializers(): |
93 |
| - return validation.return_list_of_typeddict_for_list_serializer_from_to_representation |
94 |
| - |
95 |
| - if method_name in {'to_internal_value', 'run_validation'}: |
96 |
| - if class_name in self._get_currently_defined_serializers(): |
97 |
| - return validation.return_typeddict_from_to_internal_value |
98 |
| - |
99 |
| - if class_name in self._get_currently_defined_list_serializers(): |
100 |
| - return validation.return_list_of_typeddict_for_list_serializer_from_to_internal_value |
101 |
| - |
102 |
| - if method_name in {'create', 'save'}: |
103 |
| - if class_name in self._get_currently_defined_serializers(): |
104 |
| - return get_instance_of_model_bound_to_serializer |
105 |
| - |
106 | 37 | def get_base_class_hook(self, fullname: str
|
107 | 38 | ) -> Optional[Callable[[ClassDefContext], None]]:
|
108 |
| - if fullname in self._get_defined_serializer_base_classes(): |
109 |
| - return BaseClassTransformers([serializers.transform_serializer_class, |
110 |
| - fields.set_types_metadata]) |
111 |
| - |
112 |
| - if fullname in self._get_defined_field_base_classes(): |
113 |
| - return fields.set_types_metadata |
| 39 | + if fullname in self._get_currently_defined_serializers(): |
| 40 | + return transform_serializer_class |
| 41 | + return None |
114 | 42 |
|
115 | 43 |
|
116 | 44 | def plugin(version):
|
117 |
| - return DRFPlugin |
| 45 | + return NewSemanalDRFPlugin |
0 commit comments