Skip to main content

maya-py

Python bindings for maya — a C++26 TUI framework with flexbox layout, a SIMD cell-diff renderer, and an Elm-style runtime. maya-py gives you a dead-simple Python API for building styled terminal UIs and interactive apps.

3D FPS raycaster in a terminal — examples/fps.py

import maya_py as maya
from maya_py import card, field, b, hr

maya.show(card(
    b("maya-py").fg("sky"),
    hr(20),
    field("Status", "Online", value_color="green"),
    field("Region", "us-east-1"),
    title="service",
))

That's the whole program. Strings are UI — no manual element wrapping.

Every demo below is a Python program under examples/ — run any of them with python examples/<name>.py.

Dashboard
examples/dashboard.py — oscilloscope · radar · hex waterfall · spirograph
Stock Ticker
examples/stocks.py — live charts · sparklines · portfolio
Doom Fire
examples/doom_fire.py — classic fire effect · half-block rendering
IDE
examples/ide.py — syntax highlighting · file tree · tabs

Plus a 3D raycaster, raymarcher, fluid sim, mandelbrot zoom, matrix rain, particle systems, spectrum analyzer, breakout, snake, and more — all under examples/.

Captures are from the shared maya engine; the maya-py examples drive the same renderer and produce identical frames.

Documentation

A full reference manual lives in docs/:

The 30-second tour

Text: just style strings

from maya_py import T, b, i, dim_text, c

b("bold")                 # bold
T("hi").bold.fg("sky")     # fluent chain
c("warn", "orange")        # colored
T("x").bg("red").fg("white")

Colors accept names ("red", "sky", "gold"), hex ("#ff8800", "#f80"), tuples ((255, 128, 0)), or ints (0xFF8800).

Layout: stacks that take bare strings

from maya_py import col, row, card, field, hr

col("top", "middle", "bottom")          # vertical
row("left", "right", gap=2)             # horizontal
card("body", title="hi", pad=1)          # bordered box
field("Name", "Ada")                     # "Name: Ada"
hr(40)                                   # horizontal rule

col / row / card accept the full maya flexbox surface as keywords:

  • box model: pad, margin, gap (int or 1/2/4-tuples)
  • border: border ("round"/"double"/"bold"/"dashed"/...), border_color, border_sides=sides(top=..., left=...), title, and positioned border_text=("Title", Top, Center) / border_text_end
  • sizing: width, height, min_width/max_width, min_height/max_height — each takes an int (cells), "50%", a float like 0.5, "auto", or pct(50)/cells(20)/auto()
  • flex: grow, shrink, basis, align, align_self, justify, wrap ("wrap"/"nowrap"/"reverse"), overflow ("hidden"/"scroll")
  • style: bg, fg, style=maya.style(...)

Full layout power

Everything maya C++ can express, the Python API can too:

from maya_py import T, col, row, card, center, stack, grow, component, pct, cells, sides

# percent widths + a flex child that fills the rest
row(
    card("nav", width=pct(30), title="sidebar"),
    grow(card("main content", title="body")),   # expands to fill
    gap=1,
)

# center anything in a region
center("ready", width=cells(20), height=5, border="round")

# z-stack: layers paint on top; the first sets the size
stack(card("  panel  ", height=6), T("NEW").fg("red").bold)

# partial borders
card("footer", border_sides=sides(top=True, right=False, bottom=False, left=False))

# a size-aware widget — render_fn(width, height) draws to fit its box
def bar(w, h):
    filled = int(w * 0.4)
    return T("█" * filled + "░" * (w - filled)).fg("green")
col("Loading", component(bar, height=1))

Widgets: maya's native renderers

maya ships a library of ready-made widgets — they render through the same C++ renderer maya uses, then drop straight into any layout:

from maya_py import col, row, sparkline, gauge, progress, badge, table, bar_chart

col(
    sparkline([3, 1, 4, 1, 5, 9, 2, 6], label="req/s", color="sky", show_last=True),
    gauge(0.72, "load", style="bar"),            # "arc" or "bar"
    progress(0.55, "build", width=24, fill="lime"),
    row(badge("PASS", kind="success"), badge("SKIP", kind="warning"), gap=1),
    table(["Name", ("Score", 0, "right")],       # (header, width, align)
          [["Ada", 99], ["Bob", 7]], bordered=True, title="top"),
    bar_chart([("jan", 4), ("feb", 9), ("mar", 6)]),
    gap=1,
)

