def run_with_model_cls(self, model_cls: Type[Model]) -> None: if "_default_manager" in self.model_classdef.info.names: return None default_manager_cls = model_cls._meta.default_manager.__class__ default_manager_fullname = helpers.get_class_fullname( default_manager_cls) try: default_manager_info = self.lookup_typeinfo_or_incomplete_defn_error( default_manager_fullname) except helpers.IncompleteDefnException as exc: # Check if default manager could be a generated manager base_manager_fullname = helpers.get_class_fullname( default_manager_cls.__bases__[0]) generated_manager_info = self.get_generated_manager_info( default_manager_fullname, base_manager_fullname) if generated_manager_info is None: # Manager doesn't appear to be generated. Unless we're on the final round, # see if another round could help figuring out the default manager type if not self.api.final_iteration: raise exc else: return None default_manager_info = generated_manager_info default_manager = Instance(default_manager_info, [Instance(self.model_classdef.info, [])]) self.add_new_node_to_model_class("_default_manager", default_manager)
def run_with_model_cls(self, model_cls: Type[Model]) -> None: for manager_name, manager in model_cls._meta.managers_map.items(): manager_fullname = helpers.get_class_fullname(manager.__class__) manager_info = self.lookup_typeinfo_or_incomplete_defn_error(manager_fullname) if manager_name not in self.model_classdef.info.names: manager_type = Instance(manager_info, [Instance(self.model_classdef.info, [])]) self.add_new_node_to_model_class(manager_name, manager_type) else: # create new MODELNAME_MANAGERCLASSNAME class that represents manager parametrized with current model has_manager_any_base = any(self._is_manager_any(base) for base in manager_info.bases) if has_manager_any_base: custom_model_manager_name = manager.model.__name__ + '_' + manager.__class__.__name__ bases = [] for original_base in manager_info.bases: if self._is_manager_any(original_base): if original_base.type is None: if not self.api.final_iteration: self.api.defer() original_base = helpers.reparametrize_instance(original_base, [Instance(self.model_classdef.info, [])]) bases.append(original_base) current_module = self.api.modules[self.model_classdef.info.module_name] custom_manager_info = helpers.add_new_class_for_module(current_module, custom_model_manager_name, bases=bases, fields=OrderedDict()) custom_manager_type = Instance(custom_manager_info, [Instance(self.model_classdef.info, [])]) self.add_new_node_to_model_class(manager_name, custom_manager_type) # add _default_manager if '_default_manager' not in self.model_classdef.info.names: default_manager_fullname = helpers.get_class_fullname(model_cls._meta.default_manager.__class__) default_manager_info = self.lookup_typeinfo_or_incomplete_defn_error(default_manager_fullname) default_manager = Instance(default_manager_info, [Instance(self.model_classdef.info, [])]) self.add_new_node_to_model_class('_default_manager', default_manager) # add related managers for relation in self.django_context.get_model_relations(model_cls): attname = relation.get_accessor_name() if attname is None: # no reverse accessor continue related_model_info = self.lookup_class_typeinfo_or_incomplete_defn_error(relation.related_model) if isinstance(relation, OneToOneRel): self.add_new_node_to_model_class(attname, Instance(related_model_info, [])) continue if isinstance(relation, (ManyToOneRel, ManyToManyRel)): manager_info = self.lookup_typeinfo_or_incomplete_defn_error(fullnames.RELATED_MANAGER_CLASS_FULLNAME) self.add_new_node_to_model_class(attname, Instance(manager_info, [Instance(related_model_info, [])])) continue
def run_with_model_cls(self, model_cls: Type[Model]) -> None: manager_info: Optional[TypeInfo] encountered_incomplete_manager_def = False for manager_name, manager in model_cls._meta.managers_map.items(): manager_class_name = manager.__class__.__name__ manager_fullname = helpers.get_class_fullname(manager.__class__) try: manager_info = self.lookup_typeinfo_or_incomplete_defn_error( manager_fullname) except helpers.IncompleteDefnException as exc: # Check if manager is a generated (dynamic class) manager base_manager_fullname = helpers.get_class_fullname( manager.__class__.__bases__[0]) manager_info = self.get_generated_manager_info( manager_fullname, base_manager_fullname) if manager_info is None: # Manager doesn't appear to be generated. Track that we encountered an # incomplete definition and skip encountered_incomplete_manager_def = True continue _, manager_class_name = manager_info.fullname.rsplit( ".", maxsplit=1) if manager_name not in self.model_classdef.info.names: manager_type = Instance( manager_info, [Instance(self.model_classdef.info, [])]) self.add_new_node_to_model_class(manager_name, manager_type) else: # Ending up here could for instance be due to having a custom _Manager_ # that is not built from a custom QuerySet. Another example is a # related manager. # Don't interfere with dynamically generated manager classes is_dynamically_generated = "django" in manager_info.metadata and manager_info.metadata[ "django"].get("from_queryset_manager") if not self.has_any_parametrized_manager_as_base( manager_info) or is_dynamically_generated: continue custom_model_manager_name = manager.model.__name__ + "_" + manager_class_name try: custom_manager_type = self.create_new_model_parametrized_manager( custom_model_manager_name, base_manager_info=manager_info) except helpers.IncompleteDefnException: continue self.add_new_node_to_model_class(manager_name, custom_manager_type) if encountered_incomplete_manager_def and not self.api.final_iteration: # Unless we're on the final round, see if another round could figuring out all manager types raise helpers.IncompleteDefnException()
def run_with_model_cls(self, model_cls: Type[Model]) -> None: # add _default_manager if '_default_manager' not in self.model_classdef.info.names: default_manager_fullname = helpers.get_class_fullname(model_cls._meta.default_manager.__class__) default_manager_info = self.lookup_typeinfo_or_incomplete_defn_error(default_manager_fullname) default_manager = Instance(default_manager_info, [Instance(self.model_classdef.info, [])]) self.add_new_node_to_model_class('_default_manager', default_manager)
def return_proper_field_type_from_get_field( ctx: MethodContext, django_context: DjangoContext) -> MypyType: # Options instance assert isinstance(ctx.type, Instance) model_type = ctx.type.args[0] if not isinstance(model_type, Instance): return _get_field_instance(ctx, fullnames.FIELD_FULLNAME) model_cls = django_context.get_model_class_by_fullname( model_type.type.fullname()) if model_cls is None: return _get_field_instance(ctx, fullnames.FIELD_FULLNAME) field_name_expr = helpers.get_call_argument_by_name(ctx, 'field_name') if field_name_expr is None: return _get_field_instance(ctx, fullnames.FIELD_FULLNAME) field_name = helpers.resolve_string_attribute_value( field_name_expr, ctx, django_context) if field_name is None: return _get_field_instance(ctx, fullnames.FIELD_FULLNAME) try: field = model_cls._meta.get_field(field_name) except FieldDoesNotExist as exc: ctx.api.fail(exc.args[0], ctx.context) return AnyType(TypeOfAny.from_error) field_fullname = helpers.get_class_fullname(field.__class__) return _get_field_instance(ctx, field_fullname)
def get_type_of_settings_attribute(ctx: AttributeContext, django_context: DjangoContext) -> MypyType: assert isinstance(ctx.context, MemberExpr) setting_name = ctx.context.name if not hasattr(django_context.settings, setting_name): ctx.api.fail(f"'Settings' object has no attribute {setting_name!r}", ctx.context) return ctx.default_attr_type typechecker_api = helpers.get_typechecker_api(ctx) # first look for the setting in the project settings file, then global settings settings_module = typechecker_api.modules.get( django_context.django_settings_module) global_settings_module = typechecker_api.modules.get( 'django.conf.global_settings') for module in [settings_module, global_settings_module]: if module is not None: sym = module.names.get(setting_name) if sym is not None and sym.type is not None: return sym.type # if by any reason it isn't present there, get type from django settings value = getattr(django_context.settings, setting_name) value_fullname = helpers.get_class_fullname(value.__class__) value_info = helpers.lookup_fully_qualified_typeinfo( typechecker_api, value_fullname) if value_info is None: return ctx.default_attr_type return Instance(value_info, [])
def run_with_model_cls(self, model_cls: Type[Model]) -> None: for manager_name, manager in model_cls._meta.managers_map.items(): manager_fullname = helpers.get_class_fullname(manager.__class__) manager_info = self.lookup_typeinfo_or_incomplete_defn_error(manager_fullname) if manager_name not in self.model_classdef.info.names: manager_type = Instance(manager_info, [Instance(self.model_classdef.info, [])]) self.add_new_node_to_model_class(manager_name, manager_type) else: # creates new MODELNAME_MANAGERCLASSNAME class that represents manager parametrized with current model has_manager_any_base = any(self._is_manager_any(base) for base in manager_info.bases) if has_manager_any_base: custom_model_manager_name = manager.model.__name__ + '_' + manager.__class__.__name__ bases = [] for original_base in manager_info.bases: if self._is_manager_any(original_base): if original_base.type is None: raise helpers.IncompleteDefnException() original_base = helpers.reparametrize_instance(original_base, [Instance(self.model_classdef.info, [])]) bases.append(original_base) current_module = self.api.modules[self.model_classdef.info.module_name] custom_manager_info = helpers.add_new_class_for_module(current_module, custom_model_manager_name, bases=bases, fields=OrderedDict()) custom_manager_type = Instance(custom_manager_info, [Instance(self.model_classdef.info, [])]) self.add_new_node_to_model_class(manager_name, custom_manager_type)
def try_generate_related_manager( self, related_model_cls: Type[Model], related_model_info: TypeInfo) -> Optional[Instance]: manager = related_model_cls._meta.managers_map["objects"] base_manager_fullname = helpers.get_class_fullname( manager.__class__.__bases__[0]) manager_fullname = helpers.get_class_fullname(manager.__class__) generated_managers = self.get_generated_manager_mappings( base_manager_fullname) if manager_fullname in generated_managers: real_manager_fullname = generated_managers[manager_fullname] manager_info = self.lookup_typeinfo(real_manager_fullname) if manager_info: return Instance(manager_info, [Instance(related_model_info, [])]) return None
def run_with_model_cls(self, model_cls: Type[Model]) -> None: manager_info: Optional[TypeInfo] for manager_name, manager in model_cls._meta.managers_map.items(): manager_class_name = manager.__class__.__name__ manager_fullname = helpers.get_class_fullname(manager.__class__) try: manager_info = self.lookup_typeinfo_or_incomplete_defn_error( manager_fullname) except helpers.IncompleteDefnException as exc: if not self.api.final_iteration: raise exc else: base_manager_fullname = helpers.get_class_fullname( manager.__class__.__bases__[0]) generated_managers = self.get_generated_manager_mappings( base_manager_fullname) if manager_fullname not in generated_managers: # not a generated manager, continue with the loop continue real_manager_fullname = generated_managers[ manager_fullname] manager_info = self.lookup_typeinfo(real_manager_fullname) if manager_info is None: continue manager_class_name = real_manager_fullname.rsplit( ".", maxsplit=1)[1] if manager_name not in self.model_classdef.info.names: manager_type = Instance( manager_info, [Instance(self.model_classdef.info, [])]) self.add_new_node_to_model_class(manager_name, manager_type) else: # creates new MODELNAME_MANAGERCLASSNAME class that represents manager parametrized with current model if not self.has_any_parametrized_manager_as_base(manager_info): continue custom_model_manager_name = manager.model.__name__ + "_" + manager_class_name try: custom_manager_type = self.create_new_model_parametrized_manager( custom_model_manager_name, base_manager_info=manager_info) except helpers.IncompleteDefnException: continue self.add_new_node_to_model_class(manager_name, custom_manager_type)
def run_with_model_cls(self, model_cls: Type[Model]) -> None: auto_field = model_cls._meta.auto_field if auto_field and not self.model_classdef.info.has_readable_member(auto_field.attname): # autogenerated field auto_field_fullname = helpers.get_class_fullname(auto_field.__class__) auto_field_info = self.lookup_typeinfo_or_incomplete_defn_error(auto_field_fullname) set_type, get_type = fields.get_field_descriptor_types(auto_field_info, is_nullable=False) self.add_new_node_to_model_class(auto_field.attname, Instance(auto_field_info, [set_type, get_type]))
def get_user_model_hook(ctx: FunctionContext, django_context: DjangoContext) -> MypyType: auth_user_model = django_context.settings.AUTH_USER_MODEL model_cls = django_context.apps_registry.get_model(auth_user_model) model_cls_fullname = helpers.get_class_fullname(model_cls) model_info = helpers.lookup_fully_qualified_typeinfo( helpers.get_typechecker_api(ctx), model_cls_fullname) if model_info is None: return AnyType(TypeOfAny.unannotated) return TypeType(Instance(model_info, []))
def create_autofield( self, auto_field: Field, dest_name: str, existing_field: bool, ) -> None: if existing_field: auto_field_fullname = helpers.get_class_fullname(auto_field.__class__) auto_field_info = self.lookup_typeinfo_or_incomplete_defn_error(auto_field_fullname) set_type, get_type = fields.get_field_descriptor_types( auto_field_info, is_set_nullable=True, is_get_nullable=False, ) self.add_new_node_to_model_class(dest_name, Instance(auto_field_info, [set_type, get_type]))
def return_proper_field_type_from_get_field( ctx: MethodContext, django_context: DjangoContext) -> MypyType: # Options instance assert isinstance(ctx.type, Instance) # bail if list of generic params is empty if len(ctx.type.args) == 0: return ctx.default_return_type model_type = ctx.type.args[0] if not isinstance(model_type, Instance): return ctx.default_return_type model_cls = django_context.get_model_class_by_fullname( model_type.type.fullname) if model_cls is None: return ctx.default_return_type field_name_expr = helpers.get_call_argument_by_name(ctx, 'field_name') if field_name_expr is None: return ctx.default_return_type field_name = helpers.resolve_string_attribute_value( field_name_expr, django_context) if field_name is None: return ctx.default_return_type try: field = model_cls._meta.get_field(field_name) except FieldDoesNotExist as exc: # if model is abstract, do not raise exception, skip false positives if not model_cls._meta.abstract: ctx.api.fail(exc.args[0], ctx.context) return AnyType(TypeOfAny.from_error) field_fullname = helpers.get_class_fullname(field.__class__) return _get_field_instance(ctx, field_fullname)
def all_registered_model_class_fullnames(self) -> Set[str]: return { helpers.get_class_fullname(cls) for cls in self.all_registered_model_classes }
def lookup_class_typeinfo_or_incomplete_defn_error(self, klass: type) -> TypeInfo: fullname = helpers.get_class_fullname(klass) field_info = self.lookup_typeinfo_or_incomplete_defn_error(fullname) return field_info