Blob Blame History Raw
Patch from Tim Hatch
http://genshi.edgewall.org/ticket/602

diff --git a/genshi/filters/i18n.py b/genshi/filters/i18n.py
index b724956..dfb52b8 100644
--- a/genshi/filters/i18n.py
+++ b/genshi/filters/i18n.py
@@ -1187,8 +1187,10 @@ def extract_from_code(code, gettext_functions):
                 elif arg:
                     strings.append(None)
             [_add(arg) for arg in node.args]
-            _add(node.starargs)
-            _add(node.kwargs)
+            if hasattr(node, 'starargs'):
+                _add(node.starargs)
+            if hasattr(node, 'kwargs'):
+                _add(node.kwargs)
             if len(strings) == 1:
                 strings = strings[0]
             else:
diff --git a/genshi/template/astutil.py b/genshi/template/astutil.py
index a3946b4..07edc92 100644
--- a/genshi/template/astutil.py
+++ b/genshi/template/astutil.py
@@ -148,6 +148,10 @@ class ASTCodeGenerator(object):
         def visit_arg(self, node):
             self._write(node.arg)
 
+    def visit_Starred(self, node):
+        self._write('*')
+        self.visit(node.value)
+
     # FunctionDef(identifier name, arguments args,
     #                           stmt* body, expr* decorator_list)
     def visit_FunctionDef(self, node):
@@ -661,9 +665,13 @@ class ASTCodeGenerator(object):
             if not first:
                 self._write(', ')
             first = False
-            # keyword = (identifier arg, expr value)
-            self._write(keyword.arg)
-            self._write('=')
+            if not keyword.arg:
+                # Python 3.5+ star-star args
+                self._write('**')
+            else:
+                # keyword = (identifier arg, expr value)
+                self._write(keyword.arg)
+                self._write('=')
             self.visit(keyword.value)
         if getattr(node, 'starargs', None):
             if not first:
diff --git a/genshi/template/directives.py b/genshi/template/directives.py
index 7301c2d..6fd0f28 100644
--- a/genshi/template/directives.py
+++ b/genshi/template/directives.py
@@ -266,13 +266,21 @@ class DefDirective(Directive):
         if isinstance(ast, _ast.Call):
             self.name = ast.func.id
             for arg in ast.args:
-                # only names
-                self.args.append(arg.id)
+                if isinstance(arg, _ast.Starred):
+                    # Python 3.5+
+                    self.star_args = arg.value.id
+                else:
+                    # only names
+                    self.args.append(arg.id)
             for kwd in ast.keywords:
-                self.args.append(kwd.arg)
-                exp = Expression(kwd.value, template.filepath,
-                                 lineno, lookup=template.lookup)
-                self.defaults[kwd.arg] = exp
+                if kwd.arg is None:
+                    # Python 3.5+
+                    self.dstar_args = kwd.value.id
+                else:
+                    self.args.append(kwd.arg)
+                    exp = Expression(kwd.value, template.filepath,
+                                     lineno, lookup=template.lookup)
+                    self.defaults[kwd.arg] = exp
             if getattr(ast, 'starargs', None):
                 self.star_args = ast.starargs.id
             if getattr(ast, 'kwargs', None):
diff --git a/genshi/template/eval.py b/genshi/template/eval.py
index de4bc86..065c0c7 100644
--- a/genshi/template/eval.py
+++ b/genshi/template/eval.py
@@ -597,6 +597,11 @@ class TemplateASTTransformer(ASTTransformer):
         finally:
             self.locals.pop()
 
+    # Only used in Python 3.5+
+    def visit_Starred(self, node):
+        node.value = self.visit(node.value)
+        return node
+
     def visit_Name(self, node):
         # If the name refers to a local inside a lambda, list comprehension, or
         # generator expression, leave it alone