~ubuntu-branches/ubuntu/maverick/python3.1/maverick

« back to all changes in this revision

Viewing changes to Lib/lib2to3/fixes/fix_dict.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-03-23 00:01:27 UTC
  • Revision ID: james.westby@ubuntu.com-20090323000127-5fstfxju4ufrhthq
Tags: upstream-3.1~a1+20090322
ImportĀ upstreamĀ versionĀ 3.1~a1+20090322

Show diffs side-by-side

added added

removed removed

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