Example #1
0
        def add_method(funcname: str,
                       ret: Type,
                       args: List[Argument],
                       name: Optional[str] = None,
                       is_classmethod: bool = False,
                       is_new: bool = False,
                       ) -> None:
            if is_classmethod or is_new:
                first = [Argument(Var('cls'), TypeType.make_normalized(selftype), None, ARG_POS)]
            else:
                first = [Argument(Var('self'), selftype, None, ARG_POS)]
            args = first + args

            types = [arg.type_annotation for arg in args]
            items = [arg.variable.name() for arg in args]
            arg_kinds = [arg.kind for arg in args]
            assert None not in types
            signature = CallableType(cast(List[Type], types), arg_kinds, items, ret,
                                     function_type)
            signature.variables = [tvd]
            func = FuncDef(funcname, args, Block([]))
            func.info = info
            func.is_class = is_classmethod
            func.type = set_callable_name(signature, func)
            func._fullname = info.fullname() + '.' + funcname
            if is_classmethod:
                v = Var(funcname, func.type)
                v.is_classmethod = True
                v.info = info
                v._fullname = func._fullname
                dec = Decorator(func, [NameExpr('classmethod')], v)
                info.names[funcname] = SymbolTableNode(MDEF, dec)
            else:
                info.names[funcname] = SymbolTableNode(MDEF, func)
Example #2
0
def add_new_class_for_module(
    module: MypyFile,
    name: str,
    bases: List[Instance],
    fields: Optional[Dict[str, MypyType]] = None,
    no_serialize: bool = False,
) -> TypeInfo:
    new_class_unique_name = checker.gen_unique_name(name, module.names)

    # make new class expression
    classdef = ClassDef(new_class_unique_name, Block([]))
    classdef.fullname = module.fullname + "." + new_class_unique_name

    # make new TypeInfo
    new_typeinfo = TypeInfo(SymbolTable(), classdef, module.fullname)
    new_typeinfo.bases = bases
    calculate_mro(new_typeinfo)
    new_typeinfo.calculate_metaclass_type()

    # add fields
    if fields:
        for field_name, field_type in fields.items():
            var = Var(field_name, type=field_type)
            var.info = new_typeinfo
            var._fullname = new_typeinfo.fullname + "." + field_name
            new_typeinfo.names[field_name] = SymbolTableNode(
                MDEF, var, plugin_generated=True, no_serialize=no_serialize)

    classdef.info = new_typeinfo
    module.names[new_class_unique_name] = SymbolTableNode(
        GDEF, new_typeinfo, plugin_generated=True, no_serialize=no_serialize)
    return new_typeinfo
Example #3
0
    def create_new_model_parametrized_manager(self, name: str, base_manager_info: TypeInfo) -> Instance:
        bases = []
        for original_base in base_manager_info.bases:
            if self.is_any_parametrized_manager(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)

        new_manager_info = self.add_new_class_for_current_module(name, bases)
        # copy fields to a new manager
        new_cls_def_context = ClassDefContext(cls=new_manager_info.defn, reason=self.ctx.reason, api=self.api)
        custom_manager_type = Instance(new_manager_info, [Instance(self.model_classdef.info, [])])

        for name, sym in base_manager_info.names.items():
            # replace self type with new class, if copying method
            if isinstance(sym.node, FuncDef):
                helpers.copy_method_to_another_class(
                    new_cls_def_context, self_type=custom_manager_type, new_method_name=name, method_node=sym.node
                )
                continue

            new_sym = sym.copy()
            if isinstance(new_sym.node, Var):
                new_var = Var(name, type=sym.type)
                new_var.info = new_manager_info
                new_var._fullname = new_manager_info.fullname + "." + name
                new_sym.node = new_var
            new_manager_info.names[name] = new_sym

        return custom_manager_type
Example #4
0
 def add_new_node_to_model_class(self, name: str, typ: Instance) -> None:
     var = Var(name=name, type=typ)
     var.info = typ.type
     var._fullname = self.model_classdef.info.fullname() + '.' + name
     var.is_inferred = True
     var.is_initialized_in_class = True
     self.model_classdef.info.names[name] = SymbolTableNode(MDEF, var)
