Skip to main content

structguru

A native structured logging library with a loguru-style API.

Combines a loguru-style API — brace formatting, bind, contextualize, opt, sink management — with a native Rust renderer for maximum performance. Since v1.0, the Rust extension is the default (and only) rendering path; structlog and orjson are no longer dependencies.

Features

  • Loguru-style API — logger.info("User {id} logged in", id=123)
  • Structured JSON output in production (rendered natively in Rust for speed)
  • Pretty colored console output in development
  • Context management — bind() for persistent context, contextualize() for request-scoped context
  • Sentry integration — redacted breadcrumbs/events with raw exceptions preserved for capture
  • stdlib interop — logger.add() sinks can also receive third-party logging records
  • RFC 5424 severity codes included in every log record
  • Native Rust runtime — rendering and output run through the bundled abi3 extension
  • Fully typed — PEP 561 compliant with strict mypy

Native processing:

  • Redaction — mask sensitive fields (passwords, tokens) by key name or regex
  • Sampling — probabilistic and rate-limited log suppression
  • Metrics — extract counters/histograms from log events via callbacks
  • Exception formatting — render exc_info as text or a structured frame dictionary
  • Off-thread logging — native Rust writer with a bounded queue and backpressure
  • OpenTelemetry — automatic trace_id/span_id injection from current span

Framework integrations (optional dependencies):

  • ASGI (FastAPI, Starlette) — request ID, timing, context binding middleware
  • Celery — task context binding and cross-worker context propagation via headers
  • Flask — before/after request hooks with request ID tracking
  • Django — logging dict config builder and request middleware
  • SQLAlchemy — slow query detection and logging
  • gRPC — server interceptor with per-RPC context binding
  • Sentry — forward log events as breadcrumbs/events with configurable severity

Installation

pip install structguru

With optional integrations:

pip install structguru[celery,flask,sentry]  # pick what you need
pip install structguru[all]                   # everything

Available extras: otel, celery, flask, django, sqlalchemy, grpc, sentry, httpx, requests, all.

Quick start

from structguru import Logger, configure, logger

# Configure once at startup
configure(service="myapp", level="DEBUG", format="json")

# Use anywhere
logger.info("Hello {name}", name="world")
# → {"logger":"...","level":"INFO","severity":6,"timestamp":"...","service":"myapp","message":"Hello world"}

# Or choose an explicit module name
log = Logger(name=__name__)

Configuration

Call configure() once at startup. Each call replaces the previous configuration: explicit keywords override environment values, which override built-in defaults. Use update() to retain existing options while changing selected ones:

from structguru import Settings, configure, get_config, update

configure(service="checkout", sensitive_patterns=[r"token=\w+"])
update(otel=True, structured_exceptions=True)  # retains service and redaction
current = get_config()  # Settings, or None after shutdown()

# Applications can load a mapping themselves; no files are read automatically.
settings = Settings.from_mapping({"service": "checkout", "level": "DEBUG"})
configure(settings)  # uses this object instead of environment values

Settings.from_env() resolves environment values without applying them; pass a mapping instead of using the process environment when testing. Settings validates Python values and freezes collections. Native regex compilation and file access are checked when configuring; failure leaves the previous runtime active. Explicit keywords, including None and built-in default values, win over the selected base.

update() never rereads the environment and requires an active runtime. An empty update does nothing. Level-only updates and set_level() preserve queues and rate-limit state; other updates rebuild writers and reset filter state. Snapshots describe configured options, not buffered records, counters, stdlib bridge state, or logger.add() sinks. Those registered sinks survive reconfiguration. Streams and callbacks retain their identity.

Levels accept case-insensitive names (including NOTSET) or non-negative integer thresholds. Unknown names, booleans and negative integers raise ValueError.

Environment configuration

Variable Default Compatibility fallback
STRUCTGURU_SERVICE app —
STRUCTGURU_LEVEL INFO LOG_LEVEL
STRUCTGURU_TARGET stdout STRUCTGURU_NATIVE_TARGET
STRUCTGURU_FORMAT json —
STRUCTGURU_SAMPLE_RATE 1.0 STRUCTGURU_NATIVE_SAMPLE_RATE
STRUCTGURU_RATE_LIMIT disabled; period defaults to 60 seconds STRUCTGURU_NATIVE_RATE_LIMIT
STRUCTGURU_AUTOCONFIGURE enabled inverse of STRUCTGURU_LEGACY

