예제 #1
0
    def __init__(self, scene_class, module_tested, tmpdir, rgb_atol=0):
        # Disable the the logs, (--quiet is broken) TODO
        logging.disable(logging.CRITICAL)
        tests_directory = Path(__file__).absolute().parent.parent

        self.path_tests_medias_cache = (
            Path(tmpdir)
            / "test_graphical_units"
            / "tests_cache"
            / module_tested
            / scene_class.__name__
        )

        self.path_control_data = (
            Path(tests_directory)
            / "control_data"
            / "graphical_units_data"
            / module_tested
        )
        self.rgb_atol = rgb_atol

        # IMPORTANT NOTE : The graphical units tests don't use for now any
        # custom manim.cfg, since it is impossible to manually select a
        # manim.cfg from a python file. (see issue #293)
        config["text_dir"] = Path(self.path_tests_medias_cache) / "Text"
        config["tex_dir"] = Path(self.path_tests_medias_cache) / "Tex"

        config["disable_caching"] = True
        config["quality"] = "low_quality"

        for dir_temp in [
            self.path_tests_medias_cache,
            config["text_dir"],
            config["tex_dir"],
        ]:
            Path(dir_temp).mkdir(parents=True)

        with tempconfig({"dry_run": True}):
            if config["renderer"] == "opengl":
                self.scene = scene_class(renderer=OpenGLRenderer())
            else:
                self.scene = scene_class(skip_animations=True)
            self.scene.render()
예제 #2
0
    def __init__(self, scene_class, module_tested, tmpdir, rgb_atol=0):
        # Disable the the logs, (--quiet is broken) TODO
        logging.disable(logging.CRITICAL)
        tests_directory = os.path.dirname(
            os.path.dirname(os.path.abspath(__file__)))
        self.path_tests_medias_cache = os.path.join(
            tmpdir,
            "test_graphical_units",
            "tests_cache",
            module_tested,
            scene_class.__name__,
        )
        self.path_control_data = os.path.join(
            tests_directory,
            "control_data",
            "graphical_units_data",
            module_tested,
        )
        self.rgb_atol = rgb_atol

        # IMPORTANT NOTE : The graphical units tests don't use for now any
        # custom manim.cfg, since it is impossible to manually select a
        # manim.cfg from a python file. (see issue #293)
        config["text_dir"] = os.path.join(self.path_tests_medias_cache, "Text")
        config["tex_dir"] = os.path.join(self.path_tests_medias_cache, "Tex")

        config["disable_caching"] = True
        config["quality"] = "low_quality"

        for dir_temp in [
                self.path_tests_medias_cache,
                config["text_dir"],
                config["tex_dir"],
        ]:
            os.makedirs(dir_temp)

        with tempconfig({"dry_run": True}):
            if config["renderer"] == "opengl":
                self.scene = scene_class(renderer=OpenGLRenderer())
            else:
                self.scene = scene_class(skip_animations=True)
            self.scene.render()