Example #5
0
        def add_method(funcname: str,
                       ret: Type,
                       args: List[Argument],
                       name: Optional[str] = None,
                       is_classmethod: bool = False,
                       is_new: bool = False,
                       ) -> None:
            if is_classmethod or is_new:
                first = [Argument(Var('cls'), TypeType.make_normalized(selftype), None, ARG_POS)]
            else:
                first = [Argument(Var('self'), selftype, None, ARG_POS)]
            args = first + args

            types = [arg.type_annotation for arg in args]
            items = [arg.variable.name() for arg in args]
            arg_kinds = [arg.kind for arg in args]
            assert None not in types
            signature = CallableType(cast(List[Type], types), arg_kinds, items, ret,
                                     function_type)
            signature.variables = [tvd]
            func = FuncDef(funcname, args, Block([]))
            func.info = info
            func.is_class = is_classmethod
            func.type = set_callable_name(signature, func)
            func._fullname = info.fullname() + '.' + funcname
            if is_classmethod:
                v = Var(funcname, func.type)
                v.is_classmethod = True
                v.info = info
                v._fullname = func._fullname
                dec = Decorator(func, [NameExpr('classmethod')], v)
                info.names[funcname] = SymbolTableNode(MDEF, dec)
            else:
                info.names[funcname] = SymbolTableNode(MDEF, func)
Example #6
0
def add_attribute_to_class(
    api: SemanticAnalyzerPluginInterface,
    cls: ClassDef,
    name: str,
    typ: Type,
    final: bool = False,
) -> None:
    """
    Adds a new attribute to a class definition.
    This currently only generates the symbol table entry and no corresponding AssignmentStatement
    """
    info = cls.info

    # NOTE: we would like the plugin generated node to dominate, but we still
    # need to keep any existing definitions so they get semantically analyzed.
    if name in info.names:
        # Get a nice unique name instead.
        r_name = get_unique_redefinition_name(name, info.names)
        info.names[r_name] = info.names[name]

    node = Var(name, typ)
    node.info = info
    node.is_final = final
    node._fullname = info.fullname + '.' + name
    info.names[name] = SymbolTableNode(MDEF, node, plugin_generated=True)
Example #7
0
 def add_field(var: Var, is_initialized_in_class: bool = False,
               is_property: bool = False) -> None:
     var.info = info
     var.is_initialized_in_class = is_initialized_in_class
     var.is_property = is_property
     var._fullname = '%s.%s' % (info.fullname(), var.name())
     info.names[var.name()] = SymbolTableNode(MDEF, var)
Example #8
0
 def add_field(var: Var, is_initialized_in_class: bool = False,
               is_property: bool = False) -> None:
     var.info = info
     var.is_initialized_in_class = is_initialized_in_class
     var.is_property = is_property
     var._fullname = '%s.%s' % (info.fullname, var.name)
     info.names[var.name] = SymbolTableNode(MDEF, var)
Example #9
0
def _add_attrs_magic_attribute(
        ctx: 'mypy.plugin.ClassDefContext',
        attrs: 'List[Tuple[str, Optional[Type]]]') -> None:
    any_type = AnyType(TypeOfAny.explicit)
    attributes_types: 'List[Type]' = [
        ctx.api.named_type_or_none('attr.Attribute', [attr_type or any_type])
        or any_type for _, attr_type in attrs
    ]
    fallback_type = ctx.api.named_type('builtins.tuple', [
        ctx.api.named_type_or_none('attr.Attribute', [any_type]) or any_type,
    ])

    ti = ctx.api.basic_new_typeinfo(MAGIC_ATTR_CLS_NAME, fallback_type, 0)
    ti.is_named_tuple = True
    for (name, _), attr_type in zip(attrs, attributes_types):
        var = Var(name, attr_type)
        var.is_property = True
        proper_type = get_proper_type(attr_type)
        if isinstance(proper_type, Instance):
            var.info = proper_type.type
        ti.names[name] = SymbolTableNode(MDEF, var, plugin_generated=True)
    attributes_type = Instance(ti, [])

    # TODO: refactor using `add_attribute_to_class`
    var = Var(name=MAGIC_ATTR_NAME,
              type=TupleType(attributes_types, fallback=attributes_type))
    var.info = ctx.cls.info
    var.is_classvar = True
    var._fullname = f"{ctx.cls.fullname}.{MAGIC_ATTR_CLS_NAME}"
    ctx.cls.info.names[MAGIC_ATTR_NAME] = SymbolTableNode(
        kind=MDEF,
        node=var,
        plugin_generated=True,
        no_serialize=True,
    )
