mirror of
https://github.com/jeertmans/manim-slides.git
synced 2025-05-21 12:37:00 +08:00
feat(convert/html): inline CSS and JS with convert --one_file --offline (#505)
* feat: Inline CSS and JS by default with --offline * chore(fmt): auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * chore: Add test * Add one_file parameter * chore(fmt): auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix lint * Fix typo * Fix typo * Fix IPython magic doc * Update manim_slides/convert.py Co-authored-by: Jérome Eertmans <jeertmans@icloud.com> * Add test for one_file=true * chore(fmt): auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update manim_slides/convert.py Co-authored-by: Jérome Eertmans <jeertmans@icloud.com> * Update manim_slides/convert.py Co-authored-by: Jérome Eertmans <jeertmans@icloud.com> * Update docs/source/reference/sharing.md Co-authored-by: Jérome Eertmans <jeertmans@icloud.com> * Update manim_slides/convert.py Co-authored-by: Jérome Eertmans <jeertmans@icloud.com> * chore(fmt): auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add changelog and tests * Fix IPython magic * Update docs/source/faq.md * Update CHANGELOG.md --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Jérome Eertmans <jeertmans@icloud.com>
This commit is contained in:
13
CHANGELOG.md
13
CHANGELOG.md
@ -10,6 +10,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
(unreleased)=
|
(unreleased)=
|
||||||
## [Unreleased](https://github.com/jeertmans/manim-slides/compare/v5.2.0...HEAD)
|
## [Unreleased](https://github.com/jeertmans/manim-slides/compare/v5.2.0...HEAD)
|
||||||
|
|
||||||
|
(unreleased-added)=
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added CSS and JS inline for `manim-slides convert` if `--offline`
|
||||||
|
and `--one-file` (`-cone_file`) are used for HTML output.
|
||||||
|
[@Rapsssito](https://github.com/Rapsssito) [#505](https://github.com/jeertmans/manim-slides/pull/505)
|
||||||
|
|
||||||
|
(unreleased-changed)=
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Deprecate `-cdata_uri` in favor of `-cone_file` for `manim-slides convert`.
|
||||||
|
[@Rapsssito](https://github.com/Rapsssito) [#505](https://github.com/jeertmans/manim-slides/pull/505)
|
||||||
|
|
||||||
(v5.2.0)=
|
(v5.2.0)=
|
||||||
## [v5.2.0](https://github.com/jeertmans/manim-slides/compare/v5.1.10...v5.2.0)
|
## [v5.2.0](https://github.com/jeertmans/manim-slides/compare/v5.1.10...v5.2.0)
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
{%- for presentation_config in presentation_configs -%}
|
{%- for presentation_config in presentation_configs -%}
|
||||||
{% set outer_loop = loop %}
|
{% set outer_loop = loop %}
|
||||||
{%- for slide_config in presentation_config.slides -%}
|
{%- for slide_config in presentation_config.slides -%}
|
||||||
{%- if data_uri -%}
|
{%- if one_file -%}
|
||||||
{% set file = file_to_data_uri(slide_config.file) %}
|
{% set file = file_to_data_uri(slide_config.file) %}
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
{% set file = assets_dir / slide_config.file.name %}
|
{% set file = assets_dir / slide_config.file.name %}
|
||||||
@ -315,7 +315,7 @@
|
|||||||
hideCursorTime: {{ hide_cursor_time }}
|
hideCursorTime: {{ hide_cursor_time }}
|
||||||
});
|
});
|
||||||
|
|
||||||
{% if data_uri %}
|
{% if one_file %}
|
||||||
// Fix found by @t-fritsch on GitHub
|
// Fix found by @t-fritsch on GitHub
|
||||||
// see: https://github.com/hakimel/reveal.js/discussions/3362#discussioncomment-6651475.
|
// see: https://github.com/hakimel/reveal.js/discussions/3362#discussioncomment-6651475.
|
||||||
function fixBase64VideoBackground(event) {
|
function fixBase64VideoBackground(event) {
|
||||||
|
@ -102,7 +102,7 @@ Questions related to `manim-slides convert [SCENES]... output.html`.
|
|||||||
|
|
||||||
### I moved my `.html` file and it stopped working
|
### I moved my `.html` file and it stopped working
|
||||||
|
|
||||||
If you did not specify `-cdata_uri=true` when converting,
|
If you did not specify `--one-file` (or `-cone_file=true`) when converting,
|
||||||
then Manim Slides generated a folder containing all
|
then Manim Slides generated a folder containing all
|
||||||
the video files, in the same folder as the HTML
|
the video files, in the same folder as the HTML
|
||||||
output. As the path to video files is a relative path,
|
output. As the path to video files is a relative path,
|
||||||
|
@ -137,9 +137,10 @@ and it there to preserve the original aspect ratio (16:9).
|
|||||||
|
|
||||||
### Sharing ONE HTML file
|
### Sharing ONE HTML file
|
||||||
|
|
||||||
If you set the `data_uri` option to `true` (with `-cdata_uri=true`),
|
If you set the `--one-file` flag, all animations will be data URI encoded,
|
||||||
all animations will be data URI encoded, making the HTML a self-contained
|
making the HTML a self-contained presentation file that can be shared
|
||||||
presentation file that can be shared on its own.
|
on its own. If you also set the `--offline` flag, the JS and CSS files will
|
||||||
|
be included in the HTML file as well.
|
||||||
|
|
||||||
### Over the internet
|
### Over the internet
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import shutil
|
|||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
import textwrap
|
import textwrap
|
||||||
|
import warnings
|
||||||
import webbrowser
|
import webbrowser
|
||||||
from base64 import b64encode
|
from base64 import b64encode
|
||||||
from collections import deque
|
from collections import deque
|
||||||
@ -298,9 +299,9 @@ class RevealJS(Converter):
|
|||||||
Please check out https://revealjs.com/config/ for more details.
|
Please check out https://revealjs.com/config/ for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Export option: use data-uri
|
# Export option:
|
||||||
data_uri: bool = Field(
|
one_file: bool = Field(
|
||||||
False, description="Store all animations inside the HTML as data URI."
|
False, description="Embed all assets (e.g., animations) inside the HTML."
|
||||||
)
|
)
|
||||||
offline: bool = Field(
|
offline: bool = Field(
|
||||||
False, description="Download remote assets for offline presentation."
|
False, description="Download remote assets for offline presentation."
|
||||||
@ -562,11 +563,10 @@ class RevealJS(Converter):
|
|||||||
)
|
)
|
||||||
full_assets_dir = dirname / assets_dir
|
full_assets_dir = dirname / assets_dir
|
||||||
|
|
||||||
if not self.data_uri or self.offline:
|
if not self.one_file or self.offline:
|
||||||
logger.debug(f"Assets will be saved to: {full_assets_dir}")
|
logger.debug(f"Assets will be saved to: {full_assets_dir}")
|
||||||
full_assets_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
if not self.data_uri:
|
if not self.one_file:
|
||||||
num_presentation_configs = len(self.presentation_configs)
|
num_presentation_configs = len(self.presentation_configs)
|
||||||
|
|
||||||
if num_presentation_configs > 1:
|
if num_presentation_configs > 1:
|
||||||
@ -585,6 +585,7 @@ class RevealJS(Converter):
|
|||||||
def prefix(i: int) -> str:
|
def prefix(i: int) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
full_assets_dir.mkdir(parents=True, exist_ok=True)
|
||||||
for i, presentation_config in enumerate(self.presentation_configs):
|
for i, presentation_config in enumerate(self.presentation_configs):
|
||||||
presentation_config.copy_to(
|
presentation_config.copy_to(
|
||||||
full_assets_dir, include_reversed=False, prefix=prefix(i)
|
full_assets_dir, include_reversed=False, prefix=prefix(i)
|
||||||
@ -611,28 +612,50 @@ class RevealJS(Converter):
|
|||||||
get_duration_ms=get_duration_ms,
|
get_duration_ms=get_duration_ms,
|
||||||
has_notes=has_notes,
|
has_notes=has_notes,
|
||||||
env=os.environ,
|
env=os.environ,
|
||||||
prefix=prefix if not self.data_uri else None,
|
prefix=prefix if not self.one_file else None,
|
||||||
**options,
|
**options,
|
||||||
)
|
)
|
||||||
|
# If not offline, write the content to the file
|
||||||
|
if not self.offline:
|
||||||
|
f.write(content)
|
||||||
|
return
|
||||||
|
|
||||||
if self.offline:
|
# If offline, download remote assets and store them in the assets folder
|
||||||
soup = BeautifulSoup(content, "html.parser")
|
soup = BeautifulSoup(content, "html.parser")
|
||||||
session = requests.Session()
|
session = requests.Session()
|
||||||
|
|
||||||
for tag, inner in [("link", "href"), ("script", "src")]:
|
for tag, inner in [("link", "href"), ("script", "src")]:
|
||||||
for item in soup.find_all(tag):
|
for item in soup.find_all(tag):
|
||||||
if item.has_attr(inner) and (link := item[inner]).startswith(
|
if item.has_attr(inner) and (link := item[inner]).startswith(
|
||||||
"http"
|
"http"
|
||||||
):
|
):
|
||||||
asset_name = link.rsplit("/", 1)[1]
|
asset_name = link.rsplit("/", 1)[1]
|
||||||
asset = session.get(link)
|
asset = session.get(link)
|
||||||
|
if self.one_file:
|
||||||
|
# If it is a CSS file, inline it
|
||||||
|
if tag == "link" and "stylesheet" in item["rel"]:
|
||||||
|
item.decompose()
|
||||||
|
style = soup.new_tag("style")
|
||||||
|
style.string = asset.text
|
||||||
|
soup.head.append(style)
|
||||||
|
# If it is a JS file, inline it
|
||||||
|
elif tag == "script":
|
||||||
|
item.decompose()
|
||||||
|
script = soup.new_tag("script")
|
||||||
|
script.string = asset.text
|
||||||
|
soup.head.append(script)
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"Unable to inline {tag} asset: {link}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
full_assets_dir.mkdir(parents=True, exist_ok=True)
|
||||||
with open(full_assets_dir / asset_name, "wb") as asset_file:
|
with open(full_assets_dir / asset_name, "wb") as asset_file:
|
||||||
asset_file.write(asset.content)
|
asset_file.write(asset.content)
|
||||||
|
|
||||||
item[inner] = str(assets_dir / asset_name)
|
item[inner] = str(assets_dir / asset_name)
|
||||||
|
|
||||||
content = str(soup)
|
content = str(soup)
|
||||||
|
|
||||||
f.write(content)
|
f.write(content)
|
||||||
|
|
||||||
|
|
||||||
@ -919,6 +942,12 @@ def show_template_option(function: Callable[..., Any]) -> Callable[..., Any]:
|
|||||||
help="Use the template given by FILE instead of default one. "
|
help="Use the template given by FILE instead of default one. "
|
||||||
"To echo the default template, use '--show-template'.",
|
"To echo the default template, use '--show-template'.",
|
||||||
)
|
)
|
||||||
|
@click.option(
|
||||||
|
"--one-file",
|
||||||
|
is_flag=True,
|
||||||
|
help="Embed all local assets (e.g., video files) in the output file. "
|
||||||
|
"The is a convenient alias to '-cone_file=true'.",
|
||||||
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--offline",
|
"--offline",
|
||||||
is_flag=True,
|
is_flag=True,
|
||||||
@ -937,6 +966,7 @@ def convert(
|
|||||||
config_options: dict[str, str],
|
config_options: dict[str, str],
|
||||||
template: Optional[Path],
|
template: Optional[Path],
|
||||||
offline: bool,
|
offline: bool,
|
||||||
|
one_file: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Convert SCENE(s) into a given format and writes the result in DEST."""
|
"""Convert SCENE(s) into a given format and writes the result in DEST."""
|
||||||
presentation_configs = get_scenes_presentation_config(scenes, folder)
|
presentation_configs = get_scenes_presentation_config(scenes, folder)
|
||||||
@ -954,6 +984,28 @@ def convert(
|
|||||||
else:
|
else:
|
||||||
cls = Converter.from_string(to)
|
cls = Converter.from_string(to)
|
||||||
|
|
||||||
|
if (
|
||||||
|
one_file
|
||||||
|
and issubclass(cls, (RevealJS, HtmlZip))
|
||||||
|
and "one_file" not in config_options
|
||||||
|
):
|
||||||
|
config_options["one_file"] = "true"
|
||||||
|
|
||||||
|
# Change data_uri to one_file and print a warning if present
|
||||||
|
if "data_uri" in config_options:
|
||||||
|
warnings.warn(
|
||||||
|
"The 'data_uri' configuration option is deprecated and will be "
|
||||||
|
"removed in the next major version. "
|
||||||
|
"Use 'one_file' instead.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
config_options["one_file"] = (
|
||||||
|
config_options["one_file"]
|
||||||
|
if "one_file" in config_options
|
||||||
|
else config_options.pop("data_uri")
|
||||||
|
)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
offline
|
offline
|
||||||
and issubclass(cls, (RevealJS, HtmlZip))
|
and issubclass(cls, (RevealJS, HtmlZip))
|
||||||
|
@ -125,7 +125,7 @@ class ManimSlidesMagic(Magics): # type: ignore
|
|||||||
in a cell and evaluate it. Then, a typical Jupyter notebook cell for Manim Slides
|
in a cell and evaluate it. Then, a typical Jupyter notebook cell for Manim Slides
|
||||||
could look as follows::
|
could look as follows::
|
||||||
|
|
||||||
%%manim_slides -v WARNING --progress_bar None MySlide --manim-slides controls=true data_uri=true
|
%%manim_slides -v WARNING --progress_bar None MySlide --manim-slides controls=true one_file=true
|
||||||
|
|
||||||
class MySlide(Slide):
|
class MySlide(Slide):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
@ -222,17 +222,29 @@ class ManimSlidesMagic(Magics): # type: ignore
|
|||||||
|
|
||||||
kwargs = dict(arg.split("=", 1) for arg in manim_slides_args)
|
kwargs = dict(arg.split("=", 1) for arg in manim_slides_args)
|
||||||
|
|
||||||
if embed: # Embedding implies data-uri
|
# If data_uri is set, raise a warning
|
||||||
kwargs["data_uri"] = "true"
|
if "data_uri" in kwargs:
|
||||||
|
logger.warning(
|
||||||
|
"'data_uri' configuration option is deprecated and will be removed in a future release. "
|
||||||
|
"Please use 'one_file' instead."
|
||||||
|
)
|
||||||
|
kwargs["one_file"] = (
|
||||||
|
kwargs["one_file"]
|
||||||
|
if "one_file" in kwargs
|
||||||
|
else kwargs.pop("data_uri")
|
||||||
|
)
|
||||||
|
|
||||||
|
if embed: # Embedding implies one_file
|
||||||
|
kwargs["one_file"] = "true"
|
||||||
|
|
||||||
# TODO: FIXME
|
# TODO: FIXME
|
||||||
# Seems like files are blocked so date-uri is the only working option...
|
# Seems like files are blocked so one_file is the only working option...
|
||||||
if kwargs.get("data_uri", "false").lower().strip() == "false":
|
if kwargs.get("one_file", "false").lower().strip() == "false":
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"data_uri option is currently automatically enabled, "
|
"one_file option is currently automatically enabled, "
|
||||||
"because using local video files does not seem to work properly."
|
"because using local video files does not seem to work properly."
|
||||||
)
|
)
|
||||||
kwargs["data_uri"] = "true"
|
kwargs["one_file"] = "true"
|
||||||
|
|
||||||
presentation_configs = get_scenes_presentation_config(
|
presentation_configs = get_scenes_presentation_config(
|
||||||
[clsname], Path("./slides")
|
[clsname], Path("./slides")
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
{% for presentation_config in presentation_configs -%}
|
{% for presentation_config in presentation_configs -%}
|
||||||
{% set outer_loop = loop %}
|
{% set outer_loop = loop %}
|
||||||
{%- for slide_config in presentation_config.slides -%}
|
{%- for slide_config in presentation_config.slides -%}
|
||||||
{%- if data_uri -%}
|
{%- if one_file -%}
|
||||||
{% set file = file_to_data_uri(slide_config.file) %}
|
{% set file = file_to_data_uri(slide_config.file) %}
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
{% set file = assets_dir / (prefix(outer_loop.index0) + slide_config.file.name) %}
|
{% set file = assets_dir / (prefix(outer_loop.index0) + slide_config.file.name) %}
|
||||||
@ -320,7 +320,7 @@
|
|||||||
hideCursorTime: {{ hide_cursor_time }}
|
hideCursorTime: {{ hide_cursor_time }}
|
||||||
});
|
});
|
||||||
|
|
||||||
{% if data_uri -%}
|
{% if one_file -%}
|
||||||
// Fix found by @t-fritsch on GitHub
|
// Fix found by @t-fritsch on GitHub
|
||||||
// see: https://github.com/hakimel/reveal.js/discussions/3362#discussioncomment-6651475.
|
// see: https://github.com/hakimel/reveal.js/discussions/3362#discussioncomment-6651475.
|
||||||
function fixBase64VideoBackground(event) {
|
function fixBase64VideoBackground(event) {
|
||||||
|
@ -3,6 +3,8 @@ from enum import EnumMeta
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
import requests
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
from manim_slides.config import PresentationConfig
|
from manim_slides.config import PresentationConfig
|
||||||
from manim_slides.convert import (
|
from manim_slides.convert import (
|
||||||
@ -173,6 +175,101 @@ class TestConverter:
|
|||||||
]:
|
]:
|
||||||
assert (assets_dir / file).exists()
|
assert (assets_dir / file).exists()
|
||||||
|
|
||||||
|
def test_revealjs_data_encode(
|
||||||
|
self,
|
||||||
|
tmp_path: Path,
|
||||||
|
presentation_config: PresentationConfig,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
|
# Mock requests.Session.get to return a fake response (should not be called)
|
||||||
|
class MockResponse:
|
||||||
|
def __init__(self, content: bytes, text: str, status_code: int) -> None:
|
||||||
|
self.content = content
|
||||||
|
self.text = text
|
||||||
|
self.status_code = status_code
|
||||||
|
|
||||||
|
# Apply the monkeypatch
|
||||||
|
monkeypatch.setattr(
|
||||||
|
requests.Session,
|
||||||
|
"get",
|
||||||
|
lambda self, url: MockResponse(
|
||||||
|
b"body { background-color: #9a3241; }",
|
||||||
|
"body { background-color: #9a3241; }",
|
||||||
|
200,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
out_file = tmp_path / "slides.html"
|
||||||
|
RevealJS(
|
||||||
|
presentation_configs=[presentation_config], offline="false", one_file="true"
|
||||||
|
).convert_to(out_file)
|
||||||
|
assert out_file.exists()
|
||||||
|
# Check that assets are not stored
|
||||||
|
assert not (tmp_path / "slides_assets").exists()
|
||||||
|
|
||||||
|
with open(out_file, encoding="utf-8") as file:
|
||||||
|
content = file.read()
|
||||||
|
|
||||||
|
soup = BeautifulSoup(content, "html.parser")
|
||||||
|
|
||||||
|
# Check if video is encoded in base64
|
||||||
|
videos = soup.find_all("section")
|
||||||
|
assert all(
|
||||||
|
"data:video/mp4;base64," in video["data-background-video"]
|
||||||
|
for video in videos
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if CSS is not inlined
|
||||||
|
styles = soup.find_all("style")
|
||||||
|
assert not any("background-color: #9a3241;" in style.string for style in styles)
|
||||||
|
# Check if JS is not inlined
|
||||||
|
scripts = soup.find_all("script")
|
||||||
|
assert not any(
|
||||||
|
"background-color: #9a3241;" in (script.string or "") for script in scripts
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_revealjs_offline_inlining(
|
||||||
|
self,
|
||||||
|
tmp_path: Path,
|
||||||
|
presentation_config: PresentationConfig,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
|
# Mock requests.Session.get to return a fake response
|
||||||
|
class MockResponse:
|
||||||
|
def __init__(self, content: bytes, text: str, status_code: int) -> None:
|
||||||
|
self.content = content
|
||||||
|
self.text = text
|
||||||
|
self.status_code = status_code
|
||||||
|
|
||||||
|
# Apply the monkeypatch
|
||||||
|
monkeypatch.setattr(
|
||||||
|
requests.Session,
|
||||||
|
"get",
|
||||||
|
lambda self, url: MockResponse(
|
||||||
|
b"body { background-color: #9a3241; }",
|
||||||
|
"body { background-color: #9a3241; }",
|
||||||
|
200,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
out_file = tmp_path / "slides.html"
|
||||||
|
RevealJS(
|
||||||
|
presentation_configs=[presentation_config], offline="true", one_file="true"
|
||||||
|
).convert_to(out_file)
|
||||||
|
assert out_file.exists()
|
||||||
|
|
||||||
|
with open(out_file, encoding="utf-8") as file:
|
||||||
|
content = file.read()
|
||||||
|
|
||||||
|
soup = BeautifulSoup(content, "html.parser")
|
||||||
|
|
||||||
|
# Check if CSS is inlined
|
||||||
|
styles = soup.find_all("style")
|
||||||
|
assert any("background-color: #9a3241;" in style.string for style in styles)
|
||||||
|
|
||||||
|
# Check if JS is inlined
|
||||||
|
scripts = soup.find_all("script")
|
||||||
|
assert any("background-color: #9a3241;" in script.string for script in scripts)
|
||||||
|
|
||||||
def test_htmlzip_converter(
|
def test_htmlzip_converter(
|
||||||
self, tmp_path: Path, presentation_config: PresentationConfig
|
self, tmp_path: Path, presentation_config: PresentationConfig
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import warnings
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -64,6 +65,34 @@ def test_convert(slides_folder: Path, extension: str) -> None:
|
|||||||
assert results.exit_code == 0
|
assert results.exit_code == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(("extension",), [("html",)])
|
||||||
|
def test_convert_data_uri_deprecated(slides_folder: Path, extension: str) -> None:
|
||||||
|
runner = CliRunner(mix_stderr=False)
|
||||||
|
|
||||||
|
with runner.isolated_filesystem():
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
|
warnings.simplefilter("always")
|
||||||
|
results = runner.invoke(
|
||||||
|
cli,
|
||||||
|
[
|
||||||
|
"convert",
|
||||||
|
"BasicSlide",
|
||||||
|
f"basic_example.{extension}",
|
||||||
|
"--folder",
|
||||||
|
str(slides_folder),
|
||||||
|
"--to",
|
||||||
|
extension,
|
||||||
|
"-cdata_uri=true",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert any(
|
||||||
|
"'data_uri' configuration option is deprecated" in str(item.message)
|
||||||
|
and item.category is DeprecationWarning
|
||||||
|
for item in w
|
||||||
|
)
|
||||||
|
assert results.exit_code == 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("extension", "expected_log"),
|
("extension", "expected_log"),
|
||||||
[("html", ""), ("pdf", ""), ("pptx", ""), ("ppt", "WARNING")],
|
[("html", ""), ("pdf", ""), ("pptx", ""), ("ppt", "WARNING")],
|
||||||
|
Reference in New Issue
Block a user