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. A native or callable sink that makes no progress for 10 seconds is abandoned with a warning instead of blocking the caller. Queued native records are discarded, and the warning does not wait on a full stderr. 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)
# query is "<omitted>" by default; pass include_query=True to log statement[:500]

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.6.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.6.0
File Size Uploaded Provenance
structguru-1.6.0.tar.gz 167.2 kB With provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for structguru 1.6.0
File
structguru-1.6.0-cp315-cp315t-win_amd64.whl CPython 3.15 CPython 3.15 free-threading Windows x86-64 Details
structguru-1.6.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.6.0-cp315-cp315t-macosx_11_0_arm64.whl CPython 3.15 CPython 3.15 free-threading macOS 11.0+ ARM64 Details
structguru-1.6.0-cp314-cp314t-win_amd64.whl CPython 3.14 CPython 3.14 free-threading Windows x86-64 Details
structguru-1.6.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.6.0-cp314-cp314t-macosx_11_0_arm64.whl CPython 3.14 CPython 3.14 free-threading macOS 11.0+ ARM64 Details
structguru-1.6.0-cp311-abi3-win_amd64.whl CPython 3.11 abi3 Windows x86-64 Details
structguru-1.6.0-cp311-abi3-musllinux_1_2_x86_64.whl CPython 3.11 abi3 Linux musl 1.2+ x86-64 Details
structguru-1.6.0-cp311-abi3-musllinux_1_2_aarch64.whl CPython 3.11 abi3 Linux musl 1.2+ ARM64 Details
structguru-1.6.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.6.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.11 abi3 Linux glibc 2.17+ ARM64 Details
structguru-1.6.0-cp311-abi3-macosx_11_0_arm64.whl CPython 3.11 abi3 macOS 11.0+ ARM64 Details
structguru-1.6.0-cp311-abi3-macosx_10_12_x86_64.whl CPython 3.11 abi3 macOS 10.12+ x86-64 Details

Total release size: 14.4 MB

Release files / structguru-1.6.0.tar.gz

Download URL structguru-1.6.0.tar.gz
Size 167.2 kB
Tags Source
SHA-256 checksum
How to use checksums
a0c7e97caf3c9f127494a6233299f6e561708acacf86831c9fccaceab0460fb1
BLAKE2b-256 checksum
How to use checksums
4ba2fddf17f2f971cfd1496763c5412b1a9a7142eba09cf383f3608f529aca61
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 24, 2026.

Transparency log

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

Download URL structguru-1.6.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
edaa99433b7c7df76bec39838a37026bb59896adfe1d9f4ca7f6ece32821ca20
BLAKE2b-256 checksum
How to use checksums
8e6c63563b1a65a21a27ec2694c90e3f1be9dff7a78a5dcaaaa9a85c6826903e
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 24, 2026.

Transparency log

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

Download URL structguru-1.6.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
06ed8f618323f9956e58bc9f62440affd29aeced00375a5863d7bf1cc4ab5d35
BLAKE2b-256 checksum
How to use checksums
21bf11042a701d11d3d26888f31d1863cd4d14fdb2fbcbb7cdd6ffe26e7ab443
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 24, 2026.

Transparency log

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

Download URL structguru-1.6.0-cp315-cp315t-macosx_11_0_arm64.whl
Size 1.0 MB
Tags CPython 3.15 CPython 3.15 free-threading macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
d4b0bc2fbfb18e03b01755746c621c5ddd4659a5138d70aca2ea2f2e64f47aef
BLAKE2b-256 checksum
How to use checksums
0fa46b09344ff1f30b16d907c885b9c38687abbf53bb86cffe4b840f15b17b15
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 24, 2026.

Transparency log

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

Download URL structguru-1.6.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
5ae4a47470b3f89f4413cfc8f1ffbadac29f449ff5c392d0e4d5f84d9ccc5864
BLAKE2b-256 checksum
How to use checksums
8338cdeefe1581b343516c82cbd73f7b0e4990edc625f6886899759e6fae89f3
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 24, 2026.

