Changeset 391 for python/trunk/Lib/lib2to3
- Timestamp:
- Mar 19, 2014, 11:31:01 PM (11 years ago)
- Location:
- python/trunk
- Files:
-
- 68 edited
- 5 copied
Legend:
- Unmodified
- Added
- Removed
-
python/trunk
-
Property svn:mergeinfo
set to
/python/vendor/Python-2.7.6 merged eligible /python/vendor/current merged eligible
-
Property svn:mergeinfo
set to
-
python/trunk/Lib/lib2to3/Grammar.txt
r2 r391 1 # Grammar for Python1 # Grammar for 2to3. This grammar supports Python 2.x and 3.x. 2 2 3 3 # Note: Changing the grammar specified in this file will most likely … … 129 129 NAME | NUMBER | STRING+ | '.' '.' '.') 130 130 listmaker: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] ) 131 testlist_gexp: test( comp_for | (',' (test|star_expr))* [','] )131 testlist_gexp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] ) 132 132 lambdef: 'lambda' [varargslist] ':' test 133 133 trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME -
python/trunk/Lib/lib2to3/fixer_base.py
r2 r391 25 25 PATTERN = None # Most subclasses should override with a string literal 26 26 pattern = None # Compiled pattern, set by compile_pattern() 27 pattern_tree = None # Tree representation of the pattern 27 28 options = None # Options object passed to initializer 28 29 filename = None # The filename (set by set_filename) … … 36 37 _accept_type = None # [Advanced and not public] This tells RefactoringTool 37 38 # which node type to accept when there's not a pattern. 39 40 keep_line_order = False # For the bottom matcher: match with the 41 # original line order 42 BM_compatible = False # Compatibility with the bottom matching 43 # module; every fixer should set this 44 # manually 38 45 39 46 # Shortcut for access to Python grammar symbols … … 59 66 """ 60 67 if self.PATTERN is not None: 61 self.pattern = PatternCompiler().compile_pattern(self.PATTERN) 68 PC = PatternCompiler() 69 self.pattern, self.pattern_tree = PC.compile_pattern(self.PATTERN, 70 with_tree=True) 62 71 63 72 def set_filename(self, filename): -
python/trunk/Lib/lib2to3/fixer_util.py
r2 r391 1 1 """Utility functions, node construction macros, etc.""" 2 2 # Author: Collin Winter 3 4 from itertools import islice 3 5 4 6 # Local imports … … 15 17 def KeywordArg(keyword, value): 16 18 return Node(syms.argument, 17 [keyword, Leaf(token.EQUAL, u '='), value])19 [keyword, Leaf(token.EQUAL, u"="), value]) 18 20 19 21 def LParen(): … … 77 79 def Subscript(index_node): 78 80 """A numeric or string subscript""" 79 return Node(syms.trailer, [Leaf(token.LBRACE, u '['),81 return Node(syms.trailer, [Leaf(token.LBRACE, u"["), 80 82 index_node, 81 Leaf(token.RBRACE, u ']')])83 Leaf(token.RBRACE, u"]")]) 82 84 83 85 def String(string, prefix=None): … … 121 123 leaf.remove() 122 124 123 children = [Leaf(token.NAME, u 'from'),125 children = [Leaf(token.NAME, u"from"), 124 126 Leaf(token.NAME, package_name, prefix=u" "), 125 Leaf(token.NAME, u 'import', prefix=u" "),127 Leaf(token.NAME, u"import", prefix=u" "), 126 128 Node(syms.import_as_names, name_leafs)] 127 129 imp = Node(syms.import_from, children) … … 164 166 165 167 consuming_calls = set(["sorted", "list", "set", "any", "all", "tuple", "sum", 166 "min", "max" ])168 "min", "max", "enumerate"]) 167 169 168 170 def attr_chain(obj, attr): … … 191 193 power< 192 194 ( 'iter' | 'list' | 'tuple' | 'sorted' | 'set' | 'sum' | 193 'any' | 'all' | (any* trailer< '.' 'join' >) )195 'any' | 'all' | 'enumerate' | (any* trailer< '.' 'join' >) ) 194 196 trailer< '(' node=any ')' > 195 197 any* … … 198 200 p2 = """ 199 201 power< 200 'sorted'202 ( 'sorted' | 'enumerate' ) 201 203 trailer< '(' arglist<node=any any*> ')' > 202 204 any* … … 206 208 def in_special_context(node): 207 209 """ Returns true if node is in an environment where all that is required 208 of it is being it terable (ie, it doesn't matter if it returns a list209 or an it terator).210 of it is being iterable (ie, it doesn't matter if it returns a list 211 or an iterator). 210 212 See test_map_nochange in test_fixers.py for some examples and tests. 211 213 """ 212 214 global p0, p1, p2, pats_built 213 215 if not pats_built: 216 p0 = patcomp.compile_pattern(p0) 214 217 p1 = patcomp.compile_pattern(p1) 215 p0 = patcomp.compile_pattern(p0)216 218 p2 = patcomp.compile_pattern(p2) 217 219 pats_built = True … … 246 248 return True 247 249 250 def find_indentation(node): 251 """Find the indentation of *node*.""" 252 while node is not None: 253 if node.type == syms.suite and len(node.children) > 2: 254 indent = node.children[1] 255 if indent.type == token.INDENT: 256 return indent.value 257 node = node.parent 258 return u"" 259 248 260 ########################################################### 249 261 ### The following functions are to find bindings in a suite … … 263 275 # Scamper up to the top level namespace 264 276 while node.type != syms.file_input: 265 assert node.parent, "Tree is insane! root found before "\266 "file_input node was found."267 277 node = node.parent 278 if not node: 279 raise ValueError("root found before file_input node was found.") 268 280 return node 269 281 … … 284 296 if it was not imported. """ 285 297 def is_import_stmt(node): 286 return node.type == syms.simple_stmt and node.children and \287 is_import(node.children[0])298 return (node.type == syms.simple_stmt and node.children and 299 is_import(node.children[0])) 288 300 289 301 root = find_root(node) … … 308 320 if insert_pos == 0: 309 321 for idx, node in enumerate(root.children): 310 if node.type == syms.simple_stmt and node.children and \311 node.children[0].type == token.STRING :322 if (node.type == syms.simple_stmt and node.children and 323 node.children[0].type == token.STRING): 312 324 insert_pos = idx + 1 313 325 break … … 315 327 if package is None: 316 328 import_ = Node(syms.import_name, [ 317 Leaf(token.NAME, u 'import'),318 Leaf(token.NAME, name, prefix=u ' ')329 Leaf(token.NAME, u"import"), 330 Leaf(token.NAME, name, prefix=u" ") 319 331 ]) 320 332 else: 321 import_ = FromImport(package, [Leaf(token.NAME, name, prefix=u ' ')])333 import_ = FromImport(package, [Leaf(token.NAME, name, prefix=u" ")]) 322 334 323 335 children = [import_, Newline()] … … 405 417 return None 406 418 n = node.children[3] 407 if package and _find(u 'as', n):419 if package and _find(u"as", n): 408 420 # See test_from_import_as for explanation 409 421 return None -
python/trunk/Lib/lib2to3/fixes/fix_apply.py
r2 r391 13 13 14 14 class FixApply(fixer_base.BaseFix): 15 BM_compatible = True 15 16 16 17 PATTERN = """ -
python/trunk/Lib/lib2to3/fixes/fix_basestring.py
r2 r391 7 7 8 8 class FixBasestring(fixer_base.BaseFix): 9 BM_compatible = True 9 10 10 11 PATTERN = "'basestring'" -
python/trunk/Lib/lib2to3/fixes/fix_buffer.py
r2 r391 10 10 11 11 class FixBuffer(fixer_base.BaseFix): 12 BM_compatible = True 12 13 13 14 explicit = True # The user must ask for this fixer -
python/trunk/Lib/lib2to3/fixes/fix_callable.py
r2 r391 12 12 13 13 class FixCallable(fixer_base.BaseFix): 14 BM_compatible = True 15 16 order = "pre" 14 17 15 18 # Ignore callable(*args) or use of keywords. -
python/trunk/Lib/lib2to3/fixes/fix_dict.py
r2 r391 41 41 42 42 class FixDict(fixer_base.BaseFix): 43 BM_compatible = True 44 43 45 PATTERN = """ 44 46 power< head=any+ -
python/trunk/Lib/lib2to3/fixes/fix_except.py
r2 r391 35 35 36 36 class FixExcept(fixer_base.BaseFix): 37 BM_compatible = True 37 38 38 39 PATTERN = """ -
python/trunk/Lib/lib2to3/fixes/fix_exec.py
r2 r391 17 17 18 18 class FixExec(fixer_base.BaseFix): 19 BM_compatible = True 19 20 20 21 PATTERN = """ -
python/trunk/Lib/lib2to3/fixes/fix_execfile.py
r2 r391 14 14 15 15 class FixExecfile(fixer_base.BaseFix): 16 BM_compatible = True 16 17 17 18 PATTERN = """ -
python/trunk/Lib/lib2to3/fixes/fix_filter.py
r2 r391 20 20 21 21 class FixFilter(fixer_base.ConditionalFix): 22 BM_compatible = True 22 23 23 24 PATTERN = """ -
python/trunk/Lib/lib2to3/fixes/fix_funcattrs.py
r2 r391 8 8 9 9 class FixFuncattrs(fixer_base.BaseFix): 10 BM_compatible = True 11 10 12 PATTERN = """ 11 13 power< any+ trailer< '.' attr=('func_closure' | 'func_doc' | 'func_globals' -
python/trunk/Lib/lib2to3/fixes/fix_future.py
r2 r391 10 10 11 11 class FixFuture(fixer_base.BaseFix): 12 BM_compatible = True 13 12 14 PATTERN = """import_from< 'from' module_name="__future__" 'import' any >""" 13 15 -
python/trunk/Lib/lib2to3/fixes/fix_getcwdu.py
r2 r391 9 9 10 10 class FixGetcwdu(fixer_base.BaseFix): 11 BM_compatible = True 11 12 12 13 PATTERN = """ -
python/trunk/Lib/lib2to3/fixes/fix_has_key.py
r2 r391 38 38 39 39 class FixHasKey(fixer_base.BaseFix): 40 BM_compatible = True 40 41 41 42 PATTERN = """ -
python/trunk/Lib/lib2to3/fixes/fix_idioms.py
r2 r391 36 36 37 37 class FixIdioms(fixer_base.BaseFix): 38 39 38 explicit = True # The user must ask for this fixer 40 39 -
python/trunk/Lib/lib2to3/fixes/fix_import.py
r2 r391 37 37 38 38 class FixImport(fixer_base.BaseFix): 39 BM_compatible = True 39 40 40 41 PATTERN = """ … … 44 45 """ 45 46 47 def start_tree(self, tree, name): 48 super(FixImport, self).start_tree(tree, name) 49 self.skip = "absolute_import" in tree.future_features 50 46 51 def transform(self, node, results): 52 if self.skip: 53 return 47 54 imp = results['imp'] 48 55 … … 72 79 return 73 80 74 new = FromImport( '.', [imp])81 new = FromImport(u".", [imp]) 75 82 new.prefix = node.prefix 76 83 return new 77 84 78 85 def probably_a_local_import(self, imp_name): 79 imp_name = imp_name.split('.', 1)[0] 86 if imp_name.startswith(u"."): 87 # Relative imports are certainly not local imports. 88 return False 89 imp_name = imp_name.split(u".", 1)[0] 80 90 base_path = dirname(self.filename) 81 91 base_path = join(base_path, imp_name) 82 92 # If there is no __init__.py next to the file its not in a package 83 93 # so can't be a relative import. 84 if not exists(join(dirname(base_path), '__init__.py')):94 if not exists(join(dirname(base_path), "__init__.py")): 85 95 return False 86 for ext in [ '.py', sep, '.pyc', '.so', '.sl', '.pyd']:96 for ext in [".py", sep, ".pyc", ".so", ".sl", ".pyd"]: 87 97 if exists(base_path + ext): 88 98 return True -
python/trunk/Lib/lib2to3/fixes/fix_imports.py
r2 r391 85 85 class FixImports(fixer_base.BaseFix): 86 86 87 BM_compatible = True 88 keep_line_order = True 87 89 # This is overridden in fix_imports2. 88 90 mapping = MAPPING -
python/trunk/Lib/lib2to3/fixes/fix_input.py
r2 r391 12 12 13 13 class FixInput(fixer_base.BaseFix): 14 14 BM_compatible = True 15 15 PATTERN = """ 16 16 power< 'input' args=trailer< '(' [any] ')' > > -
python/trunk/Lib/lib2to3/fixes/fix_intern.py
r2 r391 13 13 14 14 class FixIntern(fixer_base.BaseFix): 15 BM_compatible = True 16 order = "pre" 15 17 16 18 PATTERN = """ -
python/trunk/Lib/lib2to3/fixes/fix_isinstance.py
r2 r391 15 15 16 16 class FixIsinstance(fixer_base.BaseFix): 17 17 BM_compatible = True 18 18 PATTERN = """ 19 19 power< -
python/trunk/Lib/lib2to3/fixes/fix_itertools.py
r2 r391 13 13 14 14 class FixItertools(fixer_base.BaseFix): 15 it_funcs = "('imap'|'ifilter'|'izip'|'ifilterfalse')" 15 BM_compatible = True 16 it_funcs = "('imap'|'ifilter'|'izip'|'izip_longest'|'ifilterfalse')" 16 17 PATTERN = """ 17 18 power< it='itertools' … … 28 29 prefix = None 29 30 func = results['func'][0] 30 if 'it' in results and func.value != u'ifilterfalse': 31 if ('it' in results and 32 func.value not in (u'ifilterfalse', u'izip_longest')): 31 33 dot, it = (results['dot'], results['it']) 32 34 # Remove the 'itertools' 33 35 prefix = it.prefix 34 36 it.remove() 35 # Replace the node w ich contains ('.', 'function') with the36 # function (to be consist ant with the second part of the pattern)37 # Replace the node which contains ('.', 'function') with the 38 # function (to be consistent with the second part of the pattern) 37 39 dot.remove() 38 40 func.parent.replace(func) -
python/trunk/Lib/lib2to3/fixes/fix_itertools_imports.py
r2 r391 7 7 8 8 class FixItertoolsImports(fixer_base.BaseFix): 9 BM_compatible = True 9 10 PATTERN = """ 10 11 import_from< 'from' 'itertools' 'import' imports=any > … … 21 22 member = child.value 22 23 name_node = child 24 elif child.type == token.STAR: 25 # Just leave the import as is. 26 return 23 27 else: 24 28 assert child.type == syms.import_as_name … … 28 32 child.value = None 29 33 child.remove() 30 elif member_name == u'ifilterfalse':34 elif member_name in (u'ifilterfalse', u'izip_longest'): 31 35 node.changed() 32 name_node.value = u'filterfalse' 36 name_node.value = (u'filterfalse' if member_name[1] == u'f' 37 else u'zip_longest') 33 38 34 39 # Make sure the import statement is still sane … … 41 46 remove_comma ^= True 42 47 43 ifchildren[-1].type == token.COMMA:44 children [-1].remove()48 while children and children[-1].type == token.COMMA: 49 children.pop().remove() 45 50 46 51 # If there are no imports left, just get rid of the entire statement 47 if not (imports.children or getattr(imports, 'value', None)) or \48 imports.parent is None:52 if (not (imports.children or getattr(imports, 'value', None)) or 53 imports.parent is None): 49 54 p = node.prefix 50 55 node = BlankLine() -
python/trunk/Lib/lib2to3/fixes/fix_long.py
r2 r391 11 11 12 12 class FixLong(fixer_base.BaseFix): 13 13 BM_compatible = True 14 14 PATTERN = "'long'" 15 15 -
python/trunk/Lib/lib2to3/fixes/fix_map.py
r2 r391 27 27 28 28 class FixMap(fixer_base.ConditionalFix): 29 BM_compatible = True 29 30 30 31 PATTERN = """ -
python/trunk/Lib/lib2to3/fixes/fix_metaclass.py
r2 r391 49 49 for node in cls_node.children: 50 50 if node.type == syms.suite: 51 # already in the prefer ed format, do nothing51 # already in the preferred format, do nothing 52 52 return 53 53 … … 72 72 """ if there is a semi-colon all the parts count as part of the same 73 73 simple_stmt. We just want the __metaclass__ part so we move 74 everything efter the semi-colon into its own simple_stmt node74 everything after the semi-colon into its own simple_stmt node 75 75 """ 76 76 for semi_ind, node in enumerate(stmt_node.children): … … 144 144 145 145 class FixMetaclass(fixer_base.BaseFix): 146 BM_compatible = True 146 147 147 148 PATTERN = """ -
python/trunk/Lib/lib2to3/fixes/fix_methodattrs.py
r2 r391 14 14 15 15 class FixMethodattrs(fixer_base.BaseFix): 16 BM_compatible = True 16 17 PATTERN = """ 17 18 power< any+ trailer< '.' attr=('im_func' | 'im_self' | 'im_class') > any* > -
python/trunk/Lib/lib2to3/fixes/fix_next.py
r2 r391 16 16 17 17 class FixNext(fixer_base.BaseFix): 18 BM_compatible = True 18 19 PATTERN = """ 19 20 power< base=any+ trailer< '.' attr='next' > trailer< '(' ')' > > -
python/trunk/Lib/lib2to3/fixes/fix_nonzero.py
r2 r391 7 7 8 8 class FixNonzero(fixer_base.BaseFix): 9 BM_compatible = True 9 10 PATTERN = """ 10 11 classdef< 'class' any+ ':' -
python/trunk/Lib/lib2to3/fixes/fix_operator.py
r2 r391 1 """Fixer for operator .{isCallable,sequenceIncludes}1 """Fixer for operator functions. 2 2 3 operator.isCallable(obj) -> hasattr(obj, '__call__')3 operator.isCallable(obj) -> hasattr(obj, '__call__') 4 4 operator.sequenceIncludes(obj) -> operator.contains(obj) 5 operator.isSequenceType(obj) -> isinstance(obj, collections.Sequence) 6 operator.isMappingType(obj) -> isinstance(obj, collections.Mapping) 7 operator.isNumberType(obj) -> isinstance(obj, numbers.Number) 8 operator.repeat(obj, n) -> operator.mul(obj, n) 9 operator.irepeat(obj, n) -> operator.imul(obj, n) 5 10 """ 6 11 7 12 # Local imports 8 from .. import fixer_base 9 from ..fixer_util import Call, Name, String 13 from lib2to3 import fixer_base 14 from lib2to3.fixer_util import Call, Name, String, touch_import 15 16 17 def invocation(s): 18 def dec(f): 19 f.invocation = s 20 return f 21 return dec 22 10 23 11 24 class FixOperator(fixer_base.BaseFix): 25 BM_compatible = True 26 order = "pre" 12 27 13 methods = "method=('isCallable'|'sequenceIncludes')" 14 func = "'(' func=any ')'" 28 methods = """ 29 method=('isCallable'|'sequenceIncludes' 30 |'isSequenceType'|'isMappingType'|'isNumberType' 31 |'repeat'|'irepeat') 32 """ 33 obj = "'(' obj=any ')'" 15 34 PATTERN = """ 16 35 power< module='operator' 17 trailer< '.' {methods} > trailer< {func}> >36 trailer< '.' %(methods)s > trailer< %(obj)s > > 18 37 | 19 power< {methods} trailer< {func}> >20 """ .format(methods=methods, func=func)38 power< %(methods)s trailer< %(obj)s > > 39 """ % dict(methods=methods, obj=obj) 21 40 22 41 def transform(self, node, results): 42 method = self._check_method(node, results) 43 if method is not None: 44 return method(node, results) 45 46 @invocation("operator.contains(%s)") 47 def _sequenceIncludes(self, node, results): 48 return self._handle_rename(node, results, u"contains") 49 50 @invocation("hasattr(%s, '__call__')") 51 def _isCallable(self, node, results): 52 obj = results["obj"] 53 args = [obj.clone(), String(u", "), String(u"'__call__'")] 54 return Call(Name(u"hasattr"), args, prefix=node.prefix) 55 56 @invocation("operator.mul(%s)") 57 def _repeat(self, node, results): 58 return self._handle_rename(node, results, u"mul") 59 60 @invocation("operator.imul(%s)") 61 def _irepeat(self, node, results): 62 return self._handle_rename(node, results, u"imul") 63 64 @invocation("isinstance(%s, collections.Sequence)") 65 def _isSequenceType(self, node, results): 66 return self._handle_type2abc(node, results, u"collections", u"Sequence") 67 68 @invocation("isinstance(%s, collections.Mapping)") 69 def _isMappingType(self, node, results): 70 return self._handle_type2abc(node, results, u"collections", u"Mapping") 71 72 @invocation("isinstance(%s, numbers.Number)") 73 def _isNumberType(self, node, results): 74 return self._handle_type2abc(node, results, u"numbers", u"Number") 75 76 def _handle_rename(self, node, results, name): 23 77 method = results["method"][0] 78 method.value = name 79 method.changed() 24 80 25 if method.value == u"sequenceIncludes": 26 if "module" not in results: 27 # operator may not be in scope, so we can't make a change. 28 self.warning(node, "You should use operator.contains here.") 81 def _handle_type2abc(self, node, results, module, abc): 82 touch_import(None, module, node) 83 obj = results["obj"] 84 args = [obj.clone(), String(u", " + u".".join([module, abc]))] 85 return Call(Name(u"isinstance"), args, prefix=node.prefix) 86 87 def _check_method(self, node, results): 88 method = getattr(self, "_" + results["method"][0].value.encode("ascii")) 89 if callable(method): 90 if "module" in results: 91 return method 29 92 else: 30 method.value = u"contains" 31 method.changed() 32 elif method.value == u"isCallable": 33 if "module" not in results: 34 self.warning(node, 35 "You should use hasattr(%s, '__call__') here." % 36 results["func"].value) 37 else: 38 func = results["func"] 39 args = [func.clone(), String(u", "), String(u"'__call__'")] 40 return Call(Name(u"hasattr"), args, prefix=node.prefix) 93 sub = (unicode(results["obj"]),) 94 invocation_str = unicode(method.invocation) % sub 95 self.warning(node, u"You should use '%s' here." % invocation_str) 96 return None -
python/trunk/Lib/lib2to3/fixes/fix_paren.py
r2 r391 11 11 # XXX This doesn't support nested for loops like [x for x in 1, 2 for x in 1, 2] 12 12 class FixParen(fixer_base.BaseFix): 13 BM_compatible = True 14 13 15 PATTERN = """ 14 16 atom< ('[' | '(') -
python/trunk/Lib/lib2to3/fixes/fix_print.py
r2 r391 28 28 29 29 class FixPrint(fixer_base.BaseFix): 30 31 BM_compatible = True 30 32 31 33 PATTERN = """ -
python/trunk/Lib/lib2to3/fixes/fix_raise.py
r2 r391 5 5 raise E, V -> raise E(V) 6 6 raise E, V, T -> raise E(V).with_traceback(T) 7 raise E, None, T -> raise E.with_traceback(T) 7 8 8 9 raise (((E, E'), E''), E'''), V -> raise E(V) … … 30 31 class FixRaise(fixer_base.BaseFix): 31 32 33 BM_compatible = True 32 34 PATTERN = """ 33 35 raise_stmt< 'raise' exc=any [',' val=any [',' tb=any]] > … … 38 40 39 41 exc = results["exc"].clone() 40 if exc.type is token.STRING: 41 self.cannot_convert(node, "Python 3 does not support string exceptions") 42 if exc.type == token.STRING: 43 msg = "Python 3 does not support string exceptions" 44 self.cannot_convert(node, msg) 42 45 return 43 46 … … 53 56 # exc.children[1].children[0] is the first element of the tuple 54 57 exc = exc.children[1].children[0].clone() 55 exc.prefix = " "58 exc.prefix = u" " 56 59 57 60 if "val" not in results: … … 72 75 tb.prefix = u"" 73 76 74 e = Call(exc, args) 77 e = exc 78 # If there's a traceback and None is passed as the value, then don't 79 # add a call, since the user probably just wants to add a 80 # traceback. See issue #9661. 81 if val.type != token.NAME or val.value != u"None": 82 e = Call(exc, args) 75 83 with_tb = Attr(e, Name(u'with_traceback')) + [ArgList([tb])] 76 84 new = pytree.Node(syms.simple_stmt, [Name(u"raise")] + with_tb) -
python/trunk/Lib/lib2to3/fixes/fix_raw_input.py
r2 r391 8 8 class FixRawInput(fixer_base.BaseFix): 9 9 10 BM_compatible = True 10 11 PATTERN = """ 11 12 power< name='raw_input' trailer< '(' [any] ')' > any* > -
python/trunk/Lib/lib2to3/fixes/fix_reduce.py
r2 r391 8 8 """ 9 9 10 from .. import pytree 11 from .. import fixer_base 12 from ..fixer_util import Name, Attr, touch_import 10 from lib2to3 import fixer_base 11 from lib2to3.fixer_util import touch_import 13 12 14 13 15 14 16 15 class FixReduce(fixer_base.BaseFix): 16 17 BM_compatible = True 18 order = "pre" 17 19 18 20 PATTERN = """ -
python/trunk/Lib/lib2to3/fixes/fix_renames.py
r2 r391 41 41 42 42 class FixRenames(fixer_base.BaseFix): 43 BM_compatible = True 43 44 PATTERN = "|".join(build_pattern()) 44 45 -
python/trunk/Lib/lib2to3/fixes/fix_repr.py
r2 r391 11 11 class FixRepr(fixer_base.BaseFix): 12 12 13 BM_compatible = True 13 14 PATTERN = """ 14 15 atom < '`' expr=any '`' > -
python/trunk/Lib/lib2to3/fixes/fix_set_literal.py
r2 r391 12 12 class FixSetLiteral(fixer_base.BaseFix): 13 13 14 BM_compatible = True 14 15 explicit = True 15 16 -
python/trunk/Lib/lib2to3/fixes/fix_standarderror.py
r2 r391 10 10 11 11 class FixStandarderror(fixer_base.BaseFix): 12 12 BM_compatible = True 13 13 PATTERN = """ 14 14 'StandardError' -
python/trunk/Lib/lib2to3/fixes/fix_sys_exc.py
r2 r391 14 14 class FixSysExc(fixer_base.BaseFix): 15 15 # This order matches the ordering of sys.exc_info(). 16 exc_info = ["exc_type", "exc_value", "exc_traceback"] 16 exc_info = [u"exc_type", u"exc_value", u"exc_traceback"] 17 BM_compatible = True 17 18 PATTERN = """ 18 19 power< 'sys' trailer< dot='.' attribute=(%s) > > -
python/trunk/Lib/lib2to3/fixes/fix_throw.py
r2 r391 15 15 16 16 class FixThrow(fixer_base.BaseFix): 17 17 BM_compatible = True 18 18 PATTERN = """ 19 19 power< any trailer< '.' 'throw' > -
python/trunk/Lib/lib2to3/fixes/fix_tuple_params.py
r2 r391 30 30 31 31 class FixTupleParams(fixer_base.BaseFix): 32 run_order = 4 #use a lower order since lambda is part of other 33 #patterns 34 BM_compatible = True 35 32 36 PATTERN = """ 33 37 funcdef< 'def' any parameters< '(' args=any ')' > … … 55 59 else: 56 60 start = 0 57 indent = "; "61 indent = u"; " 58 62 end = pytree.Leaf(token.INDENT, u"") 59 63 … … 155 159 d = {} 156 160 for i, obj in enumerate(param_list): 157 trailer = [Subscript(Number( i))]161 trailer = [Subscript(Number(unicode(i)))] 158 162 if isinstance(obj, list): 159 163 map_to_index(obj, trailer, d=d) -
python/trunk/Lib/lib2to3/fixes/fix_types.py
r2 r391 53 53 54 54 class FixTypes(fixer_base.BaseFix): 55 55 BM_compatible = True 56 56 PATTERN = '|'.join(_pats) 57 57 -
python/trunk/Lib/lib2to3/fixes/fix_unicode.py
r2 r391 1 """Fixer that changes unicode to str, unichr to chr, and u"..." into "...". 1 r"""Fixer for unicode. 2 3 * Changes unicode to str and unichr to chr. 4 5 * If "...\u..." is not unicode literal change it into "...\\u...". 6 7 * Change u"..." into "...". 2 8 3 9 """ 4 10 5 import re6 11 from ..pgen2 import token 7 12 from .. import fixer_base 8 13 9 14 _mapping = {u"unichr" : u"chr", u"unicode" : u"str"} 10 _literal_re = re.compile(ur"[uU][rR]?[\'\"]")11 15 12 16 class FixUnicode(fixer_base.BaseFix): 17 BM_compatible = True 18 PATTERN = "STRING | 'unicode' | 'unichr'" 13 19 14 PATTERN = "STRING | 'unicode' | 'unichr'" 20 def start_tree(self, tree, filename): 21 super(FixUnicode, self).start_tree(tree, filename) 22 self.unicode_literals = 'unicode_literals' in tree.future_features 15 23 16 24 def transform(self, node, results): … … 20 28 return new 21 29 elif node.type == token.STRING: 22 if _literal_re.match(node.value): 23 new = node.clone() 24 new.value = new.value[1:] 25 return new 30 val = node.value 31 if not self.unicode_literals and val[0] in u'\'"' and u'\\' in val: 32 val = ur'\\'.join([ 33 v.replace(u'\\u', ur'\\u').replace(u'\\U', ur'\\U') 34 for v in val.split(ur'\\') 35 ]) 36 if val[0] in u'uU': 37 val = val[1:] 38 if val == node.value: 39 return node 40 new = node.clone() 41 new.value = val 42 return new -
python/trunk/Lib/lib2to3/fixes/fix_urllib.py
r2 r391 6 6 7 7 # Local imports 8 from .fix_imports import alternates, FixImports 9 from .. import fixer_base 10 from ..fixer_util import Name, Comma, FromImport, Newline, attr_chain 8 from lib2to3.fixes.fix_imports import alternates, FixImports 9 from lib2to3 import fixer_base 10 from lib2to3.fixer_util import (Name, Comma, FromImport, Newline, 11 find_indentation, Node, syms) 11 12 12 MAPPING = { 'urllib': [13 ( 'urllib.request',14 [ 'URLOpener', 'FancyURLOpener', 'urlretrieve',15 '_urlopener', 'urlopen', 'urlcleanup',16 'pathname2url', 'url2pathname']),17 ( 'urllib.parse',18 [ 'quote', 'quote_plus', 'unquote', 'unquote_plus',19 'urlencode', 'splitattr', 'splithost', 'splitnport',20 'splitpasswd', 'splitport', 'splitquery', 'splittag',21 'splittype', 'splituser', 'splitvalue', ]),22 ( 'urllib.error',23 [ 'ContentTooShortError'])],24 'urllib2': [25 ( 'urllib.request',26 [ 'urlopen', 'install_opener', 'build_opener',27 'Request', 'OpenerDirector', 'BaseHandler',28 'HTTPDefaultErrorHandler', 'HTTPRedirectHandler',29 'HTTPCookieProcessor', 'ProxyHandler',30 'HTTPPasswordMgr',31 'HTTPPasswordMgrWithDefaultRealm',32 'AbstractBasicAuthHandler',33 'HTTPBasicAuthHandler', 'ProxyBasicAuthHandler',34 'AbstractDigestAuthHandler',35 'HTTPDigestAuthHandler', 'ProxyDigestAuthHandler',36 'HTTPHandler', 'HTTPSHandler', 'FileHandler',37 'FTPHandler', 'CacheFTPHandler',38 'UnknownHandler']),39 ( 'urllib.error',40 [ 'URLError', 'HTTPError']),13 MAPPING = {"urllib": [ 14 ("urllib.request", 15 ["URLopener", "FancyURLopener", "urlretrieve", 16 "_urlopener", "urlopen", "urlcleanup", 17 "pathname2url", "url2pathname"]), 18 ("urllib.parse", 19 ["quote", "quote_plus", "unquote", "unquote_plus", 20 "urlencode", "splitattr", "splithost", "splitnport", 21 "splitpasswd", "splitport", "splitquery", "splittag", 22 "splittype", "splituser", "splitvalue", ]), 23 ("urllib.error", 24 ["ContentTooShortError"])], 25 "urllib2" : [ 26 ("urllib.request", 27 ["urlopen", "install_opener", "build_opener", 28 "Request", "OpenerDirector", "BaseHandler", 29 "HTTPDefaultErrorHandler", "HTTPRedirectHandler", 30 "HTTPCookieProcessor", "ProxyHandler", 31 "HTTPPasswordMgr", 32 "HTTPPasswordMgrWithDefaultRealm", 33 "AbstractBasicAuthHandler", 34 "HTTPBasicAuthHandler", "ProxyBasicAuthHandler", 35 "AbstractDigestAuthHandler", 36 "HTTPDigestAuthHandler", "ProxyDigestAuthHandler", 37 "HTTPHandler", "HTTPSHandler", "FileHandler", 38 "FTPHandler", "CacheFTPHandler", 39 "UnknownHandler"]), 40 ("urllib.error", 41 ["URLError", "HTTPError"]), 41 42 ] 42 43 } … … 79 80 replacements. 80 81 """ 81 import_mod = results.get( 'module')82 import_mod = results.get("module") 82 83 pref = import_mod.prefix 83 84 … … 95 96 module. 96 97 """ 97 mod_member = results.get( 'mod_member')98 mod_member = results.get("mod_member") 98 99 pref = mod_member.prefix 99 member = results.get( 'member')100 member = results.get("member") 100 101 101 102 # Simple case with only a single member being imported … … 112 113 mod_member.replace(Name(new_name, prefix=pref)) 113 114 else: 114 self.cannot_convert(node, 115 'This is an invalid module element') 115 self.cannot_convert(node, "This is an invalid module element") 116 116 117 117 # Multiple members being imported … … 120 120 modules = [] 121 121 mod_dict = {} 122 members = results .get('members')122 members = results["members"] 123 123 for member in members: 124 member = member.value125 124 # we only care about the actual members 126 if member != ',': 125 if member.type == syms.import_as_name: 126 as_name = member.children[2].value 127 member_name = member.children[0].value 128 else: 129 member_name = member.value 130 as_name = None 131 if member_name != u",": 127 132 for change in MAPPING[mod_member.value]: 128 if member in change[1]: 129 if change[0] in mod_dict: 130 mod_dict[change[0]].append(member) 131 else: 132 mod_dict[change[0]] = [member] 133 if member_name in change[1]: 134 if change[0] not in mod_dict: 133 135 modules.append(change[0]) 136 mod_dict.setdefault(change[0], []).append(member) 134 137 135 138 new_nodes = [] 139 indentation = find_indentation(node) 140 first = True 141 def handle_name(name, prefix): 142 if name.type == syms.import_as_name: 143 kids = [Name(name.children[0].value, prefix=prefix), 144 name.children[1].clone(), 145 name.children[2].clone()] 146 return [Node(syms.import_as_name, kids)] 147 return [Name(name.value, prefix=prefix)] 136 148 for module in modules: 137 149 elts = mod_dict[module] 138 150 names = [] 139 151 for elt in elts[:-1]: 140 names.extend([Name(elt, prefix=pref), Comma()]) 141 names.append(Name(elts[-1], prefix=pref)) 142 new_nodes.append(FromImport(module, names)) 152 names.extend(handle_name(elt, pref)) 153 names.append(Comma()) 154 names.extend(handle_name(elts[-1], pref)) 155 new = FromImport(module, names) 156 if not first or node.parent.prefix.endswith(indentation): 157 new.prefix = indentation 158 new_nodes.append(new) 159 first = False 143 160 if new_nodes: 144 161 nodes = [] … … 148 165 node.replace(nodes) 149 166 else: 150 self.cannot_convert(node, 'All module elements are invalid')167 self.cannot_convert(node, "All module elements are invalid") 151 168 152 169 def transform_dot(self, node, results): 153 170 """Transform for calls to module members in code.""" 154 module_dot = results.get( 'bare_with_attr')155 member = results.get( 'member')171 module_dot = results.get("bare_with_attr") 172 member = results.get("member") 156 173 new_name = None 157 174 if isinstance(member, list): … … 165 182 prefix=module_dot.prefix)) 166 183 else: 167 self.cannot_convert(node, 'This is an invalid module element')184 self.cannot_convert(node, "This is an invalid module element") 168 185 169 186 def transform(self, node, results): 170 if results.get( 'module'):187 if results.get("module"): 171 188 self.transform_import(node, results) 172 elif results.get( 'mod_member'):189 elif results.get("mod_member"): 173 190 self.transform_member(node, results) 174 elif results.get( 'bare_with_attr'):191 elif results.get("bare_with_attr"): 175 192 self.transform_dot(node, results) 176 193 # Renaming and star imports are not supported for these modules. 177 elif results.get( 'module_star'):178 self.cannot_convert(node, 'Cannot handle star imports.')179 elif results.get( 'module_as'):180 self.cannot_convert(node, 'This module is now multiple modules')194 elif results.get("module_star"): 195 self.cannot_convert(node, "Cannot handle star imports.") 196 elif results.get("module_as"): 197 self.cannot_convert(node, "This module is now multiple modules") -
python/trunk/Lib/lib2to3/fixes/fix_xrange.py
r2 r391 11 11 12 12 class FixXrange(fixer_base.BaseFix): 13 13 BM_compatible = True 14 14 PATTERN = """ 15 15 power< … … 17 17 rest=any* > 18 18 """ 19 20 def start_tree(self, tree, filename): 21 super(FixXrange, self).start_tree(tree, filename) 22 self.transformed_xranges = set() 23 24 def finish_tree(self, tree, filename): 25 self.transformed_xranges = None 19 26 20 27 def transform(self, node, results): … … 30 37 name = results["name"] 31 38 name.replace(Name(u"range", prefix=name.prefix)) 39 # This prevents the new range call from being wrapped in a list later. 40 self.transformed_xranges.add(id(node)) 32 41 33 42 def transform_range(self, node, results): 34 if not self.in_special_context(node): 43 if (id(node) not in self.transformed_xranges and 44 not self.in_special_context(node)): 35 45 range_call = Call(Name(u"range"), [results["args"].clone()]) 36 46 # Encase the range call in list(). -
python/trunk/Lib/lib2to3/fixes/fix_xreadlines.py
r2 r391 10 10 11 11 class FixXreadlines(fixer_base.BaseFix): 12 BM_compatible = True 12 13 PATTERN = """ 13 14 power< call=any+ trailer< '.' 'xreadlines' > trailer< '(' ')' > > -
python/trunk/Lib/lib2to3/fixes/fix_zip.py
r2 r391 14 14 class FixZip(fixer_base.ConditionalFix): 15 15 16 BM_compatible = True 16 17 PATTERN = """ 17 18 power< 'zip' args=trailer< '(' [any] ')' > -
python/trunk/Lib/lib2to3/main.py
r2 r391 2 2 Main program for 2to3. 3 3 """ 4 5 from __future__ import with_statement 4 6 5 7 import sys … … 24 26 class StdoutRefactoringTool(refactor.MultiprocessRefactoringTool): 25 27 """ 28 A refactoring tool that can avoid overwriting its input files. 26 29 Prints output to stdout. 30 31 Output files can optionally be written to a different directory and or 32 have an extra file suffix appended to their name for use in situations 33 where you do not want to replace the input files. 27 34 """ 28 35 29 def __init__(self, fixers, options, explicit, nobackups, show_diffs): 36 def __init__(self, fixers, options, explicit, nobackups, show_diffs, 37 input_base_dir='', output_dir='', append_suffix=''): 38 """ 39 Args: 40 fixers: A list of fixers to import. 41 options: A dict with RefactoringTool configuration. 42 explicit: A list of fixers to run even if they are explicit. 43 nobackups: If true no backup '.bak' files will be created for those 44 files that are being refactored. 45 show_diffs: Should diffs of the refactoring be printed to stdout? 46 input_base_dir: The base directory for all input files. This class 47 will strip this path prefix off of filenames before substituting 48 it with output_dir. Only meaningful if output_dir is supplied. 49 All files processed by refactor() must start with this path. 50 output_dir: If supplied, all converted files will be written into 51 this directory tree instead of input_base_dir. 52 append_suffix: If supplied, all files output by this tool will have 53 this appended to their filename. Useful for changing .py to 54 .py3 for example by passing append_suffix='3'. 55 """ 30 56 self.nobackups = nobackups 31 57 self.show_diffs = show_diffs 58 if input_base_dir and not input_base_dir.endswith(os.sep): 59 input_base_dir += os.sep 60 self._input_base_dir = input_base_dir 61 self._output_dir = output_dir 62 self._append_suffix = append_suffix 32 63 super(StdoutRefactoringTool, self).__init__(fixers, options, explicit) 33 64 … … 37 68 38 69 def write_file(self, new_text, filename, old_text, encoding): 70 orig_filename = filename 71 if self._output_dir: 72 if filename.startswith(self._input_base_dir): 73 filename = os.path.join(self._output_dir, 74 filename[len(self._input_base_dir):]) 75 else: 76 raise ValueError('filename %s does not start with the ' 77 'input_base_dir %s' % ( 78 filename, self._input_base_dir)) 79 if self._append_suffix: 80 filename += self._append_suffix 81 if orig_filename != filename: 82 output_dir = os.path.dirname(filename) 83 if not os.path.isdir(output_dir): 84 os.makedirs(output_dir) 85 self.log_message('Writing converted %s to %s.', orig_filename, 86 filename) 39 87 if not self.nobackups: 40 88 # Make backup … … 54 102 if not self.nobackups: 55 103 shutil.copymode(backup, filename) 104 if orig_filename != filename: 105 # Preserve the file mode in the new output directory. 106 shutil.copymode(orig_filename, filename) 56 107 57 108 def print_output(self, old, new, filename, equal): … … 63 114 diff_lines = diff_texts(old, new, filename) 64 115 try: 65 for line in diff_lines: 66 print line 116 if self.output_lock is not None: 117 with self.output_lock: 118 for line in diff_lines: 119 print line 120 sys.stdout.flush() 121 else: 122 for line in diff_lines: 123 print line 67 124 except UnicodeEncodeError: 68 125 warn("couldn't encode %s's diff for your terminal" % … … 94 151 type="int", help="Run 2to3 concurrently") 95 152 parser.add_option("-x", "--nofix", action="append", default=[], 96 help="Prevent a fixer from being run.")153 help="Prevent a transformation from being run") 97 154 parser.add_option("-l", "--list-fixes", action="store_true", 98 help="List available transformations (fixes/fix_*.py)")155 help="List available transformations") 99 156 parser.add_option("-p", "--print-function", action="store_true", 100 157 help="Modify the grammar so that print() is a function") … … 106 163 help="Write back modified files") 107 164 parser.add_option("-n", "--nobackups", action="store_true", default=False, 108 help="Don't write backups for modified files.") 165 help="Don't write backups for modified files") 166 parser.add_option("-o", "--output-dir", action="store", type="str", 167 default="", help="Put output files in this directory " 168 "instead of overwriting the input files. Requires -n.") 169 parser.add_option("-W", "--write-unchanged-files", action="store_true", 170 help="Also write files even if no changes were required" 171 " (useful with --output-dir); implies -w.") 172 parser.add_option("--add-suffix", action="store", type="str", default="", 173 help="Append this string to all output filenames." 174 " Requires -n if non-empty. " 175 "ex: --add-suffix='3' will generate .py3 files.") 109 176 110 177 # Parse command line arguments … … 112 179 flags = {} 113 180 options, args = parser.parse_args(args) 181 if options.write_unchanged_files: 182 flags["write_unchanged_files"] = True 183 if not options.write: 184 warn("--write-unchanged-files/-W implies -w.") 185 options.write = True 186 # If we allowed these, the original files would be renamed to backup names 187 # but not replaced. 188 if options.output_dir and not options.nobackups: 189 parser.error("Can't use --output-dir/-o without -n.") 190 if options.add_suffix and not options.nobackups: 191 parser.error("Can't use --add-suffix without -n.") 192 114 193 if not options.write and options.no_diffs: 115 194 warn("not writing files and not printing diffs; that's not very useful") … … 137 216 level = logging.DEBUG if options.verbose else logging.INFO 138 217 logging.basicConfig(format='%(name)s: %(message)s', level=level) 218 logger = logging.getLogger('lib2to3.main') 139 219 140 220 # Initialize the refactoring tool … … 153 233 requested = avail_fixes.union(explicit) 154 234 fixer_names = requested.difference(unwanted_fixes) 155 rt = StdoutRefactoringTool(sorted(fixer_names), flags, sorted(explicit), 156 options.nobackups, not options.no_diffs) 235 input_base_dir = os.path.commonprefix(args) 236 if (input_base_dir and not input_base_dir.endswith(os.sep) 237 and not os.path.isdir(input_base_dir)): 238 # One or more similar names were passed, their directory is the base. 239 # os.path.commonprefix() is ignorant of path elements, this corrects 240 # for that weird API. 241 input_base_dir = os.path.dirname(input_base_dir) 242 if options.output_dir: 243 input_base_dir = input_base_dir.rstrip(os.sep) 244 logger.info('Output in %r will mirror the input directory %r layout.', 245 options.output_dir, input_base_dir) 246 rt = StdoutRefactoringTool( 247 sorted(fixer_names), flags, sorted(explicit), 248 options.nobackups, not options.no_diffs, 249 input_base_dir=input_base_dir, 250 output_dir=options.output_dir, 251 append_suffix=options.add_suffix) 157 252 158 253 # Refactor all files and directories passed as arguments -
python/trunk/Lib/lib2to3/patcomp.py
r2 r391 13 13 # Python imports 14 14 import os 15 import StringIO 15 16 16 17 # Fairly local imports … … 33 34 """Tokenizes a string suppressing significant whitespace.""" 34 35 skip = set((token.NEWLINE, token.INDENT, token.DEDENT)) 35 tokens = tokenize.generate_tokens( driver.generate_lines(input).next)36 tokens = tokenize.generate_tokens(StringIO.StringIO(input).readline) 36 37 for quintuple in tokens: 37 38 type, value, start, end, line_text = quintuple … … 53 54 self.driver = driver.Driver(self.grammar, convert=pattern_convert) 54 55 55 def compile_pattern(self, input, debug=False ):56 def compile_pattern(self, input, debug=False, with_tree=False): 56 57 """Compiles a pattern string to a nested pytree.*Pattern object.""" 57 58 tokens = tokenize_wrapper(input) … … 60 61 except parse.ParseError as e: 61 62 raise PatternSyntaxError(str(e)) 62 return self.compile_node(root) 63 if with_tree: 64 return self.compile_node(root), root 65 else: 66 return self.compile_node(root) 63 67 64 68 def compile_node(self, node): -
python/trunk/Lib/lib2to3/pgen2/conv.py
r2 r391 52 52 53 53 def parse_graminit_h(self, filename): 54 """Parse the .h file writ en by pgen. (Internal)54 """Parse the .h file written by pgen. (Internal) 55 55 56 56 This file is a sequence of #define statements defining the … … 83 83 84 84 def parse_graminit_c(self, filename): 85 """Parse the .c file writ en by pgen. (Internal)85 """Parse the .c file written by pgen. (Internal) 86 86 87 87 The file looks as follows. The first two lines are always this: -
python/trunk/Lib/lib2to3/pgen2/driver.py
r2 r391 20 20 import os 21 21 import logging 22 import StringIO 22 23 import sys 23 24 … … 102 103 def parse_string(self, text, debug=False): 103 104 """Parse a string and return the syntax tree.""" 104 tokens = tokenize.generate_tokens( generate_lines(text).next)105 tokens = tokenize.generate_tokens(StringIO.StringIO(text).readline) 105 106 return self.parse_tokens(tokens, debug) 106 107 108 def generate_lines(text):109 """Generator that behaves like readline without using StringIO."""110 for line in text.splitlines(True):111 yield line112 while True:113 yield ""114 107 115 108 … … 146 139 return True 147 140 return os.path.getmtime(a) >= os.path.getmtime(b) 141 142 143 def main(*args): 144 """Main program, when run as a script: produce grammar pickle files. 145 146 Calls load_grammar for each argument, a path to a grammar text file. 147 """ 148 if not args: 149 args = sys.argv[1:] 150 logging.basicConfig(level=logging.INFO, stream=sys.stdout, 151 format='%(message)s') 152 for gt in args: 153 load_grammar(gt, save=True, force=True) 154 return True 155 156 if __name__ == "__main__": 157 sys.exit(int(not main())) -
python/trunk/Lib/lib2to3/pgen2/grammar.py
r2 r391 21 21 22 22 class Grammar(object): 23 """Pgen parsing tables tablesconversion class.23 """Pgen parsing tables conversion class. 24 24 25 25 Once initialized, this class supplies the grammar tables for the … … 46 46 47 47 states -- a list of DFAs, where each DFA is a list of 48 states, each state is isa list of arcs, and each48 states, each state is a list of arcs, and each 49 49 arc is a (i, j) pair where i is a label and j is 50 50 a state number. The DFA number is the index into -
python/trunk/Lib/lib2to3/pgen2/tokenize.py
r2 r391 38 38 "generate_tokens", "untokenize"] 39 39 del token 40 41 try: 42 bytes 43 except NameError: 44 # Support bytes type in Python <= 2.5, so 2to3 turns itself into 45 # valid Python 3 code. 46 bytes = str 40 47 41 48 def group(*choices): return '(' + '|'.join(choices) + ')' … … 230 237 toks_append(tokval) 231 238 232 cookie_re = re.compile( "coding[:=]\s*([-\w.]+)")239 cookie_re = re.compile(r'^[ \t\f]*#.*coding[:=][ \t]*([-\w.]+)') 233 240 234 241 def _get_normal_name(orig_enc): … … 254 261 255 262 It detects the encoding from the presence of a utf-8 bom or an encoding 256 cookie as specified in pep-0263. If both a bom and a cookie are present, 257 but disagree, a SyntaxError will be raised. If the encoding cookie is an 258 invalid charset, raise a SyntaxError. 263 cookie as specified in pep-0263. If both a bom and a cookie are present, but 264 disagree, a SyntaxError will be raised. If the encoding cookie is an invalid 265 charset, raise a SyntaxError. Note that if a utf-8 bom is found, 266 'utf-8-sig' is returned. 259 267 260 268 If no encoding is specified, then the default of 'utf-8' will be returned. … … 262 270 bom_found = False 263 271 encoding = None 272 default = 'utf-8' 264 273 def read_or_stop(): 265 274 try: 266 275 return readline() 267 276 except StopIteration: 268 return b ''277 return bytes() 269 278 270 279 def find_cookie(line): … … 273 282 except UnicodeDecodeError: 274 283 return None 275 276 matches = cookie_re.findall(line_string) 277 if not matches: 284 match = cookie_re.match(line_string) 285 if not match: 278 286 return None 279 encoding = _get_normal_name(match es[0])287 encoding = _get_normal_name(match.group(1)) 280 288 try: 281 289 codec = lookup(encoding) … … 288 296 # This behaviour mimics the Python interpreter 289 297 raise SyntaxError('encoding problem: utf-8') 290 else: 291 # Allow it to be properly encoded and decoded. 292 encoding = 'utf-8-sig' 298 encoding += '-sig' 293 299 return encoding 294 300 … … 297 303 bom_found = True 298 304 first = first[3:] 305 default = 'utf-8-sig' 299 306 if not first: 300 return 'utf-8', []307 return default, [] 301 308 302 309 encoding = find_cookie(first) … … 306 313 second = read_or_stop() 307 314 if not second: 308 return 'utf-8', [first]315 return default, [first] 309 316 310 317 encoding = find_cookie(second) … … 312 319 return encoding, [first, second] 313 320 314 return 'utf-8', [first, second]321 return default, [first, second] 315 322 316 323 def untokenize(iterable): -
python/trunk/Lib/lib2to3/pygram.py
r2 r391 14 14 # The grammar file 15 15 _GRAMMAR_FILE = os.path.join(os.path.dirname(__file__), "Grammar.txt") 16 _PATTERN_GRAMMAR_FILE = os.path.join(os.path.dirname(__file__), 17 "PatternGrammar.txt") 16 18 17 19 … … 34 36 python_grammar_no_print_statement = python_grammar.copy() 35 37 del python_grammar_no_print_statement.keywords["print"] 38 39 pattern_grammar = driver.load_grammar(_PATTERN_GRAMMAR_FILE) 40 pattern_symbols = Symbols(pattern_grammar) -
python/trunk/Lib/lib2to3/pytree.py
r2 r391 16 16 import warnings 17 17 from StringIO import StringIO 18 19 18 20 19 HUGE = 0x7FFFFFFF # maximum repeat count, default max … … 31 30 return _type_reprs.setdefault(type_num, type_num) 32 31 33 34 32 class Base(object): 35 33 … … 48 46 children = () # Tuple of subnodes 49 47 was_changed = False 48 was_checked = False 50 49 51 50 def __new__(cls, *args, **kwds): … … 214 213 return self.parent.children[i-1] 215 214 215 def leaves(self): 216 for child in self.children: 217 for x in child.leaves(): 218 yield x 219 220 def depth(self): 221 if self.parent is None: 222 return 0 223 return 1 + self.parent.depth() 224 216 225 def get_suffix(self): 217 226 """ … … 228 237 return unicode(self).encode("ascii") 229 238 230 231 239 class Node(Base): 232 240 233 241 """Concrete implementation for interior nodes.""" 234 242 235 def __init__(self, type, children, context=None, prefix=None): 243 def __init__(self,type, children, 244 context=None, 245 prefix=None, 246 fixers_applied=None): 236 247 """ 237 248 Initializer. … … 250 261 if prefix is not None: 251 262 self.prefix = prefix 263 if fixers_applied: 264 self.fixers_applied = fixers_applied[:] 265 else: 266 self.fixers_applied = None 252 267 253 268 def __repr__(self): … … 274 289 def clone(self): 275 290 """Return a cloned (deep) copy of self.""" 276 return Node(self.type, [ch.clone() for ch in self.children]) 291 return Node(self.type, [ch.clone() for ch in self.children], 292 fixers_applied=self.fixers_applied) 277 293 278 294 def post_order(self): … … 287 303 yield self 288 304 for child in self.children: 289 for node in child.p ost_order():305 for node in child.pre_order(): 290 306 yield node 291 307 292 @property 293 def prefix(self): 308 def _prefix_getter(self): 294 309 """ 295 310 The whitespace and comments preceding this node in the input. … … 299 314 return self.children[0].prefix 300 315 301 @prefix.setter 302 def prefix(self, prefix): 316 def _prefix_setter(self, prefix): 303 317 if self.children: 304 318 self.children[0].prefix = prefix 319 320 prefix = property(_prefix_getter, _prefix_setter) 305 321 306 322 def set_child(self, i, child): … … 342 358 column = 0 # Column where this token tarts in the input 343 359 344 def __init__(self, type, value, context=None, prefix=None): 360 def __init__(self, type, value, 361 context=None, 362 prefix=None, 363 fixers_applied=[]): 345 364 """ 346 365 Initializer. … … 356 375 if prefix is not None: 357 376 self._prefix = prefix 377 self.fixers_applied = fixers_applied[:] 358 378 359 379 def __repr__(self): … … 381 401 """Return a cloned (deep) copy of self.""" 382 402 return Leaf(self.type, self.value, 383 (self.prefix, (self.lineno, self.column))) 403 (self.prefix, (self.lineno, self.column)), 404 fixers_applied=self.fixers_applied) 405 406 def leaves(self): 407 yield self 384 408 385 409 def post_order(self): … … 391 415 yield self 392 416 393 @property 394 def prefix(self): 417 def _prefix_getter(self): 395 418 """ 396 419 The whitespace and comments preceding this token in the input. … … 398 421 return self._prefix 399 422 400 @prefix.setter 401 def prefix(self, prefix): 423 def _prefix_setter(self, prefix): 402 424 self.changed() 403 425 self._prefix = prefix 404 426 427 prefix = property(_prefix_getter, _prefix_setter) 405 428 406 429 def convert(gr, raw_node): … … 636 659 if absent, matches one node; 637 660 if present, each subsequence is an alternative [*] 638 min: opti nal minumum number of times to match, default 0639 max: optional maximum number of times t ro match, default HUGE661 min: optional minimum number of times to match, default 0 662 max: optional maximum number of times to match, default HUGE 640 663 name: optional name assigned to this match 641 664 … … 721 744 # The reason for this is that hitting the recursion limit usually 722 745 # results in some ugly messages about how RuntimeErrors are being 723 # ignored. 724 save_stderr = sys.stderr 725 sys.stderr = StringIO() 746 # ignored. We don't do this on non-CPython implementation because 747 # they don't have this problem. 748 if hasattr(sys, "getrefcount"): 749 save_stderr = sys.stderr 750 sys.stderr = StringIO() 726 751 try: 727 752 for count, r in self._recursive_matches(nodes, 0): … … 737 762 yield count, r 738 763 finally: 739 sys.stderr = save_stderr 764 if hasattr(sys, "getrefcount"): 765 sys.stderr = save_stderr 740 766 741 767 def _iterative_matches(self, nodes): -
python/trunk/Lib/lib2to3/refactor.py
r2 r391 8 8 provides infrastructure to write your own refactoring tool. 9 9 """ 10 11 from __future__ import with_statement 10 12 11 13 __author__ = "Guido van Rossum <guido@python.org>" … … 23 25 # Local imports 24 26 from .pgen2 import driver, tokenize, token 27 from .fixer_util import find_root 25 28 from . import pytree, pygram 29 from . import btm_utils as bu 30 from . import btm_matcher as bm 26 31 27 32 … … 123 128 124 129 125 def _detect_future_ print(source):130 def _detect_future_features(source): 126 131 have_docstring = False 127 132 gen = tokenize.generate_tokens(StringIO.StringIO(source).readline) 128 133 def advance(): 129 tok = next(gen)134 tok = gen.next() 130 135 return tok[0], tok[1] 131 136 ignore = frozenset((token.NEWLINE, tokenize.NL, token.COMMENT)) 137 features = set() 132 138 try: 133 139 while True: … … 141 147 elif tp == token.NAME and value == u"from": 142 148 tp, value = advance() 143 if tp != token.NAME andvalue != u"__future__":149 if tp != token.NAME or value != u"__future__": 144 150 break 145 151 tp, value = advance() 146 if tp != token.NAME andvalue != u"import":152 if tp != token.NAME or value != u"import": 147 153 break 148 154 tp, value = advance() … … 150 156 tp, value = advance() 151 157 while tp == token.NAME: 152 if value == u"print_function": 153 return True 158 features.add(value) 154 159 tp, value = advance() 155 if tp != token.OP andvalue != u",":160 if tp != token.OP or value != u",": 156 161 break 157 162 tp, value = advance() … … 160 165 except StopIteration: 161 166 pass 162 return False167 return frozenset(features) 163 168 164 169 … … 169 174 class RefactoringTool(object): 170 175 171 _default_options = {"print_function" : False} 176 _default_options = {"print_function" : False, 177 "write_unchanged_files" : False} 172 178 173 179 CLASS_PREFIX = "Fix" # The prefix for fixer classes … … 191 197 else: 192 198 self.grammar = pygram.python_grammar 199 # When this is True, the refactor*() methods will call write_file() for 200 # files processed even if they were not changed during refactoring. If 201 # and only if the refactor method's write parameter was True. 202 self.write_unchanged_files = self.options.get("write_unchanged_files") 193 203 self.errors = [] 194 204 self.logger = logging.getLogger("RefactoringTool") … … 200 210 self.pre_order, self.post_order = self.get_fixers() 201 211 202 self.pre_order_heads = _get_headnode_dict(self.pre_order)203 self.post_order_heads = _get_headnode_dict(self.post_order)204 212 205 213 self.files = [] # List of files that were or should be modified 214 215 self.BM = bm.BottomMatcher() 216 self.bmi_pre_order = [] # Bottom Matcher incompatible fixers 217 self.bmi_post_order = [] 218 219 for fixer in chain(self.post_order, self.pre_order): 220 if fixer.BM_compatible: 221 self.BM.add_fixer(fixer) 222 # remove fixers that will be handled by the bottom-up 223 # matcher 224 elif fixer in self.pre_order: 225 self.bmi_pre_order.append(fixer) 226 elif fixer in self.post_order: 227 self.bmi_post_order.append(fixer) 228 229 self.bmi_pre_order_heads = _get_headnode_dict(self.bmi_pre_order) 230 self.bmi_post_order_heads = _get_headnode_dict(self.bmi_post_order) 231 232 206 233 207 234 def get_fixers(self): … … 267 294 def refactor(self, items, write=False, doctests_only=False): 268 295 """Refactor a list of files and directories.""" 296 269 297 for dir_or_file in items: 270 298 if os.path.isdir(dir_or_file): … … 280 308 Files and subdirectories starting with '.' are skipped. 281 309 """ 310 py_ext = os.extsep + "py" 282 311 for dirpath, dirnames, filenames in os.walk(dir_name): 283 312 self.log_debug("Descending into %s", dirpath) … … 285 314 filenames.sort() 286 315 for name in filenames: 287 if not name.startswith(".") and \288 os.path.splitext(name)[1].endswith("py"):316 if (not name.startswith(".") and 317 os.path.splitext(name)[1] == py_ext): 289 318 fullname = os.path.join(dirpath, name) 290 319 self.refactor_file(fullname, write, doctests_only) … … 298 327 try: 299 328 f = open(filename, "rb") 300 except IOError ,err:329 except IOError as err: 301 330 self.log_error("Can't open %s: %s", filename, err) 302 331 return None, None … … 318 347 self.log_debug("Refactoring doctests in %s", filename) 319 348 output = self.refactor_docstring(input, filename) 320 if output != input:349 if self.write_unchanged_files or output != input: 321 350 self.processed_file(output, filename, input, write, encoding) 322 351 else: … … 324 353 else: 325 354 tree = self.refactor_string(input, filename) 326 if tree and tree.was_changed:355 if self.write_unchanged_files or (tree and tree.was_changed): 327 356 # The [:-1] is to take off the \n we added earlier 328 357 self.processed_file(unicode(tree)[:-1], filename, … … 342 371 there were errors during the parse. 343 372 """ 344 if _detect_future_print(data): 373 features = _detect_future_features(data) 374 if "print_function" in features: 345 375 self.driver.grammar = pygram.python_grammar_no_print_statement 346 376 try: 347 377 tree = self.driver.parse_string(data) 348 except Exception ,err:378 except Exception as err: 349 379 self.log_error("Can't parse %s: %s: %s", 350 380 name, err.__class__.__name__, err) … … 352 382 finally: 353 383 self.driver.grammar = self.grammar 384 tree.future_features = features 354 385 self.log_debug("Refactoring %s", name) 355 386 self.refactor_tree(tree, name) … … 361 392 self.log_debug("Refactoring doctests in stdin") 362 393 output = self.refactor_docstring(input, "<stdin>") 363 if output != input:394 if self.write_unchanged_files or output != input: 364 395 self.processed_file(output, "<stdin>", input) 365 396 else: … … 367 398 else: 368 399 tree = self.refactor_string(input, "<stdin>") 369 if tree and tree.was_changed:400 if self.write_unchanged_files or (tree and tree.was_changed): 370 401 self.processed_file(unicode(tree), "<stdin>", input) 371 402 else: … … 374 405 def refactor_tree(self, tree, name): 375 406 """Refactors a parse tree (modifying the tree in place). 407 408 For compatible patterns the bottom matcher module is 409 used. Otherwise the tree is traversed node-to-node for 410 matches. 376 411 377 412 Args: … … 383 418 True if the tree was modified, False otherwise. 384 419 """ 420 385 421 for fixer in chain(self.pre_order, self.post_order): 386 422 fixer.start_tree(tree, name) 387 423 388 self.traverse_by(self.pre_order_heads, tree.pre_order()) 389 self.traverse_by(self.post_order_heads, tree.post_order()) 424 #use traditional matching for the incompatible fixers 425 self.traverse_by(self.bmi_pre_order_heads, tree.pre_order()) 426 self.traverse_by(self.bmi_post_order_heads, tree.post_order()) 427 428 # obtain a set of candidate nodes 429 match_set = self.BM.run(tree.leaves()) 430 431 while any(match_set.values()): 432 for fixer in self.BM.fixers: 433 if fixer in match_set and match_set[fixer]: 434 #sort by depth; apply fixers from bottom(of the AST) to top 435 match_set[fixer].sort(key=pytree.Base.depth, reverse=True) 436 437 if fixer.keep_line_order: 438 #some fixers(eg fix_imports) must be applied 439 #with the original file's line order 440 match_set[fixer].sort(key=pytree.Base.get_lineno) 441 442 for node in list(match_set[fixer]): 443 if node in match_set[fixer]: 444 match_set[fixer].remove(node) 445 446 try: 447 find_root(node) 448 except ValueError: 449 # this node has been cut off from a 450 # previous transformation ; skip 451 continue 452 453 if node.fixers_applied and fixer in node.fixers_applied: 454 # do not apply the same fixer again 455 continue 456 457 results = fixer.match(node) 458 459 if results: 460 new = fixer.transform(node, results) 461 if new is not None: 462 node.replace(new) 463 #new.fixers_applied.append(fixer) 464 for node in new.post_order(): 465 # do not apply the fixer again to 466 # this or any subnode 467 if not node.fixers_applied: 468 node.fixers_applied = [] 469 node.fixers_applied.append(fixer) 470 471 # update the original match set for 472 # the added code 473 new_matches = self.BM.run(new.leaves()) 474 for fxr in new_matches: 475 if not fxr in match_set: 476 match_set[fxr]=[] 477 478 match_set[fxr].extend(new_matches[fxr]) 390 479 391 480 for fixer in chain(self.pre_order, self.post_order): … … 419 508 encoding=None): 420 509 """ 421 Called when a file has been refactored , and there are changes.510 Called when a file has been refactored and there may be changes. 422 511 """ 423 512 self.files.append(filename) … … 430 519 if equal: 431 520 self.log_debug("No changes to %s", filename) 432 return 521 if not self.write_unchanged_files: 522 return 433 523 if write: 434 524 self.write_file(new_text, filename, old_text, encoding) … … 445 535 try: 446 536 f = _open_with_encoding(filename, "w", encoding=encoding) 447 except os.error ,err:537 except os.error as err: 448 538 self.log_error("Can't create %s: %s", filename, err) 449 539 return 450 540 try: 451 541 f.write(_to_system_newlines(new_text)) 452 except os.error ,err:542 except os.error as err: 453 543 self.log_error("Can't write %s: %s", filename, err) 454 544 finally: … … 513 603 try: 514 604 tree = self.parse_block(block, lineno, indent) 515 except Exception ,err:516 if self.log .isEnabledFor(logging.DEBUG):605 except Exception as err: 606 if self.logger.isEnabledFor(logging.DEBUG): 517 607 for line in block: 518 608 self.log_debug("Source: %s", line.rstrip(u"\n")) … … 561 651 in the parser diagnostics and embedded into the parse tree. 562 652 """ 563 return self.driver.parse_tokens(self.wrap_toks(block, lineno, indent)) 653 tree = self.driver.parse_tokens(self.wrap_toks(block, lineno, indent)) 654 tree.future_features = frozenset() 655 return tree 564 656 565 657 def wrap_toks(self, block, lineno, indent): … … 606 698 super(MultiprocessRefactoringTool, self).__init__(*args, **kwargs) 607 699 self.queue = None 700 self.output_lock = None 608 701 609 702 def refactor(self, items, write=False, doctests_only=False, … … 619 712 raise RuntimeError("already doing multiple processes") 620 713 self.queue = multiprocessing.JoinableQueue() 714 self.output_lock = multiprocessing.Lock() 621 715 processes = [multiprocessing.Process(target=self._child) 622 716 for i in xrange(num_processes)] -
python/trunk/Lib/lib2to3/tests/data/bom.py
r2 r391 1 1 # coding: utf-8 2 2 print "BOM BOOM!" 3 -
python/trunk/Lib/lib2to3/tests/data/py2_test_grammar.py
r2 r391 317 317 x = 1; pass; del x 318 318 def foo(): 319 # verify stat ments that end with semi-colons319 # verify statements that end with semi-colons 320 320 x = 1; pass; del x; 321 321 foo() -
python/trunk/Lib/lib2to3/tests/data/py3_test_grammar.py
r2 r391 357 357 x = 1; pass; del x 358 358 def foo(): 359 # verify stat ments that end with semi-colons359 # verify statements that end with semi-colons 360 360 x = 1; pass; del x; 361 361 foo() -
python/trunk/Lib/lib2to3/tests/test_fixers.py
r2 r391 869 869 self.check(b, a) 870 870 871 def test_None_value(self): 872 b = """raise Exception(5), None, tb""" 873 a = """raise Exception(5).with_traceback(tb)""" 874 self.check(b, a) 875 871 876 def test_tuple_value(self): 872 877 b = """raise Exception, (5, 6, 7)""" … … 1401 1406 self.check(b, a) 1402 1407 1403 def test_ 14(self):1408 def test_28(self): 1404 1409 b = "[i for i in d.viewkeys()]" 1405 1410 a = "[i for i in d.keys()]" 1406 1411 self.check(b, a) 1407 1412 1408 def test_ 15(self):1413 def test_29(self): 1409 1414 b = "(i for i in d.viewkeys())" 1410 1415 a = "(i for i in d.keys())" 1411 1416 self.check(b, a) 1412 1417 1413 def test_ 17(self):1418 def test_30(self): 1414 1419 b = "iter(d.viewkeys())" 1415 1420 a = "iter(d.keys())" 1416 1421 self.check(b, a) 1417 1422 1418 def test_ 18(self):1423 def test_31(self): 1419 1424 b = "list(d.viewkeys())" 1420 1425 a = "list(d.keys())" 1421 1426 self.check(b, a) 1422 1427 1423 def test_ 19(self):1428 def test_32(self): 1424 1429 b = "sorted(d.viewkeys())" 1425 1430 a = "sorted(d.keys())" … … 1497 1502 for call in fixer_util.consuming_calls: 1498 1503 self.unchanged("a = %s(range(10))" % call) 1504 1505 class Test_xrange_with_reduce(FixerTestCase): 1506 1507 def setUp(self): 1508 super(Test_xrange_with_reduce, self).setUp(["xrange", "reduce"]) 1509 1510 def test_double_transform(self): 1511 b = """reduce(x, xrange(5))""" 1512 a = """from functools import reduce 1513 reduce(x, range(5))""" 1514 self.check(b, a) 1499 1515 1500 1516 class Test_raw_input(FixerTestCase): … … 1802 1818 a = "from %s import %s as foo_bar" % (new, member) 1803 1819 self.check(b, a) 1820 b = "from %s import %s as blah, %s" % (old, member, member) 1821 a = "from %s import %s as blah, %s" % (new, member, member) 1822 self.check(b, a) 1804 1823 1805 1824 def test_star(self): … … 1807 1826 s = "from %s import *" % old 1808 1827 self.warns_unchanged(s, "Cannot handle star imports") 1828 1829 def test_indented(self): 1830 b = """ 1831 def foo(): 1832 from urllib import urlencode, urlopen 1833 """ 1834 a = """ 1835 def foo(): 1836 from urllib.parse import urlencode 1837 from urllib.request import urlopen 1838 """ 1839 self.check(b, a) 1840 1841 b = """ 1842 def foo(): 1843 other() 1844 from urllib import urlencode, urlopen 1845 """ 1846 a = """ 1847 def foo(): 1848 other() 1849 from urllib.parse import urlencode 1850 from urllib.request import urlopen 1851 """ 1852 self.check(b, a) 1853 1854 1809 1855 1810 1856 def test_import_module_usage(self): … … 2779 2825 self.check(b, a) 2780 2826 2827 def test_native_literal_escape_u(self): 2828 b = """'\\\\\\u20ac\\U0001d121\\\\u20ac'""" 2829 a = """'\\\\\\\\u20ac\\\\U0001d121\\\\u20ac'""" 2830 self.check(b, a) 2831 2832 b = """r'\\\\\\u20ac\\U0001d121\\\\u20ac'""" 2833 a = """r'\\\\\\u20ac\\U0001d121\\\\u20ac'""" 2834 self.check(b, a) 2835 2836 def test_bytes_literal_escape_u(self): 2837 b = """b'\\\\\\u20ac\\U0001d121\\\\u20ac'""" 2838 a = """b'\\\\\\u20ac\\U0001d121\\\\u20ac'""" 2839 self.check(b, a) 2840 2841 b = """br'\\\\\\u20ac\\U0001d121\\\\u20ac'""" 2842 a = """br'\\\\\\u20ac\\U0001d121\\\\u20ac'""" 2843 self.check(b, a) 2844 2845 def test_unicode_literal_escape_u(self): 2846 b = """u'\\\\\\u20ac\\U0001d121\\\\u20ac'""" 2847 a = """'\\\\\\u20ac\\U0001d121\\\\u20ac'""" 2848 self.check(b, a) 2849 2850 b = """ur'\\\\\\u20ac\\U0001d121\\\\u20ac'""" 2851 a = """r'\\\\\\u20ac\\U0001d121\\\\u20ac'""" 2852 self.check(b, a) 2853 2854 def test_native_unicode_literal_escape_u(self): 2855 f = 'from __future__ import unicode_literals\n' 2856 b = f + """'\\\\\\u20ac\\U0001d121\\\\u20ac'""" 2857 a = f + """'\\\\\\u20ac\\U0001d121\\\\u20ac'""" 2858 self.check(b, a) 2859 2860 b = f + """r'\\\\\\u20ac\\U0001d121\\\\u20ac'""" 2861 a = f + """r'\\\\\\u20ac\\U0001d121\\\\u20ac'""" 2862 self.check(b, a) 2863 2781 2864 class Test_callable(FixerTestCase): 2782 2865 fixer = "callable" … … 2936 3019 a = """sorted(filter(f, 'abc'), key=blah)[0]""" 2937 3020 self.unchanged(a) 3021 a = """enumerate(filter(f, 'abc'))""" 3022 self.unchanged(a) 3023 a = """enumerate(filter(f, 'abc'), start=1)""" 3024 self.unchanged(a) 2938 3025 a = """for i in filter(f, 'abc'): pass""" 2939 3026 self.unchanged(a) … … 3044 3131 a = """sorted(map(f, 'abc'), key=blah)[0]""" 3045 3132 self.unchanged(a) 3133 a = """enumerate(map(f, 'abc'))""" 3134 self.unchanged(a) 3135 a = """enumerate(map(f, 'abc'), start=1)""" 3136 self.unchanged(a) 3046 3137 a = """for i in map(f, 'abc'): pass""" 3047 3138 self.unchanged(a) … … 3106 3197 self.unchanged(a) 3107 3198 a = """sorted(zip(a, b), key=blah)[0]""" 3199 self.unchanged(a) 3200 a = """enumerate(zip(a, b))""" 3201 self.unchanged(a) 3202 a = """enumerate(zip(a, b), start=1)""" 3108 3203 self.unchanged(a) 3109 3204 a = """for i in zip(a, b): pass""" … … 3578 3673 self.checkall(b, a) 3579 3674 3580 def test_ 2(self):3675 def test_qualified(self): 3581 3676 b = """itertools.ifilterfalse(a, b)""" 3582 3677 a = """itertools.filterfalse(a, b)""" 3583 3678 self.check(b, a) 3584 3679 3585 def test_4(self): 3680 b = """itertools.izip_longest(a, b)""" 3681 a = """itertools.zip_longest(a, b)""" 3682 self.check(b, a) 3683 3684 def test_2(self): 3586 3685 b = """ifilterfalse(a, b)""" 3587 3686 a = """filterfalse(a, b)""" 3687 self.check(b, a) 3688 3689 b = """izip_longest(a, b)""" 3690 a = """zip_longest(a, b)""" 3588 3691 self.check(b, a) 3589 3692 … … 3598 3701 self.check(b, a) 3599 3702 3703 b = """ itertools.izip_longest(a, b)""" 3704 a = """ itertools.zip_longest(a, b)""" 3705 self.check(b, a) 3706 3600 3707 def test_run_order(self): 3601 3708 self.assert_runs_after('map', 'zip', 'filter') 3709 3602 3710 3603 3711 class Test_itertools_imports(FixerTestCase): … … 3613 3721 self.check(b, a) 3614 3722 3723 b = "from itertools import chain, imap, izip" 3724 a = "from itertools import chain" 3725 self.check(b, a) 3726 3615 3727 def test_comments(self): 3616 3728 b = "#foo\nfrom itertools import imap, izip" … … 3647 3759 self.unchanged(s) 3648 3760 3649 def test_ifilter(self): 3650 b = "from itertools import ifilterfalse" 3651 a = "from itertools import filterfalse" 3652 self.check(b, a) 3653 3654 b = "from itertools import imap, ifilterfalse, foo" 3655 a = "from itertools import filterfalse, foo" 3656 self.check(b, a) 3657 3658 b = "from itertools import bar, ifilterfalse, foo" 3659 a = "from itertools import bar, filterfalse, foo" 3660 self.check(b, a) 3761 def test_ifilter_and_zip_longest(self): 3762 for name in "filterfalse", "zip_longest": 3763 b = "from itertools import i%s" % (name,) 3764 a = "from itertools import %s" % (name,) 3765 self.check(b, a) 3766 3767 b = "from itertools import imap, i%s, foo" % (name,) 3768 a = "from itertools import %s, foo" % (name,) 3769 self.check(b, a) 3770 3771 b = "from itertools import bar, i%s, foo" % (name,) 3772 a = "from itertools import bar, %s, foo" % (name,) 3773 self.check(b, a) 3774 3775 def test_import_star(self): 3776 s = "from itertools import *" 3777 self.unchanged(s) 3661 3778 3662 3779 … … 3680 3797 return self.always_exists or (name in self.present_files) 3681 3798 3682 from ..fixes import fix_import3799 from lib2to3.fixes import fix_import 3683 3800 fix_import.exists = fake_exists 3684 3801 … … 3723 3840 self.unchanged(s) 3724 3841 3842 def test_with_absolute_import_enabled(self): 3843 s = "from __future__ import absolute_import\nimport bar" 3844 self.always_exists = False 3845 self.present_files = set(["__init__.py", "bar.py"]) 3846 self.unchanged(s) 3847 3725 3848 def test_in_package(self): 3726 3849 b = "import bar" … … 3736 3859 self.present_files = set(["__init__.py", "bar" + os.path.sep]) 3737 3860 self.check(b, a) 3861 3862 def test_already_relative_import(self): 3863 s = "from . import bar" 3864 self.unchanged(s) 3738 3865 3739 3866 def test_comments_and_indent(self): … … 4279 4406 self.check(b, a) 4280 4407 4408 b = "operator .sequenceIncludes(x, y)" 4409 a = "operator .contains(x, y)" 4410 self.check(b, a) 4411 4412 b = "operator. sequenceIncludes(x, y)" 4413 a = "operator. contains(x, y)" 4414 self.check(b, a) 4415 4416 def test_operator_isSequenceType(self): 4417 b = "operator.isSequenceType(x)" 4418 a = "import collections\nisinstance(x, collections.Sequence)" 4419 self.check(b, a) 4420 4421 def test_operator_isMappingType(self): 4422 b = "operator.isMappingType(x)" 4423 a = "import collections\nisinstance(x, collections.Mapping)" 4424 self.check(b, a) 4425 4426 def test_operator_isNumberType(self): 4427 b = "operator.isNumberType(x)" 4428 a = "import numbers\nisinstance(x, numbers.Number)" 4429 self.check(b, a) 4430 4431 def test_operator_repeat(self): 4432 b = "operator.repeat(x, n)" 4433 a = "operator.mul(x, n)" 4434 self.check(b, a) 4435 4436 b = "operator .repeat(x, n)" 4437 a = "operator .mul(x, n)" 4438 self.check(b, a) 4439 4440 b = "operator. repeat(x, n)" 4441 a = "operator. mul(x, n)" 4442 self.check(b, a) 4443 4444 def test_operator_irepeat(self): 4445 b = "operator.irepeat(x, n)" 4446 a = "operator.imul(x, n)" 4447 self.check(b, a) 4448 4449 b = "operator .irepeat(x, n)" 4450 a = "operator .imul(x, n)" 4451 self.check(b, a) 4452 4453 b = "operator. irepeat(x, n)" 4454 a = "operator. imul(x, n)" 4455 self.check(b, a) 4456 4281 4457 def test_bare_isCallable(self): 4282 4458 s = "isCallable(x)" 4283 self.warns_unchanged(s, "You should use hasattr(x, '__call__') here.") 4459 t = "You should use 'hasattr(x, '__call__')' here." 4460 self.warns_unchanged(s, t) 4284 4461 4285 4462 def test_bare_sequenceIncludes(self): 4286 4463 s = "sequenceIncludes(x, y)" 4287 self.warns_unchanged(s, "You should use operator.contains here.") 4464 t = "You should use 'operator.contains(x, y)' here." 4465 self.warns_unchanged(s, t) 4466 4467 def test_bare_operator_isSequenceType(self): 4468 s = "isSequenceType(z)" 4469 t = "You should use 'isinstance(z, collections.Sequence)' here." 4470 self.warns_unchanged(s, t) 4471 4472 def test_bare_operator_isMappingType(self): 4473 s = "isMappingType(x)" 4474 t = "You should use 'isinstance(x, collections.Mapping)' here." 4475 self.warns_unchanged(s, t) 4476 4477 def test_bare_operator_isNumberType(self): 4478 s = "isNumberType(y)" 4479 t = "You should use 'isinstance(y, numbers.Number)' here." 4480 self.warns_unchanged(s, t) 4481 4482 def test_bare_operator_repeat(self): 4483 s = "repeat(x, n)" 4484 t = "You should use 'operator.mul(x, n)' here." 4485 self.warns_unchanged(s, t) 4486 4487 def test_bare_operator_irepeat(self): 4488 s = "irepeat(y, 187)" 4489 t = "You should use 'operator.imul(y, 187)' here." 4490 self.warns_unchanged(s, t) 4491 4492 4493 class Test_exitfunc(FixerTestCase): 4494 4495 fixer = "exitfunc" 4496 4497 def test_simple(self): 4498 b = """ 4499 import sys 4500 sys.exitfunc = my_atexit 4501 """ 4502 a = """ 4503 import sys 4504 import atexit 4505 atexit.register(my_atexit) 4506 """ 4507 self.check(b, a) 4508 4509 def test_names_import(self): 4510 b = """ 4511 import sys, crumbs 4512 sys.exitfunc = my_func 4513 """ 4514 a = """ 4515 import sys, crumbs, atexit 4516 atexit.register(my_func) 4517 """ 4518 self.check(b, a) 4519 4520 def test_complex_expression(self): 4521 b = """ 4522 import sys 4523 sys.exitfunc = do(d)/a()+complex(f=23, g=23)*expression 4524 """ 4525 a = """ 4526 import sys 4527 import atexit 4528 atexit.register(do(d)/a()+complex(f=23, g=23)*expression) 4529 """ 4530 self.check(b, a) 4531 4532 def test_comments(self): 4533 b = """ 4534 import sys # Foo 4535 sys.exitfunc = f # Blah 4536 """ 4537 a = """ 4538 import sys 4539 import atexit # Foo 4540 atexit.register(f) # Blah 4541 """ 4542 self.check(b, a) 4543 4544 b = """ 4545 import apples, sys, crumbs, larry # Pleasant comments 4546 sys.exitfunc = func 4547 """ 4548 a = """ 4549 import apples, sys, crumbs, larry, atexit # Pleasant comments 4550 atexit.register(func) 4551 """ 4552 self.check(b, a) 4553 4554 def test_in_a_function(self): 4555 b = """ 4556 import sys 4557 def f(): 4558 sys.exitfunc = func 4559 """ 4560 a = """ 4561 import sys 4562 import atexit 4563 def f(): 4564 atexit.register(func) 4565 """ 4566 self.check(b, a) 4567 4568 def test_no_sys_import(self): 4569 b = """sys.exitfunc = f""" 4570 a = """atexit.register(f)""" 4571 msg = ("Can't find sys import; Please add an atexit import at the " 4572 "top of your file.") 4573 self.warns(b, a, msg) 4574 4575 4576 def test_unchanged(self): 4577 s = """f(sys.exitfunc)""" 4578 self.unchanged(s) -
python/trunk/Lib/lib2to3/tests/test_main.py
r2 r391 3 3 import codecs 4 4 import logging 5 import os 6 import re 7 import shutil 5 8 import StringIO 9 import sys 10 import tempfile 6 11 import unittest 7 12 … … 9 14 10 15 16 TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), "data") 17 PY2_TEST_MODULE = os.path.join(TEST_DATA_DIR, "py2_test_grammar.py") 18 19 11 20 class TestMain(unittest.TestCase): 21 22 if not hasattr(unittest.TestCase, 'assertNotRegex'): 23 # This method was only introduced in 3.2. 24 def assertNotRegex(self, text, regexp, msg=None): 25 import re 26 if not hasattr(regexp, 'search'): 27 regexp = re.compile(regexp) 28 if regexp.search(text): 29 self.fail("regexp %s MATCHED text %r" % (regexp.pattern, text)) 30 31 def setUp(self): 32 self.temp_dir = None # tearDown() will rmtree this directory if set. 12 33 13 34 def tearDown(self): 14 35 # Clean up logging configuration down by main. 15 36 del logging.root.handlers[:] 37 if self.temp_dir: 38 shutil.rmtree(self.temp_dir) 16 39 17 40 def run_2to3_capture(self, args, in_capture, out_capture, err_capture): … … 40 63 self.assertTrue("WARNING: couldn't encode <stdin>'s diff for " 41 64 "your terminal" in err.getvalue()) 65 66 def setup_test_source_trees(self): 67 """Setup a test source tree and output destination tree.""" 68 self.temp_dir = tempfile.mkdtemp() # tearDown() cleans this up. 69 self.py2_src_dir = os.path.join(self.temp_dir, "python2_project") 70 self.py3_dest_dir = os.path.join(self.temp_dir, "python3_project") 71 os.mkdir(self.py2_src_dir) 72 os.mkdir(self.py3_dest_dir) 73 # Turn it into a package with a few files. 74 self.setup_files = [] 75 open(os.path.join(self.py2_src_dir, "__init__.py"), "w").close() 76 self.setup_files.append("__init__.py") 77 shutil.copy(PY2_TEST_MODULE, self.py2_src_dir) 78 self.setup_files.append(os.path.basename(PY2_TEST_MODULE)) 79 self.trivial_py2_file = os.path.join(self.py2_src_dir, "trivial.py") 80 self.init_py2_file = os.path.join(self.py2_src_dir, "__init__.py") 81 with open(self.trivial_py2_file, "w") as trivial: 82 trivial.write("print 'I need a simple conversion.'") 83 self.setup_files.append("trivial.py") 84 85 def test_filename_changing_on_output_single_dir(self): 86 """2to3 a single directory with a new output dir and suffix.""" 87 self.setup_test_source_trees() 88 out = StringIO.StringIO() 89 err = StringIO.StringIO() 90 suffix = "TEST" 91 ret = self.run_2to3_capture( 92 ["-n", "--add-suffix", suffix, "--write-unchanged-files", 93 "--no-diffs", "--output-dir", 94 self.py3_dest_dir, self.py2_src_dir], 95 StringIO.StringIO(""), out, err) 96 self.assertEqual(ret, 0) 97 stderr = err.getvalue() 98 self.assertIn(" implies -w.", stderr) 99 self.assertIn( 100 "Output in %r will mirror the input directory %r layout" % ( 101 self.py3_dest_dir, self.py2_src_dir), stderr) 102 self.assertEqual(set(name+suffix for name in self.setup_files), 103 set(os.listdir(self.py3_dest_dir))) 104 for name in self.setup_files: 105 self.assertIn("Writing converted %s to %s" % ( 106 os.path.join(self.py2_src_dir, name), 107 os.path.join(self.py3_dest_dir, name+suffix)), stderr) 108 sep = re.escape(os.sep) 109 self.assertRegexpMatches( 110 stderr, r"No changes to .*/__init__\.py".replace("/", sep)) 111 self.assertNotRegex( 112 stderr, r"No changes to .*/trivial\.py".replace("/", sep)) 113 114 def test_filename_changing_on_output_two_files(self): 115 """2to3 two files in one directory with a new output dir.""" 116 self.setup_test_source_trees() 117 err = StringIO.StringIO() 118 py2_files = [self.trivial_py2_file, self.init_py2_file] 119 expected_files = set(os.path.basename(name) for name in py2_files) 120 ret = self.run_2to3_capture( 121 ["-n", "-w", "--write-unchanged-files", 122 "--no-diffs", "--output-dir", self.py3_dest_dir] + py2_files, 123 StringIO.StringIO(""), StringIO.StringIO(), err) 124 self.assertEqual(ret, 0) 125 stderr = err.getvalue() 126 self.assertIn( 127 "Output in %r will mirror the input directory %r layout" % ( 128 self.py3_dest_dir, self.py2_src_dir), stderr) 129 self.assertEqual(expected_files, set(os.listdir(self.py3_dest_dir))) 130 131 def test_filename_changing_on_output_single_file(self): 132 """2to3 a single file with a new output dir.""" 133 self.setup_test_source_trees() 134 err = StringIO.StringIO() 135 ret = self.run_2to3_capture( 136 ["-n", "-w", "--no-diffs", "--output-dir", self.py3_dest_dir, 137 self.trivial_py2_file], 138 StringIO.StringIO(""), StringIO.StringIO(), err) 139 self.assertEqual(ret, 0) 140 stderr = err.getvalue() 141 self.assertIn( 142 "Output in %r will mirror the input directory %r layout" % ( 143 self.py3_dest_dir, self.py2_src_dir), stderr) 144 self.assertEqual(set([os.path.basename(self.trivial_py2_file)]), 145 set(os.listdir(self.py3_dest_dir))) 146 147 148 if __name__ == '__main__': 149 unittest.main() -
python/trunk/Lib/lib2to3/tests/test_parser.py
r2 r391 7 7 """ 8 8 9 from __future__ import with_statement 10 9 11 # Testing imports 10 12 from . import support … … 13 15 # Python imports 14 16 import os 15 import io16 17 import sys 17 18 … … 19 20 from lib2to3.pgen2 import tokenize 20 21 from ..pgen2.parse import ParseError 22 from lib2to3.pygram import python_symbols as syms 23 24 25 class TestDriver(support.TestCase): 26 27 def test_formfeed(self): 28 s = """print 1\n\x0Cprint 2\n""" 29 t = driver.parse_string(s) 30 self.assertEqual(t.children[0].children[0].type, syms.print_stmt) 31 self.assertEqual(t.children[1].children[0].type, syms.print_stmt) 21 32 22 33 … … 63 74 64 75 65 # Adap ated from Python 3's Lib/test/test_grammar.py:GrammarTests.testFuncdef76 # Adaptated from Python 3's Lib/test/test_grammar.py:GrammarTests.testFuncdef 66 77 class TestFunctionAnnotations(GrammarTest): 67 78 def test_1(self): … … 157 168 self.assertTrue(encoding is not None, 158 169 "can't detect encoding for %s" % filepath) 159 with io.open(filepath, "r", encoding=encoding) as fp:170 with open(filepath, "r") as fp: 160 171 source = fp.read() 172 source = source.decode(encoding) 161 173 tree = driver.parse_string(source) 162 174 new = unicode(tree) … … 204 216 205 217 def diff(fn, result, encoding): 206 f = io.open("@", "w", encoding=encoding)218 f = open("@", "w") 207 219 try: 208 f.write(result )220 f.write(result.encode(encoding)) 209 221 finally: 210 222 f.close() 211 223 try: 212 return os.system("diff -u %r @" % fn) 224 fn = fn.replace('"', '\\"') 225 return os.system('diff -u "%s" @' % fn) 213 226 finally: 214 227 os.remove("@") -
python/trunk/Lib/lib2to3/tests/test_pytree.py
r2 r391 10 10 """ 11 11 12 from __future__ import with_statement 13 14 import sys 12 15 import warnings 13 16 … … 29 32 """Unit tests for nodes (Base, Leaf, Node).""" 30 33 31 def test_deprecated_prefix_methods(self): 32 l = pytree.Leaf(100, "foo") 33 with warnings.catch_warnings(record=True) as w: 34 warnings.simplefilter("always", DeprecationWarning) 35 self.assertEqual(l.get_prefix(), "") 36 l.set_prefix("hi") 37 self.assertEqual(l.prefix, "hi") 38 self.assertEqual(len(w), 2) 39 for warning in w: 40 self.assertTrue(warning.category is DeprecationWarning) 41 self.assertEqual(str(w[0].message), "get_prefix() is deprecated; " \ 42 "use the prefix property") 43 self.assertEqual(str(w[1].message), "set_prefix() is deprecated; " \ 44 "use the prefix property") 34 if sys.version_info >= (2,6): 35 # warnings.catch_warnings is new in 2.6. 36 def test_deprecated_prefix_methods(self): 37 l = pytree.Leaf(100, "foo") 38 with warnings.catch_warnings(record=True) as w: 39 warnings.simplefilter("always", DeprecationWarning) 40 self.assertEqual(l.get_prefix(), "") 41 l.set_prefix("hi") 42 self.assertEqual(l.prefix, "hi") 43 self.assertEqual(len(w), 2) 44 for warning in w: 45 self.assertTrue(warning.category is DeprecationWarning) 46 self.assertEqual(str(w[0].message), "get_prefix() is deprecated; " \ 47 "use the prefix property") 48 self.assertEqual(str(w[1].message), "set_prefix() is deprecated; " \ 49 "use the prefix property") 45 50 46 51 def test_instantiate_base(self): … … 174 179 self.assertTrue(isinstance(n1.children, list)) 175 180 181 def test_leaves(self): 182 l1 = pytree.Leaf(100, "foo") 183 l2 = pytree.Leaf(100, "bar") 184 l3 = pytree.Leaf(100, "fooey") 185 n2 = pytree.Node(1000, [l1, l2]) 186 n3 = pytree.Node(1000, [l3]) 187 n1 = pytree.Node(1000, [n2, n3]) 188 189 self.assertEqual(list(n1.leaves()), [l1, l2, l3]) 190 191 def test_depth(self): 192 l1 = pytree.Leaf(100, "foo") 193 l2 = pytree.Leaf(100, "bar") 194 n2 = pytree.Node(1000, [l1, l2]) 195 n3 = pytree.Node(1000, []) 196 n1 = pytree.Node(1000, [n2, n3]) 197 198 self.assertEqual(l1.depth(), 2) 199 self.assertEqual(n3.depth(), 1) 200 self.assertEqual(n1.depth(), 0) 201 176 202 def test_post_order(self): 177 203 l1 = pytree.Leaf(100, "foo") 178 204 l2 = pytree.Leaf(100, "bar") 179 n1 = pytree.Node(1000, [l1, l2]) 180 self.assertEqual(list(n1.post_order()), [l1, l2, n1]) 205 l3 = pytree.Leaf(100, "fooey") 206 c1 = pytree.Node(1000, [l1, l2]) 207 n1 = pytree.Node(1000, [c1, l3]) 208 self.assertEqual(list(n1.post_order()), [l1, l2, c1, l3, n1]) 181 209 182 210 def test_pre_order(self): 183 211 l1 = pytree.Leaf(100, "foo") 184 212 l2 = pytree.Leaf(100, "bar") 185 n1 = pytree.Node(1000, [l1, l2]) 186 self.assertEqual(list(n1.pre_order()), [n1, l1, l2]) 213 l3 = pytree.Leaf(100, "fooey") 214 c1 = pytree.Node(1000, [l1, l2]) 215 n1 = pytree.Node(1000, [c1, l3]) 216 self.assertEqual(list(n1.pre_order()), [n1, c1, l1, l2, l3]) 187 217 188 218 def test_changed(self): -
python/trunk/Lib/lib2to3/tests/test_refactor.py
r2 r391 2 2 Unit tests for refactor.py. 3 3 """ 4 5 from __future__ import with_statement 4 6 5 7 import sys … … 52 54 pygram.python_grammar_no_print_statement) 53 55 56 def test_write_unchanged_files_option(self): 57 rt = self.rt() 58 self.assertFalse(rt.write_unchanged_files) 59 rt = self.rt({"write_unchanged_files" : True}) 60 self.assertTrue(rt.write_unchanged_files) 61 54 62 def test_fixer_loading_helpers(self): 55 63 contents = ["explicit", "first", "last", "parrot", "preorder"] … … 62 70 ["myfixes.fix_" + name for name in contents]) 63 71 64 def test_detect_future_print(self): 65 run = refactor._detect_future_print 66 self.assertFalse(run("")) 67 self.assertTrue(run("from __future__ import print_function")) 68 self.assertFalse(run("from __future__ import generators")) 69 self.assertFalse(run("from __future__ import generators, feature")) 70 input = "from __future__ import generators, print_function" 71 self.assertTrue(run(input)) 72 input ="from __future__ import print_function, generators" 73 self.assertTrue(run(input)) 74 input = "from __future__ import (print_function,)" 75 self.assertTrue(run(input)) 76 input = "from __future__ import (generators, print_function)" 77 self.assertTrue(run(input)) 78 input = "from __future__ import (generators, nested_scopes)" 79 self.assertFalse(run(input)) 80 input = """from __future__ import generators 72 def test_detect_future_features(self): 73 run = refactor._detect_future_features 74 fs = frozenset 75 empty = fs() 76 self.assertEqual(run(""), empty) 77 self.assertEqual(run("from __future__ import print_function"), 78 fs(("print_function",))) 79 self.assertEqual(run("from __future__ import generators"), 80 fs(("generators",))) 81 self.assertEqual(run("from __future__ import generators, feature"), 82 fs(("generators", "feature"))) 83 inp = "from __future__ import generators, print_function" 84 self.assertEqual(run(inp), fs(("generators", "print_function"))) 85 inp ="from __future__ import print_function, generators" 86 self.assertEqual(run(inp), fs(("print_function", "generators"))) 87 inp = "from __future__ import (print_function,)" 88 self.assertEqual(run(inp), fs(("print_function",))) 89 inp = "from __future__ import (generators, print_function)" 90 self.assertEqual(run(inp), fs(("generators", "print_function"))) 91 inp = "from __future__ import (generators, nested_scopes)" 92 self.assertEqual(run(inp), fs(("generators", "nested_scopes"))) 93 inp = """from __future__ import generators 81 94 from __future__ import print_function""" 82 self.assertTrue(run(input)) 83 self.assertFalse(run("from")) 84 self.assertFalse(run("from 4")) 85 self.assertFalse(run("from x")) 86 self.assertFalse(run("from x 5")) 87 self.assertFalse(run("from x im")) 88 self.assertFalse(run("from x import")) 89 self.assertFalse(run("from x import 4")) 90 input = "'docstring'\nfrom __future__ import print_function" 91 self.assertTrue(run(input)) 92 input = "'docstring'\n'somng'\nfrom __future__ import print_function" 93 self.assertFalse(run(input)) 94 input = "# comment\nfrom __future__ import print_function" 95 self.assertTrue(run(input)) 96 input = "# comment\n'doc'\nfrom __future__ import print_function" 97 self.assertTrue(run(input)) 98 input = "class x: pass\nfrom __future__ import print_function" 99 self.assertFalse(run(input)) 95 self.assertEqual(run(inp), fs(("generators", "print_function"))) 96 invalid = ("from", 97 "from 4", 98 "from x", 99 "from x 5", 100 "from x im", 101 "from x import", 102 "from x import 4", 103 ) 104 for inp in invalid: 105 self.assertEqual(run(inp), empty) 106 inp = "'docstring'\nfrom __future__ import print_function" 107 self.assertEqual(run(inp), fs(("print_function",))) 108 inp = "'docstring'\n'somng'\nfrom __future__ import print_function" 109 self.assertEqual(run(inp), empty) 110 inp = "# comment\nfrom __future__ import print_function" 111 self.assertEqual(run(inp), fs(("print_function",))) 112 inp = "# comment\n'doc'\nfrom __future__ import print_function" 113 self.assertEqual(run(inp), fs(("print_function",))) 114 inp = "class x: pass\nfrom __future__ import print_function" 115 self.assertEqual(run(inp), empty) 100 116 101 117 def test_get_headnode_dict(self): … … 167 183 self.assertEqual(results, expected) 168 184 169 def check_file_refactoring(self, test_file, fixers=_2TO3_FIXERS): 185 def check_file_refactoring(self, test_file, fixers=_2TO3_FIXERS, 186 options=None, mock_log_debug=None, 187 actually_write=True): 188 tmpdir = tempfile.mkdtemp(prefix="2to3-test_refactor") 189 self.addCleanup(shutil.rmtree, tmpdir) 190 # make a copy of the tested file that we can write to 191 shutil.copy(test_file, tmpdir) 192 test_file = os.path.join(tmpdir, os.path.basename(test_file)) 193 os.chmod(test_file, 0o644) 194 170 195 def read_file(): 171 196 with open(test_file, "rb") as fp: 172 197 return fp.read() 198 173 199 old_contents = read_file() 174 rt = self.rt(fixers=fixers) 200 rt = self.rt(fixers=fixers, options=options) 201 if mock_log_debug: 202 rt.log_debug = mock_log_debug 175 203 176 204 rt.refactor_file(test_file) 177 205 self.assertEqual(old_contents, read_file()) 178 206 179 try: 180 rt.refactor_file(test_file, True) 181 new_contents = read_file() 182 self.assertNotEqual(old_contents, new_contents) 183 finally: 184 with open(test_file, "wb") as fp: 185 fp.write(old_contents) 207 if not actually_write: 208 return 209 rt.refactor_file(test_file, True) 210 new_contents = read_file() 211 self.assertNotEqual(old_contents, new_contents) 186 212 return new_contents 187 213 … … 189 215 test_file = os.path.join(FIXER_DIR, "parrot_example.py") 190 216 self.check_file_refactoring(test_file, _DEFAULT_FIXERS) 217 218 def test_refactor_file_write_unchanged_file(self): 219 test_file = os.path.join(FIXER_DIR, "parrot_example.py") 220 debug_messages = [] 221 def recording_log_debug(msg, *args): 222 debug_messages.append(msg % args) 223 self.check_file_refactoring(test_file, fixers=(), 224 options={"write_unchanged_files": True}, 225 mock_log_debug=recording_log_debug, 226 actually_write=False) 227 # Testing that it logged this message when write=False was passed is 228 # sufficient to see that it did not bail early after "No changes". 229 message_regex = r"Not writing changes to .*%s%s" % ( 230 os.sep, os.path.basename(test_file)) 231 for message in debug_messages: 232 if "Not writing changes" in message: 233 self.assertRegexpMatches(message, message_regex) 234 break 235 else: 236 self.fail("%r not matched in %r" % (message_regex, debug_messages)) 191 237 192 238 def test_refactor_dir(self): … … 214 260 ".dumb", 215 261 ".after.py", 262 "notpy.npy", 216 263 "sappy"] 217 264 expected = ["hi.py"] … … 224 271 fn = os.path.join(TEST_DATA_DIR, "different_encoding.py") 225 272 self.check_file_refactoring(fn) 273 274 def test_false_file_encoding(self): 275 fn = os.path.join(TEST_DATA_DIR, "false_encoding.py") 276 data = self.check_file_refactoring(fn) 226 277 227 278 def test_bom(self): -
python/trunk/Lib/lib2to3/tests/test_util.py
r2 r391 569 569 def test_from_import(self): 570 570 node = parse('bar()') 571 fixer_util.touch_import(" cgi", "escape", node)572 self.assertEqual(str(node), 'from cgiimport escape\nbar()\n\n')571 fixer_util.touch_import("html", "escape", node) 572 self.assertEqual(str(node), 'from html import escape\nbar()\n\n') 573 573 574 574 def test_name_import(self): … … 576 576 fixer_util.touch_import(None, "cgi", node) 577 577 self.assertEqual(str(node), 'import cgi\nbar()\n\n') 578 579 class Test_find_indentation(support.TestCase): 580 581 def test_nothing(self): 582 fi = fixer_util.find_indentation 583 node = parse("node()") 584 self.assertEqual(fi(node), u"") 585 node = parse("") 586 self.assertEqual(fi(node), u"") 587 588 def test_simple(self): 589 fi = fixer_util.find_indentation 590 node = parse("def f():\n x()") 591 self.assertEqual(fi(node), u"") 592 self.assertEqual(fi(node.children[0].children[4].children[2]), u" ") 593 node = parse("def f():\n x()\n y()") 594 self.assertEqual(fi(node.children[0].children[4].children[4]), u" ")
Note:
See TracChangeset
for help on using the changeset viewer.