|
From: <mi...@us...> - 2025-11-02 17:51:00
|
Revision: 10254
http://sourceforge.net/p/docutils/code/10254
Author: milde
Date: 2025-11-02 17:50:57 +0000 (Sun, 02 Nov 2025)
Log Message:
-----------
Better error message for substitution definitions.
More informative and easier to comprehend error messages when a
substitution definition contains problematic or not supported content.
Document limits to content of substitution definitions.
Modified Paths:
--------------
trunk/docutils/HISTORY.rst
trunk/docutils/docs/ref/rst/directives.rst
trunk/docutils/docutils/parsers/rst/states.py
trunk/docutils/test/test_parsers/test_rst/test_directives/test_replace.py
trunk/docutils/test/test_parsers/test_rst/test_substitutions.py
trunk/docutils/test/test_transforms/test_hyperlinks.py
trunk/docutils/test/test_transforms/test_substitutions.py
Modified: trunk/docutils/HISTORY.rst
===================================================================
--- trunk/docutils/HISTORY.rst 2025-10-06 12:29:47 UTC (rev 10253)
+++ trunk/docutils/HISTORY.rst 2025-11-02 17:50:57 UTC (rev 10254)
@@ -20,6 +20,8 @@
* docutils/parsers/rst/states.py
- Ignore combining characters when extracting a grid table block
+ - More informative error messages when a substitution definition contains
+ problematic or not supported content.
* docutils/parsers/rst/tableparser.py
Modified: trunk/docutils/docs/ref/rst/directives.rst
===================================================================
--- trunk/docutils/docs/ref/rst/directives.rst 2025-10-06 12:29:47 UTC (rev 10253)
+++ trunk/docutils/docs/ref/rst/directives.rst 2025-11-02 17:50:57 UTC (rev 10254)
@@ -259,7 +259,7 @@
.. _image options:
The "image" directive recognizes the common options `class <class option_>`_
-and name_ as well as
+and name_ [#no-inline-name]_ as well as
``align`` : "top", "middle", "bottom", "left", "center", or "right"
The alignment of the image, equivalent to the HTML ``<img>`` tag's
@@ -1424,9 +1424,12 @@
The `image`_ directive can be used both, stand-alone (to define
block-level images) and in substitution definitions to define
-inline images.
+inline images. [#no-inline-name]_
+.. [#no-inline-name] The name_ option cannot be used in
+ a substitution definition. [#substitution-limits]_
+
.. _replace:
Replacement Text
@@ -1435,7 +1438,7 @@
.. class:: field-indent-13em
:Directive Type: "replace"
-:Doctree Element: Text & `inline elements`_
+:Doctree Element: Text & `inline elements`_ [#substitution-limits]_
:Directive Arguments: none
:Directive Options: none
:Directive Content: A single paragraph; may contain inline markup.
@@ -1461,7 +1464,14 @@
.. |Python| replace:: Python, *the* best language around
.. _Python: https://www.python.org/
+.. [#substitution-limits] As a substitution may be referenced more than
+ one time, a substitution definition may not contain references to
+ `anonymous hyperlinks`_, `auto-numbered`_ or `auto-symbol`_ footnotes
+ and no `hyperlink targets`__ (names and identifiers must be unique).
+ __ restructuredtext.html#inline-internal-targets
+
+
.. _unicode:
Unicode Character Codes
@@ -2312,6 +2322,9 @@
https://docs.python.org/3/library/codecs.html#standard-encodings
.. _reStructuredText Markup Specification: restructuredtext.html
+.. _anonymous hyperlinks: restructuredtext.html#anonymous-hyperlinks
+.. _auto-numbered: restructuredtext.html#auto-numbered-footnotes
+.. _auto-symbol: restructuredtext.html#auto-symbol-footnotes
.. _block quote: restructuredtext.html#block-quotes
.. _citation references: restructuredtext.html#citation-references
.. _citation: restructuredtext.html#citations
Modified: trunk/docutils/docutils/parsers/rst/states.py
===================================================================
--- trunk/docutils/docutils/parsers/rst/states.py 2025-10-06 12:29:47 UTC (rev 10253)
+++ trunk/docutils/docutils/parsers/rst/states.py 2025-11-02 17:50:57 UTC (rev 10254)
@@ -2189,15 +2189,23 @@
del substitution_node[i]
else:
i += 1
- for node in substitution_node.findall(nodes.Element):
- if self.disallowed_inside_substitution_definitions(node):
- pformat = nodes.literal_block('', node.pformat().rstrip())
+ for node in substitution_node.findall(nodes.Element,
+ include_self=False):
+ if isinstance(node, nodes.problematic):
msg = self.reporter.error(
- 'Substitution definition contains illegal element <%s>:'
- % node.tagname,
- pformat, nodes.literal_block(blocktext, blocktext),
+ 'Problematic content in substitution definition',
+ nodes.literal_block('', blocktext),
source=src, line=srcline)
+ msg.append(nodes.block_quote(
+ '', nodes.paragraph('', '', *substitution_node.children)))
return [msg], blank_finish
+ illegal = self.disallowed_inside_substitution_definitions(node)
+ if illegal:
+ msg = self.reporter.error(f'{illegal} are not supported in '
+ 'a substitution definition.',
+ nodes.literal_block('', blocktext),
+ source=src, line=srcline)
+ return [msg], blank_finish
if len(substitution_node) == 0:
msg = self.reporter.warning(
'Substitution definition "%s" empty or invalid.' % subname,
@@ -2208,13 +2216,15 @@
substitution_node, subname, self.parent)
return [substitution_node], blank_finish
- def disallowed_inside_substitution_definitions(self, node) -> bool:
- if (node['ids']
- or isinstance(node, nodes.reference) and node.get('anonymous')
- or isinstance(node, nodes.footnote_reference) and node.get('auto')): # noqa: E501
- return True
+ def disallowed_inside_substitution_definitions(self, node) -> str:
+ if isinstance(node, nodes.reference) and node.get('anonymous'):
+ return 'Anonymous references'
+ if isinstance(node, nodes.footnote_reference) and node.get('auto'):
+ return 'References to auto-numbered and auto-symbol footnotes'
+ if node['names'] or node['ids']:
+ return 'Targets (names and identifiers)'
else:
- return False
+ return ''
def directive(self, match, **option_presets):
"""Returns a 2-tuple: list of nodes, and a "blank finish" boolean."""
Modified: trunk/docutils/test/test_parsers/test_rst/test_directives/test_replace.py
===================================================================
--- trunk/docutils/test/test_parsers/test_rst/test_directives/test_replace.py 2025-10-06 12:29:47 UTC (rev 10253)
+++ trunk/docutils/test/test_parsers/test_rst/test_directives/test_replace.py 2025-11-02 17:50:57 UTC (rev 10254)
@@ -23,6 +23,8 @@
class ParserTestCase(unittest.TestCase):
+ maxDiff = None
+
def test_parser(self):
parser = Parser()
settings = get_default_settings(Parser)
@@ -129,12 +131,20 @@
Inline literal start-string without end-string.
<system_message level="3" line="1" source="test data" type="ERROR">
<paragraph>
- Substitution definition contains illegal element <problematic>:
+ Problematic content in substitution definition
<literal_block xml:space="preserve">
- <problematic ids="problematic-1" refid="system-message-1">
- *
- <literal_block xml:space="preserve">
.. |name| replace:: *error in **inline ``markup
+ <block_quote>
+ <paragraph>
+ <problematic ids="problematic-1" refid="system-message-1">
+ *
+ error in \n\
+ <problematic ids="problematic-2" refid="system-message-2">
+ **
+ inline \n\
+ <problematic ids="problematic-3" refid="system-message-3">
+ ``
+ markup
"""],
["""\
.. replace:: not valid outside of a substitution definition
Modified: trunk/docutils/test/test_parsers/test_rst/test_substitutions.py
===================================================================
--- trunk/docutils/test/test_parsers/test_rst/test_substitutions.py 2025-10-06 12:29:47 UTC (rev 10253)
+++ trunk/docutils/test/test_parsers/test_rst/test_substitutions.py 2025-11-02 17:50:57 UTC (rev 10254)
@@ -23,6 +23,8 @@
class ParserTestCase(unittest.TestCase):
+ maxDiff = None
+
def test_parser(self):
parser = Parser()
settings = get_default_settings(Parser)
@@ -287,26 +289,18 @@
Elements that are prohibited inside of substitution definitions:
<system_message level="3" line="3" source="test data" type="ERROR">
<paragraph>
- Substitution definition contains illegal element <target>:
+ Targets (names and identifiers) are not supported in a substitution definition.
<literal_block xml:space="preserve">
- <target ids="target" names="target">
- target
- <literal_block xml:space="preserve">
.. |target| replace:: _`target`
<system_message level="3" line="4" source="test data" type="ERROR">
<paragraph>
- Substitution definition contains illegal element <reference>:
+ Anonymous references are not supported in a substitution definition.
<literal_block xml:space="preserve">
- <reference anonymous="1" name="anonymous">
- anonymous
- <literal_block xml:space="preserve">
.. |reference| replace:: anonymous__
<system_message level="3" line="5" source="test data" type="ERROR">
<paragraph>
- Substitution definition contains illegal element <footnote_reference>:
+ References to auto-numbered and auto-symbol footnotes are not supported in a substitution definition.
<literal_block xml:space="preserve">
- <footnote_reference auto="1" ids="footnote-reference-1">
- <literal_block xml:space="preserve">
.. |auto-numbered footnote| replace:: [#]_
"""],
]
Modified: trunk/docutils/test/test_transforms/test_hyperlinks.py
===================================================================
--- trunk/docutils/test/test_transforms/test_hyperlinks.py 2025-10-06 12:29:47 UTC (rev 10253)
+++ trunk/docutils/test/test_transforms/test_hyperlinks.py 2025-11-02 17:50:57 UTC (rev 10254)
@@ -321,11 +321,8 @@
match in this snippet.
<system_message level="3" line="5" source="test data" type="ERROR">
<paragraph>
- Substitution definition contains illegal element <reference>:
+ Anonymous references are not supported in a substitution definition.
<literal_block xml:space="preserve">
- <reference anonymous="1" name="anonymous">
- anonymous
- <literal_block xml:space="preserve">
.. |invalid| replace:: anonymous__
<paragraph>
<reference anonymous="1" name="hyperlink" refuri="URL">
Modified: trunk/docutils/test/test_transforms/test_substitutions.py
===================================================================
--- trunk/docutils/test/test_transforms/test_substitutions.py 2025-10-06 12:29:47 UTC (rev 10253)
+++ trunk/docutils/test/test_transforms/test_substitutions.py 2025-11-02 17:50:57 UTC (rev 10254)
@@ -25,6 +25,8 @@
class TransformTestCase(unittest.TestCase):
+ maxDiff = None
+
def test_transforms(self):
parser = Parser()
settings = get_default_settings(Parser)
@@ -378,11 +380,8 @@
Substitution definition with an illegal element:
<system_message level="3" line="3" source="test data" type="ERROR">
<paragraph>
- Substitution definition contains illegal element <target>:
+ Targets (names and identifiers) are not supported in a substitution definition.
<literal_block xml:space="preserve">
- <target ids="target" names="target">
- target
- <literal_block xml:space="preserve">
.. |target| replace:: _`target`
<paragraph>
Make sure this substitution definition is not registered: \n\
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|