mirror of
https://github.com/jeertmans/manim-slides.git
synced 2025-05-19 11:36:37 +08:00
Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
528952dbc3 | |||
dbced6e62e | |||
941b895083 | |||
289b7c1683 | |||
b07a83898b | |||
074a029759 | |||
b4af76050e | |||
adce58e1b7 | |||
32ab690932 | |||
df31345f83 |
@ -21,7 +21,7 @@ repos:
|
|||||||
exclude: poetry.lock
|
exclude: poetry.lock
|
||||||
args: [--autofix, --trailing-commas]
|
args: [--autofix, --trailing-commas]
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.9.1
|
rev: v0.9.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff
|
- id: ruff
|
||||||
args: [--fix]
|
args: [--fix]
|
||||||
|
51
CHANGELOG.md
51
CHANGELOG.md
@ -8,7 +8,50 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
<!-- start changelog -->
|
<!-- start changelog -->
|
||||||
|
|
||||||
(unreleased)=
|
(unreleased)=
|
||||||
## [Unreleased](https://github.com/jeertmans/manim-slides/compare/v5.3.1...HEAD)
|
## [Unreleased](https://github.com/jeertmans/manim-slides/compare/v5.4.2...HEAD)
|
||||||
|
|
||||||
|
(v5.4.2)=
|
||||||
|
## [v5.4.2](https://github.com/jeertmans/manim-slides/compare/v5.4.1...v5.4.2)
|
||||||
|
|
||||||
|
(v5.4.2-fixed)=
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed `start_skip_animations` to actually pass argument to ManimCE,
|
||||||
|
otherwise video animations were still rendered, just excluded from
|
||||||
|
the final output.
|
||||||
|
[#524](https://github.com/jeertmans/manim-slides/pull/524)
|
||||||
|
|
||||||
|
(v5.4.1)=
|
||||||
|
## [v5.4.1](https://github.com/jeertmans/manim-slides/compare/v5.4.0...v5.4.1)
|
||||||
|
|
||||||
|
(v5.4.1-added)=
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added `start_skip_animations` and `stop_skip_animations` methods.
|
||||||
|
[#523](https://github.com/jeertmans/manim-slides/pull/523)
|
||||||
|
|
||||||
|
(v5.4.0)=
|
||||||
|
## [v5.4.0](https://github.com/jeertmans/manim-slides/compare/v5.3.1...v5.4.0)
|
||||||
|
|
||||||
|
(v5.4.0-added)=
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added `skip_animations` compatibility with ManimCE.
|
||||||
|
[@Rapsssito](https://github.com/Rapsssito) [#516](https://github.com/jeertmans/manim-slides/pull/516)
|
||||||
|
|
||||||
|
(v5.4.0-chore)=
|
||||||
|
### Chore
|
||||||
|
|
||||||
|
- Bumped Manim to `>=0.19`, as it fixed OpenGL renderer issue.
|
||||||
|
[#522](https://github.com/jeertmans/manim-slides/pull/522)
|
||||||
|
|
||||||
|
(v5.4.0-fixed)=
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed OpenGL renderer having no partial movie files with Manim bindings.
|
||||||
|
[#522](https://github.com/jeertmans/manim-slides/pull/522)
|
||||||
|
- Fixed `ConvertExample` example as `manim>=0.19` changed the `Code` class.
|
||||||
|
[#522](https://github.com/jeertmans/manim-slides/pull/522)
|
||||||
|
|
||||||
(v5.3.1)=
|
(v5.3.1)=
|
||||||
## [v5.3.1](https://github.com/jeertmans/manim-slides/compare/v5.3.0...v5.3.1)
|
## [v5.3.1](https://github.com/jeertmans/manim-slides/compare/v5.3.0...v5.3.1)
|
||||||
@ -54,11 +97,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
(v5.2.0-chore)=
|
(v5.2.0-chore)=
|
||||||
### Chore
|
### Chore
|
||||||
|
|
||||||
- Bump ManimGL to `>=1.7.1`, to remove conflicting dependencies
|
- Bumped ManimGL to `>=1.7.1`, to remove conflicting dependencies
|
||||||
with Manim's.
|
with Manim's.
|
||||||
[#499](https://github.com/jeertmans/manim-slides/pull/499)
|
[#499](https://github.com/jeertmans/manim-slides/pull/499)
|
||||||
|
|
||||||
- Bump ManimGL to `>=1.7.2`, to remove `pyrr` from dependencies,
|
- Bumped ManimGL to `>=1.7.2`, to remove `pyrr` from dependencies,
|
||||||
and to avoid complex code for supporting both `1.7.1` and `>=1.7.2`,
|
and to avoid complex code for supporting both `1.7.1` and `>=1.7.2`,
|
||||||
as the latter includes many breaking changes.
|
as the latter includes many breaking changes.
|
||||||
[#506](https://github.com/jeertmans/manim-slides/pull/506)
|
[#506](https://github.com/jeertmans/manim-slides/pull/506)
|
||||||
@ -121,7 +164,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
(v5.1.8-chore)=
|
(v5.1.8-chore)=
|
||||||
### Chore
|
### Chore
|
||||||
|
|
||||||
- Pin `rtoml==0.9.0` on Windows platforms,
|
- Pinned `rtoml==0.9.0` on Windows platforms,
|
||||||
see [#398](https://github.com/jeertmans/manim-slides/pull/398),
|
see [#398](https://github.com/jeertmans/manim-slides/pull/398),
|
||||||
until
|
until
|
||||||
[samuelcolvin/rtoml#74](https://github.com/samuelcolvin/rtoml/issues/74)
|
[samuelcolvin/rtoml#74](https://github.com/samuelcolvin/rtoml/issues/74)
|
||||||
|
@ -26,7 +26,7 @@ keywords:
|
|||||||
- PowerPoint
|
- PowerPoint
|
||||||
- Python
|
- Python
|
||||||
license: MIT
|
license: MIT
|
||||||
version: v5.3.1
|
version: v5.4.2
|
||||||
preferred-citation:
|
preferred-citation:
|
||||||
publisher:
|
publisher:
|
||||||
name: The Open Journal
|
name: The Open Journal
|
||||||
|
@ -18,6 +18,8 @@ use, not the methods used internally when rendering.
|
|||||||
next_section,
|
next_section,
|
||||||
next_slide,
|
next_slide,
|
||||||
remove_from_canvas,
|
remove_from_canvas,
|
||||||
|
start_skip_animations,
|
||||||
|
stop_skip_animations,
|
||||||
wait_time_between_slides,
|
wait_time_between_slides,
|
||||||
wipe,
|
wipe,
|
||||||
zoom,
|
zoom,
|
||||||
|
16
example.py
16
example.py
@ -53,7 +53,7 @@ class ConvertExample(Slide):
|
|||||||
self.next_slide()
|
self.next_slide()
|
||||||
|
|
||||||
code = Code(
|
code = Code(
|
||||||
code="""from manim import *
|
code_string="""from manim import *
|
||||||
|
|
||||||
|
|
||||||
class Example(Scene):
|
class Example(Scene):
|
||||||
@ -72,7 +72,7 @@ class Example(Scene):
|
|||||||
)
|
)
|
||||||
|
|
||||||
code_step_1 = Code(
|
code_step_1 = Code(
|
||||||
code="""from manim import *
|
code_string="""from manim import *
|
||||||
from manim_slides import Slide
|
from manim_slides import Slide
|
||||||
|
|
||||||
class Example(Scene):
|
class Example(Scene):
|
||||||
@ -91,7 +91,7 @@ class Example(Scene):
|
|||||||
)
|
)
|
||||||
|
|
||||||
code_step_2 = Code(
|
code_step_2 = Code(
|
||||||
code="""from manim import *
|
code_string="""from manim import *
|
||||||
from manim_slides import Slide
|
from manim_slides import Slide
|
||||||
|
|
||||||
class Example(Slide):
|
class Example(Slide):
|
||||||
@ -110,7 +110,7 @@ class Example(Slide):
|
|||||||
)
|
)
|
||||||
|
|
||||||
code_step_3 = Code(
|
code_step_3 = Code(
|
||||||
code="""from manim import *
|
code_string="""from manim import *
|
||||||
from manim_slides import Slide
|
from manim_slides import Slide
|
||||||
|
|
||||||
class Example(Slide):
|
class Example(Slide):
|
||||||
@ -129,7 +129,7 @@ class Example(Slide):
|
|||||||
)
|
)
|
||||||
|
|
||||||
code_step_4 = Code(
|
code_step_4 = Code(
|
||||||
code="""from manim import *
|
code_string="""from manim import *
|
||||||
from manim_slides import Slide
|
from manim_slides import Slide
|
||||||
|
|
||||||
class Example(Slide):
|
class Example(Slide):
|
||||||
@ -148,19 +148,19 @@ class Example(Slide):
|
|||||||
)
|
)
|
||||||
|
|
||||||
code_step_5 = Code(
|
code_step_5 = Code(
|
||||||
code="manim-slide render example.py Example",
|
code_string="manim-slide render example.py Example",
|
||||||
language="console",
|
language="console",
|
||||||
)
|
)
|
||||||
|
|
||||||
code_step_6 = Code(
|
code_step_6 = Code(
|
||||||
code="manim-slides Example",
|
code_string="manim-slides Example",
|
||||||
language="console",
|
language="console",
|
||||||
)
|
)
|
||||||
|
|
||||||
or_text = Text("or generate HTML presentation").scale(0.5)
|
or_text = Text("or generate HTML presentation").scale(0.5)
|
||||||
|
|
||||||
code_step_7 = Code(
|
code_step_7 = Code(
|
||||||
code="manim-slides convert Example slides.html --open",
|
code_string="manim-slides convert Example slides.html --open",
|
||||||
language="console",
|
language="console",
|
||||||
).shift(DOWN)
|
).shift(DOWN)
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
__version__ = "5.3.1"
|
__version__ = "5.4.2"
|
||||||
|
@ -160,6 +160,7 @@ class BaseSlideConfig(BaseModel): # type: ignore
|
|||||||
reversed_playback_rate: float = 1.0
|
reversed_playback_rate: float = 1.0
|
||||||
notes: str = ""
|
notes: str = ""
|
||||||
dedent_notes: bool = True
|
dedent_notes: bool = True
|
||||||
|
skip_animations: bool = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def wrapper(cls, arg_name: str) -> Callable[..., Any]:
|
def wrapper(cls, arg_name: str) -> Callable[..., Any]:
|
||||||
|
@ -49,6 +49,7 @@ class BaseSlide:
|
|||||||
self._start_animation = 0
|
self._start_animation = 0
|
||||||
self._canvas: MutableMapping[str, Mobject] = {}
|
self._canvas: MutableMapping[str, Mobject] = {}
|
||||||
self._wait_time_between_slides = 0.0
|
self._wait_time_between_slides = 0.0
|
||||||
|
self._skip_animations = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@ -277,7 +278,7 @@ class BaseSlide:
|
|||||||
self._wait_time_between_slides = max(wait_time, 0.0)
|
self._wait_time_between_slides = max(wait_time, 0.0)
|
||||||
|
|
||||||
def play(self, *args: Any, **kwargs: Any) -> None:
|
def play(self, *args: Any, **kwargs: Any) -> None:
|
||||||
"""Overload `self.play` and increment animation count."""
|
"""Overload 'self.play' and increment animation count."""
|
||||||
super().play(*args, **kwargs) # type: ignore[misc]
|
super().play(*args, **kwargs) # type: ignore[misc]
|
||||||
self._current_animation += 1
|
self._current_animation += 1
|
||||||
|
|
||||||
@ -299,6 +300,16 @@ class BaseSlide:
|
|||||||
Positional arguments passed to
|
Positional arguments passed to
|
||||||
:meth:`Scene.next_section<manim.scene.scene.Scene.next_section>`,
|
:meth:`Scene.next_section<manim.scene.scene.Scene.next_section>`,
|
||||||
or ignored if `manimlib` API is used.
|
or ignored if `manimlib` API is used.
|
||||||
|
:param skip_animations:
|
||||||
|
Exclude the next slide from the output.
|
||||||
|
|
||||||
|
If `manim` is used, this is also passed to `:meth:`Scene.next_section<manim.scene.scene.Scene.next_section>`,
|
||||||
|
which will avoid rendering the corresponding animations.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
:meth:`start_skip_animations`
|
||||||
|
:meth:`stop_skip_animations`
|
||||||
:param loop:
|
:param loop:
|
||||||
If set, next slide will be looping.
|
If set, next slide will be looping.
|
||||||
:param auto_next:
|
:param auto_next:
|
||||||
@ -458,6 +469,9 @@ class BaseSlide:
|
|||||||
|
|
||||||
self._current_slide += 1
|
self._current_slide += 1
|
||||||
|
|
||||||
|
if self._skip_animations:
|
||||||
|
base_slide_config.skip_animations = True
|
||||||
|
|
||||||
self._base_slide_config = base_slide_config
|
self._base_slide_config = base_slide_config
|
||||||
self._start_animation = self._current_animation
|
self._start_animation = self._current_animation
|
||||||
|
|
||||||
@ -521,9 +535,16 @@ class BaseSlide:
|
|||||||
ascii=True if platform.system() == "Windows" else None,
|
ascii=True if platform.system() == "Windows" else None,
|
||||||
disable=not self._show_progress_bar,
|
disable=not self._show_progress_bar,
|
||||||
):
|
):
|
||||||
|
if pre_slide_config.skip_animations:
|
||||||
|
continue
|
||||||
slide_files = files[pre_slide_config.slides_slice]
|
slide_files = files[pre_slide_config.slides_slice]
|
||||||
|
|
||||||
file = merge_basenames(slide_files)
|
try:
|
||||||
|
file = merge_basenames(slide_files)
|
||||||
|
except ValueError as e:
|
||||||
|
raise ValueError(
|
||||||
|
f"Failed to merge basenames of files for slide: {pre_slide_config!r}"
|
||||||
|
) from e
|
||||||
dst_file = scene_files_folder / file.name
|
dst_file = scene_files_folder / file.name
|
||||||
rev_file = scene_files_folder / f"{file.stem}_reversed{file.suffix}"
|
rev_file = scene_files_folder / f"{file.stem}_reversed{file.suffix}"
|
||||||
|
|
||||||
@ -560,6 +581,22 @@ class BaseSlide:
|
|||||||
f"Slide '{scene_name}' configuration written in '{slide_path.absolute()}'"
|
f"Slide '{scene_name}' configuration written in '{slide_path.absolute()}'"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def start_skip_animations(self) -> None:
|
||||||
|
"""
|
||||||
|
Start skipping animations.
|
||||||
|
|
||||||
|
This automatically applies ``skip_animations=True``
|
||||||
|
to all subsequent calls to :meth:`next_slide`.
|
||||||
|
|
||||||
|
This is useful when you want to skip animations from multiple slides in a row,
|
||||||
|
without having to manually set ``skip_animations=True``.
|
||||||
|
"""
|
||||||
|
self._skip_animations = True
|
||||||
|
|
||||||
|
def stop_skip_animations(self) -> None:
|
||||||
|
"""Stop skipping animations."""
|
||||||
|
self._skip_animations = False
|
||||||
|
|
||||||
def wipe(
|
def wipe(
|
||||||
self,
|
self,
|
||||||
*args: Any,
|
*args: Any,
|
||||||
|
@ -31,6 +31,12 @@ class Slide(BaseSlide, Scene): # type: ignore[misc]
|
|||||||
for the current slide config.
|
for the current slide config.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
|
# OpenGL renderer disables 'write_to_movie' by default
|
||||||
|
# which is required for saving the animations
|
||||||
|
config["write_to_movie"] = True
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _frame_shape(self) -> tuple[float, float]:
|
def _frame_shape(self) -> tuple[float, float]:
|
||||||
if isinstance(self.renderer, OpenGLRenderer):
|
if isinstance(self.renderer, OpenGLRenderer):
|
||||||
@ -89,6 +95,15 @@ class Slide(BaseSlide, Scene): # type: ignore[misc]
|
|||||||
def _start_at_animation_number(self) -> Optional[int]:
|
def _start_at_animation_number(self) -> Optional[int]:
|
||||||
return config["from_animation_number"] # type: ignore
|
return config["from_animation_number"] # type: ignore
|
||||||
|
|
||||||
|
def play(self, *args: Any, **kwargs: Any) -> None:
|
||||||
|
"""Overload 'self.play' and increment animation count."""
|
||||||
|
super().play(*args, **kwargs)
|
||||||
|
|
||||||
|
if self._base_slide_config.skip_animations:
|
||||||
|
# Manim will not render the animations, so we reset the animation
|
||||||
|
# counter to the previous value
|
||||||
|
self._current_animation -= 1
|
||||||
|
|
||||||
def next_section(self, *args: Any, **kwargs: Any) -> None:
|
def next_section(self, *args: Any, **kwargs: Any) -> None:
|
||||||
"""
|
"""
|
||||||
Alias to :meth:`next_slide`.
|
Alias to :meth:`next_slide`.
|
||||||
@ -111,7 +126,12 @@ class Slide(BaseSlide, Scene): # type: ignore[misc]
|
|||||||
base_slide_config: BaseSlideConfig,
|
base_slide_config: BaseSlideConfig,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> None:
|
) -> None:
|
||||||
Scene.next_section(self, *args, **kwargs)
|
Scene.next_section(
|
||||||
|
self,
|
||||||
|
*args,
|
||||||
|
skip_animations=base_slide_config.skip_animations | self._skip_animations,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
BaseSlide.next_slide.__wrapped__(
|
BaseSlide.next_slide.__wrapped__(
|
||||||
self,
|
self,
|
||||||
base_slide_config=base_slide_config,
|
base_slide_config=base_slide_config,
|
||||||
|
@ -61,7 +61,7 @@ full = [
|
|||||||
"manim-slides[magic,manim,sphinx-directive]",
|
"manim-slides[magic,manim,sphinx-directive]",
|
||||||
]
|
]
|
||||||
magic = ["manim-slides[manim]", "ipython>=8.12.2"]
|
magic = ["manim-slides[manim]", "ipython>=8.12.2"]
|
||||||
manim = ["manim>=0.17"]
|
manim = ["manim>=0.19"]
|
||||||
manimgl = ["manimgl>=1.7.2"]
|
manimgl = ["manimgl>=1.7.2"]
|
||||||
pyqt6 = ["pyqt6>=6.7.0"]
|
pyqt6 = ["pyqt6>=6.7.0"]
|
||||||
pyqt6-full = ["manim-slides[full,pyqt6]"]
|
pyqt6-full = ["manim-slides[full,pyqt6]"]
|
||||||
@ -91,7 +91,7 @@ Repository = "https://github.com/jeertmans/manim-slides"
|
|||||||
allow_dirty = false
|
allow_dirty = false
|
||||||
commit = true
|
commit = true
|
||||||
commit_args = ""
|
commit_args = ""
|
||||||
current_version = "5.3.1"
|
current_version = "5.4.2"
|
||||||
ignore_missing_version = false
|
ignore_missing_version = false
|
||||||
message = "chore(deps): bump version from {current_version} to {new_version}"
|
message = "chore(deps): bump version from {current_version} to {new_version}"
|
||||||
parse = '(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(-rc(?P<release>\d+))?'
|
parse = '(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(-rc(?P<release>\d+))?'
|
||||||
@ -137,13 +137,6 @@ replace = '''<!-- start changelog -->
|
|||||||
## [Unreleased](https://github.com/jeertmans/manim-slides/compare/v{new_version}...HEAD)'''
|
## [Unreleased](https://github.com/jeertmans/manim-slides/compare/v{new_version}...HEAD)'''
|
||||||
search = "<!-- start changelog -->"
|
search = "<!-- start changelog -->"
|
||||||
|
|
||||||
[[tool.bumpversion.files]]
|
|
||||||
filename = "uv.lock"
|
|
||||||
replace = '''name = "manim-slides"
|
|
||||||
version = "{new_version}"'''
|
|
||||||
search = '''name = "manim-slides"
|
|
||||||
version = "{current_version}"'''
|
|
||||||
|
|
||||||
[tool.codespell]
|
[tool.codespell]
|
||||||
builtin = "clear,rare,informal,usage,names,en-GB_to_en-US"
|
builtin = "clear,rare,informal,usage,names,en-GB_to_en-US"
|
||||||
check-hidden = true
|
check-hidden = true
|
||||||
|
@ -86,6 +86,15 @@ class TestBaseSlide:
|
|||||||
|
|
||||||
assert base_slide.wait_time_between_slides == 0.0
|
assert base_slide.wait_time_between_slides == 0.0
|
||||||
|
|
||||||
|
def test_skip_animations(self, base_slide: BaseSlide) -> None:
|
||||||
|
assert not base_slide._skip_animations
|
||||||
|
|
||||||
|
def test_start_and_stop_skip_animations(self, base_slide: BaseSlide) -> None:
|
||||||
|
base_slide.start_skip_animations()
|
||||||
|
assert base_slide._skip_animations
|
||||||
|
base_slide.stop_skip_animations()
|
||||||
|
assert not base_slide._skip_animations
|
||||||
|
|
||||||
def test_play(self) -> None:
|
def test_play(self) -> None:
|
||||||
pass # This method should be tested in test_slide.py
|
pass # This method should be tested in test_slide.py
|
||||||
|
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
|
import contextlib
|
||||||
|
import os
|
||||||
import random
|
import random
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
|
from collections.abc import Iterator
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Union
|
from typing import Any, Union
|
||||||
|
|
||||||
@ -17,6 +21,7 @@ from manim import (
|
|||||||
Dot,
|
Dot,
|
||||||
FadeIn,
|
FadeIn,
|
||||||
GrowFromCenter,
|
GrowFromCenter,
|
||||||
|
Square,
|
||||||
Text,
|
Text,
|
||||||
)
|
)
|
||||||
from manim.renderer.opengl_renderer import OpenGLRenderer
|
from manim.renderer.opengl_renderer import OpenGLRenderer
|
||||||
@ -65,7 +70,9 @@ Slide = Union[CESlide, _GLSlide, CEGLSlide]
|
|||||||
reason="See https://github.com/3b1b/manim/issues/2263.",
|
reason="See https://github.com/3b1b/manim/issues/2263.",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
"--CE --renderer=opengl",
|
||||||
],
|
],
|
||||||
|
ids=("CE", "GL", "CE(GL)"),
|
||||||
)
|
)
|
||||||
def test_render_basic_slide(
|
def test_render_basic_slide(
|
||||||
renderer: str,
|
renderer: str,
|
||||||
@ -78,7 +85,7 @@ def test_render_basic_slide(
|
|||||||
with runner.isolated_filesystem() as tmp_dir:
|
with runner.isolated_filesystem() as tmp_dir:
|
||||||
shutil.copy(manimgl_config, tmp_dir)
|
shutil.copy(manimgl_config, tmp_dir)
|
||||||
results = runner.invoke(
|
results = runner.invoke(
|
||||||
render, [renderer, str(slides_file), "BasicSlide", "-ql"]
|
render, [*renderer.split(" "), str(slides_file), "BasicSlide", "-ql"]
|
||||||
)
|
)
|
||||||
|
|
||||||
assert results.exit_code == 0, results
|
assert results.exit_code == 0, results
|
||||||
@ -229,8 +236,22 @@ def assert_constructs(cls: SlideType) -> None:
|
|||||||
init_slide(cls).construct()
|
init_slide(cls).construct()
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def tmp_cwd() -> Iterator[str]:
|
||||||
|
cwd = os.getcwd()
|
||||||
|
tmp_dir = tempfile.mkdtemp()
|
||||||
|
|
||||||
|
os.chdir(tmp_dir)
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield tmp_dir
|
||||||
|
finally:
|
||||||
|
os.chdir(cwd)
|
||||||
|
|
||||||
|
|
||||||
def assert_renders(cls: SlideType) -> None:
|
def assert_renders(cls: SlideType) -> None:
|
||||||
init_slide(cls).render()
|
with tmp_cwd():
|
||||||
|
init_slide(cls).render()
|
||||||
|
|
||||||
|
|
||||||
class TestSlide:
|
class TestSlide:
|
||||||
@ -479,6 +500,75 @@ class TestSlide:
|
|||||||
self.next_slide()
|
self.next_slide()
|
||||||
assert self._current_slide == 2
|
assert self._current_slide == 2
|
||||||
|
|
||||||
|
def test_next_slide_skip_animations(self) -> None:
|
||||||
|
class Foo(CESlide):
|
||||||
|
def construct(self) -> None:
|
||||||
|
circle = Circle(color=BLUE)
|
||||||
|
self.play(GrowFromCenter(circle))
|
||||||
|
assert not self._base_slide_config.skip_animations
|
||||||
|
self.next_slide(skip_animations=True)
|
||||||
|
square = Square(color=BLUE)
|
||||||
|
self.play(GrowFromCenter(square))
|
||||||
|
assert self._base_slide_config.skip_animations
|
||||||
|
self.next_slide()
|
||||||
|
assert not self._base_slide_config.skip_animations
|
||||||
|
self.play(GrowFromCenter(square))
|
||||||
|
|
||||||
|
class Bar(CESlide):
|
||||||
|
def construct(self) -> None:
|
||||||
|
circle = Circle(color=BLUE)
|
||||||
|
self.play(GrowFromCenter(circle))
|
||||||
|
assert not self._base_slide_config.skip_animations
|
||||||
|
self.next_slide(skip_animations=False)
|
||||||
|
square = Square(color=BLUE)
|
||||||
|
self.play(GrowFromCenter(square))
|
||||||
|
assert not self._base_slide_config.skip_animations
|
||||||
|
self.next_slide()
|
||||||
|
assert not self._base_slide_config.skip_animations
|
||||||
|
self.play(GrowFromCenter(square))
|
||||||
|
|
||||||
|
class Baz(CESlide):
|
||||||
|
def construct(self) -> None:
|
||||||
|
circle = Circle(color=BLUE)
|
||||||
|
self.play(GrowFromCenter(circle))
|
||||||
|
assert not self._base_slide_config.skip_animations
|
||||||
|
self.start_skip_animations()
|
||||||
|
self.next_slide()
|
||||||
|
square = Square(color=BLUE)
|
||||||
|
self.play(GrowFromCenter(square))
|
||||||
|
assert self._base_slide_config.skip_animations
|
||||||
|
self.next_slide()
|
||||||
|
assert self._base_slide_config.skip_animations
|
||||||
|
self.play(GrowFromCenter(square))
|
||||||
|
self.stop_skip_animations()
|
||||||
|
|
||||||
|
with tmp_cwd() as tmp_dir:
|
||||||
|
init_slide(Foo).render()
|
||||||
|
init_slide(Bar).render()
|
||||||
|
init_slide(Baz).render()
|
||||||
|
|
||||||
|
slides_folder = Path(tmp_dir) / "slides"
|
||||||
|
|
||||||
|
assert slides_folder.exists()
|
||||||
|
|
||||||
|
slide_file = slides_folder / "Foo.json"
|
||||||
|
|
||||||
|
config = PresentationConfig.from_file(slide_file)
|
||||||
|
|
||||||
|
assert len(config.slides) == 2
|
||||||
|
|
||||||
|
slide_file = slides_folder / "Bar.json"
|
||||||
|
|
||||||
|
config = PresentationConfig.from_file(slide_file)
|
||||||
|
|
||||||
|
assert len(config.slides) == 3
|
||||||
|
|
||||||
|
slide_file = slides_folder / "Baz.json"
|
||||||
|
|
||||||
|
config = PresentationConfig.from_file(slide_file)
|
||||||
|
|
||||||
|
assert len(config.slides) == 1
|
||||||
|
|
||||||
def test_canvas(self) -> None:
|
def test_canvas(self) -> None:
|
||||||
@assert_constructs
|
@assert_constructs
|
||||||
class _(CESlide):
|
class _(CESlide):
|
||||||
|
Reference in New Issue
Block a user