diff options
Diffstat (limited to 'Lib/lib2to3/fixes')
-rw-r--r-- | Lib/lib2to3/fixes/basefix.py | 23 | ||||
-rw-r--r-- | Lib/lib2to3/fixes/fix_filter.py | 18 | ||||
-rw-r--r-- | Lib/lib2to3/fixes/fix_future.py | 7 | ||||
-rw-r--r-- | Lib/lib2to3/fixes/fix_import.py | 55 | ||||
-rw-r--r-- | Lib/lib2to3/fixes/fix_itertools.py | 5 | ||||
-rw-r--r-- | Lib/lib2to3/fixes/fix_itertools_imports.py | 43 | ||||
-rw-r--r-- | Lib/lib2to3/fixes/fix_map.py | 18 | ||||
-rw-r--r-- | Lib/lib2to3/fixes/fix_print.py | 11 | ||||
-rw-r--r-- | Lib/lib2to3/fixes/fix_zip.py | 19 |
9 files changed, 155 insertions, 44 deletions
diff --git a/Lib/lib2to3/fixes/basefix.py b/Lib/lib2to3/fixes/basefix.py index 66c448e..87fa205 100644 --- a/Lib/lib2to3/fixes/basefix.py +++ b/Lib/lib2to3/fixes/basefix.py @@ -16,6 +16,7 @@ except NameError: # Local imports from ..patcomp import PatternCompiler from .. import pygram +from .util import does_tree_import class BaseFix(object): @@ -36,6 +37,8 @@ class BaseFix(object): used_names = set() # A set of all used NAMEs order = "post" # Does the fixer prefer pre- or post-order traversal explicit = 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. # Shortcut for access to Python grammar symbols syms = pygram.python_symbols @@ -163,3 +166,23 @@ class BaseFix(object): filename - the name of the file the tree came from. """ pass + + +class 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 skipped + skip_on = None + + def start_tree(self, *args): + super(ConditionalFix, self).start_tree(*args) + self._should_skip = None + + def should_skip(self, node): + if self._should_skip is not None: + return self._should_skip + pkg = self.skip_on.split(".") + name = pkg[-1] + pkg = ".".join(pkg[:-1]) + self._should_skip = does_tree_import(pkg, name, node) + return self._should_skip diff --git a/Lib/lib2to3/fixes/fix_filter.py b/Lib/lib2to3/fixes/fix_filter.py index 70d8f5e..08d3495 100644 --- a/Lib/lib2to3/fixes/fix_filter.py +++ b/Lib/lib2to3/fixes/fix_filter.py @@ -16,9 +16,9 @@ Python 2.6 figure it out. # Local imports from ..pgen2 import token from . import basefix -from .util import Name, Call, ListComp, does_tree_import, in_special_context +from .util import Name, Call, ListComp, in_special_context -class FixFilter(basefix.BaseFix): +class FixFilter(basefix.ConditionalFix): PATTERN = """ filter_lambda=power< @@ -47,20 +47,10 @@ class FixFilter(basefix.BaseFix): > """ - def start_tree(self, *args): - super(FixFilter, self).start_tree(*args) - self._new_filter = None - - def has_new_filter(self, node): - if self._new_filter is not None: - return self._new_filter - self._new_filter = does_tree_import('future_builtins', 'filter', node) - return self._new_filter + skip_on = "future_builtins.filter" def transform(self, node, results): - if self.has_new_filter(node): - # If filter is imported from future_builtins, we don't want to - # do anything here. + if self.should_skip(node): return if "filter_lambda" in results: diff --git a/Lib/lib2to3/fixes/fix_future.py b/Lib/lib2to3/fixes/fix_future.py index f3ba127..62ba6f6 100644 --- a/Lib/lib2to3/fixes/fix_future.py +++ b/Lib/lib2to3/fixes/fix_future.py @@ -11,5 +11,10 @@ from .util import BlankLine class FixFuture(basefix.BaseFix): PATTERN = """import_from< 'from' module_name="__future__" 'import' any >""" + # This should be run last -- some things check for the import + run_order = 10 + def transform(self, node, results): - return BlankLine() + new = BlankLine() + new.prefix = node.get_prefix() + return new diff --git a/Lib/lib2to3/fixes/fix_import.py b/Lib/lib2to3/fixes/fix_import.py new file mode 100644 index 0000000..6617054 --- /dev/null +++ b/Lib/lib2to3/fixes/fix_import.py @@ -0,0 +1,55 @@ +"""Fixer for import statements. +If spam is being imported from the local directory, this import: + from spam import eggs +Becomes: + from .spam import eggs + +And this import: + import spam +Becomes: + import .spam +""" + +# Local imports +from . import basefix +from os.path import dirname, join, exists, pathsep + +class FixImport(basefix.BaseFix): + + PATTERN = """ + import_from< 'from' imp=any 'import' any > + | + import_name< 'import' imp=any > + """ + + def transform(self, node, results): + imp = results['imp'] + + if unicode(imp).startswith('.'): + # Already a new-style import + return + + if not probably_a_local_import(unicode(imp), self.filename): + # I guess this is a global import -- skip it! + return + + # Some imps are top-level (eg: 'import ham') + # some are first level (eg: 'import ham.eggs') + # some are third level (eg: 'import ham.eggs as spam') + # Hence, the loop + while not hasattr(imp, 'value'): + imp = imp.children[0] + + imp.value = "." + imp.value + node.changed() + return node + +def probably_a_local_import(imp_name, file_path): + # Must be stripped because the right space is included by the parser + imp_name = imp_name.split('.', 1)[0].strip() + base_path = dirname(file_path) + base_path = join(base_path, imp_name) + for ext in ['.py', pathsep, '.pyc', '.so', '.sl', '.pyd']: + if exists(base_path + ext): + return True + return False diff --git a/Lib/lib2to3/fixes/fix_itertools.py b/Lib/lib2to3/fixes/fix_itertools.py index af49270..ba10f26 100644 --- a/Lib/lib2to3/fixes/fix_itertools.py +++ b/Lib/lib2to3/fixes/fix_itertools.py @@ -1,6 +1,8 @@ """ Fixer for itertools.(imap|ifilter|izip) --> (map|filter|zip) and itertools.ifilterfalse --> itertools.filterfalse (bugs 2360-2363) + imports from itertools are fixed in fix_itertools_import.py + If itertools is imported as something else (ie: import itertools as it; it.izip(spam, eggs)) method calls will not get fixed. """ @@ -19,6 +21,9 @@ class FixItertools(basefix.BaseFix): power< func=%(it_funcs)s trailer< '(' [any] ')' > > """ %(locals()) + # Needs to be run after fix_(map|zip|filter) + run_order = 6 + def transform(self, node, results): prefix = None func = results['func'][0] diff --git a/Lib/lib2to3/fixes/fix_itertools_imports.py b/Lib/lib2to3/fixes/fix_itertools_imports.py new file mode 100644 index 0000000..0faa4ea --- /dev/null +++ b/Lib/lib2to3/fixes/fix_itertools_imports.py @@ -0,0 +1,43 @@ +""" Fixer for imports of itertools.(imap|ifilter|izip|ifilterfalse) """ + +# Local imports +from . import basefix +from .util import BlankLine + +class FixItertoolsImports(basefix.BaseFix): + PATTERN = """ + import_from< 'from' 'itertools' 'import' imports=any > + """ %(locals()) + + def transform(self, node, results): + imports = results['imports'] + children = imports.children[:] or [imports] + for child in children: + if not hasattr(child, 'value'): + # Handle 'import ... as ...' + continue + if child.value in ('imap', 'izip', 'ifilter'): + child.remove() + elif child.value == 'ifilterfalse': + node.changed() + child.value = 'filterfalse' + + # Make sure the import statement is still sane + children = imports.children[:] or [imports] + remove_comma = True + for child in children: + if remove_comma and getattr(child, 'value', None) == ',': + child.remove() + else: + remove_comma ^= True + + if unicode(children[-1]) == ',': + children[-1].remove() + + # If there is nothing left, return a blank line + if not (imports.children or getattr(imports, 'value', None)): + new = BlankLine() + new.prefix = node.get_prefix() + else: + new = node + return new diff --git a/Lib/lib2to3/fixes/fix_map.py b/Lib/lib2to3/fixes/fix_map.py index d16cf9f..7b57c50 100644 --- a/Lib/lib2to3/fixes/fix_map.py +++ b/Lib/lib2to3/fixes/fix_map.py @@ -22,10 +22,10 @@ soon as the shortest argument is exhausted. # Local imports from ..pgen2 import token from . import basefix -from .util import Name, Call, ListComp, does_tree_import, in_special_context +from .util import Name, Call, ListComp, in_special_context from ..pygram import python_symbols as syms -class FixMap(basefix.BaseFix): +class FixMap(basefix.ConditionalFix): PATTERN = """ map_none=power< @@ -54,20 +54,10 @@ class FixMap(basefix.BaseFix): > """ - def start_tree(self, *args): - super(FixMap, self).start_tree(*args) - self._future_map_found = None - - def has_future_map(self, node): - if self._future_map_found is not None: - return self._future_map_found - self._future_map_found = does_tree_import('future_builtins', 'map', node) - return self._future_map_found + skip_on = 'future_builtins.map' def transform(self, node, results): - if self.has_future_map(node): - # If a future map has been imported for this file, we won't - # be making any modifications + if self.should_skip(node): return if node.parent.type == syms.simple_stmt: diff --git a/Lib/lib2to3/fixes/fix_print.py b/Lib/lib2to3/fixes/fix_print.py index ddd846a..ae91a8d 100644 --- a/Lib/lib2to3/fixes/fix_print.py +++ b/Lib/lib2to3/fixes/fix_print.py @@ -8,6 +8,9 @@ Change: 'print ...' into 'print(...)' 'print ... ,' into 'print(..., end=" ")' 'print >>x, ...' into 'print(..., file=x)' + +No changes are applied if print_function is imported from __future__ + """ # Local imports @@ -23,14 +26,20 @@ parend_expr = patcomp.compile_pattern( ) -class FixPrint(basefix.BaseFix): +class FixPrint(basefix.ConditionalFix): PATTERN = """ simple_stmt< bare='print' any > | print_stmt """ + skip_on = '__future__.print_function' + def transform(self, node, results): assert results + + if self.should_skip(node): + return + bare_print = results.get("bare") if bare_print: diff --git a/Lib/lib2to3/fixes/fix_zip.py b/Lib/lib2to3/fixes/fix_zip.py index e072713..e319b54 100644 --- a/Lib/lib2to3/fixes/fix_zip.py +++ b/Lib/lib2to3/fixes/fix_zip.py @@ -9,33 +9,24 @@ iter(<>), list(<>), tuple(<>), sorted(<>), ...join(<>), or for V in <>:. # Local imports from . import basefix -from .util import Name, Call, does_tree_import, in_special_context +from .util import Name, Call, in_special_context -class FixZip(basefix.BaseFix): +class FixZip(basefix.ConditionalFix): PATTERN = """ power< 'zip' args=trailer< '(' [any] ')' > > """ - def start_tree(self, *args): - super(FixZip, self).start_tree(*args) - self._future_zip_found = None - - def has_future_zip(self, node): - if self._future_zip_found is not None: - return self._future_zip_found - self._future_zip_found = does_tree_import('future_builtins', 'zip', node) - return self._future_zip_found + skip_on = "future_builtins.zip" def transform(self, node, results): - if self.has_future_zip(node): - # If a future zip has been imported for this file, we won't - # be making any modifications + if self.should_skip(node): return if in_special_context(node): return None + new = node.clone() new.set_prefix("") new = Call(Name("list"), [new]) |