summaryrefslogtreecommitdiffstats
path: root/Lib/lib2to3/refactor.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/lib2to3/refactor.py')
-rw-r--r--Lib/lib2to3/refactor.py97
1 files changed, 58 insertions, 39 deletions
diff --git a/Lib/lib2to3/refactor.py b/Lib/lib2to3/refactor.py
index 55fd60f..8a40deb 100644
--- a/Lib/lib2to3/refactor.py
+++ b/Lib/lib2to3/refactor.py
@@ -8,23 +8,26 @@ recursively descend down directories. Imported as a module, this
provides infrastructure to write your own refactoring tool.
"""
+from __future__ import with_statement
+
__author__ = "Guido van Rossum <guido@python.org>"
# Python imports
-import io
import os
import pkgutil
import sys
import logging
import operator
import collections
+import StringIO
from itertools import chain
# Local imports
from .pgen2 import driver, tokenize, token
from .fixer_util import find_root
from . import pytree, pygram
+from . import btm_utils as bu
from . import btm_matcher as bm
@@ -54,7 +57,7 @@ def _get_head_types(pat):
# Always return leafs
if pat.type is None:
raise _EveryNode
- return {pat.type}
+ return set([pat.type])
if isinstance(pat, pytree.NegatedPattern):
if pat.content:
@@ -91,7 +94,7 @@ def _get_headnode_dict(fixer_list):
head_nodes[fixer._accept_type].append(fixer)
else:
every.append(fixer)
- for node_type in chain(pygram.python_grammar.symbol2number.values(),
+ for node_type in chain(pygram.python_grammar.symbol2number.itervalues(),
pygram.python_grammar.tokens):
head_nodes[node_type].extend(every)
return dict(head_nodes)
@@ -107,14 +110,30 @@ def get_fixers_from_package(pkg_name):
def _identity(obj):
return obj
+if sys.version_info < (3, 0):
+ import codecs
+ _open_with_encoding = codecs.open
+ # codecs.open doesn't translate newlines sadly.
+ def _from_system_newlines(input):
+ return input.replace(u"\r\n", u"\n")
+ def _to_system_newlines(input):
+ if os.linesep != "\n":
+ return input.replace(u"\n", os.linesep)
+ else:
+ return input
+else:
+ _open_with_encoding = open
+ _from_system_newlines = _identity
+ _to_system_newlines = _identity
+
def _detect_future_features(source):
have_docstring = False
- gen = tokenize.generate_tokens(io.StringIO(source).readline)
+ gen = tokenize.generate_tokens(StringIO.StringIO(source).readline)
def advance():
- tok = next(gen)
+ tok = gen.next()
return tok[0], tok[1]
- ignore = frozenset({token.NEWLINE, tokenize.NL, token.COMMENT})
+ ignore = frozenset((token.NEWLINE, tokenize.NL, token.COMMENT))
features = set()
try:
while True:
@@ -125,20 +144,20 @@ def _detect_future_features(source):
if have_docstring:
break
have_docstring = True
- elif tp == token.NAME and value == "from":
+ elif tp == token.NAME and value == u"from":
tp, value = advance()
- if tp != token.NAME or value != "__future__":
+ if tp != token.NAME or value != u"__future__":
break
tp, value = advance()
- if tp != token.NAME or value != "import":
+ if tp != token.NAME or value != u"import":
break
tp, value = advance()
- if tp == token.OP and value == "(":
+ if tp == token.OP and value == u"(":
tp, value = advance()
while tp == token.NAME:
features.add(value)
tp, value = advance()
- if tp != token.OP or value != ",":
+ if tp != token.OP or value != u",":
break
tp, value = advance()
else:
@@ -232,7 +251,7 @@ class RefactoringTool(object):
try:
fix_class = getattr(mod, class_name)
except AttributeError:
- raise FixerError("Can't find %s.%s" % (fix_name, class_name)) from None
+ raise FixerError("Can't find %s.%s" % (fix_name, class_name))
fixer = fix_class(self.options, self.fixer_log)
if fixer.explicit and self.explicit is not True and \
fix_mod_path not in self.explicit:
@@ -307,15 +326,15 @@ class RefactoringTool(object):
"""
try:
f = open(filename, "rb")
- except OSError as err:
+ except IOError as err:
self.log_error("Can't open %s: %s", filename, err)
return None, None
try:
encoding = tokenize.detect_encoding(f.readline)[0]
finally:
f.close()
- with io.open(filename, "r", encoding=encoding, newline='') as f:
- return f.read(), encoding
+ with _open_with_encoding(filename, "r", encoding=encoding) as f:
+ return _from_system_newlines(f.read()), encoding
def refactor_file(self, filename, write=False, doctests_only=False):
"""Refactors a file."""
@@ -323,7 +342,7 @@ class RefactoringTool(object):
if input is None:
# Reading the file failed.
return
- input += "\n" # Silence certain parse errors
+ input += u"\n" # Silence certain parse errors
if doctests_only:
self.log_debug("Refactoring doctests in %s", filename)
output = self.refactor_docstring(input, filename)
@@ -335,7 +354,7 @@ class RefactoringTool(object):
tree = self.refactor_string(input, filename)
if self.write_unchanged_files or (tree and tree.was_changed):
# The [:-1] is to take off the \n we added earlier
- self.processed_file(str(tree)[:-1], filename,
+ self.processed_file(unicode(tree)[:-1], filename,
write=write, encoding=encoding)
else:
self.log_debug("No changes in %s", filename)
@@ -379,7 +398,7 @@ class RefactoringTool(object):
else:
tree = self.refactor_string(input, "<stdin>")
if self.write_unchanged_files or (tree and tree.was_changed):
- self.processed_file(str(tree), "<stdin>", input)
+ self.processed_file(unicode(tree), "<stdin>", input)
else:
self.log_debug("No changes in stdin")
@@ -514,16 +533,16 @@ class RefactoringTool(object):
set.
"""
try:
- fp = io.open(filename, "w", encoding=encoding, newline='')
- except OSError as err:
+ f = _open_with_encoding(filename, "w", encoding=encoding)
+ except os.error as err:
self.log_error("Can't create %s: %s", filename, err)
return
-
- with fp:
- try:
- fp.write(new_text)
- except OSError as err:
- self.log_error("Can't write %s: %s", filename, err)
+ try:
+ f.write(_to_system_newlines(new_text))
+ except os.error as err:
+ self.log_error("Can't write %s: %s", filename, err)
+ finally:
+ f.close()
self.log_debug("Wrote changes to %s", filename)
self.wrote = True
@@ -547,7 +566,7 @@ class RefactoringTool(object):
block_lineno = None
indent = None
lineno = 0
- for line in input.splitlines(keepends=True):
+ for line in input.splitlines(True):
lineno += 1
if line.lstrip().startswith(self.PS1):
if block is not None:
@@ -559,7 +578,7 @@ class RefactoringTool(object):
indent = line[:i]
elif (indent is not None and
(line.startswith(indent + self.PS2) or
- line == indent + self.PS2.rstrip() + "\n")):
+ line == indent + self.PS2.rstrip() + u"\n")):
block.append(line)
else:
if block is not None:
@@ -571,7 +590,7 @@ class RefactoringTool(object):
if block is not None:
result.extend(self.refactor_doctest(block, block_lineno,
indent, filename))
- return "".join(result)
+ return u"".join(result)
def refactor_doctest(self, block, lineno, indent, filename):
"""Refactors one doctest.
@@ -586,17 +605,17 @@ class RefactoringTool(object):
except Exception as err:
if self.logger.isEnabledFor(logging.DEBUG):
for line in block:
- self.log_debug("Source: %s", line.rstrip("\n"))
+ self.log_debug("Source: %s", line.rstrip(u"\n"))
self.log_error("Can't parse docstring in %s line %s: %s: %s",
filename, lineno, err.__class__.__name__, err)
return block
if self.refactor_tree(tree, filename):
- new = str(tree).splitlines(keepends=True)
+ new = unicode(tree).splitlines(True)
# Undo the adjustment of the line numbers in wrap_toks() below.
clipped, new = new[:lineno-1], new[lineno-1:]
- assert clipped == ["\n"] * (lineno-1), clipped
- if not new[-1].endswith("\n"):
- new[-1] += "\n"
+ assert clipped == [u"\n"] * (lineno-1), clipped
+ if not new[-1].endswith(u"\n"):
+ new[-1] += u"\n"
block = [indent + self.PS1 + new.pop(0)]
if new:
block += [indent + self.PS2 + line for line in new]
@@ -637,7 +656,7 @@ class RefactoringTool(object):
def wrap_toks(self, block, lineno, indent):
"""Wraps a tokenize stream to systematically modify start/end."""
- tokens = tokenize.generate_tokens(self.gen_lines(block, indent).__next__)
+ tokens = tokenize.generate_tokens(self.gen_lines(block, indent).next)
for type, value, (line0, col0), (line1, col1), line_text in tokens:
line0 += lineno - 1
line1 += lineno - 1
@@ -660,8 +679,8 @@ class RefactoringTool(object):
for line in block:
if line.startswith(prefix):
yield line[len(prefix):]
- elif line == prefix.rstrip() + "\n":
- yield "\n"
+ elif line == prefix.rstrip() + u"\n":
+ yield u"\n"
else:
raise AssertionError("line=%r, prefix=%r" % (line, prefix))
prefix = prefix2
@@ -694,7 +713,7 @@ class MultiprocessRefactoringTool(RefactoringTool):
self.queue = multiprocessing.JoinableQueue()
self.output_lock = multiprocessing.Lock()
processes = [multiprocessing.Process(target=self._child)
- for i in range(num_processes)]
+ for i in xrange(num_processes)]
try:
for p in processes:
p.start()
@@ -702,7 +721,7 @@ class MultiprocessRefactoringTool(RefactoringTool):
doctests_only)
finally:
self.queue.join()
- for i in range(num_processes):
+ for i in xrange(num_processes):
self.queue.put(None)
for p in processes:
if p.is_alive():