Example #10
0
 def add_field_to_new_typeinfo(var: Var,
                               is_initialized_in_class: bool = False,
                               is_property: bool = False) -> None:
     var.info = new_typeinfo
     var.is_initialized_in_class = is_initialized_in_class
     var.is_property = is_property
     var._fullname = new_typeinfo.fullname() + '.' + var.name()
     new_typeinfo.names[var.name()] = SymbolTableNode(MDEF, var)
Example #11
0
def add_new_sym_for_info(info: TypeInfo, *, name: str, sym_type: MypyType) -> None:
    # type=: type of the variable itself
    var = Var(name=name, type=sym_type)
    # var.info: type of the object variable is bound to
    var.info = info
    var._fullname = info.fullname + "." + name
    var.is_initialized_in_class = True
    var.is_inferred = True
    info.names[name] = SymbolTableNode(MDEF, var, plugin_generated=True)
Example #12
0
 def create_new_var(self, name: str, typ: Instance) -> Var:
     # type=: type of the variable itself
     var = Var(name=name, type=typ)
     # var.info: type of the object variable is bound to
     var.info = self.model_classdef.info
     var._fullname = self.model_classdef.info.fullname() + '.' + name
     var.is_initialized_in_class = True
     var.is_inferred = True
     return var
Example #13
0
def add_var_to_class(name: str, typ: Type, info: TypeInfo) -> None:
    """Add a variable with given name and type to the symbol table of a class.

    This also takes care about setting necessary attributes on the variable node.
    """
    var = Var(name)
    var.info = info
    var._fullname = fullname(info) + '.' + name
    var.type = typ
    info.names[name] = SymbolTableNode(MDEF, var)
Example #14
0
 def add_new_node_to_model_class(self, name: str, typ: Instance) -> None:
     # type=: type of the variable itself
     var = Var(name=name, type=typ)
     # var.info: type of the object variable is bound to
     var.info = self.model_classdef.info
     var._fullname = self.model_classdef.info.fullname() + '.' + name
     var.is_inferred = True
     var.is_initialized_in_class = True
     self.model_classdef.info.names[name] = SymbolTableNode(
         MDEF, var, plugin_generated=True)
def _add_var_to_class(name: str, typ: Type, info: TypeInfo) -> None:
    """
    Add a variable with given name and type to the symbol table of a class.
    This also takes care about setting necessary attributes on the variable node.
    """

    var = Var(name)
    var.info = info
    var._fullname = f'{info.fullname}.{name}'  # pylint: disable=protected-access
    var.type = typ
    info.names[name] = SymbolTableNode(MDEF, var)
Example #16
0
 def build_enum_call_typeinfo(self, name: str, items: List[str], fullname: str) -> TypeInfo:
     base = self.api.named_type_or_none(fullname)
     assert base is not None
     info = self.api.basic_new_typeinfo(name, base)
     info.metaclass_type = info.calculate_metaclass_type()
     info.is_enum = True
     for item in items:
         var = Var(item)
         var.info = info
         var.is_property = True
         var._fullname = '{}.{}'.format(self.api.qualified_name(name), item)
         info.names[item] = SymbolTableNode(MDEF, var)
     return info
Example #17
0
 def build_enum_call_typeinfo(self, name: str, items: List[str], fullname: str) -> TypeInfo:
     base = self.api.named_type_or_none(fullname)
     assert base is not None
     info = self.api.basic_new_typeinfo(name, base)
     info.metaclass_type = info.calculate_metaclass_type()
     info.is_enum = True
     for item in items:
         var = Var(item)
         var.info = info
         var.is_property = True
         var._fullname = '{}.{}'.format(self.api.qualified_name(name), item)
         info.names[item] = SymbolTableNode(MDEF, var)
     return info
