def leave_Name( self, original_node: cst.Name, updated_node: cst.Name) -> Union[cst.Name, cst.SimpleString]: value = updated_node.value if value == "NoneType": # This is special-cased in typing, un-special case it. return updated_node.with_changes(value="None") if value in CST_DIR and not value.endswith("Sentinel"): # If this isn't a typing define and it isn't a builtin, convert it to # a forward ref string. return cst.SimpleString(repr(value)) return updated_node
def leave_Decorator( self, original_node: Decorator, updated_node: Decorator ) -> Union[Decorator, FlattenSentinel[Decorator], RemovalSentinel]: """Update decorator call if all conditions are met.""" if self.decorators_matcher and m.matches(updated_node, self.decorators_matcher): # If we have a decorator matcher, and it matches, # then update the node with new name updated_decorator = updated_node.decorator.with_changes( attr=Name("simple_tag") ) return updated_node.with_changes(decorator=updated_decorator) return super().leave_Decorator(original_node, updated_node)
def visit_Name(self, node: libcst.Name) -> None: if self.annotation_counter > 0 and node.value in BUILTINS_TO_REPLACE: correct_type = node.value.title() scope = self.get_metadata(ScopeProvider, node) replacement = None if scope is not None and correct_type in scope: replacement = node.with_changes(value=correct_type) self.report( node, REPLACE_BUILTIN_TYPE_ANNOTATION.format( builtin_type=node.value, correct_type=correct_type ), replacement=replacement, )
def visit_Name(self, node: cst.Name) -> Optional[bool]: if (len(self.imports) > 0 or len(self.attributes) > 0 or len(self.annotations) > 0): return pos = self.get_metadata(PositionProvider, node) start = pos.start end = pos.end tup = (start.line, start.column, end.line, end.column) # remove this if condition when the type issues are fixed. if not any( node.deep_equals(name) and tup == _tup for (name, _tup) in { (cst.Name("i"), (17, 21, 17, 22)), }): self.test.assertIn( tup, self.lookup, f"Name node {node.value} at {tup} found without inferred type.", )
def leave_ImportFrom( self, original_node: ImportFrom, updated_node: ImportFrom ) -> Union[BaseSmallStatement, RemovalSentinel]: if self._test_import_from(updated_node): new_names = [] new_import_missing = True new_import_alias = None for import_alias in original_node.names: if import_alias.evaluated_name == self.old_name: new_import_alias = ImportAlias(name=Name(self.new_name)) else: if import_alias.evaluated_name == self.new_name: new_import_missing = False new_names.append(import_alias) if new_import_missing and new_import_alias is not None: new_names.append(new_import_alias) new_names = list(sorted(new_names, key=lambda n: n.evaluated_name)) return ImportFrom(module=updated_node.module, names=new_names) return super().leave_ImportFrom(original_node, updated_node)
def _check_import_from_exact( self, original_node: ImportFrom, updated_node: ImportFrom ) -> Optional[Union[BaseSmallStatement, RemovalSentinel]]: """ Check for when the thing to replace is imported exactly. When `parent.module.the_thing` is transformed, detect such import: from parent.module import the_thing """ # First, exit early if 'import *' is used if isinstance(updated_node.names, ImportStar): return None # Check whether the exact symbol is imported if not import_from_matches(updated_node, self.old_module_parts): return None # Match, update the node an return it new_import_aliases = [] for import_alias in updated_node.names: if not self.old_name or import_alias.evaluated_name == self.old_name: if import_alias.evaluated_alias is None: self.save_import_scope(original_node) self.context.scratch[self.ctx_key_name_matcher] = m.Name( self.old_name) if self.new_name: self.context.scratch[self.ctx_key_new_func] = Name( self.new_name) if self.rename_from != self.rename_to: if self.simple_rename: AddImportsVisitor.add_needed_import( context=self.context, module=".".join(self.new_module_parts), obj=self.new_name or import_alias.evaluated_name, asname=import_alias.evaluated_alias, ) continue new_import_aliases.append(import_alias) if not new_import_aliases: # Nothing left in the import statement: remove it return RemoveFromParent() # Some imports are left, update the statement new_import_aliases = clean_new_import_aliases(new_import_aliases) return updated_node.with_changes(names=new_import_aliases)
def visit_Name(self, node: libcst.Name) -> None: # Avoid a false-positive in this scenario: # # ``` # from typing import List as list # from graphene import List # ``` qualified_names = self.get_metadata(QualifiedNameProvider, node, set()) is_builtin_type = node.value in BUILTINS_TO_REPLACE and all(qualified_name.name in QUALIFIED_BUILTINS_TO_REPLACE for qualified_name in qualified_names) if self.annotation_counter > 0 and is_builtin_type: correct_type = node.value.title() scope = self.get_metadata(ScopeProvider, node) replacement = None if scope is not None and correct_type in scope: replacement = node.with_changes(value=correct_type) self.report( node, REPLACE_BUILTIN_TYPE_ANNOTATION.format(builtin_type=node.value, correct_type=correct_type), replacement=replacement, )
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_node: Call, updated_node: Call) -> BaseExpression: if self.is_entity_imported and m.matches( updated_node, m.Call(func=m.Name(self.old_name))): return Name(self.new_name) return super().leave_Call(original_node, 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 leave_Module(self, original_node: "Module", updated_node: "Module") -> "Module": if not self.names: return original_node modified_body = list(original_node.body) indented_space = ParenthesizedWhitespace( first_line=TrailingWhitespace( whitespace=SimpleWhitespace(value=""), comment=None, newline=Newline(value=None), ), empty_lines=[], indent=True, last_line=SimpleWhitespace(value=" "), ) indented_comma = Comma( whitespace_before=SimpleWhitespace(value=""), whitespace_after=indented_space, ) line_break = ParenthesizedWhitespace(first_line=TrailingWhitespace( whitespace=SimpleWhitespace(value=""), comment=None, newline=Newline(value=None), )) list_values = [ Element(SimpleString(value=f'"{global_name}"'), comma=indented_comma) for global_name in self.names[:-1] ] list_values.append( Element( SimpleString(value=f'"{self.names[-1]}"'), comma=Comma( whitespace_before=SimpleWhitespace(value=""), whitespace_after=line_break, ), )) all_names = Assign( targets=(AssignTarget(target=Name(value="__all__")), ), value=List( list_values, lbracket=LeftSquareBracket( whitespace_after=ParenthesizedWhitespace( first_line=TrailingWhitespace( whitespace=SimpleWhitespace(value=""), comment=None, newline=Newline(value=None), ), empty_lines=[], indent=True, last_line=SimpleWhitespace(value=" "), )), rbracket=RightSquareBracket(whitespace_before=SimpleWhitespace( value="")), ), ) modified_body.append(Newline()) modified_body.append(all_names) return updated_node.with_changes(body=modified_body)
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 update_call_args(self, node: Call) -> Sequence[Arg]: return (Arg(value=Name("None")), *node.args)
def update_call(self, updated_node: Call) -> BaseExpression: updated_args = self.update_call_args(updated_node) return Call(args=updated_args, func=Name(self.new_name))
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_unicode(self, original_node: Name, updated_node: Name) -> BaseExpression: value = "text_type" if value not in self.future_utils_imports: self.future_utils_new_imports.add(value) return updated_node.with_changes(value=value)
def leave_Name(self, original_node: cst.Name, updated_node: cst.Name): if re.match(r"^\$.+\$$", original_node.value): return updated_node.with_changes( value=original_node.value.replace(" ", "")) else: return original_node
def leave_Call(self, original_node: Call, updated_node: Call) -> BaseExpression: matcher = self.name_matcher if m.matches(updated_node, m.Call(func=matcher)): return Name(self.new_name) return super().leave_Call(original_node, updated_node)
def leave_Call(self, original_node: Call, updated_node: Call) -> BaseExpression: if m.matches(updated_node, m.Call(func=m.Name(self.old_name))): updated_args = self.update_call_args(updated_node) return Call(args=updated_args, func=Name(self.new_name)) return super().leave_Call(original_node, updated_node)