class RemoveBarTransformer(VisitorBasedCodemodCommand):

            METADATA_DEPENDENCIES = (QualifiedNameProvider, ScopeProvider)

            @m.leave(
                m.SimpleStatementLine(body=[
                    m.Expr(
                        m.Call(metadata=m.MatchMetadata(
                            QualifiedNameProvider,
                            {
                                QualifiedName(
                                    source=QualifiedNameSource.IMPORT,
                                    name="foo.bar",
                                )
                            },
                        )))
                ]))
            def _leave_foo_bar(
                self,
                original_node: cst.SimpleStatementLine,
                updated_node: cst.SimpleStatementLine,
            ) -> cst.RemovalSentinel:
                RemoveImportsVisitor.remove_unused_import_by_node(
                    self.context, original_node)
                return cst.RemoveFromParent()
Exemple #2
0
 def leave_Expr(self, original_node, updated_node):
     final_node = super().leave_Expr(original_node, updated_node)
     if is_pure(final_node.value):
         if m.matches(final_node, m.Expr(m.SimpleString())):
             s = final_node.value.value
             if s.startswith('"""'):
                 return final_node
         return cst.RemoveFromParent()
     return final_node
 def leave_Expr(
     self, original_node: cst.Expr, updated_node: cst.Expr
 ) -> Union[cst.BaseSmallStatement, cst.RemovalSentinel]:
     if match.matches(original_node,
                      match.Expr(value=match.SimpleString())):
         return updated_node.with_changes(value=cst.SimpleString(
             value='"""[docstring]"""'))
     else:
         return updated_node
Exemple #4
0
    def on_leave(self, original_node, updated_node):
        final_node = super().on_leave(original_node, updated_node)

        if (isinstance(final_node, cst.BaseStatement) and not m.matches(
                final_node,
                m.SimpleStatementLine(body=[m.Expr(m.SimpleString())]))
                and self.exec_counts[original_node] == 0):
            return cst.RemoveFromParent()

        return final_node
Exemple #5
0
 def leave_Expr(self, original_node, updated_node):
     if m.matches(updated_node, m.Expr(m.SimpleString())):
         s = updated_node.value.value
         if s.startswith('"""'):
             lines = s[3:-3].splitlines()
             final = ''
             for line in lines:
                 if line.strip() != '':
                     final = line
                     break
             return updated_node.with_changes(
                 value=cst.SimpleString(f'"""{final}"""'))
     return updated_node
    def _split_module(
        self, orig_module: libcst.Module, updated_module: libcst.Module
    ) -> Tuple[List[Union[libcst.SimpleStatementLine,
                          libcst.BaseCompoundStatement]],
               List[Union[libcst.SimpleStatementLine,
                          libcst.BaseCompoundStatement]], List[Union[
                              libcst.SimpleStatementLine,
                              libcst.BaseCompoundStatement]], ]:
        statement_before_import_location = 0
        import_add_location = 0

        # never insert an import before initial __strict__ flag
        if m.matches(
                orig_module,
                m.Module(body=[
                    m.SimpleStatementLine(body=[
                        m.Assign(targets=[
                            m.AssignTarget(target=m.Name("__strict__"))
                        ])
                    ]),
                    m.ZeroOrMore(),
                ]),
        ):
            statement_before_import_location = import_add_location = 1

        # This works under the principle that while we might modify node contents,
        # we have yet to modify the number of statements. So we can match on the
        # original tree but break up the statements of the modified tree. If we
        # change this assumption in this visitor, we will have to change this code.
        for i, statement in enumerate(orig_module.body):
            if m.matches(
                    statement,
                    m.SimpleStatementLine(
                        body=[m.Expr(value=m.SimpleString())])):
                statement_before_import_location = import_add_location = 1
            elif isinstance(statement, libcst.SimpleStatementLine):
                for possible_import in statement.body:
                    for last_import in self.all_imports:
                        if possible_import is last_import:
                            import_add_location = i + 1
                            break

        return (
            list(updated_module.body[:statement_before_import_location]),
            list(updated_module.
                 body[statement_before_import_location:import_add_location]),
            list(updated_module.body[import_add_location:]),
        )
Exemple #7
0
    def leave_Expr(
            self, original_node: "Expr", updated_node: "Expr"
    ) -> Union["BaseSmallStatement", RemovalSentinel]:
        # FIXME: For some strange reason if we put that matcher combination
        # into m.call_if_inside() (or others), then it will get triggered on
        # _every_ function call. Not sure if bug or a feature :/
        if m.matches(
                original_node,
                m.Expr(value=m.Call(func=m.OneOf(
                    m.Attribute(
                        value=m.OneOf(m.Name(value="pdb"), m.Name(
                            value="ipdb")),
                        attr=m.Name(value="set_trace"),
                    ),
                    m.Name("breakpoint"),
                ))),
        ):
            return cst.RemoveFromParent()

        return original_node
Exemple #8
0
 def _is_awaitable_callable(annotation: str) -> bool:
     if not (annotation.startswith("typing.Callable")
             or annotation.startswith("typing.ClassMethod")
             or annotation.startswith("StaticMethod")):
         # Exit early if this is not even a `typing.Callable` annotation.
         return False
     try:
         # Wrap this in a try-except since the type annotation may not be parse-able as a module.
         # If it is not parse-able, we know it's not what we are looking for anyway, so return `False`.
         parsed_ann = cst.parse_module(annotation)
     except Exception:
         return False
     # If passed annotation does not match the expected annotation structure for a `typing.Callable` with
     # typing.Coroutine as the return type, matched_callable_ann will simply be `None`.
     # The expected structure of an awaitable callable annotation from Pyre is: typing.Callable()[[...], typing.Coroutine[...]]
     matched_callable_ann: Optional[Dict[str, Union[
         Sequence[cst.CSTNode], cst.CSTNode]]] = m.extract(
             parsed_ann,
             m.Module(body=[
                 m.SimpleStatementLine(body=[
                     m.Expr(value=m.Subscript(slice=[
                         m.SubscriptElement(),
                         m.SubscriptElement(slice=m.Index(value=m.Subscript(
                             value=m.SaveMatchedNode(
                                 m.Attribute(),
                                 "base_return_type",
                             )))),
                     ], ))
                 ]),
             ]),
         )
     if (matched_callable_ann is not None
             and "base_return_type" in matched_callable_ann):
         base_return_type = get_full_name_for_node(
             cst.ensure_type(matched_callable_ann["base_return_type"],
                             cst.CSTNode))
         return (base_return_type is not None
                 and base_return_type == "typing.Coroutine")
     return False
Exemple #9
0
def is_docstring(node):
    return m.matches(
        node, m.SimpleStatementLine(body=[m.Expr(value=m.SimpleString())]))
 def leave_Expr(self, old_node, new_node):
     if m.matches(old_node, m.Expr(m.SimpleString())):
         return cst.RemovalSentinel.REMOVE
     return new_node