Example #18
0
    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())
                    # copy fields to a new manager
                    for name, sym in manager_info.names.items():
                        new_sym = sym.copy()
                        if isinstance(new_sym.node, Var):
                            new_var = Var(name, type=sym.type)
                            new_var.info = custom_manager_info
                            new_var._fullname = custom_manager_info.fullname(
                            ) + '.' + name
                            new_sym.node = new_var
                        custom_manager_info.names[name] = new_sym

                    custom_manager_type = Instance(
                        custom_manager_info,
                        [Instance(self.model_classdef.info, [])])
                    self.add_new_node_to_model_class(manager_name,
                                                     custom_manager_type)
Example #19
0
 def visit_var(self, node: Var) -> Var:
     # Note that a Var must be transformed to a Var.
     if node in self.var_map:
         return self.var_map[node]
     new = Var(node.name(), self.optional_type(node.type))
     new.line = node.line
     new._fullname = node._fullname
     new.info = node.info
     new.is_self = node.is_self
     new.is_ready = node.is_ready
     new.is_initialized_in_class = node.is_initialized_in_class
     new.is_staticmethod = node.is_staticmethod
     new.is_property = node.is_property
     new.set_line(node.line)
     self.var_map[node] = new
     return new
Example #20
0
 def visit_var(self, node: Var) -> Var:
     # Note that a Var must be transformed to a Var.
     if node in self.var_map:
         return self.var_map[node]
     new = Var(node.name(), self.optional_type(node.type))
     new.line = node.line
     new._fullname = node._fullname
     new.info = node.info
     new.is_self = node.is_self
     new.is_ready = node.is_ready
     new.is_initialized_in_class = node.is_initialized_in_class
     new.is_staticmethod = node.is_staticmethod
     new.is_property = node.is_property
     new.set_line(node.line)
     self.var_map[node] = new
     return new
Example #21
0
 def _add_dataclass_fields_magic_attribute(self) -> None:
     attr_name = '__dataclass_fields__'
     any_type = AnyType(TypeOfAny.explicit)
     field_type = self._ctx.api.named_type_or_none('dataclasses.Field', [any_type]) or any_type
     attr_type = self._ctx.api.named_type('builtins.dict', [
         self._ctx.api.named_type('builtins.str'),
         field_type,
     ])
     var = Var(name=attr_name, type=attr_type)
     var.info = self._ctx.cls.info
     var._fullname = self._ctx.cls.info.fullname + '.' + attr_name
     self._ctx.cls.info.names[attr_name] = SymbolTableNode(
         kind=MDEF,
         node=var,
         plugin_generated=True,
     )
Example #22
0
def _make_frozen(ctx: 'mypy.plugin.ClassDefContext', attributes: List[Attribute]) -> None:
    """Turn all the attributes into properties to simulate frozen classes."""
    for attribute in attributes:
        if attribute.name in ctx.cls.info.names:
            # This variable belongs to this class so we can modify it.
            node = ctx.cls.info.names[attribute.name].node
            assert isinstance(node, Var)
            node.is_property = True
        else:
            # This variable belongs to a super class so create new Var so we
            # can modify it.
            var = Var(attribute.name, ctx.cls.info[attribute.name].type)
            var.info = ctx.cls.info
            var._fullname = '%s.%s' % (ctx.cls.info.fullname, var.name)
            ctx.cls.info.names[var.name] = SymbolTableNode(MDEF, var)
            var.is_property = True
Example #23
0
def _make_frozen(ctx: 'mypy.plugin.ClassDefContext', attributes: List[Attribute]) -> None:
    """Turn all the attributes into properties to simulate frozen classes."""
    for attribute in attributes:
        if attribute.name in ctx.cls.info.names:
            # This variable belongs to this class so we can modify it.
            node = ctx.cls.info.names[attribute.name].node
            assert isinstance(node, Var)
            node.is_property = True
        else:
            # This variable belongs to a super class so create new Var so we
            # can modify it.
            var = Var(attribute.name, ctx.cls.info[attribute.name].type)
            var.info = ctx.cls.info
            var._fullname = '%s.%s' % (ctx.cls.info.fullname(), var.name())
            ctx.cls.info.names[var.name()] = SymbolTableNode(MDEF, var)
            var.is_property = True
