pytex-preprocessor 0.1.0__py3-none-any.whl

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.
Files changed (119) hide show
  1. pytex/__init__.py +87 -0
  2. pytex/commands/__init__.py +51 -0
  3. pytex/commands/biblatex.py +98 -0
  4. pytex/commands/builtin.py +598 -0
  5. pytex/commands/captions.py +56 -0
  6. pytex/commands/cleveref.py +43 -0
  7. pytex/commands/colors.py +60 -0
  8. pytex/commands/conditionals.py +62 -0
  9. pytex/commands/counters.py +85 -0
  10. pytex/commands/definitions.py +109 -0
  11. pytex/commands/floats.py +93 -0
  12. pytex/commands/font.py +138 -0
  13. pytex/commands/fontawesome.py +88 -0
  14. pytex/commands/fontspec.py +75 -0
  15. pytex/commands/geometry.py +25 -0
  16. pytex/commands/glossaries.py +126 -0
  17. pytex/commands/graphics.py +68 -0
  18. pytex/commands/hooks.py +58 -0
  19. pytex/commands/hyperref.py +57 -0
  20. pytex/commands/lengths.py +200 -0
  21. pytex/commands/listings.py +63 -0
  22. pytex/commands/mdframed.py +43 -0
  23. pytex/commands/picture.py +32 -0
  24. pytex/commands/setspace.py +38 -0
  25. pytex/commands/tables.py +123 -0
  26. pytex/helpers/__init__.py +3 -0
  27. pytex/helpers/coerce.py +13 -0
  28. pytex/helpers/parenting.py +13 -0
  29. pytex/helpers/sanitize.py +54 -0
  30. pytex/helpers/with_package.py +61 -0
  31. pytex/interface/__init__.py +3 -0
  32. pytex/interface/control_sequence.py +29 -0
  33. pytex/interface/package.py +52 -0
  34. pytex/interface/tex.py +41 -0
  35. pytex/model/__init__.py +25 -0
  36. pytex/model/color.py +203 -0
  37. pytex/model/concat.py +31 -0
  38. pytex/model/control_sequence.py +72 -0
  39. pytex/model/document.py +120 -0
  40. pytex/model/document_class.py +29 -0
  41. pytex/model/empty.py +19 -0
  42. pytex/model/environment.py +30 -0
  43. pytex/model/image.py +137 -0
  44. pytex/model/include.py +21 -0
  45. pytex/model/length.py +54 -0
  46. pytex/model/math.py +401 -0
  47. pytex/model/package.py +132 -0
  48. pytex/model/raw.py +61 -0
  49. pytex/packages.py +221 -0
  50. pytex/registry.py +49 -0
  51. pytex_builder/__init__.py +8 -0
  52. pytex_builder/build.py +175 -0
  53. pytex_builder/console.py +77 -0
  54. pytex_builder/render.py +90 -0
  55. pytex_builder/tectonic.py +370 -0
  56. pytex_hsrtreport/__init__.py +116 -0
  57. pytex_hsrtreport/assets/fonts/Blender/Blender-Bold.ttf +0 -0
  58. pytex_hsrtreport/assets/fonts/Blender/Blender-BoldItalic.ttf +0 -0
  59. pytex_hsrtreport/assets/fonts/Blender/Blender-Book.ttf +0 -0
  60. pytex_hsrtreport/assets/fonts/Blender/Blender-BookItalic.ttf +0 -0
  61. pytex_hsrtreport/assets/fonts/Blender/Blender-Medium.ttf +0 -0
  62. pytex_hsrtreport/assets/fonts/Blender/Blender-MediumItalic.ttf +0 -0
  63. pytex_hsrtreport/assets/fonts/Blender/Blender-Strong.ttf +0 -0
  64. pytex_hsrtreport/assets/fonts/Blender/Blender-Thin.ttf +0 -0
  65. pytex_hsrtreport/assets/fonts/Blender/Blender-ThinItalic.ttf +0 -0
  66. pytex_hsrtreport/assets/fonts/DIN/DIN-Black.ttf +0 -0
  67. pytex_hsrtreport/assets/fonts/DIN/DIN-Bold.ttf +0 -0
  68. pytex_hsrtreport/assets/fonts/DIN/DIN-BoldItalic.ttf +0 -0
  69. pytex_hsrtreport/assets/fonts/DIN/DIN-Italic.ttf +0 -0
  70. pytex_hsrtreport/assets/fonts/DIN/DIN-Medium.ttf +0 -0
  71. pytex_hsrtreport/assets/fonts/DIN/DIN-Regular.ttf +0 -0
  72. pytex_hsrtreport/assets/fonts/Times New Roman.ttf +0 -0
  73. pytex_hsrtreport/assets/logos/ASTA.svg +79 -0
  74. pytex_hsrtreport/assets/logos/DUMMY.png +0 -0
  75. pytex_hsrtreport/assets/logos/DUMMY_FOOT.png +0 -0
  76. pytex_hsrtreport/assets/logos/ECHO.svg +226 -0
  77. pytex_hsrtreport/assets/logos/HSRT.pdf +0 -0
  78. pytex_hsrtreport/assets/logos/INF.pdf +0 -0
  79. pytex_hsrtreport/assets/logos/STUPA.pdf +0 -0
  80. pytex_hsrtreport/assets/logos/Skyline.pdf +0 -0
  81. pytex_hsrtreport/boxes.py +215 -0
  82. pytex_hsrtreport/citations.py +21 -0
  83. pytex_hsrtreport/cleveref_names.py +47 -0
  84. pytex_hsrtreport/colors.py +30 -0
  85. pytex_hsrtreport/document.py +307 -0
  86. pytex_hsrtreport/fonts.py +66 -0
  87. pytex_hsrtreport/glossary.py +61 -0
  88. pytex_hsrtreport/hyperref_config.py +49 -0
  89. pytex_hsrtreport/listings.py +90 -0
  90. pytex_hsrtreport/logos.py +234 -0
  91. pytex_hsrtreport/pagebreak.py +67 -0
  92. pytex_hsrtreport/pagesetup.py +33 -0
  93. pytex_hsrtreport/tex/pagesetup.tex +76 -0
  94. pytex_hsrtreport/titlepage.py +136 -0
  95. pytex_hsrtreport/variants.py +24 -0
  96. pytex_hsrtreport/voting.py +96 -0
  97. pytex_hsrtreport/watermark.py +63 -0
  98. pytex_hsrtreport/wordcount.py +33 -0
  99. pytex_koma/__init__.py +90 -0
  100. pytex_koma/commands.py +296 -0
  101. pytex_koma/document.py +138 -0
  102. pytex_markdown/__init__.py +62 -0
  103. pytex_markdown/convert.py +271 -0
  104. pytex_markdown/escape.py +11 -0
  105. pytex_preprocessor-0.1.0.dist-info/METADATA +82 -0
  106. pytex_preprocessor-0.1.0.dist-info/RECORD +119 -0
  107. pytex_preprocessor-0.1.0.dist-info/WHEEL +5 -0
  108. pytex_preprocessor-0.1.0.dist-info/entry_points.txt +2 -0
  109. pytex_preprocessor-0.1.0.dist-info/top_level.txt +7 -0
  110. pytex_protocol/__init__.py +37 -0
  111. pytex_protocol/convert.py +202 -0
  112. pytex_protocol/document.py +91 -0
  113. pytex_protocol/entries.py +96 -0
  114. pytex_protocol/frontmatter.py +80 -0
  115. pytex_protocol/header.py +139 -0
  116. pytex_protocol/shortcodes.py +130 -0
  117. pytex_protocol/signatures.py +84 -0
  118. pytex_tikz/__init__.py +25 -0
  119. pytex_tikz/tikz.py +272 -0
