Repository: edgewall/genshi

Issue:
Exception handler tries to use nonexistent error class (html.HTMLParseError)
At line 349 of `input.py` the exception handler tries to access html.HTMLParseError, an error class, that used to exist in the cPython's html library but has been [removed](https://github.com/python/cpython/blob/d57f8a9f76e75384ec997686c2a826b1dc3c69c4/Doc/whatsnew/3.3.rst#html) since Python 3.3. 

The genshi code in question is this:

```py
        def _generate():
            if self.encoding:
                reader = codecs.getreader(self.encoding)
                source = reader(self.source)
            else:
                source = self.source
            try:
                bufsize = 4 * 1024 # 4K
                done = False
                while 1:
                    while not done and len(self._queue) == 0:
                        data = source.read(bufsize)
                        if not data: # end of data
                            self.close()
                            done = True
                        else:
                            if not isinstance(data, six.text_type):
                                raise UnicodeError("source returned bytes, but no encoding specified")
                            self.feed(data)
                    for kind, data, pos in self._queue:
                        yield kind, data, pos
                    self._queue = []
                    if done:
                        open_tags = self._open_tags
                        open_tags.reverse()
                        for tag in open_tags:
                            yield END, QName(tag), pos
                        break
            except html.HTMLParseError as e:
                msg = '%s: line %d, column %d' % (e.msg, e.lineno, e.offset)
                raise ParseError(msg, self.filename, e.lineno, e.offset)
        return Stream(_generate()).filter(_coalesce)
```

Discussion:

Patch:
diff --git a/genshi/input.py b/genshi/input.py
index fa18c38..c21990a 100644
--- a/genshi/input.py
+++ b/genshi/input.py
@@ -346,9 +346,13 @@ class HTMLParser(html.HTMLParser, object):
                         for tag in open_tags:
                             yield END, QName(tag), pos
                         break
-            except html.HTMLParseError as e:
-                msg = '%s: line %d, column %d' % (e.msg, e.lineno, e.offset)
-                raise ParseError(msg, self.filename, e.lineno, e.offset)
+            except Exception as e:
+                # Python's simple HTMLParser does not raise detailed
+                # errors except in strict mode which was deprecated
+                # in Python 3.3 and removed in Python 3.5 and which in
+                # any case is not used is this code.
+                msg = str(e)
+                raise ParseError(msg, self.filename)
         return Stream(_generate()).filter(_coalesce)
 
     def __iter__(self):


Test patch:
diff --git a/genshi/tests/test_input.py b/genshi/tests/test_input.py
index 44b7442..e68515d 100644
--- a/genshi/tests/test_input.py
+++ b/genshi/tests/test_input.py
@@ -15,7 +15,7 @@ import unittest
 
 from genshi.core import Attrs, QName, Stream
 from genshi.input import XMLParser, HTMLParser, ParseError, ET
-from genshi.compat import StringIO, BytesIO
+from genshi.compat import IS_PYTHON2, StringIO, BytesIO
 from genshi.tests.utils import doctest_suite
 from xml.etree import ElementTree
 
@@ -294,6 +294,20 @@ bar</elem>'''
         self.assertEqual((Stream.END, QName("span")), events[4][:2])
         self.assertEqual((Stream.END, QName("div")), events[5][:2])
 
+    def test_parsing_error(self):
+        text = u'<div></div>'.encode('utf-8')
+        events = HTMLParser(BytesIO(text))
+        if IS_PYTHON2:
+            self.assertRaises(ParseError, list, events)
+        else:
+            self.assertRaisesRegex(
+                ParseError,
+                r"source returned bytes, but no encoding specified",
+                list,
+                events,
+            )
+
+
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(doctest_suite(XMLParser.__module__))