Skip to content

finprint.encoding

module finprint

Tagged JSON for step arguments and series expressions, and the inverse used by replay.

Arguments are stored as JSON-safe values. Values JSON cannot carry are tagged objects:

===================== ===================================================== {"__frame__": id} a tracked frame (or a series a step produced), by id {"__expr__": node} a tracked series built from frames (see below) {"__tuple__": []} tuple; __set__ set; __slice__ [start, stop, step] {"__dict__": []} mapping with non-string keys, as [[key, value], …] {"__ts__": iso} timestamp; __date__, __td__ (timedelta), __na__ (NA / NaT), __float__ (nan/inf) {"__dtype__": s} a dtype; {"__callable__": "module:qualname"} a function on the replay allowlist (pure pandas, numpy, math, statistics, datetime and builtins functions); {"__index__": [...]} a pandas Index of labels; {"__module__": name} a module a named step uses {"__scalar__": e} a value computed from tracked data (s.median(), s.max() - 52 weeks, s.iloc[0]): the expression e, evaluated again on replay, so apply recomputes it on new data {"__opaque__": s} something that could not be recorded (lambda, untracked frame, array); not replayable {"__truncated__":} a string longer than 200 characters (prefix, length, sha256); not replayable ===================== =====================================================

Expression nodes: {"__col__": {"frame", "name"}}, {"__ref__": id}, {"__op__": {"self", "name", "args", "kwargs"}}`, `{"__attr__": {"self", "name"}}`, `{"__acc__": {"self", "accessor"}}`, `{"__idx__": {"frame", "kind"}}`, `{"__ufunc__": {"name", "args", "kwargs"}}`, `{"__sop__": {"op", "args"}} (arithmetic, a comparison or round/abs/math.floor on scalars, from SCALAR_OPS only), and for edits made through a tracked series {"__setv__": {"self", "indexer", "key", "value"}} (s[k] = v, s.loc[k] = v) and {"__seta__": {"self", "name", "value"}}` (`s.name = v`); an `__op__` with `inplace=True replays on a copy. Nothing is ever pickled.

Replay is data-driven and never runs a string: callables resolve only through the allowlist in resolve_callable, method and attribute names must be public (or operator dunders) and never file I/O (to_csv, read_*).

class

class TrackedBase

Base of the proxies, so the encoder can recognise them without importing tracked.

Source: packages/finprint/src/finprint/encoding.py, line 103

class

class NotReplayable(Exception)

Raised when a recorded value cannot be rebuilt.

Source: packages/finprint/src/finprint/encoding.py, line 115

class

class NotAllowedInReplay(NotReplayable)

A recipe names a function, method or attribute that replay never runs (I/O, code execution, private names).

Source: packages/finprint/src/finprint/encoding.py, line 119

class

class Encoder

Accumulates whether everything encoded so far is replayable, the frame ids referenced and why not.

Fields

NameTypeDefaultDescription
exemptexempt
replayableTrue
refslist[str][]
reasonslist[str][]
Methods and properties (6)

init constructor

Encoder(self, *, pandas_call: bool = True, exempt: frozenset[str] | None = None) -> None

opaque method

def opaque(self, what: str) -> dict[str, Any]

text method

def text(self, v: str) -> Any

value method

def value(self, v: Any, name: str | None = None, rows: int | None = None) -> Any

A value assigned into a frame: a list of more than a few items is row values and never recorded.

enc method

def enc(self, v: Any, name: str | None = None) -> Any

call method

def call(
self,
args: tuple[Any, ...] | list[Any],
kwargs: Mapping[str, Any],
names: list[str | None] | None = None,
) -> dict[str, Any]

Source: packages/finprint/src/finprint/encoding.py, line 399

function

def safe_method(name: str) -> bool

A DataFrame or Series method name replay may call: public, or an operator dunder; never file I/O.

Source: packages/finprint/src/finprint/encoding.py, line 123

function

def check_method(name: str) -> str

Source: packages/finprint/src/finprint/encoding.py, line 130

function

def unsafe_function_arg(method: str, args: Any, kwargs: Any) -> str | None

The first string a recorded call would run as a method that safe_method refuses, else None.

For apply/agg/aggregate/transform/pipe/map the function slot (the first positional argument, or func/arg) is checked, and for agg/aggregate every named aggregation too; aggfunc is checked on any call (pivot_table).

Source: packages/finprint/src/finprint/encoding.py, line 164

function

def check_function_arg(method: str, args: Any, kwargs: Any) -> None

Source: packages/finprint/src/finprint/encoding.py, line 187

function

def eval_text_reason(expr: Any, names: set[str] | None) -> str | None

Why a query/eval expression is not something replay runs, else None. names are the @ names the recipe recorded for the call (None: the recorded values could not be read, so no @ name is allowed).

