Merge branch 'main' into fix/morse-spacing

This commit is contained in:
Tim Grelka
2025-11-12 13:28:44 +01:00
committed by GitHub
9 changed files with 172 additions and 155 deletions
+1
View File
@@ -6,6 +6,7 @@
"python.testing.unittestEnabled": false, "python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true, "python.testing.pytestEnabled": true,
"[python]": { "[python]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll.ruff": "explicit", "source.fixAll.ruff": "explicit",
"source.organizeImports.ruff": "explicit" "source.organizeImports.ruff": "explicit"
+6 -19
View File
@@ -2,11 +2,6 @@
margin-bottom: 2ex; margin-bottom: 2ex;
} }
.table_inner {
padding: 1ex;
background: #ddd;
}
.table tr { .table tr {
border-bottom: 1px solid #aaa; border-bottom: 1px solid #aaa;
} }
@@ -175,16 +170,8 @@ td {
text-align: justify; text-align: justify;
} }
ul.list { ul li::marker {
list-style: none; /* Remove default bullets */
}
ul.list li::before {
content: "▪";
color: #2aa6da; color: #2aa6da;
display: inline-block;
width: 1em;
margin-left: -1em;
} }
ol li { ol li {
@@ -252,10 +239,10 @@ span.formula {
@media (min-width: 800px) { @media (min-width: 800px) {
.course p, .course p,
.course ul,
.course ol,
.course .question, .course .question,
.course .table, .course .table {
.course ul.list,
.course ol.list {
width: 59.3%; width: 59.3%;
} }
@@ -272,8 +259,8 @@ span.formula {
} }
.course .margin p, .course .margin p,
.course .margin ul.list, .course .margin ul,
.course .margin ol.list { .course .margin ol {
width: auto; width: auto;
} }
+1 -1
View File
@@ -14,8 +14,8 @@ dl.download_edition("N")
# Download additional files: # Download additional files:
dl.download_question_metadata() dl.download_question_metadata()
dl.download_pictures()
dl.download_photos() dl.download_photos()
dl.download_pictures()
dl.download_includes() dl.download_includes()
dl.download_snippets() dl.download_snippets()
dl.download_content() dl.download_content()
+30 -19
View File
@@ -13,7 +13,7 @@ from .qso import Qso
from .question import Question from .question import Question
from .quote import Quote from .quote import Quote
from .references import References from .references import References
from .table import Table from .table import Table, TableBody, TableCell, TableHeader, TableRow
from .tag import Tag from .tag import Tag
from .underline import Underline from .underline import Underline
from .unit import Unit from .unit import Unit
@@ -46,6 +46,10 @@ class FiftyOhmHtmlRenderer(HtmlRenderer):
Picture, Picture,
Photo, Photo,
Table, Table,
TableHeader,
TableRow,
TableCell,
TableBody,
Qso, Qso,
Include, Include,
*extras, *extras,
@@ -104,7 +108,7 @@ class FiftyOhmHtmlRenderer(HtmlRenderer):
for char in morse_code: for char in morse_code:
result += '<span class="morse_char">\n' result += '<span class="morse_char">\n'
for symbol in char: for symbol in char:
result += '<span class="morse_char">\n' result += '<span class="morse_symbol">\n'
if symbol == 1: if symbol == 1:
result += "▄" result += "▄"
elif symbol == 2: elif symbol == 2:
@@ -217,28 +221,35 @@ class FiftyOhmHtmlRenderer(HtmlRenderer):
self.photo_handler(token.id) self.photo_handler(token.id)
return self.render_photo_helper(token.id, token.ref, token.text, token.number) return self.render_photo_helper(token.id, token.ref, token.text, token.number)
@staticmethod def render_table(self, token: Table):
def render_cell_helper(cell, alignment, type): table = f'<table class="table table-hover">\n{self.render_inner(token)}'
style = ""
if alignment in table_alignment:
style = f' style="text-align: {table_alignment[alignment]};"'
return f"<{type}{style}>{cell}</{type}>\n"
def render_table(self, token):
alignment = token.alignment
table = "<table>\n"
for i, row in enumerate(token.children):
content = ""
for j, cell in enumerate(row.children):
content += self.render_cell_helper(self.render_inner(cell), alignment[j], ("th" if i == 0 else "td"))
table += f"<tr>\n{content}</tr>\n"
if token.caption != "": if token.caption != "":
table += f"<caption>{token.caption}</caption>" table += f"<caption>{token.caption}</caption>\n"
table += "</table>" table += "</table>"
return table return table
def render_table_row(self, token: TableRow):
return f"<tr>\n{self.render_inner(token)}</tr>\n"
def render_table_header(self, token: TableHeader):
return self.render_table_row(token)
def render_table_cell(self, token: TableCell):
type = "th" if token.header else "td"
style = ""
if token.alignment in table_alignment:
style = f' style="text-align: {table_alignment[token.alignment]};"'
return f"<{type}{style}>{self.render_inner(token)}</{type}>\n"
def render_table_body(self, token: TableBody):
if token.children is None or len(token.children) == 0:
return None
else:
type = "thead" if token.header else "tbody"
return f"<{type}>\n{self.render_inner(token)}</{type}>\n"
def render_include(self, token): def render_include(self, token):
return self.include_handler(token.ident) return self.include_handler(token.ident)
+26 -16
View File
@@ -8,7 +8,7 @@ from .photo import Photo
from .picture import Picture from .picture import Picture
from .question import Question from .question import Question
from .quote import Quote from .quote import Quote
from .table import Table from .table import Table, TableBody, TableCell, TableHeader, TableRow
from .tag import Tag from .tag import Tag
from .underline import Underline from .underline import Underline
@@ -28,9 +28,17 @@ class FiftyOhmLaTeXRenderer(LaTeXRenderer):
Picture, Picture,
Photo, Photo,
Table, Table,
TableBody,
TableRow,
TableHeader,
TableCell,
) )
self.question_renderer = question_renderer self.question_renderer = question_renderer
def render_inner(self, token, base="") -> str:
# Filter out None values, so block tokens can return None to not be rendered.
return base.join(filter(lambda x: x is not None, [self.render(child) for child in token.children]))
def render_document(self, token): def render_document(self, token):
self.footnotes.update(token.footnotes) self.footnotes.update(token.footnotes)
return self.render_inner(token) return self.render_inner(token)
@@ -118,23 +126,25 @@ class FiftyOhmLaTeXRenderer(LaTeXRenderer):
return self.render_photo_helper(token.id, token.ref, token.text, token.number) return self.render_photo_helper(token.id, token.ref, token.text, token.number)
def render_table(self, token): def render_table(self, token):
alignments = token.alignment table = "\\begin{DARCtabular}" + f"{self.render_inner(token)}" + "\\end{DARCtabular}"
align = ""
for alignment in alignments:
align += alignment
table = f"\\begin{{DARCtabular}}{{{align}}}\n"
for row in token.children:
for j, cell in enumerate(row.children):
table += self.render_inner(cell)
if j < len(row.children) - 1:
table += " & "
table += r"\\" + "\n"
table += "\\end{DARCtabular}"
if token.caption != "": if token.caption != "":
table += f"\\captionof{{figure}}{{{token.caption}}}\n" table += f"\\captionof{{figure}}{{{token.caption}}}\n"
table += f"\\label{{{token.name}}}\n" table += f"\\label{{{token.name}}}\n"
return table return table
def render_table_body(self, token: TableBody):
return self.render_inner(token)
def render_table_row(self, token: TableRow):
return rf"{self.render_inner(token, ' & ')}\\" + "\n"
def render_table_header(self, token: TableHeader):
align = ""
for alignment in token.alignment:
align += alignment
return f"{{{align}}}\n{self.render_table_row(token)}"
def render_table_cell(self, token: TableCell):
return self.render_inner(token)
+84 -44
View File
@@ -1,37 +1,99 @@
import re import re
from enum import Enum
from mistletoe import span_token from mistletoe import span_token
from mistletoe.block_token import BlockToken from mistletoe.block_token import BlockToken
class CellAlignment(Enum):
LEFT = "l"
CENTER = "c"
RIGHT = "r"
EXPAND = "X"
class TableCell(BlockToken):
alignment: CellAlignment
header: bool
@staticmethod
def start(_):
return False
def __init__(self, match, alignment: CellAlignment, header=False):
super().__init__(match, span_token.tokenize_inner)
self.alignment, self.header = alignment, header
class TableRow(BlockToken):
@staticmethod
def start(_):
return False
@classmethod
def parse(cls, line) -> list[str]:
line = line.strip().strip("|")
return [col.strip() for col in line.split("|")]
def __init__(self, match, alignment: list[CellAlignment]):
self.children = [TableCell(cell, alignment[i]) for i, cell in enumerate(self.parse(match))]
class TableHeader(TableRow):
alignment: list[CellAlignment]
@staticmethod
def start(_):
return False
@classmethod
def parse(cls, line) -> list[str]:
alignment: list[CellAlignment] = []
columns: list[str] = []
for column in super().parse(line):
attr: CellAlignment
value: str
attr, value = re.match(r"^ ?(?:([lcrX]):)? ?(.*)", column).group(1, 2)
alignment.append(attr)
columns.append(value)
return columns, alignment
def __init__(self, match):
columns, self.alignment = self.parse(match)
self.children = [TableCell(cell, self.alignment[i], True) for i, cell in enumerate(columns)]
class TableBody(BlockToken):
header: bool
@staticmethod
def start(_):
return False
def __init__(self, rows: TableRow, header=False):
self.children, self.header = rows, header
class Table(BlockToken): class Table(BlockToken):
name: str
caption: str
header: list[TableHeader]
rows: list[TableRow]
@staticmethod @staticmethod
def start(line): def start(line):
return "|" in line return "|" in line
@classmethod
def parse_header(cls, line):
# Parse header, extract alignment and make an ordinary row out of it
line = line.strip().strip("|") # Remove leading/trailing whitespace and pipes
columns = [col.strip() for col in line.split("|")] # Split by pipe |
alignment = []
header = "| "
for column in columns:
attr, val = re.match(r"^ ?(?:([lcrX]):)?(.*)", column).group(1, 2)
alignment.append(attr)
header += val + " | "
return header, alignment
@classmethod @classmethod
def read(cls, lines): def read(cls, lines):
header = next(lines) header = TableHeader(next(lines))
header, alignment = cls.parse_header(header) alignment = header.alignment
name = "" name = ""
caption = "" caption = ""
rows = [TableRow(header)] children = [TableBody([header], True)]
# Read table until the end: No more column definitions, caption, or empty line. # Read table until the end: No more column definitions, caption, or empty line.
line_buffer = [] line_buffer = []
@@ -48,31 +110,9 @@ class Table(BlockToken):
line_buffer.append(next(lines)) line_buffer.append(next(lines))
next_line = lines.peek() next_line = lines.peek()
rows.extend([TableRow(line) for line in line_buffer]) children.append(TableBody([TableRow(line, alignment) for line in line_buffer]))
return alignment, rows, name, caption return children, name, caption
def __init__(self, match): def __init__(self, match):
self.alignment, self.children, self.name, self.caption = match self.children, self.name, self.caption = match
class TableRow(BlockToken):
@classmethod
def parse_row(cls, line):
line = line.strip().strip("|")
columns = [col.strip() for col in line.split("|")]
data = []
for column in columns:
data.append(TableCell(column))
return data
def __init__(self, match):
self.children = self.parse_row(match)
class TableCell(BlockToken):
def __init__(self, match):
super().__init__(match, span_token.tokenize_inner)
+9 -40
View File
@@ -1,9 +1,5 @@
import json import json
import multiprocessing
import os
import shutil
from joblib import Memory, Parallel, delayed
from tqdm import tqdm from tqdm import tqdm
from api.directus import DirectusAPI from api.directus import DirectusAPI
@@ -102,45 +98,18 @@ class Download:
def download_pictures(self): def download_pictures(self):
self.config.p_data_pictures.mkdir(parents=True, exist_ok=True) self.config.p_data_pictures.mkdir(parents=True, exist_ok=True)
# Symlink photos, so LaTeX can access these assets to render into graphics.
foto_link = self.config.p_data_pictures / "foto"
if not foto_link.is_symlink():
foto_link.symlink_to(self.config.p_data_photos)
memory = Memory("./cache", verbose=0) pictures = self.api.get("items/pictures", {"limit": -1})
@memory.cache for picture in tqdm(pictures, desc="Downloading pictures"):
def build_picture(picture): # Save LaTeX sources to file
pid = picture["id"] with (self.config.p_data_pictures / f"{picture['id']}include.tex").open("w") as file:
file.write(picture["latex"])
if ( # Download SVG
"\\begin{document}" in picture["latex"] or "\\begin{table}" in picture["latex"] data = self.api.get_file(f"assets/{picture['picture']}")
): # Workaround, if the picture contains a document class it should be ignored! with (self.config.p_data_pictures / f"{picture['id']}.svg").open("wb") as file:
return file.write(data)
if self.config.no_latex:
shutil.copyfile("./assets/images/50ohm_gray.svg", self.config.p_data_pictures / f"{pid}.svg")
else:
with (self.config.p_data_pictures / f"img/{pid}include.tex").open("w") as file:
file.write(picture["latex"])
aux_file = self.config.p_data_photos / f"{pid}.tex"
with aux_file.open("w", encoding="utf-8") as file:
# Write the auxilary LaTeX file:
file.write(f"\\documentclass{{BNetzA-Fragenkatalog}}\\DARCimageOnly{{9cm}}{{{pid}include}}")
# Build the picture:
os.system(f"latexmk -lualatex -f -interaction=nonstopmode {aux_file} > /dev/null 2>&1")
# Convert the PDF to SVG:
os.system(
"pdftocairo -svg"
f"{self.config.p_data_pictures / f'{pid}.pdf'} - > {self.config.p_data_pictures / f'{pid}.svg'}"
)
pictures = self.api.get("items/pictures", params={"limit": -1})
Parallel(n_jobs=multiprocessing.cpu_count())(
delayed(build_picture)(picture) for picture in tqdm(pictures, desc="Build All Pictures")
)
def download_includes(self): def download_includes(self):
includes = self.api.get("items/include", params={"limit": -1}) includes = self.api.get("items/include", params={"limit": -1})
+4 -5
View File
@@ -100,11 +100,9 @@
</div> </div>
<br> <br>
<h5>DARC Chat</h5> <h5>DARC Chat</h5>
<p>Der DARC e. V. betreibt eine eigene Matrix-Instanz. Dort gibt es Räume, in denen du deine Fragen stellen kannst (🌍 öffentlich, d. h. auch von anderen Matrix-Servern erreichbar, und 🔐 nur für Mitglieder):</p> <p>Der DARC e. V. betreibt eine eigene Matrix-Instanz. Dort gibt es einen Raum, in denen du deine Fragen stellen kannst:</p>
<div class="row row-cols-lg-3"> <div class="row row-cols-lg-3">
<div class="col"><a href="https://matrix.to/#/#ausbildung:darc.de" class="btn btn-outline-dark w-100">🌍 Ausbildung</a></div> <div class="col"><a href="https://matrix.to/#/#ausbildung:darc.de" class="btn btn-outline-dark w-100">💬 Ausbildung</a></div>
<div class="col"><a href="https://matrix.to/#/#Fragen_Technik:darc.de" class="btn btn-outline-dark w-100">🔐 Fragen T</a></div>
<div class="col"><a href="https://matrix.to/#/#Fragen_BV:darc.de" class="btn btn-outline-dark w-100">🔐 Fragen B+V</a></div>
</div> </div>
<br> <br>
<h5>Mitglied werden</h5> <h5>Mitglied werden</h5>
@@ -135,13 +133,14 @@
<p>Die Lernhinhalte für die Klasse N gibt es auch als gedrucktes Buch. Es ist passend zum Online-Kurs ausgelegt.</p> <p>Die Lernhinhalte für die Klasse N gibt es auch als gedrucktes Buch. Es ist passend zum Online-Kurs ausgelegt.</p>
<div class="d-grid gap-2 d-md-block mb-5"> <div class="d-grid gap-2 d-md-block mb-5">
<a href="https://darcverlag.de/DARC-Amateurfunklehrgang-Klasse-N" class="btn btn-primary">Beim DARC-Verlag kaufen</a> <a href="https://darcverlag.de/DARC-Amateurfunklehrgang-Klasse-N" class="btn btn-primary">Beim DARC-Verlag kaufen</a>
<a href="https://www.amazon.de/dp/388692100X" class="btn btn-primary">Amazon</a>
</div> </div>
</div> </div>
<div class="feature col"> <div class="feature col">
<div class="feature-icon bg-primary bg-gradient"> <div class="feature-icon bg-primary bg-gradient">
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 0 640 512" width="48"><path d="M337.8 5.4C327-1.8 313-1.8 302.2 5.4L166.3 96 48 96C21.5 96 0 117.5 0 144L0 464c0 26.5 21.5 48 48 48l208 0 0-96c0-35.3 28.7-64 64-64s64 28.7 64 64l0 96 208 0c26.5 0 48-21.5 48-48l0-320c0-26.5-21.5-48-48-48L473.7 96 337.8 5.4zM96 192l32 0c8.8 0 16 7.2 16 16l0 64c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-64c0-8.8 7.2-16 16-16zm400 16c0-8.8 7.2-16 16-16l32 0c8.8 0 16 7.2 16 16l0 64c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-64zM96 320l32 0c8.8 0 16 7.2 16 16l0 64c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-64c0-8.8 7.2-16 16-16zm400 16c0-8.8 7.2-16 16-16l32 0c8.8 0 16 7.2 16 16l0 64c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-64zM232 176a88 88 0 1 1 176 0 88 88 0 1 1 -176 0zm88-48c-8.8 0-16 7.2-16 16l0 32c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-16 0 0-16c0-8.8-7.2-16-16-16z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 0 640 512" width="48"><path d="M337.8 5.4C327-1.8 313-1.8 302.2 5.4L166.3 96 48 96C21.5 96 0 117.5 0 144L0 464c0 26.5 21.5 48 48 48l208 0 0-96c0-35.3 28.7-64 64-64s64 28.7 64 64l0 96 208 0c26.5 0 48-21.5 48-48l0-320c0-26.5-21.5-48-48-48L473.7 96 337.8 5.4zM96 192l32 0c8.8 0 16 7.2 16 16l0 64c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-64c0-8.8 7.2-16 16-16zm400 16c0-8.8 7.2-16 16-16l32 0c8.8 0 16 7.2 16 16l0 64c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-64zM96 320l32 0c8.8 0 16 7.2 16 16l0 64c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-64c0-8.8 7.2-16 16-16zm400 16c0-8.8 7.2-16 16-16l32 0c8.8 0 16 7.2 16 16l0 64c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-64zM232 176a88 88 0 1 1 176 0 88 88 0 1 1 -176 0zm88-48c-8.8 0-16 7.2-16 16l0 32c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-16 0 0-16c0-8.8-7.2-16-16-16z"/></svg>
</div> </div>
<h2>Kurse vor Ort</h2> <h2>Kurse</h2>
<p>Einige unserer Ortsverbände bieten Präsenz- oder Onlinekurse mit erfahrenen Ausbildern an. Finde heraus, ob es einen für dich passenden Kurs bei dir in der Nähe gibt!</p> <p>Einige unserer Ortsverbände bieten Präsenz- oder Onlinekurse mit erfahrenen Ausbildern an. Finde heraus, ob es einen für dich passenden Kurs bei dir in der Nähe gibt!</p>
<div class="d-grid gap-2 d-md-block mb-5"> <div class="d-grid gap-2 d-md-block mb-5">
<a href="kurse_vor_ort_karte.html" class="btn btn-primary">Präsenz</a> <a href="kurse_vor_ort_karte.html" class="btn btn-primary">Präsenz</a>
+11 -11
View File
@@ -8,17 +8,17 @@ from renderer.fifty_ohm_latex_renderer import FiftyOhmLaTeXRenderer
@pytest.mark.html @pytest.mark.html
def test_table_html(): def test_table_html():
assertions = { assertions = {
"| l: a |": '<table>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n</table>\n', "| l: a |": '<table class="table table-hover">\n<thead>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n</thead>\n</table>\n', # noqa: E501
"| r: a |": '<table>\n<tr>\n<th style="text-align: right;">a</th>\n</tr>\n</table>\n', "| r: a |": '<table class="table table-hover">\n<thead>\n<tr>\n<th style="text-align: right;">a</th>\n</tr>\n</thead>\n</table>\n', # noqa: E501
"| c: a |": '<table>\n<tr>\n<th style="text-align: center;">a</th>\n</tr>\n</table>\n', "| c: a |": '<table class="table table-hover">\n<thead>\n<tr>\n<th style="text-align: center;">a</th>\n</tr>\n</thead>\n</table>\n', # noqa: E501
"| l: a |\n| b |": '<table>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n<tr>\n<td style="text-align: left;">b</td>\n</tr>\n</table>\n', # noqa: E501 "| l: a |\n| b |": '<table class="table table-hover">\n<thead>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style="text-align: left;">b</td>\n</tr>\n</tbody>\n</table>\n', # noqa: E501
"| l: a |\n| b |\n| c |": '<table>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n<tr>\n<td style="text-align: left;">b</td>\n</tr>\n<tr>\n<td style="text-align: left;">c</td>\n</tr>\n</table>\n', # noqa: E501 "| l: a |\n| b |\n| c |": '<table class="table table-hover">\n<thead>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style="text-align: left;">b</td>\n</tr>\n<tr>\n<td style="text-align: left;">c</td>\n</tr>\n</tbody>\n</table>\n', # noqa: E501
"| a |\n| b |\n| c |": "<table>\n<tr>\n<th>a</th>\n</tr>\n<tr>\n<td>b</td>\n</tr>\n<tr>\n<td>c</td>\n</tr>\n</table>\n", # noqa: E501 "| a |\n| b |\n| c |": '<table class="table table-hover">\n<thead>\n<tr>\n<th>a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>b</td>\n</tr>\n<tr>\n<td>c</td>\n</tr>\n</tbody>\n</table>\n', # noqa: E501
"| l: a |\n| *b* |": '<table>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n<tr>\n<td style="text-align: left;"><em>b</em></td>\n</tr>\n</table>\n', # noqa: E501 "| l: a |\n| *b* |": '<table class="table table-hover">\n<thead>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style="text-align: left;"><em>b</em></td>\n</tr>\n</tbody>\n</table>\n', # noqa: E501
"| l: a |\n| b |\n[table:n_ab:A und B]": '<table>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n<tr>\n<td style="text-align: left;">b</td>\n</tr>\n<caption>A und B</caption></table>\n', # noqa: E501 "| l: a |\n| b |\n[table:n_ab:A und B]": '<table class="table table-hover">\n<thead>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style="text-align: left;">b</td>\n</tr>\n</tbody>\n<caption>A und B</caption>\n</table>\n', # noqa: E501
"| l: *a* |": '<table>\n<tr>\n<th style="text-align: left;"><em>a</em></th>\n</tr>\n</table>\n', "| l: *a* |": '<table class="table table-hover">\n<thead>\n<tr>\n<th style="text-align: left;"><em>a</em></th>\n</tr>\n</thead>\n</table>\n', # noqa: E501
"| l: a |\n| [morse:a] |": '<table>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n<tr>\n<td style="text-align: left;"><span class="morse"><span class="morse_char">\n<span class="morse_char">\n▄</span>\n<span class="morse_char">\n▄▄▄</span>\n</span>\n</span></td>\n</tr>\n</table>\n', # noqa: E501 "| l: a |\n| [morse:a] |": '<table class="table table-hover">\n<thead>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style="text-align: left;"><span class="morse"><span class="morse_char">\n<span class="morse_symbol">\n▄</span>\n<span class="morse_symbol">\n▄▄▄</span>\n</span>\n</span></td>\n</tr>\n</tbody>\n</table>\n', # noqa: E501
"| l: abc | r: abc | X: abc |\n| 123 | 456 | 789 | \n | 987 | 654 | 321 | ": '<table>\n<tr>\n<th style="text-align: left;">abc</th>\n<th style="text-align: right;">abc</th>\n<th>abc</th>\n</tr>\n<tr>\n<td style="text-align: left;">123</td>\n<td style="text-align: right;">456</td>\n<td>789</td>\n</tr>\n<tr>\n<td style="text-align: left;">987</td>\n<td style="text-align: right;">654</td>\n<td>321</td>\n</tr>\n</table>\n', # noqa: E501 "| l: abc | r: abc | X: abc |\n| 123 | 456 | 789 | \n | 987 | 654 | 321 | ": '<table class="table table-hover">\n<thead>\n<tr>\n<th style="text-align: left;">abc</th>\n<th style="text-align: right;">abc</th>\n<th>abc</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style="text-align: left;">123</td>\n<td style="text-align: right;">456</td>\n<td>789</td>\n</tr>\n<tr>\n<td style="text-align: left;">987</td>\n<td style="text-align: right;">654</td>\n<td>321</td>\n</tr>\n</tbody>\n</table>\n', # noqa: E501
} }
with FiftyOhmHtmlRenderer() as renderer: with FiftyOhmHtmlRenderer() as renderer: