Utilities¶
concurrency
¶
Concurrency utility helpers.
RLock
¶
A re-entrant lock that copies and pickles as a fresh, unheld lock.
A drop-in for threading.RLock on models that get deep-copied, as a
destination does with the source it is bound to: a bare lock cannot be
copied. A copy never shares the original's lock, so it starts unheld.
Create the underlying lock.
acquire
¶
Acquire the lock, re-entrantly for the thread already holding it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
blocking
|
bool
|
Whether to wait for the lock when another thread holds it. |
True
|
timeout
|
float
|
Seconds to wait at most when blocking; |
-1
|
Returns:
| Type | Description |
|---|---|
bool
|
Whether the lock was acquired. |
ThreadLocal
¶
Bases: _thread._local
Per-thread attributes that copy and pickle as a fresh, empty namespace.
A drop-in for threading.local on models that get deep-copied: a bare
one cannot be copied, and a copy has no claim on the original's threads.
run
¶
Run a coroutine to completion from synchronous code.
The sync bridge to the async-native engine. It backs the sync
entrypoints — asset.run(), asset.materialize(),
dag.materialize() — and can be called directly to drive any other
framework coroutine (e.g. a configured runner) from a script, a REPL,
or a notebook cell without touching asyncio:
Unlike asyncio.run, this works where an event loop is already
running (Jupyter) and reuses one persistent background loop across
calls, so loop-bound clients cached on connections stay valid from one
invocation to the next. Async code should await the coroutine
directly instead.
Ctrl-C cancels the coroutine before re-raising KeyboardInterrupt.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
coro
|
Coroutine[Any, Any, _T]
|
The coroutine to execute. |
required |
Returns:
| Type | Description |
|---|---|
_T
|
The coroutine's result. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If called from code already running on the bridge's
own loop ( |
KeyboardInterrupt
|
Re-raised after cancelling the coroutine. |
bounded_gather
¶
Await coroutines concurrently, capped at limit in flight at once.
Results are returned in the order the coroutines were given (like
asyncio.gather), but at most limit run concurrently — the bound is
what keeps fan-out (paginated pages, per-entity requests) from stampeding an
API into rate limits. If any coroutine raises, the exception propagates and
the rest are cancelled.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
coros
|
Iterable[Coroutine[Any, Any, _T]]
|
The coroutines to run. |
required |
limit
|
int
|
Maximum number of coroutines in flight at once (must be >= 1). |
required |
Returns:
| Type | Description |
|---|---|
list[_T]
|
The results, ordered to match |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
invoke
¶
Call a sync or async callable uniformly on the event loop.
Async callables are awaited natively; sync ones are offloaded to a
worker thread via asyncio.to_thread so they never block the loop.
This is how the framework lets data(), destination read/write
and fetch-field providers be written as either sync or async while the
engine stays async-native.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fn
|
Any
|
The callable to invoke. |
required |
*args
|
Any
|
Positional arguments forwarded to |
required |
**kwargs
|
Any
|
Keyword arguments forwarded to |
required |
Returns:
| Type | Description |
|---|---|
Any
|
The callable's result. |
data
¶
Data utility helpers.
is_empty
¶
Return whether a value carries no data.
Kept deliberately conservative: only values we can positively confirm
are empty count as empty, so callers never skip work on a value they don't
understand. None is empty; objects exposing a boolean empty (pandas
/ polars DataFrames and Series — whose own bool() raises) defer to it;
sized containers (lists, dicts, ...) are empty when their length is zero.
Anything else (e.g. a lazy generator we must not consume) is treated as
non-empty.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
Any
|
The value to inspect; any type, never consumed. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True only when the value is positively confirmed to carry no data. |
text
¶
Text processing utilities for naming, casing, and labeling.
validate_key
¶
Validate that key starts with a letter and contains only letters, numbers, and underscores.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The key to validate. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the key is invalid. |
to_identifier
¶
Coerce text into a lowercase identifier (letters, digits, underscores).
Unlike to_snake_case, existing underscores are preserved verbatim
(including __ runs used as name separators) — only invalid characters
are replaced.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The text to coerce. |
required |
Returns:
| Type | Description |
|---|---|
str
|
The coerced text. |
to_label
¶
Convert text to a human-readable title-cased label.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The text to convert. |
required |
Returns:
| Type | Description |
|---|---|
str
|
The converted text. |
to_snake_case
¶
Convert text to snake_case.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The text to convert. |
required |
Returns:
| Type | Description |
|---|---|
str
|
The converted text. |
time
¶
Date and datetime helpers shared across the framework.
coerce_to_date
¶
Coerce a value to a datetime.date.
Accepts a date, a datetime (its date part is used), or an ISO-8601
date string. Anything else raises TypeError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
object
|
The value to coerce. |
required |
Returns:
| Type | Description |
|---|---|
date
|
The value as a |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the value cannot be interpreted as a date. |
coerce_to_datetime
¶
Coerce a value to a naive-UTC datetime.datetime.
Accepts a datetime, a date (midnight is assumed), or an ISO-8601
datetime string. Anything else raises TypeError.
The result is a UTC label, not an instant: an aware datetime is converted to UTC and stripped of its tzinfo, so comparisons never mix aware and naive values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
object
|
The value to coerce. |
required |
Returns:
| Type | Description |
|---|---|
datetime
|
The value as a |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the value cannot be interpreted as a datetime. |
add_months
¶
Shift a date by months, clamping the day to the target month's length.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
date
|
The date to shift. |
required |
months
|
int
|
Number of months to add; negative shifts backwards. |
required |
Returns:
| Type | Description |
|---|---|
date
|
The shifted date. |
assume_utc
¶
Treat a naive timestamp as UTC, leaving an aware one alone.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
datetime
|
The timestamp to normalise, aware or naive. |
required |
Returns:
| Type | Description |
|---|---|
datetime
|
An aware datetime; an already-aware value is returned unchanged. |
month_start
¶
The first day of the UTC calendar month a timestamp falls in.
Naive values are treated as UTC, so a timestamp read back from a database that drops tzinfo attributes to the same month it was written in.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
datetime
|
The timestamp to attribute, aware or naive. |
required |
Returns:
| Type | Description |
|---|---|
date
|
The first day of that UTC month, as a date. |
imports
¶
Dynamic import helpers.
import_from_path
¶
Import an object from a path.
Two forms are supported:
- Dotted path —
"module.submodule.ClassName": imports the parent module, then does a singlegetattrfor the final name. - Composite path —
"module.submodule:ClassName.nested": the colon marks the module / attribute boundary explicitly. Everything before:is imported as a module, everything after is a chain ofgetattrcalls on the imported object. This is the form emitted byAsset.classpathfor source-owned assets so that the asset class can be reached via a class-level descriptor without instantiating its parent source.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
Dotted or composite import path. |
required |
Returns:
| Type | Description |
|---|---|
Any
|
The imported object. |
get_object_path
¶
Return the dotted import path for a class or function.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
Any
|
A class or function. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Dotted path string like |
stats
¶
Statistics over plain samples.
percentile
¶
The nearest-rank q-th percentile of values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
values
|
Sequence[float]
|
The sample; order does not matter. |
required |
q
|
float
|
Percentile in |
required |
Returns:
| Type | Description |
|---|---|
float | None
|
The sample value at that rank, or |