コード例 #1
0
 def on_leave(
     self, original_node: CSTNodeT, updated_node: CSTNodeT
 ) -> Union[cst.Import, cst.ImportFrom, CSTNodeT, RemovalSentinel]:
     if isinstance(updated_node, cst.Import):
         for alias in updated_node.names:
             name = alias.name
             if isinstance(name, cst.Name) and name.value == "b":
                 return cst.RemoveFromParent()
     elif isinstance(updated_node, cst.ImportFrom):
         module = updated_node.module
         if isinstance(module, cst.Name) and module.value == "e":
             return cst.RemoveFromParent()
     return updated_node
コード例 #2
0
ファイル: deadcode.py プロジェクト: willcrichton/inliner
    def leave_Try(
            self, original_node,
            updated_node) -> Union[cst.BaseStatement, cst.RemovalSentinel]:
        for original_handler, updated_handler in zip(original_node.handlers,
                                                     updated_node.handlers):
            if self.exec_counts[original_handler.body] > 0:
                self.insert_statements_before_current(
                    updated_handler.body.body)
                super().leave_Try(original_node, updated_node)
                return cst.RemoveFromParent()

        self.insert_statements_before_current(updated_node.body.body)

        super().leave_Try(original_node, updated_node)
        return cst.RemoveFromParent()
コード例 #3
0
ファイル: refactor.py プロジェクト: furkanonder/unimport
 def leave_import_alike(
     self,
     original_node: Union[cst.Import, cst.ImportFrom],
     updated_node: Union[cst.Import, cst.ImportFrom],
 ) -> Union[cst.RemovalSentinel, cst.Import, cst.ImportFrom]:
     names_to_keep = []
     for import_alias in updated_node.names:
         if isinstance(import_alias.name, cst.Attribute):
             import_name = self.get_import_name_from_attr(
                 attr_node=import_alias.name
             )
         else:
             import_name = (import_alias.asname or import_alias).name.value
         if self.is_import_used(
             import_name, self.get_location(original_node)
         ):
             names_to_keep.append(import_alias)
     if not names_to_keep:
         return cst.RemoveFromParent()
     elif len(updated_node.names) == len(names_to_keep):
         return updated_node
     else:
         names_to_keep[-1] = names_to_keep[-1].with_changes(
             comma=cst.MaybeSentinel.DEFAULT
         )
         return updated_node.with_changes(names=names_to_keep)
コード例 #4
0
ファイル: _codemods.py プロジェクト: Zac-HD/shed
 def discard_empty_else_blocks(self, _, updated_node):
     # An `else: pass` block can always simply be discarded, and libcst ensures
     # that an Else node can only ever occur attached to an If, While, For, or Try
     # node; in each case `None` is the valid way to represent "no else block".
     if m.findall(updated_node, m.Comment()):
         return updated_node  # If there are any comments, keep the node
     return cst.RemoveFromParent()
コード例 #5
0
    def leave_ImportFrom(
            self, original_node: cst.Import, updated_node: cst.Import
    ) -> Union[cst.Import, cst.RemovalSentinel]:

        # TODO: Handle star imports?

        if original_node.module:
            mod_name = original_node.module
        elif original_node.relative:
            mod_name = cst.Name(
                importlib.util.resolve_name("." * len(original_node.relative),
                                            self.pkg_fullname))

        for alias in original_node.names:

            indirect_name = alias.asname.name if alias.asname else alias.name
            direct_name = alias.name

            indirect_ref = cst.helpers.parse_template_expression(
                self.pkg_fullname + ".{name}", name=indirect_name)

            direct_ref = cst.helpers.parse_template_expression(
                "{mod}.{name}", mod=mod_name, name=direct_name)

            indirect_ref_name = cst.helpers.get_full_name_for_node(
                indirect_ref)

            if direct_ref.deep_equals(indirect_ref):
                continue

            self.rewrites[indirect_ref_name] = direct_ref

        return cst.RemoveFromParent()
