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
|
---|