def argument(self, ctx: 'mypy.plugin.ClassDefContext') -> Argument: """Return this attribute as an argument to __init__.""" assert self.init init_type = self.info[self.name].type if self.converter_name: # When a converter is set the init_type is overriden by the first argument # of the converter method. converter = lookup_qualified_stnode(ctx.api.modules, self.converter_name, True) if not converter: # The converter may be a local variable. Check there too. converter = ctx.api.lookup_qualified(self.converter_name, self.info, True) if (converter and converter.type and isinstance(converter.type, CallableType) and converter.type.arg_types): init_type = ctx.api.anal_type(converter.type.arg_types[0]) else: ctx.api.fail("Cannot determine type of converter function", self.context) init_type = AnyType(TypeOfAny.from_error) elif self.converter_name == '': # This means we had a converter but it's not of a type we can infer. # Error was shown in _get_converter_name init_type = AnyType(TypeOfAny.from_error) if init_type is None: if ctx.api.options.disallow_untyped_defs: # This is a compromise. If you don't have a type here then the # __init__ will be untyped. But since the __init__ is added it's # pointing at the decorator. So instead we also show the error in the # assignment, which is where you would fix the issue. node = self.info[self.name].node assert node is not None ctx.api.msg.need_annotation_for_var(node, self.context) # Convert type not set to Any. init_type = AnyType(TypeOfAny.unannotated) # Attrs removes leading underscores when creating the __init__ arguments. return Argument(Var(self.name.lstrip("_"), init_type), init_type, None, ARG_OPT if self.has_default else ARG_POS)
def argument(self, ctx: 'mypy.plugin.ClassDefContext') -> Argument: """Return this attribute as an argument to __init__.""" assert self.init init_type = self.info[self.name].type if self.converter_name: # When a converter is set the init_type is overriden by the first argument # of the converter method. converter = lookup_qualified_stnode(ctx.api.modules, self.converter_name, True) if not converter: # The converter may be a local variable. Check there too. converter = ctx.api.lookup_qualified(self.converter_name, self.info, True) if (converter and converter.type and isinstance(converter.type, CallableType) and converter.type.arg_types): init_type = ctx.api.anal_type(converter.type.arg_types[0]) else: ctx.api.fail("Cannot determine type of converter function", self.context) init_type = AnyType(TypeOfAny.from_error) elif self.converter_name == '': # This means we had a converter but it's not of a type we can infer. # Error was shown in _get_converter_name init_type = AnyType(TypeOfAny.from_error) if init_type is None: if ctx.api.options.disallow_untyped_defs: # This is a compromise. If you don't have a type here then the # __init__ will be untyped. But since the __init__ is added it's # pointing at the decorator. So instead we also show the error in the # assignment, which is where you would fix the issue. node = self.info[self.name].node assert node is not None ctx.api.msg.need_annotation_for_var(node, self.context) # Convert type not set to Any. init_type = AnyType(TypeOfAny.unannotated) # Attrs removes leading underscores when creating the __init__ arguments. return Argument(Var(self.name.lstrip("_"), init_type), init_type, None, ARG_OPT if self.has_default else ARG_POS)
def argument(self, ctx: 'mypy.plugin.ClassDefContext') -> Argument: """Return this attribute as an argument to __init__.""" assert self.init init_type = self.init_type or self.info[self.name].type if self.converter.name: # When a converter is set the init_type is overridden by the first argument # of the converter method. converter = lookup_qualified_stnode(ctx.api.modules, self.converter.name, True) if not converter: # The converter may be a local variable. Check there too. converter = ctx.api.lookup_qualified(self.converter.name, self.info, True) # Get the type of the converter. converter_type = None # type: Optional[Type] if converter and isinstance(converter.node, TypeInfo): from mypy.checkmember import type_object_type # To avoid import cycle. converter_type = type_object_type(converter.node, ctx.api.builtin_type) elif converter and isinstance(converter.node, OverloadedFuncDef): converter_type = converter.node.type elif converter and converter.type: converter_type = converter.type init_type = None converter_type = get_proper_type(converter_type) if isinstance(converter_type, CallableType) and converter_type.arg_types: init_type = ctx.api.anal_type(converter_type.arg_types[0]) elif isinstance(converter_type, Overloaded): types = [] # type: List[Type] for item in converter_type.items(): # Walk the overloads looking for methods that can accept one argument. num_arg_types = len(item.arg_types) if not num_arg_types: continue if num_arg_types > 1 and any(kind == ARG_POS for kind in item.arg_kinds[1:]): continue types.append(item.arg_types[0]) # Make a union of all the valid types. if types: args = make_simplified_union(types) init_type = ctx.api.anal_type(args) if self.converter.is_attr_converters_optional and init_type: # If the converter was attr.converter.optional(type) then add None to # the allowed init_type. init_type = UnionType.make_union([init_type, NoneType()]) if not init_type: ctx.api.fail("Cannot determine __init__ type from converter", self.context) init_type = AnyType(TypeOfAny.from_error) elif self.converter.name == '': # This means we had a converter but it's not of a type we can infer. # Error was shown in _get_converter_name init_type = AnyType(TypeOfAny.from_error) if init_type is None: if ctx.api.options.disallow_untyped_defs: # This is a compromise. If you don't have a type here then the # __init__ will be untyped. But since the __init__ is added it's # pointing at the decorator. So instead we also show the error in the # assignment, which is where you would fix the issue. node = self.info[self.name].node assert node is not None ctx.api.msg.need_annotation_for_var(node, self.context) # Convert type not set to Any. init_type = AnyType(TypeOfAny.unannotated) if self.kw_only: arg_kind = ARG_NAMED_OPT if self.has_default else ARG_NAMED else: arg_kind = ARG_OPT if self.has_default else ARG_POS # Attrs removes leading underscores when creating the __init__ arguments. return Argument(Var(self.name.lstrip("_"), init_type), init_type, None, arg_kind)
def argument(self, ctx: 'mypy.plugin.ClassDefContext') -> Argument: """Return this attribute as an argument to __init__.""" assert self.init init_type = self.info[self.name].type if self.converter.name: # When a converter is set the init_type is overridden by the first argument # of the converter method. converter = lookup_qualified_stnode(ctx.api.modules, self.converter.name, True) if not converter: # The converter may be a local variable. Check there too. converter = ctx.api.lookup_qualified(self.converter.name, self.info, True) # Get the type of the converter. converter_type = None if converter and isinstance(converter.node, TypeInfo): from mypy.checkmember import type_object_type # To avoid import cycle. converter_type = type_object_type(converter.node, ctx.api.builtin_type) elif converter and isinstance(converter.node, OverloadedFuncDef): converter_type = converter.node.type elif converter and converter.type: converter_type = converter.type init_type = None if isinstance(converter_type, CallableType) and converter_type.arg_types: init_type = ctx.api.anal_type(converter_type.arg_types[0]) elif isinstance(converter_type, Overloaded): types = [] # type: List[Type] for item in converter_type.items(): # Walk the overloads looking for methods that can accept one argument. num_arg_types = len(item.arg_types) if not num_arg_types: continue if num_arg_types > 1 and any(kind == ARG_POS for kind in item.arg_kinds[1:]): continue types.append(item.arg_types[0]) # Make a union of all the valid types. if types: args = UnionType.make_simplified_union(types) init_type = ctx.api.anal_type(args) if self.converter.is_attr_converters_optional and init_type: # If the converter was attr.converter.optional(type) then add None to # the allowed init_type. init_type = UnionType.make_union([init_type, NoneTyp()]) if not init_type: ctx.api.fail("Cannot determine __init__ type from converter", self.context) init_type = AnyType(TypeOfAny.from_error) elif self.converter.name == '': # This means we had a converter but it's not of a type we can infer. # Error was shown in _get_converter_name init_type = AnyType(TypeOfAny.from_error) if init_type is None: if ctx.api.options.disallow_untyped_defs: # This is a compromise. If you don't have a type here then the # __init__ will be untyped. But since the __init__ is added it's # pointing at the decorator. So instead we also show the error in the # assignment, which is where you would fix the issue. node = self.info[self.name].node assert node is not None ctx.api.msg.need_annotation_for_var(node, self.context) # Convert type not set to Any. init_type = AnyType(TypeOfAny.unannotated) if self.kw_only: arg_kind = ARG_NAMED_OPT if self.has_default else ARG_NAMED else: arg_kind = ARG_OPT if self.has_default else ARG_POS # Attrs removes leading underscores when creating the __init__ arguments. return Argument(Var(self.name.lstrip("_"), init_type), init_type, None, arg_kind)