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
|
From 86b98a11559da7d1b21dc9b4c6b10511b9095bc4 Mon Sep 17 00:00:00 2001
From: Simon Cross <hodgestar@gmail.com>
Date: Sun, 16 Feb 2014 18:46:15 +0000
Subject: [PATCH 05/16] Add support for Python 3.4 AST (support for
NameConstants and changes to existing to arguments node attributes).
---
genshi/template/astutil.py | 31 ++++++++++++++++++++++++++++---
genshi/template/eval.py | 34 +++++++++++++++++++---------------
2 files changed, 47 insertions(+), 18 deletions(-)
diff --git a/genshi/template/astutil.py b/genshi/template/astutil.py
index a4c21c8..a3946b4 100644
--- a/genshi/template/astutil.py
+++ b/genshi/template/astutil.py
@@ -21,7 +21,7 @@ else:
def parse(source, mode):
return compile(source, '', mode, _ast.PyCF_ONLY_AST)
-from genshi.compat import IS_PYTHON2
+from genshi.compat import IS_PYTHON2, isstring
__docformat__ = 'restructuredtext en'
@@ -103,8 +103,13 @@ class ASTCodeGenerator(object):
self._new_line()
return self.visit(node.body)
+ # Python < 3.4
# arguments = (expr* args, identifier? vararg,
# identifier? kwarg, expr* defaults)
+ #
+ # Python >= 3.4
+ # arguments = (arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults,
+ # arg? kwarg, expr* defaults)
def visit_arguments(self, node):
first = True
no_default_count = len(node.args) - len(node.defaults)
@@ -122,13 +127,21 @@ class ASTCodeGenerator(object):
self._write(', ')
else:
first = False
- self._write('*' + node.vararg)
+ self._write('*')
+ if isstring(node.vararg):
+ self._write(node.vararg)
+ else:
+ self.visit(node.vararg)
if getattr(node, 'kwarg', None):
if not first:
self._write(', ')
else:
first = False
- self._write('**' + node.kwarg)
+ self._write('**')
+ if isstring(node.kwarg):
+ self._write(node.kwarg)
+ else:
+ self.visit(node.kwarg)
if not IS_PYTHON2:
# In Python 3 arguments get a special node
@@ -724,6 +737,17 @@ class ASTCodeGenerator(object):
def visit_Name(self, node):
self._write(node.id)
+ # NameConstant(singleton value)
+ def visit_NameConstant(self, node):
+ if node.value is None:
+ self._write('None')
+ elif node.value is True:
+ self._write('True')
+ elif node.value is False:
+ self._write('False')
+ else:
+ raise Exception("Unknown NameConstant %r" % (node.value,))
+
# List(expr* elts, expr_context ctx)
def visit_List(self, node):
self._write('[')
@@ -829,6 +853,7 @@ class ASTTransformer(object):
visit_Attribute = _clone
visit_Subscript = _clone
visit_Name = _clone
+ visit_NameConstant = _clone
visit_List = _clone
visit_Tuple = _clone
diff --git a/genshi/template/eval.py b/genshi/template/eval.py
index 89aec49..de4bc86 100644
--- a/genshi/template/eval.py
+++ b/genshi/template/eval.py
@@ -24,7 +24,8 @@ from genshi.template.astutil import ASTTransformer, ASTCodeGenerator, \
from genshi.template.base import TemplateRuntimeError
from genshi.util import flatten
-from genshi.compat import get_code_params, build_code_chunk, IS_PYTHON2
+from genshi.compat import get_code_params, build_code_chunk, isstring, \
+ IS_PYTHON2
__all__ = ['Code', 'Expression', 'Suite', 'LenientLookup', 'StrictLookup',
'Undefined', 'UndefinedError']
@@ -495,28 +496,31 @@ class TemplateASTTransformer(ASTTransformer):
def __init__(self):
self.locals = [CONSTANTS]
+ def _process(self, names, node):
+ if not IS_PYTHON2 and isinstance(node, _ast.arg):
+ names.add(node.arg)
+ elif isstring(node):
+ names.add(node)
+ elif isinstance(node, _ast.Name):
+ names.add(node.id)
+ elif isinstance(node, _ast.alias):
+ names.add(node.asname or node.name)
+ elif isinstance(node, _ast.Tuple):
+ for elt in node.elts:
+ self._process(names, elt)
+
def _extract_names(self, node):
names = set()
- def _process(node):
- if not IS_PYTHON2 and isinstance(node, _ast.arg):
- names.add(node.arg)
- if isinstance(node, _ast.Name):
- names.add(node.id)
- elif isinstance(node, _ast.alias):
- names.add(node.asname or node.name)
- elif isinstance(node, _ast.Tuple):
- for elt in node.elts:
- _process(elt)
if hasattr(node, 'args'):
for arg in node.args:
- _process(arg)
+ self._process(names, arg)
if hasattr(node, 'vararg'):
- names.add(node.vararg)
+ self._process(names, node.vararg)
if hasattr(node, 'kwarg'):
- names.add(node.kwarg)
+ self._process(names, node.kwarg)
elif hasattr(node, 'names'):
for elt in node.names:
- _process(elt)
+ self._process(names, elt)
return names
def visit_Str(self, node):
--
2.12.0
|