Example #24
0
def _apply_placeholder_attr_to_class(
    api: SemanticAnalyzerPluginInterface,
    cls: ClassDef,
    qualified_name: str,
    attrname: str,
) -> None:
    sym = api.lookup_fully_qualified_or_none(qualified_name)
    if sym:
        assert isinstance(sym.node, TypeInfo)
        type_: ProperType = Instance(sym.node, [])
    else:
        type_ = AnyType(TypeOfAny.special_form)
    var = Var(attrname)
    var._fullname = cls.fullname + "." + attrname
    var.info = cls.info
    var.type = type_
    cls.info.names[attrname] = SymbolTableNode(MDEF, var)
Example #25
0
def _add_attrs_magic_attribute(ctx: 'mypy.plugin.ClassDefContext',
                               raw_attr_types: 'List[Optional[Type]]') -> None:
    attr_name = '__attrs_attrs__'
    any_type = AnyType(TypeOfAny.explicit)
    attributes_types: 'List[Type]' = [
        ctx.api.named_type_or_none('attr.Attribute', [attr_type or any_type])
        or any_type for attr_type in raw_attr_types
    ]
    fallback_type = ctx.api.named_type('builtins.tuple', [
        ctx.api.named_type_or_none('attr.Attribute', [any_type]) or any_type,
    ])
    var = Var(name=attr_name,
              type=TupleType(attributes_types, fallback=fallback_type))
    var.info = ctx.cls.info
    var._fullname = ctx.cls.info.fullname + '.' + attr_name
    ctx.cls.info.names[attr_name] = SymbolTableNode(
        kind=MDEF,
        node=var,
        plugin_generated=True,
    )
Example #26
0
    def visit_file(self, file: MypyFile, fnam: str, mod_id: str,
                   options: Options) -> None:
        """Perform the first analysis pass.

        Populate module global table.  Resolve the full names of
        definitions not nested within functions and construct type
        info structures, but do not resolve inter-definition
        references such as base classes.

        Also add implicit definitions such as __name__.

        In this phase we don't resolve imports. For 'from ... import',
        we generate dummy symbol table nodes for the imported names,
        and these will get resolved in later phases of semantic
        analysis.
        """
        sem = self.sem
        self.sem.options = options  # Needed because we sometimes call into it
        self.pyversion = options.python_version
        self.platform = options.platform
        sem.cur_mod_id = mod_id
        sem.cur_mod_node = file
        sem.errors.set_file(fnam, mod_id, scope=sem.scope)
        sem.globals = SymbolTable()
        sem.global_decls = [set()]
        sem.nonlocal_decls = [set()]
        sem.block_depth = [0]

        sem.scope.enter_file(mod_id)

        defs = file.defs

        with experiments.strict_optional_set(options.strict_optional):
            # Add implicit definitions of module '__name__' etc.
            for name, t in implicit_module_attrs.items():
                # unicode docstrings should be accepted in Python 2
                if name == '__doc__':
                    if self.pyversion >= (3, 0):
                        typ = UnboundType('__builtins__.str')  # type: Type
                    else:
                        typ = UnionType([
                            UnboundType('__builtins__.str'),
                            UnboundType('__builtins__.unicode')
                        ])
                else:
                    assert t is not None, 'type should be specified for {}'.format(
                        name)
                    typ = UnboundType(t)
                v = Var(name, typ)
                v._fullname = self.sem.qualified_name(name)
                self.sem.globals[name] = SymbolTableNode(GDEF, v)

            for d in defs:
                d.accept(self)

            # Add implicit definition of literals/keywords to builtins, as we
            # cannot define a variable with them explicitly.
            if mod_id == 'builtins':
                literal_types = [
                    ('None', NoneTyp()),
                    # reveal_type is a mypy-only function that gives an error with
                    # the type of its arg.
                    ('reveal_type', AnyType(TypeOfAny.special_form)),
                    # reveal_locals is a mypy-only function that gives an error with the types of
                    # locals
                    ('reveal_locals', AnyType(TypeOfAny.special_form)),
                ]  # type: List[Tuple[str, Type]]

                # TODO(ddfisher): This guard is only needed because mypy defines
                # fake builtins for its tests which often don't define bool.  If
                # mypy is fast enough that we no longer need those, this
                # conditional check should be removed.
                if 'bool' in self.sem.globals:
                    bool_type = self.sem.named_type('bool')
                    literal_types.extend([
                        ('True', bool_type),
                        ('False', bool_type),
                        ('__debug__', bool_type),
                    ])
                else:
                    # We are running tests without 'bool' in builtins.
                    # TODO: Find a permanent solution to this problem.
                    # Maybe add 'bool' to all fixtures?
                    literal_types.append(
                        ('True', AnyType(TypeOfAny.special_form)))

                for name, typ in literal_types:
                    v = Var(name, typ)
                    v._fullname = self.sem.qualified_name(name)
                    self.sem.globals[name] = SymbolTableNode(GDEF, v)

            del self.sem.options

        sem.scope.leave()