New names win over their fallbacks; old names remain supported without warnings. Level variables accept a name or a non-negative integer threshold (LOG_LEVEL=10). Rate limits use MAX or MAX/PERIOD, with integer counts and seconds for the period. Autoconfiguration accepts 1/0, true/false, yes/no, or on/off and controls import only. Set it to 0 before import to configure explicitly later. Invalid selected values fail validation; an invalid import-time value must be corrected or autoconfiguration disabled before the application can call configure().

File output, redaction, exceptions and other settings currently use Python configuration. The stdlib bridge retains its separate STRUCTGURU_STDLIB_* options and explicit installer.

Usage

Log levels

logger.debug("Debug message")
logger.info("Info message")
logger.warning("Warning message")
logger.error("Error message")
logger.critical("Critical message")

# Aliases
logger.trace("Maps to DEBUG")
logger.success("Maps to INFO")
logger.warn("Alias for warning")
logger.fatal("Alias for critical")

Brace formatting

Arguments used in str.format placeholders are consumed by formatting (matching loguru behaviour). Extra kwargs that are not in any placeholder are forwarded as structured fields:

logger.info("User {user_id} logged in", user_id=42, ip="10.0.0.1")
# message: "User 42 logged in"
# ip: "10.0.0.1"  (extra kwarg kept as structured field)
# user_id is consumed by formatting and not duplicated

The message is formatted whenever positional or keyword arguments are passed, as str.format would ("a }} b" becomes "a } b"); exc_info and stack_info alone do not count, so logger.exception("{{x}}") logs {{x}} like logger.error. Fields named in a nested format spec ("{x:{width}}") are consumed too. A placeholder that names a sensitive key — as the root ({token}) or an attribute or index ({creds[password]}) — is interpolated as [REDACTED]. A mapping, sequence, set, dataclass, or namespace interpolated whole ({creds}) renders with the values under sensitive keys redacted; other objects' own str() text is covered by sensitive_patterns only. The message is positional-only, so message= and self= are ordinary fields. A template that fails to format, or a message whose str() raises, is logged raw or as a placeholder with a one-shot UserWarning; logging calls do not raise for their arguments.

Bound context

log = logger.bind(request_id="abc-123", user="alice")
log.info("Processing request")  # includes request_id and user
log.info("Request complete")  # same context carried through

Request-scoped context

with logger.contextualize(request_id="abc-123"):
    logger.info("Handling request")  # includes request_id
    do_work()  # any logging inside also gets request_id
# request_id removed automatically

Exception logging

try:
    risky_operation()
except Exception:
    logger.exception("Operation failed")  # logs with exc_info at ERROR level

# Or with opt():
logger.opt(exception=True).error("Something went wrong")

Sink management

# Add a file sink
handler_id = logger.add("/var/log/app.log", level="ERROR")

# Add a callable sink
logger.add(lambda msg: send_to_monitoring(msg), level="CRITICAL")

# Remove a specific sink
logger.remove(handler_id)

# Remove all added sinks
logger.remove()

Handler ids are process-wide: any Logger can remove a sink that another one added. Removing an id that names no active sink raises ValueError (a non-integer raises TypeError), as in loguru; remove() without an id removes the sinks added through that logger and its bind()/opt() children. level accepts a name or a non-negative integer and raises ValueError for anything else, like configure(level=...). A logging.Handler passed to add() keeps its own level and formatter: its formatter wraps the rendered line, only level gates what it receives, and remove() closes it.

On Unix, new files created by either logger.add(path) or the native rotating file sink are owner-only (0600). Existing files retain their permissions.

All sink forms receive structguru records. They are also registered with the stdlib root logger for third-party records, which arrive raw (unrendered) on that path. Install the stdlib bridge to receive them rendered and redacted instead — while it is installed the raw delivery is suspended, so a sink never sees the same record twice.

Logs emitted inside a sink callback, whether it received a native record or a raw stdlib one, reach the native writer but skip callable and logger.add() sinks, preventing recursive delivery and worker deadlocks. Outside callbacks, logger.remove() waits for producers that already selected the removed sink and for raw stdlib deliveries in progress. Lifecycle calls inside a callback, including a stdlib handler's emit() on the raw path, cannot wait for the worker; previously selected deliveries finish as that worker drains. For native file/stdout mirroring, writer_metrics()["sink_errors"] includes failed destinations even when another destination successfully writes the record.

Native delivery uses the bounded callable queue and is drained on reconfiguration, shutdown(), fork, and interpreter exit. Call structguru.flush() when you need to block until buffered records have actually been written:

import structguru

logger.info("checkpoint")
structguru.flush()  # returns once the line has reached its sink

Console vs JSON output

format= selects the renderer: "json" (default, production) or "console" (colored, human-readable development output).

# JSON (production)
update(service="myapp", format="json")
# → {"logger":"...","level":"INFO","severity":6,"timestamp":"...","service":"myapp","message":"..."}

# Console (development) — colored, human-readable
update(service="myapp", format="console")
# → 2026-01-15T12:00:00.123456Z [INFO    ] Hello world

Native processing

Redaction

Mask sensitive fields automatically:

from structguru import update

update(
    sensitive_keys=["password", "token", "ssn"],
    sensitive_patterns=[r"\b\d{3}-\d{2}-\d{4}\b"],
    pattern_replacement="***",
)

Patterns apply to the message, field names, and string values at any depth, and to integers by their decimal digits (a matching integer is emitted as the redacted string). If redaction makes two keys of one map equal, the record keeps one key with the last value.

Patterns run on Rust's linear-time regex engine (no ReDoS), which rejects look-around and backreferences at update() time. Most look-behinds rewrite as capture groups — (?<=password=)\S+ becomes (password=)\S+ with pattern_replacement="$1[REDACTED]", so the prefix is re-emitted and the secret is replaced (password=hunter2 → password=[REDACTED]). Put the capture group around the part you want to keep, never around the secret. For patterns that can't be rewritten, allow_backtracking_patterns=True opts them into a bounded backtracking engine: look-around and backreferences then work as written, at the cost of the linear-time guarantee for those patterns. If a value ever exceeds the backtrack limit, it is redacted entirely (fail-closed) rather than emitted unchecked.

update(
    sensitive_patterns=[r"(?<=password=)\S+"],
    allow_backtracking_patterns=True,
)

Sampling & rate limiting

Suppress noisy logs:

from structguru import update

update(sample_rate=0.1, rate_limit_max=5, rate_limit_period=60)

Metric extraction

Derive metrics from log events:

from structguru import MetricProcessor, update

metrics = MetricProcessor()
metrics.counter("user.login", lambda ed: login_counter.inc())
metrics.histogram("db.query", "duration_ms", lambda v, ed: query_hist.observe(v))

update(metric_processor=metrics)

Exception formatting

Render exceptions as JSON-serializable dictionaries:

from structguru import update

update(structured_exceptions=True, exception_max_frames=20)

exception_max_frames=0 omits traceback frames entirely. Negative frame and local-representation limits are rejected during configuration.

Formatted tracebacks (the default) carry CPython's per-frame position markers, the ~~~^^^ lines, and on Python 3.11+ computing them is most of the cost of logger.exception(). exception_carets=False omits them, which formats a traceback about five times faster and matches what CPython prints under PYTHONNODEBUGRANGES=1:

update(exception_carets=False)

OpenTelemetry correlation

Inject trace context into every log event:

from structguru import update

update(otel=True)  # no-op injection when opentelemetry-api is absent

Non-blocking logging

Since v1.0, log I/O is offloaded to a background thread by default. The native Rust writer uses a bounded 8192-record queue and waits for space while it is open. Set overflow="drop" to favor caller latency, or explicitly pass maxsize=0 only when an unbounded queue is acceptable.

Native runtime

structguru ships a required Rust extension that renders and enqueues logging natively, off-thread. It is auto-enabled at import time, and importing the package without the extension raises RuntimeError. The runtime does not depend on orjson; exotic values (datetime, UUID, Enum, dataclasses) are converted natively in Rust.

A field value the renderer cannot represent never fails the record. It is replaced by a marker so the message, level, remaining fields, and exception traceback still ship:

  • <unsupported: WSGIRequest> for any other object (Decimal, bytes, set, Path, request objects, ...). The marker names the type only: structguru never calls str()/repr() on an arbitrary object or reads its attributes, so nothing it holds can leak into a log line.
  • <cycle: dict> for a container that refers back to itself.
  • <max depth exceeded> beyond 64 levels of nesting.

