From d72917335f5166c61ca315495ffe1dce0a462d39 Mon Sep 17 00:00:00 2001 From: Johanna Riedel Date: Sun, 8 Dec 2024 00:54:59 +0100 Subject: [PATCH 01/12] feat: Renderer add interim references with default values --- renderer/fifty_ohm_html_renderer.py | 8 ++++++-- renderer/references.py | 15 +++++++++++++++ test/test_references.py | 16 ++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 renderer/references.py create mode 100644 test/test_references.py diff --git a/renderer/fifty_ohm_html_renderer.py b/renderer/fifty_ohm_html_renderer.py index fdcf7a9..a591496 100644 --- a/renderer/fifty_ohm_html_renderer.py +++ b/renderer/fifty_ohm_html_renderer.py @@ -4,11 +4,12 @@ from renderer.comment import Comment from renderer.quote import Quote from renderer.halfwidth_spaces import HalfwidthSpaces from renderer.nonbreaking_spaces import NonbreakingSpaces, NonbreakingSpacesDots +from renderer.references import References class FiftyOhmHtmlRenderer(HtmlRenderer): def __init__(self): - super().__init__(Comment, Quote, HalfwidthSpaces, NonbreakingSpaces, NonbreakingSpacesDots) + super().__init__(Comment, Quote, HalfwidthSpaces, NonbreakingSpaces, NonbreakingSpacesDots, References) def render_comment(): return None @@ -26,4 +27,7 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): return f"{token.first} {token.second}" def render_nonbreaking_spaces_dots(self, token): - return f" {token.first} " \ No newline at end of file + return f" {token.first} " + + def render_references(self, token, dest_id=0, chap_url="DeineMama.html"): + return f"{dest_id}" \ No newline at end of file diff --git a/renderer/references.py b/renderer/references.py new file mode 100644 index 0000000..e8b5f18 --- /dev/null +++ b/renderer/references.py @@ -0,0 +1,15 @@ +import re + +from mistletoe.span_token import SpanToken + + +class References(SpanToken): + """ + Resolve references for html + Identifies "[ref:$]" + """ + pattern = re.compile(r"\[ref\:(\S+)\]") + + def __init__(self, match_object): + self.first = match_object.group(1) + diff --git a/test/test_references.py b/test/test_references.py new file mode 100644 index 0000000..acd35e6 --- /dev/null +++ b/test/test_references.py @@ -0,0 +1,16 @@ +import mistletoe + +from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer +from test.util import paragraph + +def test_references_html(): + # Right now this tests only the default values. + # The correct behavior can be tested when the information is added to the renderer class + assertions = { + "[ref:e_oszilloskop_bildschirmfoto_sinus]" : "0", + "[ref:n_rst_r]" : "0", + "[ref:Uuuuuh]" : "0" # Test the default parameters + } + + for key, value in assertions.items(): + assert mistletoe.markdown(key, FiftyOhmHtmlRenderer) == paragraph(value) From 26fa657e4a92a260aa03ca73ceda4fdc6aa30f13 Mon Sep 17 00:00:00 2001 From: Tim Grelka Date: Sun, 8 Dec 2024 11:33:21 +0100 Subject: [PATCH 02/12] feat: render units with non-breaking space --- renderer/fifty_ohm_html_renderer.py | 49 ++++++++++++++++++++++++--- renderer/unit.py | 51 +++++++++++++++++++++++++++++ test/test_unit_token.py | 18 ++++++++++ 3 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 renderer/unit.py create mode 100644 test/test_unit_token.py diff --git a/renderer/fifty_ohm_html_renderer.py b/renderer/fifty_ohm_html_renderer.py index fa6a6ab..ed2f077 100644 --- a/renderer/fifty_ohm_html_renderer.py +++ b/renderer/fifty_ohm_html_renderer.py @@ -1,12 +1,45 @@ from mistletoe import HtmlRenderer -from renderer.comment import Comment -from renderer.quote import Quote +from .comment import Comment +from .unit import Unit +from .quote import Quote + + +units = { + "A": "A", + "Ah": "Ah", + "A/mm²": "A/mm²", + "baud": "baud", + "Bit": "Bit", + "Bit/s": "Bit/s", + "dB": "dB", + "dBi": "dBi", + "dBm": "dBm", + "dBW": "dBW", + "F": "F", + "J": "J", + "Hz": "Hz", + "H": "H", + "cm": "cm", + "m": "m", + "m²": "m²", + "Ohm": "Ω", + "ppm": "ppm", + "pps": "pps", + "s": "s", + "V": "V", + "W": "W", + "Wh": "Wh", + "°": "°", + "%": "%", +} + +no_space_units = ["°", "%"] class FiftyOhmHtmlRenderer(HtmlRenderer): def __init__(self): - super().__init__(Comment, Quote) + super().__init__(Comment, Unit, Quote) def render_comment(): return None @@ -15,4 +48,12 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): return f"„{self.render_inner(token)}“" def render_underline(self, token): - return f"{self.render_inner(token)}" \ No newline at end of file + return f"{self.render_inner(token)}" + + @staticmethod + def render_unit(token): + unit = token.prefix + units[token.unit] + if token.unit in no_space_units: + return f"{token.value}{unit}" + else: + return f"{token.value} {unit}" diff --git a/renderer/unit.py b/renderer/unit.py new file mode 100644 index 0000000..7364ff0 --- /dev/null +++ b/renderer/unit.py @@ -0,0 +1,51 @@ +import re + +from mistletoe.span_token import SpanToken + + +class Unit(SpanToken): + units = [ + "A", + "Ah", + "A/mm²", + "baud", + "Bit", + "Bit/s", + "dB", + "dBi", + "dBm", + "dBW", + "F", + "J", + "Hz", + "H", + "cm", + "m", + "m²", + "Ohm", + "ppm", + "pps", + "s", + "V", + "W", + "Wh", + "°", + "%", + ] + prefixes = ["p", "n", "μ", "m", "k", "M", "G"] + + pattern = re.compile( + r"([0-9,]+) ?(" + # Group all prefixes together in a capture group + # Empty string at end of list is required so the group always exists in the resulting match + + "|".join(prefixes + [""]) + + ")(" + # Group all units together in a capture group. + + "|".join(units) + + r")(?!\w)" + ) + + def __init__(self, match): + self.value = match.group(1) + self.prefix = match.group(2) + self.unit = match.group(3) diff --git a/test/test_unit_token.py b/test/test_unit_token.py new file mode 100644 index 0000000..47c929e --- /dev/null +++ b/test/test_unit_token.py @@ -0,0 +1,18 @@ +import mistletoe + +from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer + +from .util import paragraph + + +def test_unit_html(): + assertions = { + "0,1 V": "0,1 V", + "33 A": "33 A", + "1 Ah": "1 Ah", + "100 mOhm": "100 mΩ", + "25 Ohm": "25 Ω", + } + + for input, output in assertions.items(): + assert mistletoe.markdown(input, FiftyOhmHtmlRenderer) == paragraph(output) From 8bf03e5b20fcafff7386437708da65cb67570e22 Mon Sep 17 00:00:00 2001 From: Tim Grelka Date: Sun, 8 Dec 2024 11:36:02 +0100 Subject: [PATCH 03/12] refactor: create module --- renderer/__init__.py | 0 renderer/__main__.py | 8 -------- 2 files changed, 8 deletions(-) create mode 100644 renderer/__init__.py delete mode 100644 renderer/__main__.py diff --git a/renderer/__init__.py b/renderer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/renderer/__main__.py b/renderer/__main__.py deleted file mode 100644 index b8a5ddf..0000000 --- a/renderer/__main__.py +++ /dev/null @@ -1,8 +0,0 @@ -import sys - -import mistletoe -from fifty_ohm_html_renderer import FiftyOhmHtmlRenderer - -if __name__ == "__main__": - with open(sys.argv[1]) as fin, open(sys.argv[2], "w") as fout: - fout.write(mistletoe.markdown(fin, FiftyOhmHtmlRenderer)) From 0f8af3defac618dfbcd948a25ce3d23bd6fe2360 Mon Sep 17 00:00:00 2001 From: "Prof. Dr. Matthias Jung DL9MJ" Date: Sun, 8 Dec 2024 12:40:46 +0100 Subject: [PATCH 04/12] feature: add morse code --- renderer/fifty_ohm_html_renderer.py | 37 +++++++++++- renderer/morse.py | 89 +++++++++++++++++++++++++++++ test/test_morse.py | 17 ++++++ 3 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 renderer/morse.py create mode 100644 test/test_morse.py diff --git a/renderer/fifty_ohm_html_renderer.py b/renderer/fifty_ohm_html_renderer.py index 7e8b1e7..06e6149 100644 --- a/renderer/fifty_ohm_html_renderer.py +++ b/renderer/fifty_ohm_html_renderer.py @@ -5,6 +5,7 @@ from mistletoe import HtmlRenderer from renderer.comment import BlockComment, SpanComment from renderer.dash import Dash from renderer.halfwidth_spaces import HalfwidthSpaces +from renderer.morse import Morse from renderer.nonbreaking_spaces import NonbreakingSpaces, NonbreakingSpacesDots from renderer.quote import Quote from renderer.tag import Tag @@ -17,7 +18,18 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): margin_id = 0 def __init__(self): - super().__init__(Dash, BlockComment, SpanComment, Quote, Underline, Tag, HalfwidthSpaces, NonbreakingSpaces, NonbreakingSpacesDots) + super().__init__( + Dash, + BlockComment, + SpanComment, + Quote, + Underline, + Morse, + Tag, + HalfwidthSpaces, + NonbreakingSpaces, + NonbreakingSpacesDots, + ) def render_dash(self, token): return " – " @@ -38,6 +50,29 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): self.margin_anchor_id += 1 return f'' + @staticmethod + def render_morse_helper(morse_code): + result = '' + for char in morse_code: + result += '\n' + for symbol in char: + result += '\n' + if symbol == 1: + result += '▄' + elif symbol == 2: + result += '▄▄▄' + elif symbol == 3: + result += ' ' + result += '\n' + result += '\n' + result += '' + + return result + + def render_morse(self, token): + morse_code = Morse.convert_to_morse_code(token.content) + return self.render_morse_helper(morse_code) + @staticmethod def render_tag_helper(type, content, margin_id, margin_anchor_id): """ This function is used to render the different types of tags. It is diff --git a/renderer/morse.py b/renderer/morse.py new file mode 100644 index 0000000..93ffd73 --- /dev/null +++ b/renderer/morse.py @@ -0,0 +1,89 @@ +import re + +from mistletoe.span_token import SpanToken + + +class Morse(SpanToken): + """ + Morse code span token ("[morse:moe]"). + Generates morse code from a text. + """ + @staticmethod + def convert_to_morse_code(text): + dit = 1 + dah = 2 + space = 3 + + morse_code = { + "a": [dit, dah], + "b": [dah, dit, dit, dit], + "c": [dah, dit, dah, dit], + "d": [dah, dit, dit], + "e": [dit], + "f": [dit, dit, dah, dit], + "g": [dah, dah, dit], + "h": [dit, dit, dit, dit], + "i": [dit, dit], + "j": [dit, dah, dah, dah], + "k": [dah, dit, dah], + "l": [dit, dah, dit, dit], + "m": [dah, dah], + "n": [dah, dit], + "o": [dah, dah, dah], + "p": [dit, dah, dah, dit], + "q": [dah, dah, dit, dah], + "r": [dit, dah, dit], + "s": [dit, dit, dit], + "t": [dah], + "u": [dit, dit, dah], + "v": [dit, dit, dit, dah], + "w": [dit, dah, dah], + "x": [dah, dit, dit, dah], + "y": [dah, dit, dah, dah], + "z": [dah, dah, dit, dit], + "ä": [dit, dah, dit, dah], + "ö": [dah, dah, dah, dit], + "ü": [dit, dit, dah, dah], + "ß": [dit, dit, dit, dah, dah, dit, dit], + "0": [dah, dah, dah, dah, dah], + "1": [dit, dah, dah, dah, dah], + "2": [dit, dit, dah, dah, dah], + "3": [dit, dit, dit, dah, dah], + "4": [dit, dit, dit, dit, dah], + "5": [dit, dit, dit, dit, dit], + "6": [dah, dit, dit, dit, dit], + "7": [dah, dah, dit, dit, dit], + "8": [dah, dah, dah, dit, dit], + "9": [dah, dah, dah, dah, dit], + ".": [dit, dah, dit, dah, dit, dah], + ",": [dah, dah, dit, dit, dah, dah], + ":": [dah, dah, dah, dit, dit, dit], + ";": [dah, dit, dah, dit, dah, dit], + "?": [dit, dit, dah, dah, dit, dit], + "!": [dah, dit, dah, dit, dah, dah], + "-": [dah, dit, dit, dit, dit, dah], + "_": [dit, dit, dah, dah, dit, dah], + "(": [dah, dit, dah, dah, dit], + ")": [dah, dit, dah, dah, dit, dah], + "'": [dit, dah, dah, dah, dah, dit], + "=": [dah, dit, dit, dit, dah], + "+": [dit, dah, dit, dah, dit], + "/": [dah, dit, dit, dah, dit], + "@": [dit, dah, dah, dit, dah, dit], + "ar": [dit, dah, dit, dah, dit], + "bk": [dah, dit, dit, dit, dah, dit, dah], + "sk": [dit, dit, dit, dah, dit, dah], + "correction": [dit, dit, dit, dit, dit, dit, dit, dit], + " ": [space] + } + + result = [] + + for char in text: + if char.lower() in morse_code: + result.append(morse_code[char.lower()]) + + return result + + parse_inner = False + pattern = re.compile(r'"\[morse:\s*(.+)\]"') \ No newline at end of file diff --git a/test/test_morse.py b/test/test_morse.py new file mode 100644 index 0000000..d7ece1a --- /dev/null +++ b/test/test_morse.py @@ -0,0 +1,17 @@ +import mistletoe + +from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer + + +def test_morse_html() : + + assertions = { + '"[morse:a]"' : "

