symbian-qemu-0.9.1-12/python-win32-2.6.1/lib/lib2to3/fixer_base.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 # Copyright 2006 Google, Inc. All Rights Reserved.
       
     2 # Licensed to PSF under a Contributor Agreement.
       
     3 
       
     4 """Base class for fixers (optional, but recommended)."""
       
     5 
       
     6 # Python imports
       
     7 import logging
       
     8 import itertools
       
     9 
       
    10 # Local imports
       
    11 from .patcomp import PatternCompiler
       
    12 from . import pygram
       
    13 from .fixer_util import does_tree_import
       
    14 
       
    15 class BaseFix(object):
       
    16 
       
    17     """Optional base class for fixers.
       
    18 
       
    19     The subclass name must be FixFooBar where FooBar is the result of
       
    20     removing underscores and capitalizing the words of the fix name.
       
    21     For example, the class name for a fixer named 'has_key' should be
       
    22     FixHasKey.
       
    23     """
       
    24 
       
    25     PATTERN = None  # Most subclasses should override with a string literal
       
    26     pattern = None  # Compiled pattern, set by compile_pattern()
       
    27     options = None  # Options object passed to initializer
       
    28     filename = None # The filename (set by set_filename)
       
    29     logger = None   # A logger (set by set_filename)
       
    30     numbers = itertools.count(1) # For new_name()
       
    31     used_names = set() # A set of all used NAMEs
       
    32     order = "post" # Does the fixer prefer pre- or post-order traversal
       
    33     explicit = False # Is this ignored by refactor.py -f all?
       
    34     run_order = 5   # Fixers will be sorted by run order before execution
       
    35                     # Lower numbers will be run first.
       
    36 
       
    37     # Shortcut for access to Python grammar symbols
       
    38     syms = pygram.python_symbols
       
    39 
       
    40     def __init__(self, options, log):
       
    41         """Initializer.  Subclass may override.
       
    42 
       
    43         Args:
       
    44             options: an dict containing the options passed to RefactoringTool
       
    45             that could be used to customize the fixer through the command line.
       
    46             log: a list to append warnings and other messages to.
       
    47         """
       
    48         self.options = options
       
    49         self.log = log
       
    50         self.compile_pattern()
       
    51 
       
    52     def compile_pattern(self):
       
    53         """Compiles self.PATTERN into self.pattern.
       
    54 
       
    55         Subclass may override if it doesn't want to use
       
    56         self.{pattern,PATTERN} in .match().
       
    57         """
       
    58         if self.PATTERN is not None:
       
    59             self.pattern = PatternCompiler().compile_pattern(self.PATTERN)
       
    60 
       
    61     def set_filename(self, filename):
       
    62         """Set the filename, and a logger derived from it.
       
    63 
       
    64         The main refactoring tool should call this.
       
    65         """
       
    66         self.filename = filename
       
    67         self.logger = logging.getLogger(filename)
       
    68 
       
    69     def match(self, node):
       
    70         """Returns match for a given parse tree node.
       
    71 
       
    72         Should return a true or false object (not necessarily a bool).
       
    73         It may return a non-empty dict of matching sub-nodes as
       
    74         returned by a matching pattern.
       
    75 
       
    76         Subclass may override.
       
    77         """
       
    78         results = {"node": node}
       
    79         return self.pattern.match(node, results) and results
       
    80 
       
    81     def transform(self, node, results):
       
    82         """Returns the transformation for a given parse tree node.
       
    83 
       
    84         Args:
       
    85           node: the root of the parse tree that matched the fixer.
       
    86           results: a dict mapping symbolic names to part of the match.
       
    87 
       
    88         Returns:
       
    89           None, or a node that is a modified copy of the
       
    90           argument node.  The node argument may also be modified in-place to
       
    91           effect the same change.
       
    92 
       
    93         Subclass *must* override.
       
    94         """
       
    95         raise NotImplementedError()
       
    96 
       
    97     def parenthesize(self, node):
       
    98         """Wrapper around pygram.parenthesize()."""
       
    99         return pygram.parenthesize(node)
       
   100 
       
   101     def new_name(self, template="xxx_todo_changeme"):
       
   102         """Return a string suitable for use as an identifier
       
   103 
       
   104         The new name is guaranteed not to conflict with other identifiers.
       
   105         """
       
   106         name = template
       
   107         while name in self.used_names:
       
   108             name = template + str(self.numbers.next())
       
   109         self.used_names.add(name)
       
   110         return name
       
   111 
       
   112     def log_message(self, message):
       
   113         if self.first_log:
       
   114             self.first_log = False
       
   115             self.log.append("### In file %s ###" % self.filename)
       
   116         self.log.append(message)
       
   117 
       
   118     def cannot_convert(self, node, reason=None):
       
   119         """Warn the user that a given chunk of code is not valid Python 3,
       
   120         but that it cannot be converted automatically.
       
   121 
       
   122         First argument is the top-level node for the code in question.
       
   123         Optional second argument is why it can't be converted.
       
   124         """
       
   125         lineno = node.get_lineno()
       
   126         for_output = node.clone()
       
   127         for_output.set_prefix("")
       
   128         msg = "Line %d: could not convert: %s"
       
   129         self.log_message(msg % (lineno, for_output))
       
   130         if reason:
       
   131             self.log_message(reason)
       
   132 
       
   133     def warning(self, node, reason):
       
   134         """Used for warning the user about possible uncertainty in the
       
   135         translation.
       
   136 
       
   137         First argument is the top-level node for the code in question.
       
   138         Optional second argument is why it can't be converted.
       
   139         """
       
   140         lineno = node.get_lineno()
       
   141         self.log_message("Line %d: %s" % (lineno, reason))
       
   142 
       
   143     def start_tree(self, tree, filename):
       
   144         """Some fixers need to maintain tree-wide state.
       
   145         This method is called once, at the start of tree fix-up.
       
   146 
       
   147         tree - the root node of the tree to be processed.
       
   148         filename - the name of the file the tree came from.
       
   149         """
       
   150         self.used_names = tree.used_names
       
   151         self.set_filename(filename)
       
   152         self.numbers = itertools.count(1)
       
   153         self.first_log = True
       
   154 
       
   155     def finish_tree(self, tree, filename):
       
   156         """Some fixers need to maintain tree-wide state.
       
   157         This method is called once, at the conclusion of tree fix-up.
       
   158 
       
   159         tree - the root node of the tree to be processed.
       
   160         filename - the name of the file the tree came from.
       
   161         """
       
   162         pass
       
   163 
       
   164 
       
   165 class ConditionalFix(BaseFix):
       
   166     """ Base class for fixers which not execute if an import is found. """
       
   167 
       
   168     # This is the name of the import which, if found, will cause the test to be skipped
       
   169     skip_on = None
       
   170 
       
   171     def start_tree(self, *args):
       
   172         super(ConditionalFix, self).start_tree(*args)
       
   173         self._should_skip = None
       
   174 
       
   175     def should_skip(self, node):
       
   176         if self._should_skip is not None:
       
   177             return self._should_skip
       
   178         pkg = self.skip_on.split(".")
       
   179         name = pkg[-1]
       
   180         pkg = ".".join(pkg[:-1])
       
   181         self._should_skip = does_tree_import(pkg, name, node)
       
   182         return self._should_skip