SF.net SVN: docutils:[10228 ] trunk/docutils
milde--- via Docutils-checkins <[email protected]> Mon, 08 Sep 2025 13:44:23 +0000
| Newsgroups | gmane.text.docutils.cvs |
|---|---|
| Message-ID | <[email protected]> |
Revision: 10228
http://sourceforge.net/p/docutils/code/10228
Author: milde
Date: 2025-09-08 13:44:23 +0000 (Mon, 08 Sep 2025)
Log Message:
-----------
rST parser: simplifications, fixes, and improvements
Define the attribute `parent_state_machine` only in
`parsers.rst.state.NestedStateMachine`.
It does not make sense in other state machines.
More detailled error message for inacessible section parents.
Test with a copy of Sphinx's `_fresh_title_style_context`.
Modified Paths:
--------------
trunk/docutils/HISTORY.rst
trunk/docutils/docutils/parsers/rst/states.py
trunk/docutils/docutils/statemachine.py
trunk/docutils/test/test_parsers/test_rst/test_nested_parsing.py
Modified: trunk/docutils/HISTORY.rst
===================================================================
--- trunk/docutils/HISTORY.rst 2025-09-05 14:07:30 UTC (rev 10227)
+++ trunk/docutils/HISTORY.rst 2025-09-08 13:44:23 UTC (rev 10228)
@@ -14,7 +14,7 @@
.. contents::
-Release 0.23b0 (unpublished)
+Release 0.22.1 (unpublished)
============================
* docutils/frontend.py, docutils/writers/
@@ -29,19 +29,14 @@
* docutils/parsers/rst/states.py
- Relax "section title" system messages from SEVERE to ERROR.
- - Revert to using `document.memo.section_level` to fix behaviour with
- nested parsing into a detached node (cf. bugs #508 and #509).
- - Set `parent_state_machine` attribute when creating nested state machines.
- Use it to update the "current node" of the parent state machines after
- nested parsing.
+ - Fix behaviour with nested parsing into a detached node
+ (cf. bugs #508 and #509).
+ - New attribute `NestedStateMachine.parent_state_machine`.
+ Use case: update the "current node" of parent state machine(s)
+ after nested parsing.
- Better error messages for grid table markup errors (bug #504),
based on patch #214 by Jynn Nelson.
-* docutils/statemachine.py
-
- - New attribute `StateMachine.parent_state_machine` to store the
- parent state machine of nested state machines.
-
* docutils/transforms/references.py
- Better error reports for hyperlinks with embedded URI or alias.
@@ -52,7 +47,7 @@
for elements with IDs (fixes bug #503).
- Fix cross-reference anchor placement in figures, images,
literal-blocks, tables, and (sub)titles.
- - Simplify code for nested image.
+ - Simplify code for images nested in reference or figure elements.
Release 0.22 (2026-07-29)
Modified: trunk/docutils/docutils/parsers/rst/states.py
===================================================================
--- trunk/docutils/docutils/parsers/rst/states.py 2025-09-05 14:07:30 UTC (rev 10227)
+++ trunk/docutils/docutils/parsers/rst/states.py 2025-09-08 13:44:23 UTC (rev 10228)
@@ -182,6 +182,14 @@
document structures.
"""
+ def __init__(self, state_classes, initial_state,
+ debug=False, parent_state_machine=None) -> None:
+
+ self.parent_state_machine = parent_state_machine
+ """The instance of the parent state machine."""
+
+ super().__init__(state_classes, initial_state, debug)
+
def run(self, input_lines, input_offset, memo, node, match_titles=True):
"""
Parse `input_lines` and populate `node`.
@@ -328,7 +336,6 @@
# run the state machine and populate `node`:
block_length = len(block)
- old_section_level = self.memo.section_level
my_state_machine.run(block, input_offset, memo=self.memo,
node=node, match_titles=match_titles)
@@ -342,8 +349,10 @@
sm = sm.parent_state_machine
except AttributeError:
pass
- else:
- self.memo.section_level = old_section_level
+ # set section level
+ # (fails with Sphinx's `_fresh_title_style_context`)
+ self.memo.section_level = len(
+ self.state_machine.node.section_hierarchy())
# clean up
new_offset = my_state_machine.abs_line_offset()
if use_default == 2:
@@ -438,11 +447,12 @@
try:
new_parent = parent_sections[newlevel-oldlevel-1].parent
except IndexError:
- new_parent = None
- if new_parent is None:
styles = ' '.join('/'.join(style) for style in title_styles)
details = (f'The parent of level {newlevel} sections cannot'
- ' be reached.\nOne reason may be a high level'
+ ' be reached. The parser is at section level'
+ f' {oldlevel} but the current node has only'
+ f' {len(parent_sections)} parent section(s).'
+ '\nOne reason may be a high level'
' section used in a directive that parses its'
' content into a base node not attached to'
' the document\n(up to Docutils 0.21,'
Modified: trunk/docutils/docutils/statemachine.py
===================================================================
--- trunk/docutils/docutils/statemachine.py 2025-09-05 14:07:30 UTC (rev 10227)
+++ trunk/docutils/docutils/statemachine.py 2025-09-08 13:44:23 UTC (rev 10228)
@@ -130,8 +130,7 @@
results of processing in a list.
"""
- def __init__(self, state_classes, initial_state,
- debug=False, parent_state_machine=None) -> None:
+ def __init__(self, state_classes, initial_state, debug=False) -> None:
"""
Initialize a `StateMachine` object; add state objects.
@@ -140,7 +139,6 @@
- `state_classes`: a list of `State` (sub)classes.
- `initial_state`: a string, the class name of the initial state.
- `debug`: a boolean; produce verbose output if true (nonzero).
- - `parent_state_machine`: the parent of a nested state machine.
"""
self.input_lines = None
"""`StringList` of input lines (without newlines).
@@ -158,9 +156,6 @@
self.debug = debug
"""Debugging mode on/off."""
- self.parent_state_machine = parent_state_machine
- """The instance of the parent state machine or None."""
-
self.initial_state = initial_state
"""The name of the initial state (key to `self.states`)."""
Modified: trunk/docutils/test/test_parsers/test_rst/test_nested_parsing.py
===================================================================
--- trunk/docutils/test/test_parsers/test_rst/test_nested_parsing.py 2025-09-05 14:07:30 UTC (rev 10227)
+++ trunk/docutils/test/test_parsers/test_rst/test_nested_parsing.py 2025-09-08 13:44:23 UTC (rev 10228)
@@ -24,6 +24,7 @@
"""
from pathlib import Path
+import contextlib
import sys
import unittest
@@ -87,6 +88,7 @@
class ParseIntoSectionNode(ParseIntoNode):
# Some 3rd party extensions use a <section> as dummy base node.
+ # cf. https://github.com/sphinx-contrib/autoprogram/blob/master/sphinxcontrib/autoprogram.py
#
# Attention: this directive is flawed:
# * no check for section validity,
@@ -98,6 +100,53 @@
return node.children
+class FreshParseIntoNode(ParseIntoNode):
+ """Nested parsing with support for sections (separate title styles).
+
+ * no check for section validity,
+ * "current" node not updated! -> element order may get lost.
+
+ cf. `sphinx.util.nodes.nested_parse_with_titles()`
+ and `sphinx.util.parsing.nested_parse_to_nodes()`
+ """
+ def run(self):
+ node = nodes.Element()
+ with _fresh_title_style_context(self.state):
+ self.state.nested_parse(self.content, self.content_offset,
+ node, match_titles=True)
+ return node.children
+
+
+class FreshParseIntoCurrentNode(ParseIntoNode):
+ # Nested parsing with support for sections (separate title styles)
+ #
+ # Parsing into the current node, `nested_parse()` ensures validity
+ # and updates the "current node".
+ def run(self):
+ with _fresh_title_style_context(self.state):
+ self.state.nested_parse(self.content, self.content_offset,
+ match_titles=True)
+ # update section level
+ self.state_machine.memo.section_level = len(
+ self.state_machine.node.section_hierarchy())
+ return [] # node already attached to document
+
+
[email protected]
+def _fresh_title_style_context(state):
+ # copied from sphinx/sphinx/util/parsing.py
+ memo = state.memo
+ surrounding_title_styles = memo.title_styles
+ surrounding_section_level = memo.section_level
+ memo.title_styles = []
+ memo.section_level = 0
+ try:
+ yield
+ finally:
+ memo.title_styles = surrounding_title_styles
+ memo.section_level = surrounding_section_level
+
+
class ParserTestCase(unittest.TestCase):
maxDiff = None
@@ -105,6 +154,8 @@
register_directive('nested', ParseIntoNode)
register_directive('nested-current', ParseIntoCurrentNode)
register_directive('nested-section', ParseIntoSectionNode)
+ register_directive('fresh', FreshParseIntoNode)
+ register_directive('fresh-current', FreshParseIntoCurrentNode)
parser = rst.Parser()
settings = get_default_settings(rst.Parser)
settings.warning_stream = ''
@@ -147,6 +198,8 @@
***********
nested2.1
---------
+ nested2.2
+ ---------
inaccessible2
=============
@@ -183,7 +236,10 @@
<section ids="nested2-1" names="nested2.1">
<title>
nested2.1
- <system_message level="3" line="20" source="test data" type="ERROR">
+ <section ids="nested2-2" names="nested2.2">
+ <title>
+ nested2.2
+ <system_message level="3" line="22" source="test data" type="ERROR">
<paragraph>
A level 1 section cannot be used here.
<literal_block xml:space="preserve">
@@ -192,13 +248,13 @@
<paragraph>
Established title styles: = - * ~
<paragraph>
- The parent of level 1 sections cannot be reached.
+ The parent of level 1 sections cannot be reached. The parser is at section level 2 but the current node has only 1 parent section(s).
One reason may be a high level section used in a directive that parses its content into a base node not attached to the document
(up to Docutils 0.21, these sections were silently dropped).
<section ids="sec2-2" names="sec2.2">
<title>
sec2.2
- <system_message level="3" line="25" source="test data" type="ERROR">
+ <system_message level="3" line="27" source="test data" type="ERROR">
<paragraph>
Inconsistent title style: skip from level 2 to 4.
<literal_block xml:space="preserve">
@@ -385,7 +441,7 @@
<paragraph>
Established title styles: =
<paragraph>
- The parent of level 1 sections cannot be reached.
+ The parent of level 1 sections cannot be reached. The parser is at section level 1 but the current node has only 0 parent section(s).
One reason may be a high level section used in a directive that parses its content into a base node not attached to the document
(up to Docutils 0.21, these sections were silently dropped).
<paragraph>
@@ -439,6 +495,132 @@
Element <block_quote> invalid:
Child element <section ids="invalid-section-sic" names="invalid\\ section\\ (sic!)"> not allowed at this position.
"""],
+# Nested parsing with new title style hierarchy
+["""\
+sec1
+====
+sec1.1
+------
+.. fresh::
+
+ fresh1.1.1
+ ==========
+ fresh1.1.1.1
+ ~~~~~~~~~~~~~
+
+sec2
+====
+.. fresh::
+
+ fresh2.1
+ ***********
+ New title styles with every directive.
+
+ fresh2.1.1
+ -----------
+ fresh2.1.2
+ -----------
+ fresh2.1.2.1
+ =============
+
+This text belongs into the last nested section (sic!).
+
+sec2.2
+------
+Document-wide title styles unchanged
+
+sec2.2.1
+********
+""",
+"""\
+<document source="test data">
+ <section ids="sec1" names="sec1">
+ <title>
+ sec1
+ <section ids="sec1-1" names="sec1.1">
+ <title>
+ sec1.1
+ <section ids="fresh1-1-1" names="fresh1.1.1">
+ <title>
+ fresh1.1.1
+ <section ids="fresh1-1-1-1" names="fresh1.1.1.1">
+ <title>
+ fresh1.1.1.1
+ <section ids="sec2" names="sec2">
+ <title>
+ sec2
+ <section ids="fresh2-1" names="fresh2.1">
+ <title>
+ fresh2.1
+ <paragraph>
+ New title styles with every directive.
+ <section ids="fresh2-1-1" names="fresh2.1.1">
+ <title>
+ fresh2.1.1
+ <section ids="fresh2-1-2" names="fresh2.1.2">
+ <title>
+ fresh2.1.2
+ <section ids="fresh2-1-2-1" names="fresh2.1.2.1">
+ <title>
+ fresh2.1.2.1
+ <paragraph>
+ This text belongs into the last nested section (sic!).
+ <section ids="sec2-2" names="sec2.2">
+ <title>
+ sec2.2
+ <paragraph>
+ Document-wide title styles unchanged
+ <section ids="sec2-2-1" names="sec2.2.1">
+ <title>
+ sec2.2.1
+ <system_message level="2" line="27" source="test data" type="WARNING">
+ <paragraph>
+ Element <section ids="sec2" names="sec2"> invalid:
+ Child element <paragraph> not allowed at this position.
+"""],
+# Nested parsing into current node with new title style hierarchy
+["""\
+sec1
+====
+sec1.1
+------
+.. fresh-current::
+
+ fc1.1.1
+ -------
+ fc1.1.2
+ -------
+ fc1.1.2.1
+ =========
+
+This text belongs into the last nested section.
+
+sec1.2
+------
+""",
+"""\
+<document source="test data">
+ <section ids="sec1" names="sec1">
+ <title>
+ sec1
+ <section ids="sec1-1" names="sec1.1">
+ <title>
+ sec1.1
+ <section ids="fc1-1-1" names="fc1.1.1">
+ <title>
+ fc1.1.1
+ <section ids="fc1-1-2" names="fc1.1.2">
+ <title>
+ fc1.1.2
+ <section ids="fc1-1-2-1" names="fc1.1.2.1">
+ <title>
+ fc1.1.2.1
+ <paragraph>
+ This text belongs into the last nested section.
+ <section ids="sec1-2" names="sec1.2">
+ <title>
+ sec1.2
+"""],
]
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.