/usr/lib/python3/dist-packages/chameleon/codegen.py is in python3-chameleon 2.24-1.
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 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | try:
import ast
except ImportError:
from chameleon import ast25 as ast
import inspect
import textwrap
import types
import copy
try:
import __builtin__ as builtins
except ImportError:
import builtins
reverse_builtin_map = {}
for name, value in builtins.__dict__.items():
try:
hash(value)
except TypeError:
continue
reverse_builtin_map[value] = name
try:
basestring
except NameError:
basestring = str
from .astutil import ASTCodeGenerator
from .astutil import load
from .astutil import store
from .astutil import parse
from .astutil import Builtin
from .astutil import Symbol
from .astutil import node_annotations
from .exc import CompilationError
try:
NATIVE_NUMBERS = int, float, long, bool
except NameError:
NATIVE_NUMBERS = int, float, bool
def template(function, mode='exec', **kw):
def wrapper(*vargs, **kwargs):
symbols = dict(zip(args, vargs + defaults))
symbols.update(kwargs)
class Visitor(ast.NodeVisitor):
def visit_FunctionDef(self, node):
self.generic_visit(node)
name = symbols.get(node.name, self)
if name is not self:
node_annotations[node] = ast.FunctionDef(
name=name,
args=node.args,
body=node.body,
decorator_list=getattr(node, "decorator_list", []),
)
def visit_Name(self, node):
value = symbols.get(node.id, self)
if value is not self:
if isinstance(value, basestring):
value = load(value)
if isinstance(value, type) or value in reverse_builtin_map:
name = reverse_builtin_map.get(value)
if name is not None:
value = Builtin(name)
else:
value = Symbol(value)
assert node not in node_annotations
assert hasattr(value, '_fields')
node_annotations[node] = value
expr = parse(source, mode=mode)
if not isinstance(function, basestring):
expr = expr.body[0]
Visitor().visit(expr)
return expr.body
if isinstance(function, basestring):
source = function
defaults = args = ()
return wrapper(**kw)
source = textwrap.dedent(inspect.getsource(function))
argspec = inspect.getargspec(function)
args = argspec[0]
defaults = argspec[3] or ()
return wrapper
class TemplateCodeGenerator(ASTCodeGenerator):
"""Extends the standard Python code generator class with handlers
for the helper node classes:
- Symbol (an importable value)
- Static (value that can be made global)
- Builtin (from the builtins module)
- Marker (short-hand for a unique static object)
"""
names = ()
def __init__(self, tree):
self.imports = {}
self.defines = {}
self.markers = {}
# Generate code
super(TemplateCodeGenerator, self).__init__(tree)
def visit_Module(self, node):
super(TemplateCodeGenerator, self).visit_Module(node)
# Make sure we terminate the line printer
self.flush()
# Clear lines array for import visits
body = self.lines
self.lines = []
while self.defines:
name, node = self.defines.popitem()
assignment = ast.Assign(targets=[store(name)], value=node)
self.visit(assignment)
# Make sure we terminate the line printer
self.flush()
# Clear lines array for import visits
defines = self.lines
self.lines = []
while self.imports:
value, node = self.imports.popitem()
if isinstance(value, types.ModuleType):
stmt = ast.Import(
names=[ast.alias(name=value.__name__, asname=node.id)])
elif hasattr(value, '__name__'):
path = reverse_builtin_map.get(value)
if path is None:
path = value.__module__
name = value.__name__
stmt = ast.ImportFrom(
module=path,
names=[ast.alias(name=name, asname=node.id)],
level=0,
)
else:
raise TypeError(value)
self.visit(stmt)
# Clear last import
self.flush()
# Stich together lines
self.lines += defines + body
def define(self, name, node):
assert node is not None
value = self.defines.get(name)
if value is node:
pass
elif value is None:
self.defines[name] = node
else:
raise CompilationError(
"Duplicate symbol name for define.", name)
return load(name)
def require(self, value):
if value is None:
return load("None")
if isinstance(value, NATIVE_NUMBERS):
return ast.Num(value)
node = self.imports.get(value)
if node is None:
# we come up with a unique symbol based on the class name
name = "_%s" % getattr(value, '__name__', str(value)).\
rsplit('.', 1)[-1]
node = load(name)
self.imports[value] = store(node.id)
return node
def visit(self, node):
annotation = node_annotations.get(node)
if annotation is None:
super(TemplateCodeGenerator, self).visit(node)
else:
self.visit(annotation)
def visit_Comment(self, node):
if node.stmt is None:
self._new_line()
else:
self.visit(node.stmt)
for line in node.text.replace('\r', '\n').split('\n'):
self._new_line()
self._write("%s#%s" % (node.space, line))
def visit_Builtin(self, node):
name = load(node.id)
self.visit(name)
def visit_Symbol(self, node):
node = self.require(node.value)
self.visit(node)
def visit_Static(self, node):
if node.name is None:
name = "_static_%s" % str(id(node.value)).replace('-', '_')
else:
name = node.name
node = self.define(name, node.value)
self.visit(node)
|