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