예제 #3
0
def render(**args, ):
    """Render SCENE(S) from the input FILE.

    FILE is the file path of the script or a config file.

    SCENES is an optional list of scenes in the file.
    """

    if args["use_opengl_renderer"]:
        logger.warning(
            "--use_opengl_renderer is deprecated, please use --renderer=opengl instead!",
        )
        args["renderer"] = "opengl"

    if args["use_webgl_renderer"]:
        logger.warning(
            "--use_webgl_renderer is deprecated, please use --renderer=webgl instead!",
        )
        args["renderer"] = "webgl"

    if args["use_webgl_renderer"] and args["use_opengl_renderer"]:
        logger.warning("You may select only one renderer!")
        sys.exit()

    if args["save_as_gif"]:
        logger.warning(
            "--save_as_gif is deprecated, please use --format=gif instead!")
        args["format"] = "gif"

    if args["save_pngs"]:
        logger.warning(
            "--save_pngs is deprecated, please use --format=png instead!")
        args["format"] = "png"

    if args["show_in_file_browser"]:
        logger.warning(
            "The short form of show_in_file_browser is deprecated and will be moved to support --format.",
        )

    class ClickArgs:
        def __init__(self, args):
            for name in args:
                setattr(self, name, args[name])

        def _get_kwargs(self):
            return list(self.__dict__.items())

        def __eq__(self, other):
            if not isinstance(other, ClickArgs):
                return NotImplemented
            return vars(self) == vars(other)

        def __contains__(self, key):
            return key in self.__dict__

        def __repr__(self):
            return str(self.__dict__)

    click_args = ClickArgs(args)
    if args["jupyter"]:
        return click_args

    config.digest_args(click_args)
    file = Path(config.input_file)
    if config.renderer == "opengl":
        from manim.renderer.opengl_renderer import OpenGLRenderer

        try:
            renderer = OpenGLRenderer()
            keep_running = True
            while keep_running:
                for SceneClass in scene_classes_from_file(file):
                    scene = SceneClass(renderer)
                    rerun = scene.render()
                    if rerun or config["write_all"]:
                        renderer.num_plays = 0
                        continue
                    else:
                        keep_running = False
                        break
                if config["write_all"]:
                    keep_running = False

        except Exception:
            error_console.print_exception()
            sys.exit(1)
    elif config.renderer == "webgl":
        try:
            from manim.grpc.impl import frame_server_impl

            server = frame_server_impl.get(file)
            server.start()
            server.wait_for_termination()
        except ModuleNotFoundError:
            console.print(
                "Dependencies for the WebGL render are missing. Run "
                "pip install manim[webgl_renderer] to install them.", )
            error_console.print_exception()
            sys.exit(1)
    else:
        for SceneClass in scene_classes_from_file(file):
            try:
                scene = SceneClass()
                scene.render()
            except Exception:
                error_console.print_exception()
                sys.exit(1)

    if config.notify_outdated_version:
        manim_info_url = "https://pypi.org/pypi/manim/json"
        warn_prompt = "Cannot check if latest release of manim is installed"
        req_info = {}

        try:
            req_info = requests.get(manim_info_url)
            req_info.raise_for_status()

            stable = req_info.json()["info"]["version"]
            if stable != __version__:
                console.print(
                    f"You are using manim version [red]v{__version__}[/red], but version [green]v{stable}[/green] is available.",
                )
                console.print(
                    "You should consider upgrading via [yellow]pip install -U manim[/yellow]",
                )
        except requests.exceptions.HTTPError:
            logger.debug(f"HTTP Error: {warn_prompt}")
        except requests.exceptions.ConnectionError:
            logger.debug(f"Connection Error: {warn_prompt}")
        except requests.exceptions.Timeout:
            logger.debug(f"Timed Out: {warn_prompt}")
        except json.JSONDecodeError:
            logger.debug(warn_prompt)
            logger.debug(f"Error decoding JSON from {manim_info_url}")
        except Exception:
            logger.debug(f"Something went wrong: {warn_prompt}")

    return args
