From a048af3e0432679a2a7c61e04974fffbfc59ee78 Mon Sep 17 00:00:00 2001 From: JasonGrace2282 Date: Tue, 28 May 2024 22:09:32 -0400 Subject: [PATCH 1/7] Initial restructuring --- manim/__init__.py | 1 + manim/cli/render/render_options.py | 2 +- manim/renderer/opengl_renderer.py | 9 +- manim/renderer/opengl_shader_program.py | 11 +- manim/renderer/render_manager.py | 222 +++++++++++++++++++----- manim/renderer/renderer.py | 64 +++++-- manim/scene/scene.py | 208 +++++----------------- 7 files changed, 279 insertions(+), 238 deletions(-) diff --git a/manim/__init__.py b/manim/__init__.py index 32b831089b..32d663d4b8 100644 --- a/manim/__init__.py +++ b/manim/__init__.py @@ -72,6 +72,7 @@ from .mobject.types.vectorized_mobject import * from .mobject.value_tracker import * from .mobject.vector_field import * +from .renderer.render_manager import * from .scene.scene import * from .scene.scene_file_writer import * from .scene.section import * diff --git a/manim/cli/render/render_options.py b/manim/cli/render/render_options.py index 738f5c310f..5abc5b323b 100644 --- a/manim/cli/render/render_options.py +++ b/manim/cli/render/render_options.py @@ -100,7 +100,7 @@ def validate_resolution(ctx, param, value): case_sensitive=False, ), help="Select a renderer for your Scene.", - default="cairo", + default="opengl", ), option( "-g", diff --git a/manim/renderer/opengl_renderer.py b/manim/renderer/opengl_renderer.py index 64343eab4b..467b977c7a 100644 --- a/manim/renderer/opengl_renderer.py +++ b/manim/renderer/opengl_renderer.py @@ -11,7 +11,7 @@ from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject from manim.renderer.buffers.buffer import STD140BufferFormat from manim.renderer.opengl_shader_program import load_shader_program_by_folder -from manim.renderer.renderer import ImageType, Renderer, RendererData +from manim.renderer.renderer import ImageType, Renderer, RendererData, RendererProtocol from manim.utils.iterables import listify from manim.utils.space_ops import cross2d, earclip_triangulation, z_to_vector @@ -203,14 +203,14 @@ def bind_to_uniform_block(uniform_buffer_object: gl.Buffer, idx: int = 0): uniform_buffer_object.bind_to_uniform_block(idx) -class OpenGLRenderer(Renderer): +class OpenGLRenderer(Renderer, RendererProtocol): pixel_array_dtype = np.uint8 def __init__( self, pixel_width: int = config.pixel_width, pixel_height: int = config.pixel_height, - samples=4, + samples: int = 4, background_color: c.ManimColor = color.BLACK, background_opacity: float = 1.0, background_image: str | None = None, @@ -407,6 +407,9 @@ def render_program(self, prog, data, indices=None): vao.release() # return data, data_size + def render_image(self, mob): + raise NotImplementedError # TODO + def render_vmobject(self, mob: OpenGLVMobject) -> None: # type: ignore self.stencil_buffer_fbo.use() self.stencil_buffer_fbo.clear() diff --git a/manim/renderer/opengl_shader_program.py b/manim/renderer/opengl_shader_program.py index d48311d44e..d030f54b61 100644 --- a/manim/renderer/opengl_shader_program.py +++ b/manim/renderer/opengl_shader_program.py @@ -85,9 +85,8 @@ def load_shader_program_by_folder(ctx: gl.Context, folder_name: str): raise RuntimeError("Loading Shader Program Error") if geometry_code is None: return ctx.program(vertex_shader=vertex_code, fragment_shader=fragment_code) - elif geometry_code is not None: - return ctx.program( - vertex_shader=vertex_code, - geometry_shader=geometry_code, - fragment_shader=fragment_code, - ) + return ctx.program( + vertex_shader=vertex_code, + geometry_shader=geometry_code, + fragment_shader=fragment_code, + ) diff --git a/manim/renderer/render_manager.py b/manim/renderer/render_manager.py index 233af3585b..52d2d42ea9 100644 --- a/manim/renderer/render_manager.py +++ b/manim/renderer/render_manager.py @@ -1,82 +1,210 @@ from __future__ import annotations -import multiprocessing as mp -import queue # NOTE: Cannot use mp.Queue because of auth keys +import time from typing import TYPE_CHECKING, Any, Iterable import numpy as np from manim import config, logger +from manim.constants import RendererType +from ..scene.scene import Scene, SceneState from .opengl_file_writer import FileWriter from .opengl_renderer import OpenGLRenderer +from .opengl_renderer_window import Window if TYPE_CHECKING: + from manim.animation.protocol import AnimationProtocol + from ..camera.camera import Camera - from ..scene.scene import SceneState + from .renderer import RendererProtocol + +__all__ = ("Manager",) -__all__ = ("RenderManager",) +class EndSceneError(Exception): + pass -class RenderManager: + +class Manager: """ - Manage rendering in parallel + The Brain of Manim """ - def __init__(self, scene_name: str, camera: Camera, **kwargs) -> None: + def __init__(self, scene_cls: type[Scene]) -> None: # renderer - self.renderer = OpenGLRenderer(**kwargs) - self.ctx = mp.get_context("spawn") + self.renderer = self._renderer_class() + + # scene + self.scene: Scene = scene_cls(self) - # setup - self.processes: queue.Queue[mp.Process] = queue.Queue() - self.manager = mp.Manager() - self.manager_dict = self.manager.dict() + if not isinstance(self.scene, Scene): + raise ValueError(f"{self.scene!r} is not an instance of Scene") + + self.time = 0 + + # Initialize window, if applicable + if config.preview: + self.window = Window() + else: + self.window = None # file writer - self.camera = camera - self.file_writer = FileWriter(scene_name) # TODO + self.file_writer = FileWriter(self.scene.get_default_scene_name()) # TODO self.renderer.use_window() - def begin(self) -> None: + @property + def camera(self) -> Camera: + return self.scene.camera + + @property + def _renderer_class(self) -> type[RendererProtocol]: + # TODO: Implement based on renderer in config + match config.renderer: + case RendererType.OPENGL: + return OpenGLRenderer + + case rendertype: + raise ValueError(f"Invalid Config Renderer type {rendertype}") + + def _setup(self) -> None: """Set up processes and manager""" - ... + if self.file_writer.has_progress_display(): + self.scene.show_animation_progress = False - def get_time_progression(self, run_time: float) -> Iterable[float]: - return np.arange(0, run_time, 1 / self.camera.fps) + self.scene.setup() - def render_state(self, state: SceneState, parallel: bool = True) -> None: - """Launch a process (optionally in parallel) - to render a frame + self.virtual_animation_start_time = 0 + self.real_animation_start_time = time.perf_counter() + + def render(self) -> None: """ - if parallel and config.in_parallel: - logger.warning("Not supported yet") - self.render_frame(state) - - # type state: SceneState - def render_frame(self, state: SceneState) -> Any | None: - """Renders a frame based on a state""" - data = self.send_scene_to_renderer(state) - # result = self.file_writer.write(data) - self.manager_dict[state.time] = data + Entry point to running a Manim class - def send_scene_to_renderer(self, state: SceneState): - """Renders the State""" - result = self.renderer.render(self.camera, state.mobjects) - return result + Example + ------- - def get_frames(self) -> list: - """Get a list of every frame produced by the - manager. + .. code-block:: python - .. warning:: + class MyScene(Scene): + def construct(self): + self.play(Create(Circle())) - This list is _not guarenteed_ to be sorted until - after calling :meth:`.RenderManager.finish` + + with tempconfig({"preview": True}): + Manager(MyScene).render() + """ + self._render_first_pass() + self._render_second_pass() + self._interact() + + def _render_first_pass(self) -> None: + """ + Temporarily use the normal single pass + rendering system """ - return self.manager_dict + self._setup() + try: + self.scene.construct() + self._interact() + except EndSceneError: + pass + except KeyboardInterrupt: + # Get rid keyboard interrupt symbols + print("", end="\r") + self.file_writer.ended_with_interrupt = True + self._tear_down() + + def _render_second_pass(self) -> None: + """ + In the future, this method could be used + for two pass rendering + """ + + def _tear_down(self): + self.scene.tear_down() + + if config.save_last_frame: + self._update_frame(0) + + self.file_writer.finish() + + if self.window is not None: + self.window.close() + self.window = None + + def _interact(self) -> None: + if self.window is None: + return + logger.info( + "\nTips: Using the keys `d`, `f`, or `z` " + + "you can interact with the scene. " + + "Press `command + q` or `esc` to quit" + ) + self.scene.skip_animations = False + self.scene.refresh_static_mobjects() + while not self.window.is_closing: + # TODO: Replace with actual dt instead + # of hardcoded dt + dt = 1 / self.camera.fps + self._update_frame(dt) + + def _update_frame(self, dt: float): + self.time += dt + self.scene._update_mobjects(dt) + + if self.window is not None and self.window.is_closing: + raise EndSceneError() + + if self.window is not None: + self.window.clear() + + state = self.scene.get_state() + self._render_frame(state) + + if self.window is not None: + self.window.swap_buffers() + vt = self.time - self.virtual_animation_start_time + rt = time.time() - self.real_animation_start_time + if rt < vt: + self._update_frame(0) + + def _play(self, *animations: AnimationProtocol): + self.scene.pre_play() + + if self.window is not None: + self.real_animation_start_time = time.time() + self.virtual_animation_start_time = self.time + + self.scene.begin_animations(animations) + self._progress_through_animations(animations) + self.scene.finish_animations(animations) + + if self.scene.skip_animations and self.window is not None: + self._update_frame(dt=0) + + self.scene.post_play() + + def _progress_through_animations(self, animations: Iterable[AnimationProtocol]): + last_t = 0 + run_time = self._calc_runtime(animations) + for t in self._calc_time_progression(run_time): + dt, last_t = t - last_t, t + self.scene._update_animations(animations, t, dt) + self._update_frame(dt) + + def _calc_time_progression(self, run_time: float) -> Iterable[float]: + return np.arange(0, run_time, 1 / self.camera.fps) + + def _calc_runtime(self, animations: Iterable[AnimationProtocol]): + return max(animation.get_run_time() for animation in animations) + + def _render_frame(self, state: SceneState) -> Any | None: + """Renders a frame based on a state, and writes it to a file""" + data = self._send_scene_to_renderer(state) + # result = self.file_writer.write(data) - def finish(self) -> None: - for process in self.processes.queue: - process.join() - self.manager_dict = dict(sorted(self.manager_dict.items())) + def _send_scene_to_renderer(self, state: SceneState): + """Renders the State""" + result = self.renderer.render(self.camera, state.mobjects) + return result diff --git a/manim/renderer/renderer.py b/manim/renderer/renderer.py index 21842f9091..8ac2a25831 100644 --- a/manim/renderer/renderer.py +++ b/manim/renderer/renderer.py @@ -1,14 +1,20 @@ -from abc import ABC, abstractclassmethod, abstractstaticmethod -from typing import TYPE_CHECKING +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import TYPE_CHECKING, Protocol import numpy as np from typing_extensions import TypeAlias -from manim import config from manim._config import logger +from manim.mobject.opengl.opengl_mobject import OpenGLMobject from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject from manim.mobject.types.image_mobject import ImageMobject -from manim.mobject.types.vectorized_mobject import VMobject + +if TYPE_CHECKING: + from collections.abc import Callable, Iterable, Sequence + + from manim.camera.camera import Camera ImageType: TypeAlias = np.ndarray @@ -20,15 +26,15 @@ class RendererData: class Renderer(ABC): def __init__(self): self.capabilities = [ - (OpenGLVMobject, self.render_vmobject), - (ImageMobject, self.render_image), + (OpenGLVMobject, self.render_vmobject), # type: ignore + (ImageMobject, self.render_image), # type: ignore ] - def render(self, camera, renderables: list[OpenGLVMobject]) -> None: # Image + def render(self, camera, renderables: Iterable[OpenGLMobject]) -> None: # Image self.pre_render(camera) for mob in renderables: - for type, render_func in self.capabilities: - if isinstance(mob, type): + for type_, render_func in self.capabilities: + if isinstance(mob, type_): render_func(mob) break else: @@ -37,27 +43,51 @@ def render(self, camera, renderables: list[OpenGLVMobject]) -> None: # Image ) self.post_render() - def pre_render(self, camera): + @abstractmethod + def pre_render(self, camera: Camera): raise NotImplementedError + @abstractmethod def post_render(self): raise NotImplementedError - def use_window(self): + @abstractmethod + def render_vmobject(self, mob: OpenGLVMobject): raise NotImplementedError - @abstractclassmethod - def render_vmobject(self, mob: OpenGLVMobject) -> None: + @abstractmethod + def render_image(self, mob: ImageMobject): raise NotImplementedError + +class RendererProtocol(Protocol): + capabilities: Sequence[ + tuple[type[OpenGLMobject], Callable[[type[OpenGLMobject]], object]] + ] + + def render(self, camera: Camera, renderables: Iterable[OpenGLMobject]) -> None: + ... + + def pre_render(self, camera) -> object: + ... + + def post_render(self) -> object: + ... + + def use_window(self): + ... + + def render_vmobject(self, mob: OpenGLVMobject) -> object: + ... + def render_mesh(self, mob) -> None: - raise NotImplementedError + ... - def render_image(self, mob) -> None: - raise NotImplementedError + def render_image(self, mob: ImageMobject) -> None: + ... def get_pixels(self) -> ImageType: - raise NotImplementedError + ... # NOTE: The user should expect depth between renderers not to be handled discussed at 03.09.2023 Between jsonv and MrDiver diff --git a/manim/scene/scene.py b/manim/scene/scene.py index 991b4626de..1ccbbd81e0 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -6,7 +6,7 @@ import random import time from collections import OrderedDict -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Sequence import numpy as np from IPython.terminal import pt_inputhooks @@ -24,8 +24,8 @@ from manim.mobject.mobject import Group, Point, _AnimationBuilder from manim.mobject.opengl.opengl_mobject import OpenGLMobject as Mobject from manim.mobject.types.vectorized_mobject import VGroup, VMobject -from manim.renderer.render_manager import RenderManager from manim.utils.color import RED +from manim.utils.deprecation import deprecated from manim.utils.family_ops import extract_mobject_family_members from manim.utils.iterables import list_difference_update from manim.utils.module_ops import get_module @@ -33,12 +33,11 @@ if TYPE_CHECKING: from typing import Any, Callable, Iterable - from PIL.Image import Image - from manim.animation.protocol import AnimationProtocol as Animation from manim.animation.scene_buffer import SceneBuffer + from manim.renderer.render_manager import Manager -# TODO: these keybindings should be made configureable +# TODO: these keybindings should be made configurable PAN_3D_KEY = "d" FRAME_SHIFT_KEY = "f" @@ -57,6 +56,7 @@ class Scene: def __init__( self, + manager: Manager | None = None, window_config: dict = {}, camera_config: dict = {}, skip_animations: bool = False, @@ -81,17 +81,10 @@ def __init__( self.embed_exception_mode = embed_exception_mode self.embed_error_sound = embed_error_sound - # Initialize window, if applicable - if self.preview: - from manim.renderer.opengl_renderer_window import Window - - self.window = Window() - else: - self.window = None - # Core state of the scene self.camera: Camera = Camera() self.camera.save_state() + self.__manager = manager self.mobjects: list[Mobject] = [] self.id_to_mobject_map: dict[int, Mobject] = {} self.num_plays: int = 0 @@ -100,12 +93,9 @@ def __init__( self.original_skipping_status: bool = self.skip_animations self.undo_stack = [] self.redo_stack = [] - self.manager = RenderManager(self.get_default_scene_name(), camera=self.camera) if self.start_at_animation_number is not None: self.skip_animations = True - if self.manager.file_writer.has_progress_display(): - self.show_animation_progress = False # Items associated with interaction self.mouse_point = Point() @@ -118,6 +108,10 @@ def __init__( random.seed(self.random_seed) np.random.seed(self.random_seed) + @property + def manager(self) -> Manager: + return self.__manager + def __str__(self) -> str: return self.__class__.__name__ @@ -138,68 +132,31 @@ def process_buffer(self, buffer: SceneBuffer) -> None: self.add(*buffer.to_add) buffer.clear() - def run(self) -> None: - config.scene_name = str(self) - self.virtual_animation_start_time: float = 0 - self.real_animation_start_time: float = time.time() + @deprecated(message="Use Manager(Scene).render()") + @classmethod + def run(cls) -> None: + from ..renderer.render_manager import Manager - self.setup() - try: - self.construct() - # wait until all animations rendered in parallel - self.manager.finish() - self.interact() - except EndScene: - pass - except KeyboardInterrupt: - # Get rid keyboard interrupt symbols - print("", end="\r") - self.manager.file_writer.ended_with_interrupt = True - self.tear_down() - - render = run + return Manager(cls).render() + + render = deprecated(run) def setup(self) -> None: """ - This is meant to be implement by any scenes which - are comonly subclassed, and have some common setup + This method is used to set up scenes to do any setup involved before the construct method is called. """ - pass def construct(self) -> None: - # Where all the animation happens - # To be implemented in subclasses - pass + """ + The entrypoint to animations in Manim. + Should be overridden in the subclass to produce animations + """ def tear_down(self) -> None: - self.stop_skipping() - - if config.save_last_frame: - self.update_frame(ignore_skipping=True) - self.manager.file_writer.finish() - - if self.window: - self.window.close() - self.window = None - - def interact(self) -> None: """ - If there is a window, enter a loop - which updates the frame while under - the hood calling the pyglet event loop + This method is used to clean up scenes """ - if self.window is None: - return - logger.info( - "\nTips: Using the keys `d`, `f`, or `z` " - + "you can interact with the scene. " - + "Press `command + q` or `esc` to quit" - ) - self.skip_animations = False - self.refresh_static_mobjects() - while not self.window.is_closing: - self.update_frame(1 / self.camera.fps) def embed( self, @@ -288,7 +245,7 @@ def custom_exc(shell, etype, evalue, tb, tb_offset=None): # Launch shell shell( local_ns=local_ns, - # Pretend like we're embeding in the caller function, not here + # Pretend like we're embedding in the caller function, not here stack_depth=2, # Specify that the present module is the caller's, not here module=get_module(caller_frame.f_globals["__file__"]), @@ -299,31 +256,9 @@ def custom_exc(shell, etype, evalue, tb, tb_offset=None): raise EndScene() # Only these methods should touch the camera - def update_frame(self, dt: float = 0, ignore_skipping: bool = False) -> None: - self.increment_time(dt) - self.update_mobjects(dt) - if self.skip_animations and not ignore_skipping: - return - - if self.window.is_closing: - raise EndScene() - - if self.window: - self.window.clear() - # self.camera.clear() - state = self.get_state() - self.manager.render_state(state) - - if self.window: - self.window.swap_buffers() - vt = self.time - self.virtual_animation_start_time - rt = time.time() - self.real_animation_start_time - if rt < vt: - self.update_frame(0) - # Related to updating - def update_mobjects(self, dt: float) -> None: + def _update_mobjects(self, dt: float) -> None: for mobject in self.mobjects: mobject.update(dt) @@ -605,45 +540,6 @@ def stop_skipping(self) -> None: # Methods associated with running animations - def get_time_progression( - self, - run_time: float, - n_iterations: int | None = None, - desc: str = "", - override_skip_animations: bool = False, - ) -> list[float] | np.ndarray | ProgressDisplay: - if self.skip_animations and not override_skip_animations: - return [run_time] - - times = np.arange(0, run_time, 1 / self.camera.fps) - - # self.file_writer.set_progress_display_description(sub_desc=desc) - - if self.show_animation_progress: - return ProgressDisplay( - times, - total=n_iterations, - leave=self.leave_progress_bars, - ascii=True if platform.system() == "Windows" else None, - desc=desc, - ) - else: - return times - - def get_run_time(self, animations: Iterable[Animation]) -> float: - return max([animation.get_run_time() for animation in animations]) - - def get_animation_time_progression( - self, animations: Iterable[Animation] - ) -> list[float] | np.ndarray | ProgressDisplay: - animations = list(animations) - run_time = self.get_run_time(animations) - description = f"{self.num_plays} {animations[0]}" - if len(animations) > 1: - description += ", etc." - time_progression = self.manager.get_time_progression(run_time) - return time_progression - def get_wait_time_progression( self, duration: float, stop_condition: Callable[[], bool] | None = None ) -> list[float] | np.ndarray | ProgressDisplay: @@ -662,23 +558,13 @@ def pre_play(self): # Doesn't exist in Main # if not self.skip_animations: # self.file_writer.begin_animation() - if self.window: - self.real_animation_start_time = time.time() - self.virtual_animation_start_time = self.time - self.refresh_static_mobjects() - self.manager.begin() def post_play(self): # if not self.skip_animations: # self.manager.file_writer.end_animation() - if self.skip_animations and self.window is not None: - # Show some quick frames along the way - self.update_frame(dt=0, ignore_skipping=True) - self.num_plays += 1 - self.manager.finish() def refresh_static_mobjects(self) -> None: # self.camera.refresh_static_mobjects() @@ -689,20 +575,14 @@ def begin_animations(self, animations: Iterable[Animation]) -> None: animation.begin() self.process_buffer(animation.buffer) - def progress_through_animations(self, animations: Iterable[Animation]) -> None: - last_t = 0 - for t in self.get_animation_time_progression(animations): - dt = t - last_t - last_t = t - for animation in animations: - animation.update_mobjects(dt) - alpha = t / animation.get_run_time() - animation.interpolate(alpha) - if animation.apply_buffer: - self.process_buffer(animation.buffer) - animation.apply_buffer = False - self.update_frame(dt) - self.emit_frame() + def _update_animations(self, animations: Iterable[Animation], t: float, dt: float): + for animation in animations: + animation.update_mobjects(dt) + alpha = t / animation.get_run_time() + animation.interpolate(alpha) + if animation.apply_buffer: + self.process_buffer(animation.buffer) + animation.apply_buffer = False def finish_animations(self, animations: Iterable[Animation]) -> None: for animation in animations: @@ -710,9 +590,9 @@ def finish_animations(self, animations: Iterable[Animation]) -> None: self.process_buffer(animation.buffer) if self.skip_animations: - self.update_mobjects(self.get_run_time(animations)) + self._update_mobjects(self.manager._calc_runtime(animations)) else: - self.update_mobjects(0) + self._update_mobjects(0) def play( self, @@ -727,17 +607,14 @@ def play( animations = [prepare_animation(x) for x in proto_animations] for anim in animations: anim.update_rate_info(run_time, rate_func, lag_ratio) - self.pre_play() - self.begin_animations(animations) - self.progress_through_animations(animations) - self.finish_animations(animations) - self.post_play() + + self.manager._play(*animations) def wait( self, duration: float = DEFAULT_WAIT_TIME, - stop_condition: Callable[[], bool] = None, - note: str = None, + stop_condition: Callable[[], bool] | None = None, + note: str | None = None, ignore_presenter_mode: bool = False, ): self.pre_play() @@ -995,8 +872,8 @@ def __init__(self, scene: Scene, ignore: list[Mobject] | None = None) -> None: self.mobjects_to_copies[mob] = mob.copy() @property - def mobjects(self) -> list[Mobject]: - return self.mobjects_to_copies + def mobjects(self) -> Sequence[Mobject]: + return tuple(self.mobjects_to_copies.keys()) def __eq__(self, state: Any) -> bool: return isinstance(state, SceneState) and all( @@ -1007,6 +884,9 @@ def __eq__(self, state: Any) -> bool: ) ) + def __repr__(self) -> str: + return f"{type(self).__name__} of {len(self.mobjects_to_copies)} Mobjects" + def mobjects_match(self, state: SceneState): return self.mobjects_to_copies == state.mobjects_to_copies From 2df78a199666fb0413fcfd045283195fbf5bd491 Mon Sep 17 00:00:00 2001 From: JasonGrace2282 Date: Thu, 30 May 2024 07:55:46 -0400 Subject: [PATCH 2/7] Revamp exceptions --- example_scenes/new_test_new.py | 12 --------- example_scenes/test_new_rendering.py | 2 +- manim/renderer/render_manager.py | 39 ++++++++++++++++++---------- manim/scene/scene.py | 15 +++-------- 4 files changed, 31 insertions(+), 37 deletions(-) diff --git a/example_scenes/new_test_new.py b/example_scenes/new_test_new.py index 63589cbe5c..ed2f425226 100644 --- a/example_scenes/new_test_new.py +++ b/example_scenes/new_test_new.py @@ -22,18 +22,6 @@ from manim.mobject.text.text_mobject import Text from manim.renderer.opengl_renderer import OpenGLRenderer - -def progress_through_animations(animations): - dt = t - last_t - last_t = t - for animation in animations: - animation.update_mobjects(dt) - alpha = t / animation.run_time - animation.interpolate(alpha) - self.update_frame(dt) - self.emit_frame() - - if __name__ == "__main__": with tempconfig({"renderer": "opengl"}): win = Window( diff --git a/example_scenes/test_new_rendering.py b/example_scenes/test_new_rendering.py index 90b42db035..68485607ac 100644 --- a/example_scenes/test_new_rendering.py +++ b/example_scenes/test_new_rendering.py @@ -10,4 +10,4 @@ def construct(self) -> None: with tempconfig({"renderer": "opengl", "preview": True, "parallel": False}): - Test().render() + Manager(Test).render() diff --git a/manim/renderer/render_manager.py b/manim/renderer/render_manager.py index 52d2d42ea9..89dbcc2de7 100644 --- a/manim/renderer/render_manager.py +++ b/manim/renderer/render_manager.py @@ -7,6 +7,7 @@ from manim import config, logger from manim.constants import RendererType +from manim.utils.exceptions import EndSceneEarlyException from ..scene.scene import Scene, SceneState from .opengl_file_writer import FileWriter @@ -22,13 +23,27 @@ __all__ = ("Manager",) -class EndSceneError(Exception): - pass - - class Manager: """ The Brain of Manim + + .. note:: + + The only method of this class officially guarenteed to be + stable is :meth:`~.Manager.render`. Any other methods documented + are purely for development + + Usage + ----- + + .. code-block:: python + + class Manimation(Scene): + def construct(self): + self.play(FadeIn(Circle())) + + + Manager(Manimation).render() """ def __init__(self, scene_cls: type[Scene]) -> None: @@ -46,12 +61,12 @@ def __init__(self, scene_cls: type[Scene]) -> None: # Initialize window, if applicable if config.preview: self.window = Window() + self.renderer.use_window() else: self.window = None # file writer self.file_writer = FileWriter(self.scene.get_default_scene_name()) # TODO - self.renderer.use_window() @property def camera(self) -> Camera: @@ -59,7 +74,6 @@ def camera(self) -> Camera: @property def _renderer_class(self) -> type[RendererProtocol]: - # TODO: Implement based on renderer in config match config.renderer: case RendererType.OPENGL: return OpenGLRenderer @@ -107,7 +121,7 @@ def _render_first_pass(self) -> None: try: self.scene.construct() self._interact() - except EndSceneError: + except EndSceneEarlyException: pass except KeyboardInterrupt: # Get rid keyboard interrupt symbols @@ -153,10 +167,9 @@ def _update_frame(self, dt: float): self.time += dt self.scene._update_mobjects(dt) - if self.window is not None and self.window.is_closing: - raise EndSceneError() - if self.window is not None: + if self.window.is_closing: + raise EndSceneEarlyException() self.window.clear() state = self.scene.get_state() @@ -165,7 +178,7 @@ def _update_frame(self, dt: float): if self.window is not None: self.window.swap_buffers() vt = self.time - self.virtual_animation_start_time - rt = time.time() - self.real_animation_start_time + rt = time.perf_counter() - self.real_animation_start_time if rt < vt: self._update_frame(0) @@ -173,7 +186,7 @@ def _play(self, *animations: AnimationProtocol): self.scene.pre_play() if self.window is not None: - self.real_animation_start_time = time.time() + self.real_animation_start_time = time.perf_counter() self.virtual_animation_start_time = self.time self.scene.begin_animations(animations) @@ -206,5 +219,5 @@ def _render_frame(self, state: SceneState) -> Any | None: def _send_scene_to_renderer(self, state: SceneState): """Renders the State""" - result = self.renderer.render(self.camera, state.mobjects) + result = self.renderer.render(self.scene.camera, state.mobjects) return result diff --git a/manim/scene/scene.py b/manim/scene/scene.py index 1ccbbd81e0..71190eeb6d 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -26,6 +26,7 @@ from manim.mobject.types.vectorized_mobject import VGroup, VMobject from manim.utils.color import RED from manim.utils.deprecation import deprecated +from manim.utils.exceptions import EndSceneEarlyException from manim.utils.family_ops import extract_mobject_family_members from manim.utils.iterables import list_difference_update from manim.utils.module_ops import get_module @@ -84,7 +85,7 @@ def __init__( # Core state of the scene self.camera: Camera = Camera() self.camera.save_state() - self.__manager = manager + self.manager = manager self.mobjects: list[Mobject] = [] self.id_to_mobject_map: dict[int, Mobject] = {} self.num_plays: int = 0 @@ -108,10 +109,6 @@ def __init__( random.seed(self.random_seed) np.random.seed(self.random_seed) - @property - def manager(self) -> Manager: - return self.__manager - def __str__(self) -> str: return self.__class__.__name__ @@ -253,7 +250,7 @@ def custom_exc(shell, etype, evalue, tb, tb_offset=None): # End scene when exiting an embed if close_scene_on_exit: - raise EndScene() + raise EndSceneEarlyException() # Only these methods should touch the camera # Related to updating @@ -532,7 +529,7 @@ def update_skipping_status(self) -> None: if (self.end_at_animation_number is not None) and ( self.num_plays >= self.end_at_animation_number ): - raise EndScene() + raise EndSceneEarlyException() def stop_skipping(self) -> None: self.virtual_animation_start_time = self.time @@ -903,7 +900,3 @@ def restore_scene(self, scene: Scene): scene.mobjects = [ mob.become(mob_copy) for mob, mob_copy in self.mobjects_to_copies.items() ] - - -class EndScene(Exception): - pass From af3020ce353c8bbc51d13395786659254b210ff4 Mon Sep 17 00:00:00 2001 From: JasonGrace2282 Date: Fri, 21 Jun 2024 11:09:19 -0400 Subject: [PATCH 3/7] Got render loop working --- manim/renderer/cairo_renderer.py | 1 - manim/renderer/opengl_renderer_window.py | 3 - manim/renderer/render_manager.py | 22 +- manim/renderer/renderer.py | 1 + manim/scene/scene.py | 2 +- poetry.lock | 286 +++-------------------- 6 files changed, 44 insertions(+), 271 deletions(-) diff --git a/manim/renderer/cairo_renderer.py b/manim/renderer/cairo_renderer.py index 9be8f5a59a..add624e641 100644 --- a/manim/renderer/cairo_renderer.py +++ b/manim/renderer/cairo_renderer.py @@ -8,7 +8,6 @@ from manim.utils.hashing import get_hash_from_play_call from .. import config, logger -from ..camera.cairo_camera import CairoCamera as Camera from ..mobject.mobject import Mobject from ..scene.scene_file_writer import SceneFileWriter from ..utils.exceptions import EndSceneEarlyException diff --git a/manim/renderer/opengl_renderer_window.py b/manim/renderer/opengl_renderer_window.py index 11c47b6b26..349ef8b767 100644 --- a/manim/renderer/opengl_renderer_window.py +++ b/manim/renderer/opengl_renderer_window.py @@ -10,9 +10,6 @@ from .. import __version__, config -if TYPE_CHECKING: - import manim.scene as m_scene - class Window(FunWindow): fullscreen: bool = False diff --git a/manim/renderer/render_manager.py b/manim/renderer/render_manager.py index 89dbcc2de7..8ff9d1b99f 100644 --- a/manim/renderer/render_manager.py +++ b/manim/renderer/render_manager.py @@ -7,6 +7,7 @@ from manim import config, logger from manim.constants import RendererType +from manim.renderer.cairo_renderer import CairoRenderer from manim.utils.exceptions import EndSceneEarlyException from ..scene.scene import Scene, SceneState @@ -29,7 +30,7 @@ class Manager: .. note:: - The only method of this class officially guarenteed to be + The only method of this class officially guaranteed to be stable is :meth:`~.Manager.render`. Any other methods documented are purely for development @@ -47,9 +48,6 @@ def construct(self): """ def __init__(self, scene_cls: type[Scene]) -> None: - # renderer - self.renderer = self._renderer_class() - # scene self.scene: Scene = scene_cls(self) @@ -61,10 +59,13 @@ def __init__(self, scene_cls: type[Scene]) -> None: # Initialize window, if applicable if config.preview: self.window = Window() - self.renderer.use_window() else: self.window = None + # this must be done AFTER instantiating a window + self.renderer = self.create_renderer() + self.renderer.use_window() + # file writer self.file_writer = FileWriter(self.scene.get_default_scene_name()) # TODO @@ -72,11 +73,13 @@ def __init__(self, scene_cls: type[Scene]) -> None: def camera(self) -> Camera: return self.scene.camera - @property - def _renderer_class(self) -> type[RendererProtocol]: + def create_renderer(self) -> RendererProtocol: match config.renderer: case RendererType.OPENGL: - return OpenGLRenderer + return OpenGLRenderer() + + case RendererType.CAIRO: + return CairoRenderer() case rendertype: raise ValueError(f"Invalid Config Renderer type {rendertype}") @@ -118,6 +121,7 @@ def _render_first_pass(self) -> None: rendering system """ self._setup() + try: self.scene.construct() self._interact() @@ -168,8 +172,6 @@ def _update_frame(self, dt: float): self.scene._update_mobjects(dt) if self.window is not None: - if self.window.is_closing: - raise EndSceneEarlyException() self.window.clear() state = self.scene.get_state() diff --git a/manim/renderer/renderer.py b/manim/renderer/renderer.py index 8ac2a25831..9038e68cb2 100644 --- a/manim/renderer/renderer.py +++ b/manim/renderer/renderer.py @@ -13,6 +13,7 @@ if TYPE_CHECKING: from collections.abc import Callable, Iterable, Sequence + import moderngl as gl from manim.camera.camera import Camera diff --git a/manim/scene/scene.py b/manim/scene/scene.py index 71190eeb6d..922bdcee0a 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -136,7 +136,7 @@ def run(cls) -> None: return Manager(cls).render() - render = deprecated(run) + render = run def setup(self) -> None: """ diff --git a/poetry.lock b/poetry.lock index e17c7c7619..c0291c7374 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "aiofiles" version = "22.1.0" description = "File support for asyncio." -category = "main" optional = true python-versions = ">=3.7,<4.0" files = [ @@ -16,7 +15,6 @@ files = [ name = "aiosqlite" version = "0.19.0" description = "asyncio bridge to the standard sqlite3 module" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -32,7 +30,6 @@ docs = ["sphinx (==6.1.3)", "sphinx-mdinclude (==0.5.3)"] name = "alabaster" version = "0.7.13" description = "A configurable sidebar-enabled Sphinx theme" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -44,7 +41,6 @@ files = [ name = "anyio" version = "3.7.1" description = "High level compatibility layer for multiple asynchronous event loop implementations" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -66,7 +62,6 @@ trio = ["trio (<0.22)"] name = "appnope" version = "0.1.3" description = "Disable App Nap on macOS >= 10.9" -category = "main" optional = false python-versions = "*" files = [ @@ -78,7 +73,6 @@ files = [ name = "argon2-cffi" version = "21.3.0" description = "The secure Argon2 password hashing algorithm." -category = "main" optional = true python-versions = ">=3.6" files = [ @@ -98,7 +92,6 @@ tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pytest"] name = "argon2-cffi-bindings" version = "21.2.0" description = "Low-level CFFI bindings for Argon2" -category = "main" optional = true python-versions = ">=3.6" files = [ @@ -136,7 +129,6 @@ tests = ["pytest"] name = "arrow" version = "1.2.3" description = "Better dates & times for Python" -category = "main" optional = true python-versions = ">=3.6" files = [ @@ -151,7 +143,6 @@ python-dateutil = ">=2.7.0" name = "astor" version = "0.8.1" description = "Read/rewrite/write Python ASTs" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" files = [ @@ -163,7 +154,6 @@ files = [ name = "astroid" version = "2.15.6" description = "An abstract syntax tree for Python with inference support." -category = "dev" optional = false python-versions = ">=3.7.2" files = [ @@ -183,7 +173,6 @@ wrapt = [ name = "asttokens" version = "2.2.1" description = "Annotate AST trees with source code positions" -category = "main" optional = false python-versions = "*" files = [ @@ -201,7 +190,6 @@ test = ["astroid", "pytest"] name = "attrs" version = "23.1.0" description = "Classes Without Boilerplate" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -220,7 +208,6 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte name = "babel" version = "2.12.1" description = "Internationalization utilities" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -235,7 +222,6 @@ pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} name = "backcall" version = "0.2.0" description = "Specifications for callback functions passed in to an API" -category = "main" optional = false python-versions = "*" files = [ @@ -247,7 +233,6 @@ files = [ name = "beautifulsoup4" version = "4.12.2" description = "Screen-scraping library" -category = "main" optional = false python-versions = ">=3.6.0" files = [ @@ -266,7 +251,6 @@ lxml = ["lxml"] name = "black" version = "23.7.0" description = "The uncompromising code formatter." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -313,7 +297,6 @@ uvloop = ["uvloop (>=0.15.2)"] name = "bleach" version = "6.0.0" description = "An easy safelist-based HTML-sanitizing tool." -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -332,7 +315,6 @@ css = ["tinycss2 (>=1.1.0,<1.2)"] name = "certifi" version = "2023.7.22" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -344,7 +326,6 @@ files = [ name = "cffi" version = "1.15.1" description = "Foreign Function Interface for Python calling C code." -category = "main" optional = false python-versions = "*" files = [ @@ -421,7 +402,6 @@ pycparser = "*" name = "cfgv" version = "3.3.1" description = "Validate configuration and produce human readable error messages." -category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -433,7 +413,6 @@ files = [ name = "charset-normalizer" version = "3.2.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -518,7 +497,6 @@ files = [ name = "click" version = "8.1.6" description = "Composable command line interface toolkit" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -533,7 +511,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "click-default-group" version = "1.2.2" description = "Extends click.Group to invoke a command without explicit subcommand name" -category = "main" optional = false python-versions = "*" files = [ @@ -547,7 +524,6 @@ click = "*" name = "cloup" version = "0.13.1" description = "Adds features to Click: option groups, constraints, subcommand sections and help themes." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -563,7 +539,6 @@ typing-extensions = {version = "*", markers = "python_version <= \"3.8\""} name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -575,7 +550,6 @@ files = [ name = "comm" version = "0.1.3" description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." -category = "main" optional = true python-versions = ">=3.6" files = [ @@ -595,7 +569,6 @@ typing = ["mypy (>=0.990)"] name = "commonmark" version = "0.9.1" description = "Python parser for the CommonMark Markdown spec" -category = "dev" optional = false python-versions = "*" files = [ @@ -610,7 +583,6 @@ test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] name = "contourpy" version = "1.1.0" description = "Python library for calculating contours of 2D quadrilateral grids" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -621,6 +593,7 @@ files = [ {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a64814ae7bce73925131381603fff0116e2df25230dfc80d6d690aa6e20b37"}, {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c81f22b4f572f8a2110b0b741bb64e5a6427e0a198b2cdc1fbaf85f352a3aa"}, {file = "contourpy-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53cc3a40635abedbec7f1bde60f8c189c49e84ac180c665f2cd7c162cc454baa"}, + {file = "contourpy-1.1.0-cp310-cp310-win32.whl", hash = "sha256:9b2dd2ca3ac561aceef4c7c13ba654aaa404cf885b187427760d7f7d4c57cff8"}, {file = "contourpy-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f795597073b09d631782e7245016a4323cf1cf0b4e06eef7ea6627e06a37ff2"}, {file = "contourpy-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0b7b04ed0961647691cfe5d82115dd072af7ce8846d31a5fac6c142dcce8b882"}, {file = "contourpy-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27bc79200c742f9746d7dd51a734ee326a292d77e7d94c8af6e08d1e6c15d545"}, @@ -629,6 +602,7 @@ files = [ {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5cec36c5090e75a9ac9dbd0ff4a8cf7cecd60f1b6dc23a374c7d980a1cd710e"}, {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cbd657e9bde94cd0e33aa7df94fb73c1ab7799378d3b3f902eb8eb2e04a3a"}, {file = "contourpy-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:181cbace49874f4358e2929aaf7ba84006acb76694102e88dd15af861996c16e"}, + {file = "contourpy-1.1.0-cp311-cp311-win32.whl", hash = "sha256:edb989d31065b1acef3828a3688f88b2abb799a7db891c9e282df5ec7e46221b"}, {file = "contourpy-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb3b7d9e6243bfa1efb93ccfe64ec610d85cfe5aec2c25f97fbbd2e58b531256"}, {file = "contourpy-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb41692aa09aeb19c7c213411854402f29f6613845ad2453d30bf421fe68fed"}, {file = "contourpy-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d123a5bc63cd34c27ff9c7ac1cd978909e9c71da12e05be0231c608048bb2ae"}, @@ -637,6 +611,7 @@ files = [ {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317267d915490d1e84577924bd61ba71bf8681a30e0d6c545f577363157e5e94"}, {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d551f3a442655f3dcc1285723f9acd646ca5858834efeab4598d706206b09c9f"}, {file = "contourpy-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e7a117ce7df5a938fe035cad481b0189049e8d92433b4b33aa7fc609344aafa1"}, + {file = "contourpy-1.1.0-cp38-cp38-win32.whl", hash = "sha256:108dfb5b3e731046a96c60bdc46a1a0ebee0760418951abecbe0fc07b5b93b27"}, {file = "contourpy-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4f26b25b4f86087e7d75e63212756c38546e70f2a92d2be44f80114826e1cd4"}, {file = "contourpy-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc00bb4225d57bff7ebb634646c0ee2a1298402ec10a5fe7af79df9a51c1bfd9"}, {file = "contourpy-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:189ceb1525eb0655ab8487a9a9c41f42a73ba52d6789754788d1883fb06b2d8a"}, @@ -645,6 +620,7 @@ files = [ {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143dde50520a9f90e4a2703f367cf8ec96a73042b72e68fcd184e1279962eb6f"}, {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e94bef2580e25b5fdb183bf98a2faa2adc5b638736b2c0a4da98691da641316a"}, {file = "contourpy-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed614aea8462735e7d70141374bd7650afd1c3f3cb0c2dbbcbe44e14331bf002"}, + {file = "contourpy-1.1.0-cp39-cp39-win32.whl", hash = "sha256:71551f9520f008b2950bef5f16b0e3587506ef4f23c734b71ffb7b89f8721999"}, {file = "contourpy-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:438ba416d02f82b692e371858143970ed2eb6337d9cdbbede0d8ad9f3d7dd17d"}, {file = "contourpy-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a698c6a7a432789e587168573a864a7ea374c6be8d4f31f9d87c001d5a843493"}, {file = "contourpy-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b0ac8a12880412da3551a8cb5a187d3298a72802b45a3bd1805e204ad8439"}, @@ -669,7 +645,6 @@ test-no-images = ["pytest", "pytest-cov", "wurlitzer"] name = "coverage" version = "7.2.7" description = "Code coverage measurement for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -745,7 +720,6 @@ toml = ["tomli"] name = "cryptography" version = "41.0.2" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -791,7 +765,6 @@ test-randomorder = ["pytest-randomly"] name = "cycler" version = "0.11.0" description = "Composable style cycles" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -803,7 +776,6 @@ files = [ name = "cython" version = "3.0.0" description = "The Cython compiler for writing C extensions in the Python language." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -871,7 +843,6 @@ files = [ name = "data-science-types" version = "0.2.23" description = "Type stubs for Python machine learning libraries" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -886,7 +857,6 @@ dev = ["black", "flake8", "flake8-pyi", "matplotlib", "mypy (==0.770)", "numpy", name = "dearpygui" version = "1.9.1" description = "DearPyGui: A simple Python GUI Toolkit" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -914,7 +884,6 @@ files = [ name = "debugpy" version = "1.6.7" description = "An implementation of the Debug Adapter Protocol for Python" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -942,7 +911,6 @@ files = [ name = "decorator" version = "5.1.1" description = "Decorators for Humans" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -954,7 +922,6 @@ files = [ name = "defusedxml" version = "0.7.1" description = "XML bomb protection for Python stdlib modules" -category = "main" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -966,7 +933,6 @@ files = [ name = "deprecated" version = "1.2.14" description = "Python @deprecated decorator to deprecate old python classes, functions or methods." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -984,7 +950,6 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] name = "dill" version = "0.3.7" description = "serialize all of Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -999,7 +964,6 @@ graph = ["objgraph (>=1.7.2)"] name = "distlib" version = "0.3.7" description = "Distribution utilities" -category = "dev" optional = false python-versions = "*" files = [ @@ -1011,7 +975,6 @@ files = [ name = "docutils" version = "0.17.1" description = "Docutils -- Python Documentation Utilities" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1023,7 +986,6 @@ files = [ name = "entrypoints" version = "0.4" description = "Discover and load entry points from installed packages." -category = "main" optional = true python-versions = ">=3.6" files = [ @@ -1035,7 +997,6 @@ files = [ name = "exceptiongroup" version = "1.1.2" description = "Backport of PEP 654 (exception groups)" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1050,7 +1011,6 @@ test = ["pytest (>=6)"] name = "execnet" version = "2.0.2" description = "execnet: rapid multi-Python deployment" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1065,7 +1025,6 @@ testing = ["hatch", "pre-commit", "pytest", "tox"] name = "executing" version = "1.2.0" description = "Get the currently executing AST node of a frame, and other information" -category = "main" optional = false python-versions = "*" files = [ @@ -1080,7 +1039,6 @@ tests = ["asttokens", "littleutils", "pytest", "rich"] name = "fastjsonschema" version = "2.18.0" description = "Fastest Python implementation of JSON schema" -category = "main" optional = true python-versions = "*" files = [ @@ -1095,7 +1053,6 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc name = "filelock" version = "3.12.2" description = "A platform independent file lock." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1111,7 +1068,6 @@ testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "p name = "flake8" version = "3.9.2" description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -1128,7 +1084,6 @@ pyflakes = ">=2.3.0,<2.4.0" name = "flake8-bugbear" version = "21.11.29" description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1147,7 +1102,6 @@ dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit"] name = "flake8-builtins" version = "1.5.3" description = "Check for python builtins being used as variables or parameters." -category = "dev" optional = false python-versions = "*" files = [ @@ -1165,7 +1119,6 @@ test = ["coverage", "coveralls", "mock", "pytest", "pytest-cov"] name = "flake8-comprehensions" version = "3.14.0" description = "A flake8 plugin to help you write better list/set/dict comprehensions." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1180,7 +1133,6 @@ flake8 = ">=3.0,<3.2.0 || >3.2.0" name = "flake8-docstrings" version = "1.7.0" description = "Extension for flake8 which uses pydocstyle to check docstrings" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1196,7 +1148,6 @@ pydocstyle = ">=2.1" name = "flake8-plugin-utils" version = "1.3.3" description = "The package provides base classes and utils for flake8 plugin writing" -category = "dev" optional = false python-versions = ">=3.6,<4.0" files = [ @@ -1208,7 +1159,6 @@ files = [ name = "flake8-pytest-style" version = "1.7.2" description = "A flake8 plugin checking common style issues or inconsistencies with pytest-based tests." -category = "dev" optional = false python-versions = ">=3.7.2,<4.0.0" files = [ @@ -1223,7 +1173,6 @@ flake8-plugin-utils = ">=1.3.2,<2.0.0" name = "flake8-rst-docstrings" version = "0.2.7" description = "Python docstring reStructuredText (RST) validator" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1240,7 +1189,6 @@ restructuredtext-lint = "*" name = "flake8-simplify" version = "0.14.6" description = "flake8 plugin which checks for code that can be simplified" -category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -1256,7 +1204,6 @@ flake8 = ">=3.7" name = "fonttools" version = "4.41.1" description = "Tools to manipulate font files" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1314,7 +1261,6 @@ woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] name = "fqdn" version = "1.5.1" description = "Validates fully-qualified domain names against RFC 1123, so that they are acceptable to modern bowsers" -category = "main" optional = true python-versions = ">=2.7, !=3.0, !=3.1, !=3.2, !=3.3, !=3.4, <4" files = [ @@ -1326,7 +1272,6 @@ files = [ name = "furo" version = "2022.9.29" description = "A clean customisable Sphinx documentation theme." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1344,7 +1289,6 @@ sphinx-basic-ng = "*" name = "gitdb" version = "4.0.10" description = "Git Object Database" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1359,7 +1303,6 @@ smmap = ">=3.0.1,<6" name = "gitpython" version = "3.1.32" description = "GitPython is a Python library used to interact with Git repositories" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1374,7 +1317,6 @@ gitdb = ">=4.0.1,<5" name = "glcontext" version = "2.4.0" description = "Portable OpenGL Context" -category = "main" optional = false python-versions = "*" files = [ @@ -1443,7 +1385,6 @@ files = [ name = "identify" version = "2.5.26" description = "File identification library for Python" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1458,7 +1399,6 @@ license = ["ukkonen"] name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1470,7 +1410,6 @@ files = [ name = "imagesize" version = "1.4.1" description = "Getting image size from png/jpeg/jpeg2000/gif file" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1482,7 +1421,6 @@ files = [ name = "importlib-metadata" version = "6.8.0" description = "Read metadata from Python packages" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1502,7 +1440,6 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs name = "importlib-resources" version = "6.0.0" description = "Read resources from Python packages" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1521,7 +1458,6 @@ testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1533,7 +1469,6 @@ files = [ name = "ipykernel" version = "6.25.0" description = "IPython Kernel for Jupyter" -category = "main" optional = true python-versions = ">=3.8" files = [ @@ -1547,7 +1482,7 @@ comm = ">=0.1.1" debugpy = ">=1.6.5" ipython = ">=7.23.1" jupyter-client = ">=6.1.12" -jupyter-core = ">=4.12,<5.0.0 || >=5.1.0" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" matplotlib-inline = ">=0.1" nest-asyncio = "*" packaging = "*" @@ -1567,7 +1502,6 @@ test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio" name = "ipython" version = "8.12.2" description = "IPython: Productive Interactive Computing" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1607,7 +1541,6 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pa name = "ipython-genutils" version = "0.2.0" description = "Vestigial utilities from IPython" -category = "main" optional = true python-versions = "*" files = [ @@ -1619,7 +1552,6 @@ files = [ name = "isoduration" version = "20.11.0" description = "Operations with ISO 8601 durations" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -1634,7 +1566,6 @@ arrow = ">=0.15.0" name = "isort" version = "5.12.0" description = "A Python utility / library to sort Python imports." -category = "dev" optional = false python-versions = ">=3.8.0" files = [ @@ -1652,7 +1583,6 @@ requirements-deprecated-finder = ["pip-api", "pipreqs"] name = "isosurfaces" version = "0.1.0" description = "Construct isolines/isosurfaces over a 2D/3D scalar field defined by a function (not a uniform grid)" -category = "main" optional = false python-versions = "*" files = [ @@ -1667,7 +1597,6 @@ numpy = "*" name = "jedi" version = "0.19.0" description = "An autocompletion tool for Python that can be used for text editors." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1687,7 +1616,6 @@ testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1705,7 +1633,6 @@ i18n = ["Babel (>=2.7)"] name = "json5" version = "0.9.14" description = "A Python implementation of the JSON5 data format." -category = "main" optional = true python-versions = "*" files = [ @@ -1720,7 +1647,6 @@ dev = ["hypothesis"] name = "jsonpointer" version = "2.4" description = "Identify specific nodes in a JSON document (RFC 6901)" -category = "main" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" files = [ @@ -1732,7 +1658,6 @@ files = [ name = "jsonschema" version = "4.18.4" description = "An implementation of JSON Schema validation for Python" -category = "main" optional = true python-versions = ">=3.8" files = [ @@ -1764,7 +1689,6 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- name = "jsonschema-specifications" version = "2023.7.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" -category = "main" optional = true python-versions = ">=3.8" files = [ @@ -1780,7 +1704,6 @@ referencing = ">=0.28.0" name = "jupyter-client" version = "7.4.9" description = "Jupyter protocol implementation and client libraries" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -1805,7 +1728,6 @@ test = ["codecov", "coverage", "ipykernel (>=6.12)", "ipython", "mypy", "pre-com name = "jupyter-core" version = "5.3.1" description = "Jupyter core package. A base package on which Jupyter projects rely." -category = "main" optional = true python-versions = ">=3.8" files = [ @@ -1826,7 +1748,6 @@ test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] name = "jupyter-events" version = "0.7.0" description = "Jupyter Event System library" -category = "main" optional = true python-versions = ">=3.8" files = [ @@ -1852,7 +1773,6 @@ test = ["click", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.19.0)", "p name = "jupyter-server" version = "2.7.0" description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." -category = "main" optional = true python-versions = ">=3.8" files = [ @@ -1865,7 +1785,7 @@ anyio = ">=3.1.0" argon2-cffi = "*" jinja2 = "*" jupyter-client = ">=7.4.4" -jupyter-core = ">=4.12,<5.0.0 || >=5.1.0" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" jupyter-events = ">=0.6.0" jupyter-server-terminals = "*" nbconvert = ">=6.4.4" @@ -1889,7 +1809,6 @@ test = ["flaky", "ipykernel", "pre-commit", "pytest (>=7.0)", "pytest-console-sc name = "jupyter-server-fileid" version = "0.9.0" description = "" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -1909,7 +1828,6 @@ test = ["jupyter-server[test] (>=1.15,<3)", "pytest", "pytest-cov"] name = "jupyter-server-terminals" version = "0.4.4" description = "A Jupyter Server Extension Providing Terminals." -category = "main" optional = true python-versions = ">=3.8" files = [ @@ -1929,7 +1847,6 @@ test = ["coverage", "jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-cov", name = "jupyter-server-ydoc" version = "0.8.0" description = "A Jupyter Server Extension Providing Y Documents." -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -1949,7 +1866,6 @@ test = ["coverage", "jupyter-server[test] (>=2.0.0a0)", "pytest (>=7.0)", "pytes name = "jupyter-ydoc" version = "0.2.5" description = "Document structures for collaborative editing using Ypy" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -1969,7 +1885,6 @@ test = ["pre-commit", "pytest", "pytest-asyncio", "websockets (>=10.0)", "ypy-we name = "jupyterlab" version = "3.6.5" description = "JupyterLab computational environment" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -1998,7 +1913,6 @@ test = ["check-manifest", "coverage", "jupyterlab-server[test]", "pre-commit", " name = "jupyterlab-pygments" version = "0.2.2" description = "Pygments theme using JupyterLab CSS variables" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -2010,7 +1924,6 @@ files = [ name = "jupyterlab-server" version = "2.24.0" description = "A set of server components for JupyterLab and JupyterLab like applications." -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -2037,7 +1950,6 @@ test = ["hatch", "ipykernel", "jupyterlab-server[openapi]", "openapi-spec-valida name = "kiwisolver" version = "1.4.4" description = "A fast implementation of the Cassowary constraint solver" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2115,7 +2027,6 @@ files = [ name = "lazy-object-proxy" version = "1.9.0" description = "A fast and thorough lazy object proxy." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2161,7 +2072,6 @@ files = [ name = "manimpango" version = "0.4.3" description = "Bindings for Pango for using with Manim." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2187,7 +2097,6 @@ files = [ name = "mapbox-earcut" version = "1.0.1" description = "Python bindings for the mapbox earcut C++ polygon triangulation library." -category = "main" optional = false python-versions = "*" files = [ @@ -2207,6 +2116,14 @@ files = [ {file = "mapbox_earcut-1.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9af9369266bf0ca32f4d401152217c46c699392513f22639c6b1be32bde9c1cc"}, {file = "mapbox_earcut-1.0.1-cp311-cp311-win32.whl", hash = "sha256:ff9a13be4364625697b0e0e04ba6a0f77300148b871bba0a85bfa67e972e85c4"}, {file = "mapbox_earcut-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:5e736557539c74fa969e866889c2b0149fc12668f35e3ae33667d837ff2880d3"}, + {file = "mapbox_earcut-1.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4fe92174410e4120022393013705d77cb856ead5bdf6c81bec614a70df4feb5d"}, + {file = "mapbox_earcut-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:082f70a865c6164a60af039aa1c377073901cf1f94fd37b1c5610dfbae2a7369"}, + {file = "mapbox_earcut-1.0.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43d268ece49d0c9e22cb4f92cd54c2cc64f71bf1c5e10800c189880d923e1292"}, + {file = "mapbox_earcut-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7748f1730fd36dd1fcf0809d8f872d7e1ddaa945f66a6a466ad37ef3c552ae93"}, + {file = "mapbox_earcut-1.0.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:5a82d10c8dec2a0bd9a6a6c90aca7044017c8dad79f7e209fd0667826f842325"}, + {file = "mapbox_earcut-1.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:01b292588cd3f6bad7d76ee31c004ed1b557a92bbd9602a72d2be15513b755be"}, + {file = "mapbox_earcut-1.0.1-cp312-cp312-win32.whl", hash = "sha256:fce236ddc3a56ea7260acc94601a832c260e6ac5619374bb2cec2e73e7414ff0"}, + {file = "mapbox_earcut-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:1ce86407353b4f09f5778c436518bbbc6f258f46c5736446f25074fe3d3a3bd8"}, {file = "mapbox_earcut-1.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:aa6111a18efacb79c081f3d3cdd7d25d0585bb0e9f28896b207ebe1d56efa40e"}, {file = "mapbox_earcut-1.0.1-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2911829d1e6e5e1282fbe2840fadf578f606580f02ed436346c2d51c92f810b"}, {file = "mapbox_earcut-1.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01ff909a7b8405a923abedd701b53633c997cc2b5dc9d5b78462f51c25ec2c33"}, @@ -2262,7 +2179,6 @@ test = ["pytest"] name = "markdown-it-py" version = "2.2.0" description = "Python port of markdown-it. Markdown parsing, done right!" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2287,7 +2203,6 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] name = "markupsafe" version = "2.1.3" description = "Safely add untrusted strings to HTML/XML markup." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2311,6 +2226,16 @@ files = [ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, @@ -2347,7 +2272,6 @@ files = [ name = "matplotlib" version = "3.7.2" description = "Python plotting package" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -2405,13 +2329,11 @@ packaging = ">=20.0" pillow = ">=6.2.0" pyparsing = ">=2.3.1,<3.1" python-dateutil = ">=2.7" -setuptools_scm = ">=7" [[package]] name = "matplotlib-inline" version = "0.1.6" description = "Inline Matplotlib backend for Jupyter" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -2426,7 +2348,6 @@ traitlets = "*" name = "mccabe" version = "0.6.1" description = "McCabe checker, plugin for flake8" -category = "dev" optional = false python-versions = "*" files = [ @@ -2438,7 +2359,6 @@ files = [ name = "mdit-py-plugins" version = "0.3.5" description = "Collection of plugins for markdown-it-py" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2458,7 +2378,6 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] name = "mdurl" version = "0.1.2" description = "Markdown URL utilities" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2470,7 +2389,6 @@ files = [ name = "mistune" version = "3.0.1" description = "A sane and fast Markdown parser with useful plugins and renderers" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -2482,7 +2400,6 @@ files = [ name = "moderngl" version = "5.8.2" description = "ModernGL: High performance rendering for Python 3" -category = "main" optional = false python-versions = "*" files = [ @@ -2545,7 +2462,6 @@ glcontext = ">=2.3.6,<3" name = "moderngl-window" version = "2.4.4" description = "A cross platform helper library for ModernGL making window creation and resource loading simple" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2574,7 +2490,6 @@ trimesh = ["scipy (>=1.3.2)", "trimesh (>=3.2.6,<4)"] name = "multipledispatch" version = "1.0.0" description = "Multiple dispatch" -category = "main" optional = false python-versions = "*" files = [ @@ -2586,7 +2501,6 @@ files = [ name = "mypy" version = "0.931" description = "Optional static typing for Python" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2625,7 +2539,6 @@ python2 = ["typed-ast (>=1.4.0,<2)"] name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -2637,7 +2550,6 @@ files = [ name = "myst-parser" version = "0.17.2" description = "An extended commonmark compliant parser, with bridges to docutils & sphinx." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2664,7 +2576,6 @@ testing = ["beautifulsoup4", "coverage", "docutils (>=0.17.0,<0.18.0)", "pytest name = "nbclassic" version = "1.0.0" description = "Jupyter Notebook as a Jupyter Server extension." -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -2700,7 +2611,6 @@ test = ["coverage", "nbval", "pytest", "pytest-cov", "pytest-jupyter", "pytest-p name = "nbclient" version = "0.8.0" description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." -category = "main" optional = true python-versions = ">=3.8.0" files = [ @@ -2710,7 +2620,7 @@ files = [ [package.dependencies] jupyter-client = ">=6.1.12" -jupyter-core = ">=4.12,<5.0.0 || >=5.1.0" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" nbformat = ">=5.1" traitlets = ">=5.4" @@ -2723,7 +2633,6 @@ test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>= name = "nbconvert" version = "7.7.3" description = "Converting Jupyter Notebooks" -category = "main" optional = true python-versions = ">=3.8" files = [ @@ -2762,7 +2671,6 @@ webpdf = ["playwright"] name = "nbformat" version = "5.9.2" description = "The Jupyter Notebook format" -category = "main" optional = true python-versions = ">=3.8" files = [ @@ -2784,7 +2692,6 @@ test = ["pep440", "pre-commit", "pytest", "testpath"] name = "nest-asyncio" version = "1.5.7" description = "Patch asyncio to allow nested event loops" -category = "main" optional = true python-versions = ">=3.5" files = [ @@ -2796,7 +2703,6 @@ files = [ name = "networkx" version = "2.8.8" description = "Python package for creating and manipulating graphs and networks" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2815,7 +2721,6 @@ test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"] name = "nodeenv" version = "1.8.0" description = "Node.js virtual environment builder" -category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ @@ -2830,7 +2735,6 @@ setuptools = "*" name = "notebook" version = "6.5.5" description = "A web-based notebook environment for interactive computing" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -2865,7 +2769,6 @@ test = ["coverage", "nbval", "pytest", "pytest-cov", "requests", "requests-unixs name = "notebook-shim" version = "0.2.3" description = "A shim layer for notebook traits and config" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -2883,7 +2786,6 @@ test = ["pytest", "pytest-console-scripts", "pytest-jupyter", "pytest-tornasync" name = "numpy" version = "1.24.4" description = "Fundamental package for array computing in Python" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2921,7 +2823,6 @@ files = [ name = "overrides" version = "7.3.1" description = "A decorator to automatically detect mismatch when overriding a method." -category = "main" optional = true python-versions = ">=3.6" files = [ @@ -2933,7 +2834,6 @@ files = [ name = "packaging" version = "23.1" description = "Core utilities for Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2945,7 +2845,6 @@ files = [ name = "pandocfilters" version = "1.5.0" description = "Utilities for writing pandoc filters in python" -category = "main" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2957,7 +2856,6 @@ files = [ name = "parso" version = "0.8.3" description = "A Python Parser" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2973,7 +2871,6 @@ testing = ["docopt", "pytest (<6.0.0)"] name = "pathspec" version = "0.11.2" description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2985,7 +2882,6 @@ files = [ name = "pexpect" version = "4.8.0" description = "Pexpect allows easy control of interactive console applications." -category = "main" optional = false python-versions = "*" files = [ @@ -3000,7 +2896,6 @@ ptyprocess = ">=0.5" name = "pickleshare" version = "0.7.5" description = "Tiny 'shelve'-like database with concurrency support" -category = "main" optional = false python-versions = "*" files = [ @@ -3012,7 +2907,6 @@ files = [ name = "pillow" version = "9.5.0" description = "Python Imaging Library (Fork)" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3092,7 +2986,6 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa name = "pkgutil-resolve-name" version = "1.3.10" description = "Resolve a name to an object." -category = "main" optional = true python-versions = ">=3.6" files = [ @@ -3104,7 +2997,6 @@ files = [ name = "platformdirs" version = "3.10.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3120,7 +3012,6 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co name = "pluggy" version = "1.2.0" description = "plugin and hook calling mechanisms for python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3136,7 +3027,6 @@ testing = ["pytest", "pytest-benchmark"] name = "pre-commit" version = "2.21.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3155,7 +3045,6 @@ virtualenv = ">=20.10.0" name = "prometheus-client" version = "0.17.1" description = "Python client for the Prometheus monitoring system." -category = "main" optional = true python-versions = ">=3.6" files = [ @@ -3170,8 +3059,7 @@ twisted = ["twisted"] name = "prompt-toolkit" version = "3.0.39" description = "Library for building powerful interactive command lines in Python" -category = "main" -optional = true +optional = false python-versions = ">=3.7.0" files = [ {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, @@ -3185,7 +3073,6 @@ wcwidth = "*" name = "psutil" version = "5.9.5" description = "Cross-platform lib for process and system monitoring in Python." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -3212,7 +3099,6 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] name = "psutil-wheels" version = "5.8.0" description = "Cross-platform lib for process and system monitoring in Python." -category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -3238,7 +3124,6 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "unittest2", "wmi"] name = "ptyprocess" version = "0.7.0" description = "Run a subprocess in a pseudo terminal" -category = "main" optional = false python-versions = "*" files = [ @@ -3250,7 +3135,6 @@ files = [ name = "pure-eval" version = "0.2.2" description = "Safely evaluate AST nodes without side effects" -category = "main" optional = false python-versions = "*" files = [ @@ -3265,7 +3149,6 @@ tests = ["pytest"] name = "py" version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -3277,7 +3160,6 @@ files = [ name = "pycairo" version = "1.24.0" description = "Python interface for cairo" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3298,7 +3180,6 @@ files = [ name = "pycodestyle" version = "2.7.0" description = "Python style guide checker" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -3310,7 +3191,6 @@ files = [ name = "pycparser" version = "2.21" description = "C parser in Python" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -3322,7 +3202,6 @@ files = [ name = "pydocstyle" version = "6.3.0" description = "Python docstring style checker" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -3340,7 +3219,6 @@ toml = ["tomli (>=1.2.3)"] name = "pydub" version = "0.25.1" description = "Manipulate audio with an simple and easy high level interface" -category = "main" optional = false python-versions = "*" files = [ @@ -3352,7 +3230,6 @@ files = [ name = "pyflakes" version = "2.3.1" description = "passive checker of Python programs" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -3364,7 +3241,6 @@ files = [ name = "pygithub" version = "1.59.0" description = "Use the full Github API v3" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3382,7 +3258,6 @@ requests = ">=2.14.0" name = "pyglet" version = "2.0.9" description = "Cross-platform windowing and multimedia library" -category = "main" optional = false python-versions = "*" files = [ @@ -3394,7 +3269,6 @@ files = [ name = "pygments" version = "2.15.1" description = "Pygments is a syntax highlighting package written in Python." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3409,7 +3283,6 @@ plugins = ["importlib-metadata"] name = "pyjwt" version = "2.8.0" description = "JSON Web Token implementation in Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3430,7 +3303,6 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] name = "pylint" version = "2.17.5" description = "python code static checker" -category = "dev" optional = false python-versions = ">=3.7.2" files = [ @@ -3460,7 +3332,6 @@ testutils = ["gitpython (>3)"] name = "pynacl" version = "1.5.0" description = "Python binding to the Networking and Cryptography (NaCl) library" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -3480,14 +3351,13 @@ files = [ cffi = ">=1.4.1" [package.extras] -docs = ["sphinx (>=1.6.5)", "sphinx_rtd_theme"] +docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] [[package]] name = "pyobjc-core" version = "9.2" description = "Python<->ObjC Interoperability Module" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3505,7 +3375,6 @@ files = [ name = "pyobjc-framework-cocoa" version = "9.2" description = "Wrappers for the Cocoa frameworks on macOS" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3526,7 +3395,6 @@ pyobjc-core = ">=9.2" name = "pyopengl" version = "3.1.6" description = "Standard OpenGL bindings for Python" -category = "main" optional = false python-versions = "*" files = [ @@ -3539,7 +3407,6 @@ files = [ name = "pyparsing" version = "3.0.9" description = "pyparsing module - Classes and methods to define and execute parsing grammars" -category = "dev" optional = false python-versions = ">=3.6.8" files = [ @@ -3554,7 +3421,6 @@ diagrams = ["jinja2", "railroad-diagrams"] name = "pyrr" version = "0.10.3" description = "3D mathematical functions using NumPy" -category = "main" optional = false python-versions = "*" files = [ @@ -3570,7 +3436,6 @@ numpy = "*" name = "pytest" version = "7.4.0" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3593,7 +3458,6 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no name = "pytest-cov" version = "3.0.0" description = "Pytest plugin for measuring coverage." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -3612,7 +3476,6 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale name = "pytest-forked" version = "1.6.0" description = "run tests in isolated forked subprocesses" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3628,7 +3491,6 @@ pytest = ">=3.10" name = "pytest-xdist" version = "2.5.0" description = "pytest xdist plugin for distributed testing and loop-on-failing modes" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -3650,7 +3512,6 @@ testing = ["filelock"] name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -3665,7 +3526,6 @@ six = ">=1.5" name = "python-json-logger" version = "2.0.7" description = "A python library adding a json log formatter" -category = "main" optional = true python-versions = ">=3.6" files = [ @@ -3677,7 +3537,6 @@ files = [ name = "pytz" version = "2023.3" description = "World timezone definitions, modern and historical" -category = "main" optional = false python-versions = "*" files = [ @@ -3689,7 +3548,6 @@ files = [ name = "pywin32" version = "306" description = "Python for Window Extensions" -category = "main" optional = true python-versions = "*" files = [ @@ -3713,7 +3571,6 @@ files = [ name = "pywinpty" version = "2.0.11" description = "Pseudo terminal support for Windows from Python." -category = "main" optional = true python-versions = ">=3.8" files = [ @@ -3728,7 +3585,6 @@ files = [ name = "pyyaml" version = "6.0.1" description = "YAML parser and emitter for Python" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -3750,6 +3606,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -3788,7 +3645,6 @@ files = [ name = "pyzmq" version = "24.0.1" description = "Python bindings for 0MQ" -category = "main" optional = true python-versions = ">=3.6" files = [ @@ -3876,7 +3732,6 @@ py = {version = "*", markers = "implementation_name == \"pypy\""} name = "recommonmark" version = "0.7.1" description = "A docutils-compatibility bridge to CommonMark, enabling you to write CommonMark inside of Docutils & Sphinx projects." -category = "dev" optional = false python-versions = "*" files = [ @@ -3893,7 +3748,6 @@ sphinx = ">=1.3.1" name = "referencing" version = "0.30.0" description = "JSON Referencing + Python" -category = "main" optional = true python-versions = ">=3.8" files = [ @@ -3909,7 +3763,6 @@ rpds-py = ">=0.7.0" name = "requests" version = "2.31.0" description = "Python HTTP for Humans." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3931,7 +3784,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "restructuredtext-lint" version = "1.4.0" description = "reStructuredText linter" -category = "dev" optional = false python-versions = "*" files = [ @@ -3945,7 +3797,6 @@ docutils = ">=0.11,<1.0" name = "rfc3339-validator" version = "0.1.4" description = "A pure python RFC3339 validator" -category = "main" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -3960,7 +3811,6 @@ six = "*" name = "rfc3986-validator" version = "0.1.1" description = "Pure python rfc3986 validator" -category = "main" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -3972,7 +3822,6 @@ files = [ name = "rich" version = "13.5.1" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" -category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -3992,7 +3841,6 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] name = "rpds-py" version = "0.9.2" description = "Python bindings to Rust's persistent data structures (rpds)" -category = "main" optional = true python-versions = ">=3.8" files = [ @@ -4099,7 +3947,6 @@ files = [ name = "scipy" version = "1.10.1" description = "Fundamental algorithms for scientific computing in Python" -category = "main" optional = false python-versions = "<3.12,>=3.8" files = [ @@ -4138,7 +3985,6 @@ test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeo name = "screeninfo" version = "0.8.1" description = "Fetch location and size of physical screens." -category = "main" optional = false python-versions = ">=3.6.2,<4.0.0" files = [ @@ -4154,7 +4000,6 @@ pyobjc-framework-Cocoa = {version = "*", markers = "sys_platform == \"darwin\""} name = "send2trash" version = "1.8.2" description = "Send file to trash natively under Mac OS X, Windows and Linux" -category = "main" optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -4171,7 +4016,6 @@ win32 = ["pywin32"] name = "setuptools" version = "68.0.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -4184,33 +4028,10 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-g testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] -[[package]] -name = "setuptools-scm" -version = "7.1.0" -description = "the blessed package to manage your versions by scm tags" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "setuptools_scm-7.1.0-py3-none-any.whl", hash = "sha256:73988b6d848709e2af142aa48c986ea29592bbcfca5375678064708205253d8e"}, - {file = "setuptools_scm-7.1.0.tar.gz", hash = "sha256:6c508345a771aad7d56ebff0e70628bf2b0ec7573762be9960214730de278f27"}, -] - -[package.dependencies] -packaging = ">=20.0" -setuptools = "*" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} -typing-extensions = "*" - -[package.extras] -test = ["pytest (>=6.2)", "virtualenv (>20)"] -toml = ["setuptools (>=42)"] - [[package]] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -4222,7 +4043,6 @@ files = [ name = "skia-pathops" version = "0.7.4" description = "Python access to operations on paths using the Skia library" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4278,7 +4098,6 @@ testing = ["coverage", "pytest", "pytest-randomly", "pytest-xdist"] name = "smmap" version = "5.0.0" description = "A pure Python implementation of a sliding window memory map manager" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -4290,7 +4109,6 @@ files = [ name = "sniffio" version = "1.3.0" description = "Sniff out which async library your code is running under" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -4302,7 +4120,6 @@ files = [ name = "snowballstemmer" version = "2.2.0" description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." -category = "dev" optional = false python-versions = "*" files = [ @@ -4314,7 +4131,6 @@ files = [ name = "soupsieve" version = "2.4.1" description = "A modern CSS selector implementation for Beautiful Soup." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4326,7 +4142,6 @@ files = [ name = "sphinx" version = "4.5.0" description = "Python documentation generator" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -4362,7 +4177,6 @@ test = ["cython", "html5lib", "pytest", "pytest-cov", "typed-ast"] name = "sphinx-basic-ng" version = "1.0.0b2" description = "A modern skeleton for Sphinx themes." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -4380,7 +4194,6 @@ docs = ["furo", "ipython", "myst-parser", "sphinx-copybutton", "sphinx-inline-ta name = "sphinx-copybutton" version = "0.4.0" description = "Add a copy button to each of your code cells." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -4399,7 +4212,6 @@ rtd = ["ipython", "sphinx", "sphinx-book-theme"] name = "sphinxcontrib-applehelp" version = "1.0.4" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -4415,7 +4227,6 @@ test = ["pytest"] name = "sphinxcontrib-devhelp" version = "1.0.2" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -4431,7 +4242,6 @@ test = ["pytest"] name = "sphinxcontrib-htmlhelp" version = "2.0.1" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -4447,7 +4257,6 @@ test = ["html5lib", "pytest"] name = "sphinxcontrib-jsmath" version = "1.0.1" description = "A sphinx extension which renders display math in HTML via JavaScript" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -4462,7 +4271,6 @@ test = ["flake8", "mypy", "pytest"] name = "sphinxcontrib-programoutput" version = "0.17" description = "Sphinx extension to include program output" -category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" files = [ @@ -4477,7 +4285,6 @@ Sphinx = ">=1.7.0" name = "sphinxcontrib-qthelp" version = "1.0.3" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -4493,7 +4300,6 @@ test = ["pytest"] name = "sphinxcontrib-serializinghtml" version = "1.1.5" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -4509,7 +4315,6 @@ test = ["pytest"] name = "sphinxext-opengraph" version = "0.8.2" description = "Sphinx Extension to enable OGP support" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -4525,7 +4330,6 @@ sphinx = ">=4.0" name = "srt" version = "3.5.3" description = "A tiny library for parsing, modifying, and composing SRT files." -category = "main" optional = false python-versions = ">=2.7" files = [ @@ -4536,7 +4340,6 @@ files = [ name = "stack-data" version = "0.6.2" description = "Extract data from python stack frames and tracebacks for informative displays" -category = "main" optional = false python-versions = "*" files = [ @@ -4556,7 +4359,6 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] name = "svgelements" version = "1.9.5" description = "Svg Elements Parsing" -category = "main" optional = false python-versions = "*" files = [ @@ -4568,7 +4370,6 @@ files = [ name = "terminado" version = "0.17.1" description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library." -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -4589,7 +4390,6 @@ test = ["pre-commit", "pytest (>=7.0)", "pytest-timeout"] name = "tinycss2" version = "1.2.1" description = "A tiny CSS parser" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -4608,7 +4408,6 @@ test = ["flake8", "isort", "pytest"] name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4620,7 +4419,6 @@ files = [ name = "tomlkit" version = "0.12.1" description = "Style preserving TOML library" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -4632,7 +4430,6 @@ files = [ name = "tornado" version = "6.3.2" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." -category = "main" optional = true python-versions = ">= 3.8" files = [ @@ -4653,7 +4450,6 @@ files = [ name = "tqdm" version = "4.65.0" description = "Fast, Extensible Progress Meter" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4674,7 +4470,6 @@ telegram = ["requests"] name = "traitlets" version = "5.9.0" description = "Traitlets Python configuration system" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4690,7 +4485,6 @@ test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"] name = "types-decorator" version = "0.1.7" description = "Typing stubs for decorator" -category = "dev" optional = false python-versions = "*" files = [ @@ -4702,7 +4496,6 @@ files = [ name = "types-docutils" version = "0.20.0.1" description = "Typing stubs for docutils" -category = "dev" optional = false python-versions = "*" files = [ @@ -4714,7 +4507,6 @@ files = [ name = "types-pillow" version = "8.3.11" description = "Typing stubs for Pillow" -category = "dev" optional = false python-versions = "*" files = [ @@ -4726,7 +4518,6 @@ files = [ name = "types-protobuf" version = "3.20.4.6" description = "Typing stubs for protobuf" -category = "dev" optional = false python-versions = "*" files = [ @@ -4738,7 +4529,6 @@ files = [ name = "types-pygments" version = "2.15.0.2" description = "Typing stubs for Pygments" -category = "dev" optional = false python-versions = "*" files = [ @@ -4754,7 +4544,6 @@ types-setuptools = "*" name = "types-requests" version = "2.31.0.2" description = "Typing stubs for requests" -category = "dev" optional = false python-versions = "*" files = [ @@ -4769,7 +4558,6 @@ types-urllib3 = "*" name = "types-setuptools" version = "57.4.18" description = "Typing stubs for setuptools" -category = "dev" optional = false python-versions = "*" files = [ @@ -4781,7 +4569,6 @@ files = [ name = "types-urllib3" version = "1.26.25.14" description = "Typing stubs for urllib3" -category = "dev" optional = false python-versions = "*" files = [ @@ -4793,7 +4580,6 @@ files = [ name = "typing-extensions" version = "4.7.1" description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4805,7 +4591,6 @@ files = [ name = "uri-template" version = "1.3.0" description = "RFC 6570 URI Template Processor" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -4820,7 +4605,6 @@ dev = ["flake8", "flake8-annotations", "flake8-bandit", "flake8-bugbear", "flake name = "urllib3" version = "2.0.4" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4838,7 +4622,6 @@ zstd = ["zstandard (>=0.18.0)"] name = "virtualenv" version = "20.24.2" description = "Virtual Python Environment builder" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -4859,7 +4642,6 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess name = "watchdog" version = "2.3.1" description = "Filesystem events monitoring" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -4900,7 +4682,6 @@ watchmedo = ["PyYAML (>=3.10)"] name = "wcwidth" version = "0.2.6" description = "Measures the displayed width of unicode strings in a terminal" -category = "main" optional = false python-versions = "*" files = [ @@ -4912,7 +4693,6 @@ files = [ name = "webcolors" version = "1.13" description = "A library for working with the color formats defined by HTML and CSS." -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -4928,7 +4708,6 @@ tests = ["pytest", "pytest-cov"] name = "webencodings" version = "0.5.1" description = "Character encoding aliases for legacy web content" -category = "main" optional = true python-versions = "*" files = [ @@ -4940,7 +4719,6 @@ files = [ name = "websocket-client" version = "1.6.1" description = "WebSocket client for Python with low level API options" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -4957,7 +4735,6 @@ test = ["websockets"] name = "wrapt" version = "1.15.0" description = "Module for decorators, wrappers and monkey patching." -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -5042,7 +4819,6 @@ files = [ name = "y-py" version = "0.6.0" description = "Python bindings for the Y-CRDT built from yrs (Rust)" -category = "main" optional = true python-versions = "*" files = [ @@ -5118,7 +4894,6 @@ files = [ name = "ypy-websocket" version = "0.8.4" description = "WebSocket connector for Ypy" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -5138,7 +4913,6 @@ test = ["mypy", "pre-commit", "pytest", "pytest-asyncio", "websockets (>=10.0)"] name = "zipp" version = "3.16.2" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -5157,4 +4931,4 @@ jupyterlab = ["jupyterlab", "notebook"] [metadata] lock-version = "2.0" python-versions = ">=3.8,<3.12" -content-hash = "4599b550efe5d668ee87521ebfb4d39f8329153c119c40cf1dad302498d25e55" +content-hash = "c0d844e1977d8f6e870d0da318527817cce0c59f06ef4bd0378611c361b5142f" From f574a931968374e77720d2529a5ceb0a4ac764c1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 15:10:11 +0000 Subject: [PATCH 4/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- manim/renderer/renderer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/manim/renderer/renderer.py b/manim/renderer/renderer.py index 9038e68cb2..0365f8da9d 100644 --- a/manim/renderer/renderer.py +++ b/manim/renderer/renderer.py @@ -13,6 +13,7 @@ if TYPE_CHECKING: from collections.abc import Callable, Iterable, Sequence + import moderngl as gl from manim.camera.camera import Camera From 90affab69835fedf18db4f44f65a64a8d824dac8 Mon Sep 17 00:00:00 2001 From: JasonGrace2282 Date: Fri, 21 Jun 2024 12:11:01 -0400 Subject: [PATCH 5/7] Implement self.wait --- manim/renderer/opengl_renderer.py | 3 ++ manim/renderer/render_manager.py | 19 ++++++- manim/renderer/renderer.py | 3 ++ manim/scene/scene.py | 85 ++++++++++++++++--------------- 4 files changed, 68 insertions(+), 42 deletions(-) diff --git a/manim/renderer/opengl_renderer.py b/manim/renderer/opengl_renderer.py index 467b977c7a..26899611de 100644 --- a/manim/renderer/opengl_renderer.py +++ b/manim/renderer/opengl_renderer.py @@ -410,6 +410,9 @@ def render_program(self, prog, data, indices=None): def render_image(self, mob): raise NotImplementedError # TODO + def render_previous(self, camera: Camera) -> None: + raise NotImplementedError + def render_vmobject(self, mob: OpenGLVMobject) -> None: # type: ignore self.stencil_buffer_fbo.use() self.stencil_buffer_fbo.clear() diff --git a/manim/renderer/render_manager.py b/manim/renderer/render_manager.py index 8ff9d1b99f..aad2d65c97 100644 --- a/manim/renderer/render_manager.py +++ b/manim/renderer/render_manager.py @@ -1,7 +1,7 @@ from __future__ import annotations import time -from typing import TYPE_CHECKING, Any, Iterable +from typing import TYPE_CHECKING, Any, Callable, Iterable import numpy as np @@ -200,6 +200,23 @@ def _play(self, *animations: AnimationProtocol): self.scene.post_play() + def _wait(self, duration: float, *, stop_condition: Callable[[], bool] | None = None): + self.scene.pre_play() + + update_mobjects = self.scene.should_update_mobjects() # TODO: this method needs to be implemented + condition = stop_condition or (lambda: False) + + last_t = 0 + for t in self._calc_time_progression(duration): + if update_mobjects: + dt, last_t = t - last_t, t + self._update_frame(dt) + if condition(): + break + else: + self.renderer.render_previous(self.camera) + self.scene.post_play() + def _progress_through_animations(self, animations: Iterable[AnimationProtocol]): last_t = 0 run_time = self._calc_runtime(animations) diff --git a/manim/renderer/renderer.py b/manim/renderer/renderer.py index 0365f8da9d..82c4e5a28e 100644 --- a/manim/renderer/renderer.py +++ b/manim/renderer/renderer.py @@ -70,6 +70,9 @@ class RendererProtocol(Protocol): def render(self, camera: Camera, renderables: Iterable[OpenGLMobject]) -> None: ... + def render_previous(self, camera: Camera) -> None: + ... + def pre_render(self, camera) -> object: ... diff --git a/manim/scene/scene.py b/manim/scene/scene.py index 922bdcee0a..bf309b7ce3 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -261,21 +261,28 @@ def _update_mobjects(self, dt: float) -> None: def should_update_mobjects(self) -> bool: """ - This is only called when a single Wait animation is played. + This is called to check if a wait frame should be frozen + + Returns + ------- + bool: does it have to be rerendered or is it static """ - wait_animation = self.animations[0] - if wait_animation.is_static_wait is None: - should_update = ( - self.always_update_mobjects - or self.updaters - or wait_animation.stop_condition is not None - or any( - mob.has_time_based_updater() - for mob in self.get_mobject_family_members() - ) - ) - wait_animation.is_static_wait = not should_update - return not wait_animation.is_static_wait + # always rerender by returning True + # TODO: Apply caching here + return True + # wait_animation = self.animations[0] + # if wait_animation.is_static_wait is None: + # should_update = ( + # self.always_update_mobjects + # or self.updaters + # or wait_animation.stop_condition is not None + # or any( + # mob.has_time_based_updater() + # for mob in self.get_mobject_family_members() + # ) + # ) + # wait_animation.is_static_wait = not should_update + # return not wait_animation.is_static_wait def has_time_based_updaters(self) -> bool: return any( @@ -614,33 +621,29 @@ def wait( note: str | None = None, ignore_presenter_mode: bool = False, ): - self.pre_play() - self.update_mobjects(dt=0) # Any problems with this? - if ( - self.presenter_mode - and not self.skip_animations - and not ignore_presenter_mode - ): - if note: - logger.info(note) - self.hold_loop() - else: - time_progression = self.get_wait_time_progression(duration, stop_condition) - last_t = 0 - for t in time_progression: - dt = t - last_t - last_t = t - self.update_frame(dt) - self.emit_frame() - if stop_condition is not None and stop_condition(): - break - self.refresh_static_mobjects() - self.post_play() - - def hold_loop(self): - while self.hold_on_wait: - self.update_frame(dt=1 / self.camera.fps) - self.hold_on_wait = True + self.manager._wait(duration, stop_condition=stop_condition) + # self.pre_play() + # self.update_mobjects(dt=0) # Any problems with this? + # if ( + # self.presenter_mode + # and not self.skip_animations + # and not ignore_presenter_mode + # ): + # if note: + # logger.info(note) + # self.hold_loop() + # else: + # time_progression = self.get_wait_time_progression(duration, stop_condition) + # last_t = 0 + # for t in time_progression: + # dt = t - last_t + # last_t = t + # self.update_frame(dt) + # self.emit_frame() + # if stop_condition is not None and stop_condition(): + # break + # self.refresh_static_mobjects() + # self.post_play() def wait_until(self, stop_condition: Callable[[], bool], max_time: float = 60): self.wait(max_time, stop_condition=stop_condition) From ca5d4d639a6f2f31e2d3dc6d268a009506fbabdb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 16:14:43 +0000 Subject: [PATCH 6/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- manim/renderer/render_manager.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/manim/renderer/render_manager.py b/manim/renderer/render_manager.py index aad2d65c97..e9d68bfd99 100644 --- a/manim/renderer/render_manager.py +++ b/manim/renderer/render_manager.py @@ -200,10 +200,14 @@ def _play(self, *animations: AnimationProtocol): self.scene.post_play() - def _wait(self, duration: float, *, stop_condition: Callable[[], bool] | None = None): + def _wait( + self, duration: float, *, stop_condition: Callable[[], bool] | None = None + ): self.scene.pre_play() - update_mobjects = self.scene.should_update_mobjects() # TODO: this method needs to be implemented + update_mobjects = ( + self.scene.should_update_mobjects() + ) # TODO: this method needs to be implemented condition = stop_condition or (lambda: False) last_t = 0 From 7a0cb7d5d0827a1dac63eba51db055fccfd58d01 Mon Sep 17 00:00:00 2001 From: Tristan Schulz Date: Fri, 21 Jun 2024 18:59:39 +0200 Subject: [PATCH 7/7] Add note --- manim/renderer/render_manager.py | 1 + manim/scene/scene.py | 1 + 2 files changed, 2 insertions(+) diff --git a/manim/renderer/render_manager.py b/manim/renderer/render_manager.py index e9d68bfd99..31e477b573 100644 --- a/manim/renderer/render_manager.py +++ b/manim/renderer/render_manager.py @@ -138,6 +138,7 @@ def _render_second_pass(self) -> None: In the future, this method could be used for two pass rendering """ + ... def _tear_down(self): self.scene.tear_down() diff --git a/manim/scene/scene.py b/manim/scene/scene.py index bf309b7ce3..01c64823aa 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -612,6 +612,7 @@ def play( for anim in animations: anim.update_rate_info(run_time, rate_func, lag_ratio) + # NOTE: Should be changed at some point with the 2 pass rendering system 21.06.2024 self.manager._play(*animations) def wait(