Integers outside the 64-bit range are written as JSON numbers, int and float subclasses (such as numpy.float64) are written by value, non-string mapping keys are rendered as strings ({200: 3} becomes {"200": 3}), and each unpaired surrogate in text becomes one U+FFFD while a split surrogate pair decodes to its character. Keys that render to the same text never produce duplicate JSON keys: the later value wins at the earlier key's position. Markers are redacted like any other string. The policy applies to native logger fields and to extra= fields bridged from the standard library alike.

import structguru

# Native mode is already on. Logger calls route through the Rust renderer.
structguru.logger.info("order {id} accepted", id=987)
# → JSON line written to stdout by a background writer thread

No configuration is required for the default JSON-to-stdout behavior. Call configure(...) to customize the renderer, filtering, or sinks.

import structguru

structguru.configure(service="myapp", level="INFO", file_path="/var/log/app.log")
structguru.logger.bind(request_id="abc").info("order {id} accepted", id=987)
# → JSON line written to /var/log/app.log by a background writer thread

Import-time configuration and configure() without a Settings object honor environment variables:

STRUCTGURU_LEVEL=INFO STRUCTGURU_SERVICE=myapp python -m myapp

Invalid native environment values fail import with an actionable exception. This prevents a deployment from starting while the native-only logging path is disabled.

Public API:

Symbol Purpose
configure(...) Replace rendering, filtering, redaction, and output settings.
Settings Validate reusable options; construct from Python values, a mapping, or the environment.
get_config() Return configured options, or None when shut down.
update(...) Change selected active options without rereading the environment.
shutdown() Stop the writer; logging is disabled until configure() is called.
set_level(level) Adjust the level threshold at runtime.
writer_metrics() Current writer counters (enqueued/written/dropped/depth/...) plus filter counters when active; None after shutdown.
lifecycle_metrics() Cumulative native deliveries rejected by closed writers; available after shutdown and across reconfiguration.
is_available() Compatibility helper; always True once the package has imported, because a missing extension fails import.

Behavior notes:

  • Overflow: the default maxsize=8192 uses overflow="block" to wait for queue space. Use overflow="drop" for drop-newest behavior with metrics and rate-limited warnings. maxsize=0 explicitly opts into an unbounded queue.
  • Redaction, level filtering, exceptions, and OpenTelemetry injection are supported natively; redaction covers the message, field names, string values, and integers at any depth before rendering or Sentry export, and message placeholders that name a sensitive key are interpolated as [REDACTED] (see the redaction API reference for the exact coverage). sensitive_keys overrides the default redaction keys. Rust's linear-time regex engine rejects backreferences and look-around with ValueError at configuration time.
  • Sampling & rate limiting (sample_rate, rate_limit_max, rate_limit_period) are applied as native pre-render filters — dropped records cost zero rendering. sampled and rate_limited counters are distinct from the transport dropped counter. sample_max_level restricts sampling to records at or below that level; more severe records always pass.
  • Metric hooks (metric_processor=...) invoke a structlog-style processor (e.g. MetricProcessor) for every kept record on the caller's thread, with (None, method, {"event": message, **fields}); the message stays in "event" even when a field has that name. Dropped records (level/sampling/rate-limit) never reach it; hook errors are swallowed.
  • Fork/shutdown safe — the writer is flushed on exit and respawned in forked children (gunicorn/celery prefork). The exit drain is registered when structguru is imported, so atexit handlers registered afterwards can still log. Rotating-file writers sharing a path coordinate through an owner-only .lock sidecar; distributed hosts should still prefer stdout and an external collector.
  • Structured exceptions (structured_exceptions=True) render type, message, module, and frames as a dictionary, with optional redacted/truncated locals controlled by the exception_* options. A local named like a sensitive key is redacted, and so is any value under a sensitive key inside a mapping, list, tuple, named tuple, set, dataclass with its generated __repr__, or SimpleNamespace (walked with bounded depth and size, cycle-safe); other objects' own repr() text is covered by sensitive_patterns, which see each local's full rendering before it is truncated to exception_max_local_repr. Exception groups include nested members under exceptions, with the same frame limits and redaction. Traversal stops at ten nesting levels or 100 exception nodes; exceptions_truncated counts omitted direct children. Failed message conversions produce a marker instead of interrupting logging.
  • stack_info is supported natively: the stack is captured in Python and rendered in the same position as StackInfoRenderer (stack between service and message). Unlike the standard path, the stack ends at the user's calling frame (frames of the structguru package are skipped, the way structlog skips its own).
  • Console mode (format="console"): renders colored, human-readable lines instead of JSON — structguru's own stable dev format (<timestamp> [<LEVEL>] <message> k=v), with ANSI colors by default on a TTY. Override with colors=True/False. String values are double-quoted with " and \ escaped, keys containing spaces, =, quotes, or backslashes are quoted, and control characters, U+2028/U+2029, and bidirectional controls are escaped everywhere, so a field key or value cannot forge another field or line. Floats use the JSON renderer's text (1.0, 1e+300); the stack and a formatted exception follow as indented blocks.
  • File sinks (file_path=...): write to a rotating file natively. Defaults mirror RotatingFileHandler (50 MB, 5 backups); configure via file_max_bytes/file_backup_count. Set also_stdout=True to mirror output to both file and stdout (e.g. container + persistent log).
  • Callable sinks (callable_sinks=[fn, ...]): use a bounded queue (callable_queue_maxsize=1024). overflow="block" provides lossless backpressure; overflow="drop" reports callable_dropped metrics. One background thread at a time calls the sinks, in log order, also across reconfiguration; logger.add() never waits for the queue. Sink exceptions are counted in callable_errors with a rate-limited warning. Flush and lifecycle operations drain queued calls; a sink that makes no progress for 10 seconds is abandoned with a warning instead of blocking them.
  • Sentry integration (sentry_processor=SentryProcessor(...)): receives the already-redacted event and raw exc_info only for exception capture.
  • Scope: the native renderer covers JSON and console rendering, file/stdout/callable sinks, redaction, sampling/rate limiting, metrics, exceptions, and stack information. logger.add() sinks receive native and stdlib records.