Example #27
0
def add_method(
    ctx: ClassDefContext,
    name: str,
    args: List[Argument],
    return_type: Type,
    self_type: Optional[Type] = None,
    tvar_def: Optional[TypeVarDef] = None,
    is_classmethod: bool = False,
    is_new: bool = False,
    # is_staticmethod: bool = False,
) -> None:
    """
    Adds a new method to a class.

    This can be dropped if/when https://github.com/python/mypy/issues/7301 is merged
    """
    info = ctx.cls.info

    # First remove any previously generated methods with the same name
    # to avoid clashes and problems in the semantic analyzer.
    if name in info.names:
        sym = info.names[name]
        if sym.plugin_generated and isinstance(sym.node, FuncDef):
            ctx.cls.defs.body.remove(sym.node)

    self_type = self_type or fill_typevars(info)
    if is_classmethod or is_new:
        first = [
            Argument(Var("_cls"), TypeType.make_normalized(self_type), None,
                     ARG_POS)
        ]
    # elif is_staticmethod:
    #     first = []
    else:
        self_type = self_type or fill_typevars(info)
        first = [Argument(Var("self"), self_type, None, ARG_POS)]
    args = first + args
    arg_types, arg_names, arg_kinds = [], [], []
    for arg in args:
        assert arg.type_annotation, "All arguments must be fully typed."
        arg_types.append(arg.type_annotation)
        arg_names.append(get_name(arg.variable))
        arg_kinds.append(arg.kind)

    function_type = ctx.api.named_type("__builtins__.function")
    signature = CallableType(arg_types, arg_kinds, arg_names, return_type,
                             function_type)
    if tvar_def:
        signature.variables = [tvar_def]

    func = FuncDef(name, args, Block([PassStmt()]))
    func.info = info
    func.type = set_callable_name(signature, func)
    func.is_class = is_classmethod
    # func.is_static = is_staticmethod
    func._fullname = get_fullname(info) + "." + name
    func.line = info.line

    # NOTE: we would like the plugin generated node to dominate, but we still
    # need to keep any existing definitions so they get semantically analyzed.
    if name in info.names:
        # Get a nice unique name instead.
        r_name = get_unique_redefinition_name(name, info.names)
        info.names[r_name] = info.names[name]

    if is_classmethod:  # or is_staticmethod:
        func.is_decorated = True
        v = Var(name, func.type)
        v.info = info
        v._fullname = func._fullname
        # if is_classmethod:
        v.is_classmethod = True
        dec = Decorator(func, [NameExpr("classmethod")], v)
        # else:
        #     v.is_staticmethod = True
        #     dec = Decorator(func, [NameExpr('staticmethod')], v)

        dec.line = info.line
        sym = SymbolTableNode(MDEF, dec)
    else:
        sym = SymbolTableNode(MDEF, func)
    sym.plugin_generated = True

    info.names[name] = sym
    info.defn.defs.body.append(func)
Example #28
0
def add_var_to_class(info: TypeInfo, name: str, typ: Type) -> None:
    var = Var(name)
    var.info = info
    var._fullname = get_fullname(info) + "." + name
    var.type = typ
    info.names[name] = SymbolTableNode(MDEF, var)
Example #29
0
    def visit_file(self, file: MypyFile, fnam: str, mod_id: str, options: Options) -> None:
        """Perform the first analysis pass.

        Populate module global table.  Resolve the full names of
        definitions not nested within functions and construct type
        info structures, but do not resolve inter-definition
        references such as base classes.

        Also add implicit definitions such as __name__.

        In this phase we don't resolve imports. For 'from ... import',
        we generate dummy symbol table nodes for the imported names,
        and these will get resolved in later phases of semantic
        analysis.
        """
        sem = self.sem
        self.sem.options = options  # Needed because we sometimes call into it
        self.pyversion = options.python_version
        self.platform = options.platform
        sem.cur_mod_id = mod_id
        sem.cur_mod_node = file
        sem.errors.set_file(fnam, mod_id, scope=sem.scope)
        sem.globals = SymbolTable()
        sem.global_decls = [set()]
        sem.nonlocal_decls = [set()]
        sem.block_depth = [0]

        sem.scope.enter_file(mod_id)

        defs = file.defs

        with experiments.strict_optional_set(options.strict_optional):
            # Add implicit definitions of module '__name__' etc.
            for name, t in implicit_module_attrs.items():
                # unicode docstrings should be accepted in Python 2
                if name == '__doc__':
                    if self.pyversion >= (3, 0):
                        typ = UnboundType('__builtins__.str')  # type: Type
                    else:
                        typ = UnionType([UnboundType('__builtins__.str'),
                                        UnboundType('__builtins__.unicode')])
                else:
                    assert t is not None, 'type should be specified for {}'.format(name)
                    typ = UnboundType(t)
                v = Var(name, typ)
                v._fullname = self.sem.qualified_name(name)
                self.sem.globals[name] = SymbolTableNode(GDEF, v)

            for d in defs:
                d.accept(self)

            # Add implicit definition of literals/keywords to builtins, as we
            # cannot define a variable with them explicitly.
            if mod_id == 'builtins':
                literal_types = [
                    ('None', NoneTyp()),
                    # reveal_type is a mypy-only function that gives an error with
                    # the type of its arg.
                    ('reveal_type', AnyType(TypeOfAny.special_form)),
                ]  # type: List[Tuple[str, Type]]

                # TODO(ddfisher): This guard is only needed because mypy defines
                # fake builtins for its tests which often don't define bool.  If
                # mypy is fast enough that we no longer need those, this
                # conditional check should be removed.
                if 'bool' in self.sem.globals:
                    bool_type = self.sem.named_type('bool')
                    literal_types.extend([
                        ('True', bool_type),
                        ('False', bool_type),
                        ('__debug__', bool_type),
                    ])
                else:
                    # We are running tests without 'bool' in builtins.
                    # TODO: Find a permanent solution to this problem.
                    # Maybe add 'bool' to all fixtures?
                    literal_types.append(('True', AnyType(TypeOfAny.special_form)))

                for name, typ in literal_types:
                    v = Var(name, typ)
                    v._fullname = self.sem.qualified_name(name)
                    self.sem.globals[name] = SymbolTableNode(GDEF, v)

            del self.sem.options

        sem.scope.leave()
