diff --git a/gnu/local.mk b/gnu/local.mk index 0ef6e2af98..50e8713bf1 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -929,6 +929,12 @@ dist_patch_DATA = \ %D%/packages/patches/python-dendropy-fix-tests.patch \ %D%/packages/patches/python-file-double-encoding-bug.patch \ %D%/packages/patches/python-fix-tests.patch \ + %D%/packages/patches/python-genshi-add-support-for-python-3.4-AST.patch \ + %D%/packages/patches/python-genshi-buildable-on-python-2.7.patch \ + %D%/packages/patches/python-genshi-disable-speedups-on-python-3.3.patch \ + %D%/packages/patches/python-genshi-fix-tests-on-python-3.5.patch \ + %D%/packages/patches/python-genshi-isstring-helper.patch \ + %D%/packages/patches/python-genshi-stripping-of-unsafe-script-tags.patch \ %D%/packages/patches/python-parse-too-many-fields.patch \ %D%/packages/patches/python2-rdflib-drop-sparqlwrapper.patch \ %D%/packages/patches/python-statsmodels-fix-tests.patch \ diff --git a/gnu/packages/patches/python-genshi-add-support-for-python-3.4-AST.patch b/gnu/packages/patches/python-genshi-add-support-for-python-3.4-AST.patch new file mode 100644 index 0000000000..4e40c1daa1 --- /dev/null +++ b/gnu/packages/patches/python-genshi-add-support-for-python-3.4-AST.patch @@ -0,0 +1,151 @@ +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 + diff --git a/gnu/packages/patches/python-genshi-buildable-on-python-2.7.patch b/gnu/packages/patches/python-genshi-buildable-on-python-2.7.patch new file mode 100644 index 0000000000..2bc516c697 --- /dev/null +++ b/gnu/packages/patches/python-genshi-buildable-on-python-2.7.patch @@ -0,0 +1,25 @@ +From 32bfaa7cc1c736fd62fcbb6414de9498dc20ed07 Mon Sep 17 00:00:00 2001 +From: Adriano Peluso +Date: Wed, 5 Apr 2017 15:13:06 +0200 +Subject: [PATCH 2/2] buildable on python27 too + +--- + genshi/template/directives.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/genshi/template/directives.py b/genshi/template/directives.py +index 6fd0f28..1f70ef6 100644 +--- a/genshi/template/directives.py ++++ b/genshi/template/directives.py +@@ -266,7 +266,7 @@ class DefDirective(Directive): + if isinstance(ast, _ast.Call): + self.name = ast.func.id + for arg in ast.args: +- if isinstance(arg, _ast.Starred): ++ if hasattr(_ast, 'Starred') and isinstance(arg, _ast.Starred): + # Python 3.5+ + self.star_args = arg.value.id + else: +-- +2.12.0 + diff --git a/gnu/packages/patches/python-genshi-disable-speedups-on-python-3.3.patch b/gnu/packages/patches/python-genshi-disable-speedups-on-python-3.3.patch new file mode 100644 index 0000000000..c25c3bd7a9 --- /dev/null +++ b/gnu/packages/patches/python-genshi-disable-speedups-on-python-3.3.patch @@ -0,0 +1,32 @@ +From cef2c8df44166195e1705638f9f17033a4943bb7 Mon Sep 17 00:00:00 2001 +From: Simon Cross +Date: Sun, 16 Feb 2014 18:32:21 +0000 +Subject: [PATCH 02/15] Disable the speedups C extension on CPython >= 3.3 + since Genshi doesn't support the new Unicode C API yet. + +--- + setup.py | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/setup.py b/setup.py +index 123a2cb..a3d748c 100755 +--- a/setup.py ++++ b/setup.py +@@ -65,9 +65,13 @@ available.""") + + + if Feature: ++ # Optional C extension module for speeding up Genshi: ++ # Not activated by default on: ++ # - PyPy (where it harms performance) ++ # - CPython >= 3.3 (the new Unicode C API is not supported yet) + speedups = Feature( + "optional C speed-enhancements", +- standard = not is_pypy, ++ standard = not is_pypy and sys.version_info < (3, 3), + ext_modules = [ + Extension('genshi._speedups', ['genshi/_speedups.c']), + ], +-- +2.12.0 + diff --git a/gnu/packages/patches/python-genshi-fix-tests-on-python-3.5.patch b/gnu/packages/patches/python-genshi-fix-tests-on-python-3.5.patch new file mode 100644 index 0000000000..05be080cdf --- /dev/null +++ b/gnu/packages/patches/python-genshi-fix-tests-on-python-3.5.patch @@ -0,0 +1,112 @@ +From ce796ad4bae5c47011876778674ad036357febdf Mon Sep 17 00:00:00 2001 +From: Adriano Peluso +Date: Wed, 5 Apr 2017 15:10:06 +0200 +Subject: [PATCH 1/2] fixing the tests on python35 + +--- + genshi/filters/i18n.py | 6 ++++-- + genshi/template/astutil.py | 14 +++++++++++--- + genshi/template/directives.py | 20 ++++++++++++++------ + genshi/template/eval.py | 5 +++++ + 4 files changed, 34 insertions(+), 11 deletions(-) + +diff --git a/genshi/filters/i18n.py b/genshi/filters/i18n.py +index 526fda4..5387fcf 100644 +--- a/genshi/filters/i18n.py ++++ b/genshi/filters/i18n.py +@@ -1194,8 +1194,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 f4e1edd..e561846 100644 +--- a/genshi/template/astutil.py ++++ b/genshi/template/astutil.py +@@ -151,6 +151,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): +@@ -664,9 +668,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 d378419..81644a7 100644 +--- a/genshi/template/eval.py ++++ b/genshi/template/eval.py +@@ -600,6 +600,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 +-- +2.12.0 + diff --git a/gnu/packages/patches/python-genshi-isstring-helper.patch b/gnu/packages/patches/python-genshi-isstring-helper.patch new file mode 100644 index 0000000000..4f6c19bba9 --- /dev/null +++ b/gnu/packages/patches/python-genshi-isstring-helper.patch @@ -0,0 +1,37 @@ +From cc5e07284f44cdd9beec178c69070a53f55d1323 Mon Sep 17 00:00:00 2001 +From: Simon Cross +Date: Sun, 16 Feb 2014 18:43:20 +0000 +Subject: [PATCH 03/15] Add isstring helper. + +--- + genshi/compat.py | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/genshi/compat.py b/genshi/compat.py +index 9787325..6574e39 100644 +--- a/genshi/compat.py ++++ b/genshi/compat.py +@@ -35,6 +35,15 @@ else: + 'Python 2 compatibility function. Not usable in Python 3.') + + ++# We need to test if an object is an instance of a string type in places ++ ++if IS_PYTHON2: ++ def isstring(obj): ++ return isinstance(obj, basestring) ++else: ++ def isstring(obj): ++ return isinstance(obj, str) ++ + # We need to differentiate between StringIO and BytesIO in places + + if IS_PYTHON2: +@@ -112,4 +121,3 @@ except NameError: + if not x: + return False + return True +- +-- +2.12.0 + diff --git a/gnu/packages/patches/python-genshi-stripping-of-unsafe-script-tags.patch b/gnu/packages/patches/python-genshi-stripping-of-unsafe-script-tags.patch new file mode 100644 index 0000000000..29951a6149 --- /dev/null +++ b/gnu/packages/patches/python-genshi-stripping-of-unsafe-script-tags.patch @@ -0,0 +1,51 @@ +From 0769be04c3891ae5c724c6779ba13d1d0f53b4ae Mon Sep 17 00:00:00 2001 +From: Simon Cross +Date: Sun, 16 Feb 2014 18:25:17 +0000 +Subject: [PATCH 01/15] Also allow stripping of unsafe script tags (Python 3.4 + parses the second example as a tag whose name is script&xyz). + +--- + genshi/filters/tests/test_html.py | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/genshi/filters/tests/test_html.py b/genshi/filters/tests/test_html.py +index 0c6cfe1..45ec0da 100644 +--- a/genshi/filters/tests/test_html.py ++++ b/genshi/filters/tests/test_html.py +@@ -368,12 +368,16 @@ def StyleSanitizer(): + + class HTMLSanitizerTestCase(unittest.TestCase): + +- def assert_parse_error_or_equal(self, expected, exploit): ++ def assert_parse_error_or_equal(self, expected, exploit, ++ allow_strip=False): + try: + html = HTML(exploit) + except ParseError: + return +- self.assertEquals(expected, (html | HTMLSanitizer()).render()) ++ sanitized_html = (html | HTMLSanitizer()).render() ++ if not sanitized_html and allow_strip: ++ return ++ self.assertEquals(expected, sanitized_html) + + def test_sanitize_unchanged(self): + html = HTML(u'fo
o
') +@@ -416,10 +420,12 @@ class HTMLSanitizerTestCase(unittest.TestCase): + html = HTML(u'') + self.assertEquals('', (html | HTMLSanitizer()).render()) + src = u'alert("foo")' +- self.assert_parse_error_or_equal('<SCR\x00IPT>alert("foo")', src) ++ self.assert_parse_error_or_equal('<SCR\x00IPT>alert("foo")', src, ++ allow_strip=True) + src = u'' + self.assert_parse_error_or_equal('<SCRIPT&XYZ; ' +- 'SRC="http://example.com/">', src) ++ 'SRC="http://example.com/">', src, ++ allow_strip=True) + + def test_sanitize_remove_onclick_attr(self): + html = HTML(u'
') +-- +2.12.0 + diff --git a/gnu/packages/python.scm b/gnu/packages/python.scm index 174ebfcb03..23a96a25e5 100644 --- a/gnu/packages/python.scm +++ b/gnu/packages/python.scm @@ -14825,3 +14825,43 @@ transforms idiomatic python function calls to well-formed SQL queries.") (define-public python2-sql (package-with-python2 python-sql)) + +(define-public python-genshi + (package + (name "python-genshi") + (version "0.7") + (source + (origin + (method url-fetch) + (uri (string-append + "https://ftp.edgewall.org/pub/genshi/Genshi-" + version ".tar.gz")) + (patches + (search-patches + ;; The first 4 patches are in the master branch upstream. + ;; See this as a reference https://genshi.edgewall.org/ticket/582 + ;; The last 2 are NOT in any branch. + ;; They were sent as attachments to a ticket opened at + ;; https://genshi.edgewall.org/ticket/602#no1 + "python-genshi-stripping-of-unsafe-script-tags.patch" + "python-genshi-disable-speedups-on-python-3.3.patch" + "python-genshi-isstring-helper.patch" + "python-genshi-add-support-for-python-3.4-AST.patch" + "python-genshi-fix-tests-on-python-3.5.patch" + "python-genshi-buildable-on-python-2.7.patch")) + (sha256 + (base32 + "0lkkbp6fbwzv0zda5iqc21rr7rdldkwh3hfabfjl9i4bwq14858x")))) + (build-system python-build-system) + (home-page "https://genshi.edgewall.org/") + (synopsis "Toolkit for generation of output for the web") + (description "Genshi is a Python library that provides an integrated set +of components for parsing, generating, and processing HTML, XML or other +textual content for output generation on the web.") + (license license:bsd-3))) + +;; The linter here claims that patch file names should start with the package +;; name. But, in this case the patches are inherited from python-genshi with +;; the "python-genshi-" prefix instead of "python2-genshi-". +(define-public python2-genshi + (package-with-python2 python-genshi))