def leave_Call(self, original: cst.Call, updated: cst.Call) -> cst.CSTNode: try: key = original.func.attr.value kword_params = self.METHOD_TO_PARAMS[key] except (AttributeError, KeyError): # Either not a method from the API or too convoluted to be sure. return updated # If the existing code is valid, keyword args come after positional args. # Therefore, all positional args must map to the first parameters. args, kwargs = partition(lambda a: not bool(a.keyword), updated.args) if any(k.keyword.value == "request" for k in kwargs): # We've already fixed this file, don't fix it again. return updated kwargs, ctrl_kwargs = partition( lambda a: not a.keyword.value in self.CTRL_PARAMS, kwargs) args, ctrl_args = args[:len(kword_params)], args[len(kword_params):] ctrl_kwargs.extend( cst.Arg(value=a.value, keyword=cst.Name(value=ctrl)) for a, ctrl in zip(ctrl_args, self.CTRL_PARAMS)) request_arg = cst.Arg( value=cst.Dict([ cst.DictElement(cst.SimpleString("'{}'".format(name)), cst.Element(value=arg.value)) # Note: the args + kwargs looks silly, but keep in mind that # the control parameters had to be stripped out, and that # those could have been passed positionally or by keyword. for name, arg in zip(kword_params, args + kwargs) ]), keyword=cst.Name("request")) return updated.with_changes(args=[request_arg] + ctrl_kwargs)
def leave_Call(self, original_node: Call, updated_node: Call) -> BaseExpression: """ Remove the `weak` argument if present in the call. This is only changing calls with keyword arguments. """ if self.disconnect_call_matchers and m.matches( updated_node, m.OneOf(*self.disconnect_call_matchers)): updated_args = [] should_change = False last_comma = MaybeSentinel.DEFAULT # Keep all arguments except the one with the keyword `weak` (if present) for index, arg in enumerate(updated_node.args): if m.matches(arg, m.Arg(keyword=m.Name("weak"))): # An argument with the keyword `weak` was found # -> we need to rewrite the statement should_change = True else: updated_args.append(arg) last_comma = arg.comma # type: ignore if should_change: # Make sure the end of line is formatted as initially updated_args[-1] = updated_args[-1].with_changes( comma=last_comma) return updated_node.with_changes(args=updated_args) return super().leave_Call(original_node, updated_node)
def visit_Call(self, node: cst.Call) -> None: if m.matches( node, m.Call( func=m.Name("list") | m.Name("set") | m.Name("dict"), args=[m.Arg(value=m.GeneratorExp() | m.ListComp())], ), ): call_name = cst.ensure_type(node.func, cst.Name).value if m.matches(node.args[0].value, m.GeneratorExp()): exp = cst.ensure_type(node.args[0].value, cst.GeneratorExp) message_formatter = UNNECESSARY_GENERATOR else: exp = cst.ensure_type(node.args[0].value, cst.ListComp) message_formatter = UNNECESSARY_LIST_COMPREHENSION replacement = None if call_name == "list": replacement = node.deep_replace(node, cst.ListComp(elt=exp.elt, for_in=exp.for_in)) elif call_name == "set": replacement = node.deep_replace(node, cst.SetComp(elt=exp.elt, for_in=exp.for_in)) elif call_name == "dict": elt = exp.elt key = None value = None if m.matches(elt, m.Tuple(m.DoNotCare(), m.DoNotCare())): elt = cst.ensure_type(elt, cst.Tuple) key = elt.elements[0].value value = elt.elements[1].value elif m.matches(elt, m.List(m.DoNotCare(), m.DoNotCare())): elt = cst.ensure_type(elt, cst.List) key = elt.elements[0].value value = elt.elements[1].value else: # Unrecoginized form return replacement = node.deep_replace( node, # pyre-fixme[6]: Expected `BaseAssignTargetExpression` for 1st # param but got `BaseExpression`. cst.DictComp(key=key, value=value, for_in=exp.for_in), ) self.report(node, message_formatter.format(func=call_name), replacement=replacement)
def leave_Call(self, original_node: cst.Call, updated_node: cst.Call) -> cst.Call: if matchers.matches(updated_node, self.matcher): return updated_node.with_changes( func=updated_node.func.with_changes(attr=cst.Name( value="InsertColumn"))) return updated_node
def _get_async_call_replacement(self, node: cst.Call) -> Optional[cst.CSTNode]: func = node.func if m.matches(func, m.Attribute()): func = cast(cst.Attribute, func) attr_func_replacement = self._get_async_attr_replacement(func) if attr_func_replacement is not None: return node.with_changes(func=attr_func_replacement) return self._get_awaitable_replacement(node)
def leave_Call(self, original_node: Call, updated_node: Call) -> BaseExpression: if m.matches(updated_node, m.Call(func=m.Name("print"))): AddImportsVisitor.add_needed_import( self.context, "pprint", "pprint", ) return updated_node.with_changes(func=Name("pprint")) return super().leave_Call(original_node, updated_node)
def _gen_builtin_call(self, node: cst.Call) -> cst.Call: if not node.args: return node value = node.args[0].value if isinstance(value, cst.ListComp): pars: dict = {"lpar": [], "rpar": []} if len(node.args) == 1 else {} arg0 = node.args[0].with_changes( value=cst.GeneratorExp(elt=value.elt, for_in=value.for_in, **pars) ) return node.with_changes(args=(arg0, *node.args[1:])) if isinstance(value, cst.GeneratorExp): if len(node.args) == 1 and value.lpar: arg0 = node.args[0].with_changes( value=cst.GeneratorExp( elt=value.elt, for_in=value.for_in, lpar=[], rpar=[] ) ) return node.with_changes(args=(arg0, *node.args[1:])) return node
def visit_Call(self, node: cst.Call) -> None: if m.matches( node, m.Call(func=m.Attribute(value=m.Name("self"), attr=m.Name("assertEquals"))), ): new_call = node.with_deep_changes( old_node=cst.ensure_type(node.func, cst.Attribute).attr, value="assertEqual", ) self.report(node, replacement=new_call)
def datetime_replace( self, original_node: cst.Call, updated_node: cst.Call ) -> cst.Call: self._update_imports() return updated_node.with_changes( func=cst.Attribute( value=cst.Name(value="datetime"), attr=cst.Name("now") ), args=[cst.Arg(value=cst.Name(value="UTC"))], )
def leave_Call(self, original_node: cst.Call, updated_node: cst.Call) -> cst.Call: if matchers.matches(updated_node, self.call_matcher): # Update method's call updated_node = updated_node.with_changes( func=updated_node.func.with_changes(attr=cst.Name( value="AddTool"))) # Transform keywords updated_node_args = list(updated_node.args) for arg_matcher, renamed in self.args_matchers_map.items(): for i, node_arg in enumerate(updated_node.args): if matchers.matches(node_arg, arg_matcher): updated_node_args[i] = node_arg.with_changes( keyword=cst.Name(value=renamed)) updated_node = updated_node.with_changes( args=updated_node_args) return updated_node
def _set_call(self, node: cst.Call) -> Union[cst.Call, cst.Set, cst.SetComp]: if len(node.args) != 1: return node value = node.args[0].value if isinstance(value, (cst.List, cst.Tuple)): if value.elements: return cst.Set(elements=value.elements) else: return node.with_changes(args=[]) if isinstance(value, (cst.ListComp, cst.SetComp, cst.GeneratorExp)): return cst.SetComp(elt=value.elt, for_in=value.for_in) return node
def leave_Call(self, original_node: cst.Call) -> None: if self.current_classes and m.matches( original_node, m.Call( func=m.Name("super"), args=[ m.Arg(value=self._build_arg_class_matcher()), m.Arg(), ], ), ): self.report(original_node, replacement=original_node.with_changes(args=()))
def leave_Call(self, original_node: cst.Call, updated_node: cst.Call) -> cst.Call: # Migrate form deprecated method AppendItem() if matchers.matches(updated_node, self.deprecated_call_matcher): updated_node = updated_node.with_changes( func=updated_node.func.with_changes(attr=cst.Name( value="Append"))) # Update keywords if matchers.matches(updated_node, self.call_matcher): updated_node_args = list(updated_node.args) for arg_matcher, renamed in self.args_matchers_map.items(): for i, node_arg in enumerate(updated_node.args): if matchers.matches(node_arg, arg_matcher): updated_node_args[i] = node_arg.with_changes( keyword=cst.Name(value=renamed)) updated_node = updated_node.with_changes( args=updated_node_args) return updated_node
def leave_Call( self, original_node: cst.Call, updated_node: cst.Call, ) -> cst.Call: if len(updated_node.args) < self.argument_count: return updated_node else: last_arg = updated_node.args[-1] return updated_node.with_changes(args=( *updated_node.args[:-1], last_arg.with_changes(comma=cst.Comma()), ), )
def leave_Call(self, original_node: Call, updated_node: Call) -> BaseExpression: if (self.is_visiting_subclass and m.matches( updated_node, m.Call(func=m.Attribute( attr=m.Name("has_add_permission"), value=m.Call(func=m.Name("super")), )), ) and len(updated_node.args) < 2): updated_args = ( *updated_node.args, parse_arg("obj=obj"), ) return updated_node.with_changes(args=updated_args) return super().leave_Call(original_node, updated_node)
def leave_Call(self, original_node: Call, updated_node: Call) -> BaseExpression: if (is_one_to_one_field(original_node) or is_foreign_key(original_node) ) and not has_on_delete(original_node): AddImportsVisitor.add_needed_import( context=self.context, module="django.db", obj="models", ) updated_args = ( *updated_node.args, parse_arg("on_delete=models.CASCADE"), ) return updated_node.with_changes(args=updated_args) return super().leave_Call(original_node, updated_node)
def leave_Return( self, original_node: Return, updated_node: Return ) -> Union[BaseSmallStatement, RemovalSentinel]: if self.visiting_permalink_method and m.matches(updated_node.value, m.Tuple()): elem_0 = updated_node.value.elements[0] elem_1_3 = updated_node.value.elements[1:3] args = ( Arg(elem_0.value), Arg(Name("None")), *[Arg(el.value) for el in elem_1_3], ) return updated_node.with_changes( value=Call(func=Name("reverse"), args=args) ) return super().leave_Return(original_node, updated_node)
def leave_Call(self, original_node: cst.Call, updated_node: cst.Call) -> cst.BaseExpression: if original_node == self.call_node: new_args = [] for arg in updated_node.args: if isinstance(arg.keyword, cst.Name): if arg.keyword.value in self.keywords_to_change: value = self.keywords_to_change[arg.keyword.value] if value is not None: new_args.append(arg.with_changes(value=value)) # else don't append else: new_args.append(arg) else: new_args.append(arg) return updated_node.with_changes(args=new_args) return updated_node
def visit_Call(self, node: cst.Call) -> None: # This set excludes frozenset, max, min, sorted, sum, and tuple, which C407 would warn # about, because none of those functions short-circuit. if m.matches( node, m.Call(func=m.Name("all") | m.Name("any"), args=[m.Arg(value=m.ListComp())]), ): list_comp = cst.ensure_type(node.args[0].value, cst.ListComp) self.report( node, UNNECESSARY_LIST_COMPREHENSION.format( func=cst.ensure_type(node.func, cst.Name).value), replacement=node.deep_replace( list_comp, cst.GeneratorExp(elt=list_comp.elt, for_in=list_comp.for_in, lpar=[], rpar=[]), ), )
def leave_Call(self, original_node: libcst.Call, updated_node: libcst.Call) -> libcst.Call: check_types = False uses_pyre = True updated_fields = [] for field in original_node.args: name = field.keyword value = field.value if not name: continue name = name.value if name == "check_types": if isinstance(value, libcst.Name): check_types = check_types or value.value.lower() == "true" elif name == "check_types_options": if isinstance(value, libcst.SimpleString): uses_pyre = uses_pyre and "mypy" not in value.value.lower() elif name not in ["typing", "typing_options"]: updated_fields.append(field) if check_types and uses_pyre: return updated_node.with_changes(args=updated_fields) return updated_node
def build_path_call(self, pattern, other_args): """Build the `Call` node using Django 2.0's `path()` function.""" route = self.build_route(pattern) updated_args = (Arg(value=SimpleString(f"'{route}'")), *other_args) return Call(args=updated_args, func=Name("path"))
def visit_Call(self, node: cst.Call) -> None: if m.matches( node, m.Call( func=m.Name("tuple") | m.Name("list") | m.Name("set") | m.Name("dict"), args=[m.Arg(value=m.List() | m.Tuple())], ), ) or m.matches( node, m.Call(func=m.Name("tuple") | m.Name("list") | m.Name("dict"), args=[]), ): pairs_matcher = m.ZeroOrMore( m.Element(m.Tuple( elements=[m.DoNotCare(), m.DoNotCare()])) | m.Element(m.List( elements=[m.DoNotCare(), m.DoNotCare()]))) exp = cst.ensure_type(node, cst.Call) call_name = cst.ensure_type(exp.func, cst.Name).value # If this is a empty call, it's an Unnecessary Call where we rewrite the call # to literal, except set(). if not exp.args: elements = [] message_formatter = UNNCESSARY_CALL else: arg = exp.args[0].value elements = cst.ensure_type( arg, cst.List if isinstance(arg, cst.List) else cst.Tuple).elements message_formatter = UNNECESSARY_LITERAL if call_name == "tuple": new_node = cst.Tuple(elements=elements) elif call_name == "list": new_node = cst.List(elements=elements) elif call_name == "set": # set() doesn't have an equivelant literal call. If it was # matched here, it's an unnecessary literal suggestion. if len(elements) == 0: self.report( node, UNNECESSARY_LITERAL.format(func=call_name), replacement=node.deep_replace( node, cst.Call(func=cst.Name("set"))), ) return new_node = cst.Set(elements=elements) elif len(elements) == 0 or m.matches( exp.args[0].value, m.Tuple(elements=[pairs_matcher]) | m.List(elements=[pairs_matcher]), ): new_node = cst.Dict(elements=[( lambda val: cst.DictElement(val.elements[ 0].value, val.elements[1].value))(cst.ensure_type( ele.value, cst.Tuple if isinstance(ele.value, cst.Tuple ) else cst.List, )) for ele in elements]) else: # Unrecoginized form return self.report( node, message_formatter.format(func=call_name), replacement=node.deep_replace(node, new_node), )
def leave_Call(self, original_node: Call, updated_node: Call) -> BaseExpression: if m.matches(updated_node, m.Call(func=m.Name("url"))): return Call(args=updated_node.args, func=Name("re_path")) return super().leave_Call(original_node, updated_node)
def fix_not_iter(self, original_node: Call, updated_node: Call) -> BaseExpression: updated_node = Call(func=Name("list"), args=[Arg(updated_node)]) return updated_node
def fix_iter(self, original_node: Call, updated_node: Call) -> BaseExpression: attribute = ensure_type(updated_node.func, Attribute) func_name = attribute.attr dict_name = attribute.value return updated_node.with_changes(func=func_name, args=[Arg(dict_name)])
def fix_xrange(self, original_node: Call, updated_node: Call) -> BaseExpression: orig_func_name = ensure_type(updated_node.func, Name).value func_name = "range" if orig_func_name == "xrange" else "input" return updated_node.with_changes(func=Name(func_name))
def leave_Call(self, original: cst.Call, updated: cst.Call) -> cst.CSTNode: try: key = original.func.attr.value kword_params = self.METHOD_TO_PARAMS[key] except (AttributeError, KeyError): # Either not a method from the API or too convoluted to be sure. return updated # If the existing code is valid, keyword args come after positional args. # Therefore, all positional args must map to the first parameters. args, kwargs = partition(lambda a: not bool(a.keyword), updated.args) if any(k.keyword.value == "request" for k in kwargs): # We've already fixed this file, don't fix it again. return updated kwargs, ctrl_kwargs = partition( lambda a: not a.keyword.value in self.CTRL_PARAMS, kwargs) args, ctrl_args = args[:len(kword_params)], args[len(kword_params):] ctrl_kwargs.extend( cst.Arg( value=a.value, keyword=cst.Name(value=ctrl), equal=cst.AssignEqual( whitespace_before=cst.SimpleWhitespace(""), whitespace_after=cst.SimpleWhitespace(""), ), ) for a, ctrl in zip(ctrl_args, self.CTRL_PARAMS)) if self._use_keywords: new_kwargs = [ cst.Arg( value=arg.value, keyword=cst.Name(value=name), equal=cst.AssignEqual( whitespace_before=cst.SimpleWhitespace(""), whitespace_after=cst.SimpleWhitespace(""), ), ) for name, arg in zip(kword_params, args + kwargs) ] new_kwargs.extend([ cst.Arg( value=arg.value, keyword=cst.Name(value=arg.keyword.value), equal=cst.AssignEqual( whitespace_before=cst.SimpleWhitespace(""), whitespace_after=cst.SimpleWhitespace(""), ), ) for arg in ctrl_kwargs ]) return updated.with_changes(args=new_kwargs) else: request_arg = cst.Arg( value=cst.Dict([ cst.DictElement( cst.SimpleString('"{}"'.format(name)), cst.Element(value=arg.value), ) for name, arg in zip(kword_params, args + kwargs) ] + [ cst.DictElement( cst.SimpleString('"{}"'.format(arg.keyword.value)), cst.Element(value=arg.value), ) for arg in ctrl_kwargs ]), keyword=cst.Name("request"), equal=cst.AssignEqual( whitespace_before=cst.SimpleWhitespace(""), whitespace_after=cst.SimpleWhitespace(""), ), ) return updated.with_changes(args=[request_arg])