Shutdown and reconfiguration drain records already accepted by the native queue. Calls still formatting or waiting for space may be rejected when their writer closes, even in block mode. lifecycle_metrics()["rejected"] counts these native deliveries without queue-full warnings and survives shutdown and configuration changes; forked children start at zero. A rejected record reaches no other destination either: the synchronous stream, callable sinks, and Sentry follow the native writer's outcome. Calls begun while logging is disabled are no-ops and are not counted. See the lifecycle contract and how delivery works for details.

Framework integrations

ASGI (FastAPI / Starlette)

from structguru.integrations.asgi import StructguruMiddleware

app = FastAPI()
app.add_middleware(StructguruMiddleware, request_id_header="X-Request-ID")

Granian

Route Granian's server logs through StructguruHandler using --log-config, and use StructguruMiddleware for ASGI request IDs and structured summaries. The Granian guide includes a complete logging dictionary, application and launcher examples, and access-log options.

Celery

from structguru.integrations.celery import setup_celery_logging

setup_celery_logging(propagate_context=True, context_keys=["request_id"])
# Binds task_id/task_name; propagates selected keys (redacted, JSON-safe) via headers

Flask

from structguru.integrations.flask import setup_flask_logging

app = Flask(__name__)
setup_flask_logging(app, request_id_header="X-Request-ID")

Django

# settings.py
from structguru.integrations.django import build_logging_config, StructguruMiddleware

LOGGING = build_logging_config(service="myapp", level="INFO", json_logs=True)
MIDDLEWARE = ["structguru.integrations.django.StructguruMiddleware", ...]

SQLAlchemy

from structguru.integrations.sqlalchemy import setup_query_logging

setup_query_logging(engine, slow_threshold_ms=100, log_all=False)

gRPC

from structguru.integrations.grpc import StructguruInterceptor

server = grpc.server(
    futures.ThreadPoolExecutor(),
    interceptors=[StructguruInterceptor()],
)

Sentry

import logging

from structguru import update
from structguru.integrations.sentry import SentryProcessor

sentry = SentryProcessor(event_level=logging.ERROR, tag_keys=frozenset({"service"}))
update(sentry_processor=sentry)

Stdlib bridge