Source: packages/finprint/src/finprint/encoding.py, line 208

function

def eval_kwargs_reason(kwargs: Mapping[str, Any]) -> str | None

Keyword arguments to query/eval that replay never passes on (scope, engine or parser overrides).

Source: packages/finprint/src/finprint/encoding.py, line 236

function

def unsafe_eval_call(args: Any, kwargs: Any) -> str | None

Why a recorded query/eval call (its encoded arguments) is not something replay runs, else None.

Source: packages/finprint/src/finprint/encoding.py, line 261

function

def call_eval(target: Any, method: str, args: list[Any], kwargs: dict[str, Any]) -> Any

Run target.query/target.eval with decoded arguments, @ limited to the recorded local_dict and an empty global scope (global_dict={}, so the caller’s module globals are never visible).

Source: packages/finprint/src/finprint/encoding.py, line 292

function

def resolve_callable(name: str) -> Any

The function module:qualname names, only when it is on the replay allowlist (pure pandas, numpy, math, statistics, datetime and builtins functions; never exec, eval, open, getattr or file I/O).

Source: packages/finprint/src/finprint/encoding.py, line 340

function

def callable_name(f: Any) -> str | None

module:qualname when f is a function replay may call (see resolve_callable), else None.

Source: packages/finprint/src/finprint/encoding.py, line 363

function

def resolve_module(name: str) -> Any

Source: packages/finprint/src/finprint/encoding.py, line 382

function

def exempt_params(fn: Any) -> frozenset[str]

pandas’ own key/keys parameters of fn (they name columns, so they are not redacted).

Source: packages/finprint/src/finprint/encoding.py, line 388

function

def positional_names(
func: Any,
args: tuple[Any, ...],
kwargs: Mapping[str, Any],
*,
skip_self: bool,
) -> list[str | None]

Parameter names for positional arguments (for redaction), best effort.

Source: packages/finprint/src/finprint/encoding.py, line 540

function

def unwrap(v: Any) -> Any

Plain pandas objects for tracked ones, recursively through lists, tuples and dicts.

Source: packages/finprint/src/finprint/encoding.py, line 560

function

def tracked_in(v: Any) -> list[Any]

Tracked objects inside v (lists, tuples and dict values).

Source: packages/finprint/src/finprint/encoding.py, line 573

function

def decode(node: Any, ns: Mapping[str, Any], copy_frames: bool = True) -> Any

Source: packages/finprint/src/finprint/encoding.py, line 587

function

def eval_expr(node: Any, ns: Mapping[str, Any]) -> Any

Evaluate a series expression node against replayed frames (only public methods and operators run).

Source: packages/finprint/src/finprint/encoding.py, line 636

NameTypeValueDescription
ALLOWED_MODULES{'builtins', 'pandas', 'numpy', 'math', 'statistics', 'datetime'}
STEP_MODULESALLOWED_MODULES - {'builtins'} | {'re', 'string', 'itertools', 'functools', '...
PANDAS_KEY_PARAMSfrozenset({'key', 'keys'})
MAX_ITEMS256
MAX_VALUE_ITEMS16
SAFE_BUILTINSfrozenset({'abs', 'all', 'any', 'bool', 'dict', 'divmod', 'enumerate', 'filte...
BUILTIN_TYPESfrozenset({'str', 'int', 'float', 'bool', 'dict', 'list', 'tuple', 'set', 'fr...
DATETIME_TYPESfrozenset({'date', 'datetime', 'time', 'timedelta', 'timezone'})
NUMPY_FUNCS('where', 'select', 'clip', 'round', 'around', 'sum', 'mean', 'median', 'std'...
PANDAS_FUNCS('concat', 'merge', 'merge_asof', 'merge_ordered', 'to_datetime', 'to_numeric...
PANDAS_CLASSES('DataFrame', 'Series', 'Index', 'MultiIndex', 'DatetimeIndex', 'Categorical'...
IO_METHODSfrozenset({'to_csv', 'to_excel', 'to_parquet', 'to_pickle', 'to_json', 'to_sq...
SAFE_DUNDERSfrozenset({*(f'__{n}__' for n in ('add', 'sub', 'mul', 'truediv', 'floordiv',...
ACCESSORSfrozenset({'str', 'dt', 'cat', 'sparse', 'list', 'struct'})
SCALAR_OPSdict[str, Callable[..., Any]]{'add': operator.add, 'sub': operator.sub, 'mul': operator.mul, 'truediv': op...
FUNC_METHODSfrozenset({'apply', 'agg', 'aggregate', 'transform', 'pipe', 'map', 'applymap'})
LABEL_MAP_METHODSfrozenset[str]frozenset({'map', 'applymap'})Methods whose mapping argument holds labels (s.map({"a": "to_review"})), so its values are never method names.
EVAL_METHODSfrozenset({'query', 'eval'})