ยปCore Development>Code coverage>Lib/lib2to3/fixer_util.py

Python code coverage for Lib/lib2to3/fixer_util.py

#countcontent
1n/a"""Utility functions, node construction macros, etc."""
2n/a# Author: Collin Winter
3n/a
4n/a# Local imports
5n/afrom .pgen2 import token
6n/afrom .pytree import Leaf, Node
7n/afrom .pygram import python_symbols as syms
8n/afrom . import patcomp
9n/a
10n/a
11n/a###########################################################
12n/a### Common node-construction "macros"
13n/a###########################################################
14n/a
15n/adef KeywordArg(keyword, value):
16n/a return Node(syms.argument,
17n/a [keyword, Leaf(token.EQUAL, "="), value])
18n/a
19n/adef LParen():
20n/a return Leaf(token.LPAR, "(")
21n/a
22n/adef RParen():
23n/a return Leaf(token.RPAR, ")")
24n/a
25n/adef Assign(target, source):
26n/a """Build an assignment statement"""
27n/a if not isinstance(target, list):
28n/a target = [target]
29n/a if not isinstance(source, list):
30n/a source.prefix = " "
31n/a source = [source]
32n/a
33n/a return Node(syms.atom,
34n/a target + [Leaf(token.EQUAL, "=", prefix=" ")] + source)
35n/a
36n/adef Name(name, prefix=None):
37n/a """Return a NAME leaf"""
38n/a return Leaf(token.NAME, name, prefix=prefix)
39n/a
40n/adef Attr(obj, attr):
41n/a """A node tuple for obj.attr"""
42n/a return [obj, Node(syms.trailer, [Dot(), attr])]
43n/a
44n/adef Comma():
45n/a """A comma leaf"""
46n/a return Leaf(token.COMMA, ",")
47n/a
48n/adef Dot():
49n/a """A period (.) leaf"""
50n/a return Leaf(token.DOT, ".")
51n/a
52n/adef ArgList(args, lparen=LParen(), rparen=RParen()):
53n/a """A parenthesised argument list, used by Call()"""
54n/a node = Node(syms.trailer, [lparen.clone(), rparen.clone()])
55n/a if args:
56n/a node.insert_child(1, Node(syms.arglist, args))
57n/a return node
58n/a
59n/adef Call(func_name, args=None, prefix=None):
60n/a """A function call"""
61n/a node = Node(syms.power, [func_name, ArgList(args)])
62n/a if prefix is not None:
63n/a node.prefix = prefix
64n/a return node
65n/a
66n/adef Newline():
67n/a """A newline literal"""
68n/a return Leaf(token.NEWLINE, "\n")
69n/a
70n/adef BlankLine():
71n/a """A blank line"""
72n/a return Leaf(token.NEWLINE, "")
73n/a
74n/adef Number(n, prefix=None):
75n/a return Leaf(token.NUMBER, n, prefix=prefix)
76n/a
77n/adef Subscript(index_node):
78n/a """A numeric or string subscript"""
79n/a return Node(syms.trailer, [Leaf(token.LBRACE, "["),
80n/a index_node,
81n/a Leaf(token.RBRACE, "]")])
82n/a
83n/adef String(string, prefix=None):
84n/a """A string leaf"""
85n/a return Leaf(token.STRING, string, prefix=prefix)
86n/a
87n/adef ListComp(xp, fp, it, test=None):
88n/a """A list comprehension of the form [xp for fp in it if test].
89n/a
90n/a If test is None, the "if test" part is omitted.
91n/a """
92n/a xp.prefix = ""
93n/a fp.prefix = " "
94n/a it.prefix = " "
95n/a for_leaf = Leaf(token.NAME, "for")
96n/a for_leaf.prefix = " "
97n/a in_leaf = Leaf(token.NAME, "in")
98n/a in_leaf.prefix = " "
99n/a inner_args = [for_leaf, fp, in_leaf, it]
100n/a if test:
101n/a test.prefix = " "
102n/a if_leaf = Leaf(token.NAME, "if")
103n/a if_leaf.prefix = " "
104n/a inner_args.append(Node(syms.comp_if, [if_leaf, test]))
105n/a inner = Node(syms.listmaker, [xp, Node(syms.comp_for, inner_args)])
106n/a return Node(syms.atom,
107n/a [Leaf(token.LBRACE, "["),
108n/a inner,
109n/a Leaf(token.RBRACE, "]")])
110n/a
111n/adef FromImport(package_name, name_leafs):
112n/a """ Return an import statement in the form:
113n/a from package import name_leafs"""
114n/a # XXX: May not handle dotted imports properly (eg, package_name='foo.bar')
115n/a #assert package_name == '.' or '.' not in package_name, "FromImport has "\
116n/a # "not been tested with dotted package names -- use at your own "\
117n/a # "peril!"
118n/a
119n/a for leaf in name_leafs:
120n/a # Pull the leaves out of their old tree
121n/a leaf.remove()
122n/a
123n/a children = [Leaf(token.NAME, "from"),
124n/a Leaf(token.NAME, package_name, prefix=" "),
125n/a Leaf(token.NAME, "import", prefix=" "),
126n/a Node(syms.import_as_names, name_leafs)]
127n/a imp = Node(syms.import_from, children)
128n/a return imp
129n/a
130n/adef ImportAndCall(node, results, names):
131n/a """Returns an import statement and calls a method
132n/a of the module:
133n/a
134n/a import module
135n/a module.name()"""
136n/a obj = results["obj"].clone()
137n/a if obj.type == syms.arglist:
138n/a newarglist = obj.clone()
139n/a else:
140n/a newarglist = Node(syms.arglist, [obj.clone()])
141n/a after = results["after"]
142n/a if after:
143n/a after = [n.clone() for n in after]
144n/a new = Node(syms.power,
145n/a Attr(Name(names[0]), Name(names[1])) +
146n/a [Node(syms.trailer,
147n/a [results["lpar"].clone(),
148n/a newarglist,
149n/a results["rpar"].clone()])] + after)
150n/a new.prefix = node.prefix
151n/a return new
152n/a
153n/a
154n/a###########################################################
155n/a### Determine whether a node represents a given literal
156n/a###########################################################
157n/a
158n/adef is_tuple(node):
159n/a """Does the node represent a tuple literal?"""
160n/a if isinstance(node, Node) and node.children == [LParen(), RParen()]:
161n/a return True
162n/a return (isinstance(node, Node)
163n/a and len(node.children) == 3
164n/a and isinstance(node.children[0], Leaf)
165n/a and isinstance(node.children[1], Node)
166n/a and isinstance(node.children[2], Leaf)
167n/a and node.children[0].value == "("
168n/a and node.children[2].value == ")")
169n/a
170n/adef is_list(node):
171n/a """Does the node represent a list literal?"""
172n/a return (isinstance(node, Node)
173n/a and len(node.children) > 1
174n/a and isinstance(node.children[0], Leaf)
175n/a and isinstance(node.children[-1], Leaf)
176n/a and node.children[0].value == "["
177n/a and node.children[-1].value == "]")
178n/a
179n/a
180n/a###########################################################
181n/a### Misc
182n/a###########################################################
183n/a
184n/adef parenthesize(node):
185n/a return Node(syms.atom, [LParen(), node, RParen()])
186n/a
187n/a
188n/aconsuming_calls = {"sorted", "list", "set", "any", "all", "tuple", "sum",
189n/a "min", "max", "enumerate"}
190n/a
191n/adef attr_chain(obj, attr):
192n/a """Follow an attribute chain.
193n/a
194n/a If you have a chain of objects where a.foo -> b, b.foo-> c, etc,
195n/a use this to iterate over all objects in the chain. Iteration is
196n/a terminated by getattr(x, attr) is None.
197n/a
198n/a Args:
199n/a obj: the starting object
200n/a attr: the name of the chaining attribute
201n/a
202n/a Yields:
203n/a Each successive object in the chain.
204n/a """
205n/a next = getattr(obj, attr)
206n/a while next:
207n/a yield next
208n/a next = getattr(next, attr)
209n/a
210n/ap0 = """for_stmt< 'for' any 'in' node=any ':' any* >
211n/a | comp_for< 'for' any 'in' node=any any* >
212n/a """
213n/ap1 = """
214n/apower<
215n/a ( 'iter' | 'list' | 'tuple' | 'sorted' | 'set' | 'sum' |
216n/a 'any' | 'all' | 'enumerate' | (any* trailer< '.' 'join' >) )
217n/a trailer< '(' node=any ')' >
218n/a any*
219n/a>
220n/a"""
221n/ap2 = """
222n/apower<
223n/a ( 'sorted' | 'enumerate' )
224n/a trailer< '(' arglist<node=any any*> ')' >
225n/a any*
226n/a>
227n/a"""
228n/apats_built = False
229n/adef in_special_context(node):
230n/a """ Returns true if node is in an environment where all that is required
231n/a of it is being iterable (ie, it doesn't matter if it returns a list
232n/a or an iterator).
233n/a See test_map_nochange in test_fixers.py for some examples and tests.
234n/a """
235n/a global p0, p1, p2, pats_built
236n/a if not pats_built:
237n/a p0 = patcomp.compile_pattern(p0)
238n/a p1 = patcomp.compile_pattern(p1)
239n/a p2 = patcomp.compile_pattern(p2)
240n/a pats_built = True
241n/a patterns = [p0, p1, p2]
242n/a for pattern, parent in zip(patterns, attr_chain(node, "parent")):
243n/a results = {}
244n/a if pattern.match(parent, results) and results["node"] is node:
245n/a return True
246n/a return False
247n/a
248n/adef is_probably_builtin(node):
249n/a """
250n/a Check that something isn't an attribute or function name etc.
251n/a """
252n/a prev = node.prev_sibling
253n/a if prev is not None and prev.type == token.DOT:
254n/a # Attribute lookup.
255n/a return False
256n/a parent = node.parent
257n/a if parent.type in (syms.funcdef, syms.classdef):
258n/a return False
259n/a if parent.type == syms.expr_stmt and parent.children[0] is node:
260n/a # Assignment.
261n/a return False
262n/a if parent.type == syms.parameters or \
263n/a (parent.type == syms.typedargslist and (
264n/a (prev is not None and prev.type == token.COMMA) or
265n/a parent.children[0] is node
266n/a )):
267n/a # The name of an argument.
268n/a return False
269n/a return True
270n/a
271n/adef find_indentation(node):
272n/a """Find the indentation of *node*."""
273n/a while node is not None:
274n/a if node.type == syms.suite and len(node.children) > 2:
275n/a indent = node.children[1]
276n/a if indent.type == token.INDENT:
277n/a return indent.value
278n/a node = node.parent
279n/a return ""
280n/a
281n/a###########################################################
282n/a### The following functions are to find bindings in a suite
283n/a###########################################################
284n/a
285n/adef make_suite(node):
286n/a if node.type == syms.suite:
287n/a return node
288n/a node = node.clone()
289n/a parent, node.parent = node.parent, None
290n/a suite = Node(syms.suite, [node])
291n/a suite.parent = parent
292n/a return suite
293n/a
294n/adef find_root(node):
295n/a """Find the top level namespace."""
296n/a # Scamper up to the top level namespace
297n/a while node.type != syms.file_input:
298n/a node = node.parent
299n/a if not node:
300n/a raise ValueError("root found before file_input node was found.")
301n/a return node
302n/a
303n/adef does_tree_import(package, name, node):
304n/a """ Returns true if name is imported from package at the
305n/a top level of the tree which node belongs to.
306n/a To cover the case of an import like 'import foo', use
307n/a None for the package and 'foo' for the name. """
308n/a binding = find_binding(name, find_root(node), package)
309n/a return bool(binding)
310n/a
311n/adef is_import(node):
312n/a """Returns true if the node is an import statement."""
313n/a return node.type in (syms.import_name, syms.import_from)
314n/a
315n/adef touch_import(package, name, node):
316n/a """ Works like `does_tree_import` but adds an import statement
317n/a if it was not imported. """
318n/a def is_import_stmt(node):
319n/a return (node.type == syms.simple_stmt and node.children and
320n/a is_import(node.children[0]))
321n/a
322n/a root = find_root(node)
323n/a
324n/a if does_tree_import(package, name, root):
325n/a return
326n/a
327n/a # figure out where to insert the new import. First try to find
328n/a # the first import and then skip to the last one.
329n/a insert_pos = offset = 0
330n/a for idx, node in enumerate(root.children):
331n/a if not is_import_stmt(node):
332n/a continue
333n/a for offset, node2 in enumerate(root.children[idx:]):
334n/a if not is_import_stmt(node2):
335n/a break
336n/a insert_pos = idx + offset
337n/a break
338n/a
339n/a # if there are no imports where we can insert, find the docstring.
340n/a # if that also fails, we stick to the beginning of the file
341n/a if insert_pos == 0:
342n/a for idx, node in enumerate(root.children):
343n/a if (node.type == syms.simple_stmt and node.children and
344n/a node.children[0].type == token.STRING):
345n/a insert_pos = idx + 1
346n/a break
347n/a
348n/a if package is None:
349n/a import_ = Node(syms.import_name, [
350n/a Leaf(token.NAME, "import"),
351n/a Leaf(token.NAME, name, prefix=" ")
352n/a ])
353n/a else:
354n/a import_ = FromImport(package, [Leaf(token.NAME, name, prefix=" ")])
355n/a
356n/a children = [import_, Newline()]
357n/a root.insert_child(insert_pos, Node(syms.simple_stmt, children))
358n/a
359n/a
360n/a_def_syms = {syms.classdef, syms.funcdef}
361n/adef find_binding(name, node, package=None):
362n/a """ Returns the node which binds variable name, otherwise None.
363n/a If optional argument package is supplied, only imports will
364n/a be returned.
365n/a See test cases for examples."""
366n/a for child in node.children:
367n/a ret = None
368n/a if child.type == syms.for_stmt:
369n/a if _find(name, child.children[1]):
370n/a return child
371n/a n = find_binding(name, make_suite(child.children[-1]), package)
372n/a if n: ret = n
373n/a elif child.type in (syms.if_stmt, syms.while_stmt):
374n/a n = find_binding(name, make_suite(child.children[-1]), package)
375n/a if n: ret = n
376n/a elif child.type == syms.try_stmt:
377n/a n = find_binding(name, make_suite(child.children[2]), package)
378n/a if n:
379n/a ret = n
380n/a else:
381n/a for i, kid in enumerate(child.children[3:]):
382n/a if kid.type == token.COLON and kid.value == ":":
383n/a # i+3 is the colon, i+4 is the suite
384n/a n = find_binding(name, make_suite(child.children[i+4]), package)
385n/a if n: ret = n
386n/a elif child.type in _def_syms and child.children[1].value == name:
387n/a ret = child
388n/a elif _is_import_binding(child, name, package):
389n/a ret = child
390n/a elif child.type == syms.simple_stmt:
391n/a ret = find_binding(name, child, package)
392n/a elif child.type == syms.expr_stmt:
393n/a if _find(name, child.children[0]):
394n/a ret = child
395n/a
396n/a if ret:
397n/a if not package:
398n/a return ret
399n/a if is_import(ret):
400n/a return ret
401n/a return None
402n/a
403n/a_block_syms = {syms.funcdef, syms.classdef, syms.trailer}
404n/adef _find(name, node):
405n/a nodes = [node]
406n/a while nodes:
407n/a node = nodes.pop()
408n/a if node.type > 256 and node.type not in _block_syms:
409n/a nodes.extend(node.children)
410n/a elif node.type == token.NAME and node.value == name:
411n/a return node
412n/a return None
413n/a
414n/adef _is_import_binding(node, name, package=None):
415n/a """ Will reuturn node if node will import name, or node
416n/a will import * from package. None is returned otherwise.
417n/a See test cases for examples. """
418n/a
419n/a if node.type == syms.import_name and not package:
420n/a imp = node.children[1]
421n/a if imp.type == syms.dotted_as_names:
422n/a for child in imp.children:
423n/a if child.type == syms.dotted_as_name:
424n/a if child.children[2].value == name:
425n/a return node
426n/a elif child.type == token.NAME and child.value == name:
427n/a return node
428n/a elif imp.type == syms.dotted_as_name:
429n/a last = imp.children[-1]
430n/a if last.type == token.NAME and last.value == name:
431n/a return node
432n/a elif imp.type == token.NAME and imp.value == name:
433n/a return node
434n/a elif node.type == syms.import_from:
435n/a # str(...) is used to make life easier here, because
436n/a # from a.b import parses to ['import', ['a', '.', 'b'], ...]
437n/a if package and str(node.children[1]).strip() != package:
438n/a return None
439n/a n = node.children[3]
440n/a if package and _find("as", n):
441n/a # See test_from_import_as for explanation
442n/a return None
443n/a elif n.type == syms.import_as_names and _find(name, n):
444n/a return node
445n/a elif n.type == syms.import_as_name:
446n/a child = n.children[2]
447n/a if child.type == token.NAME and child.value == name:
448n/a return node
449n/a elif n.type == token.NAME and n.value == name:
450n/a return node
451n/a elif package and n.type == token.STAR:
452n/a return node
453n/a return None