コード例 #6
0
 def leave_import_alike(
     self,
     original_node: ImportT,
     updated_node: ImportT,
 ) -> Union[cst.RemovalSentinel, ImportT]:
     names_to_keep = []
     names = cast(Sequence[cst.ImportAlias], updated_node.names)
     # already handled by leave_ImportFrom
     for column, import_alias in enumerate(names):
         if isinstance(import_alias.name, cst.Attribute):
             import_name = self.get_import_name_from_attr(
                 attr_node=import_alias.name)
         else:
             raw_import = import_alias.asname or import_alias
             raw_import_name = cst.ensure_type(raw_import.name, cst.Name)
             import_name = raw_import_name.value
         if self.is_import_used(import_name, column + 1,
                                self.get_location(original_node)):
             names_to_keep.append(import_alias)
     if not names_to_keep:
         return cst.RemoveFromParent()
     elif len(names) == len(names_to_keep):
         return updated_node
     else:
         names_to_keep[-1] = names_to_keep[-1].with_changes(
             comma=cst.MaybeSentinel.DEFAULT)
         return cast(ImportT,
                     updated_node.with_changes(names=names_to_keep))
コード例 #7
0
    def leave_ImportFrom(
        self, original_node: cst.ImportFrom, updated_node: cst.ImportFrom
    ) -> Union[cst.ImportFrom, cst.RemovalSentinel]:
        # Grab the scope for this import. If we don't have scope, we can't determine
        # whether this import is unused so it is unsafe to remove.
        scope = self.get_metadata(ScopeProvider, original_node, None)
        if scope is None:
            return updated_node

        # Make sure we have anything to do with this node.
        names = original_node.names
        if isinstance(names, cst.ImportStar):
            # This is a star import, so we won't remove it.
            return updated_node

        # Make sure we actually know the absolute module.
        module_name = get_absolute_module_for_import(
            self.context.full_module_name, updated_node
        )
        if module_name is None or module_name not in self.unused_obj_imports:
            # This node isn't on our list of todos, so let's bail.
            return updated_node
        objects_to_remove = self.unused_obj_imports[module_name]

        names_to_keep = []
        for import_alias in names:
            # Figure out if it is in our list of things to kill
            for name, alias in objects_to_remove:
                if (
                    name == import_alias.evaluated_name
                    and alias == import_alias.evaluated_alias
                ):
                    break
            else:
                # This is a keeper, we don't have it on our list.
                names_to_keep.append(import_alias)
                continue

            # Now that we know we want to remove this object, figure out if
            # there are any live references to it.
            if self._is_in_use(scope, import_alias):
                names_to_keep.append(import_alias)
                continue

        # no changes
        if names_to_keep == names:
            return updated_node

        # Now, either remove this statement or remove the imports we are
        # deleting from this statement.
        if len(names_to_keep) == 0:
            return cst.RemoveFromParent()

        if names_to_keep[-1] != names[-1]:
            # Remove trailing comma in order to not mess up import statements.
            names_to_keep = [
                *names_to_keep[:-1],
                names_to_keep[-1].with_changes(comma=cst.MaybeSentinel.DEFAULT),
            ]
        return updated_node.with_changes(names=names_to_keep)
コード例 #8
0
 def on_leave(
     self, original_node: CSTNodeT, updated_node: CSTNodeT
 ) -> Union[CSTNodeT, RemovalSentinel]:
     if isinstance(updated_node, cst.Continue):
         return cst.RemoveFromParent()
     else:
         return updated_node
コード例 #9
0
    def leave_Assign(self, original_node, updated_node):
        if m.matches(original_node, obj_new_pattern):
            var = original_node.targets[0].target.value
            if var in self.globls and id(
                    self.globls[var]) in self.objs_to_inline:
                return cst.RemoveFromParent()

        return updated_node
コード例 #10
0
 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()
コード例 #11
0
ファイル: test_replace.py プロジェクト: shannonzhu/LibCST
 def test_replace_simple_sentinel(self) -> None:
     # Verify behavior when there's a sentinel as a replacement
     original = cst.parse_module(
         "def bar(x: int, y: int) -> bool:\n    return False\n")
     replaced = cst.ensure_type(
         m.replace(original, m.Param(), cst.RemoveFromParent()),
         cst.Module).code
     self.assertEqual(replaced, "def bar() -> bool:\n    return False\n")
コード例 #12
0
ファイル: deadcode.py プロジェクト: willcrichton/inliner
 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