"+FiftyOhmHtmlRenderer.render_morse_helper([[1,2]])+"

\n", + '"[morse: a]"' : "

"+FiftyOhmHtmlRenderer.render_morse_helper([[1,2]])+"

\n", + '"[morse: aaa]"' : "

"+FiftyOhmHtmlRenderer.render_morse_helper([[1,2],[1,2],[1,2]])+"

\n", + '"[morse: a a]"' : "

"+FiftyOhmHtmlRenderer.render_morse_helper([[1,2],[3],[1,2]])+"

\n", + '"[morse: db0]"' : "

"+FiftyOhmHtmlRenderer.render_morse_helper([[2,1,1],[2,1,1,1],[2,2,2,2,2]])+"

\n", + } + + for assertion in assertions: + assert mistletoe.markdown(assertion, FiftyOhmHtmlRenderer) == assertions[assertion] \ No newline at end of file From 608be5bd09d20f33118c513be9d8fac9e29f06e8 Mon Sep 17 00:00:00 2001 From: Johanna Riedel Date: Sun, 8 Dec 2024 13:20:14 +0100 Subject: [PATCH 05/12] fix: deleted render_references restored --- renderer/fifty_ohm_html_renderer.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/renderer/fifty_ohm_html_renderer.py b/renderer/fifty_ohm_html_renderer.py index 19b6049..804121b 100644 --- a/renderer/fifty_ohm_html_renderer.py +++ b/renderer/fifty_ohm_html_renderer.py @@ -16,6 +16,8 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): margin_anchor_id = 0 margin_id = 0 + section_url = "DeineMama.html" + ref_id = 0 def __init__(self): super().__init__(Dash, BlockComment, SpanComment, Quote, Underline, Tag, HalfwidthSpaces, NonbreakingSpaces, NonbreakingSpacesDots, HalfwidthSpaces, NonbreakingSpaces, NonbreakingSpacesDots, References) @@ -101,4 +103,9 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): "" : "", " " : " " } - return f"{lookup[token.first]}{token.second}{lookup[token.third]}" \ No newline at end of file + return f"{lookup[token.first]}{token.second}{lookup[token.third]}" + + def render_references(self, token): + return f"{self.ref_id}" + + From b469dab4b40653e42247f7889b0f9eb6947d6113 Mon Sep 17 00:00:00 2001 From: "Prof. Dr. Matthias Jung DL9MJ" Date: Sun, 8 Dec 2024 13:31:59 +0100 Subject: [PATCH 06/12] feature: add acceptance test --- .gitignore | 4 ++++ test/acceptanceTest.md | 2 ++ test/test_html.py | 14 ++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 test/test_html.py diff --git a/.gitignore b/.gitignore index 82f9275..134cd7a 100644 --- a/.gitignore +++ b/.gitignore @@ -160,3 +160,7 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +test/acceptanceTest.html +.DS_Store +.envrc diff --git a/test/acceptanceTest.md b/test/acceptanceTest.md index 715c69a..5148735 100644 --- a/test/acceptanceTest.md +++ b/test/acceptanceTest.md @@ -94,6 +94,8 @@ CQ CQ hier ist DL1PZ mit einem allgemeinen Anruf, hier ist DL1PZ und hört. [table:n_morsetelegrafie_morsecode_buchstaben:Morsecode (Buchstaben)] +Das ist ein A in Morsecode: [morse:a], das finde ich ganz toll! + ... diff --git a/test/test_html.py b/test/test_html.py new file mode 100644 index 0000000..8c2dc42 --- /dev/null +++ b/test/test_html.py @@ -0,0 +1,14 @@ + +import mistletoe + +from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer + + +def test_html(capsys) : + + with capsys.disabled(): + with open("test/acceptanceTest.md") as file: + content = file.read() + output = mistletoe.markdown(content, FiftyOhmHtmlRenderer) + with open("test/acceptanceTest.html", "w") as output_file: + output_file.write(output) \ No newline at end of file From d8670daf637ffdc161b4799845505ce50b1ea5af Mon Sep 17 00:00:00 2001 From: "Prof. Dr. Matthias Jung DL9MJ" Date: Sun, 8 Dec 2024 13:56:24 +0100 Subject: [PATCH 07/12] bugfix: tipp vs. tipp --- renderer/fifty_ohm_html_renderer.py | 4 ++-- renderer/tag.py | 4 ++-- test/test_tag.py | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/renderer/fifty_ohm_html_renderer.py b/renderer/fifty_ohm_html_renderer.py index 7e8b1e7..de7bbe2 100644 --- a/renderer/fifty_ohm_html_renderer.py +++ b/renderer/fifty_ohm_html_renderer.py @@ -74,8 +74,8 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): if(token.tagtype == "webmargin"): type = "margin" - elif(token.tagtype == "webtipp"): - type = "tipp" + elif(token.tagtype == "webtip"): + type = "tip" elif(token.tagtype == "webindepth"): type = "indepth" else : diff --git a/renderer/tag.py b/renderer/tag.py index 6bdc187..82dd528 100644 --- a/renderer/tag.py +++ b/renderer/tag.py @@ -6,8 +6,8 @@ captures = [ "margin", "indepth", "webmargin", - "tipp", - "webtipp", + "tip", + "webtip", "webindepth", "unit", "danger", diff --git a/test/test_tag.py b/test/test_tag.py index 967e8f3..e8c282f 100644 --- a/test/test_tag.py +++ b/test/test_tag.py @@ -2,6 +2,7 @@ import mistletoe from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer + def test_thematic_break_html() : assertions = { "---" : '\n', @@ -17,8 +18,8 @@ def test_tag_html() : "\nFoo\n" : FiftyOhmHtmlRenderer.render_tag_helper("margin","

