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, ArgList, Call, ListComp, in_special_context
26 from ..pygram import python_symbols as syms
27 from ..pytree import Node
28
29
30 class ESC[4;38;5;81mFixMap(ESC[4;38;5;149mfixer_baseESC[4;38;5;149m.ESC[4;38;5;149mConditionalFix):
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