예제 #4
0
        def manim(
            self,
            line: str,
            cell: str = None,
            local_ns: dict[str, Any] = None,
        ) -> None:
            r"""Render Manim scenes contained in IPython cells.
            Works as a line or cell magic.

            .. hint::

                This line and cell magic works best when used in a JupyterLab
                environment: while all of the functionality is available for
                classic Jupyter notebooks as well, it is possible that videos
                sometimes don't update on repeated execution of the same cell
                if the scene name stays the same.

                This problem does not occur when using JupyterLab.

            Please refer to `<https://jupyter.org/>`_ for more information about JupyterLab
            and Jupyter notebooks.

            Usage in line mode::

                %manim [CLI options] MyAwesomeScene

            Usage in cell mode::

                %%manim [CLI options] MyAwesomeScene

                class MyAweseomeScene(Scene):
                    def construct(self):
                        ...

            Run ``%manim --help`` and ``%manim render --help`` for possible command line interface options.

            .. note::

                The maximal width of the rendered videos that are displayed in the notebook can be
                configured via the ``media_width`` configuration option. The default is set to ``25vw``,
                which is 25% of your current viewport width. To allow the output to become as large
                as possible, set ``config.media_width = "100%"``.

            Examples
            --------

            First make sure to put ``import manim``, or even ``from manim import *``
            in a cell and evaluate it. Then, a typical Jupyter notebook cell for Manim
            could look as follows::

                %%manim -v WARNING --disable_caching -qm BannerExample

                config.media_width = "75%"

                class BannerExample(Scene):
                    def construct(self):
                        self.camera.background_color = "#ece6e2"
                        banner_large = ManimBanner(dark_theme=False).scale(0.7)
                        self.play(banner_large.create())
                        self.play(banner_large.expand())

            Evaluating this cell will render and display the ``BannerExample`` scene defined in the body of the cell.

            .. note::

                In case you want to hide the red box containing the output progress bar, the ``progress_bar`` config
                option should be set to ``None``. This can also be done by passing ``--progress_bar None`` as a
                CLI flag.

            """
            if cell:
                exec(cell, local_ns)

            args = line.split()
            if not len(args) or "-h" in args or "--help" in args or "--version" in args:
                main(args, standalone_mode=False, prog_name="manim")
                return
            modified_args = self.add_additional_args(args)
            args = main(modified_args, standalone_mode=False, prog_name="manim")
            with tempconfig(local_ns.get("config", {})):
                config.digest_args(args)

                renderer = None
                if config.renderer == "opengl":
                    # Check if the imported mobjects extend the OpenGLMobject class
                    # meaning ConvertToOpenGL did its job
                    if "OpenGLMobject" in map(lambda cls: cls.__name__, Group.mro()):
                        from manim.renderer.opengl_renderer import OpenGLRenderer

                        renderer = OpenGLRenderer()
                    else:
                        logger.warning(
                            "Renderer must be set to OpenGL in the configuration file "
                            "before importing Manim! Using cairo renderer instead.",
                        )
                        config.renderer = "cairo"

                try:
                    SceneClass = local_ns[config["scene_names"][0]]
                    scene = SceneClass(renderer=renderer)
                    scene.render()
                finally:
                    # Shader cache becomes invalid as the context is destroyed
                    shader_program_cache.clear()

                    # Close OpenGL window here instead of waiting for the main thread to
                    # finish causing the window to stay open and freeze
                    if renderer is not None and renderer.window is not None:
                        renderer.window.close()

                if config["output_file"] is None:
                    logger.info("No output file produced")
                    return

                local_path = Path(config["output_file"]).relative_to(Path.cwd())
                tmpfile = (
                    Path(config["media_dir"])
                    / "jupyter"
                    / f"{_generate_file_name()}{local_path.suffix}"
                )

                if local_path in self.rendered_files:
                    self.rendered_files[local_path].unlink()
                self.rendered_files[local_path] = tmpfile
                os.makedirs(tmpfile.parent, exist_ok=True)
                shutil.copy(local_path, tmpfile)

                file_type = mimetypes.guess_type(config["output_file"])[0]
                if file_type.startswith("image"):
                    display(Image(filename=config["output_file"]))
                    return

                # videos need to be embedded when running in google colab
                video_embed = "google.colab" in str(get_ipython())

                display(
                    Video(
                        tmpfile,
                        html_attributes=f'controls autoplay loop style="max-width: {config["media_width"]};"',
                        embed=video_embed,
                    ),
                )
