Esempio n. 1
0
def test_mobject_add():
    """Test Mobject.add()."""
    obj = Mobject()
    container_add(obj, lambda: obj.submobjects)

    # a Mobject cannot contain itself
    with pytest.raises(ValueError):
        obj.add(obj)
Esempio n. 2
0
def test_vgroup_init():
    """Test the VGroup instantiation."""
    VGroup()
    VGroup(VMobject())
    VGroup(VMobject(), VMobject())
    with pytest.raises(TypeError):
        VGroup(Mobject())
    with pytest.raises(TypeError):
        VGroup(Mobject(), Mobject())
Esempio n. 3
0
def test_overlapping_family():
    """Check that each member of the family is only gathered once."""
    mob, child1, child2, = Mobject(), Mobject(), Mobject(),
    gchild1, gchild2, gchild_common = Mobject(), Mobject(), Mobject()
    child1.add(gchild1, gchild_common)
    child2.add(gchild2, gchild_common)
    mob.add(child1, child2)
    family = mob.get_family()
    assert mob in family
    assert len(family) == 6
    assert family.count(gchild_common) == 1
Esempio n. 4
0
def container_remove(obj, get_submobjects):
    """Call this function with a Container instance to test its remove() method."""
    to_remove = Mobject()
    obj.add(to_remove)
    obj.add(*(Mobject() for _ in range(10)))
    assert len(get_submobjects()) == 11
    obj.remove(to_remove)
    assert len(get_submobjects()) == 10
    obj.remove(to_remove)
    assert len(get_submobjects()) == 10

    # check that Container.remove() returns the instance (for chained calls)
    assert obj.add(Mobject()) is obj
Esempio n. 5
0
def test_vgroup_add():
    """Test the VGroup add method."""
    obj = VGroup()
    assert len(obj.submobjects) == 0
    obj.add(VMobject())
    assert len(obj.submobjects) == 1
    with pytest.raises(TypeError):
        obj.add(Mobject())
    assert len(obj.submobjects) == 1
    with pytest.raises(TypeError):
        # If only one of the added object is not an instance of VMobject, none of them should be added
        obj.add(VMobject(), Mobject())
    assert len(obj.submobjects) == 1
    with pytest.raises(ValueError):
        # a Mobject cannot contain itself
        obj.add(obj)
Esempio n. 6
0
def test_bracelabel_copy(tmp_path):
    """Test that a copy is a deepcopy."""
    # For this test to work, we need to tweak some folders temporarily
    original_text_dir = file_writer_config["text_dir"]
    original_tex_dir = file_writer_config["tex_dir"]
    mediadir = os.path.join(tmp_path, "deepcopy")
    file_writer_config["text_dir"] = os.path.join(mediadir, "Text")
    file_writer_config["tex_dir"] = os.path.join(mediadir, "Tex")
    for el in ["text_dir", "tex_dir"]:
        os.makedirs(file_writer_config[el])

    # Before the refactoring of Mobject.copy(), the class BraceLabel was the
    # only one to have a non-trivial definition of copy.  Here we test that it
    # still works after the refactoring.
    orig = BraceLabel(Mobject(), "label")
    copy = orig.copy()

    assert orig is orig
    assert orig is not copy
    assert orig.brace is not copy.brace
    assert orig.label is not copy.label
    assert orig.submobjects is not copy.submobjects
    assert orig.submobjects[0] is orig.brace
    assert copy.submobjects[0] is copy.brace
    assert orig.submobjects[0] is not copy.brace
    assert copy.submobjects[0] is not orig.brace

    # Restore the original folders
    file_writer_config["text_dir"] = original_text_dir
    file_writer_config["tex_dir"] = original_tex_dir
