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

milde--- via Docutils-checkins <[email protected]> Mon, 16 Jun 2025 12:36:11 +0000
Newsgroups gmane.text.docutils.cvs
Message-ID <[email protected]>
Revision: 10170
          http://sourceforge.net/p/docutils/code/10170
Author:   milde
Date:     2025-06-16 12:36:11 +0000 (Mon, 16 Jun 2025)
Log Message:
-----------
Update/fix handling of duplicate identifiers.

Update the code in `nodes.document.set_duplicate_name_id()` to
* simplify the logic,
* don't insert INFO level `<system_message> at places where it is invalid,
* don't insert backlinks from a system message to an invisible target element
  (an external `<target>` is not visible in HMTL and LaTeX output).

Highlight targeted system-message in "responsive.css" style sheet.

Modified Paths:
--------------
    trunk/docutils/HISTORY.rst
    trunk/docutils/docutils/nodes.py
    trunk/docutils/docutils/writers/html5_polyglot/responsive.css
    trunk/docutils/test/test_parsers/test_rst/test_inline_markup.py
    trunk/docutils/test/test_parsers/test_rst/test_targets.py
    trunk/docutils/test/test_transforms/test_hyperlinks.py

Modified: trunk/docutils/HISTORY.rst
===================================================================
--- trunk/docutils/HISTORY.rst	2025-06-16 10:05:35 UTC (rev 10169)
+++ trunk/docutils/HISTORY.rst	2025-06-16 12:36:11 UTC (rev 10170)
@@ -17,6 +17,11 @@
 Release 0.22rc4 (unpublished)
 =============================
 
+* docutils/nodes.py
+
+  Don't include a "backlink" reference in system messages, if the
+  referenced element is an external target (not visible in the output).
+
 * docutils/parsers/rst/directives/references.py
 
   Remove "name" from `TargetNotes.option_spec`.

Modified: trunk/docutils/docutils/nodes.py
===================================================================
--- trunk/docutils/docutils/nodes.py	2025-06-16 10:05:35 UTC (rev 10169)
+++ trunk/docutils/docutils/nodes.py	2025-06-16 12:36:11 UTC (rev 10170)
@@ -1922,52 +1922,56 @@
                               msgnode: Element,
                               explicit: bool,
                               ) -> None:
-        old_id = self.nameids[name]
+        old_id = self.nameids[name]  # None if name is only dupname
         old_explicit = self.nametypes[name]
         old_node = self.ids.get(old_id)
+        level = 0  # system message level: 1-info, 2-warning
+
         self.nametypes[name] = old_explicit or explicit
+
         if explicit:
             if old_explicit:
                 level = 2
+                s = f'Duplicate explicit target name: "{name}".'
+                dupname(node, name)
                 if old_id is not None:
-                    if 'refuri' in node:
-                        refuri = node['refuri']
-                        if (old_node['names']
-                            and 'refuri' in old_node
-                            and old_node['refuri'] == refuri):
-                            level = 1  # just inform if refuri is identical
-                    if level > 1:
+                    if ('refuri' in node and 'refuri' in old_node
+                            and node['refuri'] == old_node['refuri']):
+                        level = 1  # keep old target, just inform
+                    else:
                         dupname(old_node, name)
                         self.nameids[name] = None
-                msg = self.reporter.system_message(
-                    level, 'Duplicate explicit target name: "%s".' % name,
-                    backrefs=[id], base_node=node)
-                if msgnode is not None:
-                    # append <system_message> if valid at this place
-                    msgnode += msg
-                    try:
-                        msgnode.validate(recursive=False)
-                    except ValidationError:
-                        msgnode.pop()
-                        msg.parent = None
-                dupname(node, name)
-            else:  # new explicit, old implicit -> silently overwrite
+            else:  # new explicit, old implicit -> override
                 self.nameids[name] = id
                 if old_id is not None:
+                    level = 1
+                    s = f'Target name overrides implicit target name "{name}".'
                     dupname(old_node, name)
         else:  # new name is implicit
+            level = 1
+            s = f'Duplicate implicit target name: "{name}".'
+            dupname(node, name)
             if old_id is not None and not old_explicit:
+                dupname(old_node, name)
                 self.nameids[name] = None
-                dupname(old_node, name)
-            dupname(node, name)
-        if not explicit or (not old_explicit and old_id is not None):
-            if explicit:
-                s = f'Target name overrides implicit target name "{name}".'
-            else:
-                s = f'Duplicate implicit target name: "{name}".'
-            msg = self.reporter.info(s, backrefs=[id], base_node=node)
+
+        if level:
+            backrefs = [id]
+            # don't add backref id for empty targets (not shown in output)
+            if isinstance(node, target) and 'refuri' in node:
+                backrefs = []
+            msg = self.reporter.system_message(level, s,
+                                               backrefs=backrefs,
+                                               base_node=node)
+            # try appending near to the problem:
             if msgnode is not None:
                 msgnode += msg
