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

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

Rename attributes dictionary to `attrib`.

Convert values to string representation before storing.
Improve auxiliary method `a_str()`: only lowercase boolean values.

Provide access methods `get()`, `set()`, `items()`.

Remove "magical methods" `__getitem__()`, `__setitem__()`.
For XML elements, the [...] syntax to access items is ambiguous:
`xml.etree` uses square brackets to access a node's children,
not its attributes.

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:01 UTC (rev 9524)
+++ trunk/docutils/docutils/utils/math/latex2mathml.py	2024-02-01 13:02:12 UTC (rev 9525)
@@ -599,7 +599,7 @@
 # >>> parse_latex_math(math(), '\\sqrt[3]{2 + 3}')
 # math(mroot(mrow(mn('2'), mo('+'), mn('3')), mn('3')))
 # >>> parse_latex_math(math(), '\max_x') # function takes limits
-# math(munder(mo('max', movablelimits=True), mi('x')))
+# math(munder(mo('max', movablelimits='true'), mi('x')))
 # >>> parse_latex_math(math(), 'x^j_i') # ensure correct order: base, sub, sup
 # math(msubsup(mi('x'), mi('i'), mi('j')))
 # >>> parse_latex_math(math(), '\int^j_i') # ensure correct order
@@ -638,7 +638,7 @@
             # upright in "TeX style" but MathML sets them italic ("ISO style").
             # CSS styling does not change the font style in Firefox 78.
             # Use 'mathvariant="normal"'?
-            new_node['class'] = 'capital-greek'
+            new_node.set('class', 'capital-greek')
         node = node.append(new_node)
         return node, string
 
@@ -850,7 +850,7 @@
         # mi() would be simpler, but semantically wrong
         # --- https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo
         if name == 'vec':
-            accent_node['scriptlevel'] = '+1'  # scale down arrow
+            accent_node.set('scriptlevel', '+1')  # scale down arrow
         new_node = mover(accent_node, accent=True, switch=True)
         node.append(new_node)
         return new_node, string
@@ -946,9 +946,9 @@
 # >>> handle_cmd('operatorname', math(), '{abs}(x)')
 # (math(mi('abs', mathvariant='normal'), mo('\u2061')), '(x)')
 # >>> handle_cmd('overline', math(), '{981}')
-# (mover(mo('_', accent=True), switch=True, accent=False), '{981}')
+# (mover(mo('_', accent='true'), switch=True, accent='false'), '{981}')
 # >>> handle_cmd('bar', math(), '{x}')
-# (mover(mo('ˉ', stretchy=False), switch=True, accent=True), '{x}')
+# (mover(mo('ˉ', stretchy='false'), switch=True, accent='true'), '{x}')
 # >>> handle_cmd('xleftarrow', math(), r'[\alpha]{10}')
 # (munderover(mo('⟵'), mi('α')), '{10}')
 # >>> handle_cmd('xleftarrow', math(), r'[\alpha=5]{10}')
@@ -980,7 +980,7 @@
         if isinstance(subnode, (mi, mn)):
             subnode.data = ma2ch.get(subnode.data, subnode.data)
         if isinstance(subnode, mi) and name == 'mathrm' and subnode.data.isalpha():
-            subnode.attributes['mathvariant'] = 'normal'
+            subnode.set('mathvariant', 'normal')
     return container.close(), string
 
 # >>> handle_math_alphabet('mathrm', math(), '\\alpha')
@@ -999,10 +999,10 @@
     """Append script or limit element to `node`."""
     child = node.children.pop()
     if limits == 'limits':
-        child['movablelimits'] = False
+        child.set('movablelimits', 'false')
     elif (limits == 'movablelimits'
           or getattr(child, 'data', '') in movablelimits):
-        child['movablelimits'] = True
+        child.set('movablelimits', 'true')
 
     if c == '_':
         if isinstance(child, mover):
@@ -1129,7 +1129,7 @@
     math_tree = math(xmlns='http://www.w3.org/1998/Math/MathML')
     node = math_tree
     if as_block:
-        math_tree['display'] = 'block'
+        math_tree.set('display', 'block')
         rows = toplevel_code(tex_math).split(r'\\')
         if len(rows) > 1:
             # emulate "align*" environment with a math table

