unstd 3.1.0__cp313-cp313-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- unstd/__init__.py +86 -0
- unstd/_extra.py +28 -0
- unstd/audio/README.md +86 -0
- unstd/audio/__init__.py +22 -0
- unstd/audio/wavx.py +535 -0
- unstd/clone/README.md +91 -0
- unstd/clone/__init__.py +27 -0
- unstd/clone/structural.py +312 -0
- unstd/compress/README.md +45 -0
- unstd/compress/__init__.py +5 -0
- unstd/compress/_backend.py +64 -0
- unstd/compress/_inflate.py +127 -0
- unstd/compress/gzipx.py +222 -0
- unstd/containers/README.md +78 -0
- unstd/containers/__init__.py +34 -0
- unstd/containers/persistent.py +50 -0
- unstd/containers/sorted.py +53 -0
- unstd/crypto/README.md +102 -0
- unstd/crypto/__init__.py +20 -0
- unstd/crypto/_blake3.py +19 -0
- unstd/crypto/digest.py +138 -0
- unstd/crypto/tls.py +81 -0
- unstd/crypto/token.py +149 -0
- unstd/fs/README.md +62 -0
- unstd/fs/__init__.py +279 -0
- unstd/ids/README.md +38 -0
- unstd/ids/__init__.py +17 -0
- unstd/ids/uid.py +165 -0
- unstd/iters/README.md +63 -0
- unstd/iters/__init__.py +59 -0
- unstd/iters/consecutive.py +122 -0
- unstd/iters/distinct.py +76 -0
- unstd/iters/reshape.py +52 -0
- unstd/iters/select.py +134 -0
- unstd/model/README.md +74 -0
- unstd/model/__init__.py +31 -0
- unstd/model/base.py +74 -0
- unstd/model/settings.py +47 -0
- unstd/pack/README.md +104 -0
- unstd/pack/__init__.py +15 -0
- unstd/pack/binpack.py +203 -0
- unstd/proc/README.md +58 -0
- unstd/proc/__init__.py +258 -0
- unstd/py.typed +0 -0
- unstd/rand/README.md +75 -0
- unstd/rand/__init__.py +64 -0
- unstd/rand/crypto.py +48 -0
- unstd/rand/draw.py +148 -0
- unstd/rex/README.md +89 -0
- unstd/rex/__init__.py +363 -0
- unstd/rex/_faithful.py +321 -0
- unstd/serde/README.md +318 -0
- unstd/serde/__init__.py +24 -0
- unstd/serde/_json_common.py +16 -0
- unstd/serde/_json_decode_native.h +411 -0
- unstd/serde/_json_encode.py +199 -0
- unstd/serde/_json_encode_native.h +119 -0
- unstd/serde/_json_lines_native.h +99 -0
- unstd/serde/_json_native.c +676 -0
- unstd/serde/_json_native.cp313-win_amd64.pyd +0 -0
- unstd/serde/_json_native.pyi +16 -0
- unstd/serde/b64.py +272 -0
- unstd/serde/jsonx.py +411 -0
- unstd/serde/ndjson.py +336 -0
- unstd/serde/structs.py +144 -0
- unstd/text/README.md +93 -0
- unstd/text/__init__.py +13 -0
- unstd/text/fuzz.py +413 -0
- unstd/time/README.md +69 -0
- unstd/time/__init__.py +15 -0
- unstd/time/timeutil.py +292 -0
- unstd/time/zoned.py +133 -0
- unstd/toml/README.md +75 -0
- unstd/toml/__init__.py +129 -0
- unstd/yaml/README.md +48 -0
- unstd/yaml/__init__.py +182 -0
- unstd-3.1.0.dist-info/METADATA +152 -0
- unstd-3.1.0.dist-info/RECORD +81 -0
- unstd-3.1.0.dist-info/WHEEL +4 -0
- unstd-3.1.0.dist-info/licenses/LICENSE +202 -0
- unstd-3.1.0.dist-info/licenses/NOTICE +17 -0
unstd/__init__.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""unstd — the unstandardized library.
|
|
2
|
+
|
|
3
|
+
Best-in-class native codecs behind small, **stdlib-faithful** surfaces: migrate a
|
|
4
|
+
call site by swapping the import, not the call. The base install is pure stdlib —
|
|
5
|
+
depending on ``unstd`` costs zero third-party closure — and each accelerated
|
|
6
|
+
backend rides an optional extra with a guarded stdlib fallback, so a lightweight
|
|
7
|
+
consumer never inherits a heavy dependency graph.
|
|
8
|
+
|
|
9
|
+
Module groups (grown incrementally from the stdlib census) — each named for the
|
|
10
|
+
stdlib surface it stands in for, and each either degrading to that surface or
|
|
11
|
+
failing loud where no faithful substitute exists:
|
|
12
|
+
|
|
13
|
+
- ``serde`` (``json`` / ``base64``) — ``jsonx`` (orjson/msgspec) · ``b64`` (pybase64) ·
|
|
14
|
+
``ndjson`` (newline-delimited, rides ``jsonx``) · ``structs`` (msgspec, no
|
|
15
|
+
stdlib equivalent). Behind the ``serde`` extra; the rest fall back to stdlib.
|
|
16
|
+
- ``ids`` (``uuid``) — ``uid``: UUIDv7 minting and v5 derivation, falling back to
|
|
17
|
+
a stdlib generator. Behind the ``ids`` extra.
|
|
18
|
+
- ``crypto`` (``hashlib`` / ``hmac`` / ``ssl``) — BLAKE3 digests (content
|
|
19
|
+
hashes and short ids included), key derivation, keyed MACs and the bearer
|
|
20
|
+
envelope, constant-time compare, and a verifying TLS client policy. No
|
|
21
|
+
fallback: ``hashlib`` ships BLAKE2, which is a different algorithm, not a
|
|
22
|
+
slower one.
|
|
23
|
+
- ``time`` — ``timeutil`` (clocks, RFC-3339 formatting, ISO parsing, instant
|
|
24
|
+
arithmetic — pure stdlib; its protobuf ``Timestamp`` bridge is behind the
|
|
25
|
+
``proto`` extra) · ``zoned`` (DST-correct wall-clock time over ``whenever``,
|
|
26
|
+
behind the ``time`` extra).
|
|
27
|
+
- ``model`` — the strict Pydantic wire-shape spine: ``StrictModel`` ·
|
|
28
|
+
``FrozenModel`` · ``StrictSettings``. Behind the ``model`` extra (pydantic has
|
|
29
|
+
no stdlib equivalent, so there is no fallback).
|
|
30
|
+
- ``rex`` (``re``) — irregex linear-time matching, falls back to ``re``; the
|
|
31
|
+
flag and type vocabulary is re-exported verbatim.
|
|
32
|
+
- ``containers`` (``collections``) — always-sorted collections and a persistent
|
|
33
|
+
HAMT ``Map``. No faithful fallback (an ``O(n)`` stand-in would be a silent
|
|
34
|
+
lie), so the placeholders raise on construction.
|
|
35
|
+
- ``rand`` (``random``) — numpy PCG64 bulk draws; security-sensitive draws stay
|
|
36
|
+
on ``secrets`` regardless of the extra.
|
|
37
|
+
- ``pack`` (``struct``) — numpy bulk pack/unpack.
|
|
38
|
+
- ``clone`` (``copy``) — an exact-type structural deep clone, pure stdlib.
|
|
39
|
+
- ``text`` (``difflib``) — rapidfuzz similarity and fuzzy matching.
|
|
40
|
+
- ``audio`` (``wave``) — soundfile read/write plus a streaming writer.
|
|
41
|
+
- ``toml`` (``tomllib``) — reading is stdlib; writing needs tomlkit.
|
|
42
|
+
- ``yaml`` — safe YAML 1.2 and comment-preserving edits; requires the ``yaml`` extra.
|
|
43
|
+
- ``compress`` (``gzip``) — zlib-ng codecs behind ``gzipx``; the ``compress``
|
|
44
|
+
extra accelerates compression and inflation, with a stdlib fallback.
|
|
45
|
+
- ``proc`` (``subprocess``) · ``fs`` (``os``) · ``iters`` (``itertools``) —
|
|
46
|
+
pure stdlib, no extra, always present in the base install.
|
|
47
|
+
|
|
48
|
+
Import the module, not its members::
|
|
49
|
+
|
|
50
|
+
from unstd.serde import jsonx, b64, structs, ndjson
|
|
51
|
+
from unstd.ids import uid
|
|
52
|
+
from unstd.crypto import digest, token
|
|
53
|
+
from unstd.time import timeutil, zoned
|
|
54
|
+
from unstd.model import StrictModel, FrozenModel, StrictSettings
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
from __future__ import annotations
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
__version__: str
|
|
61
|
+
|
|
62
|
+
# A reload should refresh a version cached by a previous attribute access.
|
|
63
|
+
globals().pop("__version__", None)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def __getattr__(name: str) -> str:
|
|
67
|
+
"""Resolve and cache the installed version only when it is requested."""
|
|
68
|
+
if name != "__version__":
|
|
69
|
+
msg = f"module {__name__!r} has no attribute {name!r}"
|
|
70
|
+
raise AttributeError(msg)
|
|
71
|
+
|
|
72
|
+
# Metadata discovery imports a large stdlib closure and scans distributions.
|
|
73
|
+
# Submodule consumers (including native codecs) do not need to pay that cost.
|
|
74
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
resolved = version("unstd")
|
|
78
|
+
except PackageNotFoundError: # source tree that was never installed
|
|
79
|
+
resolved = "0.0.0.dev0"
|
|
80
|
+
globals()[name] = resolved
|
|
81
|
+
return resolved
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def __dir__() -> list[str]:
|
|
85
|
+
"""Include the lazy version attribute without resolving install metadata."""
|
|
86
|
+
return sorted({*globals(), "__version__"})
|
unstd/_extra.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""The deferred-raise placeholder every capability without a stdlib fallback binds.
|
|
2
|
+
|
|
3
|
+
Where a backend has no faithful substitute (a sorted container, a persistent
|
|
4
|
+
trie, a TOML writer), its public name still has to exist so the module imports
|
|
5
|
+
cleanly on a base install. :func:`missing` is that name: calling it raises an
|
|
6
|
+
``ImportError`` naming the extra that fixes it, so a consumer that never touches
|
|
7
|
+
the capability pays nothing, and one that does gets a one-line fix.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import TYPE_CHECKING, Never
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from collections.abc import Callable
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def missing(qualname: str, extra: str) -> Callable[..., Never]:
|
|
20
|
+
"""A stand-in for ``unstd.<qualname>`` that raises naming the ``extra`` it needs."""
|
|
21
|
+
msg = f"unstd.{qualname} requires the {extra!r} extra — install with: pip install 'unstd[{extra}]'"
|
|
22
|
+
|
|
23
|
+
def _raise(*_args: object, **_kwargs: object) -> Never:
|
|
24
|
+
raise ImportError(msg)
|
|
25
|
+
|
|
26
|
+
_raise.__name__ = _raise.__qualname__ = qualname.rpartition(".")[2]
|
|
27
|
+
_raise.__doc__ = f"Unavailable — {msg}."
|
|
28
|
+
return _raise
|
unstd/audio/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# `unstd.audio`
|
|
2
|
+
|
|
3
|
+
Part of [`unstd`](../README.md). A stdlib-`wave`-faithful **replacement**
|
|
4
|
+
that hands back sample _arrays_ instead of raw frame bytes — the shape a voice
|
|
5
|
+
path (TTS/STT) actually wants. The stdlib `wave` module only exposes packed
|
|
6
|
+
PCM byte strings; every call site then re-rolls the same `struct`/`array`
|
|
7
|
+
unpacking. `unstd.audio` folds that decode into the reader and the encode into the
|
|
8
|
+
writer.
|
|
9
|
+
|
|
10
|
+
## Modules
|
|
11
|
+
|
|
12
|
+
| File | Role |
|
|
13
|
+
| --------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
14
|
+
| `wavx.py` | `read`/`write` (whole-file) · `blocks`/`Writer` (streaming) · `wrap_pcm` — numpy-native WAV samples ↔ file. |
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from unstd.audio import wavx
|
|
18
|
+
|
|
19
|
+
samples, sr = wavx.read("in.wav") # float32 in [-1, 1], sr = Hz
|
|
20
|
+
wavx.write("out.wav", samples, sr) # PCM_16 by default
|
|
21
|
+
ints, sr = wavx.read("in.wav", dtype="int16") # raw signed 16-bit
|
|
22
|
+
|
|
23
|
+
# streaming — for a live TTS/STT pipeline, not a file already fully in memory:
|
|
24
|
+
with wavx.Writer("out.wav", sr, channels=1) as w:
|
|
25
|
+
for chunk in synth_chunks:
|
|
26
|
+
w.write(chunk)
|
|
27
|
+
for block in wavx.blocks("in.wav", blocksize=4096):
|
|
28
|
+
play(block)
|
|
29
|
+
|
|
30
|
+
wavx.wrap_pcm(raw_pcm_bytes, sr, channels=1, width=2) # header only, no decode
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Mono is 1-D `(frames,)`; multichannel is 2-D `(frames, channels)` — the shape
|
|
34
|
+
libsndfile/`soundfile` use. Float samples written are clamped to `[-1, 1]` then
|
|
35
|
+
quantized; integer samples are written as-is.
|
|
36
|
+
|
|
37
|
+
## Backend
|
|
38
|
+
|
|
39
|
+
The `audio` extra (`pip install 'unstd[audio]'`) provides `soundfile==…` +
|
|
40
|
+
`numpy==2.5.0`, so reads/writes ride **libsndfile** and samples are
|
|
41
|
+
`numpy.ndarray`. Without it there are two guarded stdlib fallbacks:
|
|
42
|
+
|
|
43
|
+
| Path | When | Samples | Read widths | Write subtypes |
|
|
44
|
+
| ----------------------- | ---------------------------- | ------------------- | ----------- | ----------------- |
|
|
45
|
+
| `soundfile` + `numpy` | `audio` extra installed | `ndarray` | libsndfile | libsndfile |
|
|
46
|
+
| stdlib `wave` + `numpy` | numpy present, no soundfile | `ndarray` | 8/16/32-bit | `PCM_16`/`PCM_32` |
|
|
47
|
+
| stdlib `wave` + `array` | no numpy (pure-stdlib floor) | `list`/`list[list]` | 16-bit | `PCM_16` |
|
|
48
|
+
|
|
49
|
+
The pure-stdlib floor deliberately trades ergonomics for zero dependencies:
|
|
50
|
+
16-bit PCM only, Python lists, no vectorization. Wider widths / other subtypes
|
|
51
|
+
raise a clear error pointing at the `audio` extra rather than silently degrading.
|
|
52
|
+
|
|
53
|
+
**Fixed-point scaling is identical on every path** so a file written by one reads
|
|
54
|
+
back consistently on another: a _w_-bit sample ↔ float via `± 2**(w-1)`, so
|
|
55
|
+
`float32 → PCM16 → float32` round-trips lossless to within one quantization step
|
|
56
|
+
(`1/32768`).
|
|
57
|
+
|
|
58
|
+
## Streaming — `Writer` / `blocks`
|
|
59
|
+
|
|
60
|
+
`read`/`write` buffer the whole file; a live pipeline (streaming TTS
|
|
61
|
+
synthesis, STT playback) wants frames as they arrive instead. `Writer` is a
|
|
62
|
+
context manager — `channels`/`subtype` are fixed up front (a stream has no
|
|
63
|
+
complete array to infer them from), and each `.write(chunk)` call appends one
|
|
64
|
+
chunk; `blocks(path, blocksize)` is the read-side generator, `blocksize`
|
|
65
|
+
frames at a time. Fast path: `soundfile`'s own `SoundFile`/`blocks` streaming
|
|
66
|
+
API. Fallback: stdlib `wave`'s `writeframesraw`/chunked `readframes`, which
|
|
67
|
+
requires the write target be **seekable** (a real file path, or a file object
|
|
68
|
+
opened on one) so `close()` can patch the RIFF/`data` sizes — a genuinely
|
|
69
|
+
non-seekable sink (a raw socket) needs the `audio` extra.
|
|
70
|
+
|
|
71
|
+
## `wrap_pcm` — a header, nothing else
|
|
72
|
+
|
|
73
|
+
Some PCM never becomes samples: bytes straight off a wire (a codec's output, a
|
|
74
|
+
socket frame, a transcription upload) just need a RIFF/WAVE container around
|
|
75
|
+
them. `wrap_pcm(raw, samplerate, channels=1, width=2)` does exactly that — no
|
|
76
|
+
scale, no clamp, no requantize — where routing the same bytes through
|
|
77
|
+
`write` would decode to an array and re-quantize back, paying two
|
|
78
|
+
conversions and a quantization step to reproduce its own input.
|
|
79
|
+
|
|
80
|
+
## Prior art
|
|
81
|
+
|
|
82
|
+
- **[`soundfile`](https://github.com/bastibe/python-soundfile)** (Bastian
|
|
83
|
+
Bechtold) — Python bindings over **[libsndfile](https://libsndfile.github.io/libsndfile/)**
|
|
84
|
+
(Erik de Castro Lopo), the fast path this module wraps.
|
|
85
|
+
- The stdlib [`wave`](https://docs.python.org/3/library/wave.html) module — the
|
|
86
|
+
raw-frame surface `unstd.audio` replaces, and the fallback codec.
|
unstd/audio/__init__.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Audio I/O — numpy-native WAV read/write for voice paths.
|
|
2
|
+
|
|
3
|
+
A stdlib-``wave``-faithful *replacement* that hands back sample **arrays** instead
|
|
4
|
+
of raw frame bytes. The stdlib ``wave`` module only exposes packed PCM byte
|
|
5
|
+
strings; every TTS/STT call site then re-rolls the same ``struct``/``array``
|
|
6
|
+
unpacking. ``unstd.audio`` folds that decode into the reader and the encode into
|
|
7
|
+
the writer, so the surface is samples-in / samples-out.
|
|
8
|
+
|
|
9
|
+
Backend & fallback: the ``audio`` extra provides ``soundfile``
|
|
10
|
+
(libsndfile bindings) + ``numpy``. When present, reads/writes ride libsndfile and
|
|
11
|
+
samples are ``numpy`` arrays. Without the extra (a base ``unstd`` install) the
|
|
12
|
+
module falls back to the stdlib ``wave`` module plus manual PCM↔numpy conversion,
|
|
13
|
+
or — when ``numpy`` is also absent — the stdlib ``array`` module (reduced
|
|
14
|
+
ergonomics: 16-bit PCM only, Python ``list`` samples). The public surface works
|
|
15
|
+
everywhere; only the codec and the sample container differ.
|
|
16
|
+
|
|
17
|
+
Import the module, not its members::
|
|
18
|
+
|
|
19
|
+
from unstd.audio import wavx
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|