mirror of
https://github.com/ManimCommunity/manim.git
synced 2026-06-22 10:01:47 +00:00
Merge branch 'refactor-tests' of https://github.com/Darylgolden/manim into refactor-tests
This commit is contained in:
commit
f68dcbdab5
31 changed files with 521 additions and 3727 deletions
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
|
@ -45,7 +45,7 @@ jobs:
|
|||
|
||||
- name: Install Manim
|
||||
run: |
|
||||
poetry install -E webgl_renderer
|
||||
poetry install
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
|
|
@ -202,7 +202,7 @@ jobs:
|
|||
- name: Install manim
|
||||
run: |
|
||||
poetry config experimental.new-installer false
|
||||
poetry install -E webgl_renderer
|
||||
poetry install
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ repos:
|
|||
flake8-docstrings==1.6.0, flake8-rst-docstrings==0.2.3,
|
||||
flake8-pytest-style==1.5.0, flake8-simplify==0.14.1, flake8-comprehensions>=3.6.1]
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: 'v0.941'
|
||||
rev: 'v0.942'
|
||||
hooks:
|
||||
- id: mypy
|
||||
additional_dependencies: [types-decorator, types-docutils, types-requests, types-setuptools]
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ RUN wget -O /tmp/install-tl-unx.tar.gz http://mirror.ctan.org/systems/texlive/tl
|
|||
# clone and build manim
|
||||
COPY . /opt/manim
|
||||
WORKDIR /opt/manim
|
||||
RUN pip install --no-cache .[jupyterlab,webgl_renderer]
|
||||
RUN pip install --no-cache .[jupyterlab]
|
||||
|
||||
RUN pip install -r docs/requirements.txt
|
||||
|
||||
|
|
|
|||
|
|
@ -360,7 +360,6 @@ A list of all config options
|
|||
'progress_bar', 'quality', 'right_side', 'save_as_gif', 'save_last_frame',
|
||||
'save_pngs', 'scene_names', 'show_in_file_browser', 'sound', 'tex_dir',
|
||||
'tex_template', 'tex_template_file', 'text_dir', 'top', 'transparent',
|
||||
'upto_animation_number', 'use_opengl_renderer', 'use_webgl_renderer',
|
||||
'verbosity', 'video_dir', 'webgl_renderer_path', 'window_position',
|
||||
'window_monitor', 'window_size', 'write_all', 'write_to_movie', 'enable_wireframe',
|
||||
'force_window']
|
||||
'upto_animation_number', 'use_opengl_renderer', 'verbosity', 'video_dir',
|
||||
'window_position', 'window_monitor', 'window_size', 'write_all', 'write_to_movie',
|
||||
'enable_wireframe', 'force_window']
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@ for i, arg in enumerate(sys.argv):
|
|||
config.renderer = parsed_renderer
|
||||
elif arg == "--use_opengl_renderer":
|
||||
config.renderer = "opengl"
|
||||
elif arg == "--use_webgl_renderer":
|
||||
config.renderer = "webgl"
|
||||
|
||||
# many scripts depend on this -> has to be loaded first
|
||||
from .utils.commands import * # isort:skip
|
||||
|
|
|
|||
|
|
@ -93,15 +93,9 @@ tex_dir = {media_dir}/Tex
|
|||
text_dir = {media_dir}/texts
|
||||
partial_movie_dir = {video_dir}/partial_movie_files/{scene_name}
|
||||
|
||||
# --renderer [cairo|opengl|webgl]
|
||||
# --renderer [cairo|opengl]
|
||||
renderer = cairo
|
||||
|
||||
# --use_webgl_renderer
|
||||
use_webgl_renderer = False
|
||||
|
||||
# --webgl_renderer_path
|
||||
webgl_renderer_path =
|
||||
|
||||
# --use_opengl_renderer
|
||||
use_opengl_renderer = False
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import configparser
|
|||
import copy
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
|
@ -26,7 +25,7 @@ from rich.logging import RichHandler
|
|||
from rich.theme import Theme
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from manim._config.utils import ManimConfig
|
||||
from pathlib import Path
|
||||
HIGHLIGHTED_KEYWORDS = [ # these keywords are highlighted specially
|
||||
"Played",
|
||||
"animations",
|
||||
|
|
@ -142,7 +141,7 @@ def parse_theme(parser: configparser.ConfigParser) -> Theme:
|
|||
return custom_theme
|
||||
|
||||
|
||||
def set_file_logger(config: ManimConfig, verbosity: str) -> None:
|
||||
def set_file_logger(scene_name: str, module_name: str, log_dir: Path) -> None:
|
||||
"""Add a file handler to manim logger.
|
||||
|
||||
The path to the file is built using ``config.log_dir``.
|
||||
|
|
@ -152,28 +151,13 @@ def set_file_logger(config: ManimConfig, verbosity: str) -> None:
|
|||
config : :class:`ManimConfig`
|
||||
The global config, used to determine the log file path.
|
||||
|
||||
verbosity : :class:`str`
|
||||
The verbosity level of the logger.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Calling this function changes the verbosity of all handlers assigned to
|
||||
manim logger.
|
||||
|
||||
"""
|
||||
# Note: The log file name will be
|
||||
# <name_of_animation_file>_<name_of_scene>.log, gotten from config. So it
|
||||
# can differ from the real name of the scene. <name_of_scene> would only
|
||||
# appear if scene name was provided when manim was called.
|
||||
scene_name_suffix = "".join(config["scene_names"])
|
||||
scene_file_name = os.path.basename(config["input_file"]).split(".")[0]
|
||||
log_file_name = (
|
||||
f"{scene_file_name}_{scene_name_suffix}.log"
|
||||
if scene_name_suffix
|
||||
else f"{scene_file_name}.log"
|
||||
)
|
||||
log_file_path = config.get_dir("log_dir") / log_file_name
|
||||
log_file_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
log_file_name = f"{module_name}_{scene_name}.log"
|
||||
log_file_path = log_dir / log_file_name
|
||||
|
||||
file_handler = logging.FileHandler(log_file_path, mode="w")
|
||||
file_handler.setFormatter(JSONFormatter())
|
||||
|
|
@ -182,9 +166,6 @@ def set_file_logger(config: ManimConfig, verbosity: str) -> None:
|
|||
logger.addHandler(file_handler)
|
||||
logger.info("Log file will be saved in %(logpath)s", {"logpath": log_file_path})
|
||||
|
||||
config.verbosity = verbosity
|
||||
logger.setLevel(verbosity)
|
||||
|
||||
|
||||
class JSONFormatter(logging.Formatter):
|
||||
"""A formatter that outputs logs in a custom JSON format.
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ import logging
|
|||
import os
|
||||
import re
|
||||
import sys
|
||||
import typing
|
||||
from collections.abc import Mapping, MutableMapping
|
||||
from pathlib import Path
|
||||
from typing import Any, Iterable, Iterator
|
||||
|
||||
import colour
|
||||
import numpy as np
|
||||
|
|
@ -29,7 +29,6 @@ import numpy as np
|
|||
from .. import constants
|
||||
from ..utils.tex import TexTemplate, TexTemplateFromFile
|
||||
from ..utils.tex_templates import TexTemplateLibrary
|
||||
from .logger_utils import set_file_logger
|
||||
|
||||
|
||||
def config_file_paths() -> list[Path]:
|
||||
|
|
@ -255,7 +254,6 @@ class ManimConfig(MutableMapping):
|
|||
"input_file",
|
||||
"media_embed",
|
||||
"media_width",
|
||||
"webgl_renderer_path",
|
||||
"log_dir",
|
||||
"log_to_file",
|
||||
"max_files_cached",
|
||||
|
|
@ -282,7 +280,6 @@ class ManimConfig(MutableMapping):
|
|||
"upto_animation_number",
|
||||
"renderer",
|
||||
"use_opengl_renderer",
|
||||
"use_webgl_renderer",
|
||||
"enable_gui",
|
||||
"gui_location",
|
||||
"use_projection_fill_shaders",
|
||||
|
|
@ -304,7 +301,7 @@ class ManimConfig(MutableMapping):
|
|||
self._d = {k: None for k in self._OPTS}
|
||||
|
||||
# behave like a dict
|
||||
def __iter__(self) -> typing.Iterator[str]:
|
||||
def __iter__(self) -> Iterator[str]:
|
||||
return iter(self._d)
|
||||
|
||||
def __len__(self) -> int:
|
||||
|
|
@ -317,10 +314,10 @@ class ManimConfig(MutableMapping):
|
|||
except AttributeError:
|
||||
return False
|
||||
|
||||
def __getitem__(self, key) -> typing.Any:
|
||||
def __getitem__(self, key) -> Any:
|
||||
return getattr(self, key)
|
||||
|
||||
def __setitem__(self, key: str, val: typing.Any) -> None:
|
||||
def __setitem__(self, key: str, val: Any) -> None:
|
||||
getattr(ManimConfig, key).fset(self, val) # fset is the property's setter
|
||||
|
||||
def update(self, obj: ManimConfig | dict) -> None:
|
||||
|
|
@ -395,7 +392,7 @@ class ManimConfig(MutableMapping):
|
|||
"""See ManimConfig.copy()."""
|
||||
return copy.deepcopy(self)
|
||||
|
||||
def __deepcopy__(self, memo: dict[str, typing.Any]) -> ManimConfig:
|
||||
def __deepcopy__(self, memo: dict[str, Any]) -> ManimConfig:
|
||||
"""See ManimConfig.copy()."""
|
||||
c = ManimConfig()
|
||||
# Deepcopying the underlying dict is enough because all properties
|
||||
|
|
@ -405,14 +402,14 @@ class ManimConfig(MutableMapping):
|
|||
return c
|
||||
|
||||
# helper type-checking methods
|
||||
def _set_from_list(self, key: str, val: typing.Any, values: list) -> None:
|
||||
def _set_from_list(self, key: str, val: Any, values: list) -> None:
|
||||
"""Set ``key`` to ``val`` if ``val`` is contained in ``values``."""
|
||||
if val in values:
|
||||
self._d[key] = val
|
||||
else:
|
||||
raise ValueError(f"attempted to set {key} to {val}; must be in {values}")
|
||||
|
||||
def _set_boolean(self, key: str | int, val: typing.Any) -> None:
|
||||
def _set_boolean(self, key: str | int, val: Any) -> None:
|
||||
"""Set ``key`` to ``val`` if ``val`` is Boolean."""
|
||||
if val in [True, False]:
|
||||
self._d[key] = val
|
||||
|
|
@ -425,7 +422,7 @@ class ManimConfig(MutableMapping):
|
|||
else:
|
||||
raise ValueError(f"{key} must be tuple")
|
||||
|
||||
def _set_str(self, key: str, val: typing.Any) -> None:
|
||||
def _set_str(self, key: str, val: Any) -> None:
|
||||
"""Set ``key`` to ``val`` if ``val`` is a string."""
|
||||
if isinstance(val, str):
|
||||
self._d[key] = val
|
||||
|
|
@ -537,7 +534,6 @@ class ManimConfig(MutableMapping):
|
|||
"flush_cache",
|
||||
"custom_folders",
|
||||
"use_opengl_renderer",
|
||||
"use_webgl_renderer",
|
||||
"enable_gui",
|
||||
"fullscreen",
|
||||
"use_projection_fill_shaders",
|
||||
|
|
@ -577,7 +573,6 @@ class ManimConfig(MutableMapping):
|
|||
"movie_file_extension",
|
||||
"background_color",
|
||||
"renderer",
|
||||
"webgl_renderer_path",
|
||||
"window_position",
|
||||
]:
|
||||
setattr(self, key, parser["CLI"].get(key, fallback="", raw=True))
|
||||
|
|
@ -710,7 +705,6 @@ class ManimConfig(MutableMapping):
|
|||
"renderer",
|
||||
"background_color",
|
||||
"use_opengl_renderer",
|
||||
"use_webgl_renderer",
|
||||
"enable_gui",
|
||||
"fullscreen",
|
||||
"use_projection_fill_shaders",
|
||||
|
|
@ -835,8 +829,7 @@ class ManimConfig(MutableMapping):
|
|||
filename,
|
||||
)
|
||||
|
||||
if filename:
|
||||
return self.digest_parser(make_config_parser(filename))
|
||||
return self.digest_parser(make_config_parser(filename))
|
||||
|
||||
# config options are properties
|
||||
preview = property(
|
||||
|
|
@ -861,19 +854,11 @@ class ManimConfig(MutableMapping):
|
|||
doc="Whether to show progress bars while rendering animations.",
|
||||
)
|
||||
|
||||
@property
|
||||
def log_to_file(self):
|
||||
"""Whether to save logs to a file."""
|
||||
return self._d["log_to_file"]
|
||||
|
||||
@log_to_file.setter
|
||||
def log_to_file(self, val: str) -> None:
|
||||
self._set_boolean("log_to_file", val)
|
||||
if val:
|
||||
log_dir = self.get_dir("log_dir")
|
||||
if not os.path.exists(log_dir):
|
||||
os.makedirs(log_dir)
|
||||
set_file_logger(self, self["verbosity"])
|
||||
log_to_file = property(
|
||||
lambda self: self._d["log_to_file"],
|
||||
lambda self, val: self._set_boolean("log_to_file", val),
|
||||
doc="Whether to save logs to a file.",
|
||||
)
|
||||
|
||||
notify_outdated_version = property(
|
||||
lambda self: self._d["notify_outdated_version"],
|
||||
|
|
@ -929,12 +914,6 @@ class ManimConfig(MutableMapping):
|
|||
doc="Set to force window when using the opengl renderer",
|
||||
)
|
||||
|
||||
dry_run = property(
|
||||
lambda self: self._d["dry_run"],
|
||||
lambda self, val: self._set_boolean("dry_run", val),
|
||||
doc="Enable dry_run so that no output files are generated and window is disabled.",
|
||||
)
|
||||
|
||||
@property
|
||||
def verbosity(self):
|
||||
"""Logger verbosity; "DEBUG", "INFO", "WARNING", "ERROR", or "CRITICAL" (-v)."""
|
||||
|
|
@ -1181,7 +1160,7 @@ class ManimConfig(MutableMapping):
|
|||
|
||||
@property
|
||||
def renderer(self):
|
||||
"""Renderer: "cairo", "opengl", "webgl"""
|
||||
"""Renderer: "cairo", "opengl"""
|
||||
return self._d["renderer"]
|
||||
|
||||
@renderer.setter
|
||||
|
|
@ -1221,7 +1200,7 @@ class ManimConfig(MutableMapping):
|
|||
self._set_from_list(
|
||||
"renderer",
|
||||
val,
|
||||
["cairo", "opengl", "webgl"],
|
||||
["cairo", "opengl"],
|
||||
)
|
||||
|
||||
@property
|
||||
|
|
@ -1236,31 +1215,9 @@ class ManimConfig(MutableMapping):
|
|||
self._set_from_list(
|
||||
"renderer",
|
||||
"opengl",
|
||||
["cairo", "opengl", "webgl"],
|
||||
["cairo", "opengl"],
|
||||
)
|
||||
|
||||
@property
|
||||
def use_webgl_renderer(self):
|
||||
"""Whether or not to use WebGL renderer."""
|
||||
return self._d["use_webgl_renderer"]
|
||||
|
||||
@use_webgl_renderer.setter
|
||||
def use_webgl_renderer(self, val: bool) -> None:
|
||||
self._d["use_webgl_renderer"] = val
|
||||
if val:
|
||||
self._set_from_list(
|
||||
"webgl",
|
||||
"renderer",
|
||||
["cairo", "opengl", "webgl"],
|
||||
)
|
||||
self["disable_caching"] = True
|
||||
|
||||
webgl_renderer_path = property(
|
||||
lambda self: self._d["webgl_renderer_path"],
|
||||
lambda self, val: self._d.__setitem__("webgl_renderer_path", val),
|
||||
doc="Path to WebGL renderer.",
|
||||
)
|
||||
|
||||
media_dir = property(
|
||||
lambda self: self._d["media_dir"],
|
||||
lambda self, val: self._set_dir("media_dir", val),
|
||||
|
|
@ -1637,7 +1594,7 @@ class ManimFrame(Mapping):
|
|||
self.__dict__["_c"] = c
|
||||
|
||||
# there are required by parent class Mapping to behave like a dict
|
||||
def __getitem__(self, key: str | int) -> typing.Any:
|
||||
def __getitem__(self, key: str | int) -> Any:
|
||||
if key in self._OPTS:
|
||||
return self._c[key]
|
||||
elif key in self._CONSTANTS:
|
||||
|
|
@ -1645,7 +1602,7 @@ class ManimFrame(Mapping):
|
|||
else:
|
||||
raise KeyError(key)
|
||||
|
||||
def __iter__(self) -> typing.Iterable:
|
||||
def __iter__(self) -> Iterable:
|
||||
return iter(list(self._OPTS) + list(self._CONSTANTS))
|
||||
|
||||
def __len__(self) -> int:
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
|
||||
from .camera import Camera
|
||||
|
||||
|
||||
class WebGLCamera(Camera):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(self, **kwargs)
|
||||
self.serialized_frame = []
|
||||
self.pixel_array = None
|
||||
|
||||
def display_multiple_non_background_colored_vmobjects(self, vmobjects, _):
|
||||
for vmobject in vmobjects:
|
||||
# TODO: Store a proto instead of JSON.
|
||||
needs_redraw = False
|
||||
point_hash = hash(tuple(vmobject.points.flatten()))
|
||||
if vmobject.point_hash != point_hash:
|
||||
vmobject.point_hash = point_hash
|
||||
needs_redraw = True
|
||||
self.serialized_frame.append(
|
||||
{
|
||||
"points": vmobject.points.tolist(),
|
||||
"style": vmobject.get_style(simple=True),
|
||||
"id": id(vmobject),
|
||||
"needs_redraw": needs_redraw,
|
||||
},
|
||||
)
|
||||
|
||||
def reset(self):
|
||||
self.serialized_frame = []
|
||||
|
||||
def set_frame_to_background(self, background):
|
||||
self.serialized_frame = copy.deepcopy(background)
|
||||
|
|
@ -50,16 +50,6 @@ def render(
|
|||
)
|
||||
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"
|
||||
|
|
@ -120,20 +110,6 @@ def render(
|
|||
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:
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ render_options = option_group(
|
|||
),
|
||||
option(
|
||||
"--renderer",
|
||||
type=click.Choice(["cairo", "opengl", "webgl"], case_sensitive=False),
|
||||
type=click.Choice(["cairo", "opengl"], case_sensitive=False),
|
||||
help="Select a renderer for your Scene.",
|
||||
default=None,
|
||||
),
|
||||
|
|
@ -105,18 +105,6 @@ render_options = option_group(
|
|||
help="Render scenes using OpenGL (Deprecated).",
|
||||
default=None,
|
||||
),
|
||||
option(
|
||||
"--use_webgl_renderer",
|
||||
is_flag=True,
|
||||
help="Render scenes using the WebGL frontend (Deprecated).",
|
||||
default=None,
|
||||
),
|
||||
option(
|
||||
"--webgl_renderer_path",
|
||||
default=None,
|
||||
type=click.Path(),
|
||||
help="The path to the WebGL frontend.",
|
||||
),
|
||||
option(
|
||||
"-g",
|
||||
"--save_pngs",
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ __all__ = [
|
|||
"GIF_FILE_EXTENSION",
|
||||
"FFMPEG_VERBOSITY_MAP",
|
||||
"VERBOSITY_CHOICES",
|
||||
"WEBGL_RENDERER_INFO",
|
||||
"QUALITIES",
|
||||
"DEFAULT_QUALITY",
|
||||
"DEFAULT_QUALITY_SHORT",
|
||||
|
|
@ -216,12 +215,6 @@ FFMPEG_VERBOSITY_MAP: dict[str, str] = {
|
|||
"CRITICAL": "fatal",
|
||||
}
|
||||
VERBOSITY_CHOICES = FFMPEG_VERBOSITY_MAP.keys()
|
||||
WEBGL_RENDERER_INFO: str = (
|
||||
"The Electron frontend to Manim is hosted at "
|
||||
"https://github.com/ManimCommunity/manim-renderer. After cloning and building it, "
|
||||
"you can either start it prior to running Manim or specify the path to the "
|
||||
"executable with the --webgl_renderer_path flag."
|
||||
)
|
||||
|
||||
# Video qualities
|
||||
QUALITIES: dict[str, dict[str, str | int | None]] = {
|
||||
|
|
|
|||
8
manim/grpc/gen/__init__.py
generated
8
manim/grpc/gen/__init__.py
generated
|
|
@ -1,8 +0,0 @@
|
|||
# https://github.com/protocolbuffers/protobuf/issues/1491#issuecomment-547504972
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.append(str(Path(__file__).parent))
|
||||
1638
manim/grpc/gen/frameserver_pb2.py
generated
1638
manim/grpc/gen/frameserver_pb2.py
generated
File diff suppressed because it is too large
Load diff
171
manim/grpc/gen/frameserver_pb2_grpc.py
generated
171
manim/grpc/gen/frameserver_pb2_grpc.py
generated
|
|
@ -1,171 +0,0 @@
|
|||
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
from __future__ import annotations
|
||||
|
||||
import frameserver_pb2 as frameserver__pb2
|
||||
import grpc
|
||||
|
||||
|
||||
class FrameServerStub:
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.GetFrameAtTime = channel.unary_unary(
|
||||
"/frameserver.FrameServer/GetFrameAtTime",
|
||||
request_serializer=frameserver__pb2.FrameRequest.SerializeToString,
|
||||
response_deserializer=frameserver__pb2.FrameResponse.FromString,
|
||||
)
|
||||
self.FetchSceneData = channel.unary_unary(
|
||||
"/frameserver.FrameServer/FetchSceneData",
|
||||
request_serializer=frameserver__pb2.EmptyRequest.SerializeToString,
|
||||
response_deserializer=frameserver__pb2.FetchSceneDataResponse.FromString,
|
||||
)
|
||||
self.ScriptUpdated = channel.unary_unary(
|
||||
"/frameserver.FrameServer/ScriptUpdated",
|
||||
request_serializer=frameserver__pb2.EmptyRequest.SerializeToString,
|
||||
response_deserializer=frameserver__pb2.EmptyResponse.FromString,
|
||||
)
|
||||
|
||||
|
||||
class FrameServerServicer:
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def GetFrameAtTime(self, request, context):
|
||||
"""Returns a serialization of the scene at the specified time."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def FetchSceneData(self, request, context):
|
||||
"""Returns a list of the names and durations of all animations in the scene."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def ScriptUpdated(self, request, context):
|
||||
"""Returns when the manim script changes"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
|
||||
def add_FrameServerServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {
|
||||
"GetFrameAtTime": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetFrameAtTime,
|
||||
request_deserializer=frameserver__pb2.FrameRequest.FromString,
|
||||
response_serializer=frameserver__pb2.FrameResponse.SerializeToString,
|
||||
),
|
||||
"FetchSceneData": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.FetchSceneData,
|
||||
request_deserializer=frameserver__pb2.EmptyRequest.FromString,
|
||||
response_serializer=frameserver__pb2.FetchSceneDataResponse.SerializeToString,
|
||||
),
|
||||
"ScriptUpdated": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.ScriptUpdated,
|
||||
request_deserializer=frameserver__pb2.EmptyRequest.FromString,
|
||||
response_serializer=frameserver__pb2.EmptyResponse.SerializeToString,
|
||||
),
|
||||
}
|
||||
generic_handler = grpc.method_handlers_generic_handler(
|
||||
"frameserver.FrameServer",
|
||||
rpc_method_handlers,
|
||||
)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
|
||||
|
||||
# This class is part of an EXPERIMENTAL API.
|
||||
class FrameServer:
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
@staticmethod
|
||||
def GetFrameAtTime(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/frameserver.FrameServer/GetFrameAtTime",
|
||||
frameserver__pb2.FrameRequest.SerializeToString,
|
||||
frameserver__pb2.FrameResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def FetchSceneData(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/frameserver.FrameServer/FetchSceneData",
|
||||
frameserver__pb2.EmptyRequest.SerializeToString,
|
||||
frameserver__pb2.FetchSceneDataResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def ScriptUpdated(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/frameserver.FrameServer/ScriptUpdated",
|
||||
frameserver__pb2.EmptyRequest.SerializeToString,
|
||||
frameserver__pb2.EmptyResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
)
|
||||
376
manim/grpc/gen/renderserver_pb2.py
generated
376
manim/grpc/gen/renderserver_pb2.py
generated
|
|
@ -1,376 +0,0 @@
|
|||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: renderserver.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from __future__ import annotations
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="renderserver.proto",
|
||||
package="renderserver",
|
||||
syntax="proto3",
|
||||
serialized_options=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=b'\n\x12renderserver.proto\x12\x0crenderserver"f\n\x16UpdateSceneDataRequest\x12"\n\x05scene\x18\x01 \x01(\x0b\x32\x13.renderserver.Scene\x12\x11\n\texception\x18\x02 \x01(\t\x12\x15\n\rhas_exception\x18\x03 \x01(\x08"\\\n\x05Scene\x12\x0c\n\x04name\x18\x01 \x01(\t\x12+\n\nanimations\x18\x02 \x03(\x0b\x32\x17.renderserver.Animation\x12\x18\n\x10\x62\x61\x63kground_color\x18\x03 \x01(\t"+\n\tAnimation\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x10\n\x08\x64uration\x18\x02 \x01(\x02"\x0e\n\x0c\x45mptyRequest"\x0f\n\rEmptyResponse2d\n\x0cRenderServer\x12T\n\x0fUpdateSceneData\x12$.renderserver.UpdateSceneDataRequest\x1a\x1b.renderserver.EmptyResponseb\x06proto3',
|
||||
)
|
||||
|
||||
|
||||
_UPDATESCENEDATAREQUEST = _descriptor.Descriptor(
|
||||
name="UpdateSceneDataRequest",
|
||||
full_name="renderserver.UpdateSceneDataRequest",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="scene",
|
||||
full_name="renderserver.UpdateSceneDataRequest.scene",
|
||||
index=0,
|
||||
number=1,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="exception",
|
||||
full_name="renderserver.UpdateSceneDataRequest.exception",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="has_exception",
|
||||
full_name="renderserver.UpdateSceneDataRequest.has_exception",
|
||||
index=2,
|
||||
number=3,
|
||||
type=8,
|
||||
cpp_type=7,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=False,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=36,
|
||||
serialized_end=138,
|
||||
)
|
||||
|
||||
|
||||
_SCENE = _descriptor.Descriptor(
|
||||
name="Scene",
|
||||
full_name="renderserver.Scene",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="name",
|
||||
full_name="renderserver.Scene.name",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="animations",
|
||||
full_name="renderserver.Scene.animations",
|
||||
index=1,
|
||||
number=2,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="background_color",
|
||||
full_name="renderserver.Scene.background_color",
|
||||
index=2,
|
||||
number=3,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=140,
|
||||
serialized_end=232,
|
||||
)
|
||||
|
||||
|
||||
_ANIMATION = _descriptor.Descriptor(
|
||||
name="Animation",
|
||||
full_name="renderserver.Animation",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="name",
|
||||
full_name="renderserver.Animation.name",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="duration",
|
||||
full_name="renderserver.Animation.duration",
|
||||
index=1,
|
||||
number=2,
|
||||
type=2,
|
||||
cpp_type=6,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=float(0),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=234,
|
||||
serialized_end=277,
|
||||
)
|
||||
|
||||
|
||||
_EMPTYREQUEST = _descriptor.Descriptor(
|
||||
name="EmptyRequest",
|
||||
full_name="renderserver.EmptyRequest",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=279,
|
||||
serialized_end=293,
|
||||
)
|
||||
|
||||
|
||||
_EMPTYRESPONSE = _descriptor.Descriptor(
|
||||
name="EmptyResponse",
|
||||
full_name="renderserver.EmptyResponse",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=295,
|
||||
serialized_end=310,
|
||||
)
|
||||
|
||||
_UPDATESCENEDATAREQUEST.fields_by_name["scene"].message_type = _SCENE
|
||||
_SCENE.fields_by_name["animations"].message_type = _ANIMATION
|
||||
DESCRIPTOR.message_types_by_name["UpdateSceneDataRequest"] = _UPDATESCENEDATAREQUEST
|
||||
DESCRIPTOR.message_types_by_name["Scene"] = _SCENE
|
||||
DESCRIPTOR.message_types_by_name["Animation"] = _ANIMATION
|
||||
DESCRIPTOR.message_types_by_name["EmptyRequest"] = _EMPTYREQUEST
|
||||
DESCRIPTOR.message_types_by_name["EmptyResponse"] = _EMPTYRESPONSE
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
UpdateSceneDataRequest = _reflection.GeneratedProtocolMessageType(
|
||||
"UpdateSceneDataRequest",
|
||||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _UPDATESCENEDATAREQUEST,
|
||||
"__module__": "renderserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:renderserver.UpdateSceneDataRequest)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(UpdateSceneDataRequest)
|
||||
|
||||
Scene = _reflection.GeneratedProtocolMessageType(
|
||||
"Scene",
|
||||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _SCENE,
|
||||
"__module__": "renderserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:renderserver.Scene)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(Scene)
|
||||
|
||||
Animation = _reflection.GeneratedProtocolMessageType(
|
||||
"Animation",
|
||||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _ANIMATION,
|
||||
"__module__": "renderserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:renderserver.Animation)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(Animation)
|
||||
|
||||
EmptyRequest = _reflection.GeneratedProtocolMessageType(
|
||||
"EmptyRequest",
|
||||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _EMPTYREQUEST,
|
||||
"__module__": "renderserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:renderserver.EmptyRequest)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(EmptyRequest)
|
||||
|
||||
EmptyResponse = _reflection.GeneratedProtocolMessageType(
|
||||
"EmptyResponse",
|
||||
(_message.Message,),
|
||||
{
|
||||
"DESCRIPTOR": _EMPTYRESPONSE,
|
||||
"__module__": "renderserver_pb2",
|
||||
# @@protoc_insertion_point(class_scope:renderserver.EmptyResponse)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(EmptyResponse)
|
||||
|
||||
|
||||
_RENDERSERVER = _descriptor.ServiceDescriptor(
|
||||
name="RenderServer",
|
||||
full_name="renderserver.RenderServer",
|
||||
file=DESCRIPTOR,
|
||||
index=0,
|
||||
serialized_options=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_start=312,
|
||||
serialized_end=412,
|
||||
methods=[
|
||||
_descriptor.MethodDescriptor(
|
||||
name="UpdateSceneData",
|
||||
full_name="renderserver.RenderServer.UpdateSceneData",
|
||||
index=0,
|
||||
containing_service=None,
|
||||
input_type=_UPDATESCENEDATAREQUEST,
|
||||
output_type=_EMPTYRESPONSE,
|
||||
serialized_options=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
)
|
||||
_sym_db.RegisterServiceDescriptor(_RENDERSERVER)
|
||||
|
||||
DESCRIPTOR.services_by_name["RenderServer"] = _RENDERSERVER
|
||||
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
81
manim/grpc/gen/renderserver_pb2_grpc.py
generated
81
manim/grpc/gen/renderserver_pb2_grpc.py
generated
|
|
@ -1,81 +0,0 @@
|
|||
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
from __future__ import annotations
|
||||
|
||||
import grpc
|
||||
import renderserver_pb2 as renderserver__pb2
|
||||
|
||||
|
||||
class RenderServerStub:
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.UpdateSceneData = channel.unary_unary(
|
||||
"/renderserver.RenderServer/UpdateSceneData",
|
||||
request_serializer=renderserver__pb2.UpdateSceneDataRequest.SerializeToString,
|
||||
response_deserializer=renderserver__pb2.EmptyResponse.FromString,
|
||||
)
|
||||
|
||||
|
||||
class RenderServerServicer:
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def UpdateSceneData(self, request, context):
|
||||
"""Called from Manim when a scene has been newly rendered."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
|
||||
def add_RenderServerServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {
|
||||
"UpdateSceneData": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.UpdateSceneData,
|
||||
request_deserializer=renderserver__pb2.UpdateSceneDataRequest.FromString,
|
||||
response_serializer=renderserver__pb2.EmptyResponse.SerializeToString,
|
||||
),
|
||||
}
|
||||
generic_handler = grpc.method_handlers_generic_handler(
|
||||
"renderserver.RenderServer",
|
||||
rpc_method_handlers,
|
||||
)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
|
||||
|
||||
# This class is part of an EXPERIMENTAL API.
|
||||
class RenderServer:
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
@staticmethod
|
||||
def UpdateSceneData(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/renderserver.RenderServer/UpdateSceneData",
|
||||
renderserver__pb2.UpdateSceneDataRequest.SerializeToString,
|
||||
renderserver__pb2.EmptyResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
)
|
||||
|
|
@ -1,409 +0,0 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import subprocess as sp
|
||||
import traceback
|
||||
import types
|
||||
from concurrent import futures
|
||||
|
||||
import grpc
|
||||
|
||||
from manim.mobject.value_tracker import ValueTracker
|
||||
|
||||
from ... import config, logger
|
||||
from ...constants import WEBGL_RENDERER_INFO
|
||||
from ...mobject.types.image_mobject import ImageMobject
|
||||
from ...mobject.types.vectorized_mobject import VMobject
|
||||
from ...renderer.webgl_renderer import WebGLRenderer
|
||||
from ...utils.family import extract_mobject_family_members
|
||||
from ...utils.module_ops import scene_classes_from_file
|
||||
from ..gen import (
|
||||
frameserver_pb2,
|
||||
frameserver_pb2_grpc,
|
||||
renderserver_pb2,
|
||||
renderserver_pb2_grpc,
|
||||
)
|
||||
|
||||
|
||||
class FrameServer(frameserver_pb2_grpc.FrameServerServicer):
|
||||
def __init__(self, server, input_file_path):
|
||||
self.server = server
|
||||
self.input_file_path = input_file_path
|
||||
self.exception = None
|
||||
self.load_scene_module()
|
||||
|
||||
try:
|
||||
self.update_renderer_scene_data()
|
||||
except grpc._channel._InactiveRpcError:
|
||||
logger.warning("No frontend was detected at localhost:50052.")
|
||||
try:
|
||||
sp.Popen(config["webgl_renderer_path"])
|
||||
except PermissionError:
|
||||
logger.info(WEBGL_RENDERER_INFO)
|
||||
self.server.stop(None)
|
||||
return
|
||||
|
||||
def GetFrameAtTime(self, request, context):
|
||||
try:
|
||||
requested_scene_index = request.animation_index
|
||||
|
||||
# Find the requested scene.
|
||||
scene_finished = False
|
||||
if requested_scene_index == request.end_index:
|
||||
scene_finished = True
|
||||
|
||||
if (
|
||||
request.animation_offset
|
||||
<= self.keyframes[requested_scene_index].duration
|
||||
):
|
||||
animation_offset = request.animation_offset
|
||||
else:
|
||||
if requested_scene_index + 1 < request.end_index:
|
||||
requested_scene_index += 1
|
||||
animation_offset = 0
|
||||
else:
|
||||
scene_finished = True
|
||||
animation_offset = self.keyframes[requested_scene_index].duration
|
||||
|
||||
if requested_scene_index == self.previous_scene_index:
|
||||
requested_scene = self.previous_scene
|
||||
update_previous_scene = False
|
||||
else:
|
||||
requested_scene = copy.deepcopy(self.keyframes[requested_scene_index])
|
||||
update_previous_scene = True
|
||||
|
||||
requested_scene.update_to_time(animation_offset)
|
||||
|
||||
ids_to_remove = []
|
||||
mobjects_to_add = []
|
||||
animations = []
|
||||
updaters = []
|
||||
update_data = []
|
||||
# TODO: Only remove/add changed mobjects rather than all of them.
|
||||
if self.previous_scene is not None and (
|
||||
request.first_request or self.previous_scene != requested_scene
|
||||
):
|
||||
previous_mobjects = extract_mobject_family_members(
|
||||
self.previous_scene.mobjects,
|
||||
only_those_with_points=True,
|
||||
)
|
||||
# Remove everything from the previous scene.
|
||||
ids_to_remove = [
|
||||
mob.original_id
|
||||
for mob in previous_mobjects
|
||||
if not isinstance(mob, ValueTracker)
|
||||
]
|
||||
|
||||
if request.first_request or self.previous_scene != requested_scene:
|
||||
# Add everything from the requested scene.
|
||||
mobjects_to_add = [
|
||||
serialize_mobject(mobject)
|
||||
for mobject in extract_mobject_family_members(
|
||||
requested_scene.mobjects,
|
||||
only_those_with_points=True,
|
||||
)
|
||||
if not isinstance(mobject, ValueTracker)
|
||||
]
|
||||
|
||||
# Send animation and updater info.
|
||||
all_animations_tweened = True
|
||||
for animation in requested_scene.animations:
|
||||
attribute_tween_data = generate_attribute_tween_data(animation)
|
||||
mobject_tween_data_list = []
|
||||
flickered_mobject_ids = []
|
||||
if attribute_tween_data is None:
|
||||
all_animations_tweened = False
|
||||
flickered_mobject_ids = [
|
||||
mob.original_id
|
||||
for mob in extract_mobject_family_members(
|
||||
animation.mobject,
|
||||
only_those_with_points=True,
|
||||
)
|
||||
]
|
||||
else:
|
||||
if animation.mobject is not None:
|
||||
# Add offset vector to submobjects.
|
||||
root_mobject_center = animation.mobject.get_center()
|
||||
for updated_mobject in extract_mobject_family_members(
|
||||
animation.mobject,
|
||||
only_those_with_points=True,
|
||||
):
|
||||
mobject_tween_data_list.append(
|
||||
frameserver_pb2.Animation.MobjectTweenData(
|
||||
id=updated_mobject.original_id,
|
||||
root_mobject_offset=updated_mobject.get_center()
|
||||
- root_mobject_center,
|
||||
),
|
||||
)
|
||||
animation_proto = frameserver_pb2.Animation(
|
||||
name=animation.__class__.__name__,
|
||||
duration=requested_scene.duration,
|
||||
easing_function=animation.rate_func.__name__,
|
||||
attribute_tween_data=attribute_tween_data,
|
||||
mobject_tween_data=mobject_tween_data_list,
|
||||
flickered_mobject_ids=flickered_mobject_ids,
|
||||
)
|
||||
animations.append(animation_proto)
|
||||
for (
|
||||
updated_mobject,
|
||||
updater_list,
|
||||
) in requested_scene.mobject_updater_lists:
|
||||
all_updaters_tweened = True
|
||||
for updater in updater_list:
|
||||
attribute_tween_data = generate_attribute_tween_data(updater)
|
||||
if attribute_tween_data is None:
|
||||
all_animations_tweened = False
|
||||
all_updaters_tweened = False
|
||||
updaters.append(
|
||||
frameserver_pb2.Updater(
|
||||
flickered_mobject_ids=[
|
||||
mob.original_id
|
||||
for mob in extract_mobject_family_members(
|
||||
updated_mobject,
|
||||
only_those_with_points=True,
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
break
|
||||
else:
|
||||
raise NotImplementedError("Add tween data for updaters.")
|
||||
if all_updaters_tweened:
|
||||
# Append an updater with tween data.
|
||||
pass
|
||||
else:
|
||||
all_animations_tweened = False
|
||||
for animation in requested_scene.animations:
|
||||
# Only send update data for animations that don't have tween data.
|
||||
if generate_attribute_tween_data(animation) is None:
|
||||
update_data.extend(
|
||||
[
|
||||
serialize_mobject(mobject)
|
||||
for mobject in extract_mobject_family_members(
|
||||
animation.mobject,
|
||||
only_those_with_points=True,
|
||||
)
|
||||
if not isinstance(mobject, ValueTracker)
|
||||
],
|
||||
)
|
||||
for (
|
||||
updated_mobject,
|
||||
updater_list,
|
||||
) in requested_scene.mobject_updater_lists:
|
||||
for updater in updater_list:
|
||||
# Only send update data for updaters that don't have tween data.
|
||||
if generate_attribute_tween_data(updater) is None:
|
||||
update_data.extend(
|
||||
[
|
||||
serialize_mobject(mobject)
|
||||
for mobject in extract_mobject_family_members(
|
||||
updated_mobject,
|
||||
only_those_with_points=True,
|
||||
)
|
||||
if not isinstance(mobject, ValueTracker)
|
||||
],
|
||||
)
|
||||
|
||||
resp = frameserver_pb2.FrameResponse(
|
||||
frame_data=frameserver_pb2.FrameData(
|
||||
remove=ids_to_remove,
|
||||
add=mobjects_to_add,
|
||||
update=update_data,
|
||||
),
|
||||
scene_finished=scene_finished,
|
||||
animations=animations,
|
||||
updaters=updaters,
|
||||
animation_index=requested_scene_index,
|
||||
animation_offset=animation_offset,
|
||||
all_animations_tweened=all_animations_tweened,
|
||||
)
|
||||
if update_previous_scene:
|
||||
self.previous_scene = requested_scene
|
||||
self.previous_scene_index = requested_scene_index
|
||||
return resp
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
|
||||
def FetchSceneData(self, request, context):
|
||||
try:
|
||||
request = frameserver_pb2.FetchSceneDataResponse(
|
||||
scene=frameserver_pb2.Scene(
|
||||
name=str(self.scene),
|
||||
animations=[
|
||||
frameserver_pb2.Animation(
|
||||
name=animations_to_name(scene.animations),
|
||||
duration=scene.duration,
|
||||
)
|
||||
for scene in self.keyframes
|
||||
],
|
||||
),
|
||||
path=str(self.input_file_path),
|
||||
)
|
||||
if hasattr(self.scene.camera, "background_color"):
|
||||
request.scene.background_color = self.scene.camera.background_color
|
||||
else:
|
||||
request.scene.background_color = "#000000"
|
||||
return request
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
|
||||
def ScriptUpdated(self, request, context):
|
||||
self.load_scene_module()
|
||||
with grpc.insecure_channel("localhost:50052") as channel:
|
||||
stub = renderserver_pb2_grpc.RenderServerStub(channel)
|
||||
try:
|
||||
self.update_renderer_scene_data()
|
||||
except grpc._channel._InactiveRpcError:
|
||||
logger.warning("No frontend was detected at localhost:50052.")
|
||||
sp.Popen(config["js_renderer_path"])
|
||||
return frameserver_pb2.EmptyResponse()
|
||||
|
||||
def load_scene_module(self):
|
||||
self.exception = None
|
||||
try:
|
||||
self.scene_class = scene_classes_from_file(
|
||||
self.input_file_path,
|
||||
require_single_scene=True,
|
||||
)
|
||||
self.generate_keyframe_data()
|
||||
except Exception as e:
|
||||
self.exception = e
|
||||
|
||||
def generate_keyframe_data(self):
|
||||
self.keyframes = []
|
||||
self.previous_scene_index = None
|
||||
self.previous_scene = None
|
||||
self.renderer = WebGLRenderer(self)
|
||||
self.scene = self.scene_class(self.renderer)
|
||||
self.scene.render()
|
||||
|
||||
def update_renderer_scene_data(self):
|
||||
# If a javascript renderer is running, notify it of the scene being served. If
|
||||
# not, spawn one and it will request the scene when it starts.
|
||||
with grpc.insecure_channel("localhost:50052") as channel:
|
||||
stub = renderserver_pb2_grpc.RenderServerStub(channel)
|
||||
if not self.exception:
|
||||
request = renderserver_pb2.UpdateSceneDataRequest(
|
||||
scene=renderserver_pb2.Scene(
|
||||
name=str(self.scene),
|
||||
animations=[
|
||||
renderserver_pb2.Animation(
|
||||
name=animations_to_name(scene.animations),
|
||||
duration=scene.duration,
|
||||
)
|
||||
for scene in self.keyframes
|
||||
],
|
||||
),
|
||||
)
|
||||
if hasattr(self.scene.camera, "background_color"):
|
||||
request.scene.background_color = self.scene.camera.background_color
|
||||
else:
|
||||
request.scene.background_color = "#000000"
|
||||
else:
|
||||
lines = traceback.format_exception(
|
||||
None,
|
||||
self.exception,
|
||||
self.exception.__traceback__,
|
||||
)
|
||||
request = renderserver_pb2.UpdateSceneDataRequest(
|
||||
has_exception=True,
|
||||
exception="\n".join(lines),
|
||||
)
|
||||
stub.UpdateSceneData(request)
|
||||
|
||||
|
||||
def generate_attribute_tween_data(animation):
|
||||
if isinstance(animation, types.FunctionType):
|
||||
return None
|
||||
animation_name = animation.__class__.__name__
|
||||
if animation_name == "_MethodAnimation":
|
||||
tween_data_array = []
|
||||
for method in animation.methods:
|
||||
if method.__name__ in ["shift", "to_edge"]:
|
||||
tween_data_array.append(
|
||||
frameserver_pb2.Animation.AttributeTweenData(
|
||||
attribute="position",
|
||||
start_data=animation.starting_mobject.get_center(),
|
||||
end_data=animation.target_mobject.get_center(),
|
||||
),
|
||||
)
|
||||
else:
|
||||
return None
|
||||
return tween_data_array
|
||||
elif animation_name == "FadeIn":
|
||||
return [
|
||||
frameserver_pb2.Animation.AttributeTweenData(
|
||||
attribute="fill_opacity",
|
||||
start_data=[animation.starting_mobject.fill_opacity],
|
||||
end_data=[animation.target_copy.fill_opacity],
|
||||
),
|
||||
frameserver_pb2.Animation.AttributeTweenData(
|
||||
attribute="stroke_opacity",
|
||||
start_data=[animation.starting_mobject.stroke_opacity],
|
||||
end_data=[animation.target_copy.stroke_opacity],
|
||||
),
|
||||
]
|
||||
elif animation_name == "Wait":
|
||||
return []
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def animations_to_name(animations):
|
||||
if len(animations) == 1:
|
||||
return str(animations[0].__class__.__name__)
|
||||
return f"{str(animations[0].__class__.__name__)}..."
|
||||
|
||||
|
||||
def serialize_mobject(mobject):
|
||||
mob_proto = frameserver_pb2.MobjectData(id=mobject.original_id)
|
||||
|
||||
if isinstance(mobject, VMobject):
|
||||
needs_redraw = False
|
||||
point_hash = hash(tuple(mobject.points.flatten()))
|
||||
if mobject.point_hash != point_hash:
|
||||
mobject.point_hash = point_hash
|
||||
needs_redraw = True
|
||||
mob_proto.vectorized_mobject_data.needs_redraw = needs_redraw
|
||||
|
||||
for point in mobject.points:
|
||||
point_proto = mob_proto.vectorized_mobject_data.points.add()
|
||||
point_proto.x = point[0]
|
||||
point_proto.y = point[1]
|
||||
point_proto.z = point[2]
|
||||
|
||||
mob_style = mobject.get_style(simple=True)
|
||||
mob_proto.style.fill_color = mob_style["fill_color"]
|
||||
mob_proto.style.fill_opacity = float(mob_style["fill_opacity"])
|
||||
mob_proto.style.stroke_color = mob_style["stroke_color"]
|
||||
mob_proto.style.stroke_opacity = float(mob_style["stroke_opacity"])
|
||||
mob_proto.style.stroke_width = float(mob_style["stroke_width"])
|
||||
elif isinstance(mobject, ImageMobject):
|
||||
mob_proto.type = frameserver_pb2.MobjectData.MobjectType.IMAGE_MOBJECT
|
||||
mob_style = mobject.get_style()
|
||||
mob_proto.style.fill_color = mob_style["fill_color"]
|
||||
mob_proto.style.fill_opacity = float(mob_style["fill_opacity"])
|
||||
assets_dir_path = str(config.get_dir("assets_dir"))
|
||||
if mobject.path.startswith(assets_dir_path):
|
||||
mob_proto.image_mobject_data.path = mobject.path[len(assets_dir_path) + 1 :]
|
||||
else:
|
||||
logger.info(
|
||||
f"Expected path {mobject.path} to be under the assets dir ({assets_dir_path})",
|
||||
)
|
||||
mob_proto.image_mobject_data.height = mobject.height
|
||||
mob_proto.image_mobject_data.width = mobject.width
|
||||
mob_center = mobject.get_center()
|
||||
mob_proto.image_mobject_data.center.x = mob_center[0]
|
||||
mob_proto.image_mobject_data.center.y = mob_center[1]
|
||||
mob_proto.image_mobject_data.center.z = mob_center[2]
|
||||
return mob_proto
|
||||
|
||||
|
||||
def get(input_file_path):
|
||||
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
|
||||
frameserver_pb2_grpc.add_FrameServerServicer_to_server(
|
||||
FrameServer(server, input_file_path),
|
||||
server,
|
||||
)
|
||||
server.add_insecure_port("localhost:50051")
|
||||
return server
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package frameserver;
|
||||
|
||||
service FrameServer {
|
||||
// Returns a serialization of the scene at the specified time.
|
||||
rpc GetFrameAtTime (FrameRequest) returns (FrameResponse);
|
||||
|
||||
// Returns a list of the names and durations of all animations in the scene.
|
||||
rpc FetchSceneData (EmptyRequest) returns (FetchSceneDataResponse);
|
||||
|
||||
// Returns when the manim script changes
|
||||
rpc ScriptUpdated (EmptyRequest) returns (EmptyResponse);
|
||||
}
|
||||
|
||||
message FetchSceneDataResponse {
|
||||
Scene scene = 1;
|
||||
string path = 2;
|
||||
}
|
||||
|
||||
message Scene {
|
||||
string name = 1;
|
||||
repeated Animation animations = 2;
|
||||
string background_color = 3;
|
||||
}
|
||||
|
||||
message Animation {
|
||||
string name = 1;
|
||||
float duration = 2;
|
||||
string easing_function = 3;
|
||||
|
||||
message AttributeTweenData {
|
||||
string attribute = 1;
|
||||
repeated float start_data = 2;
|
||||
repeated float end_data = 3;
|
||||
}
|
||||
repeated AttributeTweenData attribute_tween_data = 4;
|
||||
|
||||
message MobjectTweenData {
|
||||
string id = 1;
|
||||
repeated float root_mobject_offset = 2;
|
||||
}
|
||||
repeated MobjectTweenData mobject_tween_data = 5;
|
||||
repeated string flickered_mobject_ids = 6;
|
||||
}
|
||||
|
||||
message Updater {
|
||||
repeated string flickered_mobject_ids = 1;
|
||||
}
|
||||
|
||||
message FrameRequest {
|
||||
int32 end_index = 1;
|
||||
bool first_request = 2;
|
||||
int32 animation_index = 3;
|
||||
float animation_offset = 4;
|
||||
}
|
||||
|
||||
message Style {
|
||||
string fill_color = 1;
|
||||
float fill_opacity = 2;
|
||||
string stroke_color = 3;
|
||||
float stroke_opacity = 4;
|
||||
float stroke_width = 5;
|
||||
}
|
||||
|
||||
message Point {
|
||||
float x = 1;
|
||||
float y = 2;
|
||||
float z = 3;
|
||||
}
|
||||
|
||||
message MobjectData {
|
||||
string id = 1;
|
||||
Style style = 2;
|
||||
enum MobjectType {
|
||||
VMOBJECT = 0;
|
||||
IMAGE_MOBJECT = 1;
|
||||
}
|
||||
MobjectType type = 3;
|
||||
VMobjectData vectorized_mobject_data = 4;
|
||||
ImageMobjectData image_mobject_data = 5;
|
||||
repeated float root_mobject_offset = 6;
|
||||
}
|
||||
|
||||
message VMobjectData {
|
||||
repeated Point points = 1;
|
||||
bool needs_redraw = 2;
|
||||
}
|
||||
|
||||
message ImageMobjectData {
|
||||
string path = 1;
|
||||
float height = 2;
|
||||
float width = 3;
|
||||
Point center = 4;
|
||||
}
|
||||
|
||||
message FrameData {
|
||||
repeated string remove = 1;
|
||||
repeated MobjectData add = 2;
|
||||
repeated MobjectData update = 3;
|
||||
}
|
||||
|
||||
message FrameResponse {
|
||||
FrameData frame_data = 1;
|
||||
bool scene_finished = 2;
|
||||
repeated Animation animations = 3;
|
||||
repeated Updater updaters = 4;
|
||||
int32 animation_index = 5;
|
||||
float animation_offset = 6;
|
||||
bool all_animations_tweened = 7;
|
||||
}
|
||||
|
||||
message EmptyRequest {}
|
||||
message EmptyResponse {}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package renderserver;
|
||||
|
||||
service RenderServer {
|
||||
// Called from Manim when a scene has been newly rendered.
|
||||
rpc UpdateSceneData (UpdateSceneDataRequest) returns (EmptyResponse);
|
||||
}
|
||||
|
||||
message UpdateSceneDataRequest {
|
||||
Scene scene = 1;
|
||||
string exception = 2;
|
||||
bool has_exception = 3;
|
||||
}
|
||||
|
||||
message Scene {
|
||||
string name = 1;
|
||||
repeated Animation animations = 2;
|
||||
string background_color = 3;
|
||||
}
|
||||
|
||||
message Animation {
|
||||
string name = 1;
|
||||
float duration = 2;
|
||||
}
|
||||
|
||||
message EmptyRequest {}
|
||||
message EmptyResponse {}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
|
||||
from manim import config
|
||||
|
||||
from ..utils.family import extract_mobject_family_members
|
||||
|
||||
|
||||
class WebGLRenderer:
|
||||
def __init__(self, frame_server):
|
||||
self.skip_animations = True
|
||||
self.frame_server = frame_server
|
||||
self.camera = WebGLCamera()
|
||||
self.num_plays = 0
|
||||
|
||||
def init_scene(self, scene):
|
||||
pass
|
||||
|
||||
def scene_finished(self, scene):
|
||||
pass
|
||||
|
||||
def play(self, scene, *args, **kwargs):
|
||||
self.num_plays += 1
|
||||
# If the scene contains an updater it must be updated frame by frame.
|
||||
for mob in extract_mobject_family_members(scene.mobjects):
|
||||
if len(mob.updaters) > 0:
|
||||
self.skip_animations = False
|
||||
break
|
||||
s = scene.compile_animation_data(*args, skip_rendering=True, **kwargs)
|
||||
scene.begin_animations()
|
||||
self.skip_animations = True
|
||||
|
||||
scene_copy = copy.deepcopy(scene)
|
||||
scene_copy.renderer = self
|
||||
self.frame_server.keyframes.append(scene_copy)
|
||||
if s is None:
|
||||
# Nothing happens in this animation, so there's no need to update it.
|
||||
scene_copy.is_static = True
|
||||
else:
|
||||
scene_copy.is_static = False
|
||||
scene.play_internal(skip_rendering=True)
|
||||
|
||||
def update_frame( # TODO Description in Docstring
|
||||
self,
|
||||
scene,
|
||||
mobjects=None,
|
||||
include_submobjects=True,
|
||||
ignore_skipping=True,
|
||||
**kwargs,
|
||||
):
|
||||
pass
|
||||
|
||||
def save_static_frame_data(self, scene, static_mobjects):
|
||||
pass
|
||||
|
||||
def add_frame(self, frame, num_frames=1):
|
||||
pass
|
||||
|
||||
def get_frame(self):
|
||||
pass
|
||||
|
||||
|
||||
class WebGLCamera:
|
||||
def __init__(self, use_z_index=True):
|
||||
self.use_z_index = use_z_index
|
||||
self.frame_rate = config["frame_rate"]
|
||||
|
|
@ -19,6 +19,7 @@ from pydub import AudioSegment
|
|||
from manim import __version__
|
||||
|
||||
from .. import config, logger
|
||||
from .._config.logger_utils import set_file_logger
|
||||
from ..constants import FFMPEG_BIN, GIF_FILE_EXTENSION
|
||||
from ..utils.file_ops import (
|
||||
add_extension_if_not_present,
|
||||
|
|
@ -158,6 +159,12 @@ class SceneFileWriter:
|
|||
),
|
||||
)
|
||||
|
||||
if config["log_to_file"]:
|
||||
log_dir = guarantee_existence(config.get_dir("log_dir"))
|
||||
set_file_logger(
|
||||
scene_name=scene_name, module_name=module_name, log_dir=log_dir
|
||||
)
|
||||
|
||||
def finish_last_section(self) -> None:
|
||||
"""Delete current section if it is empty."""
|
||||
if len(self.sections) and self.sections[-1].is_empty():
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@ import subprocess as sp
|
|||
import time
|
||||
from pathlib import Path
|
||||
from shutil import copyfile
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..scene.scene_file_writer import SceneFileWriter
|
||||
|
||||
from manim import __version__, config, logger
|
||||
|
||||
|
|
@ -117,33 +121,35 @@ def write_to_movie() -> bool:
|
|||
)
|
||||
|
||||
|
||||
def add_extension_if_not_present(file_name, extension):
|
||||
def add_extension_if_not_present(file_name: Path, extension: str) -> Path:
|
||||
if file_name.suffix != extension:
|
||||
return file_name.with_suffix(extension)
|
||||
else:
|
||||
return file_name
|
||||
|
||||
|
||||
def add_version_before_extension(file_name):
|
||||
def add_version_before_extension(file_name: Path) -> Path:
|
||||
file_name = Path(file_name)
|
||||
path, name, suffix = file_name.parent, file_name.stem, file_name.suffix
|
||||
return Path(path, f"{name}_ManimCE_v{__version__}{suffix}")
|
||||
|
||||
|
||||
def guarantee_existence(path):
|
||||
def guarantee_existence(path: Path) -> Path:
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
return os.path.abspath(path)
|
||||
return Path(os.path.abspath(path))
|
||||
|
||||
|
||||
def guarantee_empty_existence(path):
|
||||
def guarantee_empty_existence(path: Path) -> Path:
|
||||
if os.path.exists(path):
|
||||
shutil.rmtree(path)
|
||||
os.makedirs(path)
|
||||
return os.path.abspath(path)
|
||||
return Path(os.path.abspath(path))
|
||||
|
||||
|
||||
def seek_full_path_from_defaults(file_name, default_dir, extensions):
|
||||
def seek_full_path_from_defaults(
|
||||
file_name: Path, default_dir: str, extensions: str
|
||||
) -> Path:
|
||||
possible_paths = [file_name]
|
||||
possible_paths += [
|
||||
Path(default_dir) / f"{file_name}{extension}" for extension in ["", *extensions]
|
||||
|
|
@ -155,7 +161,7 @@ def seek_full_path_from_defaults(file_name, default_dir, extensions):
|
|||
raise OSError(error)
|
||||
|
||||
|
||||
def modify_atime(file_path):
|
||||
def modify_atime(file_path) -> None:
|
||||
"""Will manually change the accessed time (called `atime`) of the file, as on a lot of OS the accessed time refresh is disabled by default.
|
||||
|
||||
Parameters
|
||||
|
|
@ -188,7 +194,7 @@ def open_file(file_path, in_browser=False):
|
|||
sp.Popen(commands)
|
||||
|
||||
|
||||
def open_media_file(file_writer):
|
||||
def open_media_file(file_writer: SceneFileWriter) -> None:
|
||||
file_paths = []
|
||||
|
||||
if config["save_last_frame"]:
|
||||
|
|
@ -207,7 +213,7 @@ def open_media_file(file_writer):
|
|||
logger.info(f"Previewed File at: '{file_path}'")
|
||||
|
||||
|
||||
def get_template_names():
|
||||
def get_template_names() -> list[str]:
|
||||
"""Returns template names from the templates directory.
|
||||
|
||||
Returns
|
||||
|
|
@ -218,7 +224,7 @@ def get_template_names():
|
|||
return [template_name.stem for template_name in template_path.glob("*.mtp")]
|
||||
|
||||
|
||||
def get_template_path():
|
||||
def get_template_path() -> Path:
|
||||
"""Returns the Path of templates directory.
|
||||
|
||||
Returns
|
||||
|
|
@ -242,7 +248,9 @@ def add_import_statement(file):
|
|||
f.write(import_line.rstrip("\r\n") + "\n" + content)
|
||||
|
||||
|
||||
def copy_template_files(project_dir=Path("."), template_name="Default"):
|
||||
def copy_template_files(
|
||||
project_dir: Path = Path("."), template_name: str = "Default"
|
||||
) -> None:
|
||||
"""Copies template files from templates dir to project_dir.
|
||||
|
||||
Parameters
|
||||
|
|
|
|||
1031
poetry.lock
generated
1031
poetry.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -35,14 +35,12 @@ Pillow = ">=8.4,<10.0"
|
|||
scipy = "^1.7.3"
|
||||
tqdm = "^4.62.3"
|
||||
pydub = "^0.25.1"
|
||||
rich = ">=6.0"
|
||||
rich = ">=6.0,!=12.0.0"
|
||||
pycairo = "^1.19"
|
||||
manimpango = "^0.4.0.post0"
|
||||
networkx = "^2.5"
|
||||
decorator = "^5.0.7"
|
||||
importlib-metadata = { version = "^4.10.0", python = "<3.8" }
|
||||
grpcio = { version = "^1.43.0", optional = true }
|
||||
grpcio-tools = { version = "^1.43.0", optional = true }
|
||||
watchdog = "^2.1.6"
|
||||
jupyterlab = { version = "^3.0", optional = true }
|
||||
moderngl = "^5.6.3"
|
||||
|
|
@ -59,7 +57,6 @@ Pygments = "^2.10.0"
|
|||
"backports.cached-property" = "^1.0.1"
|
||||
|
||||
[tool.poetry.extras]
|
||||
webgl_renderer = ["grpcio","grpcio-tools"]
|
||||
jupyterlab = ["jupyterlab"]
|
||||
gui = ["dearpygui"]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from http.server import HTTPServer, SimpleHTTPRequestHandler, test # type: ignore
|
||||
|
||||
|
||||
class CORSRequestHandler(SimpleHTTPRequestHandler):
|
||||
def end_headers(self):
|
||||
self.send_header("Access-Control-Allow-Origin", "*")
|
||||
super().end_headers()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test(
|
||||
CORSRequestHandler,
|
||||
HTTPServer,
|
||||
port=int(sys.argv[1]) if len(sys.argv) > 1 else 8000,
|
||||
)
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
This is intended to be run from manim/grpc
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
CMD_STRING = """
|
||||
poetry run python \
|
||||
-m grpc_tools.protoc \
|
||||
-I./proto \
|
||||
--python_out=./gen \
|
||||
--grpc_python_out=./gen \
|
||||
./proto/frameserver.proto \
|
||||
./proto/renderserver.proto
|
||||
"""
|
||||
os.system(CMD_STRING)
|
||||
|
|
@ -98,6 +98,7 @@ def test_custom_dirs(tmp_path):
|
|||
{
|
||||
"media_dir": tmp_path,
|
||||
"save_sections": True,
|
||||
"log_to_file": True,
|
||||
"frame_rate": 15,
|
||||
"pixel_height": 854,
|
||||
"pixel_width": 480,
|
||||
|
|
@ -108,6 +109,7 @@ def test_custom_dirs(tmp_path):
|
|||
"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()
|
||||
|
|
@ -131,7 +133,7 @@ def test_custom_dirs(tmp_path):
|
|||
|
||||
assert_dir_filled(os.path.join(tmp_path, "test_text"))
|
||||
assert_dir_filled(os.path.join(tmp_path, "test_tex"))
|
||||
# TODO: testing the log dir would be nice but it doesn't get generated for some reason and test crashes when setting "log_to_file" to True
|
||||
assert_dir_filled(os.path.join(tmp_path, "test_log"))
|
||||
|
||||
|
||||
def test_frame_size(tmp_path):
|
||||
|
|
|
|||
|
|
@ -35,32 +35,6 @@ def test_logging_to_file(tmp_path, python_version):
|
|||
assert exitcode == 0, err
|
||||
|
||||
|
||||
@logs_comparison(
|
||||
"BasicSceneLoggingTest.txt",
|
||||
os.path.join("logs", "basic_scenes_square_to_circle.log"),
|
||||
)
|
||||
def test_logging_when_scene_is_not_specified(tmp_path, python_version):
|
||||
path_basic_scene = os.path.join(
|
||||
"tests",
|
||||
"test_logging",
|
||||
"basic_scenes_square_to_circle.py",
|
||||
)
|
||||
command = [
|
||||
python_version,
|
||||
"-m",
|
||||
"manim",
|
||||
"-ql",
|
||||
"-v",
|
||||
"DEBUG",
|
||||
"--log_to_file",
|
||||
"--media_dir",
|
||||
str(tmp_path),
|
||||
path_basic_scene,
|
||||
]
|
||||
_, err, exitcode = capture(command)
|
||||
assert exitcode == 0, err
|
||||
|
||||
|
||||
def test_error_logging(tmp_path, python_version):
|
||||
path_error_scene = Path("tests/test_logging/basic_scenes_error.py")
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue