From 86b98a11559da7d1b21dc9b4c6b10511b9095bc4 Mon Sep 17 00:00:00 2001 From: Simon Cross 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