示例#1
0
def _get_type_for_expr(expr: Expression, api: SemanticAnalyzerPluginInterface):
    if isinstance(expr, NameExpr):
        # guarding agains invalid nodes, still have to figure out why this happens
        # but sometimes mypy crashes because the internal node of the named type
        # is actually a Var node, which is unexpected, so we do a naive guard here
        # and raise an exception for it.

        if expr.fullname:
            sym = api.lookup_fully_qualified_or_none(expr.fullname)

            if sym and isinstance(sym.node, Var):
                raise InvalidNodeTypeException()

        return api.named_type(expr.name)

    if isinstance(expr, IndexExpr):
        type_ = _get_type_for_expr(expr.base, api)
        type_.args = (_get_type_for_expr(expr.index, api), )

        return type_

    if isinstance(expr, MemberExpr):
        if expr.fullname:
            return api.named_type(expr.fullname)
        else:
            raise InvalidNodeTypeException()

    raise ValueError(f"Unsupported expression {type(expr)}")
def add_kw_props(cls: ClassDef, kw_class: ClassDef,
                 api: SemanticAnalyzerPluginInterface) -> None:
    try:
        ans_cls_expr = kw_class.keywords['ans_type']
        kw_set_expr = kw_class.keywords['extra_kws']
    except KeyError:
        api.fail(
            'Both `ans_type` and `extra_kws` are required to subclass '
            'KeywordsMixin',
            kw_class,
            code=CALL_ARG)
        return

    if not isinstance(ans_cls_expr, RefExpr):
        print('Wrong instance type for ans_type argument')
        return

    ans_cls_node = ans_cls_expr.node

    if not isinstance(ans_cls_node, TypeInfo):
        print('Got incorrect type for Ansible type node')
        return

    if not (isinstance(kw_set_expr, SetExpr)
            or is_empty_set_expr(kw_set_expr)):
        print('Wrong instance type for extra_kws')
        return

    # Can be an empty set, where we don't need to add any more properties.
    if isinstance(kw_set_expr, SetExpr):
        for kw_expr in kw_set_expr.items:
            add_property(cls.info, ans_cls_node, kw_expr, api)

    # Also add one for name
    add_property(cls.info, ans_cls_node, StrExpr('name'), api)
示例#3
0
def _extract_python_type_from_typeengine(
    api: SemanticAnalyzerPluginInterface,
    node: TypeInfo,
    type_args: Sequence[Expression],
) -> ProperType:
    if node.fullname == "sqlalchemy.sql.sqltypes.Enum" and type_args:
        first_arg = type_args[0]
        if isinstance(first_arg, NameExpr) and isinstance(
                first_arg.node, TypeInfo):
            for base_ in first_arg.node.mro:
                if base_.fullname == "enum.Enum":
                    return Instance(first_arg.node, [])
            # TODO: support other pep-435 types here
        else:
            return api.named_type("__builtins__.str", [])

    assert node.has_base("sqlalchemy.sql.type_api.TypeEngine"), (
        "could not extract Python type from node: %s" % node)

    type_engine_sym = api.lookup_fully_qualified_or_none(
        "sqlalchemy.sql.type_api.TypeEngine")

    assert type_engine_sym is not None and isinstance(type_engine_sym.node,
                                                      TypeInfo)
    type_engine = map_instance_to_supertype(
        Instance(node, []),
        type_engine_sym.node,
    )
    return get_proper_type(type_engine.args[-1])
def check_class_type(sym: Optional[SymbolTableNode],
                     api: SemanticAnalyzerPluginInterface,
                     ctx: Context) -> bool:
    if sym is None or not isinstance(sym.node, TypeInfo):
        api.fail('Expected a class', ctx, code=MISC)
        return False
    return True