pytex/model/math.py ADDED
@@ -0,0 +1,401 @@
1
+ from ..helpers.with_package import with_package
2
+ from ..interface.tex import TeX
3
+ from ..packages import AMSFONTS, AMSMATH
4
+ from ..registry import Registry
5
+ from .concat import Concat
6
+ from .control_sequence import ControlSequence, Parameter
7
+ from .environment import Environment
8
+ from .raw import Raw
9
+
10
+ __all__ = [
11
+ "Align",
12
+ "AlignStar",
13
+ "BBmatrix",
14
+ "Bar",
15
+ "Binom",
16
+ "Bmatrix",
17
+ "Cases",
18
+ "Ddot",
19
+ "Dfrac",
20
+ "DisplayMath",
21
+ "Dot",
22
+ "Eqref",
23
+ "Equation",
24
+ "EquationStar",
25
+ "Frac",
26
+ "Gather",
27
+ "GatherStar",
28
+ "Hat",
29
+ "IIInt",
30
+ "IInt",
31
+ "Int",
32
+ "LabelM",
33
+ "Lim",
34
+ "Math",
35
+ "Mathbb",
36
+ "Mathbf",
37
+ "Mathcal",
38
+ "Mathfrak",
39
+ "Mathit",
40
+ "Mathrm",
41
+ "Mathsf",
42
+ "Mathtt",
43
+ "Matrix",
44
+ "Multline",
45
+ "OInt",
46
+ "Operatorname",
47
+ "Overbrace",
48
+ "Overline",
49
+ "Pmatrix",
50
+ "Prod",
51
+ "Split",
52
+ "Sqrt",
53
+ "Sub",
54
+ "SubSuper",
55
+ "Substack",
56
+ "Sum",
57
+ "Super",
58
+ "Text",
59
+ "Tfrac",
60
+ "Tilde",
61
+ "Underbrace",
62
+ "UnderlineM",
63
+ "VVmatrix",
64
+ "Vec",
65
+ "Vmatrix",
66
+ ]
67
+
68
+
69
+ @Registry.add
70
+ def Math(body: TeX | str) -> TeX:
71
+ return Concat(
72
+ ControlSequence("(", ()),
73
+ body,
74
+ ControlSequence(")", ()),
75
+ )
76
+
77
+
78
+ @Registry.add
79
+ def DisplayMath(body: TeX | str) -> TeX:
80
+ return Concat(
81
+ ControlSequence("[", ()),
82
+ body,
83
+ ControlSequence("]", ()),
84
+ )
85
+
86
+
87
+ @Registry.add
88
+ def Equation(body: TeX | str) -> TeX:
89
+ return Environment("equation", body)
90
+
91
+
92
+ @Registry.add
93
+ def EquationStar(body: TeX | str) -> TeX:
94
+ return Environment("equation*", body)
95
+
96
+
97
+ @Registry.add
98
+ @with_package(AMSMATH)
99
+ def Align(body: TeX | str) -> TeX:
100
+ return Environment("align", body)
101
+
102
+
103
+ @Registry.add
104
+ @with_package(AMSMATH)
105
+ def AlignStar(body: TeX | str) -> TeX:
106
+ return Environment("align*", body)
107
+
108
+
109
+ @Registry.add
110
+ @with_package(AMSMATH)
111
+ def Gather(body: TeX | str) -> TeX:
112
+ return Environment("gather", body)
113
+
114
+
115
+ @Registry.add
116
+ @with_package(AMSMATH)
117
+ def GatherStar(body: TeX | str) -> TeX:
118
+ return Environment("gather*", body)
119
+
120
+
121
+ @Registry.add
122
+ @with_package(AMSMATH)
123
+ def Multline(body: TeX | str) -> TeX:
124
+ return Environment("multline", body)
125
+
126
+
127
+ @Registry.add
128
+ @with_package(AMSMATH)
129
+ def Split(body: TeX | str) -> TeX:
130
+ return Environment("split", body)
131
+
132
+
133
+ @Registry.add
134
+ @with_package(AMSMATH)
135
+ def Cases(body: TeX | str) -> TeX:
136
+ return Environment("cases", body)
137
+
138
+
139
+ def _matrix(kind: str, rows: list[list[TeX | str]]) -> TeX:
140
+ body_str = " \\\\ ".join(" & ".join(str(c) for c in row) for row in rows)
141
+ return Environment(kind, Raw(body_str))
142
+
143
+
144
+ @Registry.add
145
+ @with_package(AMSMATH)
146
+ def Matrix(rows: list[list[TeX | str]]) -> TeX:
147
+ return _matrix("matrix", rows)
148
+
149
+
150
+ @Registry.add
151
+ @with_package(AMSMATH)
152
+ def Pmatrix(rows: list[list[TeX | str]]) -> TeX:
153
+ return _matrix("pmatrix", rows)
154
+
155
+
156
+ @Registry.add
157
+ @with_package(AMSMATH)
158
+ def Bmatrix(rows: list[list[TeX | str]]) -> TeX:
159
+ return _matrix("bmatrix", rows)
160
+
161
+
162
+ @Registry.add
163
+ @with_package(AMSMATH)
164
+ def Vmatrix(rows: list[list[TeX | str]]) -> TeX:
165
+ return _matrix("vmatrix", rows)
166
+
167
+
168
+ @Registry.add
169
+ @with_package(AMSMATH)
170
+ def BBmatrix(rows: list[list[TeX | str]]) -> TeX:
171
+ return _matrix("Bmatrix", rows)
172
+
173
+
174
+ @Registry.add
175
+ @with_package(AMSMATH)
176
+ def VVmatrix(rows: list[list[TeX | str]]) -> TeX:
177
+ return _matrix("Vmatrix", rows)
178
+
179
+
180
+ @Registry.add
181
+ def Frac(num: TeX | str, den: TeX | str) -> TeX:
182
+ return ControlSequence("frac", (Parameter(num), Parameter(den)))
183
+
184
+
185
+ @Registry.add
186
+ @with_package(AMSMATH)
187
+ def Dfrac(num: TeX | str, den: TeX | str) -> TeX:
188
+ return ControlSequence("dfrac", (Parameter(num), Parameter(den)))
189
+
190
+
191
+ @Registry.add
192
+ @with_package(AMSMATH)
193
+ def Tfrac(num: TeX | str, den: TeX | str) -> TeX:
194
+ return ControlSequence("tfrac", (Parameter(num), Parameter(den)))
195
+
196
+
197
+ @Registry.add
198
+ @with_package(AMSMATH)
199
+ def Binom(top: TeX | str, bot: TeX | str) -> TeX:
200
+ return ControlSequence("binom", (Parameter(top), Parameter(bot)))
201
+
202
+
203
+ @Registry.add
204
+ def Sqrt(body: TeX | str, n: TeX | str | None = None) -> TeX:
205
+ if n is None:
206
+ return ControlSequence("sqrt", (Parameter(body),))
207
+ return ControlSequence("sqrt", (Parameter(n, optional=True), Parameter(body)))
208
+
209
+
210
+ def _sub_super(base: TeX, sub: TeX | str | None, sup: TeX | str | None) -> TeX:
211
+ parts: list[TeX | str] = [base]
212
+ if sub is not None:
213
+ parts.append(Raw("_{"))
214
+ parts.append(sub)
215
+ parts.append(Raw("}"))
216
+ if sup is not None:
217
+ parts.append(Raw("^{"))
218
+ parts.append(sup)
219
+ parts.append(Raw("}"))
220
+ return Concat(*parts)
221
+
222
+
223
+ @Registry.add
224
+ def Sub(base: TeX | str, sub: TeX | str) -> TeX:
225
+ return _sub_super(base if isinstance(base, TeX) else Raw(base), sub, None)
226
+
227
+
228
+ @Registry.add
229
+ def Super(base: TeX | str, sup: TeX | str) -> TeX:
230
+ return _sub_super(base if isinstance(base, TeX) else Raw(base), None, sup)
231
+
232
+
233
+ @Registry.add
234
+ def SubSuper(base: TeX | str, sub: TeX | str, sup: TeX | str) -> TeX:
235
+ return _sub_super(base if isinstance(base, TeX) else Raw(base), sub, sup)
236
+
237
+
238
+ @Registry.add
239
+ def Sum(lower: TeX | str | None = None, upper: TeX | str | None = None) -> TeX:
240
+ return _sub_super(ControlSequence("sum", ()), lower, upper)
241
+
242
+
243
+ @Registry.add
244
+ def Prod(lower: TeX | str | None = None, upper: TeX | str | None = None) -> TeX:
245
+ return _sub_super(ControlSequence("prod", ()), lower, upper)
246
+
247
+
248
+ @Registry.add
249
+ def Int(lower: TeX | str | None = None, upper: TeX | str | None = None) -> TeX:
250
+ return _sub_super(ControlSequence("int", ()), lower, upper)
251
+
252
+
253
+ @Registry.add
254
+ def OInt(lower: TeX | str | None = None, upper: TeX | str | None = None) -> TeX:
255
+ return _sub_super(ControlSequence("oint", ()), lower, upper)
256
+
257
+
258
+ @Registry.add
259
+ @with_package(AMSMATH)
260
+ def IInt(lower: TeX | str | None = None, upper: TeX | str | None = None) -> TeX:
261
+ return _sub_super(ControlSequence("iint", ()), lower, upper)
262
+
263
+
264
+ @Registry.add
265
+ @with_package(AMSMATH)
266
+ def IIInt(lower: TeX | str | None = None, upper: TeX | str | None = None) -> TeX:
267
+ return _sub_super(ControlSequence("iiint", ()), lower, upper)
268
+
269
+
270
+ @Registry.add
271
+ def Lim(var: TeX | str, to: TeX | str) -> TeX:
272
+ return _sub_super(
273
+ ControlSequence("lim", ()),
274
+ Concat(
275
+ var if isinstance(var, TeX) else Raw(var),
276
+ Raw(" \\to "),
277
+ to if isinstance(to, TeX) else Raw(to),
278
+ ),
279
+ None,
280
+ )
281
+
282
+
283
+ @Registry.add
284
+ @with_package(AMSMATH)
285
+ def Text(body: TeX | str) -> TeX:
286
+ return ControlSequence("text", (Parameter(body),))
287
+
288
+
289
+ @Registry.add
290
+ @with_package(AMSFONTS)
291
+ def Mathbb(body: TeX | str) -> TeX:
292
+ return ControlSequence("mathbb", (Parameter(body),))
293
+
294
+
295
+ @Registry.add
296
+ def Mathcal(body: TeX | str) -> TeX:
297
+ return ControlSequence("mathcal", (Parameter(body),))
298
+
299
+
300
+ @Registry.add
301
+ @with_package(AMSFONTS)
302
+ def Mathfrak(body: TeX | str) -> TeX:
303
+ return ControlSequence("mathfrak", (Parameter(body),))
304
+
305
+
306
+ @Registry.add
307
+ def Mathbf(body: TeX | str) -> TeX:
308
+ return ControlSequence("mathbf", (Parameter(body),))
309
+
310
+
311
+ @Registry.add
312
+ def Mathit(body: TeX | str) -> TeX:
313
+ return ControlSequence("mathit", (Parameter(body),))
314
+
315
+
316
+ @Registry.add
317
+ def Mathrm(body: TeX | str) -> TeX:
318
+ return ControlSequence("mathrm", (Parameter(body),))
319
+
320
+
321
+ @Registry.add
322
+ def Mathsf(body: TeX | str) -> TeX:
323
+ return ControlSequence("mathsf", (Parameter(body),))
324
+
325
+
326
+ @Registry.add
327
+ def Mathtt(body: TeX | str) -> TeX:
328
+ return ControlSequence("mathtt", (Parameter(body),))
329
+
330
+
331
+ @Registry.add
332
+ def Overline(body: TeX | str) -> TeX:
333
+ return ControlSequence("overline", (Parameter(body),))
334
+
335
+
336
+ @Registry.add
337
+ def UnderlineM(body: TeX | str) -> TeX:
338
+ return ControlSequence("underline", (Parameter(body),))
339
+
340
+
341
+ @Registry.add
342
+ def Overbrace(body: TeX | str) -> TeX:
343
+ return ControlSequence("overbrace", (Parameter(body),))
344
+
345
+
346
+ @Registry.add
347
+ def Underbrace(body: TeX | str) -> TeX:
348
+ return ControlSequence("underbrace", (Parameter(body),))
349
+
350
+
351
+ @Registry.add
352
+ def Hat(body: TeX | str) -> TeX:
353
+ return ControlSequence("hat", (Parameter(body),))
354
+
355
+
356
+ @Registry.add
357
+ def Tilde(body: TeX | str) -> TeX:
358
+ return ControlSequence("tilde", (Parameter(body),))
359
+
360
+
361
+ @Registry.add
362
+ def Bar(body: TeX | str) -> TeX:
363
+ return ControlSequence("bar", (Parameter(body),))
364
+
365
+
366
+ @Registry.add
367
+ def Vec(body: TeX | str) -> TeX:
368
+ return ControlSequence("vec", (Parameter(body),))
369
+
370
+
371
+ @Registry.add
372
+ def Dot(body: TeX | str) -> TeX:
373
+ return ControlSequence("dot", (Parameter(body),))
374
+
375
+
376
+ @Registry.add
377
+ def Ddot(body: TeX | str) -> TeX:
378
+ return ControlSequence("ddot", (Parameter(body),))
379
+
380
+
381
+ @Registry.add
382
+ def LabelM(name: str) -> TeX:
383
+ return ControlSequence("label", (Parameter(name),))
384
+
385
+
386
+ @Registry.add
387
+ @with_package(AMSMATH)
388
+ def Eqref(name: str) -> TeX:
389
+ return ControlSequence("eqref", (Parameter(name),))
390
+
391
+
392
+ @Registry.add
393
+ @with_package(AMSMATH)
394
+ def Operatorname(name: str) -> TeX:
395
+ return ControlSequence("operatorname", (Parameter(name),))
396
+
397
+
398
+ @Registry.add
399
+ @with_package(AMSMATH)
400
+ def Substack(body: TeX | str) -> TeX:
401
+ return ControlSequence("substack", (Parameter(body),))
pytex/model/package.py ADDED
@@ -0,0 +1,132 @@
1
+ from logging import Logger
2
+ from typing import Self, override
3
+
4
+ from ..interface.package import PackageProtocol
5
+ from ..interface.tex import TeX
6
+ from ..registry import Registry
7
+
8
+ __all__ = ["DefinePackage", "Package"]
9
+
10
+ PACKAGES = dict[str, "Package"]()
11
+
12
+ type PackageOption = str | tuple[str, str]
13
+
14
+
15
+ @Registry.add
16
+ class Package(PackageProtocol, TeX):
17
+ _name: str
18
+ _after: set[Self]
19
+ _incompatible: set[Self]
20
+ _options: set[PackageOption]
21
+
22
+ def __init__(
23
+ self,
24
+ name: str,
25
+ after: set[Self] | frozenset[Self] | None = None,
26
+ incompatible: set[Self] | frozenset[Self] | None = None,
27
+ options: set[PackageOption] | frozenset[PackageOption] | None = None,
28
+ ) -> None:
29
+ self._name, self._after, self._incompatible, self._options = (
30
+ name,
31
+ set(after or set()),
32
+ set(incompatible or set()),
33
+ set(options or set()),
34
+ )
35
+
36
+ @property
37
+ @override
38
+ def name(self) -> str:
39
+ return self._name
40
+
41
+ @property
42
+ @override
43
+ def after(self) -> frozenset[Self]:
44
+ return frozenset(self._after)
45
+
46
+ @property
47
+ @override
48
+ def incompatible(self) -> frozenset[Self]:
49
+ return frozenset(self._incompatible)
50
+
51
+ @property
52
+ @override
53
+ def options(self) -> frozenset[PackageOption]:
54
+ return frozenset(self._options)
55
+
56
+ def amend(
57
+ self,
58
+ after: set[Self] | frozenset[Self] | None = None,
59
+ incompatible: set[Self] | frozenset[Self] | None = None,
60
+ ) -> None:
61
+ if after is not None:
62
+ self._after |= after
63
+ if incompatible is not None:
64
+ self._incompatible |= incompatible
65
+
66
+ def __post_init__(self) -> None:
67
+ if self.name not in PACKAGES:
68
+ PACKAGES[self.name] = self
69
+ else:
70
+ Logger(self.__class__.__name__).warning(
71
+ f"Multiple Instances of {self.name} in circulation!"
72
+ )
73
+
74
+ @property
75
+ def _options_string(self) -> str:
76
+ return (
77
+ f"[{
78
+ ','.join(
79
+ item if isinstance(item, str) else f'{item[0]}={item[1]}'
80
+ for item in self.options
81
+ )
82
+ }]"
83
+ if len(self.options) != 0
84
+ else ""
85
+ )
86
+
87
+ @property
88
+ @override
89
+ def rendered(self) -> str:
90
+ """Render this object to a valid LaTeX-String"""
91
+
92
+ return f"\\usepackage{self._options_string}{{{self.name}}}"
93
+
94
+ @property
95
+ @override
96
+ def children(self) -> tuple[Self, ...]:
97
+ return ()
98
+
99
+ @property
100
+ @override
101
+ def requires(self) -> frozenset[Self]:
102
+ return frozenset(self.after)
103
+
104
+ @override
105
+ def __str__(self) -> str:
106
+ return self.rendered
107
+
108
+
109
+ @Registry.add
110
+ def DefinePackage(
111
+ name: str,
112
+ after: set[Package] | None = None,
113
+ incompatible: set[Package] | None = None,
114
+ options: set[PackageOption] | None = None,
115
+ ) -> Package:
116
+ after, incompatible, options = (
117
+ after or set(),
118
+ incompatible or set(),
119
+ options or set(),
120
+ )
121
+ if name in PACKAGES:
122
+ PACKAGES[name].amend(after=after, incompatible=incompatible)
123
+ return PACKAGES[name]
124
+
125
+ pkg = Package(
126
+ name=name,
127
+ after=after,
128
+ incompatible=incompatible,
129
+ options=options,
130
+ )
131
+ PACKAGES[name] = pkg
132
+ return pkg
pytex/model/raw.py ADDED
@@ -0,0 +1,61 @@
1
+ # pyright: reportAny=false
2
+ import re
3
+ from dataclasses import dataclass, field
4
+ from typing import override
5
+
6
+ from ..interface.tex import TeX
7
+ from ..registry import Registry
8
+
9
+ __all__ = ["Raw", "pytex_namespace"]
10
+
11
+
12
+ def _nested_inner(depth: int) -> str:
13
+ inner = r"[^()]*"
14
+ for _ in range(depth):
15
+ inner = rf"(?:[^()]|\({inner}\))*"
16
+ return inner
17
+
18
+
19
+ PATTERN = re.compile(
20
+ rf"\\iffalse\s*\{{\s*pytex\s*\((?P<expr>{_nested_inner(8)})\)\s*\}}\s*\\fi",
21
+ re.DOTALL,
22
+ )
23
+
24
+
25
+ def pytex_namespace(extra: dict[str, object] | None = None) -> dict[str, object]:
26
+ """Namespace used to ``eval`` ``pytex(...)`` expressions.
27
+
28
+ Exposes Python builtins plus every Registry-registered factory, so the same
29
+ names work in both escape hatches: ``\\iffalse{pytex(...)}\\fi`` (TeX) and
30
+ ``[//]: # "..."`` (Markdown).
31
+ """
32
+ return {
33
+ "__builtins__": __builtins__,
34
+ **Registry.namespace(),
35
+ **(extra or {}),
36
+ }
37
+
38
+
39
+ def _evaluate(content: str, extra: dict[str, object]) -> str:
40
+ namespace = pytex_namespace(extra)
41
+
42
+ def _sub(match: re.Match[str]) -> str:
43
+ return str(eval(match.group("expr"), namespace))
44
+
45
+ return PATTERN.sub(_sub, content)
46
+
47
+
48
+ @Registry.add
49
+ @dataclass
50
+ class Raw(TeX):
51
+ content: str
52
+ namespace: dict[str, object] | None = field(default=None)
53
+ allow_replacements: bool = True
54
+ _parent: "TeX | None" = field(default=None, init=False, compare=False, repr=False)
55
+
56
+ @property
57
+ @override
58
+ def rendered(self) -> str:
59
+ if not self.allow_replacements or "\\iffalse" not in self.content:
60
+ return self.content
61
+ return _evaluate(self.content, self.namespace or {})