# Copyright 2006 Google, Inc. All Rights Reserved.# Licensed to PSF under a Contributor Agreement."""Base class for fixers (optional, but recommended)."""# Python importsimport itertools# Local importsfrom .patcomp import PatternCompilerfrom . import pygramfrom .fixer_util import does_tree_importclass BaseFix(object):"""Optional base class for fixers.The subclass name must be FixFooBar where FooBar is the result ofremoving underscores and capitalizing the words of the fix name.For example, the class name for a fixer named 'has_key' should beFixHasKey."""PATTERN = None # Most subclasses should override with a string literalpattern = None # Compiled pattern, set by compile_pattern()pattern_tree = None # Tree representation of the patternoptions = None # Options object passed to initializerfilename = None # The filename (set by set_filename)numbers = itertools.count(1) # For new_name()used_names = set() # A set of all used NAMEsorder = "post" # Does the fixer prefer pre- or post-order traversalexplicit = False # Is this ignored by refactor.py -f all?run_order = 5 # Fixers will be sorted by run order before execution# Lower numbers will be run first._accept_type = None # [Advanced and not public] This tells RefactoringTool# which node type to accept when there's not a pattern.keep_line_order = False # For the bottom matcher: match with the# original line orderBM_compatible = False # Compatibility with the bottom matching# module; every fixer should set this# manually# Shortcut for access to Python grammar symbolssyms = pygram.python_symbolsdef __init__(self, options, log):"""Initializer. Subclass may override.Args:options: a dict containing the options passed to RefactoringToolthat could be used to customize the fixer through the command line.log: a list to append warnings and other messages to."""self.options = optionsself.log = logself.compile_pattern()def compile_pattern(self):"""Compiles self.PATTERN into self.pattern.Subclass may override if it doesn't want to useself.{pattern,PATTERN} in .match()."""if self.PATTERN is not None:PC = PatternCompiler()self.pattern, self.pattern_tree = PC.compile_pattern(self.PATTERN,with_tree=True)def set_filename(self, filename):"""Set the filename.The main refactoring tool should call this."""self.filename = filenamedef match(self, node):"""Returns match for a given parse tree node.Should return a true or false object (not necessarily a bool).It may return a non-empty dict of matching sub-nodes asreturned by a matching pattern.Subclass may override."""results = {"node": node}return self.pattern.match(node, results) and resultsdef transform(self, node, results):"""Returns the transformation for a given parse tree node.Args:node: the root of the parse tree that matched the fixer.results: a dict mapping symbolic names to part of the match.Returns:None, or a node that is a modified copy of theargument node. The node argument may also be modified in-place toeffect the same change.Subclass *must* override."""raise NotImplementedError()def new_name(self, template="xxx_todo_changeme"):"""Return a string suitable for use as an identifierThe new name is guaranteed not to conflict with other identifiers."""name = templatewhile name in self.used_names:name = template + str(next(self.numbers))self.used_names.add(name)return namedef log_message(self, message):if self.first_log:self.first_log = Falseself.log.append("### In file %s ###" % self.filename)self.log.append(message)def cannot_convert(self, node, reason=None):"""Warn the user that a given chunk of code is not valid Python 3,but that it cannot be converted automatically.First argument is the top-level node for the code in question.Optional second argument is why it can't be converted."""lineno = node.get_lineno()for_output = node.clone()for_output.prefix = ""msg = "Line %d: could not convert: %s"self.log_message(msg % (lineno, for_output))if reason:self.log_message(reason)def warning(self, node, reason):"""Used for warning the user about possible uncertainty in thetranslation.First argument is the top-level node for the code in question.Optional second argument is why it can't be converted."""lineno = node.get_lineno()self.log_message("Line %d: %s" % (lineno, reason))def start_tree(self, tree, filename):"""Some fixers need to maintain tree-wide state.This method is called once, at the start of tree fix-up.tree - the root node of the tree to be processed.filename - the name of the file the tree came from."""self.used_names = tree.used_namesself.set_filename(filename)self.numbers = itertools.count(1)self.first_log = Truedef finish_tree(self, tree, filename):"""Some fixers need to maintain tree-wide state.This method is called once, at the conclusion of tree fix-up.tree - the root node of the tree to be processed.filename - the name of the file the tree came from."""passclass ConditionalFix(BaseFix):""" Base class for fixers which not execute if an import is found. """# This is the name of the import which, if found, will cause the test to be skippedskip_on = Nonedef start_tree(self, *args):super(ConditionalFix, self).start_tree(*args)self._should_skip = Nonedef should_skip(self, node):if self._should_skip is not None:return self._should_skippkg = self.skip_on.split(".")name = pkg[-1]pkg = ".".join(pkg[:-1])self._should_skip = does_tree_import(pkg, name, node)return self._should_skip
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。