manim 0.18.0.post0__py3-none-any.whl → 0.19.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.
Potentially problematic release.
This version of manim might be problematic. Click here for more details.
- manim/__init__.py +3 -6
- manim/__main__.py +61 -20
- manim/_config/__init__.py +6 -3
- manim/_config/cli_colors.py +16 -8
- manim/_config/default.cfg +1 -3
- manim/_config/logger_utils.py +14 -8
- manim/_config/utils.py +651 -472
- manim/animation/animation.py +152 -5
- manim/animation/composition.py +80 -39
- manim/animation/creation.py +196 -14
- manim/animation/fading.py +5 -9
- manim/animation/indication.py +103 -47
- manim/animation/movement.py +22 -5
- manim/animation/rotation.py +3 -2
- manim/animation/specialized.py +4 -6
- manim/animation/speedmodifier.py +10 -5
- manim/animation/transform.py +4 -5
- manim/animation/transform_matching_parts.py +1 -1
- manim/animation/updaters/mobject_update_utils.py +17 -14
- manim/camera/camera.py +15 -6
- manim/cli/__init__.py +17 -0
- manim/cli/cfg/group.py +70 -44
- manim/cli/checkhealth/checks.py +93 -75
- manim/cli/checkhealth/commands.py +14 -5
- manim/cli/default_group.py +157 -25
- manim/cli/init/commands.py +32 -24
- manim/cli/plugins/commands.py +16 -3
- manim/cli/render/commands.py +72 -60
- manim/cli/render/ease_of_access_options.py +4 -3
- manim/cli/render/global_options.py +51 -15
- manim/cli/render/output_options.py +6 -5
- manim/cli/render/render_options.py +97 -32
- manim/constants.py +65 -19
- manim/gui/gui.py +2 -0
- manim/mobject/frame.py +0 -1
- manim/mobject/geometry/arc.py +112 -78
- manim/mobject/geometry/boolean_ops.py +32 -25
- manim/mobject/geometry/labeled.py +300 -77
- manim/mobject/geometry/line.py +132 -64
- manim/mobject/geometry/polygram.py +126 -30
- manim/mobject/geometry/shape_matchers.py +35 -15
- manim/mobject/geometry/tips.py +38 -29
- manim/mobject/graph.py +414 -133
- manim/mobject/graphing/coordinate_systems.py +126 -64
- manim/mobject/graphing/functions.py +25 -15
- manim/mobject/graphing/number_line.py +24 -10
- manim/mobject/graphing/probability.py +2 -10
- manim/mobject/graphing/scale.py +6 -5
- manim/mobject/matrix.py +17 -19
- manim/mobject/mobject.py +314 -165
- manim/mobject/opengl/opengl_compatibility.py +2 -0
- manim/mobject/opengl/opengl_geometry.py +30 -9
- manim/mobject/opengl/opengl_image_mobject.py +2 -0
- manim/mobject/opengl/opengl_mobject.py +509 -343
- manim/mobject/opengl/opengl_point_cloud_mobject.py +5 -7
- manim/mobject/opengl/opengl_surface.py +3 -2
- manim/mobject/opengl/opengl_three_dimensions.py +2 -0
- manim/mobject/opengl/opengl_vectorized_mobject.py +46 -79
- manim/mobject/svg/brace.py +63 -13
- manim/mobject/svg/svg_mobject.py +4 -3
- manim/mobject/table.py +11 -13
- manim/mobject/text/code_mobject.py +186 -548
- manim/mobject/text/numbers.py +9 -7
- manim/mobject/text/tex_mobject.py +23 -14
- manim/mobject/text/text_mobject.py +70 -24
- manim/mobject/three_d/polyhedra.py +98 -1
- manim/mobject/three_d/three_d_utils.py +4 -4
- manim/mobject/three_d/three_dimensions.py +62 -34
- manim/mobject/types/image_mobject.py +42 -24
- manim/mobject/types/point_cloud_mobject.py +105 -67
- manim/mobject/types/vectorized_mobject.py +496 -228
- manim/mobject/value_tracker.py +5 -4
- manim/mobject/vector_field.py +5 -5
- manim/opengl/__init__.py +3 -3
- manim/plugins/__init__.py +14 -1
- manim/plugins/plugins_flags.py +14 -8
- manim/renderer/cairo_renderer.py +20 -10
- manim/renderer/opengl_renderer.py +21 -23
- manim/renderer/opengl_renderer_window.py +2 -0
- manim/renderer/shader.py +2 -3
- manim/renderer/shader_wrapper.py +5 -2
- manim/renderer/vectorized_mobject_rendering.py +5 -0
- manim/scene/moving_camera_scene.py +23 -0
- manim/scene/scene.py +90 -43
- manim/scene/scene_file_writer.py +316 -165
- manim/scene/section.py +17 -15
- manim/scene/three_d_scene.py +13 -21
- manim/scene/vector_space_scene.py +22 -9
- manim/typing.py +830 -70
- manim/utils/bezier.py +1667 -399
- manim/utils/caching.py +13 -5
- manim/utils/color/AS2700.py +2 -0
- manim/utils/color/BS381.py +3 -0
- manim/utils/color/DVIPSNAMES.py +96 -0
- manim/utils/color/SVGNAMES.py +179 -0
- manim/utils/color/X11.py +3 -0
- manim/utils/color/XKCD.py +3 -0
- manim/utils/color/__init__.py +8 -5
- manim/utils/color/core.py +844 -309
- manim/utils/color/manim_colors.py +7 -9
- manim/utils/commands.py +48 -20
- manim/utils/config_ops.py +18 -13
- manim/utils/debug.py +8 -7
- manim/utils/deprecation.py +90 -40
- manim/utils/docbuild/__init__.py +17 -0
- manim/utils/docbuild/autoaliasattr_directive.py +234 -0
- manim/utils/docbuild/autocolor_directive.py +21 -17
- manim/utils/docbuild/manim_directive.py +50 -35
- manim/utils/docbuild/module_parsing.py +245 -0
- manim/utils/exceptions.py +6 -0
- manim/utils/family.py +5 -3
- manim/utils/family_ops.py +17 -4
- manim/utils/file_ops.py +26 -16
- manim/utils/hashing.py +9 -7
- manim/utils/images.py +10 -4
- manim/utils/ipython_magic.py +14 -8
- manim/utils/iterables.py +161 -119
- manim/utils/module_ops.py +57 -19
- manim/utils/opengl.py +83 -24
- manim/utils/parameter_parsing.py +32 -0
- manim/utils/paths.py +21 -23
- manim/utils/polylabel.py +168 -0
- manim/utils/qhull.py +218 -0
- manim/utils/rate_functions.py +74 -39
- manim/utils/simple_functions.py +24 -15
- manim/utils/sounds.py +7 -1
- manim/utils/space_ops.py +125 -69
- manim/utils/testing/__init__.py +17 -0
- manim/utils/testing/_frames_testers.py +13 -8
- manim/utils/testing/_show_diff.py +5 -3
- manim/utils/testing/_test_class_makers.py +33 -18
- manim/utils/testing/frames_comparison.py +27 -19
- manim/utils/tex.py +127 -197
- manim/utils/tex_file_writing.py +47 -45
- manim/utils/tex_templates.py +2 -1
- manim/utils/unit.py +6 -5
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/LICENSE.community +1 -1
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/METADATA +40 -39
- manim-0.19.0.dist-info/RECORD +221 -0
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/WHEEL +1 -1
- manim/cli/new/__init__.py +0 -0
- manim/cli/new/group.py +0 -189
- manim/plugins/import_plugins.py +0 -43
- manim-0.18.0.post0.dist-info/RECORD +0 -217
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/LICENSE +0 -0
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/entry_points.txt +0 -0
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import functools
|
|
4
4
|
import inspect
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import Callable
|
|
6
|
+
from typing import Any, Callable
|
|
7
7
|
|
|
8
8
|
import cairo
|
|
9
9
|
import pytest
|
|
@@ -14,7 +14,9 @@ from manim._config import tempconfig
|
|
|
14
14
|
from manim._config.utils import ManimConfig
|
|
15
15
|
from manim.camera.three_d_camera import ThreeDCamera
|
|
16
16
|
from manim.renderer.cairo_renderer import CairoRenderer
|
|
17
|
+
from manim.renderer.opengl_renderer import OpenGLRenderer
|
|
17
18
|
from manim.scene.three_d_scene import ThreeDScene
|
|
19
|
+
from manim.typing import StrPath
|
|
18
20
|
|
|
19
21
|
from ._frames_testers import _ControlDataWriter, _FramesTester
|
|
20
22
|
from ._test_class_makers import (
|
|
@@ -31,13 +33,13 @@ MIN_CAIRO_VERSION = 11800
|
|
|
31
33
|
|
|
32
34
|
|
|
33
35
|
def frames_comparison(
|
|
34
|
-
func=None,
|
|
36
|
+
func: Callable | None = None,
|
|
35
37
|
*,
|
|
36
38
|
last_frame: bool = True,
|
|
37
|
-
renderer_class=CairoRenderer,
|
|
38
|
-
base_scene=Scene,
|
|
39
|
-
**custom_config,
|
|
40
|
-
):
|
|
39
|
+
renderer_class: type[CairoRenderer | OpenGLRenderer] = CairoRenderer,
|
|
40
|
+
base_scene: type[Scene] = Scene,
|
|
41
|
+
**custom_config: Any,
|
|
42
|
+
) -> Callable:
|
|
41
43
|
"""Compares the frames generated by the test with control frames previously registered.
|
|
42
44
|
|
|
43
45
|
If there is no control frames for this test, the test will fail. To generate
|
|
@@ -60,7 +62,7 @@ def frames_comparison(
|
|
|
60
62
|
If the scene has a moving animation, then the test must set last_frame to False.
|
|
61
63
|
"""
|
|
62
64
|
|
|
63
|
-
def decorator_maker(tested_scene_construct):
|
|
65
|
+
def decorator_maker(tested_scene_construct: Callable) -> Callable:
|
|
64
66
|
if (
|
|
65
67
|
SCENE_PARAMETER_NAME
|
|
66
68
|
not in inspect.getfullargspec(tested_scene_construct).args
|
|
@@ -79,11 +81,14 @@ def frames_comparison(
|
|
|
79
81
|
"There is no module test name indicated for the graphical unit test. You have to declare __module_test__ in the test file.",
|
|
80
82
|
)
|
|
81
83
|
module_name = tested_scene_construct.__globals__.get("__module_test__")
|
|
84
|
+
assert isinstance(module_name, str)
|
|
82
85
|
test_name = tested_scene_construct.__name__[len("test_") :]
|
|
83
86
|
|
|
84
87
|
@functools.wraps(tested_scene_construct)
|
|
85
88
|
# The "request" parameter is meant to be used as a fixture by pytest. See below.
|
|
86
|
-
def wrapper(
|
|
89
|
+
def wrapper(
|
|
90
|
+
*args: Any, request: FixtureRequest, tmp_path: StrPath, **kwargs: Any
|
|
91
|
+
) -> None:
|
|
87
92
|
# check for cairo version
|
|
88
93
|
if (
|
|
89
94
|
renderer_class is CairoRenderer
|
|
@@ -146,13 +151,13 @@ def frames_comparison(
|
|
|
146
151
|
inspect.Parameter("tmp_path", inspect.Parameter.KEYWORD_ONLY),
|
|
147
152
|
]
|
|
148
153
|
new_sig = old_sig.replace(parameters=parameters)
|
|
149
|
-
wrapper.__signature__ = new_sig
|
|
154
|
+
wrapper.__signature__ = new_sig # type: ignore[attr-defined]
|
|
150
155
|
|
|
151
156
|
# Reach a bit into pytest internals to hoist the marks from our wrapped
|
|
152
157
|
# function.
|
|
153
|
-
|
|
158
|
+
wrapper.pytestmark = [] # type: ignore[attr-defined]
|
|
154
159
|
new_marks = getattr(tested_scene_construct, "pytestmark", [])
|
|
155
|
-
wrapper.pytestmark = new_marks
|
|
160
|
+
wrapper.pytestmark = new_marks # type: ignore[attr-defined]
|
|
156
161
|
return wrapper
|
|
157
162
|
|
|
158
163
|
# Case where the decorator is called with and without parentheses.
|
|
@@ -192,9 +197,10 @@ def _make_test_comparing_frames(
|
|
|
192
197
|
Callable[[], None]
|
|
193
198
|
The pytest test.
|
|
194
199
|
"""
|
|
195
|
-
|
|
196
200
|
if is_set_test_data_test:
|
|
197
|
-
frames_tester = _ControlDataWriter(
|
|
201
|
+
frames_tester: _FramesTester = _ControlDataWriter(
|
|
202
|
+
file_path, size_frame=size_frame
|
|
203
|
+
)
|
|
198
204
|
else:
|
|
199
205
|
frames_tester = _FramesTester(file_path, show_diff=show_diff)
|
|
200
206
|
|
|
@@ -205,7 +211,7 @@ def _make_test_comparing_frames(
|
|
|
205
211
|
)
|
|
206
212
|
testRenderer = _make_test_renderer_class(renderer_class)
|
|
207
213
|
|
|
208
|
-
def real_test():
|
|
214
|
+
def real_test() -> None:
|
|
209
215
|
with frames_tester.testing():
|
|
210
216
|
sceneTested = _make_test_scene_class(
|
|
211
217
|
base_scene=base_scene,
|
|
@@ -214,11 +220,13 @@ def _make_test_comparing_frames(
|
|
|
214
220
|
# If you pass a custom renderer to the Scene, the Camera class given as an argument in the Scene
|
|
215
221
|
# is not passed to the renderer. See __init__ of Scene.
|
|
216
222
|
# This potentially prevents OpenGL testing.
|
|
217
|
-
test_renderer=
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
223
|
+
test_renderer=(
|
|
224
|
+
testRenderer(file_writer_class=file_writer_class)
|
|
225
|
+
if base_scene is not ThreeDScene
|
|
226
|
+
else testRenderer(
|
|
227
|
+
file_writer_class=file_writer_class,
|
|
228
|
+
camera_class=ThreeDCamera,
|
|
229
|
+
)
|
|
222
230
|
), # testRenderer(file_writer_class=file_writer_class),
|
|
223
231
|
)
|
|
224
232
|
scene_tested = sceneTested(skip_animations=True)
|
manim/utils/tex.py
CHANGED
|
@@ -4,162 +4,135 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
__all__ = [
|
|
6
6
|
"TexTemplate",
|
|
7
|
-
"TexTemplateFromFile",
|
|
8
7
|
]
|
|
9
8
|
|
|
10
9
|
import copy
|
|
11
|
-
import os
|
|
12
10
|
import re
|
|
11
|
+
import warnings
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
13
|
from pathlib import Path
|
|
14
|
+
from typing import TYPE_CHECKING, Any
|
|
14
15
|
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from typing_extensions import Self
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
"""TeX templates are used for creating Tex() and MathTex() objects.
|
|
18
|
-
|
|
19
|
-
Parameters
|
|
20
|
-
----------
|
|
21
|
-
tex_compiler
|
|
22
|
-
The TeX compiler to be used, e.g. ``latex``, ``pdflatex`` or ``lualatex``
|
|
23
|
-
output_format
|
|
24
|
-
The output format resulting from compilation, e.g. ``.dvi`` or ``.pdf``
|
|
25
|
-
documentclass
|
|
26
|
-
The command defining the documentclass, e.g. ``\\documentclass[preview]{standalone}``
|
|
27
|
-
preamble
|
|
28
|
-
The document's preamble, i.e. the part between ``\\documentclass`` and ``\\begin{document}``
|
|
29
|
-
placeholder_text
|
|
30
|
-
Text in the document that will be replaced by the expression to be rendered
|
|
31
|
-
post_doc_commands
|
|
32
|
-
Text (definitions, commands) to be inserted at right after ``\\begin{document}``, e.g. ``\\boldmath``
|
|
33
|
-
|
|
34
|
-
Attributes
|
|
35
|
-
----------
|
|
36
|
-
tex_compiler : :class:`str`
|
|
37
|
-
The TeX compiler to be used, e.g. ``latex``, ``pdflatex`` or ``lualatex``
|
|
38
|
-
output_format : :class:`str`
|
|
39
|
-
The output format resulting from compilation, e.g. ``.dvi`` or ``.pdf``
|
|
40
|
-
documentclass : :class:`str`
|
|
41
|
-
The command defining the documentclass, e.g. ``\\documentclass[preview]{standalone}``
|
|
42
|
-
preamble : :class:`str`
|
|
43
|
-
The document's preamble, i.e. the part between ``\\documentclass`` and ``\\begin{document}``
|
|
44
|
-
placeholder_text : :class:`str`
|
|
45
|
-
Text in the document that will be replaced by the expression to be rendered
|
|
46
|
-
post_doc_commands : :class:`str`
|
|
47
|
-
Text (definitions, commands) to be inserted at right after ``\\begin{document}``, e.g. ``\\boldmath``
|
|
48
|
-
"""
|
|
19
|
+
from manim.typing import StrPath
|
|
49
20
|
|
|
50
|
-
|
|
51
|
-
default_preamble = r"""
|
|
52
|
-
\usepackage[english]{babel}
|
|
21
|
+
_DEFAULT_PREAMBLE = r"""\usepackage[english]{babel}
|
|
53
22
|
\usepackage{amsmath}
|
|
54
|
-
\usepackage{amssymb}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
default_post_doc_commands = ""
|
|
60
|
-
|
|
61
|
-
def __init__(
|
|
62
|
-
self,
|
|
63
|
-
tex_compiler: str | None = None,
|
|
64
|
-
output_format: str | None = None,
|
|
65
|
-
documentclass: str | None = None,
|
|
66
|
-
preamble: str | None = None,
|
|
67
|
-
placeholder_text: str | None = None,
|
|
68
|
-
post_doc_commands: str | None = None,
|
|
69
|
-
**kwargs,
|
|
70
|
-
):
|
|
71
|
-
self.tex_compiler = (
|
|
72
|
-
tex_compiler
|
|
73
|
-
if tex_compiler is not None
|
|
74
|
-
else TexTemplate.default_tex_compiler
|
|
75
|
-
)
|
|
76
|
-
self.output_format = (
|
|
77
|
-
output_format
|
|
78
|
-
if output_format is not None
|
|
79
|
-
else TexTemplate.default_output_format
|
|
80
|
-
)
|
|
81
|
-
self.documentclass = (
|
|
82
|
-
documentclass
|
|
83
|
-
if documentclass is not None
|
|
84
|
-
else TexTemplate.default_documentclass
|
|
85
|
-
)
|
|
86
|
-
self.preamble = (
|
|
87
|
-
preamble if preamble is not None else TexTemplate.default_preamble
|
|
88
|
-
)
|
|
89
|
-
self.placeholder_text = (
|
|
90
|
-
placeholder_text
|
|
91
|
-
if placeholder_text is not None
|
|
92
|
-
else TexTemplate.default_placeholder_text
|
|
93
|
-
)
|
|
94
|
-
self.post_doc_commands = (
|
|
95
|
-
post_doc_commands
|
|
96
|
-
if post_doc_commands is not None
|
|
97
|
-
else TexTemplate.default_post_doc_commands
|
|
98
|
-
)
|
|
99
|
-
self._rebuild()
|
|
100
|
-
|
|
101
|
-
def __eq__(self, other: TexTemplate) -> bool:
|
|
102
|
-
return (
|
|
103
|
-
self.body == other.body
|
|
104
|
-
and self.tex_compiler == other.tex_compiler
|
|
105
|
-
and self.output_format == other.output_format
|
|
106
|
-
and self.post_doc_commands == other.post_doc_commands
|
|
107
|
-
)
|
|
23
|
+
\usepackage{amssymb}"""
|
|
24
|
+
|
|
25
|
+
_BEGIN_DOCUMENT = r"\begin{document}"
|
|
26
|
+
_END_DOCUMENT = r"\end{document}"
|
|
27
|
+
|
|
108
28
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
29
|
+
@dataclass(eq=True)
|
|
30
|
+
class TexTemplate:
|
|
31
|
+
"""TeX templates are used to create ``Tex`` and ``MathTex`` objects."""
|
|
32
|
+
|
|
33
|
+
_body: str = field(default="", init=False)
|
|
34
|
+
"""A custom body, can be set from a file."""
|
|
35
|
+
|
|
36
|
+
tex_compiler: str = "latex"
|
|
37
|
+
"""The TeX compiler to be used, e.g. ``latex``, ``pdflatex`` or ``lualatex``."""
|
|
38
|
+
|
|
39
|
+
description: str = ""
|
|
40
|
+
"""A description of the template"""
|
|
41
|
+
|
|
42
|
+
output_format: str = ".dvi"
|
|
43
|
+
"""The output format resulting from compilation, e.g. ``.dvi`` or ``.pdf``."""
|
|
44
|
+
|
|
45
|
+
documentclass: str = r"\documentclass[preview]{standalone}"
|
|
46
|
+
r"""The command defining the documentclass, e.g. ``\documentclass[preview]{standalone}``."""
|
|
47
|
+
|
|
48
|
+
preamble: str = _DEFAULT_PREAMBLE
|
|
49
|
+
r"""The document's preamble, i.e. the part between ``\documentclass`` and ``\begin{document}``."""
|
|
50
|
+
|
|
51
|
+
placeholder_text: str = "YourTextHere"
|
|
52
|
+
"""Text in the document that will be replaced by the expression to be rendered."""
|
|
53
|
+
|
|
54
|
+
post_doc_commands: str = ""
|
|
55
|
+
r"""Text (definitions, commands) to be inserted at right after ``\begin{document}``, e.g. ``\boldmath``."""
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def body(self) -> str:
|
|
59
|
+
"""The entire TeX template."""
|
|
60
|
+
return self._body or "\n".join(
|
|
61
|
+
filter(
|
|
62
|
+
None,
|
|
63
|
+
[
|
|
64
|
+
self.documentclass,
|
|
65
|
+
self.preamble,
|
|
66
|
+
_BEGIN_DOCUMENT,
|
|
67
|
+
self.post_doc_commands,
|
|
68
|
+
self.placeholder_text,
|
|
69
|
+
_END_DOCUMENT,
|
|
70
|
+
],
|
|
71
|
+
)
|
|
125
72
|
)
|
|
126
73
|
|
|
127
|
-
|
|
128
|
-
|
|
74
|
+
@body.setter
|
|
75
|
+
def body(self, value: str) -> None:
|
|
76
|
+
self._body = value
|
|
77
|
+
|
|
78
|
+
@classmethod
|
|
79
|
+
def from_file(cls, file: StrPath = "tex_template.tex", **kwargs: Any) -> Self:
|
|
80
|
+
"""Create an instance by reading the content of a file.
|
|
81
|
+
|
|
82
|
+
Using the ``add_to_preamble`` and ``add_to_document`` methods on this instance
|
|
83
|
+
will have no effect, as the body is read from the file.
|
|
84
|
+
"""
|
|
85
|
+
instance = cls(**kwargs)
|
|
86
|
+
instance.body = Path(file).read_text(encoding="utf-8")
|
|
87
|
+
return instance
|
|
88
|
+
|
|
89
|
+
def add_to_preamble(self, txt: str, prepend: bool = False) -> Self:
|
|
90
|
+
r"""Adds text to the TeX template's preamble (e.g. definitions, packages). Text can be inserted at the beginning or at the end of the preamble.
|
|
129
91
|
|
|
130
92
|
Parameters
|
|
131
93
|
----------
|
|
132
94
|
txt
|
|
133
|
-
String containing the text to be added, e.g.
|
|
95
|
+
String containing the text to be added, e.g. ``\usepackage{hyperref}``.
|
|
134
96
|
prepend
|
|
135
|
-
Whether the text should be added at the beginning of the preamble, i.e. right after
|
|
97
|
+
Whether the text should be added at the beginning of the preamble, i.e. right after ``\documentclass``.
|
|
98
|
+
Default is to add it at the end of the preamble, i.e. right before ``\begin{document}``.
|
|
136
99
|
"""
|
|
100
|
+
if self._body:
|
|
101
|
+
warnings.warn(
|
|
102
|
+
"This TeX template was created with a fixed body, trying to add text the preamble will have no effect.",
|
|
103
|
+
UserWarning,
|
|
104
|
+
stacklevel=2,
|
|
105
|
+
)
|
|
137
106
|
if prepend:
|
|
138
107
|
self.preamble = txt + "\n" + self.preamble
|
|
139
108
|
else:
|
|
140
109
|
self.preamble += "\n" + txt
|
|
141
|
-
self._rebuild()
|
|
142
110
|
return self
|
|
143
111
|
|
|
144
|
-
def add_to_document(self, txt: str):
|
|
145
|
-
"""Adds
|
|
112
|
+
def add_to_document(self, txt: str) -> Self:
|
|
113
|
+
r"""Adds text to the TeX template just after \begin{document}, e.g. ``\boldmath``.
|
|
146
114
|
|
|
147
115
|
Parameters
|
|
148
116
|
----------
|
|
149
117
|
txt
|
|
150
118
|
String containing the text to be added.
|
|
151
119
|
"""
|
|
152
|
-
self.
|
|
153
|
-
|
|
120
|
+
if self._body:
|
|
121
|
+
warnings.warn(
|
|
122
|
+
"This TeX template was created with a fixed body, trying to add text the document will have no effect.",
|
|
123
|
+
UserWarning,
|
|
124
|
+
stacklevel=2,
|
|
125
|
+
)
|
|
126
|
+
self.post_doc_commands += txt
|
|
154
127
|
return self
|
|
155
128
|
|
|
156
|
-
def get_texcode_for_expression(self, expression: str):
|
|
157
|
-
"""Inserts expression verbatim into TeX template.
|
|
129
|
+
def get_texcode_for_expression(self, expression: str) -> str:
|
|
130
|
+
r"""Inserts expression verbatim into TeX template.
|
|
158
131
|
|
|
159
132
|
Parameters
|
|
160
133
|
----------
|
|
161
134
|
expression
|
|
162
|
-
The string containing the expression to be typeset, e.g.
|
|
135
|
+
The string containing the expression to be typeset, e.g. ``$\sqrt{2}$``
|
|
163
136
|
|
|
164
137
|
Returns
|
|
165
138
|
-------
|
|
@@ -168,102 +141,59 @@ class TexTemplate:
|
|
|
168
141
|
"""
|
|
169
142
|
return self.body.replace(self.placeholder_text, expression)
|
|
170
143
|
|
|
171
|
-
def
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
Parameters
|
|
176
|
-
----------
|
|
177
|
-
environment
|
|
178
|
-
The tex_environment as a string. Acceptable formats include:
|
|
179
|
-
``{align*}``, ``align*``, ``{tabular}[t]{cccl}``, ``tabular}{cccl``, ``\\begin{tabular}[t]{cccl}``.
|
|
180
|
-
|
|
181
|
-
Returns
|
|
182
|
-
-------
|
|
183
|
-
Tuple[:class:`str`, :class:`str`]
|
|
184
|
-
A pair of strings representing the opening and closing of the tex environment, e.g.
|
|
185
|
-
``\\begin{tabular}{cccl}`` and ``\\end{tabular}``
|
|
186
|
-
"""
|
|
187
|
-
|
|
188
|
-
# If the environment starts with \begin, remove it
|
|
189
|
-
if environment[0:6] == r"\begin":
|
|
190
|
-
environment = environment[6:]
|
|
191
|
-
|
|
192
|
-
# If environment begins with { strip it
|
|
193
|
-
if environment[0] == r"{":
|
|
194
|
-
environment = environment[1:]
|
|
195
|
-
|
|
196
|
-
# The \begin command takes everything and closes with a brace
|
|
197
|
-
begin = r"\begin{" + environment
|
|
198
|
-
if (
|
|
199
|
-
begin[-1] != r"}" and begin[-1] != r"]"
|
|
200
|
-
): # If it doesn't end on } or ], assume missing }
|
|
201
|
-
begin += r"}"
|
|
202
|
-
|
|
203
|
-
# While the \end command terminates at the first closing brace
|
|
204
|
-
split_at_brace = re.split(r"}", environment, 1)
|
|
205
|
-
end = r"\end{" + split_at_brace[0] + r"}"
|
|
206
|
-
|
|
207
|
-
return begin, end
|
|
208
|
-
|
|
209
|
-
def get_texcode_for_expression_in_env(self, expression: str, environment: str):
|
|
210
|
-
r"""Inserts expression into TeX template wrapped in \begin{environment} and \end{environment}
|
|
144
|
+
def get_texcode_for_expression_in_env(
|
|
145
|
+
self, expression: str, environment: str
|
|
146
|
+
) -> str:
|
|
147
|
+
r"""Inserts expression into TeX template wrapped in ``\begin{environment}`` and ``\end{environment}``.
|
|
211
148
|
|
|
212
149
|
Parameters
|
|
213
150
|
----------
|
|
214
151
|
expression
|
|
215
|
-
The string containing the expression to be typeset, e.g.
|
|
152
|
+
The string containing the expression to be typeset, e.g. ``$\sqrt{2}$``.
|
|
216
153
|
environment
|
|
217
|
-
The string containing the environment in which the expression should be typeset, e.g. ``align
|
|
154
|
+
The string containing the environment in which the expression should be typeset, e.g. ``align*``.
|
|
218
155
|
|
|
219
156
|
Returns
|
|
220
157
|
-------
|
|
221
158
|
:class:`str`
|
|
222
159
|
LaTeX code based on template, containing the given expression inside its environment, ready for typesetting
|
|
223
160
|
"""
|
|
224
|
-
begin, end =
|
|
225
|
-
return self.body.replace(
|
|
161
|
+
begin, end = _texcode_for_environment(environment)
|
|
162
|
+
return self.body.replace(
|
|
163
|
+
self.placeholder_text, "\n".join([begin, expression, end])
|
|
164
|
+
)
|
|
226
165
|
|
|
227
|
-
def copy(self) ->
|
|
166
|
+
def copy(self) -> Self:
|
|
167
|
+
"""Create a deep copy of the TeX template instance."""
|
|
228
168
|
return copy.deepcopy(self)
|
|
229
169
|
|
|
230
170
|
|
|
231
|
-
|
|
232
|
-
"""
|
|
171
|
+
def _texcode_for_environment(environment: str) -> tuple[str, str]:
|
|
172
|
+
r"""Processes the tex_environment string to return the correct ``\begin{environment}[extra]{extra}`` and
|
|
173
|
+
``\end{environment}`` strings.
|
|
233
174
|
|
|
234
175
|
Parameters
|
|
235
176
|
----------
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
body : :class:`str`
|
|
246
|
-
Content of the TeX template file
|
|
247
|
-
tex_compiler : :class:`str`
|
|
248
|
-
The TeX compiler to be used, e.g. ``latex``, ``pdflatex`` or ``lualatex``
|
|
249
|
-
output_format : :class:`str`
|
|
250
|
-
The output format resulting from compilation, e.g. ``.dvi`` or ``.pdf``
|
|
177
|
+
environment
|
|
178
|
+
The tex_environment as a string. Acceptable formats include:
|
|
179
|
+
``{align*}``, ``align*``, ``{tabular}[t]{cccl}``, ``tabular}{cccl``, ``\begin{tabular}[t]{cccl}``.
|
|
180
|
+
|
|
181
|
+
Returns
|
|
182
|
+
-------
|
|
183
|
+
Tuple[:class:`str`, :class:`str`]
|
|
184
|
+
A pair of strings representing the opening and closing of the tex environment, e.g.
|
|
185
|
+
``\begin{tabular}{cccl}`` and ``\end{tabular}``
|
|
251
186
|
"""
|
|
187
|
+
environment.removeprefix(r"\begin").removeprefix("{")
|
|
252
188
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
def _rebuild(self):
|
|
260
|
-
self.body = self.template_file.read_text()
|
|
261
|
-
|
|
262
|
-
def file_not_mutable(self):
|
|
263
|
-
raise Exception("Cannot modify TexTemplate when using a template file.")
|
|
189
|
+
# The \begin command takes everything and closes with a brace
|
|
190
|
+
begin = r"\begin{" + environment
|
|
191
|
+
# If it doesn't end on } or ], assume missing }
|
|
192
|
+
if not begin.endswith(("}", "]")):
|
|
193
|
+
begin += "}"
|
|
264
194
|
|
|
265
|
-
|
|
266
|
-
|
|
195
|
+
# While the \end command terminates at the first closing brace
|
|
196
|
+
split_at_brace = re.split("}", environment, maxsplit=1)
|
|
197
|
+
end = r"\end{" + split_at_brace[0] + "}"
|
|
267
198
|
|
|
268
|
-
|
|
269
|
-
self.file_not_mutable()
|
|
199
|
+
return begin, end
|