Example #30
0
def add_class_method(
    ctx: ClassDefContext,
    name: str,
    args: List[Argument],
    return_type: Type,
    self_type: Optional[Type] = None,
    tvar_def: Optional[TypeVarDef] = None,
) -> None:
    """Adds a new class method to a class.
    """
    info = ctx.cls.info

    # First remove any previously generated methods with the same name
    # to avoid clashes and problems in the semantic analyzer.
    if name in info.names:
        sym = info.names[name]
        if sym.plugin_generated and isinstance(sym.node, FuncDef):
            ctx.cls.defs.body.remove(sym.node)

    self_type = self_type or fill_typevars(info)
    function_type = ctx.api.named_type('__builtins__.function')

    args = [
        Argument(Var('_cls'), TypeType.make_normalized(self_type), None,
                 ARG_POS)
    ] + args
    arg_types, arg_names, arg_kinds = [], [], []
    for arg in args:
        assert arg.type_annotation, 'All arguments must be fully typed.'
        arg_types.append(arg.type_annotation)
        arg_names.append(arg.variable.name)
        arg_kinds.append(arg.kind)

    signature = CallableType(arg_types, arg_kinds, arg_names, return_type,
                             function_type)
    if tvar_def:
        signature.variables = [tvar_def]

    func = FuncDef(name, args, Block([PassStmt()]))
    func.info = info
    func.type = set_callable_name(signature, func)
    func.is_class = True
    func._fullname = info.fullname + '.' + name
    func.line = info.line

    # NOTE: we would like the plugin generated node to dominate, but we still
    # need to keep any existing definitions so they get semantically analyzed.
    if name in info.names:
        # Get a nice unique name instead.
        r_name = get_unique_redefinition_name(name, info.names)
        info.names[r_name] = info.names[name]

    func.is_decorated = True
    v = Var(name, func.type)
    v.info = info
    v._fullname = func._fullname
    v.is_classmethod = True
    dec = Decorator(func, [NameExpr('classmethod')], v)

    dec.line = info.line
    sym = SymbolTableNode(MDEF, dec)

    sym.plugin_generated = True

    info.names[name] = sym
    info.defn.defs.body.append(func)
Example #31
0
def add_method_to_class(
    api: SemanticAnalyzerPluginInterface,
    cls: ClassDef,
    name: str,
    args: List[Argument],
    return_type: Type,
    self_type: Optional[Type] = None,
    tvar_def: Optional[TypeVarDef] = None,
    is_classmethod: bool = False,
) -> None:
    """
    Adds a new method to a class definition.

    NOTE:
    Copied from mypy/plugins/common.py and extended with support for adding
    classmethods based on https://github.com/python/mypy/pull/7796

    """

    info = cls.info

    # First remove any previously generated methods with the same name
    # to avoid clashes and problems in the semantic analyzer.
    if name in info.names:
        sym = info.names[name]
        if sym.plugin_generated and isinstance(sym.node, FuncDef):
            cls.defs.body.remove(sym.node)

    self_type = self_type or fill_typevars(info)

    # Add either self or cls as the first argument
    if is_classmethod:
        first = Argument(Var("cls"), TypeType.make_normalized(self_type), None,
                         ARG_POS)
    else:
        first = Argument(Var("self"), self_type, None, ARG_POS)

    args = [first] + args
    arg_types, arg_names, arg_kinds = [], [], []
    for arg in args:
        assert arg.type_annotation, "All arguments must be fully typed."
        arg_types.append(arg.type_annotation)
        arg_names.append(arg.variable.name)
        arg_kinds.append(arg.kind)

    function_type = api.named_type("__builtins__.function")
    signature = CallableType(arg_types, arg_kinds, arg_names, return_type,
                             function_type)
    if tvar_def:
        signature.variables = [tvar_def]

    func = FuncDef(name, args, Block([PassStmt()]))
    func.info = info
    func.type = set_callable_name(signature, func)
    func._fullname = info.fullname + "." + name  # pylint: disable=protected-access
    func.line = info.line
    func.is_class = is_classmethod

    # NOTE: we would like the plugin generated node to dominate, but we still
    # need to keep any existing definitions so they get semantically analyzed.
    if name in info.names:
        # Get a nice unique name instead.
        r_name = get_unique_redefinition_name(name, info.names)
        info.names[r_name] = info.names[name]

    if is_classmethod:
        func.is_decorated = True
        v = Var(name, func.type)
        v.info = info
        v._fullname = func._fullname  # pylint: disable=protected-access
        v.is_classmethod = True
        dec = Decorator(func, [NameExpr("classmethod")], v)

        dec.line = info.line
        sym = SymbolTableNode(MDEF, dec)
    else:
        sym = SymbolTableNode(MDEF, func)
    sym.plugin_generated = True

    info.names[name] = sym
    info.defn.defs.body.append(func)