Change from tempconfig to a config fixture in tests (#3853)

* Implement changes to fixtures

* Change tests to use the config fixture
This commit is contained in:
adeshpande 2024-07-12 16:41:51 -04:00 committed by GitHub
commit 75625964b6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 431 additions and 427 deletions

View file

@ -5,7 +5,7 @@ from pathlib import Path
import pytest
from manim import config, tempconfig
import manim
def pytest_addoption(parser):
@ -45,6 +45,20 @@ def pytest_collection_modifyitems(config, items):
item.add_marker(slow_skip)
@pytest.fixture
def config():
saved = manim.config.copy()
# we need to return the actual config so that tests
# using tempconfig pass
yield manim.config
manim.config.update(saved)
@pytest.fixture
def dry_run(config):
config.dry_run = True
@pytest.fixture(scope="session")
def python_version():
# use the same python executable as it is running currently
@ -62,10 +76,10 @@ def reset_cfg_file():
@pytest.fixture
def using_opengl_renderer():
def using_opengl_renderer(config):
"""Standard fixture for running with opengl that makes tests use a standard_config.cfg with a temp dir."""
with tempconfig({"renderer": "opengl"}):
yield
config.renderer = "opengl"
yield
# as a special case needed to manually revert back to cairo
# due to side effects of setting the renderer
config.renderer = "cairo"

View file

@ -7,11 +7,11 @@ from pathlib import Path
import numpy as np
from manim import config, logger
from manim import logger
from manim.scene.scene import Scene
def set_test_scene(scene_object: type[Scene], module_name: str):
def set_test_scene(scene_object: type[Scene], module_name: str, config):
"""Function used to set up the test data for a new feature. This will basically set up a pre-rendered frame for a scene. This is meant to be used only
when setting up tests. Please refer to the wiki.
@ -46,7 +46,7 @@ def set_test_scene(scene_object: type[Scene], module_name: str):
assert not np.all(
data == np.array([0, 0, 0, 255]),
), f"Control data generated for {str(scene)} only contains empty pixels."
), f"Control data generated for {scene!s} only contains empty pixels."
assert data.shape == (480, 854, 4)
tests_directory = Path(__file__).absolute().parent.parent
path_control_data = Path(tests_directory) / "control_data" / "graphical_units_data"

View file

@ -2,7 +2,7 @@ from __future__ import annotations
import pytest
from manim import FadeIn, Scene, config
from manim import FadeIn, Scene
@pytest.mark.parametrize(
@ -15,7 +15,7 @@ def test_animation_forbidden_run_time(run_time):
test_scene.play(FadeIn(None, run_time=run_time))
def test_animation_run_time_shorter_than_frame_rate(caplog):
def test_animation_run_time_shorter_than_frame_rate(caplog, config):
test_scene = Scene()
test_scene.play(FadeIn(None, run_time=1 / (config.frame_rate + 1)))
assert (

View file

@ -3,7 +3,7 @@ from __future__ import annotations
import numpy as np
import pytest
from manim import AddTextLetterByLetter, Text, config
from manim import AddTextLetterByLetter, Text
def test_non_empty_text_creation():
@ -25,7 +25,7 @@ def test_whitespace_text_creation():
AddTextLetterByLetter(Text(" "))
def test_run_time_for_non_empty_text():
def test_run_time_for_non_empty_text(config):
"""Ensure the run_time is calculated correctly for non-empty text."""
s = Text("Hello")
run_time_per_char = 0.1

View file

@ -2,7 +2,7 @@ from __future__ import annotations
from pathlib import Path
from manim import BraceLabel, Mobject, config
from manim import BraceLabel, Mobject
def test_mobject_copy():
@ -18,7 +18,7 @@ def test_mobject_copy():
assert orig.submobjects[i] is not copy.submobjects[i]
def test_bracelabel_copy(tmp_path):
def test_bracelabel_copy(tmp_path, config):
"""Test that a copy is a deepcopy."""
# For this test to work, we need to tweak some folders temporarily
original_text_dir = config["text_dir"]

View file

@ -1,20 +1,20 @@
from __future__ import annotations
from manim import Mobject, config, tempconfig
from manim import Mobject
from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL
from manim.mobject.opengl.opengl_mobject import OpenGLMobject
def test_metaclass_registry():
def test_metaclass_registry(config):
class SomeTestMobject(Mobject, metaclass=ConvertToOpenGL):
pass
assert SomeTestMobject in ConvertToOpenGL._converted_classes
with tempconfig({"renderer": "opengl"}):
assert OpenGLMobject in SomeTestMobject.__bases__
assert Mobject not in SomeTestMobject.__bases__
config.renderer = "opengl"
assert OpenGLMobject in SomeTestMobject.__bases__
assert Mobject not in SomeTestMobject.__bases__
config.renderer = "cairo"
assert Mobject in SomeTestMobject.__bases__
assert OpenGLMobject not in SomeTestMobject.__bases__
config.renderer = "cairo"
assert Mobject in SomeTestMobject.__bases__
assert OpenGLMobject not in SomeTestMobject.__bases__

View file

@ -2,13 +2,11 @@ from __future__ import annotations
import numpy as np
from manim import RendererType, config
from manim.constants import RIGHT
from manim.mobject.geometry.polygram import Square
def test_Data():
config.renderer = RendererType.OPENGL
def test_Data(using_opengl_renderer):
a = Square().move_to(RIGHT)
data_bb = a.data["bounding_box"]
np.testing.assert_array_equal(
@ -39,6 +37,3 @@ def test_Data():
)
np.testing.assert_array_equal(a.bounding_box, data_bb)
config.renderer = (
RendererType.CAIRO
) # needs to be here or else the following cairo tests fail

View file

@ -5,15 +5,15 @@ from pathlib import Path
import numpy as np
import pytest
from manim import MathTex, SingleStringMathTex, Tex, TexTemplate, config, tempconfig
from manim import MathTex, SingleStringMathTex, Tex, TexTemplate, tempconfig
def test_MathTex():
def test_MathTex(config):
MathTex("a^2 + b^2 = c^2")
assert Path(config.media_dir, "Tex", "e4be163a00cf424f.svg").exists()
def test_SingleStringMathTex():
def test_SingleStringMathTex(config):
SingleStringMathTex("test")
assert Path(config.media_dir, "Tex", "8ce17c7f5013209f.svg").exists()
@ -27,7 +27,7 @@ def test_double_braces_testing(text_input, length_sub):
assert len(t1.submobjects) == length_sub
def test_tex():
def test_tex(config):
Tex("The horse does not eat cucumber salad.")
assert Path(config.media_dir, "Tex", "c3945e23e546c95a.svg").exists()
@ -45,7 +45,7 @@ def test_tex_temp_directory(tmpdir, monkeypatch):
assert Path("media", "Tex", "c3945e23e546c95a.svg").exists()
def test_percent_char_rendering():
def test_percent_char_rendering(config):
Tex(r"\%")
assert Path(config.media_dir, "Tex", "4a583af4d19a3adf.tex").exists()
@ -194,7 +194,7 @@ def test_error_in_nested_context(capsys):
\end{align}
"""
with pytest.raises(ValueError) as err:
with pytest.raises(ValueError):
Tex(invalid_tex)
stdout = str(capsys.readouterr().out)
@ -202,25 +202,25 @@ def test_error_in_nested_context(capsys):
assert r"\begin{frame}" not in stdout
def test_tempconfig_resetting_tex_template():
def test_tempconfig_resetting_tex_template(config):
my_template = TexTemplate()
my_template.preamble = "Custom preamble!"
tex_template_config_value = config.tex_template
with tempconfig({"tex_template": my_template}):
assert config.tex_template.preamble == "Custom preamble!"
assert config.tex_template.preamble != "Custom preamble!"
def test_tex_garbage_collection(tmpdir, monkeypatch):
def test_tex_garbage_collection(tmpdir, monkeypatch, config):
monkeypatch.chdir(tmpdir)
Path(tmpdir, "media").mkdir()
config.media_dir = "media"
with tempconfig({"media_dir": "media"}):
tex_without_log = Tex("Hello World!") # d771330b76d29ffb.tex
assert Path("media", "Tex", "d771330b76d29ffb.tex").exists()
assert not Path("media", "Tex", "d771330b76d29ffb.log").exists()
tex_without_log = Tex("Hello World!") # d771330b76d29ffb.tex
assert Path("media", "Tex", "d771330b76d29ffb.tex").exists()
assert not Path("media", "Tex", "d771330b76d29ffb.log").exists()
with tempconfig({"media_dir": "media", "no_latex_cleanup": True}):
tex_with_log = Tex("Hello World, again!") # da27670a37b08799.tex
assert Path("media", "Tex", "da27670a37b08799.log").exists()
config.no_latex_cleanup = True
tex_with_log = Tex("Hello World, again!") # da27670a37b08799.tex
assert Path("media", "Tex", "da27670a37b08799.log").exists()

View file

@ -4,104 +4,100 @@ import datetime
import pytest
from manim import Circle, FadeIn, Group, Mobject, Scene, Square, tempconfig
from manim import Circle, FadeIn, Group, Mobject, Scene, Square
from manim.animation.animation import Wait
def test_scene_add_remove():
with tempconfig({"dry_run": True}):
scene = Scene()
assert len(scene.mobjects) == 0
scene.add(Mobject())
assert len(scene.mobjects) == 1
scene.add(*(Mobject() for _ in range(10)))
assert len(scene.mobjects) == 11
def test_scene_add_remove(dry_run):
scene = Scene()
assert len(scene.mobjects) == 0
scene.add(Mobject())
assert len(scene.mobjects) == 1
scene.add(*(Mobject() for _ in range(10)))
assert len(scene.mobjects) == 11
# Check that adding a mobject twice does not actually add it twice
repeated = Mobject()
scene.add(repeated)
assert len(scene.mobjects) == 12
scene.add(repeated)
assert len(scene.mobjects) == 12
# Check that adding a mobject twice does not actually add it twice
repeated = Mobject()
scene.add(repeated)
assert len(scene.mobjects) == 12
scene.add(repeated)
assert len(scene.mobjects) == 12
# Check that Scene.add() returns the Scene (for chained calls)
assert scene.add(Mobject()) is scene
to_remove = Mobject()
scene = Scene()
scene.add(to_remove)
scene.add(*(Mobject() for _ in range(10)))
assert len(scene.mobjects) == 11
scene.remove(to_remove)
assert len(scene.mobjects) == 10
scene.remove(to_remove)
assert len(scene.mobjects) == 10
# Check that Scene.add() returns the Scene (for chained calls)
assert scene.add(Mobject()) is scene
to_remove = Mobject()
scene = Scene()
scene.add(to_remove)
scene.add(*(Mobject() for _ in range(10)))
assert len(scene.mobjects) == 11
scene.remove(to_remove)
assert len(scene.mobjects) == 10
scene.remove(to_remove)
assert len(scene.mobjects) == 10
# Check that Scene.remove() returns the instance (for chained calls)
assert scene.add(Mobject()) is scene
# Check that Scene.remove() returns the instance (for chained calls)
assert scene.add(Mobject()) is scene
def test_scene_time():
with tempconfig({"dry_run": True}):
scene = Scene()
assert scene.renderer.time == 0
scene.wait(2)
assert scene.renderer.time == 2
scene.play(FadeIn(Circle()), run_time=0.5)
assert pytest.approx(scene.renderer.time) == 2.5
scene.renderer._original_skipping_status = True
scene.play(FadeIn(Square()), run_time=5) # this animation gets skipped.
assert pytest.approx(scene.renderer.time) == 7.5
def test_scene_time(dry_run):
scene = Scene()
assert scene.renderer.time == 0
scene.wait(2)
assert scene.renderer.time == 2
scene.play(FadeIn(Circle()), run_time=0.5)
assert pytest.approx(scene.renderer.time) == 2.5
scene.renderer._original_skipping_status = True
scene.play(FadeIn(Square()), run_time=5) # this animation gets skipped.
assert pytest.approx(scene.renderer.time) == 7.5
def test_subcaption():
with tempconfig({"dry_run": True}):
scene = Scene()
scene.add_subcaption("Testing add_subcaption", duration=1, offset=0)
scene.wait()
scene.play(
Wait(),
run_time=2,
subcaption="Testing Scene.play subcaption interface",
subcaption_duration=1.5,
subcaption_offset=0.5,
)
subcaptions = scene.renderer.file_writer.subcaptions
assert len(subcaptions) == 2
assert subcaptions[0].start == datetime.timedelta(seconds=0)
assert subcaptions[0].end == datetime.timedelta(seconds=1)
assert subcaptions[0].content == "Testing add_subcaption"
assert subcaptions[1].start == datetime.timedelta(seconds=1.5)
assert subcaptions[1].end == datetime.timedelta(seconds=3)
assert subcaptions[1].content == "Testing Scene.play subcaption interface"
def test_subcaption(dry_run):
scene = Scene()
scene.add_subcaption("Testing add_subcaption", duration=1, offset=0)
scene.wait()
scene.play(
Wait(),
run_time=2,
subcaption="Testing Scene.play subcaption interface",
subcaption_duration=1.5,
subcaption_offset=0.5,
)
subcaptions = scene.renderer.file_writer.subcaptions
assert len(subcaptions) == 2
assert subcaptions[0].start == datetime.timedelta(seconds=0)
assert subcaptions[0].end == datetime.timedelta(seconds=1)
assert subcaptions[0].content == "Testing add_subcaption"
assert subcaptions[1].start == datetime.timedelta(seconds=1.5)
assert subcaptions[1].end == datetime.timedelta(seconds=3)
assert subcaptions[1].content == "Testing Scene.play subcaption interface"
def test_replace():
def test_replace(dry_run):
def assert_names(mobjs, names):
assert len(mobjs) == len(names)
for i in range(0, len(mobjs)):
assert mobjs[i].name == names[i]
with tempconfig({"dry_run": True}):
scene = Scene()
scene = Scene()
first = Mobject(name="first")
second = Mobject(name="second")
third = Mobject(name="third")
fourth = Mobject(name="fourth")
first = Mobject(name="first")
second = Mobject(name="second")
third = Mobject(name="third")
fourth = Mobject(name="fourth")
scene.add(first)
scene.add(Group(second, third, name="group"))
scene.add(fourth)
assert_names(scene.mobjects, ["first", "group", "fourth"])
assert_names(scene.mobjects[1], ["second", "third"])
scene.add(first)
scene.add(Group(second, third, name="group"))
scene.add(fourth)
assert_names(scene.mobjects, ["first", "group", "fourth"])
assert_names(scene.mobjects[1], ["second", "third"])
alpha = Mobject(name="alpha")
beta = Mobject(name="beta")
alpha = Mobject(name="alpha")
beta = Mobject(name="beta")
scene.replace(first, alpha)
assert_names(scene.mobjects, ["alpha", "group", "fourth"])
assert_names(scene.mobjects[1], ["second", "third"])
scene.replace(first, alpha)
assert_names(scene.mobjects, ["alpha", "group", "fourth"])
assert_names(scene.mobjects[1], ["second", "third"])
scene.replace(second, beta)
assert_names(scene.mobjects, ["alpha", "group", "fourth"])
assert_names(scene.mobjects[1], ["beta", "third"])
scene.replace(second, beta)
assert_names(scene.mobjects, ["alpha", "group", "fourth"])
assert_names(scene.mobjects[1], ["beta", "third"])

View file

@ -3,13 +3,13 @@ from __future__ import annotations
import numpy as np
import pytest
from manim import PI, X_AXIS, Y_AXIS, Z_AXIS, config
from manim import PI, X_AXIS, Y_AXIS, Z_AXIS
from manim.utils.unit import Degrees, Munits, Percent, Pixels
def test_units():
def test_units(config):
# make sure we are using the right frame geometry
assert config.pixel_width == 1920
config.pixel_width = 1920
np.testing.assert_allclose(config.frame_height, 8.0)

View file

@ -5,10 +5,10 @@ from pathlib import Path
import numpy as np
from manim import WHITE, Scene, Square, config, tempconfig
from manim import WHITE, Scene, Square, tempconfig
def test_tempconfig(using_opengl_renderer):
def test_tempconfig(config, using_opengl_renderer):
"""Test the tempconfig context manager."""
original = config.copy()
@ -37,35 +37,36 @@ class MyScene(Scene):
self.wait(1)
def test_background_color(using_opengl_renderer):
def test_background_color(config, using_opengl_renderer, dry_run):
"""Test the 'background_color' config option."""
with tempconfig({"background_color": WHITE, "verbosity": "ERROR", "dry_run": True}):
scene = MyScene()
scene.render()
frame = scene.renderer.get_frame()
np.testing.assert_allclose(frame[0, 0], [255, 255, 255, 255])
config.background_color = WHITE
config.verbose = "ERROR"
scene = MyScene()
scene.render()
frame = scene.renderer.get_frame()
np.testing.assert_allclose(frame[0, 0], [255, 255, 255, 255])
def test_digest_file(using_opengl_renderer, tmp_path):
def test_digest_file(config, using_opengl_renderer, tmp_path):
"""Test that a config file can be digested programmatically."""
with tempconfig({}):
tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False)
tmp_cfg.write(
"""
[CLI]
media_dir = this_is_my_favorite_path
video_dir = {media_dir}/videos
frame_height = 10
""",
)
tmp_cfg.close()
config.digest_file(tmp_cfg.name)
tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False)
tmp_cfg.write(
"""
[CLI]
media_dir = this_is_my_favorite_path
video_dir = {media_dir}/videos
frame_height = 10
""",
)
tmp_cfg.close()
config.digest_file(tmp_cfg.name)
assert config.get_dir("media_dir") == Path("this_is_my_favorite_path")
assert config.get_dir("video_dir") == Path("this_is_my_favorite_path/videos")
assert config.get_dir("media_dir") == Path("this_is_my_favorite_path")
assert config.get_dir("video_dir") == Path("this_is_my_favorite_path/videos")
def test_frame_size(using_opengl_renderer, tmp_path):
def test_frame_size(config, using_opengl_renderer, tmp_path):
"""Test that the frame size can be set via config file."""
np.testing.assert_allclose(
config.aspect_ratio, config.pixel_width / config.pixel_height
@ -90,27 +91,28 @@ def test_frame_size(using_opengl_renderer, tmp_path):
np.testing.assert_allclose(config.frame_height, 8.0)
np.testing.assert_allclose(config.frame_width, 8.0)
with tempconfig({}):
tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False)
tmp_cfg.write(
"""
[CLI]
pixel_height = 10
pixel_width = 10
frame_height = 10
frame_width = 10
""",
)
tmp_cfg.close()
config.digest_file(tmp_cfg.name)
np.testing.assert_allclose(config.aspect_ratio, 1.0)
# if both are specified in the cfg file, the aspect ratio is ignored
np.testing.assert_allclose(config.frame_height, 10.0)
np.testing.assert_allclose(config.frame_width, 10.0)
def test_frame_size_if_frame_width(config, using_opengl_renderer, tmp_path):
tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False)
tmp_cfg.write(
"""
[CLI]
pixel_height = 10
pixel_width = 10
frame_height = 10
frame_width = 10
""",
)
tmp_cfg.close()
config.digest_file(tmp_cfg.name)
np.testing.assert_allclose(config.aspect_ratio, 1.0)
# if both are specified in the cfg file, the aspect ratio is ignored
np.testing.assert_allclose(config.frame_height, 10.0)
np.testing.assert_allclose(config.frame_width, 10.0)
def test_temporary_dry_run(using_opengl_renderer):
def test_temporary_dry_run(config, using_opengl_renderer):
"""Test that tempconfig correctly restores after setting dry_run."""
assert config["write_to_movie"]
assert not config["save_last_frame"]
@ -123,21 +125,20 @@ def test_temporary_dry_run(using_opengl_renderer):
assert not config["save_last_frame"]
def test_dry_run_with_png_format(using_opengl_renderer):
def test_dry_run_with_png_format(config, using_opengl_renderer, dry_run):
"""Test that there are no exceptions when running a png without output"""
with tempconfig(
{"dry_run": True, "write_to_movie": False, "disable_caching": True}
):
assert config["dry_run"] is True
scene = MyScene()
scene.render()
config.disable_caching = True
assert config["dry_run"] is True
scene = MyScene()
scene.render()
def test_dry_run_with_png_format_skipped_animations(using_opengl_renderer):
def test_dry_run_with_png_format_skipped_animations(
config, using_opengl_renderer, dry_run
):
"""Test that there are no exceptions when running a png without output and skipped animations"""
with tempconfig(
{"dry_run": True, "write_to_movie": False, "disable_caching": True}
):
assert config["dry_run"] is True
scene = MyScene(skip_animations=True)
scene.render()
config.write_to_movie = False
config.disable_caching = True
assert config["dry_run"] is True
scene = MyScene(skip_animations=True)
scene.render()