示例#5
0
    def _adjust_interface_function(
        self,
        api: SemanticAnalyzerPluginInterface,
        class_info: TypeInfo,
        func_def: FuncDef,
    ) -> Statement:

        if func_def.arg_names and func_def.arg_names[0] == "self":
            # reveal the common mistake of leaving "self" arguments in the
            # interface
            api.fail("Interface methods should not have 'self' argument",
                     func_def)
        else:
            selftype = Instance(class_info, [],
                                line=class_info.line,
                                column=class_info.column)
            selfarg = Argument(Var("self", None), selftype, None, ARG_POS)

            if isinstance(func_def.type, CallableType):
                func_def.type.arg_names.insert(0, "self")
                func_def.type.arg_kinds.insert(0, ARG_POS)
                func_def.type.arg_types.insert(0, selftype)
            func_def.arg_names.insert(0, "self")
            func_def.arg_kinds.insert(0, ARG_POS)
            func_def.arguments.insert(0, selfarg)

        return func_def
def add_property(cls_node: TypeInfo, ans_cls_node: TypeInfo,
                 prop_node: Expression,
                 api: SemanticAnalyzerPluginInterface) -> None:
    """Add a property."""
    if not isinstance(prop_node, StrExpr):
        api.fail('Keyword must be a string literal',
                 prop_node,
                 code=VALID_TYPE)
        return
    prop_name = prop_node.value

    try:
        ans_type = ans_cls_node[prop_name].type
    except KeyError:
        api.fail(
            f'Attribute `{prop_name}` does not exist in '
            f'{ans_cls_node.name} or its parents',
            prop_node,
            code=ATTR_DEFINED)
        return

    prop_type = get_transformed_type(cls_node, ans_type, prop_node, api)
    if prop_type is None:
        return

    if not has_default(cls_node, prop_node, api) and prop_type is not None:
        prop_type = make_optional(prop_type)

    new_prop = Var(prop_name, api.anal_type(prop_type))
    new_prop.info = cls_node
    new_prop.is_initialized_in_class = True
    new_prop.is_property = True

    cls_node.names[prop_name] = SymbolTableNode(MDEF, new_prop)
示例#7
0
    def _interface_classdefs_for_meta_classdef(
            semanal: SemanticAnalyzerPluginInterface,
            classdef: ClassDef) -> List[ClassDef]:
        for statement in classdef.defs.body:
            if isinstance(statement, AssignmentStmt) and any(
                    isinstance(lval, NameExpr) and lval.name == "interfaces"
                    for lval in statement.lvalues):
                if not isinstance(statement.rvalue, TupleExpr):
                    semanal.fail(
                        '"interfaces" attribute in Meta class must be a tuple type',
                        statement,
                    )
                    return []

                # Loop through tuple and add defintions of graphene `Interface`s to the final list.
                interface_defs: List[ClassDef] = []
                for item in statement.rvalue.items:
                    if (isinstance(item, RefExpr)
                            and isinstance(item.node, TypeInfo)
                            and isinstance(item.node.defn, ClassDef)):
                        interface_defs.append(item.node.defn)

                return interface_defs

        return []
示例#8
0
def _apply_type_to_mapped_statement(
    api: SemanticAnalyzerPluginInterface,
    stmt: AssignmentStmt,
    lvalue: NameExpr,
    left_hand_explicit_type: Optional[Union[Instance, UnionType]],
    python_type_for_type: Union[Instance, UnionType],
) -> None:
    """Apply the Mapped[<type>] annotation and right hand object to a
    declarative assignment statement.

    This converts a Python declarative class statement such as::

        class User(Base):
            # ...

            attrname = Column(Integer)

    To one that describes the final Python behavior to Mypy::

        class User(Base):
            # ...

            attrname : Mapped[Optional[int]] = <meaningless temp node>

    """
    descriptor = api.modules["sqlalchemy.orm.attributes"].names["Mapped"]

    left_node = lvalue.node

    inst = Instance(descriptor.node, [python_type_for_type])

    if left_hand_explicit_type is not None:
        left_node.type = Instance(descriptor.node, [left_hand_explicit_type])
    else:
        lvalue.is_inferred_def = False
        left_node.type = inst

    # so to have it skip the right side totally, we can do this:
    # stmt.rvalue = TempNode(AnyType(TypeOfAny.special_form))

    # however, if we instead manufacture a new node that uses the old
    # one, then we can still get type checking for the call itself,
    # e.g. the Column, relationship() call, etc.

    # rewrite the node as:
    # <attr> : Mapped[<typ>] =
    # _sa_Mapped._empty_constructor(<original CallExpr from rvalue>)
    # the original right-hand side is maintained so it gets type checked
    # internally
    api.add_symbol_table_node("_sa_Mapped", descriptor)
    column_descriptor = nodes.NameExpr("_sa_Mapped")
    column_descriptor.fullname = "sqlalchemy.orm.Mapped"
    mm = nodes.MemberExpr(column_descriptor, "_empty_constructor")
    orig_call_expr = stmt.rvalue
    stmt.rvalue = CallExpr(
        mm,
        [orig_call_expr],
        [nodes.ARG_POS],
        ["arg1"],
    )
