summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCédric Krier <cedk@gentoo.org>2017-07-30 23:41:09 +0200
committerCédric Krier <cedk@gentoo.org>2017-07-30 23:41:09 +0200
commit76b894c6c0001477235be97558d329e29ce8327f (patch)
tree99de8be2e73cdb00b593d7d9c257af47d71da2dc
parentconfutils.eclass: Remove last rited eclass (diff)
downloadgentoo-76b894c6c0001477235be97558d329e29ce8327f.tar.gz
gentoo-76b894c6c0001477235be97558d329e29ce8327f.tar.bz2
gentoo-76b894c6c0001477235be97558d329e29ce8327f.zip
dev-python/genshi: Add Python3 support by applying patches
Gentoo-Bug: 616308 Package-Manager: Portage-2.3.6, Repoman-2.3.1
-rw-r--r--dev-python/genshi/files/genshi-0.7-fix_tests_failure_with_python27.patch25
-rw-r--r--dev-python/genshi/files/genshi-0.7-issue566.patch57
-rw-r--r--dev-python/genshi/files/genshi-0.7-issue582.patch364
-rw-r--r--dev-python/genshi/files/genshi-0.7-issue602.patch114
-rw-r--r--dev-python/genshi/genshi-0.7-r1.ebuild46
5 files changed, 606 insertions, 0 deletions
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
new file mode 100644
index 00000000000..4f3467d6481
--- /dev/null
+++ b/dev-python/genshi/files/genshi-0.7-fix_tests_failure_with_python27.patch
@@ -0,0 +1,25 @@
+From 7f3552a9373fadd2d37ff592769ba6c65755eea5 Mon Sep 17 00:00:00 2001
+From: SVN-Git Migration <python-modules-team@lists.alioth.debian.org>
+Date: Thu, 8 Oct 2015 09:13:47 -0700
+Subject: Skip test which still fails in Python 2.7.6.
+
+Author: Barry Warsaw <barry@debian.org>, Arnaud Fontaine <arnau@debian.org>
+Bug: http://genshi.edgewall.org/ticket/500
+
+Patch-Name: fix_tests_failure_with_python27.patch
+---
+ genshi/filters/tests/test_html.py | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/genshi/filters/tests/test_html.py b/genshi/filters/tests/test_html.py
+index 0c6cfe1..a8cfa04 100644
+--- a/genshi/filters/tests/test_html.py
++++ b/genshi/filters/tests/test_html.py
+@@ -410,6 +410,7 @@ class HTMLSanitizerTestCase(unittest.TestCase):
+ html = HTML(u'&junk;')
+ self.assertEquals('&amp;junk;', (html | HTMLSanitizer()).render())
+
++ @unittest.skip('http://genshi.edgewall.org/ticket/500#comment:3')
+ def test_sanitize_remove_script_elem(self):
+ html = HTML(u'<script>alert("Foo")</script>')
+ self.assertEquals('', (html | HTMLSanitizer()).render())
diff --git a/dev-python/genshi/files/genshi-0.7-issue566.patch b/dev-python/genshi/files/genshi-0.7-issue566.patch
new file mode 100644
index 00000000000..70fc8ea85e6
--- /dev/null
+++ b/dev-python/genshi/files/genshi-0.7-issue566.patch
@@ -0,0 +1,57 @@
+From fafbc4296902b2259c23d2ce55996b0127726b4f Mon Sep 17 00:00:00 2001
+From: SVN-Git Migration <python-modules-team@lists.alioth.debian.org>
+Date: Thu, 8 Oct 2015 09:13:49 -0700
+Subject: Fix an IndexError preventing Genshi for uploading attachments in
+
+ Trac for users with non-English language settings.
+Origin: http://genshi.edgewall.org/changeset/1243?format=diff&new=1243
+Bug: http://genshi.edgewall.org/ticket/566
+
+Patch-Name: issue566.patch
+---
+ genshi/filters/i18n.py | 8 +++++++-
+ genshi/filters/tests/i18n.py | 12 ++++++++++++
+ 2 files changed, 19 insertions(+), 1 deletion(-)
+
+diff --git a/genshi/filters/i18n.py b/genshi/filters/i18n.py
+index dfb52b8..8f2d25c 100644
+--- a/genshi/filters/i18n.py
++++ b/genshi/filters/i18n.py
+@@ -1048,7 +1048,13 @@ class MessageBuffer(object):
+
+ while parts:
+ order, string = parts.pop(0)
+- events = self.events[order].pop(0)
++ events = self.events[order]
++ if events:
++ events = events.pop(0)
++ else:
++ # create a dummy empty text event so any remaining
++ # part of the translation can be processed.
++ events = [(TEXT, "", (None, -1, -1))]
+ parts_counter[order].pop()
+
+ for event in events:
+diff --git a/genshi/filters/tests/i18n.py b/genshi/filters/tests/i18n.py
+index 212d5f6..b36a30b 100644
+--- a/genshi/filters/tests/i18n.py
++++ b/genshi/filters/tests/i18n.py
+@@ -928,6 +928,18 @@ class MsgDirectiveTestCase(unittest.TestCase):
+ """</p></html>""",
+ tmpl.generate(first="FIRST", second="SECOND").render())
+
++ def test_translate_i18n_msg_ticket_404_regression(self):
++ tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
++ xmlns:i18n="http://genshi.edgewall.org/i18n">
++ <h1 i18n:msg="name">text <a>$name</a></h1>
++ </html>""")
++ gettext = lambda s: u'head [1:%(name)s] tail'
++ translator = Translator(gettext)
++ translator.setup(tmpl)
++ self.assertEqual("""<html>
++ <h1>head <a>NAME</a> tail</h1>
++ </html>""", tmpl.generate(name='NAME').render())
++
+
+ class ChooseDirectiveTestCase(unittest.TestCase):
+
diff --git a/dev-python/genshi/files/genshi-0.7-issue582.patch b/dev-python/genshi/files/genshi-0.7-issue582.patch
new file mode 100644
index 00000000000..fbcab626d6c
--- /dev/null
+++ b/dev-python/genshi/files/genshi-0.7-issue582.patch
@@ -0,0 +1,364 @@
+From 554fa3428bea3039decfd9064b860c753b2637a1 Mon Sep 17 00:00:00 2001
+From: SVN-Git Migration <python-modules-team@lists.alioth.debian.org>
+Date: Thu, 8 Oct 2015 09:13:48 -0700
+Subject: Make genshi 0.7 compatible with Python 3.4.
+
+Origin: http://genshi.edgewall.org/changeset/1252?format=diff&new=1252
+Bug: http://genshi.edgewall.org/ticket/582
+Forwarded: not-needed
+
+Patch-Name: issue582.patch
+---
+ doc/upgrade.txt | 8 ++---
+ genshi/compat.py | 10 +++++-
+ genshi/filters/tests/test_html.py | 14 ++++++---
+ genshi/template/astutil.py | 66 ++++++++++++++++++++++++++++-----------
+ genshi/template/eval.py | 37 +++++++++++++---------
+ genshi/template/tests/eval.py | 23 ++++++++++++++
+ run_benchmarks.sh | 31 ++++++++++++++++++
+ setup.py | 6 +++-
+ 8 files changed, 151 insertions(+), 44 deletions(-)
+ create mode 100644 run_benchmarks.sh
+
+diff --git a/doc/upgrade.txt b/doc/upgrade.txt
+index b240eda..ad4c080 100644
+--- a/doc/upgrade.txt
++++ b/doc/upgrade.txt
+@@ -7,11 +7,11 @@ Upgrading Genshi
+ :depth: 2
+ .. sectnum::
+
+-------------------------------------------------------
+-Upgrading from Genshi 0.6.x to the development version
+-------------------------------------------------------
++-------------------------------------------
++Upgrading from Genshi 0.6.x to Genshi 0.7.x
++-------------------------------------------
+
+-The Genshi development version now supports both Python 2 and Python 3.
++Genshi 0.7.x now supports both Python 2 and Python 3.
+
+ The most noticable API change in the Genshi development version is that the
+ default encoding in numerous places is now None (i.e. unicode) instead
+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
+-
+diff --git a/genshi/filters/tests/test_html.py b/genshi/filters/tests/test_html.py
+index a8cfa04..7120988 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'<a href="#">fo<br />o</a>')
+@@ -417,10 +421,12 @@ class HTMLSanitizerTestCase(unittest.TestCase):
+ html = HTML(u'<SCRIPT SRC="http://example.com/"></SCRIPT>')
+ self.assertEquals('', (html | HTMLSanitizer()).render())
+ src = u'<SCR\0IPT>alert("foo")</SCR\0IPT>'
+- self.assert_parse_error_or_equal('&lt;SCR\x00IPT&gt;alert("foo")', src)
++ self.assert_parse_error_or_equal('&lt;SCR\x00IPT&gt;alert("foo")', src,
++ allow_strip=True)
+ src = u'<SCRIPT&XYZ SRC="http://example.com/"></SCRIPT>'
+ self.assert_parse_error_or_equal('&lt;SCRIPT&amp;XYZ; '
+- 'SRC="http://example.com/"&gt;', src)
++ 'SRC="http://example.com/"&gt;', src,
++ allow_strip=True)
+
+ def test_sanitize_remove_onclick_attr(self):
+ html = HTML(u'<div onclick=\'alert("foo")\' />')
+diff --git a/genshi/template/astutil.py b/genshi/template/astutil.py
+index b24f728..e561846 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,32 +103,48 @@ 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)
+- for i, arg in enumerate(node.args):
+- if not first:
+- self._write(', ')
++ def write_possible_comma():
++ if _first[0]:
++ _first[0] = False
+ else:
+- first = False
+- self.visit(arg)
+- if i >= no_default_count:
+- self._write('=')
+- self.visit(node.defaults[i - no_default_count])
+- if getattr(node, 'vararg', None):
+- if not first:
+ self._write(', ')
++ _first = [True]
++
++ def write_args(args, defaults):
++ no_default_count = len(args) - len(defaults)
++ for i, arg in enumerate(args):
++ write_possible_comma()
++ self.visit(arg)
++ default_idx = i - no_default_count
++ if default_idx >= 0 and defaults[default_idx] is not None:
++ self._write('=')
++ self.visit(defaults[i - no_default_count])
++
++ write_args(node.args, node.defaults)
++ if getattr(node, 'vararg', None):
++ write_possible_comma()
++ self._write('*')
++ if isstring(node.vararg):
++ self._write(node.vararg)
+ else:
+- first = False
+- self._write('*' + node.vararg)
++ self.visit(node.vararg)
++ if getattr(node, 'kwonlyargs', None):
++ write_args(node.kwonlyargs, node.kw_defaults)
+ if getattr(node, 'kwarg', None):
+- if not first:
+- self._write(', ')
++ write_possible_comma()
++ self._write('**')
++ if isstring(node.kwarg):
++ self._write(node.kwarg)
+ else:
+- first = False
+- self._write('**' + node.kwarg)
++ self.visit(node.kwarg)
+
+ if not IS_PYTHON2:
+ # In Python 3 arguments get a special node
+@@ -732,6 +748,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('[')
+@@ -837,6 +864,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 c00cfcb..81644a7 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,34 @@ 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, 'kwonlyargs'):
++ for arg in node.kwonlyargs:
++ 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):
+diff --git a/genshi/template/tests/eval.py b/genshi/template/tests/eval.py
+index 7722571..c44a0e3 100644
+--- a/genshi/template/tests/eval.py
++++ b/genshi/template/tests/eval.py
+@@ -590,6 +590,29 @@ x = smash(foo='abc', bar='def')
+ suite.execute(data)
+ self.assertEqual(['bardef', 'fooabc'], sorted(data['x']))
+
++ if not IS_PYTHON2:
++ def test_def_kwonlyarg(self):
++ suite = Suite("""
++def kwonly(*args, k):
++ return k
++x = kwonly(k="foo")
++""")
++ data = {}
++ suite.execute(data)
++ self.assertEqual("foo", data['x'])
++
++ def test_def_kwonlyarg_with_default(self):
++ suite = Suite("""
++def kwonly(*args, k="bar"):
++ return k
++x = kwonly(k="foo")
++y = kwonly()
++""")
++ data = {}
++ suite.execute(data)
++ self.assertEqual("foo", data['x'])
++ self.assertEqual("bar", data['y'])
++
+ def test_def_nested(self):
+ suite = Suite("""
+ def doit():
+diff --git a/run_benchmarks.sh b/run_benchmarks.sh
+new file mode 100644
+index 0000000..0c64cc8
+--- /dev/null
++++ b/run_benchmarks.sh
+@@ -0,0 +1,31 @@
++#!/bin/sh
++#
++# 1. Run the tests with `tox` (this will set up all the tox envs).
++# 2. ./run_benchmarks.sh <env-name> | tee results-<env-name>.out
++
++NAME="$1"
++PYTHON="./.tox/$NAME/bin/python"
++BENCH_DIR="bench_build/$1"
++BENCH_BIN_DIR="$BENCH_DIR/bin"
++mkdir -p "bench_build"
++
++rm -rf "$BENCH_DIR"
++cp -R "examples/bench" "$BENCH_DIR"
++
++case "$NAME" in
++ py32|py33)
++ 2to3 -w --no-diffs "$BENCH_DIR"
++ ;;
++esac
++
++echo "-- basic --"
++"$PYTHON" "$BENCH_DIR/basic.py"
++echo
++
++echo "-- bigtable --"
++"$PYTHON" "$BENCH_DIR/bigtable.py"
++echo
++
++echo "-- xpath --"
++"$PYTHON" "$BENCH_DIR/xpath.py"
++echo
+diff --git a/setup.py b/setup.py
+index 294ba9b..45099b5 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']),
+ ],
diff --git a/dev-python/genshi/files/genshi-0.7-issue602.patch b/dev-python/genshi/files/genshi-0.7-issue602.patch
new file mode 100644
index 00000000000..d7f0b77fa92
--- /dev/null
+++ b/dev-python/genshi/files/genshi-0.7-issue602.patch
@@ -0,0 +1,114 @@
+From 1acbd00b4961164edc8a185458ba4a433bedbceb Mon Sep 17 00:00:00 2001
+From: SVN-Git Migration <python-modules-team@lists.alioth.debian.org>
+Date: Thu, 8 Oct 2015 09:13:46 -0700
+Subject: Fix Python 3.5 compatibility issues.
+
+Origin: http://genshi.edgewall.org/attachment/ticket/602/t602.diff
+Bug: http://genshi.edgewall.org/ticket/602
+Forwarded: not-needed
+
+Patch-Name: issue602.patch
+---
+ 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 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 a4c21c8..b24f728 100644
+--- a/genshi/template/astutil.py
++++ b/genshi/template/astutil.py
+@@ -135,6 +135,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):
+@@ -648,9 +652,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..1f70ef6 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 hasattr(_ast, 'Starred') and 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 89aec49..c00cfcb 100644
+--- a/genshi/template/eval.py
++++ b/genshi/template/eval.py
+@@ -593,6 +593,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
diff --git a/dev-python/genshi/genshi-0.7-r1.ebuild b/dev-python/genshi/genshi-0.7-r1.ebuild
new file mode 100644
index 00000000000..65360402e2c
--- /dev/null
+++ b/dev-python/genshi/genshi-0.7-r1.ebuild
@@ -0,0 +1,46 @@
+# Copyright 1999-2017 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=5
+PYTHON_COMPAT=( python{2_7,3_{4,5,6}} pypy )
+
+inherit distutils-r1
+
+MY_P="Genshi-${PV}"
+
+DESCRIPTION="Python toolkit for stream-based generation of output for the web"
+HOMEPAGE="http://genshi.edgewall.org/ https://pypi.python.org/pypi/Genshi"
+SRC_URI="http://ftp.edgewall.com/pub/genshi/${MY_P}.tar.gz"
+
+LICENSE="BSD"
+SLOT="0"
+KEYWORDS="~amd64 ~ppc ~ppc64 ~sparc ~x86 ~x86-fbsd ~amd64-linux ~x86-linux ~x64-macos ~x86-macos"
+IUSE="doc examples"
+
+DEPEND="dev-python/setuptools[${PYTHON_USEDEP}]"
+RDEPEND="${DEPEND}"
+
+S="${WORKDIR}/${MY_P}"
+
+src_prepare() {
+ epatch "${FILESDIR}/${P}-issue566.patch"
+ epatch "${FILESDIR}/${P}-issue582.patch"
+ epatch "${FILESDIR}/${P}-fix_tests_failure_with_python27.patch"
+ epatch "${FILESDIR}/${P}-issue602.patch"
+}
+
+python_test() {
+ esetup.py test
+}
+
+python_install_all() {
+ if use doc; then
+ dodoc doc/*.txt
+ dohtml -r doc/*
+ fi
+ if use examples; then
+ insinto /usr/share/doc/${PF}
+ doins -r examples
+ fi
+ distutils-r1_python_install_all
+}