Available — every color argument takes a name / (r,g,b) / "#rrggbb" / Color, same as everywhere else:

  • charts & meters: sparkline, gauge, progress, bar_chart, line_chart, heatmap, flame_chart, waterfall, activity_indicator
  • controls (rendered in any state — pass checked/on/selected/cursor): checkbox, toggle, radio, select, slider, button
  • text & labels: badge, divider, spinner, callout, status_banner, breadcrumb, tabs, gradient, link, title_chip, model_badge, file_ref, markdown, html, error_block
  • structure & nav: table, tree, list_view, menu, disclosure, key_help, calendar, timeline, picker (bordered command palette), modal, command_palette, log_viewer
  • agent UI: thinking, todo_list, toast, inline_diff, tool_call, plan_view, phase_chip, context_gauge, context_window, diff_view, git_graph, git_status, shortcut_row, system_banner, popup, overlay, user_message, assistant_message, activity_bar, file_changes, api_usage, cost_tracker, phase_accent, checkpoint_divider, turn_divider, streaming_cursor, token_stream, token_stream_sparkline, search_result, changes_strip, welcome_screen
  • graphics: image (1-bit braille), canvas (color half-block grid), Canvas (imperative drawing surface: set_pixel/line/rect/fill)
from maya_py import col, row, checkbox, slider, todo_list, timeline, tree

col(
    checkbox("Ship it", checked=True),
    slider(0.6, "volume", width=24, fill="sky"),
    todo_list([("design", "completed"), ("build", "in_progress"), "test"],
              description="sprint", status="running"),
    timeline([("clone", "", "0.4s", "completed"),
              ("compile", "", "", "in_progress", 8)]),
    tree({"label": "src", "expanded": True,
          "children": [{"label": "main.py"}, {"label": "util.py"}]}),
    gap=1,
)

List/tuple inputs are flexible: list items accept "str", (label, description, icon), or {...} dicts; timeline/todo statuses accept strings ("completed", "in_progress", ...) or the exported enums (TaskStatus, TodoItemStatus, ToastLevel, ButtonVariant, ToolCallKind, ToolCallStatus, PopupStyle, BannerLevel, FileChangeKind, TurnRole, CursorStyle, SearchKind, SearchStatus).

Scrolling: viewport + scrollbar

Clip tall/wide content to a window and pair it with a live scrollbar. Scrolling just works with no handler code — exactly like maya, the run loop auto-forwards ↑↓ / PgUp / PgDn / Home / End and the mouse wheel + scrollbar drag to every on-screen scroll state:

from maya_py import App, col, row, T, scroll_state, viewport, scrollbar

app = App("log", mouse=True)            # mouse=True for wheel + thumb drag
s = scroll_state()                      # auto-dispatch on (the maya default)
app.state(s=s)
content = col(*[T(f"line {i}") for i in range(200)])

@app.on("q", "esc")
def quit(st): app.stop()

@app.view
def view(st):
    return row(
        viewport(content, st.s, height=14, grow=1),   # 14-row window, fills width
        scrollbar(st.s, 14, style="neon", thumb_color="sky"),
        gap=1,
    )

app.run()

That's the whole thing — no scroll handler. viewport(content, state, width=, height=, grow=) clips + scrolls (0 on an axis = fill; grow=1 expands to fill its row/column so a sibling scrollbar pins to the edge). scrollbar(state, size, axis="y"|"x", style=, thumb_color=, track_color=) draws the bar; style is a preset name — line, block, slim, heavy, double, dotted, dashed, braille, ascii, shadow, minimal, neon, retro, danger, pixel. The ScrollState exposes x/y/max_x/max_y, scroll_by, scroll_to, scroll_to_top/bottom, at_top()/at_bottom(), and viewport_bounds (the painted rect, for click hit-testing).

Need custom routing (several independent scroll regions)? Set state.auto_dispatch = False and call scroll_handle(state, ev) yourself inside @app.on_key / @app.on_mouse. Don't do both — that double-scrolls.

Apps: a class with decorators, no event loop

from maya_py import App, card, b

app = App("counter", n=0, quit_keys=("q", "esc"))   # state + quit in the constructor

@app.on("+", "=")
def inc(s): s.n += 1

@app.on("-")
def dec(s): s.n -= 1

@app.view
def view(s):
    return card(b(f"Count: {s.n}").fg("sky"), title="counter")

app.run()

Key names: single chars ("q", "+"), "up"/"down"/"left"/"right", "enter", "esc", "space", "tab"/"shift+tab", "home"/"end", "pgup"/"pgdn", "insert"/"delete", "f1"–"f12", and modifier prefixes "ctrl+s", "alt+x", "shift+a". A typo'd key spec raises with a did-you-mean hint instead of silently never firing. Handlers get the state object; the view re-renders every frame.

Text input

Real interactive Input widgets — type into them, Tab between them, read .value. Register them with app.focus(...) and drop them in the view:

from maya_py import App, text_input, col

app = App("search")
query = text_input("type to filter…")
app.focus(query)

@app.view
def view(s):
    return col(query, f"searching: {query.value}")

app.run()

text_input(password=True) masks, textarea() is multi-line. @query.on_submit fires on Enter. An animation tick is @app.on_frame def tick(s, dt): ....

Declarative state: For, bind, @app.derive

The view is a pure function of state, so the whole UI reads top-to-bottom. Three helpers kill the last of the glue — list comprehensions, widget read-back, and recomputed fields:

from maya_py import App, text_input, card, col, For

app = App("cart", items=[("Pen", 2.0), ("Mug", 9.5)], name="")

