def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef) -> cst.ClassDef: new_bases: List[cst.Arg] = [] namedtuple_base: Optional[cst.Arg] = None # Need to examine the original node's bases since they are directly tied to import metadata for base_class in original_node.bases: # Compare the base class's qualified name against the expected typing.NamedTuple if not QualifiedNameProvider.has_name(self, base_class.value, self.qualified_namedtuple): # Keep all bases that are not of type typing.NamedTuple new_bases.append(base_class) else: namedtuple_base = base_class # We still want to return the updated node in case some of its children have been modified if namedtuple_base is None: return updated_node AddImportsVisitor.add_needed_import(self.context, "attr", "dataclass") AddImportsVisitor.add_needed_import(self.context, "pydantic.dataclasses", "dataclass") RemoveImportsVisitor.remove_unused_import_by_node(self.context, namedtuple_base.value) call = cst.ensure_type( cst.parse_expression("dataclass(frozen=False)", config=self.module.config_for_parsing), cst.Call, ) return updated_node.with_changes( lpar=cst.MaybeSentinel.DEFAULT, rpar=cst.MaybeSentinel.DEFAULT, bases=new_bases, decorators=[*original_node.decorators, cst.Decorator(decorator=call)], )
def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef): self.class_stack.pop() if not self.change_classes: return updated_node class_name = updated_node.name.value new_bases = [] if self.can_rename(class_name, 'c'): updated_node = self.renamed(updated_node) for base in updated_node.bases: full_name = base.value if m.matches(full_name, m.Name()): full_name = cst.ensure_type(full_name, cst.Name) if self.can_rename(full_name.value, 'c'): base = base.with_changes( value=self.get_new_cst_name(full_name.value)) elif m.matches(full_name, m.Attribute()): # TODO поддержка импортов pass else: pass new_bases.append(base) updated_node = updated_node.with_changes(bases=new_bases) return updated_node
def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef) -> cst.CSTNode: if isinstance(original_node, cst.ClassDef): print('changing') new_body = updated_node.body.with_changes( body=self._sort_nodes(updated_node.body.body)) updated_node_2 = updated_node.with_changes(body=new_body) return updated_node_2 return updated_node
def visit_ClassDef(self, node: cst.ClassDef) -> Optional[bool]: # found class def in the source # stack += [name] # annotations+= [gramps.parent.name], base classes, None, docstring self.stack.append(node.name.value) docstring = node.get_docstring(clean=False) ##todo: or possible use deep_clone op copy tree # classDef>body>identedblock>body>SimpleStatementLine>SimpleString bases = node.bases key: Tuple[str, ...] = tuple(self.stack) self.annotations[key] = (None, None, bases, docstring) print(tuple(self.stack))
def leave_ClassDef(self, original_node: cst.ClassDef) -> None: (namedtuple_base, new_bases) = self.partition_bases(original_node.bases) if namedtuple_base is not None: call = ensure_type(parse_expression("dataclass(frozen=True)"), cst.Call) replacement = original_node.with_changes( lpar=MaybeSentinel.DEFAULT, rpar=MaybeSentinel.DEFAULT, bases=new_bases, decorators=list(original_node.decorators) + [cst.Decorator(decorator=call)], ) self.report(original_node, replacement=replacement)
def visit_ClassDef(self, node: cst.ClassDef) -> None: new_bases = tuple(base for base in node.bases if not m.matches(base.value, m.Name("object"))) if tuple(node.bases) != new_bases: # reconstruct classdef, removing parens if bases and keywords are empty new_classdef = node.with_changes( bases=new_bases, lpar=cst.MaybeSentinel.DEFAULT, rpar=cst.MaybeSentinel.DEFAULT, ) # report warning and autofix self.report(node, replacement=new_classdef)
def leave_ClassDef( self, original: libcst.ClassDef, updated: libcst.ClassDef ) -> libcst.ClassDef: resulting_decorators = [] for decorator_wrapper in updated.decorators: decorator = decorator_wrapper.decorator if not m.matches( decorator, m.Attribute( value=m.Name("six"), attr=m.Name("python_2_unicode_compatible"), ), ): resulting_decorators.append(decorator_wrapper) return updated.with_changes(decorators=resulting_decorators)
def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef) -> cst.CSTNode: key = tuple(self.stack) self.stack.pop() if key in self.annotations: annotations = self.annotations[key] # # Todo: P1 add/update docstring # print(original_node.body.body[0].body[0].value.value) # docstring = cst.SimpleString('""" docstring """') return updated_node.with_changes( # add/update base class(es) bases=annotations[2]) # Todo: add/update decorators return updated_node
def visit_ClassDef(self, node: cst.ClassDef) -> None: doc_string = node.get_docstring() if not doc_string or "@sorted-attributes" not in doc_string: return found_any_assign: bool = False pre_assign_lines: List[LineType] = [] assign_lines: List[LineType] = [] post_assign_lines: List[LineType] = [] def _add_unmatched_line(line: LineType) -> None: post_assign_lines.append( line) if found_any_assign else pre_assign_lines.append(line) for line in node.body.body: if m.matches( line, m.SimpleStatementLine( body=[m.Assign(targets=[m.AssignTarget()])])): found_any_assign = True assign_lines.append(line) else: _add_unmatched_line(line) continue sorted_assign_lines = sorted( assign_lines, key=lambda line: line.body[0].targets[0].target.value) if sorted_assign_lines == assign_lines: return self.report( node, replacement=node.with_changes(body=node.body.with_changes( body=pre_assign_lines + sorted_assign_lines + post_assign_lines)), )
def leave_ClassDef( self, original_node: cst.ClassDef, updated_node: cst.ClassDef, ) -> cst.ClassDef: cls_name = ".".join(self.qualifier) self.qualifier.pop() definition = self.annotations.class_definitions.get(cls_name) if definition: b1 = _find_generic_base(definition) b2 = _find_generic_base(updated_node) if b1 and not b2: new_bases = list(updated_node.bases) + [b1] self.annotation_counts.typevars_and_generics_added += 1 return updated_node.with_changes(bases=new_bases) return updated_node
def visit_ClassDef(self, node: cst.ClassDef) -> None: self.qualifier.append(node.name.value) new_bases = [] for base in node.bases: value = base.value if isinstance(value, NAME_OR_ATTRIBUTE): new_value = self._handle_NameOrAttribute(value) elif isinstance(value, cst.Subscript): new_value = self._handle_Subscript(value) else: start = self.get_metadata(PositionProvider, node).start raise ValueError( "Invalid type used as base class in stub file at " + f"{start.line}:{start.column}. Only subscripts, names, and " + "attributes are valid base classes for static typing.") new_bases.append(base.with_changes(value=new_value)) self.class_definitions[node.name.value] = node.with_changes( bases=new_bases)