示例#9
0
def get_transformed_type(
        cls_node: TypeInfo, ans_type: Optional[Type], prop_node: StrExpr,
        api: SemanticAnalyzerPluginInterface) -> Optional[Type]:
    transformer_name = f'_transform_{prop_node.value}'
    transformer = cls_node.get(transformer_name)
    if transformer is None:
        return ans_type

    transformer_type: Optional[Type]
    if isinstance(transformer.node, Decorator):
        transformer_type = transformer.node.func.type
    elif isinstance(transformer.node, FuncDef):
        transformer_type = transformer.node.type
    elif (isinstance(transformer.node, Var)
          and (transformer.node.is_ready or transformer.node.is_final)):
        if transformer.node.is_ready:
            transformer_type = transformer.node.type
        else:
            transformer_type = find_redef_origin(cls_node, transformer_name)
            if transformer_type is None:
                api.fail(f'Cannot resolve type of `{transformer_name}`',
                         transformer.node,
                         code=MISC)
                return None
    else:
        api.fail(
            f'Cannot handle transformer `{transformer_name}` of type ' +
            transformer.node.__class__.__name__,
            transformer.node if transformer.node is not None else cls_node,
            code=MISC)
        return None

    if not isinstance(transformer_type, CallableType):
        api.fail(f'Cannot infer type of `{transformer_name}`',
                 transformer.node,
                 code=MISC)
        return None

    if len(transformer_type.arg_types) != 2:
        api.fail(
            f'Expected exactly 2 arguments for {transformer_name}:'
            'self and source object',
            transformer.node,
            code=CALL_ARG)
        return None

    transformer_type = api.anal_type(transformer_type)
    if not isinstance(transformer_type, CallableType):
        return None

    ret_type = bind_type_var(cls_node, transformer_type.ret_type)
    return api.anal_type(ret_type)
示例#10
0
def apply_type_to_mapped_statement(
    api: SemanticAnalyzerPluginInterface,
    stmt: AssignmentStmt,
    lvalue: NameExpr,
    left_hand_explicit_type: Optional[ProperType],
    python_type_for_type: Optional[ProperType],
) -> None:
    """Apply the Mapped[<type>] annotation and right hand object to a
    declarative assignment statement.

    This converts a Python declarative class statement such as::

        class User(Base):
            # ...

            attrname = Column(Integer)

    To one that describes the final Python behavior to Mypy::

        class User(Base):
            # ...

            attrname : Mapped[Optional[int]] = <meaningless temp node>

    """
    left_node = lvalue.node
    assert isinstance(left_node, Var)

    if left_hand_explicit_type is not None:
        left_node.type = api.named_type(
            "__sa_Mapped", [left_hand_explicit_type]
        )
    else:
        lvalue.is_inferred_def = False
        left_node.type = api.named_type(
            "__sa_Mapped",
            [] if python_type_for_type is None else [python_type_for_type],
        )

    # so to have it skip the right side totally, we can do this:
    # stmt.rvalue = TempNode(AnyType(TypeOfAny.special_form))

    # however, if we instead manufacture a new node that uses the old
    # one, then we can still get type checking for the call itself,
    # e.g. the Column, relationship() call, etc.

    # rewrite the node as:
    # <attr> : Mapped[<typ>] =
    # _sa_Mapped._empty_constructor(<original CallExpr from rvalue>)
    # the original right-hand side is maintained so it gets type checked
    # internally
    stmt.rvalue = util.expr_to_mapped_constructor(stmt.rvalue)
示例#11
0
def infer_type_from_left_hand_type_only(
    api: SemanticAnalyzerPluginInterface,
    node: Var,
    left_hand_explicit_type: Optional[ProperType],
) -> Optional[ProperType]:
    """Determine the type based on explicit annotation only.

    if no annotation were present, note that we need one there to know
    the type.

    """
    if left_hand_explicit_type is None:
        msg = (
            "Can't infer type from ORM mapped expression "
            "assigned to attribute '{}'; please specify a "
            "Python type or "
            "Mapped[<python type>] on the left hand side."
        )
        util.fail(api, msg.format(node.name), node)

        return api.named_type("__sa_Mapped", [AnyType(TypeOfAny.special_form)])

    else:
        # use type from the left hand side
        return left_hand_explicit_type
def _set_declarative_metaclass(api: SemanticAnalyzerPluginInterface,
                               target_cls: ClassDef) -> None:
    info = target_cls.info
    sym = api.lookup_fully_qualified_or_none(
        "sqlalchemy.orm.decl_api.DeclarativeMeta")
    assert sym is not None and isinstance(sym.node, TypeInfo)
    info.declared_metaclass = info.metaclass_type = Instance(sym.node, [])
示例#13
0
def _re_apply_declarative_assignments(
    cls: ClassDef,
    api: SemanticAnalyzerPluginInterface,
    cls_metadata: util.DeclClassApplied,
):
    """For multiple class passes, re-apply our left-hand side types as mypy
    seems to reset them in place.

    """
    mapped_attr_lookup = {
        name: typ
        for name, typ in cls_metadata.mapped_attr_names
    }

    descriptor = api.lookup("__sa_Mapped", cls)
    for stmt in cls.defs.body:
        # for a re-apply, all of our statements are AssignmentStmt;
        # @declared_attr calls will have been converted and this
        # currently seems to be preserved by mypy (but who knows if this
        # will change).
        if (isinstance(stmt, AssignmentStmt)
                and stmt.lvalues[0].name in mapped_attr_lookup):
            typ = mapped_attr_lookup[stmt.lvalues[0].name]
            left_node = stmt.lvalues[0].node

            inst = Instance(descriptor.node, [typ])
            left_node.type = inst
示例#14
0
def _infer_type_from_left_and_inferred_right(
    api: SemanticAnalyzerPluginInterface,
    node: Var,
    left_hand_explicit_type: Optional[types.Type],
    python_type_for_type: Union[Instance, UnionType],
) -> Optional[Union[Instance, UnionType]]:
    """Validate type when a left hand annotation is present and we also
    could infer the right hand side::

        attrname: SomeType = Column(SomeDBType)

    """
    if not is_subtype(left_hand_explicit_type, python_type_for_type):
        descriptor = api.lookup("__sa_Mapped", node)

        effective_type = Instance(descriptor.node, [python_type_for_type])

        msg = ("Left hand assignment '{}: {}' not compatible "
               "with ORM mapped expression of type {}")
        util.fail(
            api,
            msg.format(
                node.name,
                format_type(left_hand_explicit_type),
                format_type(effective_type),
            ),
            node,
        )

    return left_hand_explicit_type
