Skip to content

Commit a7719db

Browse files
authored
feat(lib): change config file from json to toml (#224)
This PR introduces a **BREAKING CHANGE**: the general config file is now written in the TOML format. Keys are also placed under a shared subsection. Previous config files will be ignore. Migration from the previous format can be easily performed with `manim-slides init` and copy/pasting the key codes if necessary.
1 parent 529a6c5 commit a7719db

File tree

7 files changed

+115
-48
lines changed

7 files changed

+115
-48
lines changed

.gitignore

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,29 @@
1+
# Python files
12
__pycache__/
23
/env
34
/build
45
/dist
56
*.egg-info/
67

8+
# Manim files
9+
images/
710
/media
8-
/presentation
11+
docs/source/media/
912

10-
/.vscode
13+
# ManimGL files
14+
videos/
15+
16+
# Manim Slides files
17+
.manim-slides.toml
1118

1219
slides/
1320
!tests/slides/
1421

15-
.manim-slides.json
16-
17-
videos/
18-
19-
images/
22+
slides_assets/
2023

24+
# Docs
2125
docs/build/
2226

23-
docs/source/_static/slides_assets/
24-
25-
docs/source/_static/slides.html
26-
27-
slides_assets/
28-
2927
slides.html
3028

3129
docs/source/_static/basic_example_assets/
@@ -36,12 +34,10 @@ docs/source/_static/three_d_example.html
3634

3735
docs/source/_static/three_d_example_assets/
3836

39-
paper/media/
40-
41-
*.jats
4237

38+
# JOSE Paper
4339
paper/paper.pdf
40+
paper/media/
4441

42+
# Others
4543
coverage.xml
46-
47-
docs/source/media/

manim_slides/config.py

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from pathlib import Path
99
from typing import Any, Dict, List, Optional, Set, Tuple, Union
1010

11+
import rtoml
1112
from pydantic import (
1213
BaseModel,
1314
Field,
@@ -46,7 +47,7 @@ def merge_basenames(files: List[FilePath]) -> Path:
4647
class Key(BaseModel): # type: ignore
4748
"""Represents a list of key codes, with optionally a name."""
4849

49-
ids: Set[PositiveInt]
50+
ids: List[PositiveInt] = Field(unique=True)
5051
name: Optional[str] = None
5152

5253
@field_validator("ids")
@@ -57,7 +58,7 @@ def ids_is_non_empty_set(cls, ids: Set[Any]) -> Set[Any]:
5758
return ids
5859

5960
def set_ids(self, *ids: int) -> None:
60-
self.ids = set(ids)
61+
self.ids = list(set(ids))
6162

6263
def match(self, key_id: int) -> bool:
6364
m = key_id in self.ids
@@ -68,9 +69,7 @@ def match(self, key_id: int) -> bool:
6869
return m
6970

7071

71-
class Config(BaseModel): # type: ignore
72-
"""General Manim Slides config"""
73-
72+
class Keys(BaseModel): # type: ignore
7473
QUIT: Key = Key(ids=[Qt.Key_Q], name="QUIT")
7574
CONTINUE: Key = Key(ids=[Qt.Key_Right], name="CONTINUE / NEXT")
7675
BACK: Key = Key(ids=[Qt.Key_Left], name="BACK")
@@ -79,17 +78,6 @@ class Config(BaseModel): # type: ignore
7978
PLAY_PAUSE: Key = Key(ids=[Qt.Key_Space], name="PLAY / PAUSE")
8079
HIDE_MOUSE: Key = Key(ids=[Qt.Key_H], name="HIDE / SHOW MOUSE")
8180

82-
@classmethod
83-
def from_file(cls, path: Path) -> "Config":
84-
"""Reads a configuration from a file."""
85-
with open(path, "r") as f:
86-
return cls.model_validate_json(f.read()) # type: ignore
87-
88-
def to_file(self, path: Path) -> None:
89-
"""Dumps the configuration to a file."""
90-
with open(path, "w") as f:
91-
f.write(self.model_dump_json(indent=2))
92-
9381
@model_validator(mode="before")
9482
def ids_are_unique_across_keys(cls, values: Dict[str, Key]) -> Dict[str, Key]:
9583
ids: Set[int] = set()
@@ -103,15 +91,35 @@ def ids_are_unique_across_keys(cls, values: Dict[str, Key]) -> Dict[str, Key]:
10391

10492
return values
10593

106-
def merge_with(self, other: "Config") -> "Config":
94+
def merge_with(self, other: "Keys") -> "Keys":
10795
for key_name, key in self:
10896
other_key = getattr(other, key_name)
109-
key.ids.update(other_key.ids)
97+
print(set(key.ids))
98+
key.ids = list(set(key.ids).union(other_key.ids))
11099
key.name = other_key.name or key.name
111100

112101
return self
113102

114103

104+
class Config(BaseModel): # type: ignore
105+
"""General Manim Slides config"""
106+
107+
keys: Keys = Keys()
108+
109+
@classmethod
110+
def from_file(cls, path: Path) -> "Config":
111+
"""Reads a configuration from a file."""
112+
return cls.model_validate(rtoml.load(path)) # type: ignore
113+
114+
def to_file(self, path: Path) -> None:
115+
"""Dumps the configuration to a file."""
116+
rtoml.dump(self.model_dump(), path, pretty=True)
117+
118+
def merge_with(self, other: "Config") -> "Config":
119+
self.keys = self.keys.merge_with(other.keys)
120+
return self
121+
122+
115123
class SlideType(str, Enum):
116124
slide = "slide"
117125
loop = "loop"

manim_slides/defaults.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
FOLDER_PATH: str = "./slides"
2-
CONFIG_PATH: str = ".manim-slides.json"
2+
CONFIG_PATH: str = ".manim-slides.toml"
33
FFMPEG_BIN: str = "ffmpeg"

manim_slides/present.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -539,23 +539,24 @@ def handle_key(self) -> None:
539539
"""Handles key strokes."""
540540

541541
key = self.key
542+
keys = self.config.keys
542543

543-
if self.config.QUIT.match(key):
544+
if keys.QUIT.match(key):
544545
self.run_flag = False
545-
elif self.state == State.PLAYING and self.config.PLAY_PAUSE.match(key):
546+
elif self.state == State.PLAYING and keys.PLAY_PAUSE.match(key):
546547
self.state = State.PAUSED
547-
elif self.state == State.PAUSED and self.config.PLAY_PAUSE.match(key):
548+
elif self.state == State.PAUSED and keys.PLAY_PAUSE.match(key):
548549
self.state = State.PLAYING
549550
elif self.state == State.WAIT and (
550-
self.config.CONTINUE.match(key) or self.config.PLAY_PAUSE.match(key)
551+
keys.CONTINUE.match(key) or keys.PLAY_PAUSE.match(key)
551552
):
552553
self.current_presentation.load_next_slide()
553554
self.state = State.PLAYING
554555
elif (
555-
self.state == State.PLAYING and self.config.CONTINUE.match(key)
556+
self.state == State.PLAYING and keys.CONTINUE.match(key)
556557
) or self.skip_all:
557558
self.current_presentation.load_next_slide()
558-
elif self.config.BACK.match(key):
559+
elif keys.BACK.match(key):
559560
if self.current_presentation.current_slide_index == 0:
560561
if self.current_presentation_index == 0:
561562
self.current_presentation.load_previous_slide()
@@ -566,10 +567,10 @@ def handle_key(self) -> None:
566567
else:
567568
self.current_presentation.load_previous_slide()
568569
self.state = State.PLAYING
569-
elif self.config.REVERSE.match(key):
570+
elif keys.REVERSE.match(key):
570571
self.current_presentation.reverse_current_slide()
571572
self.state = State.PLAYING
572-
elif self.config.REWIND.match(key):
573+
elif keys.REWIND.match(key):
573574
self.current_presentation.cancel_reverse()
574575
self.current_presentation.rewind_current_slide()
575576
self.state = State.PLAYING
@@ -705,7 +706,7 @@ def __init__(
705706

706707
def keyPressEvent(self, event: QKeyEvent) -> None:
707708
key = event.key()
708-
if self.config.HIDE_MOUSE.match(key):
709+
if self.config.keys.HIDE_MOUSE.match(key):
709710
if self.hide_mouse:
710711
self.setCursor(Qt.ArrowCursor)
711712
self.hide_mouse = False

poetry.lock

Lines changed: 62 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ python = ">=3.8.1,<3.12"
6161
python-pptx = "^0.6.21"
6262
requests = "^2.28.1"
6363
rich = "^13.3.2"
64+
rtoml = "^0.9.0"
6465
tqdm = "^4.64.1"
6566

6667
[tool.poetry.extras]

tests/test_defaults.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ def test_folder_path() -> None:
66

77

88
def test_config_path() -> None:
9-
assert CONFIG_PATH == ".manim-slides.json"
9+
assert CONFIG_PATH == ".manim-slides.toml"
1010

1111

1212
def test_ffmpeg_bin() -> None:

0 commit comments

Comments
 (0)