예제 #5
0
def main():
    console.print(f"Manim Community [green]v{__version__}[/green]")
    args = parse_args(sys.argv)

    if hasattr(args, "cmd"):
        if args.cmd == "cfg":
            if args.subcmd:
                from manim._config import cfg_subcmds

                if args.subcmd == "write":
                    cfg_subcmds.write(args.level, args.open)
                elif args.subcmd == "show":
                    cfg_subcmds.show()
                elif args.subcmd == "export":
                    cfg_subcmds.export(args.dir)
            else:
                logger.error("No subcommand provided; Exiting...")

        elif args.cmd == "plugins":
            from manim.plugins import plugins_flags

            if args.list:
                plugins_flags.list_plugins()
            elif not args.list:
                logger.error("No flag provided; Exiting...")

        # elif args.cmd == "some_other_cmd":
        #     something_else_here()

    else:
        config.digest_args(args)
        input_file = config.get_dir("input_file")

        if config["use_opengl_renderer"]:
            from manim.renderer.opengl_renderer import OpenGLRenderer

            for SceneClass in scene_classes_from_file(input_file):
                try:
                    renderer = OpenGLRenderer()
                    scene = SceneClass(renderer)
                    scene.render()
                except Exception:
                    console.print_exception()
        elif config["use_webgl_renderer"]:
            try:
                from manim.grpc.impl import frame_server_impl

                server = frame_server_impl.get(input_file)
                server.start()
                server.wait_for_termination()
            except ModuleNotFoundError as e:
                console.print(
                    "Dependencies for the WebGL render are missing. Run "
                    "pip install manim[webgl_renderer] to install them.")
                console.print_exception()
        else:
            for SceneClass in scene_classes_from_file(input_file):
                try:
                    scene = SceneClass()
                    scene.render()
                except Exception:
                    console.print_exception()
예제 #6
0
def render(
    ctx,
    **args,
):
    """Render SCENE(S) from the input FILE.

    FILE is the file path of the script.

    SCENES is an optional list of scenes in the file.
    """
    for scene in args["scene_names"]:
        if str(scene).startswith("-"):
            logger.warning(
                dedent(
                    """\
                Manim Community has moved to Click for the CLI.

                This means that options in the CLI are provided BEFORE the positional
                arguments for your FILE and SCENE(s):
                `manim render [OPTIONS] [FILE] [SCENES]...`

                For example:
                New way - `manim -p -ql file.py SceneName1 SceneName2 ...`
                Old way - `manim file.py SceneName1 SceneName2 ... -p -ql`

                To see the help page for the new available options, run:
                `manim render -h`
                """
                )
            )
            sys.exit()

    if args["use_opengl_renderer"]:
        logger.warning(
            "--use_opengl_renderer is deprecated, please use --renderer=opengl instead!"
        )
        renderer = "opengl"

    if args["use_webgl_renderer"]:
        logger.warning(
            "--use_webgl_renderer is deprecated, please use --renderer=webgl instead!"
        )
        renderer = "webgl"

    if args["use_webgl_renderer"] and args["use_opengl_renderer"]:
        logger.warning("You may select only one renderer!")
        sys.exit()

    class ClickArgs:
        def __init__(self, args):
            for name in args:
                setattr(self, name, args[name])

        def _get_kwargs(self):
            return list(self.__dict__.items())

        def __eq__(self, other):
            if not isinstance(other, ClickArgs):
                return NotImplemented
            return vars(self) == vars(other)

        def __contains__(self, key):
            return key in self.__dict__

        def __repr__(self):
            return str(self.__dict__)

    click_args = ClickArgs(args)
    if args["jupyter"]:
        return click_args

    config.digest_args(click_args)
    file = args["file"]
    if config.renderer == "opengl":
        from manim.renderer.opengl_renderer import OpenGLRenderer

        for SceneClass in scene_classes_from_file(file):
            try:
                renderer = OpenGLRenderer()
                scene = SceneClass(renderer)
                scene.render()
            except Exception:
                console.print_exception()
    elif config.renderer == "webgl":
        try:
            from manim.grpc.impl import frame_server_impl

            server = frame_server_impl.get(file)
            server.start()
            server.wait_for_termination()
        except ModuleNotFoundError:
            console.print(
                "Dependencies for the WebGL render are missing. Run "
                "pip install manim[webgl_renderer] to install them."
            )
            console.print_exception()
    else:
        for SceneClass in scene_classes_from_file(file):
            try:
                scene = SceneClass()
                scene.render()
            except Exception:
                console.print_exception()

    if config.notify_outdated_version:
        manim_info_url = "https://pypi.org/pypi/manim/json"
        warn_prompt = "Cannot check if latest release of manim is installed"
        req_info = {}

        try:
            req_info = requests.get(manim_info_url)
            req_info.raise_for_status()
        except requests.exceptions.HTTPError:
            logger.debug(f"HTTP Error: {warn_prompt}")
        except requests.exceptions.ConnectionError:
            logger.debug(f"Connection Error: {warn_prompt}")
        except requests.exceptions.Timeout:
            logger.debug(f"Timed Out: {warn_prompt}")
        except Exception:
            logger.debug(f"Something went wrong: {warn_prompt}")

        try:
            stable = req_info.json()["info"]["version"]

            if stable != __version__:
                console.print(
                    f"You are using manim version [red]v{__version__}[/red], but version [green]v{stable}[/green] is available."
                )
                console.print(
                    "You should consider upgrading via [yellow]pip install -U manim[/yellow]"
                )
        except json.JSONDecodeError:
            logger.debug(warn_prompt)
            logger.debug(f"Error decoding JSON from {manim_info_url}")

    return args
예제 #7
0
def render(
    ctx,
    **args,
):
    """Render SCENE(S) from the input FILE.

    FILE is the file path of the script.

    SCENES is an optional list of scenes in the file.
    """
    for scene in args["scene_names"]:
        if str(scene).startswith("-"):
            logger.warning(
                dedent("""\
                Manim Community has moved to Click for the CLI.

                This means that options in the CLI are provided BEFORE the positional
                arguments for your FILE and SCENE(s):
                `manim render [OPTIONS] [FILE] [SCENES]...`

                For example:
                New way - `manim -p -ql file.py SceneName1 SceneName2 ...`
                Old way - `manim file.py SceneName1 SceneName2 ... -p -ql`

                To see the help page for the new available options, run:
                `manim render -h`
                """))
            sys.exit()

    if args["use_opengl_renderer"]:
        logger.warning(
            "--use_opengl_renderer is deprecated, please use --renderer=opengl instead!"
        )
        renderer = "opengl"

    if args["use_webgl_renderer"]:
        logger.warning(
            "--use_webgl_renderer is deprecated, please use --renderer=webgl instead!"
        )
        renderer = "webgl"

    if args["use_webgl_renderer"] and args["use_opengl_renderer"]:
        logger.warning("You may select only one renderer!")
        sys.exit()

    class ClickArgs:
        def __init__(self, args):
            for name in args:
                setattr(self, name, args[name])

        def _get_kwargs(self):
            return list(self.__dict__.items())

        def __eq__(self, other):
            if not isinstance(other, ClickArgs):
                return NotImplemented
            return vars(self) == vars(other)

        def __contains__(self, key):
            return key in self.__dict__

        def __repr__(self):
            return str(self.__dict__)

    click_args = ClickArgs(args)
    if args["jupyter"]:
        return click_args

    config.digest_args(click_args)
    file = args["file"]
    if config.renderer == "opengl":
        from manim.renderer.opengl_renderer import OpenGLRenderer

        for SceneClass in scene_classes_from_file(file):
            try:
                renderer = OpenGLRenderer()
                scene = SceneClass(renderer)
                scene.render()
            except Exception:
                console.print_exception()
    elif config.renderer == "webgl":
        try:
            from manim.grpc.impl import frame_server_impl

            server = frame_server_impl.get(file)
            server.start()
            server.wait_for_termination()
        except ModuleNotFoundError:
            console.print("Dependencies for the WebGL render are missing. Run "
                          "pip install manim[webgl_renderer] to install them.")
            console.print_exception()
    else:
        for SceneClass in scene_classes_from_file(file):
            try:
                scene = SceneClass()
                scene.render()
            except Exception:
                console.print_exception()

    return args