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_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_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 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)
def visit_Str(self, n: ast3.Str) -> Union[UnicodeExpr, StrExpr]: # Hack: assume all string literals in Python 2 stubs are normal # strs (i.e. not unicode). All stubs are parsed with the Python 3 # parser, which causes unprefixed string literals to be interpreted # as unicode instead of bytes. This hack is generally okay, # because mypy considers str literals to be compatible with # unicode. return StrExpr(n.s)
def visit_Bytes(self, n: ast35.Bytes) -> Node: # The following line is a bit hacky, but is the best way to maintain # compatibility with how mypy currently parses the contents of bytes literals. contents = str(n.s)[2:-1] if self.pyversion[0] >= 3: return BytesExpr(contents) else: return StrExpr(contents)
def check_specs_in_format_call(self, call: CallExpr, specs: List[ConversionSpecifier], format_value: str) -> None: """Perform pairwise checks for conversion specifiers vs their replacements. The core logic for format checking is implemented in this method. """ assert all(s.key for s in specs), "Keys must be auto-generated first!" replacements = self.find_replacements_in_call(call, [cast(str, s.key) for s in specs]) assert len(replacements) == len(specs) for spec, repl in zip(specs, replacements): repl = self.apply_field_accessors(spec, repl, ctx=call) actual_type = repl.type if isinstance(repl, TempNode) else self.chk.type_map.get(repl) assert actual_type is not None # Special case custom formatting. if (spec.format_spec and spec.non_standard_format_spec and # Exclude "dynamic" specifiers (i.e. containing nested formatting). not ('{' in spec.format_spec or '}' in spec.format_spec)): if (not custom_special_method(actual_type, '__format__', check_all=True) or spec.conversion): # TODO: add support for some custom specs like datetime? self.msg.fail('Unrecognized format' ' specification "{}"'.format(spec.format_spec[1:]), call, code=codes.STRING_FORMATTING) continue # Adjust expected and actual types. if not spec.type: expected_type = AnyType(TypeOfAny.special_form) # type: Optional[Type] else: assert isinstance(call.callee, MemberExpr) if isinstance(call.callee.expr, (StrExpr, UnicodeExpr)): format_str = call.callee.expr else: format_str = StrExpr(format_value) expected_type = self.conversion_type(spec.type, call, format_str, format_call=True) if spec.conversion is not None: # If the explicit conversion is given, then explicit conversion is called _first_. if spec.conversion[1] not in 'rsa': self.msg.fail('Invalid conversion type "{}",' ' must be one of "r", "s" or "a"'.format(spec.conversion[1]), call, code=codes.STRING_FORMATTING) actual_type = self.named_type('builtins.str') # Perform the checks for given types. if expected_type is None: continue a_type = get_proper_type(actual_type) actual_items = (get_proper_types(a_type.items) if isinstance(a_type, UnionType) else [a_type]) for a_type in actual_items: if custom_special_method(a_type, '__format__'): continue self.check_placeholder_type(a_type, expected_type, call) self.perform_special_format_checks(spec, call, repl, a_type, expected_type)
def visit_Str(self, s: ast27.Str) -> Expression: # Hack: assume all string literals in Python 2 stubs are normal # strs (i.e. not unicode). All stubs are parsed with the Python 3 # parser, which causes unprefixed string literals to be interpreted # as unicode instead of bytes. This hack is generally okay, # because mypy considers str literals to be compatible with # unicode. if isinstance(s.s, bytes): n = s.s # The following line is a bit hacky, but is the best way to maintain # compatibility with how mypy currently parses the contents of bytes literals. contents = str(n)[2:-1] if self.pyversion[0] >= 3: return BytesExpr(contents) else: return StrExpr(contents) else: if self.pyversion[0] >= 3 or self.is_stub: return StrExpr(s.s) else: return UnicodeExpr(s.s)
def validate_and_transform_accessors(self, temp_ast: Expression, original_repl: Expression, spec: ConversionSpecifier, ctx: Context) -> bool: """Validate and transform (in-place) format field accessors. On error, report it and return False. The transformations include replacing the dummy variable with actual replacement expression and translating any name expressions in an index into strings, so that this will work: class User(TypedDict): name: str id: int u: User '{[id]:d} -> {[name]}'.format(u) """ if not isinstance(temp_ast, (MemberExpr, IndexExpr)): self.msg.fail('Only index and member expressions are allowed in' ' format field accessors; got "{}"'.format( spec.field), ctx, code=codes.STRING_FORMATTING) return False if isinstance(temp_ast, MemberExpr): node = temp_ast.expr else: node = temp_ast.base if not isinstance(temp_ast.index, (NameExpr, IntExpr)): assert spec.key, "Call this method only after auto-generating keys!" assert spec.field self.msg.fail('Invalid index expression in format field' ' accessor "{}"'.format( spec.field[len(spec.key):]), ctx, code=codes.STRING_FORMATTING) return False if isinstance(temp_ast.index, NameExpr): temp_ast.index = StrExpr(temp_ast.index.name) if isinstance(node, NameExpr) and node.name == DUMMY_FIELD_NAME: # Replace it with the actual replacement expression. assert isinstance( temp_ast, (IndexExpr, MemberExpr)) # XXX: this is redundant if isinstance(temp_ast, IndexExpr): temp_ast.base = original_repl else: temp_ast.expr = original_repl return True node.line = ctx.line node.column = ctx.column return self.validate_and_transform_accessors( node, original_repl=original_repl, spec=spec, ctx=ctx)
def visit_Str(self, n: ast27.Str) -> Expression: # Note: typed_ast.ast27 will handled unicode_literals for us. If # n.s is of type 'bytes', we know unicode_literals was not enabled; # otherwise we know it was. # # Note that the following code is NOT run when parsing Python 2.7 stubs: # we always parse stub files (no matter what version) using the Python 3 # parser. This is also why string literals in Python 2.7 stubs are assumed # to be unicode. if isinstance(n.s, bytes): contents = bytes_to_human_readable_repr(n.s) e = StrExpr(contents, from_python_3=False) # type: Union[StrExpr, UnicodeExpr] return self.set_line(e, n) else: e = UnicodeExpr(n.s) return self.set_line(e, n)
def visit_Str(self, n: ast27.Str) -> Expression: # Hack: assume all string literals in Python 2 stubs are normal # strs (i.e. not unicode). All stubs are parsed with the Python 3 # parser, which causes unprefixed string literals to be interpreted # as unicode instead of bytes. This hack is generally okay, # because mypy considers str literals to be compatible with # unicode. if isinstance(n.s, bytes): value = n.s # The following line is a bit hacky, but is the best way to maintain # compatibility with how mypy currently parses the contents of bytes literals. contents = str(value)[2:-1] e = StrExpr(contents) # type: Union[StrExpr, UnicodeExpr] return self.set_line(e, n) else: e = UnicodeExpr(n.s) return self.set_line(e, n)
def visit_Str(self, n: ast35.Str) -> Node: return StrExpr(n.s)
def visit_str_expr(self, node: StrExpr) -> Node: return StrExpr(node.value)
def visit_Str(self, n): return StrExpr(n.s)
def visit_str_expr(self, node: StrExpr) -> StrExpr: return StrExpr(node.value, node.from_python_3)