Skip to content

Commit

Permalink
Add API docs (#178)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshKarpel authored Jan 3, 2023
1 parent 29c5138 commit b6d4582
Show file tree
Hide file tree
Showing 16 changed files with 639 additions and 358 deletions.
15 changes: 15 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# API Reference

## Decks and Slides

::: spiel.Deck

::: spiel.Slide

## Rendering Content

::: spiel.Triggers

## Presenting Decks

::: spiel.present
72 changes: 36 additions & 36 deletions docs/assets/quickstart_code.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions docs/assets/style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,43 @@
:root {
--class-color: #00b8d4;
--class-header-color: #00b8d41a;
--function-color: #448aff;
--function-header-color: #448aff1a;
}

article > .doc {
border-style: solid;
border-width: 0.05rem;
border-radius: 0.2rem;
padding: 0.6rem 0.6rem;
box-shadow: var(--md-shadow-z1);
}

article > .doc + .doc {
margin-top: 1rem;
}

h3.doc {
margin: -0.6rem;
padding: 0.6rem;
}

article > .doc.doc-class {
border-color: var(--class-color);
}

.doc-class > h3.doc {
background-color: var(--class-header-color);
}

article > .doc.doc-function {
border-color: var(--function-color);
}

.doc-function > h3.doc {
background-color: var(--function-header-color);
}

/* Indentation. */
div.doc-contents:not(.first) {
padding-left: 25px;
Expand Down
17 changes: 11 additions & 6 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,34 @@
# Changelog

## 0.4.3
## `0.5.0` | *Unreleased*

## `0.4.4` | *Unreleased*

## `0.4.3` | 2023-01-02

### Added

- [#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.
- [#178](https://github.com/JoshKarpel/spiel/pull/178) `spiel.Deck` is now a `Sequence[Slide]`, and `spiel.Triggers` is now a `Sequence[float]`.

### Fixed

- [#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`.
- [#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`.

## 0.4.2
## `0.4.2` | 2022-12-10

### Added

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

## 0.4.1
## `0.4.1` | 2022-11-25

### Fixed

- [#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).

## 0.4.0
## `0.4.0` | 2022-11-25

### Changed

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

## 0.3.0
## `0.3.0`

### Removed

Expand Down
10 changes: 9 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ edit_uri: edit/main/docs/
extra_css:
- assets/style.css

watch:
- spiel/

theme:
name: material
favicon: assets/favicon.png
Expand Down Expand Up @@ -42,8 +45,12 @@ plugins:
heading_level: 3
docstring_section_style: spacy
merge_init_into_class: true
show_if_no_docstring: true
show_if_no_docstring: false
show_source: false
members_order: source
import:
- https://docs.python.org/3/objects.inv


markdown_extensions:
- admonition
Expand Down Expand Up @@ -72,6 +79,7 @@ nav:
- Introduction: index.md
- quickstart.md
- presenting.md
- api.md
- gallery.md
- contributing.md
- changelog.md
632 changes: 369 additions & 263 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ pytest-mypy = ">=0.10"
pytest-mock = ">=3"
hypothesis = ">=6"
textual = {extras = ["dev"], version = "==0.4.0"}
mkdocs = ">=1.4.2"
mkdocs-material = ">=8.5.10"
mkdocs = ">=1.4"
mkdocs-material = ">=9"
mkdocstrings = {extras = ["python"], version = ">=0.19.0"}

[tool.poetry.scripts]
Expand Down
2 changes: 1 addition & 1 deletion spiel/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def watch_current_slide_idx(self, new_current_slide_idx: int) -> None:
def action_trigger(self) -> None:
now = monotonic()
slide_widget = self.query_one(SlideWidget)
slide_widget.triggers = Triggers(now=now, times=(*slide_widget.triggers.times, now))
slide_widget.triggers = Triggers(now=now, _times=(*slide_widget.triggers._times, now))

def action_reset_trigger(self) -> None:
slide_widget = self.query_one(SlideWidget)
Expand Down
64 changes: 52 additions & 12 deletions spiel/deck.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,40 @@
from __future__ import annotations

from collections.abc import Callable, Iterator, Mapping, Sequence
from dataclasses import dataclass, field
from typing import Callable, Iterator, Mapping
from typing import overload

from spiel.slide import Content, Slide


@dataclass
class Deck:
name: str
slides: list[Slide] = field(default_factory=list)

def __len__(self) -> int:
return len(self.slides)
class Deck(Sequence[Slide]):
"""
Represents a "deck" of "slides": a presentation.
"""

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

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

def slide(
self,
title: str = "",
bindings: Mapping[str, Callable[..., None]] | None = None,
) -> Callable[[Content], Slide]:
"""
A decorator that creates a new slide in the deck,
with the decorated function as the `Slide`'s `content`.
Args:
title: The title to display for the slide.
bindings: A mapping of
[keys](https://textual.textualize.io/guide/input/#key)
to callables to be executed when those keys are pressed,
when on this slide.
"""

def slideify(content: Content) -> Slide:
slide = Slide(
title=title,
Expand All @@ -37,4 +47,34 @@ def slideify(content: Content) -> Slide:
return slideify

def add_slides(self, *slides: Slide) -> None:
self.slides.extend(slides)
"""
Add `Slide`s to a `Deck`.
This function is primarily useful when adding multiple slides at once,
probably generated programmatically.
If adding a single slide, prefer the [`Deck.slide`][spiel.Deck.slide] decorator.
Args:
*slides: The `Slide`s to add.
"""
self._slides.extend(slides)

def __len__(self) -> int:
return len(self._slides)

@overload
def __getitem__(self, item: int) -> Slide:
return self._slides[item]

@overload
def __getitem__(self, item: slice) -> Sequence[Slide]:
return self._slides[item]

def __getitem__(self, item: int | slice) -> Slide | Sequence[Slide]:
return self._slides[item]

def __iter__(self) -> Iterator[Slide]:
yield from self._slides

def __contains__(self, item: object) -> bool:
return item in self._slides
2 changes: 1 addition & 1 deletion spiel/demo/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ def bindings() -> RenderableType:
suspends {SPIEL} while inside the `with` block.
A binding has been registered on this slide that suspends {SPIEL}
and opens your `$EDITOR` on this file.
and opens your `$EDITOR` on the demo deck's Python file.
Try pressing `e`!
Due to reloading, any changes you make will be reflected in the
Expand Down
14 changes: 14 additions & 0 deletions spiel/slide.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,22 @@

@dataclass
class Slide:
"""
Represents a single slide in the presentation.
"""

title: str = ""
"""The title of the `Slide`, which will be displayed in the footer."""

content: Content = lambda: Text()
"""
A callable that is invoked by Spiel to display the slide's content.
The function may optionally take arguments with these names:
- `trigger`: The current [`Trigger`][spiel.Triggers] state, for use in animations.
"""

bindings: Mapping[str, Callable[..., None]] = field(default_factory=dict)

def render(self, triggers: Triggers) -> RenderableType:
Expand Down
62 changes: 49 additions & 13 deletions spiel/triggers.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,81 @@
from __future__ import annotations

from collections.abc import Sequence
from dataclasses import dataclass
from functools import cached_property
from time import monotonic
from typing import Iterator
from typing import Iterator, overload


@dataclass(frozen=True)
class Triggers:
times: tuple[float, ...]
class Triggers(Sequence[float]):
"""
Provides information to [`Slide.content`][spiel.Slide.content] about the current slide's "trigger state".
`Triggers` is a [`Sequence`][collections.abc.Sequence] of times
(produced by [`time.monotonic`][time.monotonic])
that the current slide was triggered at.
Note that the slide will be triggered once when it starts being displayed,
so the first trigger time will be the time when the slide started being displayed.
"""

now: float
"""
The time that the slide content is being rendered at.
Use this is as a single consistent value to base relative times on.
"""

_times: tuple[float, ...]

def __post_init__(self) -> None:
if not self.times:
if not self._times:
raise ValueError("times must not be empty")

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

@classmethod
def new(self) -> Triggers:
now = monotonic()
return Triggers(now=now, times=(now,))
return Triggers(now=now, _times=(now,))

def __len__(self) -> int:
return len(self.times)
return len(self._times)

def __getitem__(self, idx: int) -> float:
return self.times[idx]
@overload
def __getitem__(self, item: int) -> float:
return self._times[item]

@overload
def __getitem__(self, item: slice) -> Sequence[float]:
return self._times[item]

def __getitem__(self, item: int | slice) -> float | Sequence[float]:
return self._times[item]

def __iter__(self) -> Iterator[float]:
return iter(self.times)
return iter(self._times)

def __contains__(self, item: object) -> bool:
return item in self._times

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

@cached_property
def time_since_first_trigger(self) -> float:
return self.now - self.times[0]
"""
The elapsed time since the first trigger,
which is equivalent to the time since the slide started being displayed.
"""
return self.now - self._times[0]

@cached_property
def triggered(self) -> bool:
"""
Returns whether the slide has been *manually* triggered
(i.e., this ignores the initial trigger from when the slide starts being displayed).
"""
return len(self) > 1
2 changes: 1 addition & 1 deletion spiel/widgets/minislides.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def render(self) -> RenderableType:
upper=max(num_rows - grid_width, 0),
)
start_slide_idx = grid_width * start_row
slides = islice(enumerate(self.app.deck.slides), start_slide_idx, None)
slides = islice(enumerate(self.app.deck), start_slide_idx, None)

rows = [Layout(name=str(r)) for r in range(grid_width)]
cols = [[Layout(name=f"{r}-{c}") for c in range(grid_width)] for r, _ in enumerate(rows)]
Expand Down
2 changes: 1 addition & 1 deletion spiel/widgets/slide.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def on_mount(self) -> None:
self.set_interval(1 / 60, self.update_triggers)

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

def render(self) -> RenderableType:
try:
Expand Down
Loading

0 comments on commit b6d4582

Please sign in to comment.