Skip to content

Commit 2853ed0

Browse files
chore(tests): adding tests for Qt widgets (#300)
* chore(tests): adding tests for Qt widgets * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix: reset WINDOW name * chore(tests): addign tests * chore: adding more tests * fix how bin existence is checked * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix: which takes str * more tests! * todo: fix * change verbosity in tests --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 760ceb8 commit 2853ed0

File tree

18 files changed

+605
-88
lines changed

18 files changed

+605
-88
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
runs-on: ${{ matrix.os }}
1515
env:
1616
QT_QPA_PLATFORM: offscreen
17-
MANIM_SLIDES_VERBOSITY: debug
17+
MANIM_SLIDES_VERBOSITY: error
1818
PYTHONFAULTHANDLER: 1
1919
DISPLAY: :99
2020
GITHUB_WORKFLOWS: 1

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ In an effort to better document changes, this CHANGELOG document is now created.
4646
- Added `Slide.next_section` for compatibility with `manim`'s
4747
`Scene.next_section` method.
4848
[#295](https://github.com/jeertmans/manim-slides/pull/295)
49+
- Added `--playback-rate` option to `manim-slides present` for testing purposes.
50+
[#300](https://github.com/jeertmans/manim-slides/pull/300)
4951

5052
(v5-changed)=
5153
### Changed

manim_slides/present/__init__.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
from click import Context, Parameter
88
from pydantic import ValidationError
99
from PySide6.QtCore import Qt
10-
from PySide6.QtWidgets import QApplication
1110

1211
from ..commons import config_path_option, folder_path_option, verbosity_option
1312
from ..config import Config, PresentationConfig
1413
from ..logger import logger
14+
from ..qt_utils import qapp
1515
from .player import Player
1616

1717
ASPECT_RATIO_MODES = {
@@ -210,7 +210,14 @@ def str_to_int_or_none(value: str) -> Optional[int]:
210210
metavar="NUMBER",
211211
type=int,
212212
default=None,
213-
help="Presents content on the given screen (a.k.a. display).",
213+
help="Present content on the given screen (a.k.a. display).",
214+
)
215+
@click.option(
216+
"--playback-rate",
217+
metavar="RATE",
218+
type=float,
219+
default=1.0,
220+
help="Playback rate of the video slides, see PySide6 docs for details.",
214221
)
215222
@click.help_option("-h", "--help")
216223
@verbosity_option
@@ -228,6 +235,7 @@ def present(
228235
start_at_scene_number: int,
229236
start_at_slide_number: int,
230237
screen_number: Optional[int] = None,
238+
playback_rate: float = 1.0,
231239
) -> None:
232240
"""
233241
Present SCENE(s), one at a time, in order.
@@ -258,13 +266,9 @@ def present(
258266
start_at_scene_number = start_at[0]
259267

260268
if start_at[1]:
261-
start_at_scene_number = start_at[1]
262-
263-
if maybe_app := QApplication.instance():
264-
app = maybe_app
265-
else:
266-
app = QApplication(sys.argv)
269+
start_at_slide_number = start_at[1]
267270

271+
app = qapp()
268272
app.setApplicationName("Manim Slides")
269273

270274
if screen_number is not None:
@@ -291,9 +295,10 @@ def present(
291295
presentation_index=start_at_scene_number,
292296
slide_index=start_at_slide_number,
293297
screen=screen,
298+
playback_rate=playback_rate,
294299
)
295300

296301
player.show()
297302

298303
signal.signal(signal.SIGINT, signal.SIG_DFL)
299-
sys.exit(app.exec_())
304+
sys.exit(app.exec())

manim_slides/present/player.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def __init__(
5353
presentation_index: int = 0,
5454
slide_index: int = 0,
5555
screen: Optional[QScreen] = None,
56+
playback_rate: float = 1.0,
5657
):
5758
super().__init__()
5859

@@ -65,11 +66,12 @@ def __init__(
6566
self.presentation_configs = presentation_configs
6667
self.__current_presentation_index = 0
6768
self.__current_slide_index = 0
68-
self.__current_file: Path = self.current_slide_config.file
6969

7070
self.current_presentation_index = presentation_index
7171
self.current_slide_index = slide_index
7272

73+
self.__current_file: Path = self.current_slide_config.file
74+
7375
self.__playing_reversed_slide = False
7476

7577
# Widgets
@@ -100,6 +102,7 @@ def __init__(
100102

101103
self.media_player = QMediaPlayer(self)
102104
self.media_player.setVideoOutput(self.video_widget)
105+
self.media_player.setPlaybackRate(playback_rate)
103106

104107
self.presentation_changed.connect(self.presentation_changed_callback)
105108
self.slide_changed.connect(self.slide_changed_callback)
@@ -108,7 +111,7 @@ def __init__(
108111

109112
# Connecting key callbacks
110113

111-
self.config.keys.QUIT.connect(self.quit)
114+
self.config.keys.QUIT.connect(self.close)
112115
self.config.keys.PLAY_PAUSE.connect(self.play_pause)
113116
self.config.keys.NEXT.connect(self.next)
114117
self.config.keys.PREVIOUS.connect(self.previous)
@@ -161,7 +164,7 @@ def current_presentation_index(self, index: int) -> None:
161164
elif -self.presentations_count <= index < 0:
162165
self.__current_presentation_index = index + self.presentations_count
163166
else:
164-
logger.warn(f"Could not set presentation index to {index}")
167+
logger.warn(f"Could not set presentation index to {index}.")
165168
return
166169

167170
self.presentation_changed.emit()
@@ -185,7 +188,7 @@ def current_slide_index(self, index: int) -> None:
185188
elif -self.current_slides_count <= index < 0:
186189
self.__current_slide_index = index + self.current_slides_count
187190
else:
188-
logger.warn(f"Could not set slide index to {index}")
191+
logger.warn(f"Could not set slide index to {index}.")
189192
return
190193

191194
self.slide_changed.emit()
@@ -257,7 +260,8 @@ def load_next_slide(self) -> None:
257260
self.current_presentation_index += 1
258261
self.current_slide_index = 0
259262
elif self.exit_after_last_slide:
260-
self.quit()
263+
self.close()
264+
return
261265
else:
262266
logger.info("No more slide to play.")
263267
return
@@ -290,10 +294,9 @@ def show(self) -> None:
290294
self.info.show()
291295

292296
@Slot()
293-
def quit(self) -> None:
297+
def close(self) -> None:
294298
logger.info("Closing gracefully...")
295-
self.info.deleteLater()
296-
self.deleteLater()
299+
super().close()
297300

298301
@Slot()
299302
def next(self) -> None:
@@ -338,7 +341,7 @@ def hide_mouse(self) -> None:
338341
self.setCursor(Qt.BlankCursor)
339342

340343
def closeEvent(self, event: QCloseEvent) -> None: # noqa: N802
341-
self.quit()
344+
self.close()
342345

343346
def keyPressEvent(self, event: QKeyEvent) -> None: # noqa: N802
344347
key = event.key()

manim_slides/qt_utils.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
"""Qt utils."""
2+
3+
from PySide6.QtWidgets import QApplication
4+
5+
6+
def qapp() -> QApplication:
7+
"""
8+
Return a QApplication instance, creating one
9+
if needed.
10+
"""
11+
if app := QApplication.instance():
12+
return app
13+
14+
return QApplication([])

manim_slides/slide/base.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,49 +45,49 @@ def _ffmpeg_bin(self) -> Path:
4545
@abstractmethod
4646
def _frame_height(self) -> float:
4747
"""Return the scene's frame height."""
48-
...
48+
raise NotImplementedError
4949

5050
@property
5151
@abstractmethod
5252
def _frame_width(self) -> float:
5353
"""Return the scene's frame width."""
54-
...
54+
raise NotImplementedError
5555

5656
@property
5757
@abstractmethod
5858
def _background_color(self) -> str:
5959
"""Return the scene's background color."""
60-
...
60+
raise NotImplementedError
6161

6262
@property
6363
@abstractmethod
6464
def _resolution(self) -> Tuple[int, int]:
6565
"""Return the scene's resolution used during rendering."""
66-
...
66+
raise NotImplementedError
6767

6868
@property
6969
@abstractmethod
7070
def _partial_movie_files(self) -> List[Path]:
7171
"""Return a list of partial movie files, a.k.a animations."""
72-
...
72+
raise NotImplementedError
7373

7474
@property
7575
@abstractmethod
7676
def _show_progress_bar(self) -> bool:
7777
"""Return True if progress bar should be displayed."""
78-
...
78+
raise NotImplementedError
7979

8080
@property
8181
@abstractmethod
8282
def _leave_progress_bar(self) -> bool:
8383
"""Return True if progress bar should be left after completed."""
84-
...
84+
raise NotImplementedError
8585

8686
@property
8787
@abstractmethod
8888
def _start_at_animation_number(self) -> Optional[int]:
8989
"""If set, return the animation number at which rendering start."""
90-
...
90+
raise NotImplementedError
9191

9292
@property
9393
def canvas(self) -> MutableMapping[str, Mobject]:
@@ -341,8 +341,9 @@ def construct(self):
341341
)
342342
)
343343

344+
self._current_slide += 1
345+
344346
self._pre_slide_config_kwargs = dict(loop=loop)
345-
self._current_slide += 1
346347
self._start_animation = self._current_animation
347348

348349
def _add_last_slide(self) -> None:

manim_slides/wizard.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from PySide6.QtCore import Qt
88
from PySide6.QtGui import QIcon, QKeyEvent
99
from PySide6.QtWidgets import (
10-
QApplication,
1110
QDialog,
1211
QDialogButtonBox,
1312
QGridLayout,
@@ -22,6 +21,7 @@
2221
from .config import Config, Key
2322
from .defaults import CONFIG_PATH
2423
from .logger import logger
24+
from .qt_utils import qapp
2525
from .resources import * # noqa: F403
2626

2727
WINDOW_NAME: str = "Configuration Wizard"
@@ -57,12 +57,13 @@ def __init__(self, config: Config):
5757
self.config = config
5858
self.icon = QIcon(":/icon.png")
5959
self.setWindowIcon(self.icon)
60+
self.closed_without_saving = False
6061

6162
button = QDialogButtonBox.Save | QDialogButtonBox.Cancel
6263

63-
self.buttonBox = QDialogButtonBox(button)
64-
self.buttonBox.accepted.connect(self.save_config)
65-
self.buttonBox.rejected.connect(self.close_without_saving)
64+
self.button_box = QDialogButtonBox(button)
65+
self.button_box.accepted.connect(self.save_config)
66+
self.button_box.rejected.connect(self.close_without_saving)
6667

6768
self.buttons = []
6869

@@ -87,17 +88,17 @@ def __init__(self, config: Config):
8788
)
8889
self.layout.addWidget(button, i, 1)
8990

90-
self.layout.addWidget(self.buttonBox, len(self.buttons), 1)
91+
self.layout.addWidget(self.button_box, len(self.buttons), 1)
9192

9293
self.setLayout(self.layout)
9394

9495
def close_without_saving(self) -> None:
9596
logger.debug("Closing configuration wizard without saving")
97+
self.closed_without_saving = True
9698
self.deleteLater()
97-
sys.exit(0)
9899

99100
def closeEvent(self, event: Any) -> None: # noqa: N802
100-
self.closeWithoutSaving()
101+
self.close_without_saving()
101102
event.accept()
102103

103104
def save_config(self) -> None:
@@ -111,15 +112,15 @@ def save_config(self) -> None:
111112
"Two or more actions share a common key: make sure actions have distinct key codes."
112113
)
113114
msg.setWindowTitle("Error: duplicated keys")
114-
msg.exec_()
115+
msg.exec()
115116
return
116117

117118
self.deleteLater()
118119

119120
def open_dialog(self, button_number: int, key: Key) -> None:
120121
button = self.buttons[button_number]
121122
dialog = KeyInput()
122-
dialog.exec_()
123+
dialog.exec()
123124
if dialog.key is not None:
124125
key_name = keymap[dialog.key]
125126
key.set_ids(dialog.key)
@@ -180,12 +181,15 @@ def _init(
180181
if config_path.exists():
181182
config = Config.from_file(config_path)
182183

183-
app = QApplication(sys.argv)
184+
app = qapp()
184185
app.setApplicationName("Manim Slides Wizard")
185186
window = Wizard(config)
186187
window.show()
187188
app.exec()
188189

190+
if window.closed_without_saving:
191+
sys.exit(0)
192+
189193
config = window.config
190194

191195
if merge:

0 commit comments

Comments
 (0)