Modified: trunk/docutils/docutils/utils/math/mathml_elements.py
===================================================================
--- trunk/docutils/docutils/utils/math/mathml_elements.py	2024-02-01 13:02:01 UTC (rev 9524)
+++ trunk/docutils/docutils/utils/math/mathml_elements.py	2024-02-01 13:02:12 UTC (rev 9525)
@@ -69,25 +69,28 @@
     def __init__(self, *children, **attributes):
         """Set up node with `children` and `attributes`.
 
-        Attributes are downcased to allow using CLASS to set "class" value.
-        >>> math(mn(3), CLASS='test')
-        math(mn(3), class='test')
-        >>> math(CLASS='test').toprettyxml()
-        '<math class="test">\n</math>'
+        Attribute names are normalised to lowercase.
+        You may use "CLASS" to set a "class" attribute.
+        Attribute values are converted to strings
+        (with True -> "true" and False -> "false").
 
+        >>> math(CLASS='test', level=3, split=True)
+        math(class='test', level='3', split='true')
+        >>> math(CLASS='test', level=3, split=True).toprettyxml()
+        '<math class="test" level="3" split="true">\n</math>'
+
         """
+        self.attrib = {k.lower(): self.a_str(v)
+                       for k, v in attributes.items()}
         self.children = []
         self += children
-        self.attributes = {}
-        for key in attributes.keys():
-            # Use .lower() to allow argument `CLASS` for attribute `class`
-            # (Python keyword). MathML uses only lowercase attributes.
-            self.attributes[key.lower()] = attributes[key]
 
     @staticmethod
     def a_str(v):
         # Return string representation for attribute value `v`.
-        return str(v).replace('True', 'true').replace('False', 'false')
+        if isinstance(v, bool):
+            return str(v).lower()
+        return str(v)
 
     def __repr__(self):
         content = [repr(item) for item in self.children]
@@ -95,23 +98,21 @@
             content.append(repr(self.data))
         if getattr(self, 'switch', None):
             content.append('switch=True')
-        content += ["%s=%r"%(k, v) for k, v in self.attributes.items()
-                    if v is not None]
+        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-like access to attributes
-    # see `docutils.nodes.Element` for dict/list interface
-    def __getitem__(self, key):
-        return self.attributes[key]
+    # emulate dictionary access methods for attributes
+    def get(self, key, default=None):
+        return self.attrib.get(key, default)
 
-    def __setitem__(self, key, item):
-        self.attributes[key] = item
+    def set(self, key, value):
+        self.attrib[key] = self.a_str(value)
 
-    def get(self, *args, **kwargs):
-        return self.attributes.get(*args, **kwargs)
+    def items(self):
+        return self.attrib.items()
 
     def subnodes(self):
         """Return iterator over all subnodes, including nested ones."""
@@ -154,7 +155,7 @@
     def is_block(self):
         """Return true, if `self` or a parent has ``display='block'``."""
         try:
-            return self['display'] == 'block'
+            return self.get('display') == 'block'
         except KeyError:
             try:
                 return self.parent.is_block()
@@ -175,8 +176,7 @@
                 '</%s>' % self.__class__.__name__]
 
     def xml_starttag(self):
-        attrs = (f'{k}="{self.a_str(v)}"'
-                 for k, v in self.attributes.items() if v is not None)
+        attrs = (f'{k}="{v}"' for k, v in self.items() if v is not None)
         return '<%s>' % ' '.join((self.__class__.__name__, *attrs))
 
     def _xml_body(self, level=0):
@@ -336,17 +336,17 @@
     """
 
     def transfer_attributes(self, other):
-        # Update dictionary `other.attributes` with self.attributes.
-        # String attributes (class, style) are appended to existing values,
-        # other attributes (displaystyle, scriptlevel) replace them.
-        for k, v in self.attributes.items():
+        # Update dictionary `other.attrib` with self.attrib.
+        # List values (class, style) are appended to existing values,
+        # other values replace existing values.
+        for k, v in self.items():
             if k in ('class', 'style') and v:
                 try:
-                    other.attributes[k] += ' ' + v
+                    other.attrib[k] += ' ' + v
                     continue
                 except (KeyError, TypeError):
                     pass
-            other.attributes[k] = v
+            other.attrib[k] = v
 
     def close(self):
         """Close element and return first non-full parent or None.
@@ -447,18 +447,18 @@
     """Attach accents or limits both under and over an expression."""
 
 
-# >>> munder(mi('lim'), mo('-'), accent=False)
-# munder(mi('lim'), mo('-'), accent=False)
-# >>> mu = munder(mo('-'), accent=False, switch=True)
+# >>> munder(mi('lim'), mo('-'), accent='false')
+# munder(mi('lim'), mo('-'), accent='false')
+# >>> mu = munder(mo('-'), accent='false', switch=True)
 # >>> mu
-# munder(mo('-'), switch=True, accent=False)
+# munder(mo('-'), switch=True, accent='false')
 # >>> mu.append(mi('lim'))
 # >>> mu
-# munder(mi('lim'), mo('-'), accent=False)
+# 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!
-# >>> munder(mo('-'), mi('lim'), accent=False, switch=True).toprettyxml()
+# 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.



_______________________________________________
Docutils-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/docutils-checkins
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.