View file

@ -2,7 +2,7 @@ from __future__ import annotations
from pathlib import Path
from manim import BraceLabel, config
from manim import BraceLabel
from manim.mobject.opengl.opengl_mobject import OpenGLMobject
@ -19,7 +19,7 @@ def test_opengl_mobject_copy(using_opengl_renderer):
assert orig.submobjects[i] is not copy.submobjects[i]
def test_bracelabel_copy(using_opengl_renderer, tmp_path):
def test_bracelabel_copy(config, using_opengl_renderer, tmp_path):
"""Test that a copy is a deepcopy."""
# For this test to work, we need to tweak some folders temporarily
original_text_dir = config["text_dir"]

View file

@ -2,36 +2,29 @@ from __future__ import annotations
import re
from manim import config, tempconfig
from manim.utils.ipython_magic import _generate_file_name
def test_jupyter_file_naming():
def test_jupyter_file_naming(config, using_opengl_renderer):
"""Check the format of file names for jupyter"""
scene_name = "SimpleScene"
expected_pattern = r"[0-9a-zA-Z_]+[@_-]\d\d\d\d-\d\d-\d\d[@_-]\d\d-\d\d-\d\d"
current_renderer = config.renderer
with tempconfig({"scene_names": [scene_name], "renderer": "opengl"}):
file_name = _generate_file_name()
match = re.match(expected_pattern, file_name)
assert scene_name in file_name, (
"Expected file to contain " + scene_name + " but got " + file_name
)
assert match, "file name does not match expected pattern " + expected_pattern
# needs manually set back to avoid issues across tests
config.renderer = current_renderer
config.scene_names = [scene_name]
file_name = _generate_file_name()
match = re.match(expected_pattern, file_name)
assert scene_name in file_name, (
"Expected file to contain " + scene_name + " but got " + file_name
)
assert match, "file name does not match expected pattern " + expected_pattern
def test_jupyter_file_output(tmp_path):
def test_jupyter_file_output(tmp_path, config, using_opengl_renderer):
"""Check the jupyter file naming is valid and can be created"""
scene_name = "SimpleScene"
current_renderer = config.renderer
with tempconfig({"scene_names": [scene_name], "renderer": "opengl"}):
file_name = _generate_file_name()
actual_path = tmp_path.with_name(file_name)
with actual_path.open("w") as outfile:
outfile.write("")
assert actual_path.exists()
assert actual_path.is_file()
# needs manually set back to avoid issues across tests
config.renderer = current_renderer
config.scene_names = [scene_name]
file_name = _generate_file_name()
actual_path = tmp_path.with_name(file_name)
with actual_path.open("w") as outfile:
outfile.write("")
assert actual_path.exists()
assert actual_path.is_file()

