pytex-preprocessor 0.3.0__tar.gz → 0.4.0__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.3.0 → pytex_preprocessor-0.4.0}/PKG-INFO +31 -1
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/README.md +30 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/pyproject.toml +4 -1
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/__init__.py +9 -0
- pytex_preprocessor-0.4.0/src/pytex/template.py +90 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_builder/build.py +11 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_preprocessor.egg-info/PKG-INFO +31 -1
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_preprocessor.egg-info/SOURCES.txt +1 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/setup.cfg +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/__init__.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/biblatex.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/builtin.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/captions.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/cleveref.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/colors.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/conditionals.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/counters.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/definitions.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/floats.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/font.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/fontawesome.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/fontspec.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/geometry.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/glossaries.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/graphics.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/hooks.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/hyperref.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/lengths.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/listings.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/mdframed.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/picture.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/setspace.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/commands/tables.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/helpers/__init__.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/helpers/coerce.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/helpers/parenting.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/helpers/sanitize.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/helpers/with_package.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/interface/__init__.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/interface/control_sequence.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/interface/package.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/interface/tex.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/model/__init__.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/model/color.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/model/comment.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/model/concat.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/model/control_sequence.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/model/document.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/model/document_class.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/model/empty.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/model/environment.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/model/image.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/model/include.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/model/length.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/model/math.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/model/package.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/model/raw.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/packages.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex/registry.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_analyze/__init__.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_analyze/analyze.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_analyze/optimize.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_builder/__init__.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_builder/console.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_builder/render.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_builder/tectonic.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_builder/tex2py.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_builder/tree.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_builder/variants.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/__init__.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-Bold.ttf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-BoldItalic.ttf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-Book.ttf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-BookItalic.ttf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-Medium.ttf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-MediumItalic.ttf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-Strong.ttf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-Thin.ttf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/fonts/Blender/Blender-ThinItalic.ttf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/fonts/DIN/DIN-Black.ttf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/fonts/DIN/DIN-Bold.ttf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/fonts/DIN/DIN-BoldItalic.ttf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/fonts/DIN/DIN-Italic.ttf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/fonts/DIN/DIN-Medium.ttf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/fonts/DIN/DIN-Regular.ttf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/fonts/Times New Roman.ttf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/logos/ASTA.svg +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/logos/DUMMY.png +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/logos/DUMMY_FOOT.png +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/logos/ECHO.svg +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/logos/HSRT.pdf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/logos/INF.pdf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/logos/STUPA.pdf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/logos/Skyline.pdf +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/boxes.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/citations.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/cleveref_names.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/colors.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/document.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/fonts.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/glossary.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/hyperref_config.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/listings.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/logos.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/pagebreak.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/pagesetup.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/tex/pagesetup.tex +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/titlepage.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/variants.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/voting.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/watermark.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/wordcount.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_koma/__init__.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_koma/commands.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_koma/document.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_markdown/__init__.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_markdown/convert.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_markdown/escape.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_preprocessor.egg-info/dependency_links.txt +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_preprocessor.egg-info/entry_points.txt +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_preprocessor.egg-info/requires.txt +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_preprocessor.egg-info/top_level.txt +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_protocol/__init__.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_protocol/convert.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_protocol/document.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_protocol/entries.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_protocol/frontmatter.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_protocol/header.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_protocol/shortcodes.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_protocol/signatures.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_tikz/__init__.py +0 -0
- {pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_tikz/tikz.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytex-preprocessor
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Type-safe LaTeX document generation with Python
|
|
5
5
|
Author-email: Frederik Beimgraben <frederik@beimgraben.net>
|
|
6
6
|
Requires-Python: >=3.13
|
|
@@ -28,6 +28,20 @@ uses.
|
|
|
28
28
|
|
|
29
29
|
## Install
|
|
30
30
|
|
|
31
|
+
### Prebuilt binary
|
|
32
|
+
|
|
33
|
+
Each release attaches standalone `pytex` binaries (Linux/macOS/Windows) — no
|
|
34
|
+
Python or `pip` needed. Download one from the
|
|
35
|
+
[Releases](https://github.com/frederikbeimgraben/PyTeX-Preprocessor/releases)
|
|
36
|
+
page, make it executable, and run it. The binary bundles its own interpreter
|
|
37
|
+
plus common data packages (numpy, pandas, openpyxl/calamine for spreadsheets,
|
|
38
|
+
Pillow, PyYAML), so documents can `import` those without installing anything;
|
|
39
|
+
see [`packaging/`](packaging/). It is built on Python 3.14, so documents may use
|
|
40
|
+
`tex(t"...")` even on machines without 3.14. (`--build` still needs `tectonic`,
|
|
41
|
+
which pytex downloads on first use.)
|
|
42
|
+
|
|
43
|
+
### From PyPI
|
|
44
|
+
|
|
31
45
|
To use the `pytex` command anywhere, install it as an isolated tool with
|
|
32
46
|
[pipx](https://pipx.pypa.io/):
|
|
33
47
|
|
|
@@ -82,6 +96,22 @@ pytex example.tex.py --build # render + compile -> build/example.out.pdf
|
|
|
82
96
|
|
|
83
97
|
Bare strings are coerced to text nodes and LaTeX-escaped.
|
|
84
98
|
|
|
99
|
+
### Template strings (Python 3.14+)
|
|
100
|
+
|
|
101
|
+
On Python 3.14, `pytex.tex` accepts a [PEP 750](https://peps.python.org/pep-0750/)
|
|
102
|
+
template string and builds a `TeX` tree from it. Static parts are literal LaTeX;
|
|
103
|
+
interpolations are LaTeX-escaped when they are plain values and spliced as-is
|
|
104
|
+
when they are `TeX` nodes (nested template strings and lists are handled too):
|
|
105
|
+
|
|
106
|
+
```py
|
|
107
|
+
from pytex import tex
|
|
108
|
+
|
|
109
|
+
name = "Q&A: 50%"
|
|
110
|
+
body = tex(t"{Bold('Heading')} — {name}") # node spliced; name -> "Q\&A: 50\%"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`tex` is only exported on 3.14+; the rest of the library runs on 3.13.
|
|
114
|
+
|
|
85
115
|
## The `pytex` command
|
|
86
116
|
|
|
87
117
|
The input file is dispatched by extension:
|
|
@@ -14,6 +14,20 @@ uses.
|
|
|
14
14
|
|
|
15
15
|
## Install
|
|
16
16
|
|
|
17
|
+
### Prebuilt binary
|
|
18
|
+
|
|
19
|
+
Each release attaches standalone `pytex` binaries (Linux/macOS/Windows) — no
|
|
20
|
+
Python or `pip` needed. Download one from the
|
|
21
|
+
[Releases](https://github.com/frederikbeimgraben/PyTeX-Preprocessor/releases)
|
|
22
|
+
page, make it executable, and run it. The binary bundles its own interpreter
|
|
23
|
+
plus common data packages (numpy, pandas, openpyxl/calamine for spreadsheets,
|
|
24
|
+
Pillow, PyYAML), so documents can `import` those without installing anything;
|
|
25
|
+
see [`packaging/`](packaging/). It is built on Python 3.14, so documents may use
|
|
26
|
+
`tex(t"...")` even on machines without 3.14. (`--build` still needs `tectonic`,
|
|
27
|
+
which pytex downloads on first use.)
|
|
28
|
+
|
|
29
|
+
### From PyPI
|
|
30
|
+
|
|
17
31
|
To use the `pytex` command anywhere, install it as an isolated tool with
|
|
18
32
|
[pipx](https://pipx.pypa.io/):
|
|
19
33
|
|
|
@@ -68,6 +82,22 @@ pytex example.tex.py --build # render + compile -> build/example.out.pdf
|
|
|
68
82
|
|
|
69
83
|
Bare strings are coerced to text nodes and LaTeX-escaped.
|
|
70
84
|
|
|
85
|
+
### Template strings (Python 3.14+)
|
|
86
|
+
|
|
87
|
+
On Python 3.14, `pytex.tex` accepts a [PEP 750](https://peps.python.org/pep-0750/)
|
|
88
|
+
template string and builds a `TeX` tree from it. Static parts are literal LaTeX;
|
|
89
|
+
interpolations are LaTeX-escaped when they are plain values and spliced as-is
|
|
90
|
+
when they are `TeX` nodes (nested template strings and lists are handled too):
|
|
91
|
+
|
|
92
|
+
```py
|
|
93
|
+
from pytex import tex
|
|
94
|
+
|
|
95
|
+
name = "Q&A: 50%"
|
|
96
|
+
body = tex(t"{Bold('Heading')} — {name}") # node spliced; name -> "Q\&A: 50\%"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`tex` is only exported on 3.14+; the rest of the library runs on 3.13.
|
|
100
|
+
|
|
71
101
|
## The `pytex` command
|
|
72
102
|
|
|
73
103
|
The input file is dispatched by extension:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pytex-preprocessor"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Frederik Beimgraben", email="frederik@beimgraben.net" },
|
|
10
10
|
]
|
|
@@ -37,6 +37,9 @@ addopts = "--import-mode=importlib"
|
|
|
37
37
|
line-length = 88
|
|
38
38
|
target-version = "py313"
|
|
39
39
|
src = ["src", "tests"]
|
|
40
|
+
# Uses Python 3.14 t-string syntax; the py313 target cannot parse it. Excluded
|
|
41
|
+
# from lint/format (it is exercised by pytest on 3.14).
|
|
42
|
+
extend-exclude = ["tests/pytex/test_template.py"]
|
|
40
43
|
|
|
41
44
|
[tool.ruff.lint]
|
|
42
45
|
select = [
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
1
3
|
from . import packages
|
|
2
4
|
from .commands import (
|
|
3
5
|
biblatex,
|
|
@@ -87,3 +89,10 @@ __all__ = [
|
|
|
87
89
|
"tables",
|
|
88
90
|
"with_package",
|
|
89
91
|
]
|
|
92
|
+
|
|
93
|
+
# `tex(t"...")` needs PEP 750 template strings (Python 3.14+). Exposed only
|
|
94
|
+
# there; the rest of the library stays importable on 3.13.
|
|
95
|
+
if sys.version_info >= (3, 14):
|
|
96
|
+
from .template import tex as tex # pyright: ignore[reportUnreachable]
|
|
97
|
+
|
|
98
|
+
__all__.append("tex")
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
r"""`tex(t"...")` — build a `TeX` tree from a template string (PEP 750).
|
|
2
|
+
|
|
3
|
+
Requires Python 3.14 (the ``t"..."`` syntax and :mod:`string.templatelib`).
|
|
4
|
+
This module is import-safe on older versions — it contains no t-string literals
|
|
5
|
+
and guards the runtime import — but :func:`tex` can only be called with a real
|
|
6
|
+
``Template``, which cannot exist before 3.14. ``pytex`` only re-exports it on
|
|
7
|
+
3.14+.
|
|
8
|
+
|
|
9
|
+
The rendering model mirrors the escape boundary a LaTeX document needs:
|
|
10
|
+
|
|
11
|
+
* static template parts are literal LaTeX (author-written, trusted);
|
|
12
|
+
* interpolations are escaped when they are plain values, spliced as-is when
|
|
13
|
+
they are `TeX` nodes, and recursed when they are nested template strings or
|
|
14
|
+
iterables of the above.
|
|
15
|
+
|
|
16
|
+
name = "Q&A: 50%"
|
|
17
|
+
tex(t"{Bold('Heading')} - {name}") # node spliced; name -> "Q\&A: 50\%"
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
# `string.templatelib` has no type stub before 3.14, so a type-checker running
|
|
21
|
+
# on an older Python cannot type the `Template` import; silence that noise for
|
|
22
|
+
# this module only (its logic is exercised on 3.14 in CI / the docker test).
|
|
23
|
+
# pyright: reportMissingImports=false, reportUnknownVariableType=false
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from typing import TYPE_CHECKING, cast
|
|
27
|
+
|
|
28
|
+
from .helpers.sanitize import escape_latex
|
|
29
|
+
from .interface.tex import TeX
|
|
30
|
+
from .model.concat import Concat
|
|
31
|
+
from .model.empty import Empty
|
|
32
|
+
from .model.raw import Raw
|
|
33
|
+
|
|
34
|
+
if TYPE_CHECKING:
|
|
35
|
+
from collections.abc import Iterator
|
|
36
|
+
from typing import Protocol
|
|
37
|
+
|
|
38
|
+
class _Interpolation(Protocol):
|
|
39
|
+
@property
|
|
40
|
+
def value(self) -> object: ...
|
|
41
|
+
@property
|
|
42
|
+
def conversion(self) -> str | None: ...
|
|
43
|
+
@property
|
|
44
|
+
def format_spec(self) -> str: ...
|
|
45
|
+
|
|
46
|
+
class _Template(Protocol):
|
|
47
|
+
def __iter__(self) -> Iterator[str | _Interpolation]: ...
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# Real `Template` class at runtime (3.14+) for the nested-template check; an
|
|
51
|
+
# empty tuple on older versions makes the isinstance test always False.
|
|
52
|
+
try:
|
|
53
|
+
from string.templatelib import Template
|
|
54
|
+
|
|
55
|
+
_template_classes = (Template,)
|
|
56
|
+
except ImportError: # Python < 3.14
|
|
57
|
+
_template_classes = ()
|
|
58
|
+
|
|
59
|
+
_TEMPLATE_TYPES: tuple[type, ...] = _template_classes
|
|
60
|
+
|
|
61
|
+
__all__ = ["tex"]
|
|
62
|
+
|
|
63
|
+
_CONVERSIONS = {"r": repr, "s": str, "a": ascii}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def tex(template: _Template) -> TeX:
|
|
67
|
+
"""Render a t-string into a `TeX` tree (see the module docstring)."""
|
|
68
|
+
parts: list[TeX] = []
|
|
69
|
+
for item in template:
|
|
70
|
+
if isinstance(item, str):
|
|
71
|
+
parts.append(Raw(item)) # literal LaTeX
|
|
72
|
+
else:
|
|
73
|
+
parts.append(_coerce(item.value, item.conversion, item.format_spec))
|
|
74
|
+
return Concat(*parts)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _coerce(value: object, conversion: str | None = None, spec: object = "") -> TeX:
|
|
78
|
+
if value is None:
|
|
79
|
+
return Empty
|
|
80
|
+
if isinstance(value, TeX):
|
|
81
|
+
return value
|
|
82
|
+
if isinstance(value, _TEMPLATE_TYPES):
|
|
83
|
+
return tex(cast("_Template", value))
|
|
84
|
+
if isinstance(value, (list, tuple)):
|
|
85
|
+
items = cast("tuple[object, ...] | list[object]", value)
|
|
86
|
+
return Concat(*(_coerce(item) for item in items))
|
|
87
|
+
if conversion in _CONVERSIONS:
|
|
88
|
+
value = _CONVERSIONS[conversion](value)
|
|
89
|
+
text = format(value, spec if isinstance(spec, str) else "")
|
|
90
|
+
return Raw(escape_latex(text))
|
|
@@ -12,6 +12,7 @@ import json
|
|
|
12
12
|
import re
|
|
13
13
|
import sys
|
|
14
14
|
from dataclasses import dataclass
|
|
15
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
15
16
|
from pathlib import Path
|
|
16
17
|
from typing import TYPE_CHECKING, cast
|
|
17
18
|
|
|
@@ -76,11 +77,21 @@ def _slug(name: str) -> str:
|
|
|
76
77
|
return name or "document"
|
|
77
78
|
|
|
78
79
|
|
|
80
|
+
def _version() -> str:
|
|
81
|
+
try:
|
|
82
|
+
return version("pytex-preprocessor")
|
|
83
|
+
except PackageNotFoundError:
|
|
84
|
+
return "unknown"
|
|
85
|
+
|
|
86
|
+
|
|
79
87
|
def _parse_args(argv: list[str]) -> Config:
|
|
80
88
|
parser = argparse.ArgumentParser(
|
|
81
89
|
prog="pytex",
|
|
82
90
|
description="Render PyTeX (.py) or LaTeX (.tex) sources and build PDFs.",
|
|
83
91
|
)
|
|
92
|
+
_ = parser.add_argument(
|
|
93
|
+
"--version", action="version", version=f"pytex {_version()}"
|
|
94
|
+
)
|
|
84
95
|
_ = parser.add_argument(
|
|
85
96
|
"input",
|
|
86
97
|
type=Path,
|
{pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_preprocessor.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytex-preprocessor
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Type-safe LaTeX document generation with Python
|
|
5
5
|
Author-email: Frederik Beimgraben <frederik@beimgraben.net>
|
|
6
6
|
Requires-Python: >=3.13
|
|
@@ -28,6 +28,20 @@ uses.
|
|
|
28
28
|
|
|
29
29
|
## Install
|
|
30
30
|
|
|
31
|
+
### Prebuilt binary
|
|
32
|
+
|
|
33
|
+
Each release attaches standalone `pytex` binaries (Linux/macOS/Windows) — no
|
|
34
|
+
Python or `pip` needed. Download one from the
|
|
35
|
+
[Releases](https://github.com/frederikbeimgraben/PyTeX-Preprocessor/releases)
|
|
36
|
+
page, make it executable, and run it. The binary bundles its own interpreter
|
|
37
|
+
plus common data packages (numpy, pandas, openpyxl/calamine for spreadsheets,
|
|
38
|
+
Pillow, PyYAML), so documents can `import` those without installing anything;
|
|
39
|
+
see [`packaging/`](packaging/). It is built on Python 3.14, so documents may use
|
|
40
|
+
`tex(t"...")` even on machines without 3.14. (`--build` still needs `tectonic`,
|
|
41
|
+
which pytex downloads on first use.)
|
|
42
|
+
|
|
43
|
+
### From PyPI
|
|
44
|
+
|
|
31
45
|
To use the `pytex` command anywhere, install it as an isolated tool with
|
|
32
46
|
[pipx](https://pipx.pypa.io/):
|
|
33
47
|
|
|
@@ -82,6 +96,22 @@ pytex example.tex.py --build # render + compile -> build/example.out.pdf
|
|
|
82
96
|
|
|
83
97
|
Bare strings are coerced to text nodes and LaTeX-escaped.
|
|
84
98
|
|
|
99
|
+
### Template strings (Python 3.14+)
|
|
100
|
+
|
|
101
|
+
On Python 3.14, `pytex.tex` accepts a [PEP 750](https://peps.python.org/pep-0750/)
|
|
102
|
+
template string and builds a `TeX` tree from it. Static parts are literal LaTeX;
|
|
103
|
+
interpolations are LaTeX-escaped when they are plain values and spliced as-is
|
|
104
|
+
when they are `TeX` nodes (nested template strings and lists are handled too):
|
|
105
|
+
|
|
106
|
+
```py
|
|
107
|
+
from pytex import tex
|
|
108
|
+
|
|
109
|
+
name = "Q&A: 50%"
|
|
110
|
+
body = tex(t"{Bold('Heading')} — {name}") # node spliced; name -> "Q\&A: 50\%"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`tex` is only exported on 3.14+; the rest of the library runs on 3.13.
|
|
114
|
+
|
|
85
115
|
## The `pytex` command
|
|
86
116
|
|
|
87
117
|
The input file is dispatched by extension:
|
|
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.3.0 → pytex_preprocessor-0.4.0}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/logos/ASTA.svg
RENAMED
|
File without changes
|
{pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/logos/DUMMY.png
RENAMED
|
File without changes
|
|
File without changes
|
{pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/logos/ECHO.svg
RENAMED
|
File without changes
|
{pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/logos/HSRT.pdf
RENAMED
|
File without changes
|
{pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/logos/INF.pdf
RENAMED
|
File without changes
|
{pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/logos/STUPA.pdf
RENAMED
|
File without changes
|
{pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/assets/logos/Skyline.pdf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/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.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/hyperref_config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_hsrtreport/tex/pagesetup.tex
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
|
{pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/src/pytex_preprocessor.egg-info/requires.txt
RENAMED
|
File without changes
|
{pytex_preprocessor-0.3.0 → pytex_preprocessor-0.4.0}/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
|
|
File without changes
|