fix(lib): Manim fixes, bump to >= 0.18, and tests (#447)

* fix(lib): Manim fixes, bump to >= 0.18, and tests

* chore(ci): tests and happy mypy

* chore(deps): fix override

* fix(tests): correct skipping

* fix(ci): coverage

* fix(docs): dead links

* fix(tests): deps fixes

* fix(deps): add missing override

* fix(tests): correctly ignore

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* chore(tests): no filterwarning

* chore(tests): add a check to see if we can install package

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* chore(ci): typo

* fix(ci): typo

* oops

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix(ci): double quote instead of single

* chore(ci): add OSes requirements

* chore(tests): removed `full-gl` extra

* chore(ci): automatically cancel jobs

* fix(docs): typo

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Jérome Eertmans
2024-07-01 18:19:24 +02:00
committed by GitHub
parent e80d1d08eb
commit e2d8c5667f
11 changed files with 603 additions and 284 deletions

View File

@ -7,7 +7,52 @@ on:
name: Tests name: Tests
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs: jobs:
pip-install:
strategy:
fail-fast: false
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
pyversion: ['3.9', '3.10', '3.11', '3.12']
extras: [pyside6-full, manimgl]
exclude:
- pyversion: '3.12'
extras: manimgl
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.pyversion }}
cache: pip
- name: Install manim dependencies on MacOS
if: matrix.os == 'macos-latest'
run: brew install ffmpeg py3cairo pango pkg-config scipy
- name: Install manim dependencies on Ubuntu
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install build-essential python3-dev libcairo2-dev libpango1.0-dev ffmpeg freeglut3-dev xvfb
nohup Xvfb $DISPLAY &
- name: Install Windows dependencies
if: matrix.os == 'windows-latest'
run: choco install ffmpeg
- name: Install package
shell: bash
env:
extras: ${{ matrix.extras }}
run: pip install ".[$extras]"
pytest: pytest:
strategy: strategy:
fail-fast: false fail-fast: false
@ -74,15 +119,9 @@ jobs:
- name: Run pytest - name: Run pytest
shell: bash shell: bash
if: matrix.os != 'ubuntu-latest' || matrix.pyversion != '3.11'
run: rye run pytest run: rye run pytest
- name: Run pytest and coverage
if: matrix.os == 'ubuntu-latest' && matrix.pyversion == '3.11'
run: rye run pytest --cov-report xml --cov=manim_slides tests/
- name: Upload to codecov.io - name: Upload to codecov.io
if: matrix.os == 'ubuntu-latest' && matrix.pyversion == '3.11'
uses: codecov/codecov-action@v4 uses: codecov/codecov-action@v4
env: env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

1
.gitignore vendored
View File

@ -45,6 +45,7 @@ paper/paper.pdf
paper/media/ paper/media/
# Others # Others
.coverage
coverage.xml coverage.xml
rendering_times.csv rendering_times.csv

View File

@ -15,4 +15,7 @@ sphinx:
fail_on_warning: true fail_on_warning: true
python: python:
install: install:
- requirements: requirements-dev.lock - method: pip
path: .
extra_requirements:
- docs

View File

