summaryrefslogtreecommitdiffstats
path: root/Lib/lib2to3/fixes
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/lib2to3/fixes')
-rw-r--r--Lib/lib2to3/fixes/basefix.py23
-rw-r--r--Lib/lib2to3/fixes/fix_filter.py18
-rw-r--r--Lib/lib2to3/fixes/fix_future.py7
-rw-r--r--Lib/lib2to3/fixes/fix_import.py55
-rw-r--r--Lib/lib2to3/fixes/fix_itertools.py5
-rw-r--r--Lib/lib2to3/fixes/fix_itertools_imports.py43
-rw-r--r--Lib/lib2to3/fixes/fix_map.py18
-rw-r--r--Lib/lib2to3/fixes/fix_print.py11
-rw-r--r--Lib/lib2to3/fixes/fix_zip.py19
9 files changed, 155 insertions, 44 deletions
diff --git a/Lib/lib2to3/fixes/basefix.py b/Lib/lib2to3/fixes/basefix.py
index 38666c1..937f8c1 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])