finprint.tracked
module finprint
Proxies that record what is done to a frame: TrackedFrame, TrackedSeries and their helpers.
A TrackedFrame wraps a DataFrame and forwards everything to it. Public methods that return a DataFrame are
recorded as verb steps and their results are tracked; methods that return a Series give a TrackedSeries
that remembers how it was built (an expression over frame versions), so df["net"] = df["spend"] * 0.85 can
be replayed. groupby, rolling, resample, expanding and ewm return a deferred object whose
next aggregation is recorded as one step. In-place edits (__setitem__, .loc/.iloc setters,
inplace=True, setting columns) are recorded as verbs that give the frame a new version id.
pandas is never patched: code that never touches a proxy behaves exactly as before. pandas functions do not
accept a proxy: pd.merge(a, b), pd.concat([a, b]), pd.to_datetime(s) and pd.DataFrame(a) raise a
TypeError that names the recorded alternative (the method form a.merge(b), rec.concat / rec.merge /
rec.call), because their result would come back untracked and the step would be lost. Operators mixing a
plain pandas object with a proxy (plain * tracked) defer to the proxy (__pandas_priority__) and are
recorded. ur.untrack(frame) gives the real object for libraries that need one.
Edits made through a tracked series (s[mask] = v, s.loc[k] = v, s.clip(..., inplace=True),
s.name = ...) become part of the series’ expression, so a column assigned from it later replays with them.
A value computed from tracked data (s.median(), s.quantile(0.9), s.max(), s.iloc[0], df.at[k, c],
a number, date, duration or text; never a yes/no answer such as s.any()) is a TrackedScalar: it carries its
expression, so a step using it records the expression ({"__scalar__": ...}) and apply recomputes it on new data.
Arithmetic, comparisons, round/abs/math.floor, NumPy ufuncs and its own methods (ts.normalize()) stay
tracked. Taking the plain value out (float, int, str/format, bool in an if, np.asarray,
math.log, fp.untrack) tells the session, which marks the next step using that literal (or, for bool,
the next step recorded) so apply refuses it.
Classes
Section titled “Classes”TrackedFrame
Section titled “TrackedFrame”class
class TrackedFrame(TrackedBase)A DataFrame proxy bound to a session. Every frame version has an id (in1, f7…).
Methods and properties (2)
init constructor
TrackedFrame( self, df: pd.DataFrame, session: Session, fid: str, state: str | None = None,) -> Noneframe_id property
frame_id: strThe id of this frame’s current version (as steps in the recipe name it).
Source: packages/finprint/src/finprint/tracked.py, line 91
TrackedSeries
Section titled “TrackedSeries”class
class TrackedSeries(TrackedBase)A Series proxy that remembers its expression over frame versions (never recorded as a step by itself).
Methods and properties (1)
init constructor
TrackedSeries( self, s: pd.Series, session: Session, expr: Any, refs: list[str], replayable: bool,) -> NoneSource: packages/finprint/src/finprint/tracked.py, line 317
TrackedAccessor
Section titled “TrackedAccessor”class
class TrackedAccessorseries.str / .dt / .cat on a tracked series.
Methods and properties (1)
init constructor
TrackedAccessor( self, sess: Session, node: Any, refs: list[str], rep: bool, acc: Any,) -> NoneSource: packages/finprint/src/finprint/tracked.py, line 500
TrackedIndexer
Section titled “TrackedIndexer”class
class TrackedIndexerframe.loc / .iloc / .at / .iat: reads are verbs, writes are in-place verbs.
Methods and properties (1)
init constructor
TrackedIndexer(self, tf: TrackedFrame, kind: str) -> NoneSource: packages/finprint/src/finprint/tracked.py, line 534
TrackedDeferred
Section titled “TrackedDeferred”class
class TrackedDeferredA tracked groupby (or rolling, resample, expanding, ewm): the next aggregation is recorded as one step.
Methods and properties (1)
init constructor
TrackedDeferred( self, sess: Session, verb: str, self_node: Any, refs: list[str], call: dict[str, Any], select: Any, obj: Any, rep: bool, reasons: list[str],) -> NoneSource: packages/finprint/src/finprint/tracked.py, line 569
TrackedScalar
Section titled “TrackedScalar”class
class TrackedScalar(TrackedBase)A value computed from tracked data (s.median(), s.max() - pd.Timedelta(weeks=52), s.iloc[0]).
It behaves like its value in pandas calls and arithmetic, and a step that uses it records its expression
({"__scalar__": ...}), so verify recomputes the same value from the same data and apply recomputes it on new
data. The plain value comes out through float, int, str/format, bool, np.asarray or
fp.untrack; the session is told, and a step that then uses the literal is refused by apply
(DATA_DERIVED_LITERAL). repr shows the value and tells nobody.
Methods and properties (1)
init constructor
TrackedScalar( self, v: Any, session: Session, expr: Any, refs: list[str], replayable: bool,) -> NoneSource: packages/finprint/src/finprint/tracked.py, line 657
Functions
Section titled “Functions”renders_text
Section titled “renders_text”function
def renders_text(node: Any) -> boolA to_* call (to_csv(), to_json(), to_string()): its text is output for the analyst, not a value a
later step computes with, so it stays a plain str.
Source: packages/finprint/src/finprint/tracked.py, line 77
traceable
Section titled “traceable”function
def traceable(v: Any, *, allow_bool: bool = False) -> boolA result worth tracking as a computed value: a number, date, duration or text (a bool only from scalar maths).
Source: packages/finprint/src/finprint/tracked.py, line 84
Constants
Section titled “Constants”| Name | Type | Value | Description |
|---|---|---|---|
DEFERRED | {'groupby', 'rolling', 'expanding', 'ewm', 'resample'} | ||
INDEXERS | {'loc', 'iloc', 'at', 'iat'} | ||
SERIES_ACCESSORS | {'str', 'dt', 'cat'} | ||
PANDAS_FUNCTION_MESSAGE | 'pandas functions do not accept a tracked {what}: the result would come back ... |