@ -19,6 +19,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[samuelcolvin/rtoml#74](https://github.com/samuelcolvin/rtoml/issues/74) [samuelcolvin/rtoml#74](https://github.com/samuelcolvin/rtoml/issues/74)
is solved. is solved.
[#432](https://github.com/jeertmans/manim-slides/pull/432) [#432](https://github.com/jeertmans/manim-slides/pull/432)
- Removed an old validation check that prevented setting `loop=True` with
`auto_next=True` on `next_slide()`
[#445](https://github.com/jeertmans/manim-slides/pull/445)
- Improved (and fixed) tests for Manim(GL), bumped minimal ManimCE version,
improved coverage, and override dependency conflicts.
[#447](https://github.com/jeertmans/manim-slides/pull/447)
(unreleased-fixed)= (unreleased-fixed)=
### Fixed ### Fixed
@ -28,12 +34,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed whitespace issue in default RevealJS template. - Fixed whitespace issue in default RevealJS template.
[#442](https://github.com/jeertmans/manim-slides/pull/442) [#442](https://github.com/jeertmans/manim-slides/pull/442)
(unreleased-chore)= (unreleased-removed)=
### Chore ### Removed
- Removed an old validation check that prevented setting `loop=True` with - Removed `full-gl` extra, because it does not make sense to ship both
`auto_next=True` on `next_slide()` `manimgl` and `manim` together.
[#445](https://github.com/jeertmans/manim-slides/pull/445) [#447](https://github.com/jeertmans/manim-slides/pull/447)
(v5.1.7)= (v5.1.7)=
## [v5.1.7](https://github.com/jeertmans/manim-slides/compare/v5.1.6...v5.1.7) ## [v5.1.7](https://github.com/jeertmans/manim-slides/compare/v5.1.6...v5.1.7)

View File

@ -23,10 +23,10 @@ using Manim Slides presentations.
Daniel publishes his presentations on *Cosmology, String Theory and related* Daniel publishes his presentations on *Cosmology, String Theory and related*
topics on his topics on his
[personal website](https://panopepino.github.io/web_page/main_page/slides.html). [personal website](https://panopepino.github.io/Web_Page/main_page/slides.html).
For example, below are the slides of a seminar he gave titled For example, below are the slides of a seminar he gave titled
[Our Universe on a (Dark) Bubble](https://panopepino.github.io/web_page/main_page/presentations/2023_11_long/LS.html). [Our Universe on a (Dark) Bubble](https://panopepino.github.io/Web_Page/main_page/presentations/2023_11_long/LS.html).
<div style="position:relative;padding-bottom:56.25%;"> <div style="position:relative;padding-bottom:56.25%;">
<iframe <iframe

View File

@ -108,8 +108,6 @@ using optional dependencies:
- `full`, to include `magic`, `manim`, and - `full`, to include `magic`, `manim`, and
`sphinx-directive` extras (see below); `sphinx-directive` extras (see below);
- `full-gl`, to include `magic`, `manimgl`, and
`sphinx-directive` extras (see below);
- `magic`, to include a Jupyter magic to render - `magic`, to include a Jupyter magic to render
animations inside notebooks. This automatically installs `manim`, animations inside notebooks. This automatically installs `manim`,
and does not work with ManimGL; and does not work with ManimGL;

View File

@ -2,6 +2,8 @@ from pathlib import Path
from typing import Any, Optional from typing import Any, Optional
from manim import Scene, ThreeDScene, config from manim import Scene, ThreeDScene, config
from manim.renderer.opengl_renderer import OpenGLRenderer
from manim.utils.color import rgba_to_color
from ..config import BaseSlideConfig from ..config import BaseSlideConfig
from .base import BaseSlide from .base import BaseSlide
@ -13,25 +15,40 @@ class Slide(BaseSlide, Scene): # type: ignore[misc]
for slides rendering. for slides rendering.
""" """
@property
def _frame_shape(self) -> tuple[float, float]:
if isinstance(self.renderer, OpenGLRenderer):
return self.renderer.camera.frame_shape # type: ignore
else:
return (
self.renderer.camera.frame_height,
self.renderer.camera.frame_width,
)
@property @property
def _frame_height(self) -> float: def _frame_height(self) -> float:
return config["frame_height"] # type: ignore return self._frame_shape[0]
@property @property
def _frame_width(self) -> float: def _frame_width(self) -> float:
return config["frame_width"] # type: ignore return self._frame_shape[1]
@property @property
def _background_color(self) -> str: def _background_color(self) -> str:
color = self.camera.background_color if isinstance(self.renderer, OpenGLRenderer):
if hex_color := getattr(color, "hex", None): return rgba_to_color(self.renderer.background_color).to_hex() # type: ignore
return hex_color # type: ignore else:
else: # manim>=0.18, see https://github.com/ManimCommunity/manim/pull/3020 return self.renderer.camera.background_color.to_hex() # type: ignore
return color.to_hex() # type: ignore
@property @property
def _resolution(self) -> tuple[int, int]: def _resolution(self) -> tuple[int, int]:
return config["pixel_width"], config["pixel_height"] if isinstance(self.renderer, OpenGLRenderer):
return self.renderer.get_pixel_shape() # type: ignore
else:
return (
self.renderer.camera.pixel_width,
self.renderer.camera.pixel_height,
)
@property @property
def _partial_movie_files(self) -> list[Path]: def _partial_movie_files(self) -> list[Path]:

View File

@ -42,20 +42,35 @@ name = "manim-slides"
requires-python = ">=3.9" requires-python = ">=3.9"
[project.optional-dependencies] [project.optional-dependencies]
docs = [
"manim-slides[magic,manim,pyqt6,sphinx-directive]",
"furo>=2023.5.20",
"ipykernel>=6.25.1",
"myst-parser>=2.0.0",
"nbsphinx>=0.9.2",
"pandoc>=2.3",
"sphinx>=7.0.1",
"sphinx-click>=4.4.0",
"sphinx-copybutton>=0.5.1",
"sphinxext-opengraph>=0.7.5",
]
full = [ full = [
"manim-slides[magic,manim,sphinx-directive]", "manim-slides[magic,manim,sphinx-directive]",
] ]
full-gl = [
"manim-slides[magic,manimgl,sphinx-directive]",
]
magic = ["manim-slides[manim]", "ipython>=8.12.2"] magic = ["manim-slides[manim]", "ipython>=8.12.2"]
manim = ["manim>=0.17.3"] manim = ["manim>=0.18.0"]
manimgl = ["manimgl>=1.6.1;python_version<'3.12'"] manimgl = ["manimgl>=1.6.1;python_version<'3.12'"]
pyqt6 = ["pyqt6>=6.6.1"] pyqt6 = ["pyqt6>=6.6.1"]
pyqt6-full = ["manim-slides[full,pyqt6]"] pyqt6-full = ["manim-slides[full,pyqt6]"]
pyside6 = ["pyside6>=6.5.1,<6.5.3;python_version<'3.12'"] pyside6 = ["pyside6>=6.5.1,<6.5.3;python_version<'3.12'", "pyside6>=6.6.1;python_version>='3.12'"]
pyside6-full = ["manim-slides[full,pyside6]"] pyside6-full = ["manim-slides[full,pyside6]"]
sphinx-directive = ["docutils>=0.20.1", "manim-slides[manim]"] sphinx-directive = ["docutils>=0.20.1", "manim-slides[manim]"]
tests = [
"pytest>=7.4.0",
"pytest-cov>=4.1.0",
"pytest-env>=0.8.2",
"pytest-qt>=4.2.0",
]
[project.scripts] [project.scripts]
manim-slides = "manim_slides.__main__:cli" manim-slides = "manim_slides.__main__:cli"
@ -161,12 +176,13 @@ python_version = "3.9"
strict = true strict = true
[tool.pytest.ini_options] [tool.pytest.ini_options]
env = [ addopts = [
"QT_QPA_PLATFORM=offscreen", "--cov-report=xml",
"--cov=manim_slides",
] ]
filterwarnings = [ env = [
"error", "QT_API=pyside6",
"ignore::DeprecationWarning", "QT_QPA_PLATFORM=offscreen",
] ]
[tool.ruff] [tool.ruff]
@ -193,27 +209,20 @@ extend-ignore = [
extend-select = ["B", "C90", "D", "I", "N", "RUF", "UP", "T"] extend-select = ["B", "C90", "D", "I", "N", "RUF", "UP", "T"]
isort = {known-first-party = ["manim_slides", "tests"]} isort = {known-first-party = ["manim_slides", "tests"]}
[tool.ruff.lint.per-file-ignores]
"tests/test_slide.py" = ["N801"]
[tool.rye] [tool.rye]
dev-dependencies = [ dev-dependencies = [
"manim-slides[magic,manim,manimgl,pyqt6,sphinx-directive]",
# dev
"bump-my-version>=0.20.3", "bump-my-version>=0.20.3",
"pre-commit>=3.5.0", "pre-commit>=3.5.0",
# docs
"furo>=2023.5.20",
"ipykernel>=6.25.1",
"myst-parser>=2.0.0",
"nbsphinx>=0.9.2",
"pandoc>=2.3",
"sphinx>=7.0.1",
"sphinx-click>=4.4.0",
"sphinx-copybutton>=0.5.1",
"sphinxext-opengraph>=0.7.5",
# tests
"pytest>=7.4.0",
"pytest-cov>=4.1.0",
"pytest-env>=0.8.2",
"pytest-qt>=4.2.0",
"pytest-xdist>=3.3.1",
] ]
managed = true managed = true
[tool.uv]
override-dependencies = [
# Bypass constraints from ManimGL
"manimpango>=0.5.0,<1.0.0",
"numpy<=1.24;python_version < '3.12'",
"numpy>=1.26;python_version >= '3.12'",
]

View File

@ -6,6 +6,7 @@
# features: [] # features: []
# all-features: true # all-features: true
# with-sources: false # with-sources: false
# generate-hashes: false
-e file:. -e file:.
alabaster==0.7.16 alabaster==0.7.16
@ -44,12 +45,10 @@ click==8.1.7
# via rich-click # via rich-click
# via sphinx-click # via sphinx-click
click-default-group==1.2.4 click-default-group==1.2.4
# via manim
# via manim-slides # via manim-slides
cloup==0.13.1 cloup==3.0.5
# via manim # via manim
colour==0.1.5 colour==0.1.5
# via manim
# via manimgl # via manimgl
comm==0.2.2 comm==0.2.2
# via ipykernel # via ipykernel
@ -74,17 +73,16 @@ docutils==0.20.1
# via nbsphinx # via nbsphinx
# via sphinx # via sphinx
# via sphinx-click # via sphinx-click
execnet==2.1.1
# via pytest-xdist
executing==2.0.1 executing==2.0.1
# via stack-data # via stack-data
fastjsonschema==2.19.1 fastjsonschema==2.19.1
# via nbformat # via nbformat
filelock==3.13.4 filelock==3.13.4
# via virtualenv # via virtualenv
fonttools==4.51.0 fonttools==4.53.0
# via matplotlib # via matplotlib
furo==2024.1.29 furo==2024.1.29
# via manim-slides
glcontext==2.5.0 glcontext==2.5.0
# via moderngl # via moderngl
identify==2.5.35 identify==2.5.35
@ -96,6 +94,7 @@ imagesize==1.4.1
iniconfig==2.0.0 iniconfig==2.0.0
# via pytest # via pytest
ipykernel==6.29.4 ipykernel==6.29.4
# via manim-slides
ipython==8.18.1 ipython==8.18.1
# via ipykernel # via ipykernel
# via manim-slides # via manim-slides
@ -131,11 +130,12 @@ kiwisolver==1.4.5
lxml==5.2.1 lxml==5.2.1
# via manim-slides # via manim-slides
# via python-pptx # via python-pptx
manim==0.17.3 manim==0.18.1
# via manim-slides # via manim-slides
manimgl==1.6.1 manimgl==1.6.1
# via manim-slides # via manim-slides
manimpango==0.4.4 manimpango==0.5.0
# via --override (workspace)
# via manim # via manim
# via manimgl # via manimgl
mapbox-earcut==1.0.1 mapbox-earcut==1.0.1
@ -148,7 +148,7 @@ markdown-it-py==3.0.0
markupsafe==2.1.5 markupsafe==2.1.5
# via jinja2 # via jinja2
# via nbconvert # via nbconvert
matplotlib==3.8.4 matplotlib==3.9.0
# via manimgl # via manimgl
matplotlib-inline==0.1.7 matplotlib-inline==0.1.7
# via ipykernel # via ipykernel
@ -163,7 +163,7 @@ moderngl==5.10.0
# via manim # via manim
# via manimgl # via manimgl
# via moderngl-window # via moderngl-window
moderngl-window==2.4.4 moderngl-window==2.4.6
# via manim # via manim
# via manimgl # via manimgl
mpmath==1.3.0 mpmath==1.3.0
@ -171,6 +171,7 @@ mpmath==1.3.0
multipledispatch==1.0.0 multipledispatch==1.0.0
# via pyrr # via pyrr
myst-parser==2.0.0 myst-parser==2.0.0
# via manim-slides
nbclient==0.10.0 nbclient==0.10.0
# via nbconvert # via nbconvert
nbconvert==7.16.3 nbconvert==7.16.3
@ -180,14 +181,17 @@ nbformat==5.10.4
# via nbconvert # via nbconvert
# via nbsphinx # via nbsphinx
nbsphinx==0.9.3 nbsphinx==0.9.3
# via manim-slides
nest-asyncio==1.6.0 nest-asyncio==1.6.0
# via ipykernel # via ipykernel
networkx==2.8.8 networkx==2.8.8
# via manim # via manim
nodeenv==1.8.0 nodeenv==1.8.0
# via pre-commit # via pre-commit
numpy==1.26.4 numpy==1.24.0
# via --override (workspace)
# via contourpy # via contourpy
# via ipython
# via isosurfaces # via isosurfaces
# via manim # via manim
# via manim-slides # via manim-slides
@ -195,6 +199,7 @@ numpy==1.26.4
# via mapbox-earcut # via mapbox-earcut
# via matplotlib # via matplotlib
# via moderngl-window # via moderngl-window
# via networkx
# via pyrr # via pyrr
# via scipy # via scipy
packaging==24.0 packaging==24.0
@ -205,13 +210,14 @@ packaging==24.0
# via qtpy # via qtpy
# via sphinx # via sphinx
pandoc==2.3 pandoc==2.3
# via manim-slides
pandocfilters==1.5.1 pandocfilters==1.5.1
# via nbconvert # via nbconvert
parso==0.8.4 parso==0.8.4
# via jedi # via jedi
pexpect==4.9.0 pexpect==4.9.0
# via ipython # via ipython
pillow==9.5.0 pillow==10.3.0
# via manim # via manim
# via manim-slides # via manim-slides
# via manimgl # via manimgl
@ -284,14 +290,16 @@ pyside6-essentials==6.5.2
# via pyside6 # via pyside6
# via pyside6-addons # via pyside6-addons
pytest==8.1.1 pytest==8.1.1
# via manim-slides
# via pytest-cov # via pytest-cov
# via pytest-env # via pytest-env
# via pytest-qt # via pytest-qt
# via pytest-xdist
pytest-cov==5.0.0 pytest-cov==5.0.0
# via manim-slides
pytest-env==1.1.3 pytest-env==1.1.3
# via manim-slides
pytest-qt==4.4.0 pytest-qt==4.4.0
pytest-xdist==3.5.0 # via manim-slides
python-dateutil==2.9.0.post0 python-dateutil==2.9.0.post0
# via jupyter-client # via jupyter-client
# via matplotlib # via matplotlib
@ -314,7 +322,6 @@ referencing==0.34.0
# via jsonschema # via jsonschema
# via jsonschema-specifications # via jsonschema-specifications
requests==2.31.0 requests==2.31.0
# via manim
# via manim-slides # via manim-slides
# via sphinx # via sphinx
rich==13.7.1 rich==13.7.1
@ -346,7 +353,7 @@ six==1.16.0
# via asttokens # via asttokens
# via bleach # via bleach
# via python-dateutil # via python-dateutil
skia-pathops==0.7.4 skia-pathops==0.8.0.post1
# via manim # via manim
# via manimgl # via manimgl
snowballstemmer==2.2.0 snowballstemmer==2.2.0
@ -355,6 +362,7 @@ soupsieve==2.5
# via beautifulsoup4 # via beautifulsoup4
sphinx==7.3.6 sphinx==7.3.6
# via furo # via furo
# via manim-slides
# via myst-parser # via myst-parser
# via nbsphinx # via nbsphinx
# via sphinx-basic-ng # via sphinx-basic-ng
@ -364,7 +372,9 @@ sphinx==7.3.6
sphinx-basic-ng==1.0.0b2 sphinx-basic-ng==1.0.0b2
# via furo # via furo
sphinx-click==5.1.0 sphinx-click==5.1.0
# via manim-slides
sphinx-copybutton==0.5.2 sphinx-copybutton==0.5.2
# via manim-slides
sphinxcontrib-applehelp==1.0.8 sphinxcontrib-applehelp==1.0.8
# via sphinx # via sphinx
sphinxcontrib-devhelp==1.0.6 sphinxcontrib-devhelp==1.0.6
@ -378,6 +388,7 @@ sphinxcontrib-qthelp==1.0.7
sphinxcontrib-serializinghtml==1.1.10 sphinxcontrib-serializinghtml==1.1.10
# via sphinx # via sphinx
sphinxext-opengraph==0.9.1 sphinxext-opengraph==0.9.1
# via manim-slides
srt==3.5.3 srt==3.5.3
# via manim # via manim
stack-data==0.6.3 stack-data==0.6.3
@ -385,7 +396,7 @@ stack-data==0.6.3
svgelements==1.9.6 svgelements==1.9.6
# via manim # via manim
# via manimgl # via manimgl
sympy==1.12 sympy==1.12.1
# via manimgl # via manimgl
tinycss2==1.2.1 tinycss2==1.2.1
# via nbconvert # via nbconvert
@ -410,12 +421,13 @@ traitlets==5.14.2
# via nbformat # via nbformat
# via nbsphinx # via nbsphinx
typing-extensions==4.11.0 typing-extensions==4.11.0
# via manim
# via pydantic # via pydantic
# via pydantic-core # via pydantic-core
# via rich-click # via rich-click
urllib3==2.2.1 urllib3==2.2.1
# via requests # via requests
validators==0.28.0 validators==0.28.3
# via manimgl # via manimgl
virtualenv==20.25.3 virtualenv==20.25.3
# via pre-commit # via pre-commit

View File

@ -6,14 +6,27 @@
# features: [] # features: []
# all-features: true # all-features: true
# with-sources: false # with-sources: false
# generate-hashes: false
-e file:. -e file:.
alabaster==0.7.16
# via sphinx
annotated-types==0.6.0 annotated-types==0.6.0
# via pydantic # via pydantic
asttokens==2.4.1 asttokens==2.4.1
# via stack-data # via stack-data
attrs==23.2.0
# via jsonschema
# via referencing
av==12.0.0 av==12.0.0
# via manim-slides # via manim-slides
babel==2.15.0
# via sphinx
beautifulsoup4==4.12.3
# via furo
# via nbconvert
bleach==6.1.0
# via nbconvert
certifi==2024.2.2 certifi==2024.2.2
# via requests # via requests
charset-normalizer==3.3.2 charset-normalizer==3.3.2
@ -23,32 +36,54 @@ click==8.1.7
# via cloup # via cloup
# via manim # via manim
# via manim-slides # via manim-slides
# via sphinx-click
click-default-group==1.2.4 click-default-group==1.2.4
# via manim
# via manim-slides # via manim-slides
cloup==0.13.1 cloup==3.0.5
# via manim # via manim
colour==0.1.5 colour==0.1.5
# via manim
# via manimgl # via manimgl
comm==0.2.2
# via ipykernel
contourpy==1.2.1 contourpy==1.2.1
# via matplotlib # via matplotlib
coverage==7.5.4
# via pytest-cov
cycler==0.12.1 cycler==0.12.1
# via matplotlib # via matplotlib
debugpy==1.8.2
# via ipykernel
decorator==5.1.1 decorator==5.1.1
# via ipython # via ipython
# via manim # via manim
defusedxml==0.7.1
# via nbconvert
docutils==0.20.1 docutils==0.20.1
# via manim-slides # via manim-slides
# via myst-parser
# via nbsphinx
# via sphinx
# via sphinx-click
executing==2.0.1 executing==2.0.1
# via stack-data # via stack-data
fonttools==4.51.0 fastjsonschema==2.20.0
# via nbformat
fonttools==4.53.0
# via matplotlib # via matplotlib
furo==2024.5.6
# via manim-slides
glcontext==2.5.0 glcontext==2.5.0
# via moderngl # via moderngl
idna==3.7 idna==3.7
# via requests # via requests
imagesize==1.4.1
# via sphinx
iniconfig==2.0.0
# via pytest
ipykernel==6.29.4
# via manim-slides
ipython==8.18.1 ipython==8.18.1
# via ipykernel
# via manim-slides # via manim-slides
# via manimgl # via manimgl
isosurfaces==0.1.0 isosurfaces==0.1.0
@ -58,46 +93,90 @@ jedi==0.19.1
# via ipython # via ipython
jinja2==3.1.3 jinja2==3.1.3
# via manim-slides # via manim-slides
# via myst-parser
# via nbconvert
# via nbsphinx
# via sphinx
jsonschema==4.22.0
# via nbformat
jsonschema-specifications==2023.12.1
# via jsonschema
jupyter-client==8.6.2
# via ipykernel
# via nbclient
jupyter-core==5.7.2
# via ipykernel
# via jupyter-client
# via nbclient
# via nbconvert
# via nbformat
jupyterlab-pygments==0.3.0
# via nbconvert
kiwisolver==1.4.5 kiwisolver==1.4.5
# via matplotlib # via matplotlib
lxml==5.2.1 lxml==5.2.1
# via manim-slides # via manim-slides
# via python-pptx # via python-pptx
manim==0.17.3 manim==0.18.1
# via manim-slides # via manim-slides
manimgl==1.6.1 manimgl==1.6.1
# via manim-slides # via manim-slides
manimpango==0.4.4 manimpango==0.5.0
# via --override (workspace)
# via manim # via manim
# via manimgl # via manimgl
mapbox-earcut==1.0.1 mapbox-earcut==1.0.1
# via manim # via manim
# via manimgl # via manimgl
markdown-it-py==3.0.0 markdown-it-py==3.0.0
# via mdit-py-plugins
# via myst-parser
# via rich # via rich
markupsafe==2.1.5 markupsafe==2.1.5
# via jinja2 # via jinja2
matplotlib==3.8.4 # via nbconvert
matplotlib==3.9.0
# via manimgl # via manimgl
matplotlib-inline==0.1.7 matplotlib-inline==0.1.7
# via ipykernel
# via ipython # via ipython
mdit-py-plugins==0.4.1
# via myst-parser
mdurl==0.1.2 mdurl==0.1.2
# via markdown-it-py # via markdown-it-py
mistune==3.0.2
# via nbconvert
moderngl==5.10.0 moderngl==5.10.0
# via manim # via manim
# via manimgl # via manimgl
# via moderngl-window # via moderngl-window
moderngl-window==2.4.4 moderngl-window==2.4.6
# via manim # via manim
# via manimgl # via manimgl
mpmath==1.3.0 mpmath==1.3.0
# via sympy # via sympy
multipledispatch==1.0.0 multipledispatch==1.0.0
# via pyrr # via pyrr
myst-parser==3.0.1
# via manim-slides
nbclient==0.10.0
# via nbconvert
nbconvert==7.16.4
# via nbsphinx
nbformat==5.10.4
# via nbclient
# via nbconvert
# via nbsphinx
nbsphinx==0.9.4
# via manim-slides
nest-asyncio==1.6.0
# via ipykernel
networkx==2.8.8 networkx==2.8.8
# via manim # via manim
numpy==1.26.4 numpy==1.24.0
# via --override (workspace)
# via contourpy # via contourpy
# via ipython
# via isosurfaces # via isosurfaces
# via manim # via manim
# via manim-slides # via manim-slides
@ -105,24 +184,44 @@ numpy==1.26.4
# via mapbox-earcut # via mapbox-earcut
# via matplotlib # via matplotlib
# via moderngl-window # via moderngl-window
# via networkx
# via pyrr # via pyrr
# via scipy # via scipy
packaging==24.0 packaging==24.0
# via ipykernel
# via matplotlib # via matplotlib
# via nbconvert
# via pytest
# via qtpy # via qtpy
# via sphinx
pandoc==2.3
# via manim-slides
pandocfilters==1.5.1
# via nbconvert
parso==0.8.4 parso==0.8.4
# via jedi # via jedi
pexpect==4.9.0 pexpect==4.9.0
# via ipython # via ipython
pillow==9.5.0 pillow==10.3.0
# via manim # via manim
# via manim-slides # via manim-slides
# via manimgl # via manimgl
# via matplotlib # via matplotlib
# via moderngl-window # via moderngl-window
# via python-pptx # via python-pptx
platformdirs==4.2.2
# via jupyter-core
pluggy==1.5.0
# via pytest
# via pytest-qt
plumbum==1.8.3
# via pandoc
ply==3.11
# via pandoc
prompt-toolkit==3.0.43 prompt-toolkit==3.0.43
# via ipython # via ipython
psutil==6.0.0
# via ipykernel
ptyprocess==0.7.0 ptyprocess==0.7.0
# via pexpect # via pexpect
pure-eval==0.2.2 pure-eval==0.2.2
@ -142,10 +241,13 @@ pydub==0.25.1
pyglet==2.0.15 pyglet==2.0.15
# via moderngl-window # via moderngl-window
pygments==2.17.2 pygments==2.17.2
# via furo
# via ipython # via ipython
# via manim # via manim
# via manimgl # via manimgl
# via nbconvert
# via rich # via rich
# via sphinx
pyopengl==3.1.7 pyopengl==3.1.7
# via manimgl # via manimgl
pyparsing==3.1.2 pyparsing==3.1.2
@ -165,21 +267,43 @@ pyside6-addons==6.5.2
pyside6-essentials==6.5.2 pyside6-essentials==6.5.2
# via pyside6 # via pyside6
# via pyside6-addons # via pyside6-addons
pytest==8.2.2
# via manim-slides
# via pytest-cov
# via pytest-env
# via pytest-qt
pytest-cov==5.0.0
# via manim-slides
pytest-env==1.1.3
# via manim-slides
pytest-qt==4.4.0
# via manim-slides
python-dateutil==2.9.0.post0 python-dateutil==2.9.0.post0
# via jupyter-client
# via matplotlib # via matplotlib
python-pptx==0.6.23 python-pptx==0.6.23
# via manim-slides # via manim-slides
pyyaml==6.0.1 pyyaml==6.0.1
# via manimgl # via manimgl
# via myst-parser
pyzmq==26.0.3
# via ipykernel
# via jupyter-client
qtpy==2.4.1 qtpy==2.4.1
# via manim-slides # via manim-slides
referencing==0.35.1
# via jsonschema
# via jsonschema-specifications
requests==2.31.0 requests==2.31.0
# via manim
# via manim-slides # via manim-slides
# via sphinx
rich==13.7.1 rich==13.7.1
# via manim # via manim
# via manim-slides # via manim-slides
# via manimgl # via manimgl
rpds-py==0.18.1
# via jsonschema
# via referencing
rtoml==0.10.0 rtoml==0.10.0
# via manim-slides # via manim-slides
scipy==1.13.0 scipy==1.13.0
@ -194,10 +318,44 @@ shiboken6==6.5.2
# via pyside6-essentials # via pyside6-essentials
six==1.16.0 six==1.16.0
# via asttokens # via asttokens
# via bleach
# via python-dateutil # via python-dateutil
skia-pathops==0.7.4 skia-pathops==0.8.0.post1
# via manim # via manim
# via manimgl # via manimgl
snowballstemmer==2.2.0
# via sphinx
soupsieve==2.5
# via beautifulsoup4
sphinx==7.3.7
# via furo
# via manim-slides
# via myst-parser
# via nbsphinx
# via sphinx-basic-ng
# via sphinx-click
# via sphinx-copybutton
# via sphinxext-opengraph
sphinx-basic-ng==1.0.0b2
# via furo
sphinx-click==6.0.0
# via manim-slides
sphinx-copybutton==0.5.2
# via manim-slides
sphinxcontrib-applehelp==1.0.8
# via sphinx
sphinxcontrib-devhelp==1.0.6
# via sphinx
sphinxcontrib-htmlhelp==2.0.5
# via sphinx
sphinxcontrib-jsmath==1.0.1
# via sphinx
sphinxcontrib-qthelp==1.0.7
# via sphinx
sphinxcontrib-serializinghtml==1.1.10
# via sphinx
sphinxext-opengraph==0.9.1
# via manim-slides
srt==3.5.3 srt==3.5.3
# via manim # via manim
stack-data==0.6.3 stack-data==0.6.3
@ -205,25 +363,42 @@ stack-data==0.6.3
svgelements==1.9.6 svgelements==1.9.6
# via manim # via manim
# via manimgl # via manimgl
sympy==1.12 sympy==1.12.1
# via manimgl # via manimgl
tinycss2==1.3.0
# via nbconvert
tornado==6.4.1
# via ipykernel
# via jupyter-client
tqdm==4.66.2 tqdm==4.66.2
# via manim # via manim
# via manim-slides # via manim-slides
# via manimgl # via manimgl
traitlets==5.14.2 traitlets==5.14.2
# via comm
# via ipykernel
# via ipython # via ipython
# via jupyter-client
# via jupyter-core
# via matplotlib-inline # via matplotlib-inline
# via nbclient
# via nbconvert
# via nbformat
# via nbsphinx
typing-extensions==4.11.0 typing-extensions==4.11.0
# via manim
# via pydantic # via pydantic
# via pydantic-core # via pydantic-core
urllib3==2.2.1 urllib3==2.2.1
# via requests # via requests
validators==0.28.0 validators==0.28.3
# via manimgl # via manimgl
watchdog==2.3.1 watchdog==2.3.1
# via manim # via manim
wcwidth==0.2.13 wcwidth==0.2.13
# via prompt-toolkit # via prompt-toolkit
webencodings==0.5.1
# via bleach
# via tinycss2
xlsxwriter==3.2.0 xlsxwriter==3.2.0
# via python-pptx # via python-pptx

View File

@ -2,13 +2,11 @@ import random
import shutil import shutil
import sys import sys
from pathlib import Path from pathlib import Path
from typing import Any, Union
import manim
import numpy as np
import pytest import pytest
from click.testing import CliRunner from click.testing import CliRunner
from manim import ( from manim import (
BLACK,
BLUE, BLUE,
DOWN, DOWN,
LEFT, LEFT,
@ -21,12 +19,30 @@ from manim import (
GrowFromCenter, GrowFromCenter,
Text, Text,
) )
from packaging import version from manim.renderer.opengl_renderer import OpenGLRenderer
from manim_slides.config import PresentationConfig from manim_slides.config import PresentationConfig
from manim_slides.defaults import FOLDER_PATH from manim_slides.defaults import FOLDER_PATH
from manim_slides.render import render from manim_slides.render import render
from manim_slides.slide.manim import Slide from manim_slides.slide.manim import Slide as CESlide
class CEGLSlide(CESlide):
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, renderer=OpenGLRenderer(), **kwargs)
if sys.version_info >= (3, 12):
class _GLSlide:
pass
GLSlide = pytest.param(_GLSlide, marks=pytest.mark.skip())
else:
from manim_slides.slide.manimlib import Slide as GLSlide
SlideType = Union[type[CESlide], type[GLSlide], type[CEGLSlide]]
Slide = Union[CESlide, GLSlide, CEGLSlide]
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -36,8 +52,7 @@ from manim_slides.slide.manim import Slide
pytest.param( pytest.param(
"--GL", "--GL",
marks=pytest.mark.skipif( marks=pytest.mark.skipif(
version.parse(np.__version__) >= version.parse("1.25") sys.version_info >= (3, 12),
or sys.version_info >= (3, 12),
reason="ManimGL requires numpy<1.25, which is outdated and Python < 3.12", reason="ManimGL requires numpy<1.25, which is outdated and Python < 3.12",
), ),
), ),
@ -82,27 +97,38 @@ def test_render_basic_slide(
assert local_presentation_config.resolution == presentation_config.resolution assert local_presentation_config.resolution == presentation_config.resolution
def assert_constructs(cls: type) -> type: def init_slide(cls: SlideType) -> Slide:
class Wrapper: if issubclass(cls, CESlide):
@classmethod return cls()
def test_construct(_) -> None: # noqa: N804 elif issubclass(cls, GLSlide):
cls().construct() from manimlib.config import get_configuration, parse_cli
from manimlib.extract_scene import get_scene_config
return Wrapper args = parse_cli()
config = get_configuration(args)
scene_config = get_scene_config(config)
return cls(**scene_config)
raise ValueError(f"Unsupported class {cls}")
def assert_renders(cls: type) -> type: parametrize_base_cls = pytest.mark.parametrize(
class Wrapper: "base_cls", (CESlide, GLSlide, CEGLSlide), ids=("CE", "GL", "CE(GL)")
@classmethod )
def test_render(_) -> None: # noqa: N804
cls().render()
return Wrapper
def assert_constructs(cls: SlideType) -> None:
init_slide(cls).construct()
def assert_renders(cls: SlideType) -> None:
init_slide(cls).render()
class TestSlide: class TestSlide:
def test_default_properties(self) -> None:
@assert_constructs @assert_constructs
class TestDefaultProperties(Slide): class _(CESlide):
def construct(self) -> None: def construct(self) -> None:
assert self._output_folder == FOLDER_PATH assert self._output_folder == FOLDER_PATH
assert len(self._slides) == 0 assert len(self._slides) == 0
@ -111,19 +137,39 @@ class TestSlide:
assert len(self._canvas) == 0 assert len(self._canvas) == 0
assert self._wait_time_between_slides == 0.0 assert self._wait_time_between_slides == 0.0
@pytest.mark.skipif( @parametrize_base_cls
version.parse(manim.__version__) < version.parse("0.18"), def test_frame_height(self, base_cls: SlideType) -> None:
reason="Manim change how color are represented in 0.18",
)
@assert_constructs @assert_constructs
class TestBackgroundColor(Slide): class _(base_cls): # type: ignore
def construct(self) -> None: def construct(self) -> None:
assert self._background_color == BLACK.to_hex() # DEFAULT assert self._frame_height > 0 and isinstance(self._frame_height, float)
self.camera.background_color = BLUE
assert self._background_color == BLUE.to_hex()
@parametrize_base_cls
def test_frame_width(self, base_cls: SlideType) -> None:
@assert_constructs
class _(base_cls): # type: ignore
def construct(self) -> None:
assert self._frame_width > 0 and isinstance(self._frame_width, float)
@parametrize_base_cls
def test_resolution(self, base_cls: SlideType) -> None:
@assert_constructs
class _(base_cls): # type: ignore
def construct(self) -> None:
pw, ph = self._resolution
assert isinstance(pw, int) and pw > 0
assert isinstance(ph, int) and ph > 0
@parametrize_base_cls
def test_backround_color(self, base_cls: SlideType) -> None:
@assert_constructs
class _(base_cls): # type: ignore
def construct(self) -> None:
assert self._background_color in ["#000000", "#000"] # DEFAULT
def test_multiple_animations_in_last_slide(self) -> None:
@assert_renders @assert_renders
class TestMultipleAnimationsInLastSlide(Slide): class _(CESlide):
"""Check against solution for issue #161.""" """Check against solution for issue #161."""
def construct(self) -> None: def construct(self) -> None:
@ -139,8 +185,9 @@ class TestSlide:
self.play(dot.animate.move_to(LEFT)) self.play(dot.animate.move_to(LEFT))
self.play(dot.animate.move_to(DOWN)) self.play(dot.animate.move_to(DOWN))
def test_file_too_long(self) -> None:
@assert_renders @assert_renders
class TestFileTooLong(Slide): class _(CESlide):
"""Check against solution for issue #123.""" """Check against solution for issue #123."""
def construct(self) -> None: def construct(self) -> None:
@ -155,8 +202,9 @@ class TestSlide:
self.play(dot.animate.move_to(direction), run_time=0.1) self.play(dot.animate.move_to(direction), run_time=0.1)
self.play(dot.animate.move_to(ORIGIN), run_time=0.1) self.play(dot.animate.move_to(ORIGIN), run_time=0.1)
def test_loop(self) -> None:
@assert_constructs @assert_constructs
class TestLoop(Slide): class _(CESlide):
def construct(self) -> None: def construct(self) -> None:
text = Text("Some text") text = Text("Some text")
@ -173,8 +221,9 @@ class TestSlide:
assert not self._base_slide_config.loop assert not self._base_slide_config.loop
def test_auto_next(self) -> None:
@assert_constructs @assert_constructs
class TestAutoNext(Slide): class _(CESlide):
def construct(self) -> None: def construct(self) -> None:
text = Text("Some text") text = Text("Some text")
@ -191,8 +240,9 @@ class TestSlide:
assert not self._base_slide_config.auto_next assert not self._base_slide_config.auto_next
def test_loop_and_auto_next_succeeds(self) -> None:
@assert_constructs @assert_constructs
class TestLoopAndAutoNextSucceeds(Slide): class _(CESlide):
def construct(self) -> None: def construct(self) -> None:
text = Text("Some text") text = Text("Some text")
@ -203,8 +253,9 @@ class TestSlide:
self.next_slide() self.next_slide()
def test_playback_rate(self) -> None:
@assert_constructs @assert_constructs
class TestPlaybackRate(Slide): class _(CESlide):
def construct(self) -> None: def construct(self) -> None:
text = Text("Some text") text = Text("Some text")
@ -217,8 +268,9 @@ class TestSlide:
assert self._base_slide_config.playback_rate == 2.0 assert self._base_slide_config.playback_rate == 2.0
def test_reversed_playback_rate(self) -> None:
@assert_constructs @assert_constructs
class TestReversedPlaybackRate(Slide): class _(CESlide):
def construct(self) -> None: def construct(self) -> None:
text = Text("Some text") text = Text("Some text")
@ -231,8 +283,9 @@ class TestSlide:
assert self._base_slide_config.reversed_playback_rate == 2.0 assert self._base_slide_config.reversed_playback_rate == 2.0
def test_notes(self) -> None:
@assert_constructs @assert_constructs
class TestNotes(Slide): class _(CESlide):
def construct(self) -> None: def construct(self) -> None:
text = Text("Some text") text = Text("Some text")
@ -245,8 +298,9 @@ class TestSlide:
assert self._base_slide_config.notes == "test" assert self._base_slide_config.notes == "test"
def test_wipe(self) -> None:
@assert_constructs @assert_constructs
class TestWipe(Slide): class _(CESlide):
def construct(self) -> None: def construct(self) -> None:
text = Text("Some text") text = Text("Some text")
bye = Text("Bye") bye = Text("Bye")
@ -261,8 +315,9 @@ class TestSlide:
assert text not in self.mobjects assert text not in self.mobjects
assert bye in self.mobjects assert bye in self.mobjects
def test_zoom(self) -> None:
@assert_constructs @assert_constructs
class TestZoom(Slide): class _(CESlide):
def construct(self) -> None: def construct(self) -> None:
text = Text("Some text") text = Text("Some text")
bye = Text("Bye") bye = Text("Bye")
@ -277,8 +332,9 @@ class TestSlide:
assert text not in self.mobjects assert text not in self.mobjects
assert bye in self.mobjects assert bye in self.mobjects
def test_animation_count(self) -> None:
@assert_constructs @assert_constructs
class TestPlay(Slide): class _(CESlide):
def construct(self) -> None: def construct(self) -> None:
assert self._current_animation == 0 assert self._current_animation == 0
circle = Circle(color=BLUE) circle = Circle(color=BLUE)
@ -289,8 +345,9 @@ class TestSlide:
self.play(FadeIn(dot)) self.play(FadeIn(dot))
assert self._current_animation == 2 assert self._current_animation == 2
def test_wait_time_between_slides(self) -> None:
@assert_constructs @assert_constructs
class TestWaitTimeBetweenSlides(Slide): class _(CESlide):
def construct(self) -> None: def construct(self) -> None:
self._wait_time_between_slides = 1.0 self._wait_time_between_slides = 1.0
assert self._current_animation == 0 assert self._current_animation == 0
@ -300,8 +357,9 @@ class TestSlide:
self.next_slide() self.next_slide()
assert self._current_animation == 2 # self.wait = +1 assert self._current_animation == 2 # self.wait = +1
def test_next_slide(self) -> None:
@assert_constructs @assert_constructs
class TestNextSlide(Slide): class _(CESlide):
def construct(self) -> None: def construct(self) -> None:
assert self._current_slide == 1 assert self._current_slide == 1
self.next_slide() self.next_slide()
@ -313,8 +371,9 @@ class TestSlide:
self.next_slide() self.next_slide()
assert self._current_slide == 2 assert self._current_slide == 2
def test_canvas(self) -> None:
@assert_constructs @assert_constructs
class TestCanvas(Slide): class _(CESlide):
def construct(self) -> None: def construct(self) -> None:
text = Text("Some text") text = Text("Some text")
bye = Text("Bye") bye = Text("Bye")