SF.net SVN: docutils:[9723] trunk/docutils

milde--- via Docutils-checkins <[email protected]>
Newsgroups gmane.text.docutils.cvs
Message-ID <[email protected]>
Revision: 9723
          http://sourceforge.net/p/docutils/code/9723
Author:   milde
Date:     2024-06-05 10:22:23 +0000 (Wed, 05 Jun 2024)
Log Message:
-----------
Doctree validation: custom exception `nodes.ValidationError`.

The custom `ValidationError` has the additional attribute "problematic
element" that holds the element close to the violation ("self", for
invalid XML attributes and spurious text or a child node that does not
fit in the content model).

Use for warnings with source-code line
in `transforms.universal.Validate`

Revise validation error messages.

Modified Paths:
--------------
    trunk/docutils/HISTORY.txt
    trunk/docutils/docutils/nodes.py
    trunk/docutils/docutils/transforms/universal.py
    trunk/docutils/test/test_nodes.py

Modified: trunk/docutils/HISTORY.txt
===================================================================
--- trunk/docutils/HISTORY.txt	2024-05-31 14:42:06 UTC (rev 9722)
+++ trunk/docutils/HISTORY.txt	2024-06-05 10:22:23 UTC (rev 9723)
@@ -24,12 +24,14 @@
 
 * docutils/nodes.py
 
-  - Raise ValueError if the "rawsource" argument in `Element.__init__()`
+  - Raise TypeError if the "rawsource" argument in `Element.__init__()`
     is an `Element` instance.
     Catches errors like ``nodes.hint(nodes.paragraph())``.
   - New element category classes `SubStructural` and `PureTextElement`.
   - Fix element categories.
-  - New method `Element.validate()` (work in progress).
+  - New method `Element.validate()`: raise `nodes.ValidationError` if
+    the element does not comply with the "Docutils Document Model"
+    (work in progress).
   - New "attribute validating functions"
     convert string representations to correct data type,
     normalize values,

Modified: trunk/docutils/docutils/nodes.py
===================================================================
--- trunk/docutils/docutils/nodes.py	2024-05-31 14:42:06 UTC (rev 9722)
+++ trunk/docutils/docutils/nodes.py	2024-06-05 10:22:23 UTC (rev 9723)
@@ -515,7 +515,7 @@
         NOTE: some elements do not set this value (default '').
         """
         if isinstance(rawsource, Element):
-            raise ValueError('First argument "rawsource" must be a string.')
+            raise TypeError('First argument "rawsource" must be a string.')
 
         self.children = []
         """List of child nodes (elements and/or `Text`)."""
@@ -1120,7 +1120,7 @@
         Convert string values to expected datatype.
         Normalize values.
 
-        Raise `ValueError` for invalid attributes or attribute values.
+        Raise `ValidationError` for invalid attributes or attribute values.
 
         Provisional.
         """
@@ -1129,7 +1129,7 @@
             if key.startswith('internal:'):
                 continue  # see docs/user/config.html#expose-internals
             if key not in self.valid_attributes:
-                va = ' '.join(self.valid_attributes)
+                va = '", "'.join(self.valid_attributes)
                 messages.append(f'Attribute "{key}" not one of "{va}".')
                 continue
             try:
@@ -1136,23 +1136,28 @@
                 self.attributes[key] = ATTRIBUTE_VALIDATORS[key](value)
             except (ValueError, TypeError, KeyError) as e:
                 messages.append(
-                    f'Attribute "{key}" has invalid value "{value}".\n{e}')
+                    f'Attribute "{key}" has invalid value "{value}".\n  {e}')
         if messages:
-            raise ValueError('\n'.join(messages))
+            raise ValidationError(f'Element {self.starttag()} invalid:\n  '
+                                  + '\n  '.join(messages),
+                                  problematic_element=self)
 
     def validate(self):
-        """Validate element against the Docutils Document Model ("doctree").
+        """Validate Docutils Document Tree element ("doctree").
 
-        Raise ValueError if there are violations.
+        Raise ValidationError if there are violations.
 
