🪟 orcsome3
Python 3 scripting for a NETWM-compliant X11 window manager you already run (Openbox, etc.). It is not a window manager.
Based in orcsome. Linux / X11 only. Requires Python 3.8 or newer (3.8, 3.9, 3.10, … current).
You write ~/.config/orcsome3/config.py. orcsome3 grabs keys, watches window create/destroy/property/focus, can change EWMH state and icons, and can post desktop notifications over D-Bus.
🏗️ Architecture
config.py (your script)
└─ orcsome3 WindowManager, Window, Notification, get_wm, keys
└─ orcsome3.libs.xlib / ev typed Python wrappers
└─ orcsome3_backend.so Cython (Xlib + statically linked ev / cairo / Magick / gd / resvg)
└─ libX11, libXext, libXss, libXtst (system, dynamic)
- Public API lives in
orcsome3/(get_wm,window_manager,notify,keys). That is whatconfig.pyshould import. - Only
orcsome3.libs.xlibandorcsome3.libs.evimportorcsome3_backend. Do not import the.sofromconfig.py. - The backend is typed via a generated
orcsome3_backend.pyi(make stubs). The package shipspy.typed. - libev, Cairo, ImageMagick 7, gd, resvg (and their image-format deps) are downloaded and statically linked into the
.so. You do not install ImageMagick from source yourself. X11 stays a normal system library.
✨ What you can do
- Global and per-window hotkeys (
XGrabKey), including CapsLock/NumLock variants - React to window create / manage / destroy / property / focus
- NETWM/EWMH: desktops, maximize, fullscreen, decorations, close, move/resize, icons —
set_icontakes SVG (via resvg) or PNG/JPEG/GIF/BMP/ICO/WebP/TIFF/… (via ImageMagick 7), not just one format - Freedesktop notifications (
dbus-next→org.freedesktop.Notifications) - Typed
config.py(mypy / basedpyright)
📦 Install
libev, Cairo, ImageMagick 7, gd, and resvg are all statically linked into orcsome3_backend.so. Whether you install the wheel from PyPI or build from source, you never install any of them yourself — the only external runtime dependency is X11.
X11 libraries
orcsome3 needs the usual X11 client libraries (libX11, libXext, libXss, libXtst). A Linux desktop almost always has them already. Install them only if the module fails to load:
# Debian / Ubuntu
sudo apt install libx11-6 libxss1 libxext6 libxtst6
# Arch
sudo pacman -S libx11 libxss libxext libxtst
Python deps (dbus-next, typing_extensions) come with the package.
From PyPI
python3 -m pip install orcsome3
Linux manylinux wheels cover CPython 3.8 through current (3.15 as of cibuildwheel 4.2). No musllinux, free-threaded (3.14t, …), Windows, or macOS. A GitHub Release (or Upload Python Package from Actions) publishes the sdist and wheels. Bump the pypa/cibuildwheel pins in .github/workflows/python-publish.yml when a new CPython ships.
Build from source
First-time native build fetches git/tarball sources and compiles static libs. You need a C/C++ toolchain, the X11 headers, and:
# Debian / Ubuntu
sudo apt install git cmake autoconf automake libtool pkg-config meson ninja-build \
libx11-dev libxss-dev libxext-dev libxtst-dev curl
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y # resvg
# Arch
sudo pacman -S git cmake autoconf automake libtool pkgconf meson ninja \
libx11 libxss libxext libxtst rust
Then:
git clone https://github.com/ahsand97/orcsome3.git
cd orcsome3
make native # static libs + orcsome3_backend.so (slow once)
python3 -m pip install .
pip install . reuses orcsome3_built_libraries/; it does not download those libs again. Run make native first on a clean clone.
To hack without installing the package:
make dev # venv + deps + native
make run # python -m orcsome3 (needs ~/.config/orcsome3/config.py)
🚀 Quick start
Create ~/.config/orcsome3/config.py (or pass -c). If the file is missing, orcsome3 logs an error and exits.
Every hook except on_init/on_deinit/on_timer calls back as (window, event) — on_key/on_button/on_create and friends all follow this shape, so there's one pattern to learn. Most take window=None (every window) or window= a specific id (typically the window parameter from on_manage, nested). wm.event_window still works as a side-channel (e.g. from code that isn't itself inside a callback), but the parameter is what you'll normally use. Decorated functions get .remove() to unregister.
Decorators
@wm.on_init/@wm.on_deinit— no parentheses, no arguments.on_initruns once at startup after root events are selected, before existing clients are scanned.on_deinitruns instop()after key/button grabs and timers are torn down.@wm.on_key(...)—XGrabKeyon KeyPress. Default is a global hotkey (grab on the root). The callback'swindowis that grab window; usewm.current_windowfor the focused client. Passwindow_matcher=to grab on matching clients instead. orcsome3 consumes the key unlesspropagate_event=True. CapsLock/NumLock variants are grabbed for you."Control + b"or aKeyDefinition; modifiersControl/Ctrl,Alt/Meta,Shift,Win/Super,AnyModifier; keys are X keysym names (XK_stripped).@wm.on_key_release(...)— same grab ason_key, but KeyRelease. Register both for the same combo; they share oneXGrabKey.@wm.on_button(...)—XGrabButtonon ButtonPress (BUTTONS.Button1…Button5orAnyButton). Same root-vs-window_matcherandpropagate_eventrules ason_key.@wm.on_create(...)— CreateNotify, including windows already mapped when orcsome3 starts. Optionalmatcher=WindowMatchers(...).eventisNonefor that startup sweep (no real CreateNotify exists for windows that already existed) and a realXCreateWindowEventotherwise.@wm.on_manage(...)— same ason_create, but skips the startup sweep, soeventis always a realXCreateWindowEvent, neverNone. Nest per-window@wm.on_destroy(window=...)(and similar) here so you do not attach once per existing client.@wm.on_destroy(...)— DestroyNotify.windowis only that id; reading properties on it will fail (it is already gone).@wm.on_property_change(property="...")— PropertyNotify when an atom (_NET_WM_STATE, …) gets a new value.@wm.on_focus()/@wm.on_unfocus()— FocusIn / FocusOut (NotifyNormal/NotifyWhileGrabbedonly; pointer-detail and grab-notify are ignored).@wm.on_map()/@wm.on_unmap()/@wm.on_configure()— MapNotify / UnmapNotify / ConfigureNotify. Configure fires often during resize; size isevent.width/event.height(not a laterget_geometry()).@wm.on_client_message(message_type="...")— ClientMessage filtered by atom name (_NET_ACTIVE_WINDOW, …).@wm.on_timer(timeout=...)— repeating libev timer (seconds), callback takes no arguments. ReturnTrueto stop;None/falsy keeps it. Also.start()/.stop()/.again(). Needs the process event loop (normalorcsome3has one).
Example config.py:
from pathlib import Path
from typing import Optional
from orcsome3 import get_wm
from orcsome3.keys import KeyboardModifiers, KeyDefinition, WindowMatchers
from orcsome3.libs.xlib import (
BUTTONS,
XButtonEvent,
XClientMessageEvent,
XConfigureEvent,
XCreateWindowEvent,
XDestroyWindowEvent,
XFocusChangeEvent,
XKeyEvent,
XMapEvent,
XPropertyEvent,
XUnmapEvent,
)
from orcsome3.notify import Notification
from orcsome3.window_manager import Window, WindowManager
wm: WindowManager = get_wm()
# Hide the title bar while a window is maximized, restore it otherwise.
@wm.on_property_change(property="_NET_WM_STATE")
def hide_title_bar_when_maximized(window: Window, event: XPropertyEvent) -> None:
if window.maximized_horz and window.maximized_vert:
if window.decorated:
window.set_state(decorate=False)
elif not window.decorated:
window.set_state(decorate=True)
@wm.on_init
def on_start() -> None:
print("orcsome3 started")
@wm.on_deinit
def on_stop() -> None:
print("orcsome3 stopping")
# Global hotkey. `window` is root; focused client is `wm.current_window`.
@wm.on_key(key_definition="Control + b")
def on_control_b(window: Window, event: XKeyEvent) -> None:
print("Control + b")
# Per-client grab (every URxvt, including ones already mapped after init).
@wm.on_key(
key_definition=KeyDefinition(modifiers=KeyboardModifiers.Control, key=KeyDefinition.Key(name="d")),
window_matcher=WindowMatchers(class_="URxvt"),
)
def close_urxvt(window: Window, event: XKeyEvent) -> None:
window.close()
@wm.on_key_release(key_definition="Control + b")
def on_control_b_up(window: Window, event: XKeyEvent) -> None:
print("Control + b released")
@wm.on_button(button=BUTTONS.Button1, modifiers=KeyboardModifiers.Control)
def on_ctrl_click(window: Window, event: XButtonEvent) -> None:
print(event.x, event.y)
# `event` is None during the startup sweep (no real CreateNotify for windows that already existed).
@wm.on_create()
def on_any_create(window: Window, event: Optional[XCreateWindowEvent]) -> None:
print(window.get_name_and_class())
@wm.on_manage(matcher=WindowMatchers(name="easyeffects", class_="easyeffects"))
def on_easyeffects(window: Window, event: XCreateWindowEvent) -> None:
# .svg goes through resvg; any other extension (.png, .jpg, .ico, …) goes through ImageMagick
window.set_icon(icon=Path("/path/to/icon.svg"))
@wm.on_destroy(window=window)
def on_easyeffects_gone(window: Window, event: XDestroyWindowEvent) -> None:
print("easyeffects closed")
@wm.on_destroy()
def on_any_destroy(window: Window, event: XDestroyWindowEvent) -> None:
print(f"destroyed {window}")
@wm.on_focus()
def on_focus(window: Window, event: XFocusChangeEvent) -> None:
print(f"focus {window}")
@wm.on_unfocus()
def on_unfocus(window: Window, event: XFocusChangeEvent) -> None:
print(f"unfocus {window}")
@wm.on_map()
def on_map(window: Window, event: XMapEvent) -> None:
print(f"mapped {window}")
@wm.on_unmap()
def on_unmap(window: Window, event: XUnmapEvent) -> None:
print(f"unmapped {window}")
@wm.on_configure()
def on_configure(window: Window, event: XConfigureEvent) -> None:
print(window, event.width, event.height)
@wm.on_client_message(message_type="_NET_ACTIVE_WINDOW")
def on_active(window: Window, event: XClientMessageEvent) -> None:
print(window, event.message_type)
@wm.on_timer(timeout=60.0)
def every_minute() -> Optional[bool]:
print("tick")
return None # return True to stop
@wm.on_manage(matcher=WindowMatchers(name="Navigator", class_="firefox", window_type=["_NET_WM_WINDOW_TYPE_NORMAL"]))
def firefox_opened(window: Window, event: XCreateWindowEvent) -> None:
n: Notification = Notification(
app_name="Firefox",
summary="Firefox is now open!",
body="<b>Notification body</b>",
actions=[Notification.Action(visible_name="Action #1", callback=lambda: print("Action #1"))],
on_close=lambda: print("notification closed"),
hints=Notification.Hints(urgency=Notification.Hints.Urgency.NORMAL),
)
n.show()
Then:
orcsome3
# or: python3 -m orcsome3
Useful flags: --config PATH, --log-file PATH, --log-level DEBUG, --version.
One process per $DISPLAY (lock under $XDG_RUNTIME_DIR/orcsome3/). Extra monitors on the same X server share that instance. A second X server (Chrome Remote Desktop, VNC, :1) is a separate process and does not steal grabs from :0. Saving the loaded config reloads it automatically (or send SIGUSR1). SIGINT / SIGTERM quit.
If the config file fails to load (syntax error, exception at import time), orcsome3 does not crash — it logs the exception and keeps running with no handlers installed until the next successful reload. This applies to the very first load too. A missing --config path is different and still exits at startup; a broken file at a real path does not. See the tray icon below for how that error is surfaced.
🖱️ Tray icon
A tray icon appears when your panel has a StatusNotifier (SNI) host — most do (KDE, LXQt, many tint2/Waybar/Polybar setups, etc.). If no host is on the session bus, there is no icon; signals still work. The icon is rendered straight from the packaged SVG into the D-Bus pixmap (via resvg, already a build dependency) — nothing is ever copied into ~/.local/share/icons or left behind on uninstall.
Right-click for the menu:
- Config:
<path>— the config file currently loaded (informational). - Error:
...— only shown while the config has a load error; same text as the icon's tooltip. The icon itself also switches to a distinct "error" variant (red dot) while this is active, and a desktop notification fires too if a notification daemon is running. Clears on the next successful reload. - Change config file... — only shown if
zenityorkdialogis installed on your system; opens a file picker and switches to the selected config live (no restart). - Quit — sends
SIGTERM.
🛠️ Develop
| Command | What it does |
|---|---|
make native |
Download/build static libs and compile the Cython backend |
make native-fast |
Re-cythonize/link only (needs a prior native) |
make native-rebuild |
Wipe the lib cache and rebuild |
make stubs |
Regenerate orcsome3_backend.pyi from the .pyx (needs the .so) |
make format / make lint |
ruff, mypy, basedpyright, extra checks, stub --check |
make test |
unittest in tests/ (X tests skip if the display cannot be opened; grab delivery prefers Xephyr/Xvfb) |
make clean |
Build artifacts, orcsome3_built_libraries/, .so |
Do not hand-edit generated .c files or orcsome3_built_libraries/.
python -m orcsome3.libs.build --build-dir . is the same as make native. --dynamic links system libev/gd/Magick instead of the static copies.
📄 License
MIT. See LICENSE.
Metadata
Release files for orcsome3 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| orcsome3-1.0.0.tar.gz | 456.1 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| orcsome3-1.0.0-cp315-cp315-manylinux_2_28_x86_64.whl | CPython 3.15 | CPython 3.15 | Linux glibc 2.28+ x86-64 | Details |
| orcsome3-1.0.0-cp314-cp314-manylinux_2_28_x86_64.whl | CPython 3.14 | CPython 3.14 | Linux glibc 2.28+ x86-64 | Details |
| orcsome3-1.0.0-cp313-cp313-manylinux_2_28_x86_64.whl | CPython 3.13 | CPython 3.13 | Linux glibc 2.28+ x86-64 | Details |
| orcsome3-1.0.0-cp312-cp312-manylinux_2_28_x86_64.whl | CPython 3.12 | CPython 3.12 | Linux glibc 2.28+ x86-64 | Details |
| orcsome3-1.0.0-cp311-cp311-manylinux_2_28_x86_64.whl | CPython 3.11 | CPython 3.11 | Linux glibc 2.28+ x86-64 | Details |
| orcsome3-1.0.0-cp310-cp310-manylinux_2_28_x86_64.whl | CPython 3.10 | CPython 3.10 | Linux glibc 2.28+ x86-64 | Details |
| orcsome3-1.0.0-cp39-cp39-manylinux_2_28_x86_64.whl | CPython 3.9 | CPython 3.9 | Linux glibc 2.28+ x86-64 | Details |
| orcsome3-1.0.0-cp38-cp38-manylinux_2_28_x86_64.whl | CPython 3.8 | CPython 3.8 | Linux glibc 2.28+ x86-64 | Details |
Total release size: 135.8 MB
Release files / orcsome3-1.0.0.tar.gz
| Download URL | orcsome3-1.0.0.tar.gz |
|---|---|
| Size | 456.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8b02bb68af1b20e94845748caae7da6a56333b1fcdff0ef07d9916a16a31e0a8
|
|
BLAKE2b-256 checksum How to use checksums |
5936fb3afed6977ef207a22edbcac5183367981a94cd33da366e2cee5542ed9b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 31, 2026.
Transparency logRelease files / orcsome3-1.0.0-cp315-cp315-manylinux_2_28_x86_64.whl
| Download URL | orcsome3-1.0.0-cp315-cp315-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 17.0 MB |
| Tags | CPython 3.15 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
032dbefb19c2a8b6a2c4d4d38b3552677637de32edbb970fa727f139b8d5a56d
|
|
BLAKE2b-256 checksum How to use checksums |
e77a9bc5dc6ae28226cfb2efa2fda901f59423489fadde5ba30ef8d00969e90a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 31, 2026.
Transparency logRelease files / orcsome3-1.0.0-cp314-cp314-manylinux_2_28_x86_64.whl
| Download URL | orcsome3-1.0.0-cp314-cp314-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 16.9 MB |
| Tags | CPython 3.14 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
e5502061d72ae0813c399f74bfc81402061ec8d2bd85a51550450106e020e151
|
|
BLAKE2b-256 checksum How to use checksums |
10a22988b177a3d3e74019e997ccd1f1486f85b1506c4b22aecdc0f6948a7e0e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 31, 2026.
Transparency logRelease files / orcsome3-1.0.0-cp313-cp313-manylinux_2_28_x86_64.whl
| Download URL | orcsome3-1.0.0-cp313-cp313-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 17.0 MB |
| Tags | CPython 3.13 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
58da0f2995a1d77bcb4e285d5762a097d0a38acb370bc70cb423c6ac4d6bdf97
|
|
BLAKE2b-256 checksum How to use checksums |
9b216b9b8a6a0b67c466e527c3314ae1aa61073ef35f8b9289fb3f1e6e66e11f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 31, 2026.
Transparency logRelease files / orcsome3-1.0.0-cp312-cp312-manylinux_2_28_x86_64.whl
| Download URL | orcsome3-1.0.0-cp312-cp312-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 17.0 MB |
| Tags | CPython 3.12 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
12de965a10f26cd9e730185bb5c8560b8dfdccdfe27858d8843bfb272751a0ee
|
|
BLAKE2b-256 checksum How to use checksums |
1e470e6c39b9a57ed4dd3fb439d1810d5223e7bd3f563ecfbc60b4f44759329a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 31, 2026.
Transparency logRelease files / orcsome3-1.0.0-cp311-cp311-manylinux_2_28_x86_64.whl
| Download URL | orcsome3-1.0.0-cp311-cp311-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 17.0 MB |
| Tags | CPython 3.11 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
2f48c3d674b76d6f3be51c52288f7bcbb57f6ce61d65bab4ce6efc9a3cd5af2d
|
|
BLAKE2b-256 checksum How to use checksums |
1498a8600a47e022a8266de54fae0b72daf6778956f347451bf29bd59f9f37a0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 31, 2026.
Transparency logRelease files / orcsome3-1.0.0-cp310-cp310-manylinux_2_28_x86_64.whl
| Download URL | orcsome3-1.0.0-cp310-cp310-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 16.9 MB |
| Tags | CPython 3.10 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
04bf00b842c0a8b1d9a28eff01827eb918e41f76ba86bb8d7b424a87ea511001
|
|
BLAKE2b-256 checksum How to use checksums |
e0fbc4d60bb40034da3a18dcdf0f3fc288a6459c1596fa43cd78ab85191ce6db
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 31, 2026.
Transparency logRelease files / orcsome3-1.0.0-cp39-cp39-manylinux_2_28_x86_64.whl
| Download URL | orcsome3-1.0.0-cp39-cp39-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 16.9 MB |
| Tags | CPython 3.9 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
962c761a7390b73a9ceaa580448c24f4c8e9e9d4b99f1d5a9f2fdb00a455f7fd
|
|
BLAKE2b-256 checksum How to use checksums |
54e5dce8b615977733d1b5ffa0f43acf68230104c5b6f5ee9108928ea7a369ab
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 31, 2026.
Transparency logRelease files / orcsome3-1.0.0-cp38-cp38-manylinux_2_28_x86_64.whl
| Download URL | orcsome3-1.0.0-cp38-cp38-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 16.7 MB |
| Tags | CPython 3.8 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
16675e08e9cd4359f5e845abcc93aeb81238cf6a1f283579601d782f37c704e9
|
|
BLAKE2b-256 checksum How to use checksums |
4d0057039c8dc43465a511c89efddf984e7b17767dd20a9edf4e0be12153a77c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 31, 2026.
Transparency log