Testing

Rendering frames and feeding events to a sketch in tests.

testing.render_frames

testing.render_frames(
    app,
    frames=1,
    size=(256, 256),
    *,
    pixel_ratio=1.0,
    on_frame=None,
    events=(),
    with_gui=False,
    fps=None,
    background=None,
    auto_clear=True,
    exit_on_escape=None,
)

Runs app for frames frames in a hidden window and returns the last frame.

The app’s full lifecycle runs: setup, then update and draw per frame, then exit. Input can be scripted with events, so tests and docs can drive mouse and keyboard handlers. To keep every frame, for an animation, pass on_frame:

frames = []
render_frames(MyApp(), frames=60, on_frame=frames.append)

The frames are the sketch’s art: kiln.Gui panels are a tool, not part of it, so they are left out, as save_screen leaves them out. Pass with_gui=True to get the frames as shown on screen, panels included (for pictures of a panel, as in the GUI tutorial).

Parameters

Name Type Description Default
app App The App to run. required
frames int Number of frames to render, at least 1. 1
size tuple[int, int] Window size in points, (width, height). (256, 256)
pixel_ratio float Pixels per point of the render target; 2 emulates Retina. 1.0
on_frame Callable[[np.ndarray], None] | None Called after each frame with that frame’s pixels, in the same format as the return value. None
events Sequence[tuple[int, object]] Scripted input, a sequence of (frame, event) pairs where event is a typed event (MouseMove(x, y), MousePress(button, x=None, y=None), MouseRelease, MouseScroll(scroll_x, scroll_y), MouseEnter(), MouseExit(), KeyPress(key), KeyRelease(key), Drop(files)). Each fires through the same dispatch as real input, right before that frame’s update (frames count from 0). The events are checked before the window opens. ()
with_gui bool Include the Gui panels in the returned frame and in the frames given to on_frame, as they were shown. False
fps float | None The starting kiln.clock.target_fps, as kiln.run takes it. None
background ColorLike | None The starting kiln.window.background, as kiln.run takes it. None
auto_clear bool The starting kiln.window.auto_clear, as kiln.run takes it. True
exit_on_escape bool | None The starting kiln.window.exit_on_escape, as kiln.run takes it. None

Returns

Name Type Description
np.ndarray The final frame as an (h, w, 4) uint8 RGBA array, top row first, where
np.ndarray h and w are size scaled by pixel_ratio.

Raises

Name Type Description
ValueError frames is less than 1, or an event names an unknown event, has the wrong arguments, or a frame outside range(frames).
RuntimeError No OpenGL 4.1 context is available (no GUI session).

testing.drain_calls

testing.drain_calls()

Runs the calls queued by kiln.call_soon, in order, on the calling thread.

A running App runs them at the start of every frame. A simulation stepped without a window (a test, a headless run) calls this instead, between its steps, so that the writes other threads made with Population.write land::

pop.write(ids, goal=targets)  # from any thread
kiln.testing.drain_calls()  # on the simulation's thread: the goals land
for _ in range(60):
    step(pop, 1 / 60)

Only the calls queued when it starts run; a call queued by one of them waits for the next drain. An exception propagates and leaves the later calls queued.

testing.pinned_clock

testing.pinned_clock(fps)

Runs Kiln’s clock off the frame number: frame n starts at n / fps seconds.

For deterministic tests and renders: a run’s timing depends only on how many frames have passed, never on the machine’s speed or load, so the same sketch gives the same pixels and the same state every time::

with kiln.testing.pinned_clock(60):
    first = render_frames(MyApp(), frames=30)
with kiln.testing.pinned_clock(60):
    second = render_frames(MyApp(), frames=30)
assert (first == second).all()

Inside the block, for an App that starts running there, every frame lasts exactly 1 / fps seconds: kiln.clock.time (and so Material.time, a shader’s kiln_time) reads n / fps during frame n, clock.dt reads 1 / fps from the first frame on, clock.fps reads fps, and clock.fixed_steps(rate) gives exactly rate steps per second of pinned time (fps / rate frames). Frames are not paced: clock.target_fps waits for nothing, so a long pinned run takes only as long as its drawing.

Only an App started inside the block is pinned, and the clock moves only when a frame ends. On exit, including on an exception, Kiln’s clock and its frame counters are as they were before the block. Blocks nest: the innermost fps applies, and leaving it brings back the outer one. The block pins the process, not one thread or one App; it is not safe to enter from two threads at once.

Parameters

Name Type Description Default
fps float Pinned frames per second, a finite number above 0. required

Raises

Name Type Description
ValueError fps is not a finite number above 0.

testing.MouseMove

testing.MouseMove(x, y)

Scripted mouse move for render_frames(events=...).

Parameters

Name Type Description Default
x float Mouse x in window points. required
y float Mouse y in window points. required

testing.MousePress

testing.MousePress(button=MouseButton.LEFT, x=None, y=None)

Scripted mouse press for render_frames(events=...).

Parameters

Name Type Description Default
button int A MouseButton. MouseButton.LEFT
x float | None Move the mouse here first. None presses at the current position. None
y float | None Move the mouse here first. None presses at the current position. None

testing.MouseRelease

testing.MouseRelease(button=MouseButton.LEFT, x=None, y=None)

Scripted mouse release for render_frames(events=...).

Parameters

Name Type Description Default
button int A MouseButton. MouseButton.LEFT
x float | None Move the mouse here first. None releases at the current position. None
y float | None Move the mouse here first. None releases at the current position. None

testing.MouseScroll

testing.MouseScroll(scroll_x, scroll_y)

Scripted scroll for render_frames(events=...).

Parameters

Name Type Description Default
scroll_x float Horizontal scroll amount. required
scroll_y float Vertical scroll amount. required

testing.MouseEnter

testing.MouseEnter()

Scripted cursor entering the window.

testing.MouseExit

testing.MouseExit()

Scripted cursor leaving the window.

testing.KeyPress

testing.KeyPress(key)

Scripted key press for render_frames(events=...).

Parameters

Name Type Description Default
key int A Key member or a character code such as ord("a"). required

testing.KeyRelease

testing.KeyRelease(key)

Scripted key release for render_frames(events=...).

Parameters

Name Type Description Default
key int A Key member or a character code such as ord("a"). required

testing.Drop

testing.Drop(files=list())

Scripted file drop for render_frames(events=...).

Parameters

Name Type Description Default
files list[str] Paths of the dropped files. list()