+                try:
+                    msgnode.validate(recursive=False)
+                except ValidationError:
+                    # detach -> will be handled by `Messages` transform
+                    msgnode.pop()
+                    msg.parent = None
 
     def has_name(self, name: str) -> bool:
         return name in self.nameids

Modified: trunk/docutils/docutils/writers/html5_polyglot/responsive.css
===================================================================
--- trunk/docutils/docutils/writers/html5_polyglot/responsive.css	2025-06-16 10:05:35 UTC (rev 10169)
+++ trunk/docutils/docutils/writers/html5_polyglot/responsive.css	2025-06-16 12:36:11 UTC (rev 10170)
@@ -293,6 +293,7 @@
 dt:target, span:target, p:target,
 .contents :target,
 .contents:target > .topic-title,
+aside.system-message:target,
 [role="doc-biblioentry"]:target,
 [role="doc-biblioref"]:target,
 [role="note"]:target, /* Docutils 0.18 and 0.19 */

Modified: trunk/docutils/test/test_parsers/test_rst/test_inline_markup.py
===================================================================
--- trunk/docutils/test/test_parsers/test_rst/test_inline_markup.py	2025-06-16 10:05:35 UTC (rev 10169)
+++ trunk/docutils/test/test_parsers/test_rst/test_inline_markup.py	2025-06-16 12:36:11 UTC (rev 10170)
@@ -1169,7 +1169,7 @@
         <target ids="anonymous-html" names="anonymous.html">
             anonymous.html
         .
-    <system_message backrefs="named-txt-1" level="2" line="4" source="test data" type="WARNING">
+    <system_message level="2" line="4" source="test data" type="WARNING">
         <paragraph>
             Duplicate explicit target name: "named.txt".
     <paragraph>

Modified: trunk/docutils/test/test_parsers/test_rst/test_targets.py
===================================================================
--- trunk/docutils/test/test_parsers/test_rst/test_targets.py	2025-06-16 10:05:35 UTC (rev 10169)
+++ trunk/docutils/test/test_parsers/test_rst/test_targets.py	2025-06-16 12:36:11 UTC (rev 10170)
@@ -199,7 +199,7 @@
     <paragraph>
         Duplicate external targets (different URIs):
     <target dupnames="target" ids="target" refuri="first">
-    <system_message backrefs="target-1" level="2" line="5" source="test data" type="WARNING">
+    <system_message level="2" line="5" source="test data" type="WARNING">
         <paragraph>
             Duplicate explicit target name: "target".
     <target dupnames="target" ids="target-1" refuri="second">
@@ -216,7 +216,7 @@
     <paragraph>
         Duplicate external targets (same URIs):
     <target ids="target" names="target" refuri="first">
-    <system_message backrefs="target-1" level="1" line="5" source="test data" type="INFO">
+    <system_message level="1" line="5" source="test data" type="INFO">
         <paragraph>
             Duplicate explicit target name: "target".
     <target dupnames="target" ids="target-1" refuri="first">
@@ -416,7 +416,7 @@
         <target dupnames="target" ids="target-3">
         <paragraph>
             Explicit internal target.
-        <system_message backrefs="target-4" level="2" line="16" source="test data" type="WARNING">
+        <system_message level="2" line="16" source="test data" type="WARNING">
             <paragraph>
                 Duplicate explicit target name: "target".
         <target dupnames="target" ids="target-4" refuri="Explicit_external_target">

Modified: trunk/docutils/test/test_transforms/test_hyperlinks.py
===================================================================
--- trunk/docutils/test/test_transforms/test_hyperlinks.py	2025-06-16 10:05:35 UTC (rev 10169)
+++ trunk/docutils/test/test_transforms/test_hyperlinks.py	2025-06-16 12:36:11 UTC (rev 10170)
@@ -764,7 +764,7 @@
             target_
         's (different URIs):
     <target dupnames="target" ids="target" refuri="first">
-    <system_message backrefs="target-1" level="2" line="5" source="test data" type="WARNING">
+    <system_message level="2" line="5" source="test data" type="WARNING">
         <paragraph>
             Duplicate explicit target name: "target".
     <target dupnames="target" ids="target-1" refuri="second">
@@ -784,7 +784,7 @@
     <paragraph>
         Duplicate external targets (different URIs) without reference:
     <target dupnames="target" ids="target" refuri="first">
-    <system_message backrefs="target-1" level="2" line="5" source="test data" type="WARNING">
+    <system_message level="2" line="5" source="test data" type="WARNING">
         <paragraph>
             Duplicate explicit target name: "target".
     <target dupnames="target" ids="target-1" refuri="second">

This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.