Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/libfuturize/fixes/fix_next_call.py @ 1:56ad4e20f292 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
author | guerler |
---|---|
date | Fri, 31 Jul 2020 00:32:28 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:d30785e31577 | 1:56ad4e20f292 |
---|---|
1 """ | |
2 Based on fix_next.py by Collin Winter. | |
3 | |
4 Replaces it.next() -> next(it), per PEP 3114. | |
5 | |
6 Unlike fix_next.py, this fixer doesn't replace the name of a next method with __next__, | |
7 which would break Python 2 compatibility without further help from fixers in | |
8 stage 2. | |
9 """ | |
10 | |
11 # Local imports | |
12 from lib2to3.pgen2 import token | |
13 from lib2to3.pygram import python_symbols as syms | |
14 from lib2to3 import fixer_base | |
15 from lib2to3.fixer_util import Name, Call, find_binding | |
16 | |
17 bind_warning = "Calls to builtin next() possibly shadowed by global binding" | |
18 | |
19 | |
20 class FixNextCall(fixer_base.BaseFix): | |
21 BM_compatible = True | |
22 PATTERN = """ | |
23 power< base=any+ trailer< '.' attr='next' > trailer< '(' ')' > > | |
24 | | |
25 power< head=any+ trailer< '.' attr='next' > not trailer< '(' ')' > > | |
26 | | |
27 global=global_stmt< 'global' any* 'next' any* > | |
28 """ | |
29 | |
30 order = "pre" # Pre-order tree traversal | |
31 | |
32 def start_tree(self, tree, filename): | |
33 super(FixNextCall, self).start_tree(tree, filename) | |
34 | |
35 n = find_binding('next', tree) | |
36 if n: | |
37 self.warning(n, bind_warning) | |
38 self.shadowed_next = True | |
39 else: | |
40 self.shadowed_next = False | |
41 | |
42 def transform(self, node, results): | |
43 assert results | |
44 | |
45 base = results.get("base") | |
46 attr = results.get("attr") | |
47 name = results.get("name") | |
48 | |
49 if base: | |
50 if self.shadowed_next: | |
51 # Omit this: | |
52 # attr.replace(Name("__next__", prefix=attr.prefix)) | |
53 pass | |
54 else: | |
55 base = [n.clone() for n in base] | |
56 base[0].prefix = "" | |
57 node.replace(Call(Name("next", prefix=node.prefix), base)) | |
58 elif name: | |
59 # Omit this: | |
60 # n = Name("__next__", prefix=name.prefix) | |
61 # name.replace(n) | |
62 pass | |
63 elif attr: | |
64 # We don't do this transformation if we're assigning to "x.next". | |
65 # Unfortunately, it doesn't seem possible to do this in PATTERN, | |
66 # so it's being done here. | |
67 if is_assign_target(node): | |
68 head = results["head"] | |
69 if "".join([str(n) for n in head]).strip() == '__builtin__': | |
70 self.warning(node, bind_warning) | |
71 return | |
72 # Omit this: | |
73 # attr.replace(Name("__next__")) | |
74 elif "global" in results: | |
75 self.warning(node, bind_warning) | |
76 self.shadowed_next = True | |
77 | |
78 | |
79 ### The following functions help test if node is part of an assignment | |
80 ### target. | |
81 | |
82 def is_assign_target(node): | |
83 assign = find_assign(node) | |
84 if assign is None: | |
85 return False | |
86 | |
87 for child in assign.children: | |
88 if child.type == token.EQUAL: | |
89 return False | |
90 elif is_subtree(child, node): | |
91 return True | |
92 return False | |
93 | |
94 def find_assign(node): | |
95 if node.type == syms.expr_stmt: | |
96 return node | |
97 if node.type == syms.simple_stmt or node.parent is None: | |
98 return None | |
99 return find_assign(node.parent) | |
100 | |
101 def is_subtree(root, node): | |
102 if root == node: | |
103 return True | |
104 return any(is_subtree(c, node) for c in root.children) |