View file

@ -4,15 +4,15 @@ from pathlib import Path
import pytest
from manim import MathTex, SingleStringMathTex, Tex, config
from manim import MathTex, SingleStringMathTex, Tex
def test_MathTex(using_opengl_renderer):
def test_MathTex(config, using_opengl_renderer):
MathTex("a^2 + b^2 = c^2")
assert Path(config.media_dir, "Tex", "e4be163a00cf424f.svg").exists()
def test_SingleStringMathTex(using_opengl_renderer):
def test_SingleStringMathTex(config, using_opengl_renderer):
SingleStringMathTex("test")
assert Path(config.media_dir, "Tex", "8ce17c7f5013209f.svg").exists()
@ -26,7 +26,7 @@ def test_double_braces_testing(using_opengl_renderer, text_input, length_sub):
assert len(t1.submobjects) == length_sub
def test_tex(using_opengl_renderer):
def test_tex(config, using_opengl_renderer):
Tex("The horse does not eat cucumber salad.")
assert Path(config.media_dir, "Tex", "c3945e23e546c95a.svg").exists()

View file

@ -5,12 +5,12 @@ from pathlib import Path
import numpy as np
from manim import WHITE, Scene, Square, Tex, Text, config, tempconfig
from manim import WHITE, Scene, Square, Tex, Text, tempconfig
from manim._config.utils import ManimConfig
from tests.assert_utils import assert_dir_exists, assert_dir_filled, assert_file_exists
def test_tempconfig():
def test_tempconfig(config):
"""Test the tempconfig context manager."""
original = config.copy()
@ -41,144 +41,141 @@ class MyScene(Scene):
self.wait(1)
def test_transparent():
def test_transparent(config):
"""Test the 'transparent' config option."""
orig_verbosity = config["verbosity"]
config["verbosity"] = "ERROR"
with tempconfig({"dry_run": True}):
scene = MyScene()
scene.render()
frame = scene.renderer.get_frame()
config.verbosity = "ERROR"
config.dry_run = True
scene = MyScene()
scene.render()
frame = scene.renderer.get_frame()
np.testing.assert_allclose(frame[0, 0], [0, 0, 0, 255])
with tempconfig({"transparent": True, "dry_run": True}):
scene = MyScene()
scene.render()
frame = scene.renderer.get_frame()
np.testing.assert_allclose(frame[0, 0], [0, 0, 0, 0])
config.transparent = True
config["verbosity"] = orig_verbosity
scene = MyScene()
scene.render()
frame = scene.renderer.get_frame()
np.testing.assert_allclose(frame[0, 0], [0, 0, 0, 0])
def test_background_color():
def test_background_color(config):
"""Test the 'background_color' config option."""
with tempconfig({"background_color": WHITE, "verbosity": "ERROR", "dry_run": True}):
scene = MyScene()
scene.render()
frame = scene.renderer.get_frame()
np.testing.assert_allclose(frame[0, 0], [255, 255, 255, 255])
config.background_color = WHITE
config.verbosity = "ERROR"
config.dry_run = True
scene = MyScene()
scene.render()
frame = scene.renderer.get_frame()
np.testing.assert_allclose(frame[0, 0], [255, 255, 255, 255])
def test_digest_file(tmp_path):
def test_digest_file(tmp_path, config):
"""Test that a config file can be digested programmatically."""
with tempconfig({}):
tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False)
tmp_cfg.write(
"""
[CLI]
media_dir = this_is_my_favorite_path
video_dir = {media_dir}/videos
sections_dir = {media_dir}/{scene_name}/prepare_for_unforeseen_consequences
frame_height = 10
""",
)
tmp_cfg.close()
config.digest_file(tmp_cfg.name)
tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False)
tmp_cfg.write(
"""
[CLI]
media_dir = this_is_my_favorite_path
video_dir = {media_dir}/videos
sections_dir = {media_dir}/{scene_name}/prepare_for_unforeseen_consequences
frame_height = 10
""",
)
tmp_cfg.close()
config.digest_file(tmp_cfg.name)
assert config.get_dir("media_dir") == Path("this_is_my_favorite_path")
assert config.get_dir("video_dir") == Path("this_is_my_favorite_path/videos")
assert config.get_dir("sections_dir", scene_name="test") == Path(
"this_is_my_favorite_path/test/prepare_for_unforeseen_consequences"
)
assert config.get_dir("media_dir") == Path("this_is_my_favorite_path")
assert config.get_dir("video_dir") == Path("this_is_my_favorite_path/videos")
assert config.get_dir("sections_dir", scene_name="test") == Path(
"this_is_my_favorite_path/test/prepare_for_unforeseen_consequences"
)
def test_custom_dirs(tmp_path):
with tempconfig(
{
"media_dir": tmp_path,
"save_sections": True,
"log_to_file": True,
"frame_rate": 15,
"pixel_height": 854,
"pixel_width": 480,
"sections_dir": "{media_dir}/test_sections",
"video_dir": "{media_dir}/test_video",
"partial_movie_dir": "{media_dir}/test_partial_movie_dir",
"images_dir": "{media_dir}/test_images",
"text_dir": "{media_dir}/test_text",
"tex_dir": "{media_dir}/test_tex",
"log_dir": "{media_dir}/test_log",
}
):
scene = MyScene()
scene.render()
tmp_path = Path(tmp_path)
assert_dir_filled(tmp_path / "test_sections")
assert_file_exists(tmp_path / "test_sections/MyScene.json")
def test_custom_dirs(tmp_path, config):
config.media_dir = tmp_path
config.save_sections = True
config.log_to_file = True
config.frame_rate = 15
config.pixel_height = 854
config.pixel_width = 480
config.sections_dir = "{media_dir}/test_sections"
config.video_dir = "{media_dir}/test_video"
config.partial_movie_dir = "{media_dir}/test_partial_movie_dir"
config.images_dir = "{media_dir}/test_images"
config.text_dir = "{media_dir}/test_text"
config.tex_dir = "{media_dir}/test_tex"
config.log_dir = "{media_dir}/test_log"
assert_dir_filled(tmp_path / "test_video")
assert_file_exists(tmp_path / "test_video/MyScene.mp4")
scene = MyScene()
scene.render()
tmp_path = Path(tmp_path)
assert_dir_filled(tmp_path / "test_sections")
assert_file_exists(tmp_path / "test_sections/MyScene.json")
assert_dir_filled(tmp_path / "test_partial_movie_dir")
assert_file_exists(
tmp_path / "test_partial_movie_dir/partial_movie_file_list.txt"
)
assert_dir_filled(tmp_path / "test_video")
assert_file_exists(tmp_path / "test_video/MyScene.mp4")
# TODO: another example with image output would be nice
assert_dir_exists(tmp_path / "test_images")
assert_dir_filled(tmp_path / "test_partial_movie_dir")
assert_file_exists(tmp_path / "test_partial_movie_dir/partial_movie_file_list.txt")
assert_dir_filled(tmp_path / "test_text")
assert_dir_filled(tmp_path / "test_tex")
assert_dir_filled(tmp_path / "test_log")
# TODO: another example with image output would be nice
assert_dir_exists(tmp_path / "test_images")
assert_dir_filled(tmp_path / "test_text")
assert_dir_filled(tmp_path / "test_tex")
assert_dir_filled(tmp_path / "test_log")
def test_frame_size(tmp_path):
def test_pixel_dimensions(tmp_path, config):
tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False)
tmp_cfg.write(
"""
[CLI]
pixel_height = 10
pixel_width = 10
""",
)
tmp_cfg.close()
config.digest_file(tmp_cfg.name)
# aspect ratio is set using pixel measurements
np.testing.assert_allclose(config.aspect_ratio, 1.0)
# if not specified in the cfg file, frame_width is set using the aspect ratio
np.testing.assert_allclose(config.frame_height, 8.0)
np.testing.assert_allclose(config.frame_width, 8.0)
def test_frame_size(tmp_path, config):
"""Test that the frame size can be set via config file."""
np.testing.assert_allclose(
config.aspect_ratio, config.pixel_width / config.pixel_height
)
np.testing.assert_allclose(config.frame_height, 8.0)
with tempconfig({}):
tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False)
tmp_cfg.write(
"""
[CLI]
pixel_height = 10
pixel_width = 10
""",
)
tmp_cfg.close()
config.digest_file(tmp_cfg.name)
tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False)
tmp_cfg.write(
"""
[CLI]
pixel_height = 10
pixel_width = 10
frame_height = 10
frame_width = 10
""",
)
tmp_cfg.close()
config.digest_file(tmp_cfg.name)
# aspect ratio is set using pixel measurements
np.testing.assert_allclose(config.aspect_ratio, 1.0)
# if not specified in the cfg file, frame_width is set using the aspect ratio
np.testing.assert_allclose(config.frame_height, 8.0)
np.testing.assert_allclose(config.frame_width, 8.0)
with tempconfig({}):
tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False)
tmp_cfg.write(
"""
[CLI]
pixel_height = 10
pixel_width = 10
frame_height = 10
frame_width = 10
""",
)
tmp_cfg.close()
config.digest_file(tmp_cfg.name)
np.testing.assert_allclose(config.aspect_ratio, 1.0)
# if both are specified in the cfg file, the aspect ratio is ignored
np.testing.assert_allclose(config.frame_height, 10.0)
np.testing.assert_allclose(config.frame_width, 10.0)
np.testing.assert_allclose(config.aspect_ratio, 1.0)
# if both are specified in the cfg file, the aspect ratio is ignored
np.testing.assert_allclose(config.frame_height, 10.0)
np.testing.assert_allclose(config.frame_width, 10.0)
def test_temporary_dry_run():
def test_temporary_dry_run(config):
"""Test that tempconfig correctly restores after setting dry_run."""
assert config["write_to_movie"]
assert not config["save_last_frame"]
@ -191,24 +188,23 @@ def test_temporary_dry_run():
assert not config["save_last_frame"]
def test_dry_run_with_png_format():
def test_dry_run_with_png_format(config, dry_run):
"""Test that there are no exceptions when running a png without output"""
with tempconfig(
{"dry_run": True, "write_to_movie": False, "disable_caching": True}
):
assert config["dry_run"] is True
scene = MyScene()
scene.render()
config.write_to_movie = False
config.disable_caching = True
assert config.dry_run is True
scene = MyScene()
scene.render()
def test_dry_run_with_png_format_skipped_animations():
def test_dry_run_with_png_format_skipped_animations(config, dry_run):
"""Test that there are no exceptions when running a png without output and skipped animations"""
with tempconfig(
{"dry_run": True, "write_to_movie": False, "disable_caching": True}
):
assert config["dry_run"] is True
scene = MyScene(skip_animations=True)
scene.render()
config.write_to_movie = False
config.disable_caching = True
assert config["dry_run"] is True
scene = MyScene(skip_animations=True)
scene.render()
def test_tex_template_file(tmp_path):