コード例 #13
0
 def leave_EmptyLine(
     self, original_node: libcst.EmptyLine, updated_node: libcst.EmptyLine
 ) -> Union[libcst.EmptyLine, libcst.RemovalSentinel]:
     # First, find misplaced lines.
     for tag in self.PYRE_TAGS:
         if m.matches(updated_node,
                      m.EmptyLine(comment=m.Comment(f"# pyre-{tag}"))):
             if self.in_module_header:
                 # We only want to remove this if we've already found another
                 # pyre-strict in the header (that means its duplicated). We
                 # also don't want to move the pyre-strict since its already in
                 # the header, so don't mark that we need to move.
                 self.module_header_tags[tag] += 1
                 if self.module_header_tags[tag] > 1:
                     return libcst.RemoveFromParent()
                 else:
                     return updated_node
             else:
                 # This showed up outside the module header, so move it inside
                 if self.module_header_tags[tag] < 1:
                     self.move_strict[tag] = True
                 return libcst.RemoveFromParent()
         # Now, find misnamed lines
         if m.matches(updated_node,
                      m.EmptyLine(comment=m.Comment(f"# pyre {tag}"))):
             if self.in_module_header:
                 # We only want to remove this if we've already found another
                 # pyre-strict in the header (that means its duplicated). We
                 # also don't want to move the pyre-strict since its already in
                 # the header, so don't mark that we need to move.
                 self.module_header_tags[tag] += 1
                 if self.module_header_tags[tag] > 1:
                     return libcst.RemoveFromParent()
                 else:
                     return updated_node.with_changes(
                         comment=libcst.Comment(f"# pyre-{tag}"))
             else:
                 # We found an intended pyre-strict, but its spelled wrong. So, remove it
                 # and re-add a new one in leave_Module.
                 if self.module_header_tags[tag] < 1:
                     self.move_strict[tag] = True
                 return libcst.RemoveFromParent()
     # We found a regular comment, don't care about this.
     return updated_node
コード例 #14
0
    def leave_Import(
            self, original_node: cst.Import, updated_node: cst.Import
    ) -> Union[cst.Import, cst.RemovalSentinel]:

        name_idxs_to_remove = []

        for n, alias in enumerate(original_node.names):

            if alias.asname:
                # If an `import ...` has an alias, then it simply needs to be
                # replaced, because that alias will necessarily serve as a type
                # of indirect import.

                indirect_ref = cst.helpers.parse_template_expression(
                    self.pkg_fullname + ".{name}", name=alias.asname.name)

                direct_ref = alias.name
                indirect_ref_name = cst.helpers.get_full_name_for_node(
                    indirect_ref)

                self.rewrites[indirect_ref_name] = direct_ref

                name_idxs_to_remove.append(n)
            else:
                module_fullname = cst.helpers.get_full_name_for_node(
                    alias.name)
                module_package = self.pkg_info.fullnames_to_packages[
                    module_fullname]

                if module_package == self.pkg_fullname:
                    pass
                elif module_package >= self.pkg_fullname:
                    # The imported object is in a sub-package of this package
                    # We could remove it, but that would require new `import`
                    # statements in the modules that use this direct reference.

                    # TODO: This seems like a good optional functionality to
                    # offer.
                    pass
                else:
                    # This import is for an object above this package level,
                    # but it's not an aliased import, so it can't be an
                    # indirect reference, but it could definitely be
                    # introducing some unwanted (sub-)package dependencies.
                    pass

        if name_idxs_to_remove:
            new_names = tuple(name for n, name in enumerate(updated_node.names)
                              if n not in name_idxs_to_remove)

            if not new_names:
                return cst.RemoveFromParent()

            updated_node = updated_node.with_changes(names=new_names)

        return updated_node
コード例 #15
0
ファイル: deadcode.py プロジェクト: willcrichton/inliner
    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
コード例 #16
0
ファイル: deadcode.py プロジェクト: willcrichton/inliner
    def leave_If(self, original_node, updated_node):
        then_branch_count = self.exec_counts[original_node.body]

        # If then was always taken, just return then branch
        if then_branch_count == self.block_execs[-1]:
            self.insert_statements_before_current(updated_node.body.body)
            super().leave_If(original_node, updated_node)
            return cst.RemoveFromParent()

        # If else was always taken, just return else branch
        elif updated_node.orelse is not None and then_branch_count == 0:
            self.insert_statements_before_current(
                self.reattach_comments(updated_node.orelse,
                                       list(updated_node.orelse.body.body)))
            self.dont_keep_comments()
            super().leave_If(original_node, updated_node)
            return cst.RemoveFromParent()

        return super().leave_If(original_node, updated_node)