Third-party libraries log through the standard logging module. Installing the bridge re-emits those records through structguru, so they share the same JSON / console formatting, redaction, and output stream as your own logs:

from structguru.integrations.stdlib import install_stdlib_bridge

bridge = install_stdlib_bridge(
    level="INFO",
    suppress_loggers=("urllib3", "botocore"),
    disable_existing_loggers=False,
)

import logging

logging.getLogger("sqlalchemy.engine").info("SELECT 1")
# → {"logger":"sqlalchemy.engine","level":"INFO",...,"message":"SELECT 1"}

While the bridge is installed, logger.add() sinks receive third-party records only through it — rendered once, never also raw. Pass the returned handler to uninstall_stdlib_bridge() to restore the previous behavior.

Installing a second bridge while one is active raises RuntimeError. When logging setup legitimately runs more than once per process (a Django manage.py that imports a Celery app module, repeated setup in test suites), pass replace=True to release the previous bridge first — last call wins:

bridge = install_stdlib_bridge(level="INFO", replace=True)

The swap is atomic for callers: a record logged by another thread during it is delivered at most once (rendered, raw, or dropped — never twice). Suppression levels applied by the earlier install are not reverted, and calling uninstall_stdlib_bridge() on the replaced handler is a no-op.

disable_existing_loggers=True disables named stdlib loggers that already exist at installation time; False re-enables them, following dictConfig semantics. When the option is omitted, install_stdlib_bridge() reads STRUCTGURU_STDLIB_DISABLE_EXISTING_LOGGERS; if the variable is also unset, existing states are preserved. Explicit Python values override the environment. An empty environment value is treated as unset.

STRUCTGURU_STDLIB_DISABLE_EXISTING_LOGGERS=false python -m myapp

To configure all bridge options from environment variables at a controlled point in application startup:

STRUCTGURU_STDLIB_LEVEL=INFO \
STRUCTGURU_STDLIB_DISABLE_EXISTING_LOGGERS=false \
python -m myapp
from structguru.integrations.stdlib import install_stdlib_bridge_from_env

bridge = install_stdlib_bridge_from_env()

Requirements

  • Python 3.11+
  • The compiled Rust extension (shipped as abi3 wheels for Linux/macOS/Windows, plus free-threaded CPython 3.14t/3.15t wheels for Linux x86_64, macOS arm64, and Windows x64)

Documentation & Examples

The documentation follows Diátaxis:

  • Tutorials — Learn structguru step by step, from the first log line to a logged web service.
  • How-to guides — Configure, route, redact, and integrate with frameworks (FastAPI, Granian, Flask, Django, Celery, gRPC, SQLAlchemy, HTTPX, Requests).
  • Reference — API, settings and environment variables, record format, metrics, and integration details.
  • Explanation — Architecture, delivery guarantees, context propagation, and redaction design.
  • Full-stack Example — FastAPI + Celery + SQLAlchemy in action.
  • Existing-loggers Example — Configure the stdlib policy and bridge replacement from code or environment.

Development

uv sync --all-extras
uv run pytest
make bench
uv run ruff check .
uv run mypy src/

License

MIT — Copyright (c) 2025 Aleksandr Pavlov

Metadata

Release files for structguru 1.5.0

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

Source distribution (sdist)

Source distribution for structguru 1.5.0
File Size Uploaded
structguru-1.5.0.tar.gz 157.2 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for structguru 1.5.0
File
structguru-1.5.0-cp315-cp315t-win_amd64.whl CPython 3.15 CPython 3.15 free-threading Windows x86-64 Details
structguru-1.5.0-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.15 CPython 3.15 free-threading Linux glibc 2.17+ x86-64 Details
structguru-1.5.0-cp315-cp315t-macosx_11_0_arm64.whl CPython 3.15 CPython 3.15 free-threading macOS 11.0+ ARM64 Details
structguru-1.5.0-cp314-cp314t-win_amd64.whl CPython 3.14 CPython 3.14 free-threading Windows x86-64 Details
structguru-1.5.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.14 CPython 3.14 free-threading Linux glibc 2.17+ x86-64 Details
structguru-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl CPython 3.14 CPython 3.14 free-threading macOS 11.0+ ARM64 Details
structguru-1.5.0-cp311-abi3-win_amd64.whl CPython 3.11 abi3 Windows x86-64 Details
structguru-1.5.0-cp311-abi3-musllinux_1_2_x86_64.whl CPython 3.11 abi3 Linux musl 1.2+ x86-64 Details
structguru-1.5.0-cp311-abi3-musllinux_1_2_aarch64.whl CPython 3.11 abi3 Linux musl 1.2+ ARM64 Details
structguru-1.5.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.11 abi3 Linux glibc 2.17+ x86-64 Details
structguru-1.5.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.11 abi3 Linux glibc 2.17+ ARM64 Details
structguru-1.5.0-cp311-abi3-macosx_11_0_arm64.whl CPython 3.11 abi3 macOS 11.0+ ARM64 Details
structguru-1.5.0-cp311-abi3-macosx_10_12_x86_64.whl CPython 3.11 abi3 macOS 10.12+ x86-64 Details

