⚡ pulselog
Non-blocking Python logger with a live browser dashboard.
pip install pulselog
Every log.info() call costs 1.8µs. Zero config. Browser opens automatically.
📚 Table of Contents
- Performance Tiers
- Benchmarks
- Quick Start
- Why pulselog?
- Dashboard
- API
- stdlib
loggingIntegration - Configuration
- Production Usage
- Examples
- Design Notes
- Requirements
- License
🚀 Performance Tiers
| Tier | How to get it | Single-thread | Multi-thread (8) |
|---|---|---|---|
| Pure Python | pip install pulselog |
355k/sec | 301k/sec |
| Rust extension | maturin build --release |
735k/sec | 608k/sec |
The Rust-backed native extension delivers 2× throughput by moving the hot path into compiled code. Same API, zero code changes — just a different install method.
# Pure Python (default)
pip install pulselog
# Rust extension (macOS / Linux)
pip install maturin
git clone https://github.com/your-repo/pulselog
cd pulselog
maturin build --release
pip install dist/*.whl
📊 Benchmarks
Pure Python
(Windows, Python 3.12, dashboard=False)
| Scenario | Throughput | Notes |
|---|---|---|
| Single-thread burst | 355.8k/sec | p50=1.8µs · p99=6.0µs · p99.9=39.7µs |
| Multi-thread burst (8 threads) | 301.4k/sec | matches single-thread — zero contention |
| Sustained (5s) | 427.6k/sec | 2.1M records logged |
| Queue saturation | 383.9k/sec | 0 drops — worker drained fast enough |
| Realistic (info + save + warn + error) | 216.4k/sec | mixed call types with kwargs |
Fast path (info_fast) |
455.4k/sec | no kwargs — zero dict allocation |
| Mixed workload (6 threads, varied calls) | 339.9k/sec | 1.86M records, 0 drops |
Rust Extension
(macOS, release build)
| Scenario | Throughput | Notes |
|---|---|---|
| Single-thread (1M records) | 735k/sec | 2× over pure Python |
| Multi-thread stress (8 × 500k) | 608k/sec | 4M total, 0 drops |
Latency Under Concurrent Load
p99 with 4 background threads flooding the queue (Pure Python):
| p50 | p99 | p99.9 | |
|---|---|---|---|
| No contention | 1.8µs | 6.0µs | 39.7µs |
| Under load (4 bg threads) | 2.1µs | 5.7µs | 27.6µs |
p99 is lower under load than idle — per-thread sharding means concurrent producers create zero interference with each other.
Version Improvements (v0.1.2 → v2.0.0)
| Metric | v0.1.2 | v2.0.0 | Change |
|---|---|---|---|
| Single-thread | 263k/sec | 356k/sec | +35% |
| Multi-thread | 41k/sec | 301k/sec | +633% |
| Fast path (new) | — | 455k/sec | 🆕 |
| Realistic | 160k/sec | 216k/sec | +35% |
| p99.9 latency | 87.9µs | 39.7µs | −55% |
| Dropped records | 0 | 0 | still 0 ✅ |
A typical ML training loop logs 10–100 records/sec. PulseLog handles 2,164× that load before any issues.
⚡ Quick Start
from pulselog import Logger
log = Logger("my-app", checkpoint_path=":memory:")
log.info("training started", epoch=1)
log.warning("learning rate too high", lr=0.1)
log.save("epoch-1", {"acc": 0.91, "loss": 0.23}, status="DONE", progress=33)
log.shutdown()
A browser tab opens at http://localhost:5678 and streams every log in real time.
🤔 Why pulselog?
Standard logging blocks the calling thread on every write — waiting for a file, a socket, or a database. In tight loops (ML training, data pipelines, inference servers) this adds up fast.
pulselog never blocks. Every log call enqueues a record in O(1) and returns immediately. A daemon worker drains the queue every 10ms and pushes batches to the dashboard over WebSocket.
log.info() ← O(1), ~1.8µs, never blocks
│
▼
ShardedLogQueue ← per-thread deques, zero cross-thread contention
│ each thread writes to its own private deque
│
▼ every 10ms (adaptive — halves under load)
BackgroundWorker ← daemon thread, fan-drains all shards
│
├──▶ DashboardServer.broadcast() ← WebSocket → live browser
│
└──▶ (custom handlers)
Why per-thread sharding matters:
A single shared queue means all producer threads compete for the same lock on every put(). At 8 threads, that bottleneck cut throughput from 356k to 41k/sec — an 87% collapse. Per-thread sharding eliminates the shared state entirely. Each thread appends to its own deque (a GIL-atomic operation) and the worker fan-drains all shards once per cycle. Result: multi-thread throughput matches single-thread.
🖥️ Dashboard
Single self-contained HTML file served over WebSocket — no build step, no CDN, no npm.
Logs Tab
- 🎨 Colour-coded by level —
DEBUGgray ·INFOblue ·WARNINGamber ·ERROR/CRITICALred - 🔍 Full-text search — filter logs by message content in real time
- 🎚️ Level filter — toggle DEBUG, INFO, WARNING, ERROR, CRITICAL visibility
- 📜 Virtual list rendering — 100k+ logs with zero browser lag
- ⏬ Auto-scroll with manual scroll override
- 📤 Export session as JSON
Checkpoints Tab
- 📈 Progress bar per checkpoint (overall = average across all checkpoints)
- 🔎 Expandable JSON data viewer
- 🏷️ Status badges —
DONE✅ ·IN_PROGRESS🟡 ·FAILED🔴 ·SKIPPED⚫ - 🔍 Search checkpoints by name
🔧 API
Logger
log = Logger(
name = "my-app",
host = "localhost",
port = 5678, # auto-increments if taken
auto_open = True, # open browser on start
dashboard = True, # False for CI / production
checkpoint_path = ".pulselog/checkpoints.db", # ":memory:" for in-memory
level = "DEBUG",
worker_interval = 0.01, # drain interval in seconds (default 10ms)
queue_size = 100_000, # max records before oldest evicted
overflow = "drop", # "drop" | "block" | "raise"
)
Logging
log.debug("msg", **extra)
log.info("msg", **extra)
log.warning("msg", **extra)
log.error("msg", **extra)
log.critical("msg", **extra)
# kwargs appear as structured metadata in the dashboard
log.info("request handled", user_id=42, latency_ms=12, status=200)
# exception() captures the current traceback automatically
try:
result = model.predict(x)
except Exception:
log.exception("prediction failed", input_shape=str(x.shape))
Zero-Allocation Fast Paths
When you call log.info("msg", key=val), Python builds the {"key": val} dict before the function is entered — in the C layer, before any pulselog code runs. At 216k/sec that's 216k dict allocations/sec you cannot avoid with **kwargs syntax.
For calls where you don't need per-record metadata, use the fast-path variants:
log.info_fast("step done") # ~455k/sec — no dict allocated, ever
log.debug_fast("heartbeat")
log.warning_fast("queue high")
log.error_fast("connection lost")
log.critical_fast("out of memory")
When to use which:
# Tight loop — no metadata needed → use fast path
for step in range(100_000):
log.info_fast("step") # 455k/sec
# Need metadata → use standard API
log.info("step", loss=loss, acc=acc) # 216k/sec — kwargs cost is unavoidable
Checkpoints
Checkpoints persist structured data with progress tracking — ideal for ML training, data pipelines, and long-running jobs.
# Save a checkpoint
log.save(
name = "epoch-5",
data = {"loss": 0.31, "acc": 0.94},
status = "DONE", # "DONE" | "IN_PROGRESS" | "FAILED" | "SKIPPED"
note = "best so far",
progress = 50 # 0–100, shown as progress bar in dashboard
)
# Load a checkpoint (returns dict or None — never raises)
result = log.load("epoch-5")
# → {"loss": 0.31, "acc": 0.94, "status": "DONE", "note": "best so far", "progress": 50}
# List all checkpoints (most recent first)
names = log.checkpoints()
# → ["epoch-5", "epoch-4", "epoch-3"]
# Delete a checkpoint
log.delete_checkpoint("epoch-3")
In-memory mode for tests and ephemeral runs:
log = Logger("test", checkpoint_path=":memory:")
log.save("step-1", {"value": 42}, status="DONE", progress=50)
log.load("step-1") # → works immediately, no disk I/O
Context and Grouping
# Tag groups subsequent logs under a label (per-thread — safe for concurrent use)
log.tag("training")
# Context manager — restores the previous tag on exit, even on exception
with log.context(tag="validation"):
log.info("val loss", loss=0.41)
# tag is restored here
# Visual divider in the dashboard stream
log.divider("epoch boundary")
Utilities
log.flush(timeout=2.0) # drain queue synchronously — returns False if timeout hit
log.shutdown() # graceful teardown (also called automatically on exit)
stats = log.stats()
# {
# "records_dropped": int,
# "drop_rate": float, # e.g. 0.04 = 4%
# "queue_size": int,
# "queue_capacity": int,
# "queue_fill_pct": float,
# "checkpoints_saved": int,
# "dashboard_clients": int,
# "uptime_seconds": float,
# }
🔌 stdlib logging Integration
Drop-in bridge — all structured fields (lineno, filename, funcName, exc_info) are forwarded to the dashboard.
import logging
from pulselog.handler import PulseHandler
logging.getLogger().addHandler(PulseHandler("my-app"))
logging.info("this appears in the dashboard")
logging.error("with traceback", exc_info=True) # traceback preserved
⚙️ Configuration
Priority (highest → lowest): Logger() kwargs → env vars → pulselog.toml → defaults
Environment variables
PULSELOG_DASHBOARD=false
PULSELOG_HOST=0.0.0.0
PULSELOG_PORT=8080
PULSELOG_AUTO_OPEN=false
PULSELOG_CHECKPOINT_PATH=/data/checkpoints.db
PULSELOG_LEVEL=INFO
PULSELOG_WORKER_INTERVAL=0.01
pulselog.toml (place in project root)
[pulselog]
host = "0.0.0.0"
port = 8080
auto_open = false
level = "INFO"
worker_interval = 0.01
🏭 Production Usage
# Disable dashboard, keep checkpoints, log to stderr on drop
log = Logger(
"prod",
dashboard = False,
checkpoint_path = "/data/checkpoints.db",
overflow = "drop", # never block — warn on stderr instead
)
With dashboard=False:
- ✅ No threads started beyond the background worker, no port bound, no browser opened
- ✅ Checkpoint reads/writes still work
- ✅ CI environments (
CI=true) disable the dashboard automatically
📖 Examples
ML Training Example
from pulselog import Logger
import time
log = Logger("resnet-training", checkpoint_path=":memory:")
log.tag("training")
for i in range(10):
loss = 1.0 - i * 0.08
acc = 0.6 + i * 0.035
log.info(f"epoch {i+1}", loss=round(loss, 3), acc=round(acc, 3))
log.save(
f"epoch-{i+1}",
{"loss": loss, "acc": acc},
status = "DONE",
progress = (i + 1) * 10,
)
if i > 0 and loss > prev_loss * 1.5:
log.warning("loss spike", epoch=i+1, loss=loss)
prev_loss = loss
time.sleep(0.5)
log.shutdown()
Data Pipeline Example
from pulselog import Logger
log = Logger("etl-pipeline")
with log.context("ingestion"):
log.info("loading source", table="events", rows=1_200_000)
records = ingest()
log.info("ingestion complete", rows=len(records))
with log.context("validation"):
errors = validate(records)
if errors:
log.warning("schema errors found", count=len(errors))
log.save("validation", {"errors": len(errors), "rows": len(records)},
status="DONE", progress=40)
with log.context("feature_engineering"):
for feat in ["activity_7d", "churn_score", "ltv_estimate"]:
features = compute_feature(feat, records)
log.info("feature computed", name=feat, coverage=features.coverage)
if features.null_rate > 0.03:
log.warning("high null rate", feat=feat, null_rate=features.null_rate)
with log.context("warehouse_write"):
rows_written = write_to_warehouse(features)
log.info("write complete", rows=rows_written, target="bigquery://features")
log.save("pipeline_run", {"rows": rows_written, "features": 3},
status="DONE", progress=100)
log.shutdown()
🧠 Design Notes
| Design choice | Why it matters |
|---|---|
| Per-thread sharding | ShardedLogQueue gives each producer thread a private deque. put() appends to the caller's own deque — no lock, no shared state, no GIL contention. The worker registers each thread's deque on first use and fan-drains all shards every cycle — this is why multi-thread throughput matches single-thread. |
Lock-free put() |
deque.append() is GIL-atomic in CPython. The hot path acquires no mutex. The threading.Event wake signal fires only on empty→non-empty transitions (~100/sec at steady state), not on every put() (which would be 300k+/sec). |
| Batch timestamps | LogRecord.timestamp is set to None at creation. The worker stamps time.time() once per drain cycle and fills every record in the batch — moving ~300k time.time() syscalls/sec down to ~100/sec, at the cost of sub-10ms timestamp precision within a batch. |
__slots__ on LogRecord |
Eliminates the per-instance __dict__ (~240 bytes each). At 300k records/sec, the original @dataclass design generated ~72 MB/sec of heap churn. With __slots__, allocation pressure drops ~3× and GC pause frequency falls accordingly — why p99.9 dropped from 87µs to 39µs. |
| Rust extension | An optional native module built with maturin moves record allocation and queue insertion into compiled Rust. The Python API is identical; the extension is detected and used automatically when installed. |
| Worker | Wakes immediately on new records via threading.Event, falls back to polling every 10ms. Adaptive: halves the interval when queue exceeds 50% capacity, restores it when calm. Drain rate is ~17–19M records/sec — 50× headroom over the producer ceiling. |
| Drop policy | When a shard is full, the oldest record is evicted and a stderr warning is emitted every 1,000 drops. Configure overflow="block" to pause the caller instead, or overflow="raise" to surface the error explicitly. |
| Shutdown | atexit and SIGTERM both call shutdown() once (guarded against double-invocation). flush() accepts a configurable timeout and returns False if the queue wasn't fully drained in time. |
| Thread safety | tag() and context() use threading.local() so each thread maintains its own tag state independently. The overflow strategy is resolved to a bound method at __init__ time — no string comparisons on the hot path. |
📦 Requirements
- Python ≥ 3.8
websockets ≥ 11.0(only needed withdashboard=True)
pip install pulselog # includes websockets
📄 License
MIT
Author: DevBuddy
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pulselog-0.1.5.tar.gz.
File metadata
- Download URL: pulselog-0.1.5.tar.gz
- Upload date:
- Size: 36.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
04a99950d65e5b8113100cc2b8bfd3833cd6fd2396994549d1c65aae706b3afd
|
|
| MD5 |
f391685a5a8b25916beb5c8be37216d0
|
|
| BLAKE2b-256 |
ff193d37b7be6b37d1210ea773e04e68d5ac972d20e4a5317d7abedb93590724
|
File details
Details for the file pulselog-0.1.5-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: pulselog-0.1.5-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 242.1 kB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
66a102286faac5bb988ca82a1ab3b8aa1fd475e55392be72e0d8049ce01be3cd
|
|
| MD5 |
49d28e57a8e1289c72bff4519897a82c
|
|
| BLAKE2b-256 |
6b9c797ac1034cc6c26def0cffd5693e80bab5fe3c2c36749f7bac5a049fd5a8
|
File details
Details for the file pulselog-0.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: pulselog-0.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 387.1 kB
- Tags: CPython 3.12, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a50bfd9cd9ee341d925d922a896563b8134766bebad68db97d4dcf8055a00b8d
|
|
| MD5 |
9846c5f8ca9fd35a7cbca70c5ff43da5
|
|
| BLAKE2b-256 |
da9ac3ff26acedb163f2d430eba07227b9de9eebe34620251545cc04b0cc7bfc
|
File details
Details for the file pulselog-0.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: pulselog-0.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 384.5 kB
- Tags: CPython 3.12, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f52c25246921e5c5e122d9239d66fb0cc1079245615c728604e402317f7f493f
|
|
| MD5 |
b12ed1622f11b19e5ba663a17eba0af0
|
|
| BLAKE2b-256 |
d83cf7ca7ce06b9ccb9b5a35aa1a6cf78a593eab8a35b6871d6f225c93bb193d
|
File details
Details for the file pulselog-0.1.5-cp311-cp311-win_amd64.whl.
File metadata
- Download URL: pulselog-0.1.5-cp311-cp311-win_amd64.whl
- Upload date:
- Size: 240.4 kB
- Tags: CPython 3.11, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0493de081c1084ada574510db57cc98662f6155f7f500f7167991487ddcf7f53
|
|
| MD5 |
4c13cb96c92bfbac011effc9f9be42f9
|
|
| BLAKE2b-256 |
b481d604256a2ff5d2ef656c591006e9b91d139d31c1d6806a4efe44ec3add0d
|
File details
Details for the file pulselog-0.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: pulselog-0.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 387.0 kB
- Tags: CPython 3.11, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a49e86eacc0797a777c6e7c54741612cd2f077e38a00dc9bbc6a79438fd21379
|
|
| MD5 |
cdd7d451912698ba2447d8272be170fd
|
|
| BLAKE2b-256 |
95ef23ca5e0db5f9978e71bc1237c7082b9980ce9a193d54c0d36e7b5b74bda6
|
File details
Details for the file pulselog-0.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: pulselog-0.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 385.2 kB
- Tags: CPython 3.11, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
189002e882451959e7f7e04603be7ccc9be1a1576a5584c34ec8d6dbce7db0fa
|
|
| MD5 |
0f319148ee6be1f2672cbb0cdee7ed88
|
|
| BLAKE2b-256 |
b8188a1223cddaf8dd19a5ac167646075ee0c78efd8bdc5ce01748463897dbe6
|
File details
Details for the file pulselog-0.1.5-cp310-cp310-win_amd64.whl.
File metadata
- Download URL: pulselog-0.1.5-cp310-cp310-win_amd64.whl
- Upload date:
- Size: 240.7 kB
- Tags: CPython 3.10, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5789c30984d16fd14e96c91e399b9935ab9b2ba4015afe347f8d6de80e6ec17c
|
|
| MD5 |
3b599f44636eee4316cfd92491280baa
|
|
| BLAKE2b-256 |
620e76e4e17dc31ad5b3511aef80c06034d61475e38dfadb0ca451f1044499ca
|
File details
Details for the file pulselog-0.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: pulselog-0.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 387.1 kB
- Tags: CPython 3.10, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
de6de950aba38441f1eee6121e95b15654f02ccf829f5923755bcc9d904139dc
|
|
| MD5 |
45bcc7c4a02e5cada980d1555183e6ed
|
|
| BLAKE2b-256 |
556628747619b30b90cc5002bbbe7bf69b4cbedc448052ba41de9f968813d1ed
|
File details
Details for the file pulselog-0.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: pulselog-0.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 385.3 kB
- Tags: CPython 3.10, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7033b8d9cad993866e53c9703edd288079a12005213b1805148b06ea4daeb2a7
|
|
| MD5 |
0dd220e0a3ab5c1feef5a3aba5a1e5b8
|
|
| BLAKE2b-256 |
71ee485611effef25ccafdfef8a84cb7395793ff0130438c502b82c6701baa8b
|
File details
Details for the file pulselog-0.1.5-cp39-cp39-win_amd64.whl.
File metadata
- Download URL: pulselog-0.1.5-cp39-cp39-win_amd64.whl
- Upload date:
- Size: 241.7 kB
- Tags: CPython 3.9, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c2d49af49760d40b394af0369bc1c5a535052cf91651feb714c315ec41b664b2
|
|
| MD5 |
41b1d4bbc48c8b9ace27c0cd092d0627
|
|
| BLAKE2b-256 |
389b830b54a774c34eca421205578241af7ec64dd367d7cdbc6643a69c111e71
|
File details
Details for the file pulselog-0.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: pulselog-0.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 387.7 kB
- Tags: CPython 3.9, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
368c83c090ac36679376bca9fe1d44ea567a27d54dde7f552ee5bb0217d50a5d
|
|
| MD5 |
6ac7bbab9dbce2e559dd25265a4f540d
|
|
| BLAKE2b-256 |
a9ea87569c00e7a0d21cc028ba9f8035c398d1672345a391b3b94ede6e3f1396
|
File details
Details for the file pulselog-0.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: pulselog-0.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 385.7 kB
- Tags: CPython 3.9, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5b3a61a30dae16561e4d70556a09333ca75292950588d2a982075745f1d0ea17
|
|
| MD5 |
c2cd1f4f88d26cad85d2cd3ef4432772
|
|
| BLAKE2b-256 |
702dc13407164b88437039c7e534bc9bc9f3ac9e950edee9aa9428afb3076876
|
File details
Details for the file pulselog-0.1.5-cp38-cp38-win_amd64.whl.
File metadata
- Download URL: pulselog-0.1.5-cp38-cp38-win_amd64.whl
- Upload date:
- Size: 243.0 kB
- Tags: CPython 3.8, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f6c82e76d2974563dc47e4d2f0119484152aac082aa735591582dc8e51ea3b05
|
|
| MD5 |
e35273d2d7275288a69a104274b48966
|
|
| BLAKE2b-256 |
00b19e0dc4e8e55c16096cad145918bfb97e9f7c7bdd3bf85e5c4b80920d9ffe
|
File details
Details for the file pulselog-0.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: pulselog-0.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 386.8 kB
- Tags: CPython 3.8, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
141d0dce517e1dace052a21d800fd9a57e0c1473c6f4aadfa2cd661655f14b7b
|
|
| MD5 |
0212fc91a3e03b62dd1c88b07efa3269
|
|
| BLAKE2b-256 |
758eaf56ba1d72151bb0f4307c1180cd5dc821863ffb6224d7c55ea084d4b540
|
File details
Details for the file pulselog-0.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: pulselog-0.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 385.3 kB
- Tags: CPython 3.8, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
90335f101a3ce4d3afa46b25db1afae5ed6e354cde4a00c6378a3279083a7811
|
|
| MD5 |
106f177b10c17725eaec356dfc2d531b
|
|
| BLAKE2b-256 |
b1405a855e6c098dbab82ca9458bc4a9f98737fe3f9f26b245b55b82751eb599
|