コード例 #17
0
    def leave_If(self, original_node, updated_node):
        final_node = super().leave_If(original_node, updated_node)
        if not isinstance(final_node, cst.RemovalSentinel):
            if (final_node.orelse is not None
                    and len(final_node.orelse.body.body) == 0):
                final_node = final_node.with_changes(orelse=None)

            if len(final_node.body.body) == 0:
                return cst.RemoveFromParent()

        return final_node
コード例 #18
0
 def leave_ExtSlice(
     self, original_node: cst.ExtSlice, updated_node: cst.ExtSlice
 ) -> Union[cst.ExtSlice, cst.RemovalSentinel]:
     slc = updated_node.slice
     if isinstance(slc, cst.Index):
         val = slc.value
         if isinstance(val, cst.Name):
             if val.value == "DoNotCareSentinel":
                 # We don't support maybes in matchers.
                 return cst.RemoveFromParent()
     return updated_node
コード例 #19
0
 def leave_SubscriptElement(
     self, original_node: cst.SubscriptElement, updated_node: cst.SubscriptElement
 ) -> Union[cst.SubscriptElement, cst.RemovalSentinel]:
     slc = updated_node.slice
     if isinstance(slc, cst.Index):
         val = slc.value
         if isinstance(val, cst.Name):
             if val.value in self.values:
                 # This type matches, so out it goes
                 return cst.RemoveFromParent()
     return updated_node
コード例 #20
0
 def leave_EmptyLine(
     self, original_node: libcst.EmptyLine, updated_node: libcst.EmptyLine
 ) -> Union[libcst.EmptyLine, libcst.RemovalSentinel]:
     if updated_node.comment is None or not bool(
             self._regex_pattern.search(
                 libcst.ensure_type(updated_node.comment,
                                    libcst.Comment).value)):
         # This is a normal comment
         return updated_node
     # This is a directive comment matching our tag, so remove it.
     return libcst.RemoveFromParent()
コード例 #21
0
 def leave_StarImport(
     updated_node: cst.ImportFrom,
     imp: ImportFrom,
 ) -> Union[cst.ImportFrom, cst.RemovalSentinel]:
     if imp.suggestions:
         names_to_suggestions = [
             cst.ImportAlias(cst.Name(module)) for module in imp.suggestions
         ]
         return updated_node.with_changes(names=names_to_suggestions)
     else:
         return cst.RemoveFromParent()
コード例 #22
0
    def leave_AnnAssign(self, original_node: cst.AnnAssign,
                        updated_node: cst.AnnAssign):
        if updated_node.value is None:
            # e.g. `some_var: str`

            # these are *only* type declarations and have no runtime behavior,
            # so they should be removed entirely:
            return cst.RemoveFromParent()

        return cst.Assign(
            targets=[cst.AssignTarget(target=updated_node.target)],
            value=updated_node.value)
コード例 #23
0
 def leave_SubscriptElement(
     self, original_node: cst.SubscriptElement, updated_node: cst.SubscriptElement
 ) -> Union[cst.SubscriptElement, cst.RemovalSentinel]:
     slc = updated_node.slice
     if isinstance(slc, cst.Index):
         val = slc.value
         if isinstance(val, cst.Name):
             if "Sentinel" in val.value:
                 # We don't support maybes in matchers.
                 return cst.RemoveFromParent()
     # Simple trick to kill trailing commas
     return updated_node.with_changes(comma=cst.MaybeSentinel.DEFAULT)
コード例 #24
0
 def leave_StarImport(self, original_node, updated_node, **kwargs):
     imp = kwargs["imp"]
     if imp["modules"]:
         modules = ",".join(imp["modules"])
         names_to_suggestion = []
         for module in modules.split(","):
             names_to_suggestion.append(cst.ImportAlias(cst.Name(module)))
         return updated_node.with_changes(names=names_to_suggestion)
     else:
         if imp["module"]:
             return cst.RemoveFromParent()
     return original_node