示例#15
0
文件: util.py 项目: nikki330/project2
def _info_for_cls(cls: ClassDef,
                  api: SemanticAnalyzerPluginInterface) -> TypeInfo:
    if cls.info is CLASSDEF_NO_INFO:
        sym = api.lookup_qualified(cls.name, cls)
        assert sym and isinstance(sym.node, TypeInfo)
        return sym.node

    return cls.info
 def for_argument(cls, semanal: SemanticAnalyzerPluginInterface,
                  argument: Argument) -> 'ResolverArgumentInfo':
     type_annotation = semanal.anal_type(
         argument.type_annotation) if argument.type_annotation else None
     return cls(
         name=argument.variable.name,
         type=type_annotation or AnyType(TypeOfAny.unannotated),
         context=argument,
     )
示例#17
0
def add_metadata_var(api: SemanticAnalyzerPluginInterface, info: TypeInfo) -> None:
    """Add .metadata attribute to a declarative base."""
    sym = api.lookup_fully_qualified_or_none('sqlalchemy.sql.schema.MetaData')
    if sym:
        assert isinstance(sym.node, TypeInfo)
        typ = Instance(sym.node, [])  # type: Type
    else:
        typ = AnyType(TypeOfAny.special_form)
    add_var_to_class('metadata', typ, info)
示例#18
0
def _get_type_for_expr(expr: Expression, api: SemanticAnalyzerPluginInterface):
    if isinstance(expr, NameExpr):
        return api.named_type(expr.name)

    if isinstance(expr, IndexExpr):
        type_ = _get_type_for_expr(expr.base, api)
        type_.args = (_get_type_for_expr(expr.index, api),)

        return type_

    raise ValueError(f"Unsupported expression f{type(expr)}")
def create_ortho_diff_class(base1: TypeInfo, base2: TypeInfo,
                            api: SemanticAnalyzerPluginInterface,
                            call_ctx: Context) -> Tuple[str, SymbolTableNode]:
    # https://github.com/dropbox/sqlalchemy-stubs/blob/55470ceab8149db983411d5c094c9fe16343c58b/sqlmypy.py#L173-L216
    cls_name = get_ortho_diff_name(base1.defn, base2.defn)
    class_def = ClassDef(cls_name, Block([]))
    class_def.fullname = api.qualified_name(cls_name)

    info = TypeInfo(SymbolTable(), class_def, api.cur_mod_id)
    class_def.info = info
    obj = api.builtin_type('builtins.object')
    info.bases = [cast(Instance, fill_typevars(b)) for b in (base1, base2)]
    try:
        calculate_mro(info)
    except MroError:
        api.fail('Unable to calculate MRO for dynamic class', call_ctx)
        info.bases = [obj]
        info.fallback_to_any = True

    return cls_name, SymbolTableNode(GDEF, info)
示例#20
0
def _type_id_for_unbound_type(type_: UnboundType, cls: ClassDef,
                              api: SemanticAnalyzerPluginInterface) -> int:
    type_id = None

    sym = api.lookup(type_.name, type_)
    if sym is not None:
        if isinstance(sym.node, TypeAlias):
            type_id = _type_id_for_named_node(sym.node.target.type)
        elif isinstance(sym.node, TypeInfo):
            type_id = _type_id_for_named_node(sym.node)

    return type_id
示例#21
0
        def apply_implementer(
            iface_arg: Expression,
            class_info: TypeInfo,
            api: SemanticAnalyzerPluginInterface,
        ) -> None:
            if not isinstance(iface_arg, RefExpr):
                api.fail("Argument to implementer should be a ref expression",
                         iface_arg)
                return
            iface_name = iface_arg.fullname
            if iface_name is None:
                # unknown interface, probably from stubless package
                return

            iface_type = iface_arg.node
            if iface_type is None:
                return
            if not isinstance(iface_type, TypeInfo):
                # Possibly an interface from unimported package, ignore
                return

            if not self._is_interface(iface_type):
                api.fail(
                    f"zope.interface.implementer accepts interface, "
                    f"not {iface_name}.",
                    iface_arg,
                )
                api.fail(
                    f"Make sure you have stubs for all packages that "
                    f"provide interfaces for {iface_name} class hierarchy.",
                    iface_arg,
                )
                return

            self._apply_interface(class_info, iface_type)