# 1) @app.derive — a computed field, recomputed on access (no stale cache):
@app.derive
def total(s): return sum(price for _, price in s.items)

# 2) bind=(state, field) — the input mirrors a state field both ways, so the
#    view reads s.name directly and never touches widget.value:
name = text_input("your name…", bind=(app.s, "name"))
app.focus(name)

@app.view
def view(s):
    return card(
        # 3) For(...) maps a list into a box — like SwiftUI ForEach / JSX map.
        #    A two-param renderer gets (index, item) for free.
        For(s.items, lambda it: col(f"{it[0]}  ${it[1]:.2f}")),
        col("Name:", name, f"hello {s.name}"),
        f"Total: ${s.total:.2f}",
        title="cart",
    )

app.run()
  • For(items, render, *, into=col, empty=None, **opts) — map a sequence into a container. render(item) or render(index, item) (auto-detected). empty= shows a fallback when the list is empty.
  • text_input(..., bind=(state, "field")) — two-way binding: the field seeds the input and every keystroke writes back. No .value plumbing.
  • @app.derive — install fn(state) as a read-only computed property on the state object. Works with the default state bag and model= objects.

Mouse: clicks, scroll, drag

Decorate handlers for mouse input — registering any of them auto-enables mouse reporting (no mouse=True needed):

from maya_py import App, card

app = App("clicker")
app.state(hits=0, pos=(0, 0))

@app.on_click("left")          # "left" / "right" / "middle" / "any"
def click(s, col, row):        # col, row are 1-based screen cells
    s.hits += 1
    s.pos = (col, row)

@app.on_scroll
def scroll(s, direction):      # -1 up, +1 down
    s.hits += direction

@app.on_mouse
def any_mouse(s, ev):          # every mouse event (press/release/move/scroll)
    ...

@app.on("q", "esc")
def quit(s): app.stop()

@app.view
def view(s):
    return card(f"clicks {s.hits}  at {s.pos}", title="clicker")

app.run()

Low-level predicates work on any event too: mouse_clicked(ev, button), mouse_released(ev), mouse_moved(ev), scrolled_up/down(ev), mouse_pos(ev) -> (col, row) | None, mouse_button(ev), mouse_kind(ev), is_mouse(ev). Mouse needs a terminal that reports it (xterm, kitty, iTerm2, Windows Terminal, or tmux with set -g mouse on).

Animation

import maya_py as maya
from maya_py import animate, card

frames = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
n = 0
def render(dt):
    global n; n += 1
    return card(frames[n % len(frames)] + " working")
animate(render, fps=30)   # maya.quit() to stop

The Elm Architecture: Program (pure, testable, no mutation)

When you want the full discipline — an immutable Model, a closed set of Msg, a pure update, and side effects described as data — maya-py exposes maya's native MVU runtime as a Program. This is the same run<P> loop the C++ side uses, so the effects and subscriptions you return from Python are interpreted by maya's real runtime, not a reimplementation.

import maya_py as maya
from maya_py import Cmd, Sub, Program, card, T

class Counter(Program):
    title = "counter"

    def init(self):                       # -> model | (model, Cmd)
        return {"n": 0}, Cmd.set_title("counter")

    def update(self, m, msg):             # pure: no I/O, no mutation
        if msg == "inc":   return {**m, "n": m["n"] + 1}
        if msg == "dec":   return {**m, "n": m["n"] - 1}
        if msg == "quit":  return m, Cmd.quit()
        return m

    def view(self, m):                    # model -> Element
        return card(T(f"count: {m['n']}").bold)

    def subscribe(self, m):               # model -> event sources
        return Sub.on_key(lambda ev:
            "inc" if maya.key(ev, "+") else
            "dec" if maya.key(ev, "-") else
            "quit" if maya.key(ev, "q") else None)

Counter().run()

update never touches the terminal, so it stays a pure state transition you can unit-test in isolation. Effects are Cmd values — Cmd.quit(), Cmd.set_title(...), Cmd.after(ms, msg), Cmd.task(fn) (async work), Cmd.batch(...), clipboard + scrollback commands. Event sources are Sub values — Sub.on_key, Sub.on_mouse, Sub.on_resize, Sub.on_paste, Sub.every(ms, msg) (a timer), Sub.on_animation_frame(msg), Sub.batch(...). There's a plain-function form too: run_program(init, update, view, subscribe).

The whole architecture is headlessly testable. Because update is pure, Program.test() hands you a ProgramPilot that runs the real init/update/view with no terminal — you dispatch messages (exactly like elm-test), thread the immutable model, and assert on it and the rendered view:

p = Counter().test()
p.send("inc", "inc", "inc", "dec")        # dispatch messages in order
assert p.model == {"n": 2}
assert p.cmds                              # Cmd.set_title was emitted at init
assert "count: 2" in p.view_string(40)

Purity is enforced, not just encouraged. The pilot runs in strict mode by default: it snapshots the model before every update/view and raises ImpureUpdateError if a hook mutated it in place instead of returning a new one. So the moment someone writes the tempting m["n"] += 1; return m, their tests fail loudly with a pointer to the exact hook — the beautiful, pure architecture is the verified one, and the subtle stale-view bug never ships:

