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