feat(lib): Sphinx directive can now read files (#261)

* feat(lib): Sphinx directive can now read files

You can optionally read a file instead of the Sphinx directive's content

* fix(lib): rst syntax and docs

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Jérome Eertmans
2023-08-29 16:23:54 +02:00
committed by GitHub
parent 9a3a343231
commit bb5b294f40
5 changed files with 57 additions and 32 deletions

View File

@ -56,18 +56,8 @@ jobs:
id: cache-media-restore
uses: actions/cache/restore@v3
with:
path: media
key: ${{ runner.os }}-media
- name: Build animations
run: |
poetry run manim example.py ConvertExample BasicExample ThreeDExample
- name: Convert animations to HTML slides
run: |
poetry run manim-slides convert -v DEBUG ConvertExample docs/source/_static/slides.html -ccontrols=true
poetry run manim-slides convert -v DEBUG BasicExample docs/source/_static/basic_example.html -ccontrols=true
poetry run manim-slides convert -v DEBUG ThreeDExample docs/source/_static/three_d_example.html -ccontrols=true
- name: Show docs/source/_static/ dir content (video only)
run: tree -L 3 docs/source/_static/ -P '*.mp4'
path: docs/media
key: ${{ runner.os }}-docs-media
- name: Clear cache
run: |
gh extension install actions/gh-actions-cache
@ -78,7 +68,7 @@ jobs:
id: cache-media-save
uses: actions/cache/save@v3
with:
path: media
path: docs/media
key: ${{ steps.cache-media-restore.outputs.cache-primary-key }}
- name: Build docs
run: cd docs && poetry run make html

View File

@ -25,6 +25,9 @@ In an effort to better document changes, this CHANGELOG document is now created.
- Added a full screen key binding (defaults to <kbd>F</kbd>) in the
presenter.
[#243](https://github.com/jeertmans/manim-slides/pull/243)
- Added support for including code from a file in Manim Slides
Sphinx directive.
[#261](https://github.com/jeertmans/manim-slides/pull/261)
### Changed

View File

@ -28,11 +28,11 @@ In a [very few steps](./quickstart), you can create slides and present them eith
Slide through the demo below to get a quick glimpse on what you can do with Manim Slides.
<!-- From: https://faq.dailymotion.com/hc/en-us/articles/360022841393-How-to-preserve-the-player-aspect-ratio-on-a-responsive-page -->
<div style="position:relative;padding-bottom:56.25%;"> <iframe style="width:100%;height:100%;position:absolute;left:0px;top:0px;" frameborder="0" width="100%" height="100%" allowfullscreen allow="autoplay" src="_static/slides.html"></iframe></div>
```{eval-rst}
.. manim-slides:: ../../example.py:ConvertExample
:hide_source:
:quality: high
```
```{toctree}
:hidden:

View File

@ -29,9 +29,11 @@ where `-ccontrols=true` indicates that we want to display the blue navigation ar
Basic example from quickstart.
<div style="position:relative;padding-bottom:56.25%;"> <iframe style="width:100%;height:100%;position:absolute;left:0px;top:0px;" frameborder="0" width="100%" height="100%" allowfullscreen allow="autoplay" src="../_static/basic_example.html"></iframe></div>
```{eval-rst}
.. manim-slides: ../../../example.py:BasicExample
:hide_source:
:quality: high
.. literalinclude:: ../../../example.py
:language: python
:linenos:
@ -42,11 +44,13 @@ Basic example from quickstart.
Example using 3D camera. As Manim and ManimGL handle 3D differently, definitions are slightly different.
<div style="position:relative;padding-bottom:56.25%;"> <iframe style="width:100%;height:100%;position:absolute;left:0px;top:0px;" frameborder="0" width="100%" height="100%" allowfullscreen allow="autoplay" src="../_static/three_d_example.html"></iframe></div>
### With Manim
```{eval-rst}
.. manim-slides: ../../../example.py:ThreeDExample
:hide_source:
:quality: high
.. literalinclude:: ../../../example.py
:language: python
:linenos:
@ -120,9 +124,11 @@ directly write the `construct` method in the body of `MovingCameraSlide`.
A more advanced example is `ConvertExample`, which is used as demo slide and tutorial.
<div style="position:relative;padding-bottom:56.25%;"> <iframe style="width:100%;height:100%;position:absolute;left:0px;top:0px;" frameborder="0" width="100%" height="100%" allowfullscreen allow="autoplay" src="../_static/slides.html"></iframe></div>
```{eval-rst}
.. manim-slides: ../../../example.py:ConvertExample
:hide_source:
:quality: high
.. literalinclude:: ../../../example.py
:language: python
:linenos:

View File

@ -70,16 +70,29 @@ render scenes that are defined within doctests, for example::
... def construct(self):
... self.play(Create(dot))
A third application is to render scenes from another specific file::
.. manim-slides:: file.py:FileExample
:hide_source:
:quality: high
.. warning::
The code will be executed with the current working directory
being the same as the one containing the source file. This being said,
you should probably not include examples that rely on external files, since
relative paths risk to be broken.
Options
-------
Options can be passed as follows::
.. manim-slides:: <Class name>
.. manim-slides:: <file>:<Class name>
:<option name>: <value>
The following configuration options are supported by the
directive:
directive::
hide_source
If this flag is present without argument,
@ -110,6 +123,7 @@ import re
import sys
from pathlib import Path
from timeit import timeit
from typing import Tuple
import jinja2
from docutils import nodes
@ -211,7 +225,17 @@ class ManimSlidesDirective(Directive):
global classnamedict
clsname = self.arguments[0]
def split_file_cls(arg: str) -> Tuple[Path, str]:
if ":" in arg:
file, cls = arg.split(":", maxsplit=1)
_, file = self.state.document.settings.env.relfn2path(file)
return Path(file), cls
else:
return None, arg
arguments = [split_file_cls(arg) for arg in self.arguments]
clsname = arguments[0][1]
if clsname not in classnamedict:
classnamedict[clsname] = 1
else:
@ -271,20 +295,24 @@ class ManimSlidesDirective(Directive):
"output_file": output_file,
}
user_code = self.content
if file := arguments[0][0]:
user_code = file.absolute().read_text().splitlines()
else:
user_code = self.content
if user_code[0].startswith(">>> "): # check whether block comes from doctest
user_code = [
line[4:] for line in user_code if line.startswith((">>> ", "... "))
]
code = [
"from manim import *",
*user_code,
f"{clsname}().render()",
]
try:
with tempconfig(example_config):
print(f"Rendering {clsname}...")
run_time = timeit(lambda: exec("\n".join(code), globals()), number=1)
video_dir = config.get_dir("video_dir")
except Exception as e:
@ -306,9 +334,6 @@ class ManimSlidesDirective(Directive):
RevealJS(presentation_configs=presentation_configs, controls="true").convert_to(
destfile
)
# shutil.copyfile(filesrc, destfile)
print("CLASS NAME:", clsname)
rendered_template = jinja2.Template(TEMPLATE).render(
clsname=clsname,
@ -400,6 +425,7 @@ TEMPLATE = r"""
.. raw:: html
<!-- From: https://faq.dailymotion.com/hc/en-us/articles/360022841393-How-to-preserve-the-player-aspect-ratio-on-a-responsive-page -->
<div style="position:relative;padding-bottom:56.25%;">
<iframe