Skip to content

Commit b6d4582

Browse files
authored
Add API docs (#178)
1 parent 29c5138 commit b6d4582

16 files changed

+639
-358
lines changed

docs/api.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# API Reference
2+
3+
## Decks and Slides
4+
5+
::: spiel.Deck
6+
7+
::: spiel.Slide
8+
9+
## Rendering Content
10+
11+
::: spiel.Triggers
12+
13+
## Presenting Decks
14+
15+
::: spiel.present

docs/assets/quickstart_code.svg

+36-36
Loading

docs/assets/style.css

+40
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,43 @@
1+
:root {
2+
--class-color: #00b8d4;
3+
--class-header-color: #00b8d41a;
4+
--function-color: #448aff;
5+
--function-header-color: #448aff1a;
6+
}
7+
8+
article > .doc {
9+
border-style: solid;
10+
border-width: 0.05rem;
11+
border-radius: 0.2rem;
12+
padding: 0.6rem 0.6rem;
13+
box-shadow: var(--md-shadow-z1);
14+
}
15+
16+
article > .doc + .doc {
17+
margin-top: 1rem;
18+
}
19+
20+
h3.doc {
21+
margin: -0.6rem;
22+
padding: 0.6rem;
23+
}
24+
25+
article > .doc.doc-class {
26+
border-color: var(--class-color);
27+
}
28+
29+
.doc-class > h3.doc {
30+
background-color: var(--class-header-color);
31+
}
32+
33+
article > .doc.doc-function {
34+
border-color: var(--function-color);
35+
}
36+
37+
.doc-function > h3.doc {
38+
background-color: var(--function-header-color);
39+
}
40+
141
/* Indentation. */
242
div.doc-contents:not(.first) {
343
padding-left: 25px;

docs/changelog.md

+11-6
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,34 @@
11
# Changelog
22

3-
## 0.4.3
3+
## `0.5.0` | *Unreleased*
4+
5+
## `0.4.4` | *Unreleased*
6+
7+
## `0.4.3` | 2023-01-02
48

59
### Added
610

711
- [#169](https://github.com/JoshKarpel/spiel/pull/169) The Textual application title and subtitle are now set dynamically from the Spiel deck name and slide title, respectively.
12+
- [#178](https://github.com/JoshKarpel/spiel/pull/178) `spiel.Deck` is now a `Sequence[Slide]`, and `spiel.Triggers` is now a `Sequence[float]`.
813

914
### Fixed
1015

1116
- [#168](https://github.com/JoshKarpel/spiel/pull/168) The correct type for the `suspend` optional argument to slide-level keybinding functions is now available as `spiel.SuspendType`.
1217
- [#168](https://github.com/JoshKarpel/spiel/pull/168) The [Spiel container image](https://github.com/JoshKarpel/spiel/pkgs/container/spiel) no longer has a leftover copy of the `spiel` package directory inside the image under `/app`.
1318

14-
## 0.4.2
19+
## `0.4.2` | 2022-12-10
1520

1621
### Added
1722

18-
- [#163](https://github.com/JoshKarpel/spiel/pull/163) Added a public `present` function that presents the deck at the given file.
23+
- [#163](https://github.com/JoshKarpel/spiel/pull/163) Added a public `spiel.present()` function that presents the deck at the given file.
1924

20-
## 0.4.1
25+
## `0.4.1` | 2022-11-25
2126

2227
### Fixed
2328

2429
- [#157](https://github.com/JoshKarpel/spiel/pull/157) Pinned to Textual v0.4.0 to work around [Textual#1274](https://github.com/Textualize/textual/issues/1274).
2530

26-
## 0.4.0
31+
## `0.4.0` | 2022-11-25
2732

2833
### Changed
2934

@@ -34,7 +39,7 @@
3439
- [#154](https://github.com/JoshKarpel/spiel/pull/154) Removed library-provided `Example` slides, `Options`, and various other small features
3540
as part of the Textual migration. Some of these features will likely be reintroduced later.
3641

37-
## 0.3.0
42+
## `0.3.0`
3843

3944
### Removed
4045

mkdocs.yml

+9-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ edit_uri: edit/main/docs/
77
extra_css:
88
- assets/style.css
99

10+
watch:
11+
- spiel/
12+
1013
theme:
1114
name: material
1215
favicon: assets/favicon.png
@@ -42,8 +45,12 @@ plugins:
4245
heading_level: 3
4346
docstring_section_style: spacy
4447
merge_init_into_class: true
45-
show_if_no_docstring: true
48+
show_if_no_docstring: false
4649
show_source: false
50+
members_order: source
51+
import:
52+
- https://docs.python.org/3/objects.inv
53+
4754

4855
markdown_extensions:
4956
- admonition
@@ -72,6 +79,7 @@ nav:
7279
- Introduction: index.md
7380
- quickstart.md
7481
- presenting.md
82+
- api.md
7583
- gallery.md
7684
- contributing.md
7785
- changelog.md

poetry.lock

+369-263
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ pytest-mypy = ">=0.10"
4949
pytest-mock = ">=3"
5050
hypothesis = ">=6"
5151
textual = {extras = ["dev"], version = "==0.4.0"}
52-
mkdocs = ">=1.4.2"
53-
mkdocs-material = ">=8.5.10"
52+
mkdocs = ">=1.4"
53+
mkdocs-material = ">=9"
5454
mkdocstrings = {extras = ["python"], version = ">=0.19.0"}
5555

5656
[tool.poetry.scripts]

spiel/app.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ def watch_current_slide_idx(self, new_current_slide_idx: int) -> None:
167167
def action_trigger(self) -> None:
168168
now = monotonic()
169169
slide_widget = self.query_one(SlideWidget)
170-
slide_widget.triggers = Triggers(now=now, times=(*slide_widget.triggers.times, now))
170+
slide_widget.triggers = Triggers(now=now, _times=(*slide_widget.triggers._times, now))
171171

172172
def action_reset_trigger(self) -> None:
173173
slide_widget = self.query_one(SlideWidget)

spiel/deck.py

+52-12
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,40 @@
11
from __future__ import annotations
22

3+
from collections.abc import Callable, Iterator, Mapping, Sequence
34
from dataclasses import dataclass, field
4-
from typing import Callable, Iterator, Mapping
5+
from typing import overload
56

67
from spiel.slide import Content, Slide
78

89

910
@dataclass
10-
class Deck:
11-
name: str
12-
slides: list[Slide] = field(default_factory=list)
13-
14-
def __len__(self) -> int:
15-
return len(self.slides)
11+
class Deck(Sequence[Slide]):
12+
"""
13+
Represents a "deck" of "slides": a presentation.
14+
"""
1615

17-
def __getitem__(self, item: int) -> Slide:
18-
return self.slides[item]
16+
name: str
17+
"""The name of the `Deck`/presentation, which will be displayed in the footer."""
1918

20-
def __iter__(self) -> Iterator[Slide]:
21-
yield from self.slides
19+
_slides: list[Slide] = field(default_factory=list)
2220

2321
def slide(
2422
self,
2523
title: str = "",
2624
bindings: Mapping[str, Callable[..., None]] | None = None,
2725
) -> Callable[[Content], Slide]:
26+
"""
27+
A decorator that creates a new slide in the deck,
28+
with the decorated function as the `Slide`'s `content`.
29+
30+
Args:
31+
title: The title to display for the slide.
32+
bindings: A mapping of
33+
[keys](https://textual.textualize.io/guide/input/#key)
34+
to callables to be executed when those keys are pressed,
35+
when on this slide.
36+
"""
37+
2838
def slideify(content: Content) -> Slide:
2939
slide = Slide(
3040
title=title,
@@ -37,4 +47,34 @@ def slideify(content: Content) -> Slide:
3747
return slideify
3848

3949
def add_slides(self, *slides: Slide) -> None:
40-
self.slides.extend(slides)
50+
"""
51+
Add `Slide`s to a `Deck`.
52+
53+
This function is primarily useful when adding multiple slides at once,
54+
probably generated programmatically.
55+
If adding a single slide, prefer the [`Deck.slide`][spiel.Deck.slide] decorator.
56+
57+
Args:
58+
*slides: The `Slide`s to add.
59+
"""
60+
self._slides.extend(slides)
61+
62+
def __len__(self) -> int:
63+
return len(self._slides)
64+
65+
@overload
66+
def __getitem__(self, item: int) -> Slide:
67+
return self._slides[item]
68+
69+
@overload
70+
def __getitem__(self, item: slice) -> Sequence[Slide]:
71+
return self._slides[item]
72+
73+
def __getitem__(self, item: int | slice) -> Slide | Sequence[Slide]:
74+
return self._slides[item]
75+
76+
def __iter__(self) -> Iterator[Slide]:
77+
yield from self._slides
78+
79+
def __contains__(self, item: object) -> bool:
80+
return item in self._slides

spiel/demo/demo.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ def bindings() -> RenderableType:
403403
suspends {SPIEL} while inside the `with` block.
404404
405405
A binding has been registered on this slide that suspends {SPIEL}
406-
and opens your `$EDITOR` on this file.
406+
and opens your `$EDITOR` on the demo deck's Python file.
407407
Try pressing `e`!
408408
409409
Due to reloading, any changes you make will be reflected in the

spiel/slide.py

+14
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,22 @@
1616

1717
@dataclass
1818
class Slide:
19+
"""
20+
Represents a single slide in the presentation.
21+
"""
22+
1923
title: str = ""
24+
"""The title of the `Slide`, which will be displayed in the footer."""
25+
2026
content: Content = lambda: Text()
27+
"""
28+
A callable that is invoked by Spiel to display the slide's content.
29+
30+
The function may optionally take arguments with these names:
31+
32+
- `trigger`: The current [`Trigger`][spiel.Triggers] state, for use in animations.
33+
"""
34+
2135
bindings: Mapping[str, Callable[..., None]] = field(default_factory=dict)
2236

2337
def render(self, triggers: Triggers) -> RenderableType:

spiel/triggers.py

+49-13
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,81 @@
11
from __future__ import annotations
22

3+
from collections.abc import Sequence
34
from dataclasses import dataclass
45
from functools import cached_property
56
from time import monotonic
6-
from typing import Iterator
7+
from typing import Iterator, overload
78

89

910
@dataclass(frozen=True)
10-
class Triggers:
11-
times: tuple[float, ...]
11+
class Triggers(Sequence[float]):
12+
"""
13+
Provides information to [`Slide.content`][spiel.Slide.content] about the current slide's "trigger state".
14+
15+
`Triggers` is a [`Sequence`][collections.abc.Sequence] of times
16+
(produced by [`time.monotonic`][time.monotonic])
17+
that the current slide was triggered at.
18+
Note that the slide will be triggered once when it starts being displayed,
19+
so the first trigger time will be the time when the slide started being displayed.
20+
"""
21+
1222
now: float
23+
"""
24+
The time that the slide content is being rendered at.
25+
Use this is as a single consistent value to base relative times on.
26+
"""
27+
28+
_times: tuple[float, ...]
1329

1430
def __post_init__(self) -> None:
15-
if not self.times:
31+
if not self._times:
1632
raise ValueError("times must not be empty")
1733

18-
if self.now < self.times[-1]:
19-
raise ValueError(f"now {self.now} must be later than the last time {self.times[-1]}")
34+
if self.now < self._times[-1]:
35+
raise ValueError(f"now {self.now} must be later than the last time {self._times[-1]}")
2036

2137
@classmethod
2238
def new(self) -> Triggers:
2339
now = monotonic()
24-
return Triggers(now=now, times=(now,))
40+
return Triggers(now=now, _times=(now,))
2541

2642
def __len__(self) -> int:
27-
return len(self.times)
43+
return len(self._times)
2844

29-
def __getitem__(self, idx: int) -> float:
30-
return self.times[idx]
45+
@overload
46+
def __getitem__(self, item: int) -> float:
47+
return self._times[item]
48+
49+
@overload
50+
def __getitem__(self, item: slice) -> Sequence[float]:
51+
return self._times[item]
52+
53+
def __getitem__(self, item: int | slice) -> float | Sequence[float]:
54+
return self._times[item]
3155

3256
def __iter__(self) -> Iterator[float]:
33-
return iter(self.times)
57+
return iter(self._times)
58+
59+
def __contains__(self, item: object) -> bool:
60+
return item in self._times
3461

3562
@cached_property
3663
def time_since_last_trigger(self) -> float:
37-
return self.now - self.times[-1]
64+
"""The elapsed time since the most recent trigger."""
65+
return self.now - self._times[-1]
3866

3967
@cached_property
4068
def time_since_first_trigger(self) -> float:
41-
return self.now - self.times[0]
69+
"""
70+
The elapsed time since the first trigger,
71+
which is equivalent to the time since the slide started being displayed.
72+
"""
73+
return self.now - self._times[0]
4274

4375
@cached_property
4476
def triggered(self) -> bool:
77+
"""
78+
Returns whether the slide has been *manually* triggered
79+
(i.e., this ignores the initial trigger from when the slide starts being displayed).
80+
"""
4581
return len(self) > 1

spiel/widgets/minislides.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def render(self) -> RenderableType:
2525
upper=max(num_rows - grid_width, 0),
2626
)
2727
start_slide_idx = grid_width * start_row
28-
slides = islice(enumerate(self.app.deck.slides), start_slide_idx, None)
28+
slides = islice(enumerate(self.app.deck), start_slide_idx, None)
2929

3030
rows = [Layout(name=str(r)) for r in range(grid_width)]
3131
cols = [[Layout(name=f"{r}-{c}") for c in range(grid_width)] for r, _ in enumerate(rows)]

spiel/widgets/slide.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def on_mount(self) -> None:
2525
self.set_interval(1 / 60, self.update_triggers)
2626

2727
def update_triggers(self) -> None:
28-
self.triggers = Triggers(now=monotonic(), times=self.triggers.times)
28+
self.triggers = Triggers(now=monotonic(), _times=self.triggers._times)
2929

3030
def render(self) -> RenderableType:
3131
try:

0 commit comments

Comments
 (0)