def visit_member_expr(self, node: MemberExpr) -> Node: member = MemberExpr(self.node(node.expr), node.name) if node.def_var: member.def_var = self.visit_var(node.def_var) self.copy_ref(member, node) return member
def visit_member_expr(self, node: MemberExpr) -> MemberExpr: member = MemberExpr(self.expr(node.expr), node.name) if node.def_var: # This refers to an attribute and we don't transform attributes by default, # just normal variables. member.def_var = node.def_var self.copy_ref(member, node) return member
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_member_expr(self, node: MemberExpr) -> None: self.strip_ref_expr(node) if self.is_duplicate_attribute_def(node): # This is marked as a instance variable definition but a base class # defines an attribute with the same name, and we can't have # multiple definitions for an attribute. Defer to the base class # definition. del self.type.names[node.name] node.is_def = False node.def_var = None
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: 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_member_expr(self, node: MemberExpr) -> None: self.strip_ref_expr(node) if self.is_duplicate_attribute_def(node): # This is marked as an instance variable definition but a base class # defines an attribute with the same name, and we can't have # multiple definitions for an attribute. Defer to the base class # definition. if self.type is not None: del self.type.names[node.name] node.is_inferred_def = False node.def_var = None super().visit_member_expr(node)
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_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_member_expr(self, node: MemberExpr) -> None: self.strip_ref_expr(node) # These need to cleared for member expressions but not for other RefExprs since # these can change based on changed in a base class. node.is_new_def = False node.is_inferred_def = False if self.is_duplicate_attribute_def(node): # This is marked as an instance variable definition but a base class # defines an attribute with the same name, and we can't have # multiple definitions for an attribute. Defer to the base class # definition. self.strip_class_attr(node.name) node.def_var = None super().visit_member_expr(node)
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], [None]) return result_expression
def visit_Attribute(self, n): if (isinstance(n.value, typed_ast.Call) and isinstance(n.value.func, typed_ast.Name) and n.value.func.id == 'super'): return SuperExpr(n.attr) return MemberExpr(self.visit(n.value), n.attr)
def make_setter_wrapper(self, name: str, typ: Type) -> FuncDef: """Create a setter wrapper for a data attribute. The setter will be of this form: . def set$name(self: C, name: typ) -> None: . self.name! = name """ scope = self.make_scope() selft = self.self_type() selfv = scope.add('self', selft) namev = scope.add(name, typ) lvalue = MemberExpr(scope.name_expr('self'), name, direct=True) rvalue = scope.name_expr(name) ret = AssignmentStmt([lvalue], rvalue) wrapper_name = 'set$' + name sig = Callable([selft, typ], [nodes.ARG_POS, nodes.ARG_POS], [None, None], Void(), False) fdef = FuncDef(wrapper_name, [selfv, namev], [nodes.ARG_POS, nodes.ARG_POS], [None, None], Block([ret]), sig) fdef.info = self.tf.type_context() return fdef
def visit_member_expr(self, node: MemberExpr) -> None: self.strip_ref_expr(node) # These need to cleared for member expressions but not for other RefExprs since # these can change based on changed in a base class. node.is_new_def = False node.is_inferred_def = False if self.is_duplicate_attribute_def(node): # This is marked as an instance variable definition but a base class # defines an attribute with the same name, and we can't have # multiple definitions for an attribute. Defer to the base class # definition. self.strip_class_attr(node.name) node.def_var = None if isinstance(node.node, Var): self._reset_var_final_flags(node.node) super().visit_member_expr(node)
def visit_Attribute(self, n: ast35.Attribute) -> Node: if (isinstance(n.value, ast35.Call) and isinstance(n.value.func, ast35.Name) and n.value.func.id == 'super'): return SuperExpr(n.attr) return MemberExpr(self.visit(n.value), n.attr)
def visit_Attribute(self, n: ast27.Attribute) -> Expression: if (isinstance(n.value, ast27.Call) and isinstance(n.value.func, ast27.Name) and n.value.func.id == 'super'): return SuperExpr(n.attr, self.visit(n.value)) return MemberExpr(self.visit(n.value), n.attr)
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 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 visit_Attribute(self, n: Attribute) -> Union[MemberExpr, SuperExpr]: value = n.value member_expr = MemberExpr(self.visit(value), n.attr) obj = member_expr.expr if (isinstance(obj, CallExpr) and isinstance(obj.callee, NameExpr) and obj.callee.name == 'super'): e = SuperExpr(member_expr.name, obj) # type: Union[MemberExpr, SuperExpr] else: e = member_expr return self.set_line(e, n)
def get_tvar_access_expression(typ: TypeInfo, tvindex: int, alt: Any, is_java: Any) -> RuntimeTypeVar: """Return a type expression that maps from runtime type variable slots to the type variable in the given class with the given index. For example, assuming class A(Generic[T, S]): ... and class B(A[X, Y[U]], Generic[U]): ...: get_tvar_access_expression(<B>, 1) == RuntimeTypeVar(<self.__tv2.args[0]>) (with <...> represented as nodes) """ # First get the description of how to get from supertype type variables to # a subtype type variable. mapping = get_tvar_access_path(typ, tvindex) # The type checker should have noticed if there is no mapping. Be defensive # and make sure there is one. if mapping is None: raise RuntimeError('Could not find a typevar mapping') # Build the expression for getting at the subtype type variable # progressively. # First read the value of a supertype runtime type variable slot. s = self_expr() # type: Node if alt == OBJECT_VAR: o = '__o' if is_java: o = '__o_{}'.format(typ.name) s = MemberExpr(s, o) expr = MemberExpr(s, tvar_slot_name(mapping[0] - 1, alt)) # type: Node # Then, optionally look into arguments based on the description. for i in mapping[1:]: expr = MemberExpr(expr, 'args') expr = IndexExpr(expr, IntExpr(i - 1)) # Than add a final wrapper so that we have a valid type. return RuntimeTypeVar(expr)
def visit_Attribute(self, n: Attribute) -> Expression: # First create MemberExpr and then potentially replace with a SuperExpr # to improve performance when compiled. The check for "super()" will be # faster with native AST nodes. Note also that super expressions are # less common than normal member expressions. member_expr = MemberExpr(self.visit(n.value), n.attr) obj = member_expr.expr if (isinstance(obj, CallExpr) and isinstance(obj.callee, NameExpr) and obj.callee.name == 'super'): e: Expression = SuperExpr(member_expr.name, obj) else: e = member_expr return self.set_line(e, n)
def _add_attr_access_to_module(module: MypyFile, class_info: TypeInfo, attr_name: str) -> None: """ Adds a statement that accesses a given `attr_name` of a type (specified via `class_info`) as the last statement in a `module`. """ module.defs.append( ExpressionStmt( MemberExpr( CastExpr(NameExpr('None'), Instance(class_info, [])), attr_name, )))
def make_instance_tvar_initializer(self, creat: FuncDef) -> None: """Add type variable member initialization code to a constructor. Modify the constructor body directly. """ for n in range(num_slots(creat.info)): rvalue = self.make_tvar_init_expression(creat.info, n) init = AssignmentStmt([MemberExpr(self_expr(), tvar_slot_name(n), direct=True)], rvalue) self.tf.set_type(init.lvalues[0], AnyType()) self.tf.set_type(init.rvalue, AnyType()) creat.body.body.insert(n, init)
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_member_expr(self, e: MemberExpr) -> None: super().visit_member_expr(e) typ = self.get_type(e.expr) if self.dynamic_funcs[-1]: e.expr = self.coerce_to_dynamic(e.expr, typ, self.type_context()) typ = AnyType() if isinstance(typ, Instance): # Reference to a statically-typed method variant with the suffix # derived from the base object type. suffix = self.get_member_reference_suffix(e.name, typ.type) else: # Reference to a dynamically-typed method variant. suffix = self.dynamic_suffix() e.name += suffix
def make_wrapper_slot_initializer(self, creat: FuncDef) -> None: """Add type variable member initializations to a wrapper constructor. The function must be a constructor of a generic wrapper class. Modify the constructor body directly. """ for alt in [BOUND_VAR, False]: for n in range(num_slots(creat.info)): rvalue = TypeExpr( RuntimeTypeVar(NameExpr(tvar_slot_name(n, alt)))) init = AssignmentStmt( [MemberExpr(self_expr(), tvar_slot_name(n, alt), direct=True)], rvalue) self.tf.set_type(init.lvalues[0], AnyType()) self.tf.set_type(init.rvalue, AnyType()) creat.body.body.insert(n, init)
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 make_getter_wrapper(self, name: str, typ: Type) -> FuncDef: """Create a getter wrapper for a data attribute. The getter will be of this form: . def $name*(self: C) -> type: . return self.name! """ scope = self.make_scope() selft = self.self_type() selfv = scope.add('self', selft) member_expr = MemberExpr(scope.name_expr('self'), name, direct=True) ret = ReturnStmt(member_expr) wrapper_name = '$' + name sig = Callable([selft], [nodes.ARG_POS], [None], typ, False) fdef = FuncDef(wrapper_name, [selfv], [nodes.ARG_POS], [None], Block([ret]), sig) fdef.info = self.tf.type_context() return fdef
def make_dynamic_getter_wrapper(self, name: str, typ: Type) -> FuncDef: """Create a dynamically-typed getter wrapper for a data attribute. The getter will be of this form: . def $name*(self: C) -> Any: . return {Any <= typ self.name!} """ scope = self.make_scope() selft = self.self_type() selfv = scope.add('self', selft) member_expr = MemberExpr(scope.name_expr('self'), name, direct=True) coerce_expr = coerce(member_expr, AnyType(), typ, self.tf.type_context()) ret = ReturnStmt(coerce_expr) wrapper_name = '$' + name + self.tf.dynamic_suffix() sig = Callable([selft], [nodes.ARG_POS], [None], AnyType(), False) return FuncDef(wrapper_name, [selfv], [nodes.ARG_POS], [None], Block([ret]), sig)
def make_dynamic_setter_wrapper(self, name: str, typ: Type) -> FuncDef: """Create a dynamically-typed setter wrapper for a data attribute. The setter will be of this form: . def set$name*(self: C, name; Any) -> None: . self.name! = {typ name} """ lvalue = MemberExpr(self_expr(), name, direct=True) name_expr = NameExpr(name) rvalue = coerce(name_expr, typ, AnyType(), self.tf.type_context()) ret = AssignmentStmt([lvalue], rvalue) wrapper_name = 'set$' + name + self.tf.dynamic_suffix() selft = self_type(self.tf.type_context()) sig = Callable([selft, AnyType()], [nodes.ARG_POS, nodes.ARG_POS], [None, None], Void(), False) return FuncDef(wrapper_name, [Var('self'), Var(name)], [nodes.ARG_POS, nodes.ARG_POS], [None, None], Block([ret]), sig)
def visit_member_expr(self, node: MemberExpr) -> None: if node.def_var: node.def_var = self.fixup(node.def_var) self.visit_ref_expr(node) super().visit_member_expr(node)