Foo

",1,0)+'\n', "\nFoo\n" : FiftyOhmHtmlRenderer.render_tag_helper("indepth","

Foo

",1,0)+'\n', "\nFoo\n" : FiftyOhmHtmlRenderer.render_tag_helper("margin","

Foo

",1,0)+'\n', - "\nFoo\n" : FiftyOhmHtmlRenderer.render_tag_helper("tipp","

Foo

",1,0)+'\n', - "\nFoo\n" : FiftyOhmHtmlRenderer.render_tag_helper("tipp","

Foo

",1,0)+'\n', + "\nFoo\n" : FiftyOhmHtmlRenderer.render_tag_helper("tip","

Foo

",1,0)+'\n', + "\nFoo\n" : FiftyOhmHtmlRenderer.render_tag_helper("tip","

Foo

",1,0)+'\n', "\nFoo\n" : FiftyOhmHtmlRenderer.render_tag_helper("indepth","

Foo

",1,0)+'\n', "\nFoo\n" : FiftyOhmHtmlRenderer.render_tag_helper("unit","

Foo

",1,0)+'\n', "\nFoo\n" : FiftyOhmHtmlRenderer.render_tag_helper("danger","

Foo

",1,0)+'\n', From 1334e9c9060f9c17e6cbe0e1fe5ff5d9bd7b84fa Mon Sep 17 00:00:00 2001 From: Tim Grelka Date: Sun, 8 Dec 2024 14:30:04 +0100 Subject: [PATCH 08/12] fix: use quotes for html attributes --- renderer/fifty_ohm_html_renderer.py | 56 +++++++++++++++-------------- test/test_references.py | 9 ++--- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/renderer/fifty_ohm_html_renderer.py b/renderer/fifty_ohm_html_renderer.py index 804121b..be23907 100644 --- a/renderer/fifty_ohm_html_renderer.py +++ b/renderer/fifty_ohm_html_renderer.py @@ -13,14 +13,27 @@ from renderer.underline import Underline class FiftyOhmHtmlRenderer(HtmlRenderer): - margin_anchor_id = 0 margin_id = 0 - section_url = "DeineMama.html" + section_url = "section.html" ref_id = 0 def __init__(self): - super().__init__(Dash, BlockComment, SpanComment, Quote, Underline, Tag, HalfwidthSpaces, NonbreakingSpaces, NonbreakingSpacesDots, HalfwidthSpaces, NonbreakingSpaces, NonbreakingSpacesDots, References) + super().__init__( + Dash, + BlockComment, + SpanComment, + Quote, + Underline, + Tag, + HalfwidthSpaces, + NonbreakingSpaces, + NonbreakingSpacesDots, + HalfwidthSpaces, + NonbreakingSpaces, + NonbreakingSpacesDots, + References, + ) def render_dash(self, token): return " – " @@ -43,9 +56,9 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): @staticmethod def render_tag_helper(type, content, margin_id, margin_anchor_id): - """ This function is used to render the different types of tags. It is - used in the HtmlRenderer class and also in the test class """ - return textwrap.dedent(f'''\ + """This function is used to render the different types of tags. It is + used in the HtmlRenderer class and also in the test class""" + return textwrap.dedent(f"""\
{content}
@@ -65,33 +78,29 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): moveFunc(); }})(); - ''') + """) def render_tag(self, token): - if(token.tagtype == "latexonly"): + if token.tagtype == "latexonly": return "" - elif(token.tagtype == "webonly"): + elif token.tagtype == "webonly": return self.render_inner(token) self.margin_id += 1 - if(token.tagtype == "webmargin"): + if token.tagtype == "webmargin": type = "margin" - elif(token.tagtype == "webtipp"): + elif token.tagtype == "webtipp": type = "tipp" - elif(token.tagtype == "webindepth"): + elif token.tagtype == "webindepth": type = "indepth" - else : + else: type = token.tagtype return self.render_tag_helper( - type, - self.render_inner(token), - self.margin_id, - self.margin_anchor_id + type, self.render_inner(token), self.margin_id, self.margin_anchor_id ) - - + def render_halfwidth_spaces(self, token): return f"{token.first}. {token.second}." @@ -99,13 +108,8 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): return f"{token.first} {token.second}" def render_nonbreaking_spaces_dots(self, token): - lookup = { - "" : "", - " " : " " - } + lookup = {"": "", " ": " "} return f"{lookup[token.first]}{token.second}{lookup[token.third]}" def render_references(self, token): - return f"{self.ref_id}" - - + return f'{self.ref_id}' diff --git a/test/test_references.py b/test/test_references.py index acd35e6..80dff9d 100644 --- a/test/test_references.py +++ b/test/test_references.py @@ -3,13 +3,14 @@ import mistletoe from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer from test.util import paragraph + def test_references_html(): - # Right now this tests only the default values. + # Right now this tests only the default values. # The correct behavior can be tested when the information is added to the renderer class assertions = { - "[ref:e_oszilloskop_bildschirmfoto_sinus]" : "0", - "[ref:n_rst_r]" : "0", - "[ref:Uuuuuh]" : "0" # Test the default parameters + "[ref:e_oszilloskop_bildschirmfoto_sinus]": '0', + "[ref:n_rst_r]": '0', + "[ref:Uuuuuh]": '0', # Test the default parameters } for key, value in assertions.items(): From d3542de894f02e61c93056898033aa8354a778cf Mon Sep 17 00:00:00 2001 From: Johanna Riedel Date: Sun, 8 Dec 2024 14:40:56 +0100 Subject: [PATCH 09/12] fix: Space support for halfwidthspaces --- renderer/halfwidth_spaces.py | 2 +- renderer/nonbreaking_spaces.py | 2 +- test/test_halfwidth_spaces.py | 13 +++++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/renderer/halfwidth_spaces.py b/renderer/halfwidth_spaces.py index f9daf9b..dfdd374 100644 --- a/renderer/halfwidth_spaces.py +++ b/renderer/halfwidth_spaces.py @@ -8,7 +8,7 @@ class HalfwidthSpaces(SpanToken): Insert halfwidth space into span token (Z. B.) Identifies "z.B.", "d.h." and "D.h." with and without space in between. """ - pattern = re.compile(r"\b(z|d|D)\.(B|h)\.") + pattern = re.compile(r"\b(z|Z|d|D)\.\s?(B|h)\.") def __init__(self, match_object): self.first = match_object.group(1) diff --git a/renderer/nonbreaking_spaces.py b/renderer/nonbreaking_spaces.py index 932653f..08ac99d 100644 --- a/renderer/nonbreaking_spaces.py +++ b/renderer/nonbreaking_spaces.py @@ -6,7 +6,7 @@ from mistletoe.span_token import SpanToken class NonbreakingSpaces(SpanToken): """ Insert unbreakable space into span token (§ 3) - Identifies "§$number", "Abs.$number", "Klasse [A,E,N]" w/ and w\ space between. + Identifies "§$number", "Abs.$number", "Klasse [A,E,N]" w/ and without space between. """ pattern = re.compile(r"(§|Abs\.|Klasse)\s?(\d|[NEA])") diff --git a/test/test_halfwidth_spaces.py b/test/test_halfwidth_spaces.py index 0438674..1d3c4f9 100644 --- a/test/test_halfwidth_spaces.py +++ b/test/test_halfwidth_spaces.py @@ -3,8 +3,13 @@ import mistletoe from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer from test.util import paragraph -def test_halfwidth_space_html(): - input = "Dies ist z.B. ein Test. D.h. hier sollten d.h. Spaces ersetzt worden sein." - target = "Dies ist z. B. ein Test. D. h. hier sollten d. h. Spaces ersetzt worden sein." - assert mistletoe.markdown(input, FiftyOhmHtmlRenderer) == paragraph(target) +def test_halfwidth_space_html(): + assertions = { + "Dies ist z.B. ein Test. D.h. hier sollten d.h. Spaces ersetzt worden sein." : "Dies ist z. B. ein Test. D. h. hier sollten d. h. Spaces ersetzt worden sein.", + "Dies ist z. B. ein Test. D. h. hier sollten d. h. Spaces ersetzt worden sein." : "Dies ist z. B. ein Test. D. h. hier sollten d. h. Spaces ersetzt worden sein.", + "Z. B. die D.B. wird auch ersetzt, aber das macht nix." : "Z. B. die D. B. wird auch ersetzt, aber das macht nix." + } + + for key, value in assertions.items(): + assert mistletoe.markdown(key, FiftyOhmHtmlRenderer) == paragraph(value) From a1626d730f62dffe2efbce0d9a3db388011f7330 Mon Sep 17 00:00:00 2001 From: Tim Grelka Date: Sun, 8 Dec 2024 16:01:30 +0100 Subject: [PATCH 10/12] refactor: use helper to format unit --- renderer/fifty_ohm_html_renderer.py | 49 +++++++++-------------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/renderer/fifty_ohm_html_renderer.py b/renderer/fifty_ohm_html_renderer.py index bec6559..db41c4b 100644 --- a/renderer/fifty_ohm_html_renderer.py +++ b/renderer/fifty_ohm_html_renderer.py @@ -12,36 +12,6 @@ from renderer.tag import Tag from renderer.underline import Underline from renderer.unit import Unit -units = { - "A": "A", - "Ah": "Ah", - "A/mm²": "A/mm²", - "baud": "baud", - "Bit": "Bit", - "Bit/s": "Bit/s", - "dB": "dB", - "dBi": "dBi", - "dBm": "dBm", - "dBW": "dBW", - "F": "F", - "J": "J", - "Hz": "Hz", - "H": "H", - "cm": "cm", - "m": "m", - "m²": "m²", - "ppm": "ppm", - "pps": "pps", - "s": "s", - "V": "V", - "W": "W", - "Wh": "Wh", - "°": "°", - "%": "%", -} - -no_space_units = ["°", "%"] - class FiftyOhmHtmlRenderer(HtmlRenderer): margin_anchor_id = 0 @@ -82,14 +52,25 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): def render_underline(self, token): return f"{self.render_inner(token)}" - @staticmethod - def render_unit(token): - unit = token.prefix + units[token.unit] - if token.unit in no_space_units: + @classmethod + def render_unit(cls, token): + unit = token.prefix + cls.format_unit(token.unit) + if token.unit in ["°", "%"]: return f"{token.value}{unit}" else: return f"{token.value} {unit}" + units = { + "Ohm": "Ω", + } + + @classmethod + def format_unit(cls, unit): + if unit in cls.units.keys(): + return cls.units[unit] + else: + return unit + def render_thematic_break(self, token): self.margin_anchor_id += 1 return f'' From 25a1e6bbac57aa1d478d887d0d1f6faad2ad60fb Mon Sep 17 00:00:00 2001 From: Tim Grelka Date: Tue, 10 Dec 2024 11:02:19 +0100 Subject: [PATCH 11/12] feat: improve tests for unit rendering --- test/test_unit.py | 45 +++++++++++++++++++++++++++++++++++++++++ test/test_unit_token.py | 18 ----------------- test/util.py | 4 ++-- 3 files changed, 47 insertions(+), 20 deletions(-) create mode 100644 test/test_unit.py delete mode 100644 test/test_unit_token.py diff --git a/test/test_unit.py b/test/test_unit.py new file mode 100644 index 0000000..eb736cd --- /dev/null +++ b/test/test_unit.py @@ -0,0 +1,45 @@ +import mistletoe +import pytest + +from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer + +from .util import paragraph + + +@pytest.mark.html +def test_basic_units_html(): + """Test basic units: Insert non-breaking, smaller space.""" + assertions = { + "1 V": "1 V", + "0,12 V": "0,12 V", + "0,75 kW": "0,75 kW", + "33 A": "33 A", + "1 Ah": "1 Ah", # Ah can be a tricky case if the RegEx is wrong, as A might match before Ah, thus rendering the output with an "A" unit + } + + for input, output in assertions.items(): + assert mistletoe.markdown(input, FiftyOhmHtmlRenderer) == paragraph(output) + + +@pytest.mark.html +def test_translated_units_html(): + """Test translated units: Replace Ohm with Ω.""" + assertions = { + "50 Ohm": "50 Ω", + "100 mOhm": "100 mΩ", + } + + for input, output in assertions.items(): + assert mistletoe.markdown(input, FiftyOhmHtmlRenderer) == paragraph(output) + + +@pytest.mark.html +def test_special_units_html(): + """Test special units: Don't put space before ° and %.""" + assertions = { + "100%": "100%", + "42,24°": "42,24°", + } + + for input, output in assertions.items(): + assert mistletoe.markdown(input, FiftyOhmHtmlRenderer) == paragraph(output) diff --git a/test/test_unit_token.py b/test/test_unit_token.py deleted file mode 100644 index 47c929e..0000000 --- a/test/test_unit_token.py +++ /dev/null @@ -1,18 +0,0 @@ -import mistletoe - -from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer - -from .util import paragraph - - -def test_unit_html(): - assertions = { - "0,1 V": "0,1 V", - "33 A": "33 A", - "1 Ah": "1 Ah", - "100 mOhm": "100 mΩ", - "25 Ohm": "25 Ω", - } - - for input, output in assertions.items(): - assert mistletoe.markdown(input, FiftyOhmHtmlRenderer) == paragraph(output) diff --git a/test/util.py b/test/util.py index f30aa79..a86b9eb 100644 --- a/test/util.py +++ b/test/util.py @@ -1,2 +1,2 @@ -def paragraph(text) : - return f'

{text}

\n' \ No newline at end of file +def paragraph(text): + return f"

{text}

\n" From 4c82c9fb146332bd3abe8e2d1d0308aafbdc54d4 Mon Sep 17 00:00:00 2001 From: Tim Grelka Date: Wed, 11 Dec 2024 00:42:24 +0100 Subject: [PATCH 12/12] refactor: improve code readability --- renderer/fifty_ohm_html_renderer.py | 12 +++++++++--- renderer/unit.py | 16 ++++++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/renderer/fifty_ohm_html_renderer.py b/renderer/fifty_ohm_html_renderer.py index db41c4b..b568b0c 100644 --- a/renderer/fifty_ohm_html_renderer.py +++ b/renderer/fifty_ohm_html_renderer.py @@ -53,11 +53,13 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): return f"{self.render_inner(token)}" @classmethod - def render_unit(cls, token): - unit = token.prefix + cls.format_unit(token.unit) + def render_unit(cls, token: Unit): + unit = token.prefix + cls.convert_unit_helper(token.unit) if token.unit in ["°", "%"]: + # Special cases with no space between value and unit. return f"{token.value}{unit}" else: + # Default case is rendered with a narrow no-break space. return f"{token.value} {unit}" units = { @@ -65,7 +67,11 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): } @classmethod - def format_unit(cls, unit): + def convert_unit_helper(cls, unit: str) -> str: + """Converts human-typable units to their preferred representation. + + :param str unit: The unit to convert + """ if unit in cls.units.keys(): return cls.units[unit] else: diff --git a/renderer/unit.py b/renderer/unit.py index 7364ff0..4a6b9f0 100644 --- a/renderer/unit.py +++ b/renderer/unit.py @@ -35,17 +35,21 @@ class Unit(SpanToken): prefixes = ["p", "n", "μ", "m", "k", "M", "G"] pattern = re.compile( - r"([0-9,]+) ?(" + r"(?P[0-9,]+) ?(?P" # Group all prefixes together in a capture group # Empty string at end of list is required so the group always exists in the resulting match + "|".join(prefixes + [""]) - + ")(" + + ")(?P" # Group all units together in a capture group. + "|".join(units) + r")(?!\w)" ) - def __init__(self, match): - self.value = match.group(1) - self.prefix = match.group(2) - self.unit = match.group(3) + value: str + prefix: str + unit: str + + def __init__(self, match: re.Match): + self.value = match.group("value") + self.prefix = match.group("prefix") or "" + self.unit = match.group("unit")