# HG changeset patch # User hodgestar # Date 1392576375 0 # Node ID 2036193f89e769b4a4f42edc8490d9063af60c4b # Parent 500573200533496cdfc11fdb6f3a45345c7b59cb Add support for Python 3.4 AST (support for NameConstants and changes to existing to arguments node attributes). diff --git a/genshi/template/astutil.py b/genshi/template/astutil.py --- a/genshi/template/astutil.py +++ b/genshi/template/astutil.py @@ -21,7 +21,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 --- a/genshi/template/eval.py +++ b/genshi/template/eval.py @@ -24,7 +24,8 @@ 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 @@ 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):