+        See `The Docutils Document Tree`__ for details of the
+        Docutils Document Model.
+
+        __ https://docutils.sourceforge.io/docs/ref/doctree.html
+
         Provisional (work in progress).
         """
+        self.validate_attributes()
+
+        # test number of children
         messages = []
-        try:
-            self.validate_attributes()
-        except ValueError as e:
-            messages.append(str(e))
-        # test number of children
         n_min, n_max = self.valid_len
         if len(self.children) < n_min:
             messages.append(f'Expects at least {n_min} children, '
@@ -1212,7 +1217,7 @@
 class SubStructural(SubRoot):
     """`Structural subelements`__ are children of structural elements.
 
-    Most Structural elements accept only some of the SubStructural elements.
+    Most Structural elements accept only specific `SubStructural` elements.
 
     __ https://docutils.sourceforge.io/docs/ref/doctree.html
        #structural-subelements
@@ -2518,6 +2523,16 @@
         self.parent = self.parent_stack.pop()
 
 
+# Custom Exceptions
+# =================
+
+class ValidationError(ValueError):
+    """Invalid Docutils Document Tree Element."""
+    def __init__(self, msg, problematic_element=None):
+        super().__init__(msg)
+        self.problematic_element = problematic_element
+
+
 class TreePruningException(Exception):
     """
     Base class for `NodeVisitor`-related tree pruning exceptions.

Modified: trunk/docutils/docutils/transforms/universal.py
===================================================================
--- trunk/docutils/docutils/transforms/universal.py	2024-05-31 14:42:06 UTC (rev 9722)
+++ trunk/docutils/docutils/transforms/universal.py	2024-06-05 10:22:23 UTC (rev 9723)
@@ -350,5 +350,11 @@
         for node in self.document.findall():
             try:
                 node.validate()
-            except ValueError as e:
-                self.document.reporter.warning(e.args[0], base_node=node)
+            except nodes.ValidationError as e:
+                self.document.reporter.warning(
+                    str(e), base_node=e.problematic_element or node)
+        # TODO: append a link to the Document Tree documentation?
+        # nodes.paragraph('', 'See ',
+        # nodes.reference('', 'doctree.html#document',
+        #                 refuri='https://docutils.sourceforge.io/'
+        #                 'docs/ref/doctree.html#document'),

Modified: trunk/docutils/test/test_nodes.py
===================================================================
--- trunk/docutils/test/test_nodes.py	2024-05-31 14:42:06 UTC (rev 9722)
+++ trunk/docutils/test/test_nodes.py	2024-06-05 10:22:23 UTC (rev 9723)
@@ -469,7 +469,11 @@
         with self.assertWarns(DeprecationWarning):
             node.set_class('parrot')
 
+
+class ElementValidationTests(unittest.TestCase):
+
     def test_validate(self):
+        """Valid node: validation should simply pass."""
         node = nodes.paragraph('', 'plain text', classes='my test classes')
         node.append(nodes.emphasis('', 'emphasised text', ids='emphtext'))
         node.validate()
@@ -487,15 +491,15 @@
 
     def test_validate_wrong_attribute(self):
         node = nodes.paragraph('', 'text', id='test-paragraph')
-        with self.assertRaisesRegex(ValueError,
-                                    'Element <paragraph> invalid:\n'
-                                    '  Attribute "id" not one of "ids '):
+        with self.assertRaisesRegex(nodes.ValidationError,
+                                    'Element <paragraph id=.*> invalid:\n'
+                                    '  Attribute "id" not one of "ids", '):
             node.validate()
 
     def test_validate_wrong_attribute_value(self):
         node = nodes.image(uri='test.png', width='20 inch')  # invalid unit
-        with self.assertRaisesRegex(ValueError,
-                                    'Element <image> invalid:\n'
+        with self.assertRaisesRegex(nodes.ValidationError,
+                                    'Element <image.*> invalid:\n'
                                     '.*"width" has invalid value "20 inch".\n'
                                     '.*Valid units: em ex '):
             node.validate()

This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.