/usr/lib/python3/dist-packages/astor/treewalk.py is in python3-astor 0.4-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | # -*- coding: utf-8 -*-
"""
Part of the astor library for Python AST manipulation.
License: 3-clause BSD
Copyright 2012 (c) Patrick Maupin
Copyright 2013 (c) Berker Peksag
"""
from .misc import MetaFlatten, iter_node
class TreeWalk(MetaFlatten):
"""The TreeWalk class can be used as a superclass in order
to walk an AST or similar tree.
Unlike other treewalkers, this class can walk a tree either
recursively or non-recursively. Subclasses can define
methods with the following signatures::
def pre_xxx(self):
pass
def post_xxx(self):
pass
def init_xxx(self):
pass
Where 'xxx' is one of:
- A class name
- An attribute member name concatenated with '_name'
For example, 'pre_targets_name' will process nodes
that are referenced by the name 'targets' in their
parent's node.
- An attribute member name concatenated with '_item'
For example, 'pre_targets_item' will process nodes
that are in a list that is the targets attribute
of some node.
pre_xxx will process a node before processing any of its subnodes.
if the return value from pre_xxx evalates to true, then walk
will not process any of the subnodes. Those can be manually
processed, if desired, by calling self.walk(node) on the subnodes
before returning True.
post_xxx will process a node after processing all its subnodes.
init_xxx methods can decorate the class instance with subclass-specific
information. A single init_whatever method could be written, but to
make it easy to keep initialization with use, any number of init_xxx
methods can be written. They will be called in alphabetical order.
"""
nodestack = None
def __init__(self, node=None):
self.setup()
if node is not None:
self.walk(node)
def setup(self):
"""All the node-specific handlers are setup at
object initialization time.
"""
self.pre_handlers = pre_handlers = {}
self.post_handlers = post_handlers = {}
for name in sorted(vars(type(self))):
if name.startswith('init_'):
getattr(self, name)()
elif name.startswith('pre_'):
pre_handlers[name[4:]] = getattr(self, name)
elif name.startswith('post_'):
post_handlers[name[5:]] = getattr(self, name)
def walk(self, node, name='', list=list, len=len, type=type):
"""Walk the tree starting at a given node.
Maintain a stack of nodes.
"""
pre_handlers = self.pre_handlers.get
post_handlers = self.post_handlers.get
oldstack = self.nodestack
self.nodestack = nodestack = []
append, pop = nodestack.append, nodestack.pop
append([node, name, list(iter_node(node, name + '_item')), -1])
while nodestack:
node, name, subnodes, index = nodestack[-1]
if index >= len(subnodes):
handler = (post_handlers(type(node).__name__) or
post_handlers(name + '_name'))
if handler is None:
pop()
continue
self.cur_node = node
self.cur_name = name
handler()
current = nodestack and nodestack[-1]
popstack = current and current[0] is node
if popstack and current[-1] >= len(current[-2]):
pop()
continue
nodestack[-1][-1] = index + 1
if index < 0:
handler = (pre_handlers(type(node).__name__) or
pre_handlers(name + '_name'))
if handler is not None:
self.cur_node = node
self.cur_name = name
if handler():
pop()
else:
node, name = subnodes[index]
append([node, name, list(iter_node(node, name + '_item')), -1])
self.nodestack = oldstack
@property
def parent(self):
"""Return the parent node of the current node."""
nodestack = self.nodestack
if len(nodestack) < 2:
return None
return nodestack[-2][0]
@property
def parent_name(self):
"""Return the parent node and name."""
nodestack = self.nodestack
if len(nodestack) < 2:
return None
return nodestack[-2][:2]
def replace(self, new_node):
"""Replace a node after first checking integrity of node stack."""
cur_node = self.cur_node
nodestack = self.nodestack
cur = nodestack.pop()
prev = nodestack[-1]
index = prev[-1] - 1
oldnode, name = prev[-2][index]
assert cur[0] is cur_node is oldnode, (cur[0], cur_node, prev[-2],
index)
parent = prev[0]
if isinstance(parent, list):
parent[index] = new_node
else:
setattr(parent, name, new_node)
|