View file

@ -2,30 +2,29 @@ from __future__ import annotations
import re
from manim import tempconfig
from manim.utils.ipython_magic import _generate_file_name
def test_jupyter_file_naming():
def test_jupyter_file_naming(config):
"""Check the format of file names for jupyter"""
scene_name = "SimpleScene"
expected_pattern = r"[0-9a-zA-Z_]+[@_-]\d\d\d\d-\d\d-\d\d[@_-]\d\d-\d\d-\d\d"
with tempconfig({"scene_names": [scene_name]}):
file_name = _generate_file_name()
match = re.match(expected_pattern, file_name)
assert scene_name in file_name, (
"Expected file to contain " + scene_name + " but got " + file_name
)
assert match, "file name does not match expected pattern " + expected_pattern
config.scene_names = [scene_name]
file_name = _generate_file_name()
match = re.match(expected_pattern, file_name)
assert scene_name in file_name, (
"Expected file to contain " + scene_name + " but got " + file_name
)
assert match, "file name does not match expected pattern " + expected_pattern
def test_jupyter_file_output(tmp_path):
def test_jupyter_file_output(tmp_path, config):
"""Check the jupyter file naming is valid and can be created"""
scene_name = "SimpleScene"
with tempconfig({"scene_names": [scene_name]}):
file_name = _generate_file_name()
actual_path = tmp_path.with_name(file_name)
with actual_path.open("w") as outfile:
outfile.write("")
assert actual_path.exists()
assert actual_path.is_file()
config.scene_names = [scene_name]
file_name = _generate_file_name()
actual_path = tmp_path.with_name(file_name)
with actual_path.open("w") as outfile:
outfile.write("")
assert actual_path.exists()
assert actual_path.is_file()

