Repository: tefra/xsdata
Pull request #581 (2021-08-15 18:37:06)

Reraise xml syntax errors as xsdata.exceptions.ParserError


Patch:
diff --git a/xsdata/formats/dataclass/parsers/bases.py b/xsdata/formats/dataclass/parsers/bases.py
index 8cb57df1..31ad1c96 100644
--- a/xsdata/formats/dataclass/parsers/bases.py
+++ b/xsdata/formats/dataclass/parsers/bases.py
@@ -51,7 +51,7 @@ class NodeParser(PushParser):
 
             try:
                 result = handler.parse(source)
-            except ConverterWarning as e:
+            except (ConverterWarning, SyntaxError) as e:
                 raise ParserError(e)
 
         if result is not None:
diff --git a/xsdata/formats/dataclass/parsers/handlers/native.py b/xsdata/formats/dataclass/parsers/handlers/native.py
index a8e496a4..e653773d 100644
--- a/xsdata/formats/dataclass/parsers/handlers/native.py
+++ b/xsdata/formats/dataclass/parsers/handlers/native.py
@@ -10,6 +10,7 @@ from urllib.parse import urljoin
 from xml import sax
 from xml.etree import ElementInclude as xinclude
 from xml.etree import ElementTree as etree
+from xml.sax import SAXException
 
 from xsdata.exceptions import XmlHandlerError
 from xsdata.formats.dataclass.parsers.mixins import PushParser
@@ -121,11 +122,14 @@ class XmlSaxHandler(SaxHandler, sax.handler.ContentHandler):
                 f"{type(self).__name__} doesn't support xinclude elements."
             )
 
-        parser = sax.make_parser()  # nosec
-        parser.setFeature(sax.handler.feature_namespaces, True)
-        parser.setContentHandler(self)
-        parser.parse(source)
-        return self.close()
+        try:
+            parser = sax.make_parser()  # nosec
+            parser.setFeature(sax.handler.feature_namespaces, True)
+            parser.setContentHandler(self)
+            parser.parse(source)
+            return self.close()
+        except SAXException as e:
+            raise SyntaxError(e)
 
     def startElementNS(self, name: Tuple[Optional[str], str], qname: Any, attrs: Dict):
         """
@@ -201,7 +205,6 @@ def iterwalk(element: etree.Element, ns_map: Dict) -> Iterator[Tuple[str, Any]]:
 
 
 def get_base_url(base_url: Optional[str], source: Any) -> Optional[str]:
-
     if base_url:
         return base_url
 


Test patch:
diff --git a/tests/formats/dataclass/parsers/handlers/test_lxml.py b/tests/formats/dataclass/parsers/handlers/test_lxml.py
index 390ad70a..71d6e4a3 100644
--- a/tests/formats/dataclass/parsers/handlers/test_lxml.py
+++ b/tests/formats/dataclass/parsers/handlers/test_lxml.py
@@ -9,6 +9,7 @@ from tests.fixtures.books import Books
 from tests.fixtures.books.fixtures import books
 from tests.fixtures.books.fixtures import events
 from tests.fixtures.books.fixtures import events_default_ns
+from xsdata.exceptions import ParserError
 from xsdata.exceptions import XmlHandlerError
 from xsdata.formats.dataclass.parsers.bases import RecordParser
 from xsdata.formats.dataclass.parsers.handlers import LxmlEventHandler
@@ -67,6 +68,10 @@ class LxmlEventHandlerTests(TestCase):
 
         self.assertEqual("Unhandled event: `reverse`.", str(cm.exception))
 
+    def test_parse_with_xml_syntax_error(self):
+        with self.assertRaises(ParserError):
+            self.parser.from_string("<", Books)
+
 
 class LxmlSaxHandlerTests(TestCase):
     def setUp(self):
@@ -122,3 +127,7 @@ class LxmlSaxHandlerTests(TestCase):
         self.assertEqual(
             "LxmlSaxHandler doesn't support xinclude elements.", str(cm.exception)
         )
+
+    def test_parse_with_xml_syntax_error(self):
+        with self.assertRaises(ParserError):
+            self.parser.from_string("<", Books)
diff --git a/tests/formats/dataclass/parsers/handlers/test_native.py b/tests/formats/dataclass/parsers/handlers/test_native.py
index afd67aec..69c0b904 100644
--- a/tests/formats/dataclass/parsers/handlers/test_native.py
+++ b/tests/formats/dataclass/parsers/handlers/test_native.py
@@ -11,6 +11,7 @@ from tests.fixtures.books import Books
 from tests.fixtures.books.fixtures import books
 from tests.fixtures.books.fixtures import events
 from tests.fixtures.books.fixtures import events_default_ns
+from xsdata.exceptions import ParserError
 from xsdata.exceptions import XmlHandlerError
 from xsdata.formats.dataclass.parsers.bases import RecordParser
 from xsdata.formats.dataclass.parsers.handlers import XmlEventHandler
@@ -43,6 +44,10 @@ class XmlEventHandlerTests(TestCase):
 
         self.assertEqual("Unhandled event: `reverse`.", str(cm.exception))
 
+    def test_parse_with_xml_syntax_error(self):
+        with self.assertRaises(ParserError):
+            self.parser.from_string("<", Books)
+
     def test_parse_with_element_or_tree(self):
         path = fixtures_dir.joinpath("books/books.xml")
         tree = etree.ElementTree.parse(str(path))
@@ -112,3 +117,7 @@ class SaxHandlerTests(TestCase):
         self.assertEqual(
             "XmlSaxHandler doesn't support xinclude elements.", str(cm.exception)
         )
+
+    def test_parse_with_xml_syntax_error(self):
+        with self.assertRaises(ParserError):
+            self.parser.from_string("<", Books)