Transparency log

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

Download URL structguru-1.6.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
984063a23e386ff83fd0305e9920dc1c73d468a8df1da554df13b40f637432dc
BLAKE2b-256 checksum
How to use checksums
5ff5085ccd26c6220d46a1b4ce0a20a32b336e09e1afaebef49131d0a8ea27f8
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 24, 2026.

Transparency log

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

Download URL structguru-1.6.0-cp314-cp314t-macosx_11_0_arm64.whl
Size 1.0 MB
Tags CPython 3.14 CPython 3.14 free-threading macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
b6d7d5eaab78a077756ed74c7f3fe7d4f7491dc0b09bbf3dfb8796c88f7a5e2c
BLAKE2b-256 checksum
How to use checksums
97ecac17344e671a6e89f365dbe090877a5008d9f342e2c8738253bfe8718867
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 24, 2026.

Transparency log

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

Download URL structguru-1.6.0-cp311-abi3-win_amd64.whl
Size 1.1 MB
Tags CPython 3.11 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
5ff34b9d324f62b077644b2f1fd7f180cc7612931e0ed7419d65594551ddb2c0
BLAKE2b-256 checksum
How to use checksums
66072bc5c6b6146081bb142b019e2d752320faebbee4db9b698187db3afb25e2
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 24, 2026.

Transparency log

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

Download URL structguru-1.6.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
ebb409d5d0f823fdfb4c953a3de056ab096d4c984bdf3be2da7db725129a06b9
BLAKE2b-256 checksum
How to use checksums
20b85edb6764dc7470db4efc20e7b14a58e585d9a72f80d072231869064a9871
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 24, 2026.

Transparency log

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

Download URL structguru-1.6.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
e5adac3cdf06ce5eace7c590c92196a9a9e9f7a26182779a59929c312fcb2801
BLAKE2b-256 checksum
How to use checksums
708fa25c4746106753b8f21d3d41dff84b95a5b2cacb8c582e1be828d4d23f39
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 24, 2026.

Transparency log

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

Download URL structguru-1.6.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
d57555817265694a20d017b093048f4066a6b2d4059553cca9af32be3d75e631
BLAKE2b-256 checksum
How to use checksums
85f02f602388569bb3d4f5b5df4491f088fcb3e128856f0fed77f663fc9bac2a
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 24, 2026.

Transparency log

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

Download URL structguru-1.6.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 1.1 MB
Tags CPython 3.11 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
f1e9b8f5e494768663b937065d42c31081d9387da701212dadb405e2408a72dd
BLAKE2b-256 checksum
How to use checksums
2a10a9aee949f16352802b649271902e66892bd5c7fa2c7d1e98409a9b346ad0
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 24, 2026.

Transparency log

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

Download URL structguru-1.6.0-cp311-abi3-macosx_11_0_arm64.whl
Size 1.0 MB
Tags CPython 3.11 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
9ba052273e2ddc37e5357f3f04a9672cea1b87ad339881576c034662fc906464
BLAKE2b-256 checksum
How to use checksums
10f7e52c52fca5eeea0d60af524f84448972198a4e226a27d7b3d3f3fb2e683c
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 24, 2026.

Transparency log

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

Download URL structguru-1.6.0-cp311-abi3-macosx_10_12_x86_64.whl
Size 1.1 MB
Tags CPython 3.11 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
4c8b37ffe02b3067b3ee07ab3330172e87ed3c62c3331e1f29794b398c4ca9b4
BLAKE2b-256 checksum
How to use checksums
817849b7d5743207fcc660e3a2b3236902358efb7665e5601255f0ce742cc8be
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 24, 2026.

Transparency log

Security for structguru 1.6.0

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.

Full provenance

All 14 files in this release have been uploaded with provenance metadata.

Select from 14 files

Attestation for structguru-1.6.0.tar.gz

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 24, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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