pytex-preprocessor 0.1.0__tar.gz → 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/PKG-INFO +1 -1
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/pyproject.toml +1 -1
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_builder/build.py +17 -4
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/tex/pagesetup.tex +2 -2
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/titlepage.py +64 -52
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_preprocessor.egg-info/PKG-INFO +1 -1
- pytex_preprocessor-0.1.1/src/pytex_protocol/document.py +154 -0
- pytex_preprocessor-0.1.0/src/pytex_protocol/document.py +0 -91
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/README.md +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/setup.cfg +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/__init__.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/__init__.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/biblatex.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/builtin.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/captions.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/cleveref.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/colors.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/conditionals.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/counters.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/definitions.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/floats.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/font.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/fontawesome.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/fontspec.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/geometry.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/glossaries.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/graphics.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/hooks.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/hyperref.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/lengths.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/listings.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/mdframed.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/picture.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/setspace.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/commands/tables.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/helpers/__init__.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/helpers/coerce.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/helpers/parenting.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/helpers/sanitize.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/helpers/with_package.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/interface/__init__.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/interface/control_sequence.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/interface/package.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/interface/tex.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/model/__init__.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/model/color.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/model/concat.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/model/control_sequence.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/model/document.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/model/document_class.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/model/empty.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/model/environment.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/model/image.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/model/include.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/model/length.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/model/math.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/model/package.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/model/raw.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/packages.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/registry.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_builder/__init__.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_builder/console.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_builder/render.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_builder/tectonic.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/__init__.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-Bold.ttf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-BoldItalic.ttf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-Book.ttf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-BookItalic.ttf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-Medium.ttf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-MediumItalic.ttf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-Strong.ttf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-Thin.ttf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-ThinItalic.ttf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/fonts/DIN/DIN-Black.ttf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/fonts/DIN/DIN-Bold.ttf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/fonts/DIN/DIN-BoldItalic.ttf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/fonts/DIN/DIN-Italic.ttf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/fonts/DIN/DIN-Medium.ttf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/fonts/DIN/DIN-Regular.ttf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/fonts/Times New Roman.ttf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/logos/ASTA.svg +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/logos/DUMMY.png +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/logos/DUMMY_FOOT.png +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/logos/ECHO.svg +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/logos/HSRT.pdf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/logos/INF.pdf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/logos/STUPA.pdf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/logos/Skyline.pdf +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/boxes.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/citations.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/cleveref_names.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/colors.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/document.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/fonts.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/glossary.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/hyperref_config.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/listings.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/logos.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/pagebreak.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/pagesetup.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/variants.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/voting.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/watermark.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/wordcount.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_koma/__init__.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_koma/commands.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_koma/document.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_markdown/__init__.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_markdown/convert.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_markdown/escape.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_preprocessor.egg-info/SOURCES.txt +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_preprocessor.egg-info/dependency_links.txt +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_preprocessor.egg-info/entry_points.txt +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_preprocessor.egg-info/requires.txt +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_preprocessor.egg-info/top_level.txt +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_protocol/__init__.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_protocol/convert.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_protocol/entries.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_protocol/frontmatter.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_protocol/header.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_protocol/shortcodes.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_protocol/signatures.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_tikz/__init__.py +0 -0
- {pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_tikz/tikz.py +0 -0
|
@@ -8,6 +8,7 @@ acronyms resolve.
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
import argparse
|
|
11
|
+
import re
|
|
11
12
|
import sys
|
|
12
13
|
from dataclasses import dataclass
|
|
13
14
|
from pathlib import Path
|
|
@@ -42,16 +43,28 @@ def _default_output(inp: Path, build_dir: Path) -> Path:
|
|
|
42
43
|
``build_dir`` so the ``.out.tex`` and its inline assets (fonts, logos,
|
|
43
44
|
images) stay out of the source tree:
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
The stem is also slugified (whitespace and shell/TeX-hostile characters
|
|
47
|
+
become ``_``) because it becomes the TeX ``\\jobname``; spaces there break
|
|
48
|
+
tectonic's biber/makeindex steps (the ``.bcf`` path cannot be opened):
|
|
49
|
+
|
|
50
|
+
* ``example.tex.py`` -> ``<build_dir>/example.out.tex``
|
|
51
|
+
* ``report.py`` -> ``<build_dir>/report.out.tex``
|
|
52
|
+
* ``2026-06-15 STUPA.md`` -> ``<build_dir>/2026-06-15_STUPA.md.out.tex``
|
|
48
53
|
"""
|
|
49
54
|
base = inp
|
|
50
55
|
if base.suffix.lower() in {".py", ".tex"}:
|
|
51
56
|
base = base.with_suffix("")
|
|
52
57
|
if base.suffix.lower() == ".tex":
|
|
53
58
|
base = base.with_suffix("")
|
|
54
|
-
return build_dir / f"{base.name}.out.tex"
|
|
59
|
+
return build_dir / f"{_slug(base.name)}.out.tex"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _slug(name: str) -> str:
|
|
63
|
+
"""Make `name` safe as a TeX jobname: collapse whitespace and drop
|
|
64
|
+
characters that confuse tectonic/biber/makeindex."""
|
|
65
|
+
name = re.sub(r"\s+", "_", name.strip())
|
|
66
|
+
name = re.sub(r"[^\w.\-]", "", name)
|
|
67
|
+
return name or "document"
|
|
55
68
|
|
|
56
69
|
|
|
57
70
|
def _parse_args(argv: list[str]) -> Config:
|
{pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/tex/pagesetup.tex
RENAMED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
\usepackage{lastpage}
|
|
1
2
|
\makeatletter
|
|
2
3
|
\def\@title{}
|
|
3
4
|
\def\@author{}
|
|
@@ -12,14 +13,13 @@
|
|
|
12
13
|
\def\chaptermark#1{\def\Chaptername{#1}\Chaptermark{#1}}
|
|
13
14
|
\let\Sectionmark\sectionmark
|
|
14
15
|
\def\sectionmark#1{\def\Sectionname{#1}\Sectionmark{#1}}
|
|
15
|
-
\AtEndDocument{\immediate\write\@auxout{\string\gdef\string\@lastpage{\thepage}}}
|
|
16
16
|
\clearpairofpagestyles
|
|
17
17
|
\setkomafont{pageheadfoot}{\color{gray}\blenderfont}
|
|
18
18
|
\setkomafont{pagenumber}{\color{gray}\blenderfont}
|
|
19
19
|
\setlength{\footskip}{20pt}
|
|
20
20
|
\ohead*{\ifHSRTBackMatter\else\ifnum\value{chapter}>0\relax\Roman{\thechapter}~–~\Chaptername\fi\fi}
|
|
21
21
|
\ifoot{\@author}
|
|
22
|
-
\cfoot{\ifHSRTBackMatter\else Seite~\thepage\if@mainmatter
|
|
22
|
+
\cfoot{\ifHSRTBackMatter\else Seite~\thepage\if@mainmatter~von~\pageref{LastPage}\fi\fi}
|
|
23
23
|
\ohead{\ifHSRTBackMatter\else\ifnum\value{chapter}>0\relax\thechapter~–~\Chaptername\fi\fi}
|
|
24
24
|
\ihead{\@title}
|
|
25
25
|
\pagestyle{scrheadings}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from collections.abc import Iterator
|
|
1
2
|
from dataclasses import dataclass, field
|
|
2
3
|
from typing import Final, override
|
|
3
4
|
|
|
@@ -20,12 +21,22 @@ from pytex.commands.tables import Tabular
|
|
|
20
21
|
from pytex.helpers.parenting import attach
|
|
21
22
|
from pytex.interface.tex import TeX
|
|
22
23
|
from pytex.model.concat import Concat
|
|
24
|
+
from pytex.model.empty import Empty
|
|
23
25
|
from pytex.model.environment import Environment
|
|
24
26
|
from pytex.model.raw import Raw
|
|
25
27
|
from pytex.registry import Registry
|
|
26
28
|
|
|
27
29
|
from .logos import titlepage_logo_overlay
|
|
28
30
|
|
|
31
|
+
|
|
32
|
+
def _is_blank(node: TeX | str) -> bool:
|
|
33
|
+
"""True for an empty string or the `Empty` node — used to skip empty
|
|
34
|
+
title-page sections (a protocol has no abstract or keywords)."""
|
|
35
|
+
if isinstance(node, str):
|
|
36
|
+
return not node.strip()
|
|
37
|
+
return node is Empty
|
|
38
|
+
|
|
39
|
+
|
|
29
40
|
__all__ = ["TitlePage", "TitlePageDataLine"]
|
|
30
41
|
|
|
31
42
|
|
|
@@ -75,62 +86,63 @@ class TitlePage(TeX):
|
|
|
75
86
|
)
|
|
76
87
|
return tuple(v for v in candidates if isinstance(v, TeX))
|
|
77
88
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
89
|
+
def _title_block(self) -> TeX:
|
|
90
|
+
return Environment(
|
|
91
|
+
"flushleft",
|
|
92
|
+
Concat(
|
|
93
|
+
Raw(r"\hyphenpenalty=10000\exhyphenpenalty=10000"),
|
|
94
|
+
Noindent(),
|
|
95
|
+
SelectColor("black"),
|
|
96
|
+
Textbf(
|
|
97
|
+
Concat(
|
|
98
|
+
Blenderfont(),
|
|
99
|
+
HugeBig(),
|
|
100
|
+
Hspace("-2.5pt", star=True),
|
|
101
|
+
self.title,
|
|
102
|
+
)
|
|
103
|
+
),
|
|
104
|
+
Raw(r"\par"),
|
|
105
|
+
Vspace("-0.5em"),
|
|
106
|
+
Rule(r"\textwidth", "0.5mm"),
|
|
107
|
+
),
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
def _content(self) -> Iterator[TeX | str]:
|
|
81
111
|
# Tikz overlay: logos chained left-to-right from the top-left corner,
|
|
82
112
|
# matching tmp/Pages/Titlepage.tex but with the foreach unrolled here.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
113
|
+
yield Raw(titlepage_logo_overlay(self.logo_names), allow_replacements=False)
|
|
114
|
+
yield Vspace("4cm")
|
|
115
|
+
yield self._title_block()
|
|
116
|
+
yield Vspace("2em")
|
|
117
|
+
yield Setstretch("1.0")
|
|
118
|
+
# Abstract and keywords are optional — skip the labels when empty
|
|
119
|
+
# (e.g. a meeting protocol has neither).
|
|
120
|
+
if not _is_blank(self.abstract):
|
|
121
|
+
yield SectionStar("Abstract")
|
|
122
|
+
yield Vspace("-1em")
|
|
123
|
+
yield self.abstract
|
|
124
|
+
yield Vspace("1em", star=True)
|
|
125
|
+
if not _is_blank(self.keywords):
|
|
126
|
+
yield Raw(r"\par\noindent ")
|
|
127
|
+
yield Textbf("Keywords")
|
|
128
|
+
yield Raw(r"\par\noindent ")
|
|
129
|
+
yield self.keywords
|
|
130
|
+
yield Vfill()
|
|
131
|
+
yield Noindent()
|
|
132
|
+
yield Setstretch("1.0")
|
|
133
|
+
yield Tabular(
|
|
134
|
+
r"@{} p{30mm} p{\dimexpr\textwidth-30mm-2\tabcolsep\relax} @{}",
|
|
135
|
+
_data_table_body(self.data_lines),
|
|
86
136
|
)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
@override
|
|
140
|
+
def rendered(self) -> str:
|
|
141
|
+
# `\HSRTTitlePagetrue` while the titlepage ships out so footer_logo_hook
|
|
142
|
+
# suppresses the bottom-right footer logos on this page only; reset
|
|
143
|
+
# after \end{titlepage} (which \clearpages while the flag is still set).
|
|
91
144
|
return Concat(
|
|
92
145
|
Raw(r"\HSRTTitlePagetrue", allow_replacements=False),
|
|
93
|
-
TitlepageEnv(
|
|
94
|
-
Concat(
|
|
95
|
-
logo_overlay,
|
|
96
|
-
Vspace("4cm"),
|
|
97
|
-
Environment(
|
|
98
|
-
"flushleft",
|
|
99
|
-
Concat(
|
|
100
|
-
Raw(r"\hyphenpenalty=10000\exhyphenpenalty=10000"),
|
|
101
|
-
Noindent(),
|
|
102
|
-
SelectColor("black"),
|
|
103
|
-
Textbf(
|
|
104
|
-
Concat(
|
|
105
|
-
Blenderfont(),
|
|
106
|
-
HugeBig(),
|
|
107
|
-
Hspace("-2.5pt", star=True),
|
|
108
|
-
self.title,
|
|
109
|
-
)
|
|
110
|
-
),
|
|
111
|
-
Raw(r"\par"),
|
|
112
|
-
Vspace("-0.5em"),
|
|
113
|
-
Rule(r"\textwidth", "0.5mm"),
|
|
114
|
-
),
|
|
115
|
-
),
|
|
116
|
-
Vspace("2em"),
|
|
117
|
-
Setstretch("1.0"),
|
|
118
|
-
SectionStar("Abstract"),
|
|
119
|
-
Vspace("-1em"),
|
|
120
|
-
self.abstract,
|
|
121
|
-
Vspace("1em", star=True),
|
|
122
|
-
Raw(r"\par\noindent "),
|
|
123
|
-
Textbf("Keywords"),
|
|
124
|
-
Raw(r"\par\noindent "),
|
|
125
|
-
self.keywords,
|
|
126
|
-
Vfill(),
|
|
127
|
-
Noindent(),
|
|
128
|
-
Setstretch("1.0"),
|
|
129
|
-
Tabular(
|
|
130
|
-
r"@{} p{30mm} p{\dimexpr\textwidth-30mm-2\tabcolsep\relax} @{}",
|
|
131
|
-
_data_table_body(self.data_lines),
|
|
132
|
-
),
|
|
133
|
-
)
|
|
134
|
-
),
|
|
146
|
+
TitlepageEnv(Concat(*self._content())),
|
|
135
147
|
Raw(r"\HSRTTitlePagefalse", allow_replacements=False),
|
|
136
148
|
).rendered
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""Render a STUPA/AStA meeting protocol from Obsidian-flavoured Markdown.
|
|
2
|
+
|
|
3
|
+
The protocol is an :class:`~pytex_hsrtreport.document.HSRTReport`: a full HSRT
|
|
4
|
+
title page carries the meeting metadata as data lines, agenda items become
|
|
5
|
+
numbered sections, and protocol entries (decisions, votes, action items) render
|
|
6
|
+
as HSRT callout boxes. An optional signature block closes the document.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import re
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import TYPE_CHECKING
|
|
14
|
+
|
|
15
|
+
import marko
|
|
16
|
+
|
|
17
|
+
from pytex.model.concat import Concat
|
|
18
|
+
from pytex.model.raw import Raw
|
|
19
|
+
from pytex.registry import Registry
|
|
20
|
+
from pytex_hsrtreport.document import HSRTReport
|
|
21
|
+
from pytex_hsrtreport.titlepage import TitlePageDataLine
|
|
22
|
+
from pytex_hsrtreport.variants import Variant
|
|
23
|
+
|
|
24
|
+
from .convert import ProtocolConverter
|
|
25
|
+
from .frontmatter import FrontmatterValue, split_frontmatter
|
|
26
|
+
from .signatures import signature_block_from_meta
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from collections.abc import Mapping
|
|
30
|
+
|
|
31
|
+
from pytex.interface.tex import TeX
|
|
32
|
+
|
|
33
|
+
__all__ = ["IncludeProtocol", "Protocol", "render_protocol"]
|
|
34
|
+
|
|
35
|
+
_PARSER = marko.Markdown()
|
|
36
|
+
|
|
37
|
+
_VARIANTS: dict[str, Variant] = {
|
|
38
|
+
"stupa": Variant.STUPA,
|
|
39
|
+
"asta": Variant.ASTA,
|
|
40
|
+
"echo": Variant.ECHO,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Title-page rows: (label, frontmatter keys to try), single-value fields first.
|
|
44
|
+
_SCALAR_ROWS: tuple[tuple[str, tuple[str, ...]], ...] = (
|
|
45
|
+
("Datum", ("datum", "date")),
|
|
46
|
+
("Ort", ("ort",)),
|
|
47
|
+
("Sitzungsleitung", ("sitzungsleitung",)),
|
|
48
|
+
("Protokoll", ("protokoll",)),
|
|
49
|
+
)
|
|
50
|
+
_LIST_ROWS: tuple[tuple[str, tuple[str, ...]], ...] = (
|
|
51
|
+
("Anwesend", ("anwesend",)),
|
|
52
|
+
("Entschuldigt", ("entschuldigt",)),
|
|
53
|
+
("Abwesend", ("abwesend",)),
|
|
54
|
+
("Gäste", ("gaeste", "gäste")),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _scalar(meta: Mapping[str, FrontmatterValue], *keys: str) -> str:
|
|
59
|
+
for key in keys:
|
|
60
|
+
value = meta.get(key)
|
|
61
|
+
if isinstance(value, str) and value:
|
|
62
|
+
return value
|
|
63
|
+
return ""
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _joined(meta: Mapping[str, FrontmatterValue], *keys: str) -> str:
|
|
67
|
+
for key in keys:
|
|
68
|
+
value = meta.get(key)
|
|
69
|
+
if isinstance(value, list) and value:
|
|
70
|
+
return ", ".join(value)
|
|
71
|
+
if isinstance(value, str) and value:
|
|
72
|
+
return value
|
|
73
|
+
return ""
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _variant(meta: Mapping[str, FrontmatterValue]) -> Variant:
|
|
77
|
+
return _VARIANTS.get(_scalar(meta, "gremium").lower(), Variant.STUPA)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _format_date(value: str) -> str:
|
|
81
|
+
"""ISO ``YYYY-MM-DD`` -> German ``DD.MM.YYYY``; anything else is kept as-is."""
|
|
82
|
+
match = re.fullmatch(r"(\d{4})-(\d{2})-(\d{2})", value)
|
|
83
|
+
return f"{match[3]}.{match[2]}.{match[1]}" if match else value
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _title(meta: Mapping[str, FrontmatterValue]) -> str:
|
|
87
|
+
gremium = _scalar(meta, "gremium")
|
|
88
|
+
datum = _format_date(_scalar(meta, "datum", "date"))
|
|
89
|
+
if gremium and datum:
|
|
90
|
+
return f"Protokoll der Sitzung des {gremium} vom {datum}"
|
|
91
|
+
if gremium:
|
|
92
|
+
return f"Protokoll der Sitzung des {gremium}"
|
|
93
|
+
return "Sitzungsprotokoll"
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _data_lines(meta: Mapping[str, FrontmatterValue]) -> tuple[TitlePageDataLine, ...]:
|
|
97
|
+
lines: list[TitlePageDataLine] = []
|
|
98
|
+
for label, keys in _SCALAR_ROWS:
|
|
99
|
+
value = _scalar(meta, *keys)
|
|
100
|
+
if value:
|
|
101
|
+
lines.append(TitlePageDataLine(label, value))
|
|
102
|
+
if label == "Datum":
|
|
103
|
+
# Append the time range right after the date when present.
|
|
104
|
+
span = " – ".join( # noqa: RUF001 (EN DASH between start/end)
|
|
105
|
+
t
|
|
106
|
+
for t in (
|
|
107
|
+
_scalar(meta, "beginn", "start"),
|
|
108
|
+
_scalar(meta, "ende", "end"),
|
|
109
|
+
)
|
|
110
|
+
if t
|
|
111
|
+
)
|
|
112
|
+
if span:
|
|
113
|
+
lines.append(TitlePageDataLine("Zeit", span))
|
|
114
|
+
for label, keys in _LIST_ROWS:
|
|
115
|
+
value = _joined(meta, *keys)
|
|
116
|
+
if value:
|
|
117
|
+
lines.append(TitlePageDataLine(f"{label} ({value.count(',') + 1})", value))
|
|
118
|
+
return tuple(lines)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def render_protocol(text: str, *, base_level: int = 0) -> HSRTReport:
|
|
122
|
+
"""Build an `HSRTReport` from the Markdown source of a protocol."""
|
|
123
|
+
meta, body_md = split_frontmatter(text)
|
|
124
|
+
converter = ProtocolConverter(meta=meta, base_level=base_level)
|
|
125
|
+
converted = converter.block(_PARSER.parse(body_md))
|
|
126
|
+
# Optional sign-off block, appended when the frontmatter lists `unterschriften`.
|
|
127
|
+
signatures = signature_block_from_meta(meta)
|
|
128
|
+
tail = (Raw("\n\n"), signatures) if signatures is not None else ()
|
|
129
|
+
return HSRTReport(
|
|
130
|
+
variant=_variant(meta),
|
|
131
|
+
document_class="scrbook",
|
|
132
|
+
show_titlepage=True,
|
|
133
|
+
show_toc=False,
|
|
134
|
+
show_footer_logos=True,
|
|
135
|
+
title=_title(meta),
|
|
136
|
+
data_lines=_data_lines(meta),
|
|
137
|
+
# Agenda items are top-level `#` headings -> \section. In scrbook a
|
|
138
|
+
# chapterless section would number as "0.1"; flatten it to a plain
|
|
139
|
+
# arabic counter so TOPs read 1, 2, 3, ...
|
|
140
|
+
user_preamble=Raw(r"\renewcommand*{\thesection}{\arabic{section}}"),
|
|
141
|
+
body=Concat(converted, *tail),
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@Registry.add
|
|
146
|
+
def Protocol(text: str, *, base_level: int = 0) -> TeX:
|
|
147
|
+
"""Convert a protocol Markdown string to a renderable `HSRTReport`."""
|
|
148
|
+
return render_protocol(text, base_level=base_level)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@Registry.add
|
|
152
|
+
def IncludeProtocol(path: str | Path, *, encoding: str = "utf-8") -> TeX:
|
|
153
|
+
"""Read a protocol Markdown file and render it (see :func:`render_protocol`)."""
|
|
154
|
+
return render_protocol(Path(path).read_text(encoding=encoding))
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
"""Render a STUPA/AStA meeting protocol from Obsidian-flavoured Markdown.
|
|
2
|
-
|
|
3
|
-
The protocol is an :class:`~pytex_hsrtreport.document.HSRTReport` configured for
|
|
4
|
-
a short minutes document: no title page, a compact header block (built from the
|
|
5
|
-
frontmatter) at the top, agenda items as numbered sections, and protocol
|
|
6
|
-
entries (decisions, votes, action items) rendered as HSRT callout boxes.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
from pathlib import Path
|
|
12
|
-
from typing import TYPE_CHECKING
|
|
13
|
-
|
|
14
|
-
import marko
|
|
15
|
-
|
|
16
|
-
from pytex.model.concat import Concat
|
|
17
|
-
from pytex.model.raw import Raw
|
|
18
|
-
from pytex.registry import Registry
|
|
19
|
-
from pytex_hsrtreport.document import HSRTReport
|
|
20
|
-
from pytex_hsrtreport.variants import Variant
|
|
21
|
-
|
|
22
|
-
from .convert import ProtocolConverter
|
|
23
|
-
from .frontmatter import FrontmatterValue, split_frontmatter
|
|
24
|
-
from .header import header_from_meta
|
|
25
|
-
from .signatures import signature_block_from_meta
|
|
26
|
-
|
|
27
|
-
if TYPE_CHECKING:
|
|
28
|
-
from pytex.interface.tex import TeX
|
|
29
|
-
|
|
30
|
-
__all__ = ["IncludeProtocol", "Protocol", "render_protocol"]
|
|
31
|
-
|
|
32
|
-
_PARSER = marko.Markdown()
|
|
33
|
-
|
|
34
|
-
_VARIANTS: dict[str, Variant] = {
|
|
35
|
-
"stupa": Variant.STUPA,
|
|
36
|
-
"asta": Variant.ASTA,
|
|
37
|
-
"echo": Variant.ECHO,
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def _variant(meta: dict[str, FrontmatterValue]) -> Variant:
|
|
42
|
-
gremium = meta.get("gremium", "")
|
|
43
|
-
key = gremium.lower().strip() if isinstance(gremium, str) else ""
|
|
44
|
-
return _VARIANTS.get(key, Variant.STUPA)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def _document_title(meta: dict[str, FrontmatterValue]) -> str:
|
|
48
|
-
gremium = meta.get("gremium")
|
|
49
|
-
datum = meta.get("datum")
|
|
50
|
-
head = (
|
|
51
|
-
f"{gremium} — Protokoll"
|
|
52
|
-
if isinstance(gremium, str) and gremium
|
|
53
|
-
else "Protokoll"
|
|
54
|
-
)
|
|
55
|
-
return f"{head} ({datum})" if isinstance(datum, str) and datum else head
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def render_protocol(text: str, *, base_level: int = 0) -> HSRTReport:
|
|
59
|
-
"""Build an `HSRTReport` from the Markdown source of a protocol."""
|
|
60
|
-
meta, body_md = split_frontmatter(text)
|
|
61
|
-
converter = ProtocolConverter(meta=meta, base_level=base_level)
|
|
62
|
-
converted = converter.block(_PARSER.parse(body_md))
|
|
63
|
-
header = header_from_meta(meta)
|
|
64
|
-
# Optional sign-off block, appended when the frontmatter lists `unterschriften`.
|
|
65
|
-
signatures = signature_block_from_meta(meta)
|
|
66
|
-
tail = (Raw("\n\n"), signatures) if signatures is not None else ()
|
|
67
|
-
return HSRTReport(
|
|
68
|
-
variant=_variant(meta),
|
|
69
|
-
document_class="scrbook",
|
|
70
|
-
show_titlepage=False,
|
|
71
|
-
show_toc=False,
|
|
72
|
-
show_footer_logos=True,
|
|
73
|
-
title=_document_title(meta),
|
|
74
|
-
# Agenda items are top-level `#` headings -> \section. In scrbook a
|
|
75
|
-
# chapterless section would number as "0.1"; flatten it to a plain
|
|
76
|
-
# arabic counter so TOPs read 1, 2, 3, ...
|
|
77
|
-
user_preamble=Raw(r"\renewcommand*{\thesection}{\arabic{section}}"),
|
|
78
|
-
body=Concat(header, Raw("\n\n"), converted, *tail),
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
@Registry.add
|
|
83
|
-
def Protocol(text: str, *, base_level: int = 0) -> TeX:
|
|
84
|
-
"""Convert a protocol Markdown string to a renderable `HSRTReport`."""
|
|
85
|
-
return render_protocol(text, base_level=base_level)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
@Registry.add
|
|
89
|
-
def IncludeProtocol(path: str | Path, *, encoding: str = "utf-8") -> TeX:
|
|
90
|
-
"""Read a protocol Markdown file and render it (see :func:`render_protocol`)."""
|
|
91
|
-
return render_protocol(Path(path).read_text(encoding=encoding))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex/interface/control_sequence.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/logos/ASTA.svg
RENAMED
|
File without changes
|
{pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/logos/DUMMY.png
RENAMED
|
File without changes
|
|
File without changes
|
{pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/logos/ECHO.svg
RENAMED
|
File without changes
|
{pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/logos/HSRT.pdf
RENAMED
|
File without changes
|
{pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/logos/INF.pdf
RENAMED
|
File without changes
|
{pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/logos/STUPA.pdf
RENAMED
|
File without changes
|
{pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/assets/logos/Skyline.pdf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/cleveref_names.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_hsrtreport/hyperref_config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_preprocessor.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_preprocessor.egg-info/requires.txt
RENAMED
|
File without changes
|
{pytex_preprocessor-0.1.0 → pytex_preprocessor-0.1.1}/src/pytex_preprocessor.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|