Skip to content
Snippets Groups Projects
Commit 75edf1df authored by Vanessa Stehr's avatar Vanessa Stehr
Browse files

Implement default values, make the parser a class

parent feb41533
No related branches found
No related tags found
No related merge requests found
......@@ -4,7 +4,8 @@ This library converts D-SI unit strings to Latex.
## Usage
Create a D-SI tree with the D-SI unit string as an argument: `tree = dsiParser.dsiTree("\mega\hertz")`.
Set up a parser (with optional arguments for default latex values): `parser = dsiParser(latexDefaultWrapper='$', latexDefaultPrefix=r'\mathrm{Prefix}', latexDefaultSuffix=r'\mathrm{Suffix}')`.
Create a D-SI tree with the D-SI unit string as an argument: `tree = parser.parse("\mega\hertz")`.
- To validate the D-SI unit string, inspect the `valid` property: `print(tree.valid)`
- To see any warning messages generated while parsing the string, inspect the `warnings` property: `print(tree.warnings)`
......
......@@ -2,10 +2,36 @@ from dataclasses import dataclass
import re
import warnings
class dsiTree:
class dsiParser:
"""Parser to parse D-SI unit string into a tree
"""
def __init__(self, latexDefaultWrapper='$$', latexDefaultPrefix='', latexDefaultSuffix=''):
"""
Args:
latexDefaultWrapper (str, optional): String to be added both in the beginning and the end of the LaTeX string. Defaults to '$$'.
latexDefaultPrefix (str, optional): String to be added in the beginning of the LaTeX string, after the wrapper. Defaults to ''.
latexDefaultSuffix (str, optional): String to be added in the end of the LaTeX string, before the wrapper. Defaults to ''.
"""
self.latexDefaultWrapper = latexDefaultWrapper
self.latexDefaultPrefix = latexDefaultPrefix
self.latexDefaultSuffix = latexDefaultSuffix
def parse(self, dsiString: str):
"""Parse D-SI unit string into tree structure
Args:
dsiString (str): The D-SI string to be parsed
Returns:
_dsiTree: The generated tree
"""
return _dsiTree(dsiString, self.latexDefaultWrapper, self.latexDefaultPrefix, self.latexDefaultSuffix)
class _dsiTree:
"""D-SI representation in tree form, also includes validity check and warnings about D-SI string
"""
def __init__(self, dsiString: str):
def __init__(self, dsiString: str, latexDefaultWrapper='$$', latexDefaultPrefix='', latexDefaultSuffix=''):
"""
Args:
dsiString (str): the D-SI unit string to be parsed
......@@ -13,18 +39,28 @@ class dsiTree:
self.dsiString = dsiString
(self.tree, self.warnings) = _parseDsi(dsiString)
self.valid = len(self.warnings) == 0
self._latexDefaultWrapper = latexDefaultWrapper
self._latexDefaultPrefix = latexDefaultPrefix
self._latexDefaultSuffix = latexDefaultSuffix
def toLatex(self, wrapper='$$', prefix='', suffix=''):
def toLatex(self, wrapper=None, prefix=None, suffix=None):
"""converts D-SI unit string to LaTeX
Args:
wrapper (str, optional): String to be added both in the beginning and the end of the LaTeX string. Defaults to '$$'.
prefix (str, optional): String to be added in the beginning of the LaTeX string, after the wrapper. Defaults to ''.
suffix (str, optional): String to be added in the end of the LaTeX string, before the wrapper. Defaults to ''.
wrapper (str, optional): String to be added both in the beginning and the end of the LaTeX string. Defaults to the value set in the parser object.
prefix (str, optional): String to be added in the beginning of the LaTeX string, after the wrapper. Defaults to the value set in the parser object.
suffix (str, optional): String to be added in the end of the LaTeX string, before the wrapper. Defaults to the value set in the parser object.
Returns:
str: the corresponding LaTeX code
"""
# If no wrapper/prefix/suffix was given, set to the parser's default
wrapper = self._latexDefaultWrapper if wrapper == None else wrapper
prefix = self._latexDefaultPrefix if prefix == None else prefix
suffix = self._latexDefaultSuffix if suffix == None else suffix
if self.tree == []:
if len(prefix)+len(suffix) > 0:
return wrapper+prefix+suffix+wrapper
......
import pytest
from dsiParser import dsiTree, _node
from dsiParser import dsiParser, _node
p = dsiParser()
def test_baseCase():
# Most basic case: one unit without prefix or exponent
tree = dsiTree(r'\metre')
tree = p.parse(r'\metre')
assert tree.tree == [[_node('','metre','')]]
assert tree.toLatex() == r'$$\mathrm{m}$$'
assert tree.valid
assert tree.warnings == []
# One longer unit
tree = dsiTree(r'\milli\metre\tothe{0.5}\kilogram\per\mega\second\tothe{3}\ampere\tothe{-2}')
tree = p.parse(r'\milli\metre\tothe{0.5}\kilogram\per\mega\second\tothe{3}\ampere\tothe{-2}')
assert tree.toLatex() == r'$$\frac{\sqrt{\mathrm{m}\mathrm{m}}\,\mathrm{kg}}{\mathrm{M}\mathrm{s}^{3}\,\mathrm{A}^{-2}}$$'
assert tree.valid
assert tree.warnings == []
......@@ -19,7 +21,7 @@ def test_baseCase():
def test_robustness():
# Unknown unit
with pytest.warns(RuntimeWarning, match='The identifier \"foo\" does not match any D-SI units!'):
tree = dsiTree(r'\foo')
tree = p.parse(r'\foo')
assert tree.toLatex() == r'$${\color{red}\mathrm{foo}}$$'
assert not tree.valid
assert len(tree.warnings) == 1
......@@ -27,7 +29,7 @@ def test_robustness():
# Unknown string in the middle of input
with pytest.warns(RuntimeWarning, match='The identifier \"mini\" does not match any D-SI units!'):
tree = dsiTree(r'\kilo\metre\per\mini\second')
tree = p.parse(r'\kilo\metre\per\mini\second')
print(tree.toLatex())
assert tree.toLatex() == r'$$\frac{\mathrm{k}\mathrm{m}}{{\color{red}\mathrm{mini}}\,\mathrm{s}}$$'
assert not tree.valid
......@@ -36,7 +38,7 @@ def test_robustness():
# Base unit missing
with pytest.warns(RuntimeWarning, match=r'This D-SI unit seems to be missing the base unit! \"\\milli\\tothe\{2\}\"'):
tree = dsiTree(r'\milli\tothe{2}')
tree = p.parse(r'\milli\tothe{2}')
print(tree.toLatex())
assert tree.toLatex() == r'$${\color{red}\mathrm{m}{\color{red}\mathrm{}}^{2}}$$'
assert not tree.valid
......@@ -46,42 +48,42 @@ def test_robustness():
def test_power():
# power
powerTree = dsiTree(r'\metre\tothe{2}')
powerTree = p.parse(r'\metre\tothe{2}')
assert powerTree.tree == [[_node('','metre','2')]]
assert powerTree.toLatex() == r'$$\mathrm{m}^{2}$$'
assert powerTree.valid
assert powerTree.warnings == []
assert dsiTree(r'\metre\tothe{0.5}').toLatex() == r'$$\sqrt{\mathrm{m}}$$'
assert dsiTree(r'\metre\tothe{-2}').toLatex() == r'$$\mathrm{m}^{-2}$$'
assert dsiTree(r'\metre\tothe{1337}').toLatex() == r'$$\mathrm{m}^{1337}$$'
assert p.parse(r'\metre\tothe{0.5}').toLatex() == r'$$\sqrt{\mathrm{m}}$$'
assert p.parse(r'\metre\tothe{-2}').toLatex() == r'$$\mathrm{m}^{-2}$$'
assert p.parse(r'\metre\tothe{1337}').toLatex() == r'$$\mathrm{m}^{1337}$$'
# Non-numerical power
with pytest.warns(RuntimeWarning, match='The exponent \"foo\" is not a number!'):
assert dsiTree(r'\metre\tothe{foo}').toLatex() == r'$$\mathrm{m}^{{\color{red}\mathrm{foo}}}$$'
assert p.parse(r'\metre\tothe{foo}').toLatex() == r'$$\mathrm{m}^{{\color{red}\mathrm{foo}}}$$'
def test_prefix():
# prefix
prefixTree = dsiTree(r'\kilo\metre')
# D-SI prefix
prefixTree = p.parse(r'\kilo\metre')
assert prefixTree.tree == [[_node('kilo','metre','')]]
assert prefixTree.toLatex() == r'$$\mathrm{k}\mathrm{m}$$'
assert prefixTree.valid
def test_node():
# full node
fullNodeTree = dsiTree(r'\kilo\metre\tothe{2}')
fullNodeTree = p.parse(r'\kilo\metre\tothe{2}')
assert fullNodeTree.tree == [[_node('kilo','metre','2')]]
assert fullNodeTree.toLatex() == r'$$\mathrm{k}\mathrm{m}^{2}$$'
assert fullNodeTree.valid
def test_fraction():
fractionTree = dsiTree(r'\mega\metre\per\second\tothe{2}')
fractionTree = p.parse(r'\mega\metre\per\second\tothe{2}')
assert fractionTree.tree == [[_node('mega','metre','')],[_node('','second','2')]]
assert fractionTree.toLatex() == r'$$\frac{\mathrm{M}\mathrm{m}}{\mathrm{s}^{2}}$$'
assert fractionTree.valid
# double fraction
with pytest.warns(RuntimeWarning, match=r'The dsi string contains more than one \\per, does not match specs! Given string: \\metre\\per\\metre\\per\\metre'):
tree = dsiTree(r'\metre\per\metre\per\metre')
tree = p.parse(r'\metre\per\metre\per\metre')
assert tree.toLatex() == r'$$\mathrm{m}{\color{red}/}\mathrm{m}{\color{red}/}\mathrm{m}$$'
assert not tree.valid
assert len(tree.warnings) == 1
......@@ -89,8 +91,12 @@ def test_fraction():
def test_empty():
with pytest.warns(RuntimeWarning, match='Given D-SI string is empty!'):
assert dsiTree('').toLatex() == ''
assert p.parse('').toLatex() == ''
def test_wrappers():
assert dsiTree(r'\metre').toLatex(wrapper='') == r'\mathrm{m}'
assert dsiTree(r'\metre').toLatex(wrapper='$',prefix=r'\mathrm{Unit: }',suffix=r'\mathrm{(generated from D-SI string)}') == r'$\mathrm{Unit: }\mathrm{m}\mathrm{(generated from D-SI string)}$'
assert p.parse(r'\metre').toLatex(wrapper='') == r'\mathrm{m}'
assert p.parse(r'\metre').toLatex(wrapper='$', prefix=r'\mathrm{Unit: }', suffix=r'\mathrm{(generated from D-SI string)}') == r'$\mathrm{Unit: }\mathrm{m}\mathrm{(generated from D-SI string)}$'
parserWrapper = dsiParser(latexDefaultWrapper="&")
assert parserWrapper.parse(r'\metre').toLatex() == r'&\mathrm{m}&'
parserFull = dsiParser(latexDefaultWrapper='@', latexDefaultPrefix=r'\mathrm{Prefix}', latexDefaultSuffix=r'\mathrm{Suffix}')
assert parserFull.parse(r'\metre').toLatex() == r'@\mathrm{Prefix}\mathrm{m}\mathrm{Suffix}@'
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment