1 # Copyright 2007 Google, Inc. All Rights Reserved. 2 # Licensed to PSF under a Contributor Agreement. 3 4 """Fixer that changes map(F, ...) into list(map(F, ...)) unless there 5 exists a 'from future_builtins import map' statement in the top-level 6 namespace. 7 8 As a special case, map(None, X) is changed into list(X). (This is 9 necessary because the semantics are changed in this case -- the new 10 map(None, X) is equivalent to [(x,) for x in X].) 11 12 We avoid the transformation (except for the special case mentioned 13 above) if the map() call is directly contained in iter(<>), list(<>), 14 tuple(<>), sorted(<>), ...join(<>), or for V in <>:. 15 16 NOTE: This is still not correct if the original code was depending on 17 map(F, X, Y, ...) to go on until the longest argument is exhausted, 18 substituting None for missing values -- like zip(), it now stops as 19 soon as the shortest argument is exhausted. 20 """ 21 22 # Local imports 23 from ..pgen2 import token 24 from .. import fixer_base 25 from ..fixer_util import Name, Call, ListComp, in_special_context 26 from ..pygram import python_symbols as syms 27 28 class FixMap(fixer_base.ConditionalFix): 29 BM_compatible = True 30 31 PATTERN = """ 32 map_none=power< 33 'map' 34 trailer< '(' arglist< 'None' ',' arg=any [','] > ')' > 35 > 36 | 37 map_lambda=power< 38 'map' 39 trailer< 40 '(' 41 arglist< 42 lambdef< 'lambda' 43 (fp=NAME | vfpdef< '(' fp=NAME ')'> ) ':' xp=any 44 > 45 ',' 46 it=any 47 > 48 ')' 49 > 50 > 51 | 52 power< 53 'map' trailer< '(' [arglist=any] ')' > 54 > 55 """ 56 57 skip_on = 'future_builtins.map' 58 59 def transform(self, node, results): 60 if self.should_skip(node): 61 return 62 63 if node.parent.type == syms.simple_stmt: 64 self.warning(node, "You should use a for loop here") 65 new = node.clone() 66 new.prefix = u"" 67 new = Call(Name(u"list"), [new]) 68 elif "map_lambda" in results: 69 new = ListComp(results["xp"].clone(), 70 results["fp"].clone(), 71 results["it"].clone()) 72 else: 73 if "map_none" in results: 74 new = results["arg"].clone() 75 else: 76 if "arglist" in results: 77 args = results["arglist"] 78 if args.type == syms.arglist and \ 79 args.children[0].type == token.NAME and \ 80 args.children[0].value == "None": 81 self.warning(node, "cannot convert map(None, ...) " 82 "with multiple arguments because map() " 83 "now truncates to the shortest sequence") 84 return 85 if in_special_context(node): 86 return None 87 new = node.clone() 88 new.prefix = u"" 89 new = Call(Name(u"list"), [new]) 90 new.prefix = node.prefix 91 return new 92