class Sloppy(Program):
    def update(self, m, msg):
        m["n"] += 1        # in-place mutation — the TEA sin
        return m
    ...

Sloppy().test().send("inc")   # raises ImpureUpdateError: update() mutated the
                              # model in place. Return a NEW model ({**m, ...}).

The check costs nothing at runtime (it lives in the test pilot), and there's an escape hatch — prog.test(strict=False) — for an intentionally huge or un-deep-copyable model.

See examples/counter_program.py and examples/stopwatch_program.py (the latter uses Sub.every timers, Sub.batch, and Cmd.batch, and ships a --test self-check that proves every transition with the pilot).

Examples

Every maya C++ example is ported 1:1 to Python — 34 of them, plus extras. Most are full apps you can drive; run any with PYTHONPATH=src python examples/NAME.py. A headless examples/smoke_all.py renders one frame of each (CI-friendly, no TTY needed).

Games & toys (half-block pixel rendering via examples/_halfblock.py):

  • snake.py — playable Snake (arrow keys / WASD).
  • breakout.py — Breakout/Arkanoid with bricks, comet trail, particles.
  • life.py — Conway's Game of Life with heat-aging palettes + patterns.
  • sorts.py — five sorting algorithms racing side by side.
  • maze.py — watch a maze carve itself (recursive backtracker) then a BFS flood-solve it; click to set the start cell, right-click the goal.

Graphics & sims (animate / App render loops):

  • doom_fire.py — the classic Doom fire effect, 3 palettes.
  • fluid.py — advection fluid / plasma with curl-noise velocity.
  • particles.py — a gravity particle fountain.
  • space.py — warp-speed starfield. space3d.py — rotating 3D wireframes.
  • raymarch.py — a real-time raymarched SDF scene (sphere + plane).
  • fps.py — a Wolfenstein-style textured raycaster with a minimap.
  • mandelbrot.py — a zooming coloured Mandelbrot. matrix.py — digital rain.
  • canvas.py — the Canvas drawing surface: lines, rects, a live plot.
  • clock.py — a live analog clock drawn on the Canvas (hands, ticks, arc).
  • gravity.py — an n-body gravity sandbox; mouse-hover crosshair, click to spawn an orbiting burst at the exact pixel.
  • boids.py — Reynolds flocking; the mouse leads or scatters the flock (precise, viewport-bounds hit-testing — no hardcoded offsets).

Dashboards & data:

  • dashboard.py — full-power layout (sidebar, z-stack, size-aware bars).
  • sysmon.py — live system monitor (sparklines, gauges, log feed).
  • stocks.py — stock ticker with sparklines + a gainers board.
  • spectrum.py — a faux audio spectrum analyzer. music.py — a player UI.
  • hacker.py — a "hollywood hacker" terminal of fake breaches.

Apps & agent UI:

  • deploy.py — a CI/CD pipeline dashboard with a live stage timeline.
  • chat.py — a chat client with bubbles + typing indicator.
  • messenger.py — multi-channel chat with unread badges + a composer.
  • ide.py — a VS Code / Zed-style mini IDE (tree, tabs, diagnostics, git).
  • agent.py / agent_session.py — Claude-Code-style agent sessions: thinking → tool cards → todo plan → streaming markdown answer.
  • widgets.py — one-shot widget showcase. widgets_gallery.py — live version.
  • markup.py — a GFM markdown render that flows into scrollback (pipe to less -R).
  • inline_progress.py — inline print + live (no alt-screen takeover).

Primitives & basics:

  • hello.py static card · counter.py / stopwatch.py / todo.py App basics · paint.py mouse painter · live_spinner.py inline animation.
  • counter_program.py / stopwatch_program.py — the pure MVU Program (Elm Architecture): immutable model, pure update, Cmd/Sub effects, and a headless --test self-check.
  • suspend.py — Cmd.suspend: hand the real terminal to an interactive child ($EDITOR / pager / shell), then restore the TUI and fold the child's exit code back into the model.
  • form.py — the declarative trio (For, bind=, @app.derive) in one cart.
  • scroll.py / scroll_clip.py / scroll_2d.py / scroll_slice.py / scroll_styles.py — every scrolling pattern (clip, two-axis, million-row slice, and all 15 scrollbar styles).

Run any of them:

PYTHONPATH=src python examples/agent_session.py

Install

The wheels are standalone — no compiler needed. maya-py ships precompiled binary wheels for CPython 3.9–3.14 on Linux (x86_64; aarch64 configured), Windows (x64), and macOS (Apple Silicon / arm64), so on a normal machine you just:

pip install maya-py

That's it — the wheel already contains the compiled extension, and pip picks the right one for your OS / architecture / Python automatically.

Then scaffold a runnable app and go:

maya new myapp     # writes myapp.py — a working counter app
python myapp.py    # run it (q / Esc to quit)

(maya new, maya demo, maya version also work as python -m maya_py ....)