Total release size: 13.8 MB

Release files / structguru-1.5.0.tar.gz

Download URL structguru-1.5.0.tar.gz
Size 157.2 kB
Tags Source
SHA-256 checksum
How to use checksums
bfd8b501dd6154870899f4aca76a65dac0c4ce0cdcf89603780ad6983c743253
BLAKE2b-256 checksum
How to use checksums
3a9f6acd27bcf424490d09d823761a5148de3e1d718458291c7e9998eb90a991
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Oct 13, 2026.

Transparency log

Release files / structguru-1.5.0-cp315-cp315t-win_amd64.whl

Download URL structguru-1.5.0-cp315-cp315t-win_amd64.whl
Size 1.0 MB
Tags CPython 3.15 CPython 3.15 free-threading Windows x86-64
SHA-256 checksum
How to use checksums
8bc937d423c022cbc1b24e136302319d2e3cc537704f9b30ee236d619f0f5f2a
BLAKE2b-256 checksum
How to use checksums
a7525fed05b8eb48f0bbd41b047a36da850724e501499672461af257d5292bad
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Oct 13, 2026.

Transparency log

Release files / structguru-1.5.0-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL structguru-1.5.0-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.1 MB
Tags CPython 3.15 CPython 3.15 free-threading Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
baff42c46e272764a23259d6e0bf979cd834c6f6710d02e22e6143d8b544891d
BLAKE2b-256 checksum
How to use checksums
320e9e4d05950efb947b5fe98639abbfcde92bf4dd0c1687c43ab12f804ac0e4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Oct 13, 2026.

Transparency log

Release files / structguru-1.5.0-cp315-cp315t-macosx_11_0_arm64.whl

Download URL structguru-1.5.0-cp315-cp315t-macosx_11_0_arm64.whl
Size 968.4 kB
Tags CPython 3.15 CPython 3.15 free-threading macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
db6333af255b15411c49812893c0be33a0c0a0a0636a1706a292388cd5f4568d
BLAKE2b-256 checksum
How to use checksums
5132bbd4569c0757ed5d8d86c33e600a76f5300dd851bb002257e34ad972164c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Oct 13, 2026.

Transparency log

Release files / structguru-1.5.0-cp314-cp314t-win_amd64.whl

Download URL structguru-1.5.0-cp314-cp314t-win_amd64.whl
Size 1.0 MB
Tags CPython 3.14 CPython 3.14 free-threading Windows x86-64
SHA-256 checksum
How to use checksums
8d46264e39db65e416cfda5fe78732ed809860794f9a226be0bb9761acf35d24
BLAKE2b-256 checksum
How to use checksums
3db4156693089aa4078ddf2ed78fa416cc9bead56f5ab84a2fe8a7b04c0db61b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Oct 13, 2026.

Transparency log

Release files / structguru-1.5.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL structguru-1.5.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.1 MB
Tags CPython 3.14 CPython 3.14 free-threading Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
fd9034c3fa180e2ee0be01ef4d08f3ccdae64ecc83148aa3bfecf0d9028ff774
BLAKE2b-256 checksum
How to use checksums
0a7936aec69d80847adc6b7b3ee97ec75c5ad383dc9d07c675ac62e230e909ed
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Oct 13, 2026.

Transparency log

Release files / structguru-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl

Download URL structguru-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl
Size 968.5 kB
Tags CPython 3.14 CPython 3.14 free-threading macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
0a427247eeaa7a6c445b7057f9944287e7b34871906f116963dc113e0f425371
BLAKE2b-256 checksum
How to use checksums
37430698e1a2278ac3049842cfe44d88f34a4c38df1615be9320d2ca2dd2e14c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Oct 13, 2026.

Transparency log

Release files / structguru-1.5.0-cp311-abi3-win_amd64.whl

Download URL structguru-1.5.0-cp311-abi3-win_amd64.whl
Size 1.0 MB
Tags CPython 3.11 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
39aa501b95a6b3303ff183c3f68156d5ecf84b17aaf085e71bd1f5adac4fd82b
BLAKE2b-256 checksum
How to use checksums
72b03c9604e8b261dba8f29d3e664532021a6e4ab274f5a312da64d0727850a9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Oct 13, 2026.

Transparency log

Release files / structguru-1.5.0-cp311-abi3-musllinux_1_2_x86_64.whl

Download URL structguru-1.5.0-cp311-abi3-musllinux_1_2_x86_64.whl
Size 1.3 MB
Tags CPython 3.11 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
658e84c2176e71c6b6ebc9e027791320d0ddcc48fc1546127bfe54d4ed731c63
BLAKE2b-256 checksum
How to use checksums
f191a0f3d05ba15950630231a18fa5f28b38e8ca8c1aa8f86906f87c54b39994
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Oct 13, 2026.

Transparency log

Release files / structguru-1.5.0-cp311-abi3-musllinux_1_2_aarch64.whl

Download URL structguru-1.5.0-cp311-abi3-musllinux_1_2_aarch64.whl
Size 1.2 MB
Tags CPython 3.11 Linux musl 1.2+ ARM64 abi3
SHA-256 checksum
How to use checksums
31e9ab5c491f7a4d547578061030c62cad2006509c7fc78cadd533822727346c
BLAKE2b-256 checksum
How to use checksums
db7ade03e2f4bf26eac1465b61c3284e0ebf6fe20ae567d39c77469abad69e32
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Oct 13, 2026.

Transparency log

Release files / structguru-1.5.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL structguru-1.5.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.1 MB
Tags CPython 3.11 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
7199e6523afebf2eb7f64e936baff1fc08e956fa399b0773963f9666b5f31510
BLAKE2b-256 checksum
How to use checksums
5f0a99c2b779b582705182a1cc52e481b2446b0695dc7e262e431cad37c9416c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Oct 13, 2026.

Transparency log

Release files / structguru-1.5.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL structguru-1.5.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 1.0 MB
Tags CPython 3.11 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
86bca0fbe3806e9083e85f911d9a20aed97840a544fec1fdd79fe7f4eed2b66f
BLAKE2b-256 checksum
How to use checksums
6db24de63a2af8982cc02c3d234e891bf197e791865c10fcbb078285d67176c7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Oct 13, 2026.

Transparency log

Release files / structguru-1.5.0-cp311-abi3-macosx_11_0_arm64.whl

Download URL structguru-1.5.0-cp311-abi3-macosx_11_0_arm64.whl
Size 978.0 kB
Tags CPython 3.11 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
757c787cd75704c989fa5762665124ec7e288ec86d4e0e6a487c00799f096ccc
BLAKE2b-256 checksum
How to use checksums
5797b323a433be8b2d2fe4463e69bbd86d3fc67aea8c8886b7011f44cb49c963
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Oct 13, 2026.

Transparency log

Release files / structguru-1.5.0-cp311-abi3-macosx_10_12_x86_64.whl

Download URL structguru-1.5.0-cp311-abi3-macosx_10_12_x86_64.whl
Size 1.0 MB
Tags CPython 3.11 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
3a596599ca813ef0ba3a7a9212b95338a97208ccadcc4a995467167cd3dd86b7
BLAKE2b-256 checksum
How to use checksums
bef7a695e6795dde13713f022defaae96d37d30b90316a2444c835e333b6a3f5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Oct 13, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.5.0 This release

14 release files

1.4.0

11 release files

1.3.1

8 release files

1.3.0

8 release files

1.2.3

8 release files

1.2.2

8 release files

1.2.1

8 release files

1.2.0

8 release files

1.1.0

8 release files

1.0.6

8 release files

1.0.5

8 release files

1.0.4

8 release files

1.0.3

8 release files

1.0.2

8 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 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