def visit_del_stmt(self, s): if isinstance(s.expr, IndexExpr): e = s.expr # Cast m = MemberExpr(e.base, '__delitem__') m.line = s.line c = CallExpr(m, [e.index], [nodes.ARG_POS], [None]) c.line = s.line return c.accept(self) else: return None # this case is handled in semantical analysis
def visit_JoinedStr(self, n: ast3.JoinedStr) -> Expression: result_expression = StrExpr('') # type: Expression for value_expr in self.translate_expr_list(n.values): string_method = MemberExpr(value_expr, '__str__') string_method.set_line(value_expr) stringified_value_expr = CallExpr(string_method, [], []) stringified_value_expr.set_line(value_expr) result_expression = OpExpr('+', result_expression, stringified_value_expr) result_expression.set_line(value_expr) return result_expression
def visit_call_expr(self, e: CallExpr) -> None: if e.analyzed: # This is not an ordinary call. e.analyzed.accept(self) return super().visit_call_expr(e) # Do no coercions if this is a call to debugging facilities. if self.is_debugging_call_expr(e): return # Get the type of the callable (type variables in the context of the # enclosing class). ctype = self.get_type(e.callee) # Add coercions for the arguments. for i in range(len(e.args)): arg_type = AnyType() # type: Type if isinstance(ctype, Callable): arg_type = ctype.arg_types[i] e.args[i] = self.coerce2(e.args[i], arg_type, self.get_type(e.args[i]), self.type_context()) # Prepend type argument values to the call as needed. if isinstance(ctype, Callable) and cast(Callable, ctype).bound_vars != []: bound_vars = (cast(Callable, ctype)).bound_vars # If this is a constructor call (target is the constructor # of a generic type or superclass __init__), include also # instance type variables. Otherwise filter them away -- # include only generic function type variables. if (not (cast(Callable, ctype)).is_type_obj() and not (isinstance(e.callee, SuperExpr) and (cast(SuperExpr, e.callee)).name == '__init__')): # Filter instance type variables; only include function tvars. bound_vars = [(id, t) for id, t in bound_vars if id < 0] args = [] # type: List[Node] for i in range(len(bound_vars)): # Compile type variables to runtime type variable expressions. tv = translate_runtime_type_vars_in_context( bound_vars[i][1], self.type_context(), self.is_java) args.append(TypeExpr(tv)) e.args = args + e.args
def make_superclass_constructor_call( self, info: TypeInfo, callee_type: Callable) -> ExpressionStmt: """Construct a statement that calls the superclass constructor. In particular, it passes any type variables arguments as needed. """ callee = SuperExpr('__init__') callee.info = info # We do not handle generic constructors. Either pass runtime # type variables from the current scope or perhaps require # explicit constructor in this case. selftype = self_type(info) # FIX overloading # FIX default args / varargs # Map self type to the superclass context. base = info.mro[1] selftype = map_instance_to_supertype(selftype, base) super_init = cast(FuncDef, base.get_method('__init__')) # Add constructor arguments. args = [] # type: List[Node] for n in range(1, callee_type.min_args): args.append(NameExpr(super_init.args[n].name())) self.tf.set_type(args[-1], callee_type.arg_types[n]) # Store callee type after stripping away the 'self' type. self.tf.set_type(callee, nodes.method_callable(callee_type)) call = CallExpr(callee, args, [nodes.ARG_POS] * len(args)) return ExpressionStmt(call)
def visit_Call(self, n: Call) -> CallExpr: arg_types: List[ast27.expr] = [] arg_kinds: List[ArgKind] = [] signature: List[Optional[str]] = [] args = n.args arg_types.extend(args) arg_kinds.extend(ARG_POS for a in args) signature.extend(None for a in args) if n.starargs is not None: arg_types.append(n.starargs) arg_kinds.append(ARG_STAR) signature.append(None) keywords = n.keywords arg_types.extend(k.value for k in keywords) arg_kinds.extend(ARG_NAMED for k in keywords) signature.extend(k.arg for k in keywords) if n.kwargs is not None: arg_types.append(n.kwargs) arg_kinds.append(ARG_STAR2) signature.append(None) e = CallExpr(self.visit(n.func), self.translate_expr_list(arg_types), arg_kinds, signature) return self.set_line(e, n)
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"], )
def visit_Call(self, n: ast27.Call) -> CallExpr: arg_types = [] # type: List[ast27.expr] arg_kinds = [] # type: List[int] signature = [] # type: List[Optional[str]] arg_types.extend(n.args) arg_kinds.extend(ARG_POS for a in n.args) signature.extend(None for a in n.args) if n.starargs is not None: arg_types.append(n.starargs) arg_kinds.append(ARG_STAR) signature.append(None) arg_types.extend(k.value for k in n.keywords) arg_kinds.extend(ARG_NAMED for k in n.keywords) signature.extend(k.arg for k in n.keywords) if n.kwargs is not None: arg_types.append(n.kwargs) arg_kinds.append(ARG_STAR2) signature.append(None) return CallExpr(self.visit(n.func), self.translate_expr_list(arg_types), arg_kinds, signature)
def expr_to_mapped_constructor(expr: Expression) -> CallExpr: column_descriptor = NameExpr("__sa_Mapped") column_descriptor.fullname = "sqlalchemy.orm.attributes.Mapped" member_expr = MemberExpr(column_descriptor, "_empty_constructor") return CallExpr( member_expr, [expr], [ARG_POS], ["arg1"], )
def expr_to_mapped_constructor(expr: Expression) -> CallExpr: column_descriptor = NameExpr("__sa_Mapped") column_descriptor.fullname = NAMED_TYPE_SQLA_MAPPED member_expr = MemberExpr(column_descriptor, "_empty_constructor") return CallExpr( member_expr, [expr], [ARG_POS], ["arg1"], )
def visit_JoinedStr(self, n: ast3.JoinedStr) -> Expression: arg_count = len(n.values) format_string = StrExpr('{}' * arg_count) format_string.set_line(n.lineno, n.col_offset) format_method = MemberExpr(format_string, 'format') format_method.set_line(format_string) format_args = self.translate_expr_list(n.values) format_arg_kinds = [ARG_POS] * arg_count result_expression = CallExpr(format_method, format_args, format_arg_kinds) return result_expression
def visit_JoinedStr(self, n: ast3.JoinedStr) -> Expression: # Each of n.values is a str or FormattedValue; we just concatenate # them all using ''.join. empty_string = StrExpr('') empty_string.set_line(n.lineno, n.col_offset) strs_to_join = ListExpr(self.translate_expr_list(n.values)) strs_to_join.set_line(empty_string) join_method = MemberExpr(empty_string, 'join') join_method.set_line(empty_string) result_expression = CallExpr(join_method, [strs_to_join], [ARG_POS], [None]) return result_expression
def visit_FormattedValue(self, n: ast3.FormattedValue) -> Expression: # A FormattedValue is a component of a JoinedStr, or it can exist # on its own. We translate them to individual '{}'.format(value) # calls -- we don't bother with the conversion/format_spec fields. exp = self.visit(n.value) exp.set_line(n.lineno, n.col_offset) format_string = StrExpr('{}') format_string.set_line(n.lineno, n.col_offset) format_method = MemberExpr(format_string, 'format') format_method.set_line(format_string) result_expression = CallExpr(format_method, [exp], [ARG_POS]) return result_expression
def visit_Call(self, n: ast35.Call) -> Node: def is_star2arg(k): return k.arg is None arg_types = self.visit_list( [a.value if isinstance(a, ast35.Starred) else a for a in n.args] + [k.value for k in n.keywords]) arg_kinds = ([ARG_STAR if isinstance(a, ast35.Starred) else ARG_POS for a in n.args] + [ARG_STAR2 if is_star2arg(k) else ARG_NAMED for k in n.keywords]) return CallExpr(self.visit(n.func), arg_types, arg_kinds, cast("List[str]", [None for _ in n.args]) + [k.arg for k in n.keywords])
def visit_Call(self, n: ast3.Call) -> CallExpr: def is_star2arg(k: ast3.keyword) -> bool: return k.arg is None arg_types = self.translate_expr_list( [a.value if isinstance(a, ast3.Starred) else a for a in n.args] + [k.value for k in n.keywords]) arg_kinds = ([ARG_STAR if isinstance(a, ast3.Starred) else ARG_POS for a in n.args] + [ARG_STAR2 if is_star2arg(k) else ARG_NAMED for k in n.keywords]) return CallExpr(self.visit(n.func), arg_types, arg_kinds, cast("List[str]", [None] * len(n.args)) + [k.arg for k in n.keywords])
def _check_str_format_call( log_msg_expr: t.Union[StrExpr, NameExpr], ctx: MethodContext, ) -> None: """ Taps into mypy to typecheck something like this: ```py logger.debug('The bar is "{my_foo.bar}"', my_foo=foo) ``` as if it was written like this: ```py logger.debug('The bar is "{my_foo.bar}"'.format(my_foo=foo)) ``` """ call_expr = CallExpr( callee=MemberExpr(expr=log_msg_expr, name='format'), args=ctx.args[1] + ctx.args[2], arg_kinds=ctx.arg_kinds[1] + ctx.arg_kinds[2], arg_names=ctx.arg_names[1] + ctx.arg_names[2], ) call_expr.set_line(log_msg_expr) # WARNING: `ctx.api` *is* technically a `mypy.checker.TypeChecker` so the cast is # safe to make, however, mypy says this should be an implementation detail. # So, anything that's not part of the `CheckerPluginInterface` should be expected to # change. See https://github.com/python/mypy/issues/6617 try: type_checker = t.cast(TypeChecker, ctx.api) type_checker.expr_checker.visit_call_expr(call_expr) except AttributeError: ctx.api.msg.fail( ("AttributeError when trying to access mypy's functionality. " 'This could mean you are trying to use incompatible versions ' 'of mypy and loguru-mypy.'), context=log_msg_expr, )
def visit_Call(self, n: Call) -> CallExpr: args = n.args keywords = n.keywords keyword_names = [k.arg for k in keywords] arg_types = self.translate_expr_list( [a.value if isinstance(a, Starred) else a for a in args] + [k.value for k in keywords]) arg_kinds = ( [ARG_STAR if type(a) is Starred else ARG_POS for a in args] + [ARG_STAR2 if arg is None else ARG_NAMED for arg in keyword_names]) e = CallExpr( self.visit(n.func), arg_types, arg_kinds, cast('List[Optional[str]]', [None] * len(args)) + keyword_names) return self.set_line(e, n)
def make_generic_wrapper_init(self, info: TypeInfo) -> FuncDef: """Build constructor of a generic wrapper class.""" nslots = num_slots(info) cdefs = [] # type: List[Node] # Build superclass constructor call. base = info.mro[1] if base.fullname() != 'builtins.object' and self.tf.is_java: s = SuperExpr('__init__') cargs = [NameExpr('__o')] # type: List[Node] for n in range(num_slots(base)): cargs.append(NameExpr(tvar_arg_name(n + 1))) for n in range(num_slots(base)): cargs.append(NameExpr(tvar_arg_name(n + 1, BOUND_VAR))) c = CallExpr(s, cargs, [nodes.ARG_POS] * len(cargs)) cdefs.append(ExpressionStmt(c)) # Create initialization of the wrapped object. cdefs.append(AssignmentStmt([MemberExpr( self_expr(), self.object_member_name(info), direct=True)], NameExpr('__o'))) # Build constructor arguments. args = [Var('self'), Var('__o')] init = [None, None] # type: List[Node] for alt in [False, BOUND_VAR]: for n in range(nslots): args.append(Var(tvar_arg_name(n + 1, alt))) init.append(None) nargs = nslots * 2 + 2 fdef = FuncDef('__init__', args, [nodes.ARG_POS] * nargs, init, Block(cdefs), Callable( [AnyType()] * nargs, [nodes.ARG_POS] * nargs, [None] * nargs, Void(), is_type_obj=False)) fdef.info = info self.make_wrapper_slot_initializer(fdef) return fdef
def visit_Call(self, n): def is_stararg(a): return isinstance(a, typed_ast.Starred) def is_star2arg(k): return k.arg is None arg_types = self.visit( [a.value if is_stararg(a) else a for a in n.args] + [k.value for k in n.keywords]) arg_kinds = ( [ARG_STAR if is_stararg(a) else ARG_POS for a in n.args] + [ARG_STAR2 if is_star2arg(k) else ARG_NAMED for k in n.keywords]) return CallExpr(self.visit(n.func), arg_types, arg_kinds, [None for _ in n.args] + [k.arg for k in n.keywords])
def call_wrapper(self, fdef: FuncDef, is_dynamic: bool, is_wrapper_class: bool, target_ann: Callable, cur_ann: Callable, target_suffix: str, bound_sig: Callable) -> Node: """Return the body of wrapper method. The body contains only a call to the wrapped method and a return statement (if the call returns a value). Arguments are coerced to the target signature. """ args = self.call_args(fdef.args, target_ann, cur_ann, is_dynamic, is_wrapper_class, bound_sig, ismethod=fdef.is_method()) selfarg = args[0] args = args[1:] member = fdef.name() + target_suffix if not is_wrapper_class: callee = MemberExpr(selfarg, member) else: callee = MemberExpr( MemberExpr(self_expr(), self.tf.object_member_name()), member) call = CallExpr(callee, args, [nodes.ARG_POS] * len(args), [None] * len(args)) # type: Node if bound_sig: call = self.tf.coerce(call, bound_sig.ret_type, target_ann.ret_type, self.tf.type_context(), is_wrapper_class) call = self.tf.coerce(call, cur_ann.ret_type, bound_sig.ret_type, self.tf.type_context(), is_wrapper_class) else: call = self.tf.coerce(call, cur_ann.ret_type, target_ann.ret_type, self.tf.type_context(), is_wrapper_class) if not isinstance(target_ann.ret_type, Void): return ReturnStmt(call) else: return ExpressionStmt(call)
def make_type_object_wrapper(self, tdef: ClassDef) -> FuncDef: """Construct dynamically typed wrapper function for a class. It simple calls the type object and returns the result. """ # TODO keyword args, default args and varargs # TODO overloads type_sig = cast(Callable, type_object_type(tdef.info, None)) type_sig = cast(Callable, erasetype.erase_typevars(type_sig)) init = cast(FuncDef, tdef.info.get_method('__init__')) arg_kinds = type_sig.arg_kinds # The wrapper function has a dynamically typed signature. wrapper_sig = Callable( [AnyType()] * len(arg_kinds), arg_kinds, [None] * len(arg_kinds), AnyType(), False) n = NameExpr(tdef.name) # TODO full name args = self.func_tf.call_args( init.args[1:], type_sig, wrapper_sig, True, False) call = CallExpr(n, args, arg_kinds) ret = ReturnStmt(call) fdef = FuncDef(tdef.name + self.tf.dynamic_suffix(), init.args[1:], arg_kinds, [None] * len(arg_kinds), Block([ret])) fdef.type = wrapper_sig return fdef
def visit_call_expr(self, node: CallExpr) -> None: super().visit_call_expr(node) if isinstance(node.analyzed, SymbolNode): node.analyzed = self.fixup(node.analyzed)
def store_namedtuple_info(self, info: TypeInfo, name: str, call: CallExpr, is_typed: bool) -> None: self.api.add_symbol(name, info, call) call.analyzed = NamedTupleExpr(info, is_typed=is_typed) call.analyzed.set_line(call.line, call.column)
def _scan_declarative_decorator_stmt( cls: ClassDef, api: SemanticAnalyzerPluginInterface, stmt: Decorator, cls_metadata: util.DeclClassApplied, ) -> None: """Extract mapping information from a @declared_attr in a declarative class. E.g.:: @reg.mapped class MyClass: # ... @declared_attr def updated_at(cls) -> Column[DateTime]: return Column(DateTime) Will resolve in mypy as:: @reg.mapped class MyClass: # ... updated_at: Mapped[Optional[datetime.datetime]] """ for dec in stmt.decorators: if ( isinstance(dec, (NameExpr, MemberExpr, SymbolNode)) and names._type_id_for_named_node(dec) is names.DECLARED_ATTR ): break else: return dec_index = cls.defs.body.index(stmt) left_hand_explicit_type: Optional[ProperType] = None if isinstance(stmt.func.type, CallableType): func_type = stmt.func.type.ret_type if isinstance(func_type, UnboundType): type_id = names._type_id_for_unbound_type(func_type, cls, api) else: # this does not seem to occur unless the type argument is # incorrect return if ( type_id in { names.MAPPED, names.RELATIONSHIP, names.COMPOSITE_PROPERTY, names.MAPPER_PROPERTY, names.SYNONYM_PROPERTY, names.COLUMN_PROPERTY, } and func_type.args ): left_hand_explicit_type = get_proper_type(func_type.args[0]) elif type_id is names.COLUMN and func_type.args: typeengine_arg = func_type.args[0] if isinstance(typeengine_arg, UnboundType): sym = api.lookup_qualified(typeengine_arg.name, typeengine_arg) if sym is not None and isinstance(sym.node, TypeInfo): if names._has_base_type_id(sym.node, names.TYPEENGINE): left_hand_explicit_type = UnionType( [ infer._extract_python_type_from_typeengine( api, sym.node, [] ), NoneType(), ] ) else: util.fail( api, "Column type should be a TypeEngine " "subclass not '{}'".format(sym.node.fullname), func_type, ) if left_hand_explicit_type is None: # no type on the decorated function. our option here is to # dig into the function body and get the return type, but they # should just have an annotation. msg = ( "Can't infer type from @declared_attr on function '{}'; " "please specify a return type from this function that is " "one of: Mapped[<python type>], relationship[<target class>], " "Column[<TypeEngine>], MapperProperty[<python type>]" ) util.fail(api, msg.format(stmt.var.name), stmt) left_hand_explicit_type = AnyType(TypeOfAny.special_form) left_node = NameExpr(stmt.var.name) left_node.node = stmt.var # totally feeling around in the dark here as I don't totally understand # the significance of UnboundType. It seems to be something that is # not going to do what's expected when it is applied as the type of # an AssignmentStatement. So do a feeling-around-in-the-dark version # of converting it to the regular Instance/TypeInfo/UnionType structures # we see everywhere else. if isinstance(left_hand_explicit_type, UnboundType): left_hand_explicit_type = get_proper_type( util._unbound_to_instance(api, left_hand_explicit_type) ) left_node.node.type = api.named_type( "__sa_Mapped", [left_hand_explicit_type] ) # this will ignore the rvalue entirely # rvalue = TempNode(AnyType(TypeOfAny.special_form)) # rewrite the node as: # <attr> : Mapped[<typ>] = # _sa_Mapped._empty_constructor(lambda: <function body>) # the function body is maintained so it gets type checked internally column_descriptor = nodes.NameExpr("__sa_Mapped") column_descriptor.fullname = "sqlalchemy.orm.attributes.Mapped" mm = nodes.MemberExpr(column_descriptor, "_empty_constructor") arg = nodes.LambdaExpr(stmt.func.arguments, stmt.func.body) rvalue = CallExpr( mm, [arg], [nodes.ARG_POS], ["arg1"], ) new_stmt = AssignmentStmt([left_node], rvalue) new_stmt.type = left_node.node.type cls_metadata.mapped_attr_names.append( (left_node.name, left_hand_explicit_type) ) cls.defs.body[dec_index] = new_stmt
def visit_call_expr(self, node: CallExpr) -> Node: return CallExpr(self.node(node.callee), self.nodes(node.args), node.arg_kinds[:], node.arg_names[:], self.optional_node(node.analyzed))
def visit_call_expr(self, node: CallExpr) -> None: node.analyzed = None super().visit_call_expr(node)
def store_namedtuple_info(self, info: TypeInfo, name: str, call: CallExpr, is_typed: bool) -> None: stnode = SymbolTableNode(GDEF, info) self.api.add_symbol_table_node(name, stnode) call.analyzed = NamedTupleExpr(info, is_typed=is_typed) call.analyzed.set_line(call.line, call.column)
def visit_call_expr(self, node: CallExpr) -> CallExpr: return CallExpr(self.expr(node.callee), self.expressions(node.args), node.arg_kinds[:], node.arg_names[:], self.optional_expr(node.analyzed))