View file

@ -4,8 +4,6 @@ from pathlib import Path
import pytest
from manim import config, tempconfig
@pytest.fixture
def manim_cfg_file():
@ -18,30 +16,25 @@ def simple_scenes_path():
@pytest.fixture
def using_temp_config(tmpdir):
"""Standard fixture that makes tests use a standard_config.cfg with a temp dir."""
with tempconfig(
config.digest_file(Path(__file__).parent.parent / "standard_config.cfg"),
):
config.media_dir = tmpdir
yield
def standard_config(config):
return config.digest_file(Path(__file__).parent.parent / "standard_config.cfg")
@pytest.fixture
def using_temp_opengl_config(tmpdir):
def using_temp_config(tmpdir, standard_config):
"""Standard fixture that makes tests use a standard_config.cfg with a temp dir."""
with tempconfig(
config.digest_file(Path(__file__).parent.parent / "standard_config.cfg"),
):
config.media_dir = tmpdir
config.renderer = "opengl"
yield
standard_config.media_dir = tmpdir
@pytest.fixture
def disabling_caching():
with tempconfig({"disable_caching": True}):
yield
def using_temp_opengl_config(tmpdir, standard_config, using_opengl_renderer):
"""Standard fixture that makes tests use a standard_config.cfg with a temp dir."""
standard_config.media_dir = tmpdir
@pytest.fixture
def disabling_caching(config):
config.disable_caching = True
@pytest.fixture
@ -50,18 +43,12 @@ def infallible_scenes_path():
@pytest.fixture
def use_opengl_renderer(enable_preview):
with tempconfig({"renderer": "opengl", "preview": enable_preview}):
yield
def force_window_config_write_to_movie(config):
config.force_window = True
config.write_to_movie = True
@pytest.fixture
def force_window_config_write_to_movie():
with tempconfig({"force_window": True, "write_to_movie": True}):
yield
@pytest.fixture
def force_window_config_pngs():
with tempconfig({"force_window": True, "format": "png"}):
yield
def force_window_config_pngs(config):
config.force_window = True
config.format = "png"

