]>
Commit | Line | Data |
---|---|---|
4710c53d | 1 | # Copyright 2007 Google, Inc. All Rights Reserved.\r |
2 | # Licensed to PSF under a Contributor Agreement.\r | |
3 | \r | |
4 | """Fixer for dict methods.\r | |
5 | \r | |
6 | d.keys() -> list(d.keys())\r | |
7 | d.items() -> list(d.items())\r | |
8 | d.values() -> list(d.values())\r | |
9 | \r | |
10 | d.iterkeys() -> iter(d.keys())\r | |
11 | d.iteritems() -> iter(d.items())\r | |
12 | d.itervalues() -> iter(d.values())\r | |
13 | \r | |
14 | d.viewkeys() -> d.keys()\r | |
15 | d.viewitems() -> d.items()\r | |
16 | d.viewvalues() -> d.values()\r | |
17 | \r | |
18 | Except in certain very specific contexts: the iter() can be dropped\r | |
19 | when the context is list(), sorted(), iter() or for...in; the list()\r | |
20 | can be dropped when the context is list() or sorted() (but not iter()\r | |
21 | or for...in!). Special contexts that apply to both: list(), sorted(), tuple()\r | |
22 | set(), any(), all(), sum().\r | |
23 | \r | |
24 | Note: iter(d.keys()) could be written as iter(d) but since the\r | |
25 | original d.iterkeys() was also redundant we don't fix this. And there\r | |
26 | are (rare) contexts where it makes a difference (e.g. when passing it\r | |
27 | as an argument to a function that introspects the argument).\r | |
28 | """\r | |
29 | \r | |
30 | # Local imports\r | |
31 | from .. import pytree\r | |
32 | from .. import patcomp\r | |
33 | from ..pgen2 import token\r | |
34 | from .. import fixer_base\r | |
35 | from ..fixer_util import Name, Call, LParen, RParen, ArgList, Dot\r | |
36 | from .. import fixer_util\r | |
37 | \r | |
38 | \r | |
39 | iter_exempt = fixer_util.consuming_calls | set(["iter"])\r | |
40 | \r | |
41 | \r | |
42 | class FixDict(fixer_base.BaseFix):\r | |
43 | BM_compatible = True\r | |
44 | \r | |
45 | PATTERN = """\r | |
46 | power< head=any+\r | |
47 | trailer< '.' method=('keys'|'items'|'values'|\r | |
48 | 'iterkeys'|'iteritems'|'itervalues'|\r | |
49 | 'viewkeys'|'viewitems'|'viewvalues') >\r | |
50 | parens=trailer< '(' ')' >\r | |
51 | tail=any*\r | |
52 | >\r | |
53 | """\r | |
54 | \r | |
55 | def transform(self, node, results):\r | |
56 | head = results["head"]\r | |
57 | method = results["method"][0] # Extract node for method name\r | |
58 | tail = results["tail"]\r | |
59 | syms = self.syms\r | |
60 | method_name = method.value\r | |
61 | isiter = method_name.startswith(u"iter")\r | |
62 | isview = method_name.startswith(u"view")\r | |
63 | if isiter or isview:\r | |
64 | method_name = method_name[4:]\r | |
65 | assert method_name in (u"keys", u"items", u"values"), repr(method)\r | |
66 | head = [n.clone() for n in head]\r | |
67 | tail = [n.clone() for n in tail]\r | |
68 | special = not tail and self.in_special_context(node, isiter)\r | |
69 | args = head + [pytree.Node(syms.trailer,\r | |
70 | [Dot(),\r | |
71 | Name(method_name,\r | |
72 | prefix=method.prefix)]),\r | |
73 | results["parens"].clone()]\r | |
74 | new = pytree.Node(syms.power, args)\r | |
75 | if not (special or isview):\r | |
76 | new.prefix = u""\r | |
77 | new = Call(Name(u"iter" if isiter else u"list"), [new])\r | |
78 | if tail:\r | |
79 | new = pytree.Node(syms.power, [new] + tail)\r | |
80 | new.prefix = node.prefix\r | |
81 | return new\r | |
82 | \r | |
83 | P1 = "power< func=NAME trailer< '(' node=any ')' > any* >"\r | |
84 | p1 = patcomp.compile_pattern(P1)\r | |
85 | \r | |
86 | P2 = """for_stmt< 'for' any 'in' node=any ':' any* >\r | |
87 | | comp_for< 'for' any 'in' node=any any* >\r | |
88 | """\r | |
89 | p2 = patcomp.compile_pattern(P2)\r | |
90 | \r | |
91 | def in_special_context(self, node, isiter):\r | |
92 | if node.parent is None:\r | |
93 | return False\r | |
94 | results = {}\r | |
95 | if (node.parent.parent is not None and\r | |
96 | self.p1.match(node.parent.parent, results) and\r | |
97 | results["node"] is node):\r | |
98 | if isiter:\r | |
99 | # iter(d.iterkeys()) -> iter(d.keys()), etc.\r | |
100 | return results["func"].value in iter_exempt\r | |
101 | else:\r | |
102 | # list(d.keys()) -> list(d.keys()), etc.\r | |
103 | return results["func"].value in fixer_util.consuming_calls\r | |
104 | if not isiter:\r | |
105 | return False\r | |
106 | # for ... in d.iterkeys() -> for ... in d.keys(), etc.\r | |
107 | return self.p2.match(node.parent, results) and results["node"] is node\r |