Gentoo Archives: gentoo-commits

From: Aaron Bauman <bman@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] repo/gentoo:master commit in: dev-python/genshi/files/
Date: Thu, 14 May 2020 22:19:50
Message-Id: 1589494766.e415f7c627770cb061257a96c5f14903192742f0.bman@gentoo
1 commit: e415f7c627770cb061257a96c5f14903192742f0
2 Author: Michael Mair-Keimberger <m.mairkeimberger <AT> gmail <DOT> com>
3 AuthorDate: Mon Mar 30 16:17:08 2020 +0000
4 Commit: Aaron Bauman <bman <AT> gentoo <DOT> org>
5 CommitDate: Thu May 14 22:19:26 2020 +0000
6 URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=e415f7c6
7
8 dev-python/genshi: remove unused patch(es)
9
10 Package-Manager: Portage-2.3.96, Repoman-2.3.22
11 Signed-off-by: Michael Mair-Keimberger <m.mairkeimberger <AT> gmail.com>
12 Signed-off-by: Aaron Bauman <bman <AT> gentoo.org>
13
14 ...enshi-0.7-fix_tests_failure_with_python27.patch | 25 --
15 dev-python/genshi/files/genshi-0.7-issue566.patch | 57 ----
16 dev-python/genshi/files/genshi-0.7-issue582.patch | 364 ---------------------
17 dev-python/genshi/files/genshi-0.7-issue602.patch | 114 -------
18 4 files changed, 560 deletions(-)
19
20 diff --git a/dev-python/genshi/files/genshi-0.7-fix_tests_failure_with_python27.patch b/dev-python/genshi/files/genshi-0.7-fix_tests_failure_with_python27.patch
21 deleted file mode 100644
22 index 4f3467d6481..00000000000
23 --- a/dev-python/genshi/files/genshi-0.7-fix_tests_failure_with_python27.patch
24 +++ /dev/null
25 @@ -1,25 +0,0 @@
26 -From 7f3552a9373fadd2d37ff592769ba6c65755eea5 Mon Sep 17 00:00:00 2001
27 -From: SVN-Git Migration <python-modules-team@×××××××××××××××××××.org>
28 -Date: Thu, 8 Oct 2015 09:13:47 -0700
29 -Subject: Skip test which still fails in Python 2.7.6.
30 -
31 -Author: Barry Warsaw <barry@××××××.org>, Arnaud Fontaine <arnau@××××××.org>
32 -Bug: http://genshi.edgewall.org/ticket/500
33 -
34 -Patch-Name: fix_tests_failure_with_python27.patch
35 ----
36 - genshi/filters/tests/test_html.py | 1 +
37 - 1 file changed, 1 insertion(+)
38 -
39 -diff --git a/genshi/filters/tests/test_html.py b/genshi/filters/tests/test_html.py
40 -index 0c6cfe1..a8cfa04 100644
41 ---- a/genshi/filters/tests/test_html.py
42 -+++ b/genshi/filters/tests/test_html.py
43 -@@ -410,6 +410,7 @@ class HTMLSanitizerTestCase(unittest.TestCase):
44 - html = HTML(u'&junk;')
45 - self.assertEquals('&amp;junk;', (html | HTMLSanitizer()).render())
46 -
47 -+ @unittest.skip('http://genshi.edgewall.org/ticket/500#comment:3')
48 - def test_sanitize_remove_script_elem(self):
49 - html = HTML(u'<script>alert("Foo")</script>')
50 - self.assertEquals('', (html | HTMLSanitizer()).render())
51
52 diff --git a/dev-python/genshi/files/genshi-0.7-issue566.patch b/dev-python/genshi/files/genshi-0.7-issue566.patch
53 deleted file mode 100644
54 index 70fc8ea85e6..00000000000
55 --- a/dev-python/genshi/files/genshi-0.7-issue566.patch
56 +++ /dev/null
57 @@ -1,57 +0,0 @@
58 -From fafbc4296902b2259c23d2ce55996b0127726b4f Mon Sep 17 00:00:00 2001
59 -From: SVN-Git Migration <python-modules-team@×××××××××××××××××××.org>
60 -Date: Thu, 8 Oct 2015 09:13:49 -0700
61 -Subject: Fix an IndexError preventing Genshi for uploading attachments in
62 -
63 - Trac for users with non-English language settings.
64 -Origin: http://genshi.edgewall.org/changeset/1243?format=diff&new=1243
65 -Bug: http://genshi.edgewall.org/ticket/566
66 -
67 -Patch-Name: issue566.patch
68 ----
69 - genshi/filters/i18n.py | 8 +++++++-
70 - genshi/filters/tests/i18n.py | 12 ++++++++++++
71 - 2 files changed, 19 insertions(+), 1 deletion(-)
72 -
73 -diff --git a/genshi/filters/i18n.py b/genshi/filters/i18n.py
74 -index dfb52b8..8f2d25c 100644
75 ---- a/genshi/filters/i18n.py
76 -+++ b/genshi/filters/i18n.py
77 -@@ -1048,7 +1048,13 @@ class MessageBuffer(object):
78 -
79 - while parts:
80 - order, string = parts.pop(0)
81 -- events = self.events[order].pop(0)
82 -+ events = self.events[order]
83 -+ if events:
84 -+ events = events.pop(0)
85 -+ else:
86 -+ # create a dummy empty text event so any remaining
87 -+ # part of the translation can be processed.
88 -+ events = [(TEXT, "", (None, -1, -1))]
89 - parts_counter[order].pop()
90 -
91 - for event in events:
92 -diff --git a/genshi/filters/tests/i18n.py b/genshi/filters/tests/i18n.py
93 -index 212d5f6..b36a30b 100644
94 ---- a/genshi/filters/tests/i18n.py
95 -+++ b/genshi/filters/tests/i18n.py
96 -@@ -928,6 +928,18 @@ class MsgDirectiveTestCase(unittest.TestCase):
97 - """</p></html>""",
98 - tmpl.generate(first="FIRST", second="SECOND").render())
99 -
100 -+ def test_translate_i18n_msg_ticket_404_regression(self):
101 -+ tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
102 -+ xmlns:i18n="http://genshi.edgewall.org/i18n">
103 -+ <h1 i18n:msg="name">text <a>$name</a></h1>
104 -+ </html>""")
105 -+ gettext = lambda s: u'head [1:%(name)s] tail'
106 -+ translator = Translator(gettext)
107 -+ translator.setup(tmpl)
108 -+ self.assertEqual("""<html>
109 -+ <h1>head <a>NAME</a> tail</h1>
110 -+ </html>""", tmpl.generate(name='NAME').render())
111 -+
112 -
113 - class ChooseDirectiveTestCase(unittest.TestCase):
114 -
115
116 diff --git a/dev-python/genshi/files/genshi-0.7-issue582.patch b/dev-python/genshi/files/genshi-0.7-issue582.patch
117 deleted file mode 100644
118 index fbcab626d6c..00000000000
119 --- a/dev-python/genshi/files/genshi-0.7-issue582.patch
120 +++ /dev/null
121 @@ -1,364 +0,0 @@
122 -From 554fa3428bea3039decfd9064b860c753b2637a1 Mon Sep 17 00:00:00 2001
123 -From: SVN-Git Migration <python-modules-team@×××××××××××××××××××.org>
124 -Date: Thu, 8 Oct 2015 09:13:48 -0700
125 -Subject: Make genshi 0.7 compatible with Python 3.4.
126 -
127 -Origin: http://genshi.edgewall.org/changeset/1252?format=diff&new=1252
128 -Bug: http://genshi.edgewall.org/ticket/582
129 -Forwarded: not-needed
130 -
131 -Patch-Name: issue582.patch
132 ----
133 - doc/upgrade.txt | 8 ++---
134 - genshi/compat.py | 10 +++++-
135 - genshi/filters/tests/test_html.py | 14 ++++++---
136 - genshi/template/astutil.py | 66 ++++++++++++++++++++++++++++-----------
137 - genshi/template/eval.py | 37 +++++++++++++---------
138 - genshi/template/tests/eval.py | 23 ++++++++++++++
139 - run_benchmarks.sh | 31 ++++++++++++++++++
140 - setup.py | 6 +++-
141 - 8 files changed, 151 insertions(+), 44 deletions(-)
142 - create mode 100644 run_benchmarks.sh
143 -
144 -diff --git a/doc/upgrade.txt b/doc/upgrade.txt
145 -index b240eda..ad4c080 100644
146 ---- a/doc/upgrade.txt
147 -+++ b/doc/upgrade.txt
148 -@@ -7,11 +7,11 @@ Upgrading Genshi
149 - :depth: 2
150 - .. sectnum::
151 -
152 --------------------------------------------------------
153 --Upgrading from Genshi 0.6.x to the development version
154 --------------------------------------------------------
155 -+-------------------------------------------
156 -+Upgrading from Genshi 0.6.x to Genshi 0.7.x
157 -+-------------------------------------------
158 -
159 --The Genshi development version now supports both Python 2 and Python 3.
160 -+Genshi 0.7.x now supports both Python 2 and Python 3.
161 -
162 - The most noticable API change in the Genshi development version is that the
163 - default encoding in numerous places is now None (i.e. unicode) instead
164 -diff --git a/genshi/compat.py b/genshi/compat.py
165 -index 9787325..6574e39 100644
166 ---- a/genshi/compat.py
167 -+++ b/genshi/compat.py
168 -@@ -35,6 +35,15 @@ else:
169 - 'Python 2 compatibility function. Not usable in Python 3.')
170 -
171 -
172 -+# We need to test if an object is an instance of a string type in places
173 -+
174 -+if IS_PYTHON2:
175 -+ def isstring(obj):
176 -+ return isinstance(obj, basestring)
177 -+else:
178 -+ def isstring(obj):
179 -+ return isinstance(obj, str)
180 -+
181 - # We need to differentiate between StringIO and BytesIO in places
182 -
183 - if IS_PYTHON2:
184 -@@ -112,4 +121,3 @@ except NameError:
185 - if not x:
186 - return False
187 - return True
188 --
189 -diff --git a/genshi/filters/tests/test_html.py b/genshi/filters/tests/test_html.py
190 -index a8cfa04..7120988 100644
191 ---- a/genshi/filters/tests/test_html.py
192 -+++ b/genshi/filters/tests/test_html.py
193 -@@ -368,12 +368,16 @@ def StyleSanitizer():
194 -
195 - class HTMLSanitizerTestCase(unittest.TestCase):
196 -
197 -- def assert_parse_error_or_equal(self, expected, exploit):
198 -+ def assert_parse_error_or_equal(self, expected, exploit,
199 -+ allow_strip=False):
200 - try:
201 - html = HTML(exploit)
202 - except ParseError:
203 - return
204 -- self.assertEquals(expected, (html | HTMLSanitizer()).render())
205 -+ sanitized_html = (html | HTMLSanitizer()).render()
206 -+ if not sanitized_html and allow_strip:
207 -+ return
208 -+ self.assertEquals(expected, sanitized_html)
209 -
210 - def test_sanitize_unchanged(self):
211 - html = HTML(u'<a href="#">fo<br />o</a>')
212 -@@ -417,10 +421,12 @@ class HTMLSanitizerTestCase(unittest.TestCase):
213 - html = HTML(u'<SCRIPT SRC="http://example.com/"></SCRIPT>')
214 - self.assertEquals('', (html | HTMLSanitizer()).render())
215 - src = u'<SCR\0IPT>alert("foo")</SCR\0IPT>'
216 -- self.assert_parse_error_or_equal('&lt;SCR\x00IPT&gt;alert("foo")', src)
217 -+ self.assert_parse_error_or_equal('&lt;SCR\x00IPT&gt;alert("foo")', src,
218 -+ allow_strip=True)
219 - src = u'<SCRIPT&XYZ SRC="http://example.com/"></SCRIPT>'
220 - self.assert_parse_error_or_equal('&lt;SCRIPT&amp;XYZ; '
221 -- 'SRC="http://example.com/"&gt;', src)
222 -+ 'SRC="http://example.com/"&gt;', src,
223 -+ allow_strip=True)
224 -
225 - def test_sanitize_remove_onclick_attr(self):
226 - html = HTML(u'<div onclick=\'alert("foo")\' />')
227 -diff --git a/genshi/template/astutil.py b/genshi/template/astutil.py
228 -index b24f728..e561846 100644
229 ---- a/genshi/template/astutil.py
230 -+++ b/genshi/template/astutil.py
231 -@@ -21,7 +21,7 @@ else:
232 - def parse(source, mode):
233 - return compile(source, '', mode, _ast.PyCF_ONLY_AST)
234 -
235 --from genshi.compat import IS_PYTHON2
236 -+from genshi.compat import IS_PYTHON2, isstring
237 -
238 - __docformat__ = 'restructuredtext en'
239 -
240 -@@ -103,32 +103,48 @@ class ASTCodeGenerator(object):
241 - self._new_line()
242 - return self.visit(node.body)
243 -
244 -+ # Python < 3.4
245 - # arguments = (expr* args, identifier? vararg,
246 - # identifier? kwarg, expr* defaults)
247 -+ #
248 -+ # Python >= 3.4
249 -+ # arguments = (arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults,
250 -+ # arg? kwarg, expr* defaults)
251 - def visit_arguments(self, node):
252 -- first = True
253 -- no_default_count = len(node.args) - len(node.defaults)
254 -- for i, arg in enumerate(node.args):
255 -- if not first:
256 -- self._write(', ')
257 -+ def write_possible_comma():
258 -+ if _first[0]:
259 -+ _first[0] = False
260 - else:
261 -- first = False
262 -- self.visit(arg)
263 -- if i >= no_default_count:
264 -- self._write('=')
265 -- self.visit(node.defaults[i - no_default_count])
266 -- if getattr(node, 'vararg', None):
267 -- if not first:
268 - self._write(', ')
269 -+ _first = [True]
270 -+
271 -+ def write_args(args, defaults):
272 -+ no_default_count = len(args) - len(defaults)
273 -+ for i, arg in enumerate(args):
274 -+ write_possible_comma()
275 -+ self.visit(arg)
276 -+ default_idx = i - no_default_count
277 -+ if default_idx >= 0 and defaults[default_idx] is not None:
278 -+ self._write('=')
279 -+ self.visit(defaults[i - no_default_count])
280 -+
281 -+ write_args(node.args, node.defaults)
282 -+ if getattr(node, 'vararg', None):
283 -+ write_possible_comma()
284 -+ self._write('*')
285 -+ if isstring(node.vararg):
286 -+ self._write(node.vararg)
287 - else:
288 -- first = False
289 -- self._write('*' + node.vararg)
290 -+ self.visit(node.vararg)
291 -+ if getattr(node, 'kwonlyargs', None):
292 -+ write_args(node.kwonlyargs, node.kw_defaults)
293 - if getattr(node, 'kwarg', None):
294 -- if not first:
295 -- self._write(', ')
296 -+ write_possible_comma()
297 -+ self._write('**')
298 -+ if isstring(node.kwarg):
299 -+ self._write(node.kwarg)
300 - else:
301 -- first = False
302 -- self._write('**' + node.kwarg)
303 -+ self.visit(node.kwarg)
304 -
305 - if not IS_PYTHON2:
306 - # In Python 3 arguments get a special node
307 -@@ -732,6 +748,17 @@ class ASTCodeGenerator(object):
308 - def visit_Name(self, node):
309 - self._write(node.id)
310 -
311 -+ # NameConstant(singleton value)
312 -+ def visit_NameConstant(self, node):
313 -+ if node.value is None:
314 -+ self._write('None')
315 -+ elif node.value is True:
316 -+ self._write('True')
317 -+ elif node.value is False:
318 -+ self._write('False')
319 -+ else:
320 -+ raise Exception("Unknown NameConstant %r" % (node.value,))
321 -+
322 - # List(expr* elts, expr_context ctx)
323 - def visit_List(self, node):
324 - self._write('[')
325 -@@ -837,6 +864,7 @@ class ASTTransformer(object):
326 - visit_Attribute = _clone
327 - visit_Subscript = _clone
328 - visit_Name = _clone
329 -+ visit_NameConstant = _clone
330 - visit_List = _clone
331 - visit_Tuple = _clone
332 -
333 -diff --git a/genshi/template/eval.py b/genshi/template/eval.py
334 -index c00cfcb..81644a7 100644
335 ---- a/genshi/template/eval.py
336 -+++ b/genshi/template/eval.py
337 -@@ -24,7 +24,8 @@ from genshi.template.astutil import ASTTransformer, ASTCodeGenerator, \
338 - from genshi.template.base import TemplateRuntimeError
339 - from genshi.util import flatten
340 -
341 --from genshi.compat import get_code_params, build_code_chunk, IS_PYTHON2
342 -+from genshi.compat import get_code_params, build_code_chunk, isstring, \
343 -+ IS_PYTHON2
344 -
345 - __all__ = ['Code', 'Expression', 'Suite', 'LenientLookup', 'StrictLookup',
346 - 'Undefined', 'UndefinedError']
347 -@@ -495,28 +496,34 @@ class TemplateASTTransformer(ASTTransformer):
348 - def __init__(self):
349 - self.locals = [CONSTANTS]
350 -
351 -+ def _process(self, names, node):
352 -+ if not IS_PYTHON2 and isinstance(node, _ast.arg):
353 -+ names.add(node.arg)
354 -+ elif isstring(node):
355 -+ names.add(node)
356 -+ elif isinstance(node, _ast.Name):
357 -+ names.add(node.id)
358 -+ elif isinstance(node, _ast.alias):
359 -+ names.add(node.asname or node.name)
360 -+ elif isinstance(node, _ast.Tuple):
361 -+ for elt in node.elts:
362 -+ self._process(names, elt)
363 -+
364 - def _extract_names(self, node):
365 - names = set()
366 -- def _process(node):
367 -- if not IS_PYTHON2 and isinstance(node, _ast.arg):
368 -- names.add(node.arg)
369 -- if isinstance(node, _ast.Name):
370 -- names.add(node.id)
371 -- elif isinstance(node, _ast.alias):
372 -- names.add(node.asname or node.name)
373 -- elif isinstance(node, _ast.Tuple):
374 -- for elt in node.elts:
375 -- _process(elt)
376 - if hasattr(node, 'args'):
377 - for arg in node.args:
378 -- _process(arg)
379 -+ self._process(names, arg)
380 -+ if hasattr(node, 'kwonlyargs'):
381 -+ for arg in node.kwonlyargs:
382 -+ self._process(names, arg)
383 - if hasattr(node, 'vararg'):
384 -- names.add(node.vararg)
385 -+ self._process(names, node.vararg)
386 - if hasattr(node, 'kwarg'):
387 -- names.add(node.kwarg)
388 -+ self._process(names, node.kwarg)
389 - elif hasattr(node, 'names'):
390 - for elt in node.names:
391 -- _process(elt)
392 -+ self._process(names, elt)
393 - return names
394 -
395 - def visit_Str(self, node):
396 -diff --git a/genshi/template/tests/eval.py b/genshi/template/tests/eval.py
397 -index 7722571..c44a0e3 100644
398 ---- a/genshi/template/tests/eval.py
399 -+++ b/genshi/template/tests/eval.py
400 -@@ -590,6 +590,29 @@ x = smash(foo='abc', bar='def')
401 - suite.execute(data)
402 - self.assertEqual(['bardef', 'fooabc'], sorted(data['x']))
403 -
404 -+ if not IS_PYTHON2:
405 -+ def test_def_kwonlyarg(self):
406 -+ suite = Suite("""
407 -+def kwonly(*args, k):
408 -+ return k
409 -+x = kwonly(k="foo")
410 -+""")
411 -+ data = {}
412 -+ suite.execute(data)
413 -+ self.assertEqual("foo", data['x'])
414 -+
415 -+ def test_def_kwonlyarg_with_default(self):
416 -+ suite = Suite("""
417 -+def kwonly(*args, k="bar"):
418 -+ return k
419 -+x = kwonly(k="foo")
420 -+y = kwonly()
421 -+""")
422 -+ data = {}
423 -+ suite.execute(data)
424 -+ self.assertEqual("foo", data['x'])
425 -+ self.assertEqual("bar", data['y'])
426 -+
427 - def test_def_nested(self):
428 - suite = Suite("""
429 - def doit():
430 -diff --git a/run_benchmarks.sh b/run_benchmarks.sh
431 -new file mode 100644
432 -index 0000000..0c64cc8
433 ---- /dev/null
434 -+++ b/run_benchmarks.sh
435 -@@ -0,0 +1,31 @@
436 -+#!/bin/sh
437 -+#
438 -+# 1. Run the tests with `tox` (this will set up all the tox envs).
439 -+# 2. ./run_benchmarks.sh <env-name> | tee results-<env-name>.out
440 -+
441 -+NAME="$1"
442 -+PYTHON="./.tox/$NAME/bin/python"
443 -+BENCH_DIR="bench_build/$1"
444 -+BENCH_BIN_DIR="$BENCH_DIR/bin"
445 -+mkdir -p "bench_build"
446 -+
447 -+rm -rf "$BENCH_DIR"
448 -+cp -R "examples/bench" "$BENCH_DIR"
449 -+
450 -+case "$NAME" in
451 -+ py32|py33)
452 -+ 2to3 -w --no-diffs "$BENCH_DIR"
453 -+ ;;
454 -+esac
455 -+
456 -+echo "-- basic --"
457 -+"$PYTHON" "$BENCH_DIR/basic.py"
458 -+echo
459 -+
460 -+echo "-- bigtable --"
461 -+"$PYTHON" "$BENCH_DIR/bigtable.py"
462 -+echo
463 -+
464 -+echo "-- xpath --"
465 -+"$PYTHON" "$BENCH_DIR/xpath.py"
466 -+echo
467 -diff --git a/setup.py b/setup.py
468 -index 294ba9b..45099b5 100755
469 ---- a/setup.py
470 -+++ b/setup.py
471 -@@ -65,9 +65,13 @@ available.""")
472 -
473 -
474 - if Feature:
475 -+ # Optional C extension module for speeding up Genshi:
476 -+ # Not activated by default on:
477 -+ # - PyPy (where it harms performance)
478 -+ # - CPython >= 3.3 (the new Unicode C API is not supported yet)
479 - speedups = Feature(
480 - "optional C speed-enhancements",
481 -- standard = not is_pypy,
482 -+ standard = not is_pypy and sys.version_info < (3, 3),
483 - ext_modules = [
484 - Extension('genshi._speedups', ['genshi/_speedups.c']),
485 - ],
486
487 diff --git a/dev-python/genshi/files/genshi-0.7-issue602.patch b/dev-python/genshi/files/genshi-0.7-issue602.patch
488 deleted file mode 100644
489 index d7f0b77fa92..00000000000
490 --- a/dev-python/genshi/files/genshi-0.7-issue602.patch
491 +++ /dev/null
492 @@ -1,114 +0,0 @@
493 -From 1acbd00b4961164edc8a185458ba4a433bedbceb Mon Sep 17 00:00:00 2001
494 -From: SVN-Git Migration <python-modules-team@×××××××××××××××××××.org>
495 -Date: Thu, 8 Oct 2015 09:13:46 -0700
496 -Subject: Fix Python 3.5 compatibility issues.
497 -
498 -Origin: http://genshi.edgewall.org/attachment/ticket/602/t602.diff
499 -Bug: http://genshi.edgewall.org/ticket/602
500 -Forwarded: not-needed
501 -
502 -Patch-Name: issue602.patch
503 ----
504 - genshi/filters/i18n.py | 6 ++++--
505 - genshi/template/astutil.py | 14 +++++++++++---
506 - genshi/template/directives.py | 20 ++++++++++++++------
507 - genshi/template/eval.py | 5 +++++
508 - 4 files changed, 34 insertions(+), 11 deletions(-)
509 -
510 -diff --git a/genshi/filters/i18n.py b/genshi/filters/i18n.py
511 -index b724956..dfb52b8 100644
512 ---- a/genshi/filters/i18n.py
513 -+++ b/genshi/filters/i18n.py
514 -@@ -1187,8 +1187,10 @@ def extract_from_code(code, gettext_functions):
515 - elif arg:
516 - strings.append(None)
517 - [_add(arg) for arg in node.args]
518 -- _add(node.starargs)
519 -- _add(node.kwargs)
520 -+ if hasattr(node, 'starargs'):
521 -+ _add(node.starargs)
522 -+ if hasattr(node, 'kwargs'):
523 -+ _add(node.kwargs)
524 - if len(strings) == 1:
525 - strings = strings[0]
526 - else:
527 -diff --git a/genshi/template/astutil.py b/genshi/template/astutil.py
528 -index a4c21c8..b24f728 100644
529 ---- a/genshi/template/astutil.py
530 -+++ b/genshi/template/astutil.py
531 -@@ -135,6 +135,10 @@ class ASTCodeGenerator(object):
532 - def visit_arg(self, node):
533 - self._write(node.arg)
534 -
535 -+ def visit_Starred(self, node):
536 -+ self._write('*')
537 -+ self.visit(node.value)
538 -+
539 - # FunctionDef(identifier name, arguments args,
540 - # stmt* body, expr* decorator_list)
541 - def visit_FunctionDef(self, node):
542 -@@ -648,9 +652,13 @@ class ASTCodeGenerator(object):
543 - if not first:
544 - self._write(', ')
545 - first = False
546 -- # keyword = (identifier arg, expr value)
547 -- self._write(keyword.arg)
548 -- self._write('=')
549 -+ if not keyword.arg:
550 -+ # Python 3.5+ star-star args
551 -+ self._write('**')
552 -+ else:
553 -+ # keyword = (identifier arg, expr value)
554 -+ self._write(keyword.arg)
555 -+ self._write('=')
556 - self.visit(keyword.value)
557 - if getattr(node, 'starargs', None):
558 - if not first:
559 -diff --git a/genshi/template/directives.py b/genshi/template/directives.py
560 -index 7301c2d..1f70ef6 100644
561 ---- a/genshi/template/directives.py
562 -+++ b/genshi/template/directives.py
563 -@@ -266,13 +266,21 @@ class DefDirective(Directive):
564 - if isinstance(ast, _ast.Call):
565 - self.name = ast.func.id
566 - for arg in ast.args:
567 -- # only names
568 -- self.args.append(arg.id)
569 -+ if hasattr(_ast, 'Starred') and isinstance(arg, _ast.Starred):
570 -+ # Python 3.5+
571 -+ self.star_args = arg.value.id
572 -+ else:
573 -+ # only names
574 -+ self.args.append(arg.id)
575 - for kwd in ast.keywords:
576 -- self.args.append(kwd.arg)
577 -- exp = Expression(kwd.value, template.filepath,
578 -- lineno, lookup=template.lookup)
579 -- self.defaults[kwd.arg] = exp
580 -+ if kwd.arg is None:
581 -+ # Python 3.5+
582 -+ self.dstar_args = kwd.value.id
583 -+ else:
584 -+ self.args.append(kwd.arg)
585 -+ exp = Expression(kwd.value, template.filepath,
586 -+ lineno, lookup=template.lookup)
587 -+ self.defaults[kwd.arg] = exp
588 - if getattr(ast, 'starargs', None):
589 - self.star_args = ast.starargs.id
590 - if getattr(ast, 'kwargs', None):
591 -diff --git a/genshi/template/eval.py b/genshi/template/eval.py
592 -index 89aec49..c00cfcb 100644
593 ---- a/genshi/template/eval.py
594 -+++ b/genshi/template/eval.py
595 -@@ -593,6 +593,11 @@ class TemplateASTTransformer(ASTTransformer):
596 - finally:
597 - self.locals.pop()
598 -
599 -+ # Only used in Python 3.5+
600 -+ def visit_Starred(self, node):
601 -+ node.value = self.visit(node.value)
602 -+ return node
603 -+
604 - def visit_Name(self, node):
605 - # If the name refers to a local inside a lambda, list comprehension, or
606 - # generator expression, leave it alone