Various infrastructure updates (#168)

pull/170/head
Josh Karpel 1 year ago committed by GitHub
parent 57dcad28c4
commit f08ed7e7c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -10,12 +10,11 @@ RUN : \
ENV COLORTERM=truecolor \
EDITOR=/usr/bin/vim
WORKDIR /app
COPY . /app/spiel
RUN : \
&& pip install --no-cache-dir /app/spiel \
RUN --mount=target=/spiel : \
&& pip install --no-cache-dir --disable-pip-version-check /spiel \
&& spiel version \
&& :
WORKDIR /app
CMD ["spiel", "demo", "present"]

@ -1,5 +1,12 @@
# Changelog
## 0.4.3
### 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 Docker image no longer has a leftover copy of the `spiel` package directory inside the image unde `/app`.
## 0.4.2
### Added

@ -0,0 +1,8 @@
# Gallery
- [pytest: It's What's For Testing](https://github.com/JoshKarpel/pytest-its-whats-for-testing) by [JoshKarpel](https://github.com/JoshKarpel).
### Submitting to the Gallery
If you've made a talk with Spiel, please feel free to submit a [pull request](https://github.com/JoshKarpel/spiel/pulls)
to add it to the gallery.

@ -3,6 +3,24 @@
Depending on your preferred workflow,
you can start a presentation in a variety of different ways.
!!! danger "Sandboxed Execution"
Spiel presentations are live Python code: they can do anything that Python can do.
You may want to run untrusted presentations (or even your own presentations) inside a container (but remember, even containers are not perfectly safe!).
We produce a [container image](https://github.com/users/JoshKarpel/packages/container/package/spiel)
that can be run by (for example) Docker.
Presentations without extra Python dependencies might just need to be bind-mounted into the container.
For example, if your demo file is at `$PWD/presentation/deck.py`, you could do
```bash
$ docker run -it --rm --mount type=bind,source=$PWD/presentation,target=/presentation ghcr.io/joshkarpel/spiel spiel present /presentation/deck.py
```
If the presentation has extra dependencies (like other Python packages),
we recommend building a new image that inherits our image (e.g., `FROM ghcr.io/joshkarpel/spiel:vX.Y.Z`).
Spiel's image itself inherits from the [Python base image](https://hub.docker.com/_/python).
## Using the `spiel` CLI
!!! warning "Under Construction"
@ -16,9 +34,11 @@ The `present` function lets you start a presentation programmatically (i.e., fro
If your deck is defined in `talk/slides.py` like so:
```python title="talk/slides.py"
#!/usr/bin/env python
from spiel import Deck, present
deck = Deck(name=f"pytest")
deck = Deck(...)
... # construct your deck
@ -26,11 +46,16 @@ if __name__ == "__main__":
present(__file__)
```
You can then present the deck by running
You can then present the deck by running the script:
```console
$ python talk/slides.py
```
or
Or by running the script as a module (you must have a `talk/__init__.py` file):
```console
$ python -m talk.slides
```
Or by running the script via its [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix))
(after running `chmod +x talk/slides.py` to mark `talk/slides.py` as executable):
```console
$ talk/slides.py
```

@ -1,16 +0,0 @@
# Sandboxed Execution
Spiel presentations are live Python code: they can do anything that Python can do.
You may want to run untrusted presentations (or even your own presentations) inside a container (but remember, even containers are not perfectly safe!).
We produce a [container image](https://github.com/users/JoshKarpel/packages/container/package/spiel)
that can be run by (for example) Docker.
Presentations without extra Python dependencies might just need to be bind-mounted into the container.
For example, if your demo file is at `$PWD/presentation/deck.py`, you could do
```bash
$ docker run -it --rm --mount type=bind,source=$PWD/presentation,target=/presentation ghcr.io/joshkarpel/spiel spiel present /presentation/deck.py
```
If the presentation has extra dependencies (like other Python packages),
we recommend building a new image that inherits our image (e.g., `FROM ghcr.io/joshkarpel/spiel:vX.Y.Z`).
Spiel's image itself inherits from the [Python base image](https://hub.docker.com/_/python).

@ -72,6 +72,6 @@ extra:
nav:
- Introduction: index.md
- Sandboxed Execution: sandboxed-execution.md
- Presenting: presenting.md
- presenting.md
- gallery.md
- changelog.md

1730
poetry.lock generated

File diff suppressed because it is too large Load Diff

@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry]
name = "spiel"
version = "0.4.2"
version = "0.4.3"
description = "A framework for building and presenting richly-styled presentations in your terminal using Python."
readme="README.md"
homepage="https://github.com/JoshKarpel/spiel"
@ -68,7 +68,6 @@ all = true
[tool.pytest.ini_options]
addopts = ["--strict-markers", "--mypy", "-n", "auto"]
testpaths = ["tests", "spiel"]
norecursedirs = ["demo"]
[tool.mypy]
pretty = false

@ -1,5 +1,7 @@
from spiel.app import present
from spiel.app import SuspendType, present
from spiel.constants import __version__
from spiel.deck import Deck
from spiel.slide import Slide
from spiel.triggers import Triggers
__all__ = ["present", "SuspendType", "__version__", "Deck", "Slide", "Triggers"]

@ -11,7 +11,7 @@ from contextlib import contextmanager, redirect_stderr, redirect_stdout
from functools import cached_property, partial
from pathlib import Path
from time import monotonic
from typing import Callable, Iterator, Optional
from typing import Callable, ContextManager, Iterator, Optional
from rich.style import Style
from rich.text import Text
@ -60,6 +60,9 @@ def load_deck(path: Path) -> Deck:
return deck
SuspendType = Callable[[], ContextManager[None]]
class SpielApp(App[None]):
CSS_PATH = "spiel.css"
BINDINGS = [

@ -23,7 +23,7 @@ class Deck:
def slide(
self,
title: str = "",
bindings: Mapping[str, Callable[[], None]] | None = None,
bindings: Mapping[str, Callable[..., None]] | None = None,
) -> Callable[[Content], Slide]:
def slideify(content: Content) -> Slide:
slide = Slide(

@ -1,3 +1,5 @@
#!/usr/bin/env python
import inspect
import shutil
import socket
@ -5,7 +7,6 @@ from datetime import datetime
from math import cos, floor, pi
from pathlib import Path
from textwrap import dedent
from typing import Callable, Iterable
from click import edit
from rich.align import Align
@ -20,7 +21,7 @@ from rich.style import Style
from rich.syntax import Syntax
from rich.text import Text
from spiel import Slide, Triggers, __version__
from spiel import Slide, SuspendType, Triggers, __version__, present
from spiel.deck import Deck
from spiel.renderables.image import Image
@ -191,7 +192,7 @@ def dynamic() -> RenderableType:
Align.center(
Panel(
Text.from_markup(
f"The local timezone on this computer ([bold]{socket.gethostname()}[/bold]) is [bold underline]{datetime.now().astimezone().tzinfo}[/bold underline]",
f"The local timezone on this computer ([bold]{socket.gethostname()}[/bold]) is [bold]{datetime.now().astimezone().tzinfo}[/bold]",
style="bright_cyan",
justify="center",
)
@ -303,9 +304,9 @@ def grid() -> RenderableType:
## Deck View
Try pressing `d` to go into "deck" view.
You can still move between slides in deck view.
You can move between slides in deck view using your arrow keys (right ``, left ``, up ``, and down ``).
Press `enter` to go back to "slide" view (this view),
Press `enter` or `escape` to go back to "slide" view (this view),
on the currently-selected slide.
"""
)
@ -363,7 +364,7 @@ def watch() -> RenderableType:
)
def edit_this_file(suspend: Callable[[], Iterable[None]]) -> None:
def edit_this_file(suspend: SuspendType) -> None:
with suspend():
edit(filename=__file__)
@ -375,6 +376,7 @@ def edit_this_file(suspend: Callable[[], Iterable[None]]) -> None:
},
)
def bindings() -> RenderableType:
edit_function_src = dedent("".join(inspect.getsourcelines(edit_this_file)[0]))
return pad_markdown(
f"""\
## Custom Per-Slide Key Bindings
@ -383,12 +385,18 @@ def bindings() -> RenderableType:
which takes a mapping of key names to callables to call when that key is pressed.
```python
def edit_this_file(suspend: SuspendType) -> None:
with suspend():
edit(filename=__file__)
@deck.slide(
title="Bindings",
bindings={{
"e": edit_this_file,
}},
)
def bindings() -> RenderableType:
...
```
If the callable takes an argument named `suspend`,
@ -421,3 +429,7 @@ def failure() -> RenderableType:
Deck reloading will still happen, so you can fix the error without stopping Spiel.
"""
)
if __name__ == "__main__":
present(__file__)

@ -18,7 +18,7 @@ Content = Callable[..., RenderableType]
class Slide:
title: str = ""
content: Content = lambda: Text()
bindings: Mapping[str, Callable[[], None]] = field(default_factory=dict)
bindings: Mapping[str, Callable[..., None]] = field(default_factory=dict)
def render(self, triggers: Triggers) -> RenderableType:
signature = inspect.signature(self.content)

@ -9,8 +9,7 @@ from spiel.utils import clamp
def test_clamp(value_lower_upper: tuple[int, int, int]) -> None:
value, lower, upper = value_lower_upper
clamped = clamp(value, lower, upper)
assert clamped <= upper
assert clamped >= lower
assert lower <= clamped <= upper
@given(st.tuples(st.integers(), st.integers(), st.integers()).filter(lambda x: x[1] > x[2]))

Loading…
Cancel
Save