Esempio n. 7
0
def test_bracelabel_copy(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"]
    original_tex_dir = config["tex_dir"]
    mediadir = Path(tmp_path) / "deepcopy"
    config["text_dir"] = str(mediadir.joinpath("Text"))
    config["tex_dir"] = str(mediadir.joinpath("Tex"))
    for el in ["text_dir", "tex_dir"]:
        Path(config[el]).mkdir(parents=True)

    # Before the refactoring of Mobject.copy(), the class BraceLabel was the
    # only one to have a non-trivial definition of copy.  Here we test that it
    # still works after the refactoring.
    orig = BraceLabel(Mobject(), "label")
    copy = orig.copy()

    assert orig is orig
    assert orig is not copy
    assert orig.brace is not copy.brace
    assert orig.label is not copy.label
    assert orig.submobjects is not copy.submobjects
    assert orig.submobjects[0] is orig.brace
    assert copy.submobjects[0] is copy.brace
    assert orig.submobjects[0] is not copy.brace
    assert copy.submobjects[0] is not orig.brace

    # Restore the original folders
    config["text_dir"] = original_text_dir
    config["tex_dir"] = original_tex_dir
Esempio n. 8
0
def test_vdict_add():
    """Test the VDict add method."""
    obj = VDict()
    assert len(obj.submob_dict) == 0
    obj.add([("a", VMobject())])
    assert len(obj.submob_dict) == 1
    with pytest.raises(TypeError):
        obj.add([("b", Mobject())])
Esempio n. 9
0
def test_ABC():
    """Test that the Container class cannot be instantiated."""
    with pytest.raises(TypeError):
        Container()

    # The following should work without raising exceptions
    Mobject()
    Scene()
Esempio n. 10
0
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

        # 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.remove() returns the instance (for chained calls)
        assert scene.add(Mobject()) is scene
Esempio n. 11
0
def test_vgroup_add_dunder():
    """Test the VGroup __add__ magic method."""
    obj = VGroup()
    assert len(obj.submobjects) == 0
    obj + VMobject()
    assert len(obj.submobjects) == 0
    obj += VMobject()
    assert len(obj.submobjects) == 1
    with pytest.raises(TypeError):
        obj += Mobject()
    assert len(obj.submobjects) == 1
    with pytest.raises(TypeError):
        # If only one of the added object is not an instance of VMobject, none of them should be added
        obj += (VMobject(), Mobject())
    assert len(obj.submobjects) == 1
    with pytest.raises(Exception):  # TODO change this to ValueError once #307 is merged
        # a Mobject cannot contain itself
        obj += obj
Esempio n. 12
0
def container_add(obj, get_submobjects):
    """Call this function with a Container instance to test its add() method."""
    # check that obj.submobjects is updated correctly
    assert len(get_submobjects()) == 0
    obj.add(Mobject())
    assert len(get_submobjects()) == 1
    obj.add(*(Mobject() for _ in range(10)))
    assert len(get_submobjects()) == 11

    # check that adding a mobject twice does not actually add it twice
    repeated = Mobject()
    obj.add(repeated)
    assert len(get_submobjects()) == 12
    obj.add(repeated)
    assert len(get_submobjects()) == 12

    # check that Container.add() returns the Mobject (for chained calls)
    assert obj.add(Mobject()) is obj
def test_mobject_inheritance():
    mob = Mobject()
    a = MobjectA()
    b = MobjectB()
    c = MobjectC()

    assert type(AnimationA1(mob)) is AnimationA1
    assert type(AnimationA1(a)) is AnimationA2
    assert type(AnimationA1(b)) is AnimationA2
    assert type(AnimationA1(c)) is AnimationA3
Esempio n. 14
0
def test_set_color():
    m = Mobject()
    assert m.color.hex == "#fff"
    m.set_color(BLACK)
    assert m.color.hex == "#000"

    m = VMobject()
    assert m.color.hex == "#fff"
    m.set_color(BLACK)
    assert m.color.hex == "#000"
Esempio n. 15
0
def test_vdict_init():
    """Test the VDict instantiation."""
    # Test empty VDict
    VDict()
    # Test VDict made from list of pairs
    VDict([("a", VMobject()), ("b", VMobject()), ("c", VMobject())])
    # Test VDict made from a python dict
    VDict({"a": VMobject(), "b": VMobject(), "c": VMobject()})
    # Test VDict made using zip
    VDict(zip(["a", "b", "c"], [VMobject(), VMobject(), VMobject()]))
    # If the value is of type Mobject, must raise a TypeError
    with pytest.raises(TypeError):
        VDict({"a": Mobject()})
Esempio n. 16
0
def test_mobject_copy():
    """Test that a copy is a deepcopy."""
    orig = Mobject()
    orig.add(*[Mobject() for _ in range(10)])
    copy = orig.copy()

    assert orig is orig
    assert orig is not copy
    assert orig.submobjects is not copy.submobjects
    for i in range(10):
        assert orig.submobjects[i] is not copy.submobjects[i]
Esempio n. 17
0
    def add(
        self,
        name: str,
        val_orig: m.Mobject,
        highlight: m.Mobject = None,
        extra_animations: List[m.Animation] = None,
    ) -> None:
        """Add an name-value association to the context and return animations

        name -- the name part of the association
        val_orig -- a Mobject that is the value part of the association
        highlight -- a Mobject that should be highlighted before other animations are
            played, defaults to val_orig
        extra_animations -- animations to be played along the others during the last
            step

        This creates a copy of `val_orig` and sets its target to the position of
        the value in the context, the returned animations will make the copy
        move to this position.
        """
        self.scene.play(m.Indicate(highlight if highlight else val_orig))

        association = m.VDict([
            ("name", m.Tex(name, color=m.GRAY)),
            ("eq", m.Tex("=", color=m.GRAY)),
            ("val", val_orig.copy()),
        ])
        association["name"].move_to(self.entries[-1], aligned_edge=m.LEFT)
        association["eq"].next_to(association["name"], m.RIGHT)
        association["val"].generate_target().next_to(association["eq"],
                                                     m.RIGHT).set_color(m.GRAY)

        self.scene.play(
            m.ApplyMethod(self.entries.shift, m.UP * 0.5),
            m.FadeInFrom(association["name"], direction=m.DOWN),
            m.FadeInFrom(association["eq"], direction=m.DOWN),
            m.MoveToTarget(association["val"]),
            *(extra_animations if extra_animations else []),
        )
        self.entries.add(association)
        self.scene.remove(association)  # The previous line created a copy
Esempio n. 18
0
def test_mobject_add():
    """Test Mobject.add()."""
    """Call this function with a Container instance to test its add() method."""
    # check that obj.submobjects is updated correctly
    obj = Mobject()
    assert len(obj.submobjects) == 0
    obj.add(Mobject())
    assert len(obj.submobjects) == 1
    obj.add(*(Mobject() for _ in range(10)))
    assert len(obj.submobjects) == 11

    # check that adding a mobject twice does not actually add it twice
    repeated = Mobject()
    obj.add(repeated)
    assert len(obj.submobjects) == 12
    obj.add(repeated)
    assert len(obj.submobjects) == 12

    # check that Mobject.add() returns the Mobject (for chained calls)
    assert obj.add(Mobject()) is obj
    obj = Mobject()

    # a Mobject cannot contain itself
    with pytest.raises(ValueError):
        obj.add(obj)

    # can only add Mobjects
    with pytest.raises(TypeError):
        obj.add("foo")
Esempio n. 19
0
    def __init__(self,
                 source: Mobject,
                 target: Mobject,
                 label: Optional[str] = None,
                 font=DEFAULT_FONT,
                 **kwargs):
        """
        Args:
            source: The source object
            target: The target object
            label: The optional label text to put over the arrow
        """
        super().__init__(**kwargs)
        self.font = font
        label_direction = UP
        label_buff = 0

        arrow: Optional[Arrow] = None
        if source.get_x(RIGHT) <= target.get_x(LEFT):
            arrow = Arrow(start=source.get_edge_center(RIGHT),
                          end=target.get_edge_center(LEFT),
                          buff=0)
            label_direction = UP
        elif source.get_x(LEFT) >= target.get_x(RIGHT):
            arrow = Arrow(start=source.get_edge_center(LEFT),
                          end=target.get_edge_center(RIGHT),
                          buff=0)
            label_direction = UP
        elif source.get_y(DOWN) >= target.get_y(UP):
            arrow = Arrow(start=source.get_edge_center(DOWN),
                          end=target.get_edge_center(UP),
                          buff=0)
            label_direction = RIGHT
            label_buff = VERTICAL_ARROW_LABEL_BUFF
        elif source.get_y(UP) <= target.get_y(DOWN):
            arrow = Arrow(start=source.get_edge_center(UP),
                          end=target.get_edge_center(DOWN),
                          buff=0)
            label_direction = RIGHT
            label_buff = VERTICAL_ARROW_LABEL_BUFF

        if not arrow:
            raise ValueError("Unable to connect")

        self.add(arrow)
        if label:
            text = Text(label, font=self.font, size=0.5, slant=ITALIC)
            text.next_to(arrow, direction=label_direction, buff=label_buff)
            self.add(text)
Esempio n. 20
0
 def change_label(self, mob: Mobject) -> Mobject:
     mob.scale(self.font_scale)
     mob.move_to(self.value['label'].get_center())
     return self.value['label'].animate.become(mob)
Esempio n. 21
0
def test_mobject_remove():
    """Test Mobject.remove()."""
    obj = Mobject()
    container_remove(obj, lambda: obj.submobjects)
Esempio n. 22
0
def test_mobject_remove():
    """Test Mobject.remove()."""
    obj = Mobject()
    to_remove = Mobject()
    obj.add(to_remove)
    obj.add(*(Mobject() for _ in range(10)))
    assert len(obj.submobjects) == 11
    obj.remove(to_remove)
    assert len(obj.submobjects) == 10
    obj.remove(to_remove)
    assert len(obj.submobjects) == 10

    assert obj.remove(Mobject()) is obj
Esempio n. 23
0
    def connect(self, source: Mobject, target: Mobject, label: Optional[str] = None) -> Connection:

        result = Connection()
        label_direction = UP
        label_buff = 0

        arrow: Optional[Arrow] = None
        if source.get_x(RIGHT) <= target.get_x(LEFT):
            arrow = Arrow(start=source.get_edge_center(RIGHT), end=target.get_edge_center(LEFT), buff=0)
            label_direction = UP
        elif source.get_x(LEFT) >= target.get_x(RIGHT):
            arrow = Arrow(start=source.get_edge_center(LEFT), end=target.get_edge_center(RIGHT), buff=0)
            label_direction = UP
        elif source.get_y(DOWN) >= target.get_y(UP):
            arrow = Arrow(start=source.get_edge_center(DOWN), end=target.get_edge_center(UP), buff=0)
            label_direction = RIGHT
            label_buff = VERTICAL_ARROW_LABEL_BUFF
        elif source.get_y(UP) <= target.get_y(DOWN):
            arrow = Arrow(start=source.get_edge_center(UP), end=target.get_edge_center(DOWN), buff=0)
            label_direction = RIGHT
            label_buff = VERTICAL_ARROW_LABEL_BUFF

        if not arrow:
            raise ValueError("Unable to connect")

        result.add(arrow)
        if label:
            text = Text(label, font=self.text_font, size=0.7, slant=ITALIC)
            text.next_to(arrow, direction=label_direction, buff=label_buff)
            result.add(text)

        return result
Esempio n. 24
0
def test_family():
    """Check that the family is gathered correctly."""
    # Check that an empty mobject's family only contains itself
    mob = Mobject()
    assert mob.get_family() == [mob]

    # Check that all children are in the family
    mob = Mobject()
    children = [Mobject() for _ in range(10)]
    mob.add(*children)
    family = mob.get_family()
    assert len(family) == 1 + 10
    assert mob in family
    for c in children:
        assert c in family

    # Nested children should be in the family
    mob = Mobject()
    grandchildren = {}
    for _ in range(10):
        child = Mobject()
        grandchildren[child] = [Mobject() for _ in range(10)]
        child.add(*grandchildren[child])
    mob.add(*list(grandchildren.keys()))
    family = mob.get_family()
    assert len(family) == 1 + 10 + 10 * 10
    assert mob in family
    for c in grandchildren:
        assert c in family
        for gc in grandchildren[c]:
            assert gc in family
Esempio n. 25
0
    def eval_call(self, call: m.Mobject, val: int,
                  val_mobject: m.Mobject) -> Tuple[int, m.Mobject]:
        """Show the evaluation of one function call, recursively

        call: the manim object representing the call, expected to be oneline
        val: the value of `n` for that call

        Returns the value and the corresponding Mobject of the result of the call
        """
        context = CallContext(call, self)
        context.add("n", val_mobject)
        self.wait()

        # Evaluate the if's condition
        context.replace_occurrence(-1, call["if"]["cond"]["n"])
        self.wait()
        replace_expr(self, call["if"]["cond"],
                     f"\\verb|{str(val == 0).lower()}|")

        # Replace the expression with the correct if branch
        self.wait()
        self.play(m.Indicate(call["if"]["cond"]))
        if val == 0:
            bad = "rec"
            good = "base"
        else:
            good = "rec"
            bad = "base"
        strike_through = ThinLine(
            call[bad].get_corner(m.DL) + m.DL * 0.1,
            call[bad].get_corner(m.UR) + m.UR * 0.1,
        )
        rect = ThinRectangle().surround(call[good], stretch=True)
        self.play(m.ShowCreation(strike_through), m.ShowCreation(rect))
        self.wait()
        self.play(
            *map(m.FadeOut,
                 [strike_through, rect, call["if"], call[bad], call["else"]]))
        self.play(
            m.ApplyMethod(call[good].next_to, call.get_corner(m.LEFT),
                          m.RIGHT * 0.1))

        if val == 0:  # end of recursion
            self.play(*map(m.FadeOut, context.entries))
            return 1, call["base"]

        # Evaluate the expression containing the recursive call up to the call, starting
        # by the right-hand operand of the multiplication
        self.wait()
        self.play(m.Indicate(call["rec"]["call"]))
        context.replace_occurrence(-1, call["rec"]["call"]["arg"]["n"])
        self.wait(m.DEFAULT_WAIT_TIME / 2)
        replace_expr(self,
                     call["rec"]["call"]["arg"],
                     f"\\verb|{val - 1}|",
                     aligned_edge=m.LEFT)
        # Evaluate the recursive call
        rect = ThinRectangle(color=m.BLUE).surround(call["rec"]["call"],
                                                    stretch=True)
        def_instance = deepcopy(self.def_box["function"]).remove("fn")
        def_instance.generate_target().scale(1 / self.def_scale_ratio).next_to(
            rect, m.RIGHT * 5)
        lines = m.VGroup(
            ThinLine(
                rect.get_corner(m.RIGHT),
                def_instance.target.get_corner(m.LEFT) + m.LEFT * 0.2,
                color=m.BLUE,
            ),
            ThinLine(
                def_instance.target.get_corner(m.DL) + m.LEFT * 0.2,
                def_instance.target.get_corner(m.UL) + m.LEFT * 0.2,
                color=m.BLUE,
            ),
        )
        self.play(m.ShowCreation(rect))
        self.wait(m.DEFAULT_WAIT_TIME / 2)
        self.play(m.Indicate(self.def_box))
        self.play(m.MoveToTarget(def_instance), m.ShowCreation(lines))
        self.wait()
        shift_vector = (call["rec"]["call"]["arg"].get_center() -
                        val_mobject.get_center())
        self.play(
            m.ApplyMethod(self.camera.frame.shift, shift_vector),
            m.ApplyMethod(self.def_box.shift, shift_vector),
        )
        recursive_call_res, recursive_call_res_mobject = self.eval_call(
            def_instance, val - 1, call["rec"]["call"]["arg"])
        self.play(
            m.ApplyMethod(self.camera.frame.shift, -shift_vector),
            m.ApplyMethod(self.def_box.shift, -shift_vector),
        )
        self.play(
            m.FadeOut(lines),
            m.FadeOut(rect),
            m.FadeOut(call["rec"]["call"]),
            m.ApplyMethod(recursive_call_res_mobject.next_to, call["rec"]["*"],
                          m.RIGHT),
        )
        self.wait()
        call["rec"]["call"] = recursive_call_res_mobject
        # Evaluate the left-hand operand of the multiplication
        context.replace_occurrence(-1, call["rec"]["n"])
        res = val * recursive_call_res
        replace_expr(self, call["rec"], f"\\verb|{res}|", aligned_edge=m.LEFT)
        self.play(*map(m.FadeOut, context.entries))
        return res, call["rec"]