示例#22
0
文件: names.py 项目: joshis1/Python
def type_id_for_unbound_type(
        type_: UnboundType, cls: ClassDef,
        api: SemanticAnalyzerPluginInterface) -> Optional[int]:
    sym = api.lookup_qualified(type_.name, type_)
    if sym is not None:
        if isinstance(sym.node, TypeAlias):
            target_type = get_proper_type(sym.node.target)
            if isinstance(target_type, Instance):
                return type_id_for_named_node(target_type.type)
        elif isinstance(sym.node, TypeInfo):
            return type_id_for_named_node(sym.node)

    return None
示例#23
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,
) -> None:
    """Adds a new method to a class definition.
    """
    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)
    function_type = api.named_type('__builtins__.function')

    args = [Argument(Var('self'), 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._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]

    info.names[name] = SymbolTableNode(MDEF, func, plugin_generated=True)
    info.defn.defs.body.append(func)
示例#24
0
    def _adjust_interface_function(
        self,
        api: SemanticAnalyzerPluginInterface,
        class_info: TypeInfo,
        func_def: FuncDef,
    ) -> Statement:

        if func_def.arg_names and func_def.arg_names[0] == "self":
            # reveal the common mistake of leaving "self" arguments in the
            # interface
            api.fail("Interface methods should not have 'self' argument",
                     func_def)
        else:
            selftype = Instance(class_info, [],
                                line=class_info.line,
                                column=class_info.column)
            selfarg = Argument(Var("self", None), selftype, None, ARG_POS)

            if isinstance(func_def.type, CallableType):
                func_def.type.arg_names.insert(0, "self")
                func_def.type.arg_kinds.insert(0, ARG_POS)
                func_def.type.arg_types.insert(0, selftype)
            func_def.arg_names.insert(0, "self")
            func_def.arg_kinds.insert(0, ARG_POS)
            func_def.arguments.insert(0, selfarg)

        func_def.is_abstract = True
        if func_def.name() in ("__getattr__", "__getattribute__"):
            # These special methods cannot be decorated. Likely a mypy bug.
            return func_def
        func_def.is_decorated = True
        var = Var(func_def.name(), func_def.type)
        var.is_initialized_in_class = True
        var.info = func_def.info
        var.set_line(func_def.line)
        decor = Decorator(func_def, [], var)
        return decor
示例#25
0
def _apply_placeholder_attr_to_class(
    api: SemanticAnalyzerPluginInterface,
    cls: ClassDef,
    qualified_name: str,
    attrname: str,
):
    sym = api.lookup_fully_qualified_or_none(qualified_name)
    if sym:
        assert isinstance(sym.node, TypeInfo)
        type_ = Instance(sym.node, [])
    else:
        type_ = AnyType(TypeOfAny.special_form)
    var = Var(attrname)
    var.info = cls.info
    var.type = type_
    cls.info.names[attrname] = SymbolTableNode(MDEF, var)
def _get_func_def_ret_type(semanal: SemanticAnalyzerPluginInterface,
                           funcdef: FuncDef) -> Type:
    """
    Given a `FuncDef`, return its return-type (or `Any`)
    """

    ret_type = None
    type_ = funcdef.type

    if isinstance(type_, CallableType):
        ret_type = type_.ret_type

    if isinstance(ret_type, UnboundType):
        ret_type = semanal.anal_type(ret_type)

    return ret_type or AnyType(TypeOfAny.unannotated)
示例#27
0
def _unbound_to_instance(
    api: SemanticAnalyzerPluginInterface, typ: Type
) -> Type:
    """Take the UnboundType that we seem to get as the ret_type from a FuncDef
    and convert it into an Instance/TypeInfo kind of structure that seems
    to work as the left-hand type of an AssignmentStatement.

    """

    if not isinstance(typ, UnboundType):
        return typ

    # TODO: figure out a more robust way to check this.  The node is some
    # kind of _SpecialForm, there's a typing.Optional that's _SpecialForm,
    # but I cant figure out how to get them to match up
    if typ.name == "Optional":
        # convert from "Optional?" to the more familiar
        # UnionType[..., NoneType()]
        return _unbound_to_instance(
            api,
            UnionType(
                [_unbound_to_instance(api, typ_arg) for typ_arg in typ.args]
                + [NoneType()]
            ),
        )

    node = api.lookup_qualified(typ.name, typ)

    if (
        node is not None
        and isinstance(node, SymbolTableNode)
        and isinstance(node.node, TypeInfo)
    ):
        bound_type = node.node

        return Instance(
            bound_type,
            [
                _unbound_to_instance(api, arg)
                if isinstance(arg, UnboundType)
                else arg
                for arg in typ.args
            ],
        )
    else:
        return typ
示例#28
0
        def apply_interface(
            iface_arg: Expression,
            class_info: TypeInfo,
            api: SemanticAnalyzerPluginInterface,
            context: Context,
        ) -> None:
            if not isinstance(iface_arg, RefExpr):
                api.fail("Argument to implementer should be a ref expression",
                         iface_arg)
                return
            iface_name = iface_arg.fullname
            if iface_name is None:
                # unknown interface, probably from stubless package
                return

            iface_type = iface_arg.node
            if iface_type is None:
                return
            if not isinstance(iface_type, TypeInfo):
                # Possibly an interface from unimported package, ignore
                return

            if not self._is_interface(iface_type):
                api.fail(
                    f"zope.interface.implementer accepts interface, "
                    f"not {iface_name}.",
                    iface_arg,
                )
                api.fail(
                    f"Make sure you have stubs for all packages that "
                    f"provide interfaces for {iface_name} class hierarchy.",
                    iface_arg,
                )
                return

            # print("CLASS INFO", class_info)
            md = self._get_metadata(class_info)
            if "implements" not in md:
                md["implements"] = []
            # impl_list = cast(List[str], md['implements'])
            md["implements"].append(iface_type.fullname)
            self.log(f"Found implementation of "
                     f"{iface_type.fullname}: {class_info.fullname}")

            # Make sure implementation is treated as a subtype of an interface. Pretend
            # there is a decorator for the class that will create a "type promotion",
            # but ensure this only gets applied a single time per interface.
            promote = Instance(iface_type, [])
            if not any(ti._promote == promote for ti in class_info.mro):
                faketi = TypeInfo(SymbolTable(), iface_type.defn,
                                  iface_type.module_name)
                faketi._promote = promote
                class_info.mro.append(faketi)
示例#29
0
def _make_declarative_meta(api: SemanticAnalyzerPluginInterface,
                           target_cls: ClassDef):

    declarative_meta_name: NameExpr = NameExpr("__sa_DeclarativeMeta")
    declarative_meta_name.kind = GDEF
    declarative_meta_name.fullname = "sqlalchemy.orm.decl_api.DeclarativeMeta"

    # installed by _add_globals
    sym = api.lookup("__sa_DeclarativeMeta", target_cls)

    declarative_meta_typeinfo = sym.node
    declarative_meta_name.node = declarative_meta_typeinfo

    target_cls.metaclass = declarative_meta_name

    declarative_meta_instance = Instance(declarative_meta_typeinfo, [])

    info = target_cls.info
    info.declared_metaclass = info.metaclass_type = declarative_meta_instance
def resolve_nameexpr(
        expr: Expression,
        api: SemanticAnalyzerPluginInterface) -> Optional[SymbolTableNode]:
    if not isinstance(expr, NameExpr):
        api.fail('Cannot resolve this, please use a simple name',
                 expr,
                 code=MISC)
        return None
    try:
        return api.lookup_qualified(expr.name, ctx=expr)
    except KeyError:
        if api.final_iteration:
            api.fail('Cannot resolve this, please use a simple name',
                     expr,
                     code=MISC)
            return None
        api.defer()
        return None