Terminal note. maya speaks ANSI/VT escapes + truecolor + UTF-8. On Linux and macOS any modern terminal works. On Windows use Windows Terminal (the default on Windows 11; free on Windows 10) or any VT-capable host — the legacy cmd.exe console works too (maya enables ENABLE_VIRTUAL_TERMINAL_PROCESSING on startup), but Windows Terminal gives the best Unicode + color fidelity.

Installing straight from a GitHub Release (no PyPI)

If you'd rather not use PyPI (or want a specific build), install from the release assets. Let pip pick the right wheel for your Python:

pip install --find-links \
  https://github.com/1ay1/maya-py/releases/expanded_assets/v0.2.7 \
  maya-py

Or install a specific .whl by direct URL:

# e.g. CPython 3.13 on x86_64 Linux
pip install https://github.com/1ay1/maya-py/releases/download/v0.2.7/maya_py-0.2.7-cp313-cp313-manylinux_2_28_x86_64.whl

The Linux and macOS wheels work even on machines with a very old C++ toolchain (or none at all), because:

  • the wheel is built inside a manylinux_2_28 container, so it targets glibc 2.28 (2019) and runs on that-or-newer distros;
  • it statically links libstdc++/libgcc, so it doesn't need the host's (old) C++ runtime — it depends only on baseline libc/libm.

The Windows wheel links the UCRT present on every Windows 10+ machine. Nothing on your machine is compiled at install time, so your system compiler is irrelevant.

No matching wheel? Build from the sdist

If no prebuilt wheel matches your platform/Python, install the source distribution; this compiles the extension locally and needs a C++23-capable toolchain and CMake ≥ 3.28:

  • Linux: GCC ≥ 14 or Clang ≥ 18
  • macOS: Homebrew GCC (brew install gcc) — AppleClang is rejected (it misses C++23 library bits maya needs); CMake auto-picks the gcc-* driver
  • Windows: Visual Studio 2022 ≥ 17.10 (MSVC cl ≥ 19.40), "Desktop development with C++" workload
pip install \
  https://github.com/1ay1/maya-py/releases/download/v0.2.7/maya_py-0.2.7.tar.gz

The compile pulls maya in via CMake FetchContent and takes ~1–2 minutes (it builds maya from source). If your compiler is too old, the build aborts early with a clear, actionable message rather than a wall of template errors.

Development build

To hack on maya-py, build the extension in place (uses a sibling ../maya-src checkout if present, else clones maya):

cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
cp build/_maya*.so src/maya_py/
PYTHONPATH=src python examples/hello.py

Wheels are produced by cibuildwheel via .github/workflows/wheels.yml — push a vX.Y.Z tag to build them and attach them to a GitHub Release automatically.

Low-level API

The friendly layer above is built on a thin primitive surface. You rarely need it, but it's there when you want raw control. box/text take explicit Style/Color objects:

maya.box(
    maya.text("Hello", maya.bold | maya.fg(255, 128, 0)),
    border=maya.Round, padding=1,
)
  • text(content, style=None, wrap=...), box(*children, **opts), vstack/hstack/zstack, center, blank(), nothing().
  • box opts mirror maya's BoxBuilder 1:1: direction, wrap, gap, padding, margin, border, border_color, border_sides, border_text, border_text_end, bg, fg, style, overflow, grow, shrink, basis, align, align_self, justify, and width/height/min_*/max_* (each accepts an int, "50%", "auto", or a Dimension).
  • component(fn, grow=..., width=..., height=...) — a lazy element whose fn(width, height) runs once layout allocates a size and returns the tree to fill it.
  • scroll_state(), viewport(content, state, width=, height=), scrollbar(state, size, axis=, style=), scroll_handle(state, ev) — the scrollable-window + scrollbar pair (maya's ScrollState + scrollbar_y/x).
  • Styles compose with |: maya.bold | maya.fg(255, 128, 0), or maya.style(fg=(80,220,120), bold=True).
  • render_to_string(element, width=80), print(element), live(render_fn, fps=30), run(event_fn, render_fn, ...).
  • Event predicates: key(ev, "q"), key_special(ev, SpecialKey.Up), ctrl(ev, "c"), alt(ev, "x"), any_key(ev), resized(ev).

Notes

maya's compile-time DSL (t<"...">, type-state pipes) is resolved by the C++ compiler and can't cross the Python boundary, so maya-py routes everything through maya's equivalent runtime builders. The element trees produced are identical — anything the DSL can express, the runtime API can too.

The widget functions wrap maya's own widget classes (Sparkline, Gauge, Table, ...) and return the Element they build, so what you see is maya's native rendering, not a Python reimplementation. Interactive controls that need maya's Program runtime + focus + signals (Input, TextArea, full List/Tree navigation) aren't wrapped — drive interactivity from the App class instead.

Performance

Honest numbers from examples/bench.py and examples/bench_live.py (30-row dashboard, this machine — yours will differ):

Rendering to a string (one-shot output). Here a tuned pure-Python renderer still edges ahead — building the element tree in Python and crossing pybind11 costs more than maya's native render saves:

path per render
maya-py (build + render) ~145 µs
pure-Python equivalent ~70 µs

~80% of maya-py's time is the Python tree construction + boundary crossing, not maya — the native render itself is only ~24 µs. So if you only render static output once, a pure-Python lib like Rich is still a touch faster (now ~2×, down from ~5×).

Live redraw to a terminal (what maya is built for). When you redraw a frame and only part changed, maya's SIMD cell-diff emits only the changed cells. A string renderer must re-emit the whole frame:

path bytes written / frame
maya-py (diff) ~112 B
re-emit whole frame ~1238 B

maya writes ~11× fewer bytes to the terminal. On a real tty — especially over SSH or a slow connection — bytes-on-wire is the bottleneck, and this is a decisive win. This is the scenario maya was designed for.

Making it fast

Three levers close most of the Python-side gap:

  1. Fluent styling is free. T("x").bold.fg("sky") accumulates state in pure Python and makes a single boundary crossing when the element is built (4.8× faster than the naive one-call-per-.bold approach).

  2. Pass styled cells as tuples to skip the T objects. row/col accept (text, fg[, bg[, attrs]]) tuple specs directly — in a hot redraw path (tables, lists, dashboards) the throwaway T per cell is the dominant build cost, and the tuple form flattens the whole row in one boundary crossing. Byte-identical output, same API:

    from maya_py import row, T, c, DIM
    
    # reads nicer for one-off UI:
    row(T(name).fg("sky"), c(status, color), T(latency).dim, gap=2)
    # faster (tuple cells, zero T allocations — use in per-frame loops):
    row((name, "sky"), (status, color), (latency, None, None, DIM), gap=2)
    

    You can mix both, and any built Element / nested box / component child transparently falls back to the general path — so row(sidebar, grow(main)) still works. (trow/tcol are kept as back-compat aliases; new code can just use row/col.)

  3. memo caches unchanged sub-trees. In a live app, wrap builders whose inputs rarely change — the hot frame then does no Python tree construction, just maya's native diff:

    from maya_py import memo, card, col, b
    
    @memo
    def header(title, count):     # rebuilt only when title/count change
        return card(b(title), f"{count} items")
    
    def view(s):
        return col(header(s.title, len(s.items)), body(s))
    

Bottom line: building a UI in Python always costs Python calls, but the thing that actually matters in a terminal — the per-frame redraw — is now faster than a hand-tuned pure-Python renderer: maya's native layout + paint renders the cached tree in ~25µs vs ~70µs for the bespoke string-builder in examples/bench.py, while still doing real flexbox, wrapping, and a partial-frame diff. memo + tuple-cell row/col let the steady-state frame skip Python almost entirely.

License

MIT (same as maya).

Metadata

Release files for maya-py 0.2.11

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for maya-py 0.2.11
File Size Uploaded
maya_py-0.2.11.tar.gz 13.5 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for maya-py 0.2.11
File
maya_py-0.2.11-cp314-cp314-win_amd64.whl CPython 3.14 CPython 3.14 Windows x86-64 Details
maya_py-0.2.11-cp314-cp314-manylinux_2_28_x86_64.whl CPython 3.14 CPython 3.14 Linux glibc 2.28+ x86-64 Details
maya_py-0.2.11-cp314-cp314-macosx_11_0_arm64.whl CPython 3.14 CPython 3.14 macOS 11.0+ ARM64 Details
maya_py-0.2.11-cp313-cp313-win_amd64.whl CPython 3.13 CPython 3.13 Windows x86-64 Details
maya_py-0.2.11-cp313-cp313-manylinux_2_28_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.28+ x86-64 Details
maya_py-0.2.11-cp313-cp313-macosx_11_0_arm64.whl CPython 3.13 CPython 3.13 macOS 11.0+ ARM64 Details
maya_py-0.2.11-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details
maya_py-0.2.11-cp312-cp312-manylinux_2_28_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.28+ x86-64 Details
maya_py-0.2.11-cp312-cp312-macosx_11_0_arm64.whl CPython 3.12 CPython 3.12 macOS 11.0+ ARM64 Details
maya_py-0.2.11-cp311-cp311-win_amd64.whl CPython 3.11 CPython 3.11 Windows x86-64 Details
maya_py-0.2.11-cp311-cp311-manylinux_2_28_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.28+ x86-64 Details
maya_py-0.2.11-cp311-cp311-macosx_11_0_arm64.whl CPython 3.11 CPython 3.11 macOS 11.0+ ARM64 Details
maya_py-0.2.11-cp310-cp310-win_amd64.whl CPython 3.10 CPython 3.10 Windows x86-64 Details
maya_py-0.2.11-cp310-cp310-manylinux_2_28_x86_64.whl CPython 3.10 CPython 3.10 Linux glibc 2.28+ x86-64 Details
maya_py-0.2.11-cp310-cp310-macosx_11_0_arm64.whl CPython 3.10 CPython 3.10 macOS 11.0+ ARM64 Details
maya_py-0.2.11-cp39-cp39-win_amd64.whl CPython 3.9 CPython 3.9 Windows x86-64 Details
maya_py-0.2.11-cp39-cp39-manylinux_2_28_x86_64.whl CPython 3.9 CPython 3.9 Linux glibc 2.28+ x86-64 Details
maya_py-0.2.11-cp39-cp39-macosx_11_0_arm64.whl CPython 3.9 CPython 3.9 macOS 11.0+ ARM64 Details

Total release size: 60.3 MB

Release files / maya_py-0.2.11.tar.gz

Download URL maya_py-0.2.11.tar.gz
Size 13.5 MB
Tags Source
SHA-256 checksum
How to use checksums
89b4d3fcc92592307e6b3c2e592befc6a48ea106acd28adcc9061de23d49e535
BLAKE2b-256 checksum
How to use checksums
2d6aeb719204eebea9e22abfaa782b6dbefc7fd22fbbbd115e79bd42f6438c71
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp314-cp314-win_amd64.whl

Download URL maya_py-0.2.11-cp314-cp314-win_amd64.whl
Size 1.3 MB
Tags CPython 3.14 Windows x86-64
SHA-256 checksum
How to use checksums
63a4a4e91d8b857970d42b269e3be5dad9dfb8386c20ab46407023bb3f3e7fb0
BLAKE2b-256 checksum
How to use checksums
9864e6c5920d0c2734a3426b40c460ab126894ac843bb2ea15ff803f8159dfc0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp314-cp314-manylinux_2_28_x86_64.whl

Download URL maya_py-0.2.11-cp314-cp314-manylinux_2_28_x86_64.whl
Size 4.2 MB
Tags CPython 3.14 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
c31a1a3a49035619f0f8429f608cd7e2bb6aa580b44b0660664552d3607d2792
BLAKE2b-256 checksum
How to use checksums
a63648d987a2d9cc8db8f49cf983ff05ffbadedff5e11180d6e44f7d077eb1fe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp314-cp314-macosx_11_0_arm64.whl

Download URL maya_py-0.2.11-cp314-cp314-macosx_11_0_arm64.whl
Size 2.3 MB
Tags CPython 3.14 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
668c8ba78deb427a63bc73a431afde384d5e3195c18eaa81e1f17ca013416a1a
BLAKE2b-256 checksum
How to use checksums
512a3ea8ac67f184a2e3a192459ff35fa476e7fe0b37687078f26becca1b8f83
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp313-cp313-win_amd64.whl

Download URL maya_py-0.2.11-cp313-cp313-win_amd64.whl
Size 1.3 MB
Tags CPython 3.13 Windows x86-64
SHA-256 checksum
How to use checksums
29092e148bcf4dacf8a0fd0b39886407926922dd8b754d4fb8480ca39c2aee1e
BLAKE2b-256 checksum
How to use checksums
8f1e176504415ef9cdcc10090cdf8cf9abd050e61dcf5207d25125e6256710ce
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp313-cp313-manylinux_2_28_x86_64.whl

Download URL maya_py-0.2.11-cp313-cp313-manylinux_2_28_x86_64.whl
Size 4.2 MB
Tags CPython 3.13 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
cd9e0e939f69d1dc274c8a3b88a192aa51264929e97801dfc602fbf9122458ca
BLAKE2b-256 checksum
How to use checksums
0a192cbf487391c9d1bde67ee3055e892dffee7f004d6ce8f9f985a9c349dd05
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp313-cp313-macosx_11_0_arm64.whl

Download URL maya_py-0.2.11-cp313-cp313-macosx_11_0_arm64.whl
Size 2.3 MB
Tags CPython 3.13 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
c9e5f4b522cf57d46b6be48db92bddbd04a8c15062740ce01ddff946f019da32
BLAKE2b-256 checksum
How to use checksums
eca1851d849694b21024eafb8fe0dae0ea0d1dffd918de904ee5274eebb02565
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp312-cp312-win_amd64.whl

Download URL maya_py-0.2.11-cp312-cp312-win_amd64.whl
Size 1.3 MB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
33c5f1e658b33342731b82d9fe206063c86a870317ae04c0a6ce5d3bd1de91eb
BLAKE2b-256 checksum
How to use checksums
229483190bb5014d2dfd5c4852e2032564147a4fb7c85f1b9fb8d38876212f6b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp312-cp312-manylinux_2_28_x86_64.whl

Download URL maya_py-0.2.11-cp312-cp312-manylinux_2_28_x86_64.whl
Size 4.2 MB
Tags CPython 3.12 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
4dd614d3d82d9ff74164071c2d013b6f057a9a33bd2e1f3647dc9f31f6b14af3
BLAKE2b-256 checksum
How to use checksums
4e1372b6a5cea90277441dbec4e3edab802cf53fe1d76448e0daa5bda3225763
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp312-cp312-macosx_11_0_arm64.whl

Download URL maya_py-0.2.11-cp312-cp312-macosx_11_0_arm64.whl
Size 2.3 MB
Tags CPython 3.12 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
7cab2d021d9595bc64aec1990f037559485710ef33ea5f482315a27313c6df3a
BLAKE2b-256 checksum
How to use checksums
51e7464e0c6d4714b1cdc3799ad8eb067b5c5c0978f817a1ea66d3b1221453a2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp311-cp311-win_amd64.whl

Download URL maya_py-0.2.11-cp311-cp311-win_amd64.whl
Size 1.3 MB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
5449cf313b4b4e37a80ca7eb2eae12352bb21205e4df5a89158be315ef285cde
BLAKE2b-256 checksum
How to use checksums
4061f8c034c11ccee9cb33ac8786f3dc5e6ae88265dd1bb6cde72b98ab1cafdf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp311-cp311-manylinux_2_28_x86_64.whl

Download URL maya_py-0.2.11-cp311-cp311-manylinux_2_28_x86_64.whl
Size 4.2 MB
Tags CPython 3.11 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
4ff0b8d7d6bdeb980357513119b61a6ab5652046a1bbf7b08b61306acc09128f
BLAKE2b-256 checksum
How to use checksums
a3ca490e0d5ed1ac282ce52ee3b17d0ff0d26058b827a08de8350ad7e23ca103
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp311-cp311-macosx_11_0_arm64.whl

Download URL maya_py-0.2.11-cp311-cp311-macosx_11_0_arm64.whl
Size 2.3 MB
Tags CPython 3.11 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
ea7399e8a203dcdf6d372e6d9eb5aa98ccc93cca498070b36671477323bba707
BLAKE2b-256 checksum
How to use checksums
ac4aad660ded9a1508dd09e450915e9301a8b1ce4a19d9e7324fb71b1099cd33
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp310-cp310-win_amd64.whl

Download URL maya_py-0.2.11-cp310-cp310-win_amd64.whl
Size 1.3 MB
Tags CPython 3.10 Windows x86-64
SHA-256 checksum
How to use checksums
9f33af8e65c1f0759c1f289612da29eb8cdcabc0a543248a04cb832a53d6197a
BLAKE2b-256 checksum
How to use checksums
53425fd5d0758d4eb89114846b0952474a61c6cfe82eea5f9f75bb1a8a634a3c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp310-cp310-manylinux_2_28_x86_64.whl

Download URL maya_py-0.2.11-cp310-cp310-manylinux_2_28_x86_64.whl
Size 4.2 MB
Tags CPython 3.10 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
e884b2fde9ac6c8159375e90ea01261f791aec71cad60c7d74ccd64963716d1f
BLAKE2b-256 checksum
How to use checksums
e29b4fc02a4b6e8040e0809236364b07a1ac76178415e47b1ff741c63bf9e0c1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp310-cp310-macosx_11_0_arm64.whl

Download URL maya_py-0.2.11-cp310-cp310-macosx_11_0_arm64.whl
Size 2.3 MB
Tags CPython 3.10 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
db917f2d50965c2b83c7cc4893b727f4759fa4461541c295a3a71e3322429c45
BLAKE2b-256 checksum
How to use checksums
771b7e84c3a949a65b035b1aa6ea1d52101458bf56c5833f7428dd95c7050980
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp39-cp39-win_amd64.whl

Download URL maya_py-0.2.11-cp39-cp39-win_amd64.whl
Size 1.3 MB
Tags CPython 3.9 Windows x86-64
SHA-256 checksum
How to use checksums
fdf68dd04fe4177e46f1d6226c340418a84fd2f8a2e617dfa480cc89475d10f3
BLAKE2b-256 checksum
How to use checksums
6eb9906726d4285f5d69b82f498ec111581ebf55ee41da04b231da37e3282461
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp39-cp39-manylinux_2_28_x86_64.whl

Download URL maya_py-0.2.11-cp39-cp39-manylinux_2_28_x86_64.whl
Size 4.2 MB
Tags CPython 3.9 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
12ecf3bad91249e969f332a22021eb2f9927cd891bc3ace4ada6d09853d9ada4
BLAKE2b-256 checksum
How to use checksums
ee274998e9dffdc5a5fc77d2f16e1fce03f31c38eac7d963049dfd11daaa7469
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / maya_py-0.2.11-cp39-cp39-macosx_11_0_arm64.whl

Download URL maya_py-0.2.11-cp39-cp39-macosx_11_0_arm64.whl
Size 2.3 MB
Tags CPython 3.9 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
d401c135b5de5886e3a187bf07eeeeac2214f7a4c1ede0328c3f02ec76b240a1
BLAKE2b-256 checksum
How to use checksums
9bd2fe128189dc3e32f2ae6125977abd8a29ae1f2c007e48aee99c69bbc31913
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.1

19 release files

This release

0.2.11 This release

19 release files

0.2.9

19 release files

0.2.8

19 release files

0.2.7

19 release files

0.2.6

19 release files

0.2.5

13 release files

0.2.3

19 release files

0.2.2

19 release files

0.2.1

19 release files

0.2.0

19 release files

0.1.6

19 release files

0.1.5

19 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page