Skip to main content

Utilities

Python 3.9+ Version Downloads

A lightweight toolkit for the plumbing every project rewrites: where settings live, how logs are set up, what a batch shows while it runs, and where the time goes. Four independent areas, one shared folder on the machine.

pip install utilities-toolkit
# or
uv add utilities-toolkit

Charts need an extra: pip install "utilities-toolkit[plot]".


What is in it

Configuration INI, JSON, YAML and Python settings under one root, reached by attribute access.
Logging One call sets up a Rich console, rotating files, and three custom levels.
Frames & sparklines Put a distribution or a DataFrame in the log, readable over SSH.
Terminal charts plotext charts at their own log level. No image, no artefact.
Probing Latency and memory instrumentation that costs nothing when off.

Full API index and cost tables: docs/.


Configuration

from utilities import Config

Config.ensure_initialized("my_project", {"PATHS": {"DATA": "/mnt/data"}})

value = Config.my_project.PATHS.DATA        # case-insensitive throughout

Files live in ~/utilities/config/ (C:/utilities/config on Windows), so several projects on the same machine share one place instead of scattering dotfiles. INI, JSON, YAML and .py are all read the same way. → docs/config.md

Logging

from utilities import LoggingConfigurator

LoggingConfigurator.configure(project="my_project", level="INFO")

Rich console, a daily-rotating my_project.log, optional JSONL, Rich tracebacks. Idempotent: calling it twice cannot stack handlers. Overridable from the environment (LOG_LEVEL, LOG_DIR, LOG_JSON…), and it understands the custom level names below.

Every format is customisable — class constants (CONSOLE_FORMAT, FILE_FORMAT, …), per-call console_formatter / file_formatter / json_formatter, extra rich_handler_kwargs, or rich_console=False for a plain stdlib StreamHandler. See docs/logging.md.

LoggingConfigurator.watch(project="my_project", module=__name__, level="DEBUG")

adds a dedicated file for one module without disturbing anything else. → docs/logging.md

Three custom levels

6   PLOT        ~1.7 ms per chart
8   DATAFRAME   ~80 µs to ~340 µs
10  DEBUG
15  PERF        ~1.15 µs per probe
20  INFO

Ordered by increasing cost as you go down: lowering the level means agreeing to pay more. Because levels are ordered, PLOT also emits DataFrames — to get one without the other, use logger namespaces (myapp.data, myapp.plot). Every helper takes the logger as its first argument so that choice stays yours.

The package never adds a handler and never touches the host's logging configuration.

Sparklines and DataFrames in the log

Start with spark(). ~12 µs for 300 points, no dependency, one line, and still greppable — 145× cheaper than a chart.

from utilities import spark, log_frame

log.info("nav n=%d %s [%.2f, %.2f]", len(nav), spark(nav), min(nav), max(nav))
nav n=300 ▂▂▂▂▂▂▁▂▃▃▃▅▅▄▅▆▆▆▇██▇▆▆ [96.32, 120.61]
log_frame(data_logger, positions, mode="describe", label="positions")

Four modes — head, tail, full, describe — with a hard row cap on full, scoped display settings, and a LazyFrame guard that logs the query plan instead of ever calling collect(). polars and pandas are supported but never imported.

A multi-line record is no longer greppable — that trade-off is the reason spark() comes first. → docs/frames.md

Terminal charts

from utilities.log.plots import plot_line
plot_line(plot_logger, nav, title="NAV")
                                     NAV
     ┌─────────────────────────────────────────────────────────────────┐
120.6┤                                                    ▐▙  ▄▖▄      │
     │                                                ▄▟  ▌▐▙▞▀▜ ▛▖    │

For a nightly batch whose log is read over SSH from a phone: no image, no artefact to fetch, the log is the only surface. Needs console_width=120 to avoid being wrapped — why. → docs/plots.md

Probing

from utilities import probed
from utilities.probe import probe, report

@probed()
def fetch_rows(cursor, sql):
    cursor.execute(sql)
    return cursor.fetchall()

with probe("materialize"):
    rows = [dict(r) for r in raw]
PROBE_TIER=1 python my_script.py
label                                  n       wall       self       wait        mean         p95
-------------------------------------------------------------------------------------------------
db.execute                             4     4.310s     4.310s     4.290s   1077.50ms   1131.02ms
transform                              1     0.412s     0.412s     0.001s    412.30ms    412.30ms
  • wait = wall - cpu — the column that decides what to do next. Close to wall, you are waiting on a database or a network share and rewriting Python will gain you nothing. Close to zero, the code is the problem.
  • self = wall - children — cProfile's tottime. A function that only delegates tops the wall ranking while being innocent.

Zero cost when off: at PROBE_TIER=0, probed() returns your function unchanged — 0.0 ns measured, no wrapper, not even a flag test. That is what makes it safe to leave in production code. The tier is read once at import and cannot be changed at runtime; that is the price of the guarantee.

Only instrument blocks of 400 µs or more, and never read latency from a PROBE_TIER=2 run — tracemalloc slows the whole process 11×. → docs/probe.md

probe tells you which block costs. To find out why, inside it:

uv run --with pyinstrument pyinstrument my_script.py

Examples

Every script in examples/ runs on its own with no arguments.

  • examples/probe/ — the three tiers side by side, the overhead measured on your machine, CPU vs I/O, nesting, asyncio, output formats
  • examples/log/ — levels and namespaces, the four frame modes, the four charts, costs, three traps, and a batch as it reads in a tail -f

Two playgrounds exist as both a notebook and a # %%-cell script: log_playground and probe_playground.

Structure

src/utilities/
├── config/      configuration store
├── log/         setup, levels, frames, plots, helpers
├── probe/       latency and memory instrumentation
└── utils/       folder helpers
docs/            full documentation
examples/        runnable demos and notebooks
tests/           test suite

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

utilities_toolkit-1.1.0.tar.gz (30.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

utilities_toolkit-1.1.0-py3-none-any.whl (36.6 kB view details)

Uploaded Python 3

File details

Details for the file utilities_toolkit-1.1.0.tar.gz.

File metadata

  • Download URL: utilities_toolkit-1.1.0.tar.gz
  • Upload date:
  • Size: 30.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for utilities_toolkit-1.1.0.tar.gz
Algorithm Hash digest
SHA256 6c967ee8933c25bde252442727800692871ed6ef2af78f5fd999c15a8bea3549
MD5 d0523ecf6d9d2df9be8f942f1424e101
BLAKE2b-256 c3d7a053f80194b77847bec7a48ad1d114f08d7b236415acd8d759ab90bbd8ed

See more details on using hashes here.

File details

Details for the file utilities_toolkit-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: utilities_toolkit-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 36.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for utilities_toolkit-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a72efcbf699b2585ee204de21efc9e76e8e0cca41e4b1c6a6892825a5d3cfa73
MD5 ca910c0e93bf6d1037c49c2633ce4707
BLAKE2b-256 b31700f010786133cf45a10fad617241be97df8880d5cf1753eea35d43d237d0

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 files

1.0.0

2 files

0.3.0

2 files

0.2.0

2 files

0.1.3

2 files

0.1.2

2 files

0.1.0

2 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