View file

@ -3,6 +3,7 @@ from __future__ import annotations
import platform
from unittest.mock import Mock
import numpy as np
import pytest
from manim.renderer.opengl_renderer import OpenGLRenderer
@ -10,18 +11,21 @@ from tests.assert_utils import assert_file_exists
from tests.test_scene_rendering.simple_scenes import *
def test_write_to_movie_disables_window(using_temp_opengl_config, disabling_caching):
def test_write_to_movie_disables_window(
config, using_temp_opengl_config, disabling_caching
):
"""write_to_movie should disable window by default"""
scene = SquareToCircle()
renderer = scene.renderer
renderer.update_frame = Mock(wraps=renderer.update_frame)
scene.render()
assert renderer.window is None
assert_file_exists(config["output_file"])
assert_file_exists(config.output_file)
@pytest.mark.skip(reason="Temporarily skip due to failing in Windows CI") # type: ignore
def test_force_window_opengl_render_with_movies(
config,
using_temp_opengl_config,
force_window_config_write_to_movie,
disabling_caching,
@ -53,9 +57,10 @@ def test_force_window_opengl_render_with_format(
renderer.window.close()
@pytest.mark.parametrize("enable_preview", [False])
def test_get_frame_with_preview_disabled(use_opengl_renderer):
def test_get_frame_with_preview_disabled(config, using_opengl_renderer):
"""Get frame is able to fetch frame with the correct dimensions when preview is disabled"""
config.preview = False
scene = SquareToCircle()
assert isinstance(scene.renderer, OpenGLRenderer)
assert not config.preview
@ -70,9 +75,10 @@ def test_get_frame_with_preview_disabled(use_opengl_renderer):
@pytest.mark.slow
@pytest.mark.parametrize("enable_preview", [True])
def test_get_frame_with_preview_enabled(use_opengl_renderer):
def test_get_frame_with_preview_enabled(config, using_opengl_renderer):
"""Get frame is able to fetch frame with the correct dimensions when preview is enabled"""
config.preview = True
scene = SquareToCircle()
assert isinstance(scene.renderer, OpenGLRenderer)
assert config.preview is True
@ -86,8 +92,9 @@ def test_get_frame_with_preview_enabled(use_opengl_renderer):
assert renderer.get_pixel_shape()[1] == frame.shape[0]
@pytest.mark.parametrize("enable_preview", [True])
def test_pixel_coords_to_space_coords(use_opengl_renderer):
def test_pixel_coords_to_space_coords(config, using_opengl_renderer):
config.preview = True
scene = SquareToCircle()
assert isinstance(scene.renderer, OpenGLRenderer)

View file

@ -5,8 +5,11 @@ from unittest.mock import Mock
import pytest
from manim import *
from manim import config
from manim import (
Scene,
ValueTracker,
np,
)
from ..simple_scenes import (
SceneForFrozenFrameTests,
@ -23,7 +26,7 @@ from ..simple_scenes import (
reason="Mock object has a different implementation in python 3.7, which makes it broken with this logic.",
)
@pytest.mark.parametrize("frame_rate", argvalues=[15, 30, 60])
def test_t_values(using_temp_opengl_config, disabling_caching, frame_rate):
def test_t_values(config, using_temp_opengl_config, disabling_caching, frame_rate):
"""Test that the framerate corresponds to the number of t values generated"""
config.frame_rate = frame_rate
scene = SquareToCircle()
@ -36,10 +39,6 @@ def test_t_values(using_temp_opengl_config, disabling_caching, frame_rate):
)
@pytest.mark.skipif(
sys.version_info < (3, 8),
reason="Mock object has a different implementation in python 3.7, which makes it broken with this logic.",
)
def test_t_values_with_skip_animations(using_temp_opengl_config, disabling_caching):
"""Test the behaviour of scene.skip_animations"""
scene = SquareToCircle()
@ -95,7 +94,7 @@ def test_t_values_with_cached_data(using_temp_opengl_config):
@pytest.mark.xfail(reason="Not currently handled correctly for opengl")
def test_t_values_save_last_frame(using_temp_opengl_config):
def test_t_values_save_last_frame(config, using_temp_opengl_config):
"""Test that there is only one t value handled when only saving the last frame"""
config.save_last_frame = True
scene = SquareToCircle()

View file

@ -4,6 +4,21 @@ from enum import Enum
from manim import *
__all__ = [
"SquareToCircle",
"SceneWithMultipleCalls",
"SceneWithMultipleWaitCalls",
"NoAnimations",
"SceneWithStaticWait",
"SceneWithSceneUpdater",
"SceneForFrozenFrameTests",
"SceneWithNonStaticWait",
"StaticScene",
"InteractiveStaticScene",
"SceneWithSections",
"ElaborateSceneWithSections",
]
class SquareToCircle(Scene):
def construct(self):

View file

@ -5,8 +5,14 @@ from unittest.mock import Mock
import pytest
from manim import *
from manim import config
from manim import (
Dot,
Mobject,
Scene,
ValueTracker,
Wait,
np,
)
from .simple_scenes import (
SceneForFrozenFrameTests,
@ -18,12 +24,8 @@ from .simple_scenes import (
)
@pytest.mark.skipif(
sys.version_info < (3, 8),
reason="Mock object has a different implementation in python 3.7, which makes it broken with this logic.",
)
@pytest.mark.parametrize("frame_rate", argvalues=[15, 30, 60])
def test_t_values(using_temp_config, disabling_caching, frame_rate):
def test_t_values(config, using_temp_config, disabling_caching, frame_rate):
"""Test that the framerate corresponds to the number of t values generated"""
config.frame_rate = frame_rate
scene = SquareToCircle()
@ -110,7 +112,7 @@ def test_t_values_with_cached_data(using_temp_config):
assert scene.update_to_time.call_count == 10
def test_t_values_save_last_frame(using_temp_config):
def test_t_values_save_last_frame(config, using_temp_config):
"""Test that there is only one t value handled when only saving the last frame"""
config.save_last_frame = True
scene = SquareToCircle()