コード例 #25
0
 def leave_import_alike(self, original_node, updated_node):
     names_to_keep = []
     for import_alias in updated_node.names:
         if isinstance(import_alias.name, cst.Attribute):
             import_name = self.get_import_name_from_attr(
                 attr_node=import_alias.name)
         else:
             import_name = (import_alias.asname or import_alias).name.value
         if self.is_import_used(import_name,
                                self.get_location(original_node)):
             names_to_keep.append(
                 import_alias.with_changes(comma=cst.MaybeSentinel.DEFAULT))
     if len(names_to_keep) == 0:
         return cst.RemoveFromParent()
     else:
         return updated_node.with_changes(names=names_to_keep)
コード例 #26
0
    def leave_Import(
        self, original_node: cst.Import, updated_node: cst.Import
    ) -> Union[cst.Import, cst.RemovalSentinel]:
        # Grab the scope for this import. If we don't have scope, we can't determine
        # whether this import is unused so it is unsafe to remove.
        scope = self.get_metadata(ScopeProvider, original_node, None)
        if scope is None:
            return updated_node

        names_to_keep = []
        for import_alias in original_node.names:
            if import_alias.evaluated_name not in self.unused_module_imports:
                # This is a keeper since we aren't removing it
                names_to_keep.append(import_alias)
                continue

            if (
                import_alias.evaluated_alias
                != self.unused_module_imports[import_alias.evaluated_name]
            ):
                # This is a keeper since the alias does not match
                # what we are looking for.
                names_to_keep.append(import_alias)
                continue

            # Now that we know we want to remove this module, figure out if
            # there are any live references to it.
            if self._is_in_use(scope, import_alias):
                names_to_keep.append(import_alias)
                continue

        # no changes
        if names_to_keep == original_node.names:
            return updated_node

        # Now, either remove this statement or remove the imports we are
        # deleting from this statement.
        if len(names_to_keep) == 0:
            return cst.RemoveFromParent()

        if names_to_keep[-1] != original_node.names[-1]:
            # Remove trailing comma in order to not mess up import statements.
            names_to_keep = [
                *names_to_keep[:-1],
                names_to_keep[-1].with_changes(comma=cst.MaybeSentinel.DEFAULT),
            ]
        return updated_node.with_changes(names=names_to_keep)
コード例 #27
0
    def leave_Import(self, original_node: cst.Import,
                     updated_node: cst.Import) -> cst.Import:

        code = self.get_metadata(cst.metadata.PositionProvider, original_node)
        new_import_alias = []
        line_no = code.start.line
        for import_alias in updated_node.names:
            if self.is_reimport(line_no, import_alias):
                continue
            new_import_alias.append(import_alias)
        if new_import_alias:
            new_import_alias[-1] = new_import_alias[-1].with_changes(
                comma=cst.MaybeSentinel.DEFAULT)
            return updated_node.with_changes(names=new_import_alias)
        if len(new_import_alias) == 0:
            return cst.RemoveFromParent()
        return updated_node
コード例 #28
0
ファイル: remove_debugger.py プロジェクト: lensvol/pytup2019
    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
コード例 #29
0
    def leave_Assign(self, original_node, updated_node):
        if any([
                m.matches(
                    updated_node,
                    m.Assign(targets=[m.AssignTarget(m.Name())],
                             value=pattern)) for pattern in self.rhs_patterns
        ]):
            var = original_node.targets[0].target
            scope = self.get_metadata(ScopeProvider, var)
            children = self._scope_children[scope]

            if len(scope.assignments[var]) == 1:
                valid_scopes = [scope] + [
                    child
                    for child in children if len(child.assignments[var]) == 0
                ]
                self.propagate(valid_scopes, var, updated_node.value)
                return cst.RemoveFromParent()

        return updated_node
コード例 #30
0
 def leave_ImportFrom(self, original_node: cst.ImportFrom,
                      updated_node: cst.ImportFrom) -> cst.ImportFrom:
     code = self.get_metadata(cst.metadata.PositionProvider, original_node)
     line_no = code.start.line
     new_import_alias = []
     if isinstance(updated_node.names, cst.ImportStar):
         # we do not handle ImportStar
         return updated_node
     for import_alias in updated_node.names:
         if self.is_reimport_from(line_no, updated_node.module,
                                  import_alias):
             continue
         new_import_alias.append(import_alias)
     if new_import_alias:
         new_import_alias[-1] = new_import_alias[-1].with_changes(
             comma=cst.MaybeSentinel.DEFAULT)
         return updated_node.with_changes(names=new_import_alias)
     if len(new_import_alias) == 0:
         return cst.RemoveFromParent()
     return updated_node