SF.net SVN: docutils:[9526 ] trunk/docutils/docutils/u tils/math

milde--- via Docutils-checkins <[email protected]>
Newsgroups gmane.text.docutils.cvs
Message-ID <[email protected]>
Revision: 9526
          http://sourceforge.net/p/docutils/code/9526
Author:   milde
Date:     2024-02-01 13:02:23 +0000 (Thu, 01 Feb 2024)
Log Message:
-----------
Make MathML element children interface compatible to xml.etree.

List access via `__setitem__()`, `__getitem__()`, `__delitem__()`,
__pop__()`, `__iter__()`.

Use the new interface for cleaner code.

Modified Paths:
--------------
    trunk/docutils/docutils/utils/math/latex2mathml.py
    trunk/docutils/docutils/utils/math/mathml_elements.py

Modified: trunk/docutils/docutils/utils/math/latex2mathml.py
===================================================================
--- trunk/docutils/docutils/utils/math/latex2mathml.py	2024-02-01 13:02:12 UTC (rev 9525)
+++ trunk/docutils/docutils/utils/math/latex2mathml.py	2024-02-01 13:02:23 UTC (rev 9526)
@@ -569,8 +569,8 @@
             # characters with a special meaning in LaTeX math mode
             # fix spacing before "unary" minus.
             attributes = {}
-            if c == '-' and node.children:
-                previous_node = node.children[-1]
+            if c == '-' and len(node):
+                previous_node = node[-1]
                 if (getattr(previous_node, 'data', '-') in '([='
                     or previous_node.get('class') == 'mathopen'):
                     attributes['form'] = 'prefix'
@@ -885,7 +885,7 @@
             new_node = munderover(base)
             sub_node = parse_latex_math(mrow(), subscript)
             if len(sub_node) == 1:
-                sub_node = sub_node.children[0]
+                sub_node = sub_node[0]
             new_node.append(sub_node)
         else:
             new_node = mover(base)
@@ -897,7 +897,7 @@
         new_node.nchildren = None
         if isinstance(node, mrow) and len(node) == 0:
             # replace node with new_node
-            node.parent.children[node.parent.children.index(node)] = new_node
+            node.parent[node.parent.children.index(node)] = new_node
             new_node.parent = node.parent
         elif node.__class__.__name__ == 'math':
             node.append(new_node)
@@ -997,7 +997,7 @@
 
 def handle_script_or_limit(node, c, limits=''):
     """Append script or limit element to `node`."""
-    child = node.children.pop()
+    child = node.pop()
     if limits == 'limits':
         child.set('movablelimits', 'false')
     elif (limits == 'movablelimits'
@@ -1006,9 +1006,9 @@
 
     if c == '_':
         if isinstance(child, mover):
-            new_node = munderover(*child.children, switch=True)
+            new_node = munderover(*child, switch=True)
         elif isinstance(child, msup):
-            new_node = msubsup(*child.children, switch=True)
+            new_node = msubsup(*child, switch=True)
         elif (limits in ('limits', 'movablelimits')
               or limits == '' and child.get('movablelimits', None)):
             new_node = munder(child)
@@ -1016,9 +1016,9 @@
             new_node = msub(child)
     elif c == '^':
         if isinstance(child, munder):
-            new_node = munderover(*child.children)
+            new_node = munderover(*child)
         elif isinstance(child, msub):
-            new_node = msubsup(*child.children)
+            new_node = msubsup(*child)
         elif (limits in ('limits', 'movablelimits')
               or limits == '' and child.get('movablelimits', None)):
             new_node = mover(child)

Modified: trunk/docutils/docutils/utils/math/mathml_elements.py
===================================================================
--- trunk/docutils/docutils/utils/math/mathml_elements.py	2024-02-01 13:02:12 UTC (rev 9525)
+++ trunk/docutils/docutils/utils/math/mathml_elements.py	2024-02-01 13:02:23 UTC (rev 9526)
@@ -83,7 +83,7 @@
         self.attrib = {k.lower(): self.a_str(v)
                        for k, v in attributes.items()}
         self.children = []
-        self += children
+        self.extend(children)
 
     @staticmethod
     def a_str(v):
@@ -93,7 +93,7 @@
         return str(v)
 
     def __repr__(self):
-        content = [repr(item) for item in self.children]
+        content = [repr(item) for item in self]
         if hasattr(self, 'data'):
             content.append(repr(self.data))
         if getattr(self, 'switch', None):
@@ -101,10 +101,10 @@
         content += [f'{k}={v!r}' for k, v in self.items() if v is not None]
         return self.__class__.__name__ + '(%s)' % ', '.join(content)
 
-    def __len__(self):
-        return len(self.children)
+# Emulate dictionary access methods for attributes
+# and list-like interface to the child elements
+# (differs from `docutils.nodes.Element` dict/list interface).
 
-    # emulate dictionary access methods for attributes
     def get(self, key, default=None):
         return self.attrib.get(key, default)
 
@@ -120,38 +120,67 @@
             yield child
             yield from child.subnodes()
 
+    def __len__(self):
+        return len(self.children)
+
+    def __getitem__(self, key):
+        return self.children.__getitem__(key)
+
+    def __setitem__(self, key, element):
+        element.parent = self
+        self.children.__setitem__(key, element)
+
+    def __delitem__(self, key):
+        self.children.__delitem__(key)
+
+    def __iter__(self):
+        return self.children.__iter__()
+
     def full(self):
         """Return boolean indicating whether children may be appended."""
         return self.nchildren is not None and len(self) >= self.nchildren
 
     def close(self):
-        """Close element and return first non-full parent or None."""
+        """Close element and return first non-full anchestor or None."""
+        self.nchildren = len(self)  # mark node as full
         parent = self.parent
         while parent is not None and parent.full():
             parent = parent.parent
         return parent
 
-    def append(self, child):
-        """Append child and return self or first non-full parent.
+    def append(self, element):
+        """Append `element` and return new "current node" (insertion point).
 
-        If self is full, go up the tree and return first non-full node or
-        `None`.
+        Append as child element and set the internal `parent` attribute.
+
+        If self is already full, raise TypeError.
+
+        If self is full after appending, call `self.close()`
+        (returns first non-full anchestor or None) else return `self`.
         """
         if self.full():
-            raise TypeError(f'Element {self} already full!')
-        self.children.append(child)
-        child.parent = self
+            raise TypeError(f'Element "{self}" already full!')
+        self.children.append(element)
+        element.parent = self
         if self.full():
             return self.close()
         return self
 
-    def extend(self, children):
-        for child in children:
-            self.append(child)
-        return self
+    def extend(self, elements):
+        """Sequentially append `elements`. Return new "current node".
 
-    __iadd__ = extend  # alias for ``+=`` operator
+        Raise TypeError if overfull.
+        """
+        current_node = self
+        for element in elements:
+            current_node = self.append(element)
+        return current_node
 
+    def pop(self, index=-1):
+        element = self[index]
+        del self[index]
+        return element
+
     def is_block(self):
         """Return true, if `self` or a parent has ``display='block'``."""
         try:
@@ -194,8 +223,7 @@
 # '<math>\n  <mn>2</mn>\n</math>'
 # >>> len(n2)
 # 1
-# >>> n2 += [mo('!')]
-# >>> n2
+# >>> n2.extend([mo('!')])
 # math(mn(2), mo('!'))
 # >>> eq3 = math(id='eq3', display='block')
 # >>> eq3
@@ -248,16 +276,26 @@
         self.switch = kwargs.pop('switch', False)
         math.__init__(self, *children, **kwargs)
 
-    def append(self, child):
-        current_node = super().append(child)
-        # normalize order if full
+    def append(self, element):
+        """Append element. Normalize order and close if full."""
+        current_node = super().append(element)
         if self.switch and self.full():
-            self.children[-1], self.children[-2] = \
-                self.children[-2], self.children[-1]
+            self[-1], self[-2] = self[-2], self[-1]
             self.switch = False
         return current_node
 
+# >>> MathSchema(switch=True, display=True)
+# MathSchema(switch=True, display='true')
+# >>> MathSchema(MathElement(), switch=True)
+# MathSchema(MathElement(), switch=True)
+# >>> MathSchema(MathElement(id='c1'), MathElement(id='c2'), switch=True)
+# MathSchema(MathElement(id='c2'), MathElement(id='c1'))
+# >>> MathSchema(MathElement(), MathElement(), MathElement())
+# Traceback (most recent call last):
+# ...
+# TypeError: Element "MathSchema(MathElement(), MathElement())" already full!
 
+
 # Token elements represent the smallest units of mathematical notation which
 # carry meaning.
 
@@ -355,10 +393,10 @@
         """
         parent = self.parent
         # replace `self` with single child
-        if len(self) == 1:
-            child = self.children[0]
+        if parent is not None and len(self) == 1:
+            child = self[0]
             try:
-                parent.children[parent.children.index(self)] = child
+                parent[parent.children.index(self)] = child
                 child.parent = parent
             except (AttributeError, ValueError):
                 return None
@@ -457,7 +495,7 @@
 # munder(mi('lim'), mo('-'), accent='false')
 # >>> mu.append(mi('lim'))
 # Traceback (most recent call last):
-# TypeError: Element munder(mi('lim'), mo('-'), accent='false') already full!
+# TypeError: Element "munder(mi('lim'), mo('-'), accent='false')" already full!
 # >>> munder(mo('-'), mi('lim'), accent='false', switch=True).toprettyxml()
 # '<munder accent="false">\n  <mi>lim</mi>\n  <mo>-</mo>\n</munder>'
 

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.