Skip to content

tdfs4ds.execution

tdfs4ds.execution

Feature ingestion and process execution for the tdfs4ds feature store.

Core execution call chain:

upload_features(df, entity_id, feature_names, ...)
  → register_process_view.__wrapped__(...)
  → execute_query(query_insert / query_insert_dist / query_insert_filtermanager)
  → [if optimize_query=True and instruct model available]
      → skill_optimize_query(process_id=process_id)
          → saves full Markdown report to tdfs4ds_optim_{timestamp}_{view}_{process_id}.md
          → if improvement found and update_view=True: REPLACE VIEW {view_name} AS {best_sql}
  → [if document=True and instruct model available]
      → document_process_incremental(process_id=process_id, display=False, upload=True)
  → run(process_id)          # ingests from the (now-optimized) view; builds dataset view if dataset_view_name set
  → [if document=True and instruct model available and dataset_view_name is not None]
      → document_dataset_incremental(dataset_id)   # bottom-up dataset docs after feature docs exist
      → SELECT * FROM process_catalog WHERE PROCESS_ID = ?
      → _upload_features(df, entity_id, feature_names, feature_versions=process_id, ...)
          → Gettdtypes / update_varchar_length / validate_feature_types
          → register_entity / register_features
          → _compute_features_batch(...)  [once, or per-filter loop]
              → followup_open
              → prepare_feature_ingestion   # unpivots df into volatile table
              → store_feature               # MERGE/UPDATE_INSERT into feature tables
              → followup_close (COMPLETED)
          → apply_collect_stats(...)        # called once after all batches

roll_out(process_list, time_manager, ...)
  → iterates time steps → run(process_id) per step

ACC_6881_HINT module-attribute

ACC_6881_HINT = "Error 6881 (not eligible for the Analytical Compute Cluster): for a tdstone2-Apply view that references a TimeManager/FilterManager, TWO things are needed — (a) the manager table on OFS (storage='OFS'), so the ACC can read it, AND (b) the filter written as a JOIN to the manager view, NOT a correlated scalar subquery '(SELECT BUSINESS_DATE FROM <view>)', which the ACC rejects. OFS + JOIN scores; OFS + scalar subquery still 6881s. The filter shape is the user's responsibility. Also: run the model's score() BEFORE upload_features — roll_out/run() cannot drive an Apply model (its ingestion CTAS also hits 6881)."

EMPTY_INGESTION_STATUS module-attribute

EMPTY_INGESTION_STATUS = 'COMPLETED,0 rows'

_FEATURE_VERSION_DEFAULT module-attribute

_FEATURE_VERSION_DEFAULT = 'dev.0.0'

_INTO_VOLATILE_ART_RE module-attribute

_INTO_VOLATILE_ART_RE = compile('INTO\\s+VOLATILE\\s+ART\\s*\\(\\s*([A-Za-z_\\"][\\w.\\"]*)', IGNORECASE)

_DATASET_TM module-attribute

_DATASET_TM = ContextVar('tdfs4ds_dataset_time_manager', default=None)

_VALID_TIME module-attribute

_VALID_TIME = ContextVar('tdfs4ds_valid_time_column', default=None)

_VARCHAR_CHECKS module-attribute

_VARCHAR_CHECKS = ContextVar('tdfs4ds_varchar_checks', default=None)

ON_FAILURE_POLICIES module-attribute

ON_FAILURE_POLICIES = ('continue', 'stop', 'raise')

ON_FAILURE_DEFAULT module-attribute

ON_FAILURE_DEFAULT = 'continue'

FilterManager

A utility for managing dynamic, versioned filter sets as database-backed views.

The FilterManager enables lightweight scenario management by storing multiple filter definitions in a hidden Teradata table and exposing a public view that dynamically switches between them by filter_id. Each row in the hidden table represents a complete filter configuration. The active configuration is controlled by updating the view definition rather than rewriting table data.

Key Features
  • Store multiple filter states (scenarios) indexed by filter_id
  • Switch filter states instantly by updating a view
  • Optionally include time-based slicing using a BUSINESS_DATE column
  • Clone filters between managers (soft or hard clone modes)
  • Prune obsolete filters to control table size
  • Retrieve current and historical filter definitions
Workflow Overview
  1. Create a FilterManager pointing to a target view name.
  2. Load one or more filter definitions using load_filter().
  3. Switch active filters using update(filter_id).
  4. Inspect the active filter via display() or view DDL.
  5. Optionally prune or clone filters as needed.
How It Works Internally
  • A hidden table named <view_name>_HIDDEN stores filter definitions.
  • A Teradata view named <view_name> exposes only the active filter row.
  • Each filter automatically receives a sequential filter_id (ROW_NUMBER() ordering ensures deterministic assignment).
  • If time-based filtering is used via time_column, a BUSINESS_DATE column is added and projected in all operations.

Parameters:

Name Type Description Default
table_name str

Public view name to manage or create.

required
schema_name str

Teradata schema where artifacts will be created.

required
filter_id_name str

Name of the filter ID column. Defaults to 'filter_id'.

'filter_id'
time_column str

Optional name of a timestamp column from input DataFrames that maps to a BUSINESS_DATE column for time-aware filters.

None

Attributes:

Name Type Description
schema_name str

Target schema for view and hidden table.

table_name str

Name of hidden table storing filters (auto-suffixed with _HIDDEN).

view_name str

Name of public view pointing to current filter.

filter_id_name str

Column containing filter ID.

nb_filters int | None

Number of stored filters (None until initialized).

col_names list[str] | None

Columns projected by the view (data columns only).

time_filtering bool | None

True if time-based filtering enabled.

Notes
  • Database objects are only created when load_filter() is first called.
  • Safe for iterative pipeline runs—auto-detects existing artifacts.
  • Designed for large production tables and Teradata-native workflows.

schema_name instance-attribute

schema_name = schema_name

table_name instance-attribute

table_name = get_hidden_table_name(schema_name=schema_name, view_name=table_name)

view_name instance-attribute

view_name = table_name

filter_id_name instance-attribute

filter_id_name = filter_id_name

nb_filters instance-attribute

nb_filters = None

col_names instance-attribute

col_names = None

time_filtering instance-attribute

time_filtering = None

storage instance-attribute

storage = storage

ofs_map instance-attribute

ofs_map = ofs_map

sql_table property

sql_table

Backing table as a qualified SQL identifier.

sql_view property

sql_view

Public view as a qualified SQL identifier.

__init__

__init__(table_name, schema_name, filter_id_name='filter_id', time_column=None, storage=None, ofs_map='TD_MAP2')

Initialize the FilterManager.

If the hidden table/view already exist, metadata (column names, maximum filter id, and time filtering status) are detected and cached. If they do not exist yet, attributes are initialized but no objects are created until load_filter() is called.

Parameters:

Name Type Description Default
storage

Where to create the hidden backing table when this manager (re)creates it. None (default) = system default (block storage, unchanged DDL); 'OFS' = Object File System on Vantage Cloud Lake (MAP = <ofs_map>, STORAGE = TD_OFSSTORAGE). Per-manager, so block and OFS managers can coexist in one session. Only affects table creation; reading an existing table is unchanged. NOTE: for a tdstone2-Apply view, storage='OFS' is necessary but not sufficient on its own — the ACC also rejects scalar subqueries against this filter (Error 6881); reference it via a JOIN instead. OFS + JOIN scores; OFS + scalar subquery still 6881s (see tdfs4ds.utils.storage).

None
ofs_map

Map paired with STORAGE = TD_OFSSTORAGE when storage='OFS'.

'TD_MAP2'

load_filter

load_filter(df, primary_index=None, time_column=None)

Load a new filter set into the hidden table and (re)point the public view at filter_id=1.

Each row in df is assigned a deterministic filter_id based on ROW_NUMBER() over the ordered set of its columns (plus BUSINESS_DATE when time filtering is enabled). If time_column is provided, values from that column are copied into BUSINESS_DATE and the view will include that time dimension.

Parameters:

Name Type Description Default
df DataFrame

Incoming filter definitions (one row per filter).

required
primary_index list[str]

Primary index columns for the hidden table. Defaults to ['filter_id'] when omitted.

None
time_column str

Name of the time column in df to map into BUSINESS_DATE. If provided, time-based filtering is enabled.

None

Raises:

Type Description
ValueError

If time_column is provided but not present in df.

update

update(filter_id)

Repoint the public view to a different filter id.

Parameters:

Name Type Description Default
filter_id int

Target filter id to apply.

required

Raises:

Type Description
ValueError

If filter artifacts do not exist yet.

display

display()

Retrieve the current view contents as a teradataml.DataFrame.

Returns:

Type Description

teradataml.DataFrame: Rows projected by the public view (current filter).

get_all_filters

get_all_filters()

Retrieve all filter rows from the hidden table.

Returns:

Type Description

teradataml.DataFrame: Full set of stored filters.

get_date_in_the_past

get_date_in_the_past()

Return the earliest business date/time from the current view.

The method reads the first BUSINESS_DATE value from the current view and normalizes it to a %Y-%m-%d %H:%M:%S string. Requires that time filtering is enabled.

Returns:

Name Type Description
str

Earliest datetime as formatted string ('YYYY-MM-DD HH:MM:SS').

Raises:

Type Description
ValueError

If time-based filtering is not enabled.

get_current_filterid

get_current_filterid()

Extract the currently active filter id from the view DDL.

Returns:

Name Type Description
int

Filter id parsed from the view's definition.

Raises:

Type Description
ValueError

If the filter id cannot be parsed from the DDL.

print_view_ddl

print_view_ddl()

Log the view definition (DDL) for troubleshooting/traceability.

prune_filter

prune_filter(filter_id=None)

Remove all filters with ids lower than filter_id and renumber remaining ones.

If filter_id is omitted, the method uses the current filter id from the view. After pruning, filter ids are normalized so the smallest remaining id becomes 1, and the public view is repointed to filter_id=1.

Parameters:

Name Type Description Default
filter_id int

Threshold id; rows with {filter_id_name} < filter_id are deleted.

None

Returns:

Name Type Description
FilterManager

Self, to allow method chaining.

clone_filter

clone_filter(source_filtermanager, filter_id_to_apply=1, take_ownership=False, clone_mode='soft', if_exists='error')

Clone filter definitions from another FilterManager.

Supports: - soft clone (default): just point to source _HIDDEN table - hard clone: copy the source _HIDDEN table and own the copy

Parameters:

Name Type Description Default
source_filtermanager FilterManager

Source FilterManager to clone.

required
filter_id_to_apply int

Filter ID to activate. Default: 1.

1
take_ownership bool

Whether this manager owns the cloned table (soft mode only).

False
clone_mode str

"soft" or "hard". Default: "soft".

'soft'
if_exists str

Behavior if target hidden table already exists - "error" (default): raise an exception - "replace": drop and recreate - "skip": reuse existing table

'error'

Returns:

Type Description

FilterManager

Raises:

Type Description
ValueError

On invalid clone_mode or missing source.

take_ownership

take_ownership()

Take ownership of the currently linked hidden filter table.

This enables this FilterManager instance to manage (and potentially drop) the hidden table via _drop() or future maintenance methods.

Returns:

Name Type Description
FilterManager

self (for chaining)

get_filter_condition

get_filter_condition(output_type: str = 'str')

Retrieve the currently applied filter condition from the database.

This method executes a SQL query that aggregates the filter columns from a filter manager view and returns the result either as a Python dictionary or a raw JSON string.

Parameters:

Name Type Description Default
output_type str

Format of the returned filter condition. - "dict": Returns a Python dictionary (default). - "str": Returns a raw JSON string.

'str'

Returns:

Type Description

dict | str | None: The current filter condition in the requested format. Returns None if no filter is present.

Raises:

Type Description
ValueError

If output_type is not "dict" or "str".

RuntimeError

If the SQL execution fails.

Example

filters = self.get_filter_condition(output_type="dict") print(filters)

_TimeManagerRefused

Bases: ValueError

A detected TimeManager is refused (TIME_MANAGER_CHECK='error'): nothing is registered.

FeatureIngestionError

Bases: RuntimeError

Raised when filter-level ingestion failures are escalated by on_failure.

Carries the machine-readable detail so an orchestrator does not have to parse the message: process_id, n_failed, n_total and failures (a list of {filter_id, error}).

process_id instance-attribute

process_id = process_id

failures instance-attribute

failures = failures or []

n_failed instance-attribute

n_failed = len(failures)

n_total instance-attribute

n_total = n_total

__init__

__init__(message, process_id=None, failures=None, n_total=None)

build_dataset

build_dataset(entity_id, selected_features, view_name, schema_name=None, comment=None, return_query=False, feature_store_time=False, join_type='INNER', grouped=False, document=False, vector_indexing=False, record_lineage=True, as_of=None, time_manager=None, feature_offsets=None, offset_strategy=None)

Generate a SQL query and create a Teradata view to retrieve records for the specified entity IDs based on selected features.

Parameters:

entity_id : list, dict, or str The entity IDs for which records are needed. Can be a list, dictionary, or string. - If list: contains multiple entity IDs. - If dict: keys are the entity IDs. - If str: a single entity ID.

list, str or dict

The feature names alone (['amount', 'nb_tx']) when each feature is computed by one process: its version is found in the catalog. A version is needed only for a feature several processes compute; write it in a dict, with None for the others ({'amount': '<UUID>', 'nb_tx': None}). Such a feature named without a version raises FeatureSelectionError (a ValueError) naming its processes and the dict to write; so does a name not registered for this entity. All features are resolved with one catalog query. In the dict, version is: - None: the feature's only version, - {"alias": <column name>}: the only version under a name of its own, - a process UUID string (the column takes the feature's name), - {"process_id": <UUID>, "alias": <column name>}: one version under a name of its own, or - a list of {"process_id": <UUID>, "process_view_name": <str>, "alias": <str, optional>}: several versions side by side, one column each, named <feature>_<process view> unless an alias is given. An alias is a plain identifier (letters, digits, _) and may not repeat another column; offsets (feature_offsets) are suffixed to it (spend_LAG_1D).

str

The name of the view to be created in the database.

str, optional

The name of the database schema where the view will be created. Defaults to the global tdfs4ds.SCHEMA if not provided.

str, optional

A comment to attach to the created view for documentation purposes. Defaults to None.

bool, optional

If True, the function will return the SQL query string instead of executing it. Defaults to False.

bool, optional

If True, the query will use a specific VALIDTIME based on tdfs4ds.FEATURE_STORE_TIME. If False, the query will use CURRENT VALIDTIME. Defaults to False.

str, datetime, date or pandas.Timestamp, optional

Freeze the dataset at this point in time (VALIDTIME AS OF TIMESTAMP). Any ISO date or timestamp is accepted — '2024-03-31', '2024-03-31 23:59:59', '2024-03-31T23:59:59+02:00' — and normalised to the literal Teradata needs (a bare date becomes midnight; Teradata rejects a date-only TIMESTAMP literal). Without an offset the value is read in the session time zone, like FEATURE_STORE_TIME.

TimeManager or str, optional

Make the dataset follow a TimeManager: every feature is read as of the manager's current BUSINESS_DATE, so time_manager.update(i) moves the dataset without rebuilding it. A 'database.view' string naming the manager's public view is accepted too.

as_of, time_manager and feature_store_time=True are mutually exclusive. With none of them the dataset reads CURRENT VALIDTIME (the default, unchanged). The chosen mode is recorded in the dataset catalog: DATASET_VALIDTIME holds the qualifier and the build table (FS_V_<catalog>_BUILD) holds the mode, timestamp or TimeManager.

str, optional

Specifies the type of join to use between features: 'INNER' (default) or 'FULL OUTER'.

bool, optional

If False (default), uses one sub-query per feature joined together — the classic multi-join approach. Every individual feature sub-query can be targeted by a PI-equality filter pushed from the outer WHERE, making single-entity lookups single-AMP. If True, groups features that share the same storage table and process version into a single sub-query with MAX(CASE WHEN …) pivoting, reducing the number of JOINs from N_features to N_distinct_(table, version) pairs. A HAVING clause enforces non-NULL for every feature in the group when join_type='INNER', preserving the same missing-feature semantics as the classic approach. PI push-down is preserved for INNER JOIN (outer SELECT uses A1.entity); for FULL OUTER the COALESCE in the outer SELECT prevents push-down, same as the classic approach.

bool, optional

If True, generate and persist business-dictionary documentation for the newly built dataset via document_dataset_incremental (LLM-powered). Requires tdfs4ds.INSTRUCT_MODEL_PROVIDER and tdfs4ds.INSTRUCT_MODEL_MODEL to be configured; silently skipped (with an info log) otherwise. Failures are non-fatal — the dataset view is always created/returned regardless. Defaults to False (opt-in). Mirrors upload_features. Leave False when the dataset is built via upload_features/run() — that path already documents it, so enabling it here would double-document.

bool, optional

If True (and document=True and an instruct model is configured), refresh the consumer-agent vector index via build_vector_index(force_rebuild=False) after documentation so the new dataset is searchable immediately. Non-fatal. Defaults to False (opt-in).

bool, optional

Persist the dataset view's lineage subgraph (dataset -> process views -> sources) into FS_LINEAGE_GRAPH via record_process_lineage. No LLM is involved and the write is diff-based (an unchanged graph writes nothing). Non-fatal. Defaults to True since 0.3.1.220: with the former opt-in default no dataset reached the lineage graph unless rebuild_lineage_graph() was run afterwards. Pass False to skip it.

dict, optional

Read features at other instants than the dataset's own (lags and leads), e.g. {'amount': ['0', '-1 day', '-2 days'], 'churn': ['+1 month']}:

  • '-1 day' is the value one day BEFORE the dataset's instant (a lag, for autoregressive inputs), '+1 month' one month AFTER (a lead, e.g. a forecast target), '0' the instant itself.
  • A listed feature gets one column per offset (amount, amount_LAG_1D, amount_LAG_2D, churn_LEAD_1MO); it keeps its plain column only when '0' is listed.
  • The instant is the dataset's: now, as_of, or the TimeManager's business date (time_manager.update() moves every offset column).
  • A lead is NULL while its instant is later than the database's current time: what is valid after now is not known yet. Under CURRENT a lead is therefore always NULL (refused with join_type='INNER').
  • Units: year, month, week, day, hour, minute, second; months are calendar months (ADD_MONTHS). No fraction of a second: valid times are stored to the second.

Without it the SQL is exactly what it was. See the user guide, "Lags and leads".

{'PIVOT', 'PER_OFFSET'}, optional

How the offset columns are read. 'PIVOT' (default) reads each storage table (and process version) once for all its offset columns: one aggregation step, local to the AMPs, partition elimination on the FEATURE_IDs. 'PER_OFFSET' gives each offset column its own sub-query and join; measured on Vantage 20 it parses far slower (32 columns: 31 s against 0.35 s) and is kept for comparison.

Returns:

str or tdml.DataFrame - If return_query is True, returns the generated SQL query as a string. - Otherwise, returns a Teradata DataFrame containing the results.

Raises:

ValueError If an invalid join_type is provided.

is_acc_ineligible_error

is_acc_ineligible_error(exc)

True if exc looks like a Teradata ACC-ineligibility error (6881).

describe_db_error

describe_db_error(exc) -> str

The error message without the driver's stack trace.

Keeps EVERY message line — the half that names the fault is often not the first line — and drops only the Go frames teradatasql appends and the SQLAlchemy "Background on this error" link. Falls back to the raw text when nothing would be left.

quote_ident

quote_ident(name, force=False)

Return name as a Teradata identifier, quoting it only if required.

Idempotent: an already-quoted name is returned unchanged rather than being wrapped a second time. Embedded quotes are escaped as "".

Parameters

name : str The raw object/database name. force : bool, default False Quote even when the name does not need it. Use only at the few sites that have always emitted unconditional quotes and whose exact output is already baked into persisted DDL (see feature_store/feature_query_retrieval.py) — elsewhere forcing would change the SQL of existing stores for no reason.

qualified

qualified(database, object_name, force=False)

Build db.obj with each part quoted only as needed.

qualified('TDB', 'FS_X') == 'TDB.FS_X' (unchanged for ordinary names); qualified('SVC@CORP', 'FS_X') == '"SVC@CORP".FS_X'. An empty/None database yields the bare object name, so unqualified callers keep working.

force=True quotes both parts unconditionally — only for the sites that have always emitted quotes and whose exact text is already persisted (dataset view DDL, returned volatile-table names).

split_qualified

split_qualified(name)

Split db.obj into (database, object), both de-quoted.

Quote-aware, so a dot inside a quoted part does not split the name: split_qualified('"DEINF.CARLOSN"."FS_X"') == ('DEINF.CARLOSN', 'FS_X'). The naive rsplit('.', 1) this replaces returns ('"DEINF.CARLOSN"', '"FS_X"') only by luck and ('"DEINF', 'CARLOSN"."FS_X"') in the split('.') variant.

An unqualified name returns ('', name).

_extract_art_name

_extract_art_name(statement)

Return the volatile ART name declared by an INTO VOLATILE ART(<name>) statement, or None when the statement is not of that shape / can't be parsed.

Used only in UAF ART view mode to DROP a stale volatile ART before recreating it (idempotent same-session re-run). A miss is harmless — the DROP is simply skipped.

_materialise_art

_materialise_art(art_sql)

Execute the UAF ART materialisation statements (art_sql) in list order.

For each statement: DROP the volatile ART it declares first (idempotent — a fresh session has none; a re-run/next-partition has a stale one), then execute the statement. All via tdml.execute_sql on the active session, so the resulting session-scoped volatile ART is visible to the ingestion CTAS that follows.

art_sql order is authoritative and must NOT be sorted/deduped — a later statement may read an ART an earlier one created. A no-op when art_sql is falsy (the classic non-UAF path). Re-raises on statement failure so the caller's followup_close(status='FAILED,...') records it.

_count_prepared_rows

_count_prepared_rows(df_prepared)

Rows staged for ingestion, or None when the count could not be taken.

Used to tell an ingestion that produced nothing from one that produced real values. A process reading an empty upstream view ingests zero rows and used to record a plain COMPLETED — indistinguishable from a real result, and permanently pinned by the skip predicate (STATUS == 'COMPLETED' at this valid time), so the hollow values survived every later run until someone deleted the row by hand.

Fail-open by design: a count is a diagnostic, never a reason to fail an ingestion that already succeeded, so any error yields None = "unknown", which the caller treats exactly as the historical behaviour.

_source_feature_types

_source_feature_types(df, feature_names)

{feature: sql type} of the feature columns of the source, or None (fail-open).

_registered_types

_registered_types(entity_id, feature_names, new_types)

The catalog rows of the features of this result set that are already registered (type_changes.stored_types), or None when the catalog could not be read.

_type_change_warnings

_type_change_warnings(source_types, stored, entity_id, df, process_id, force_varchar_length)

At run time: warn about registered features whose source type no longer fits the stored type (the run writes with the stored type), and return the truncation checks. Never raises.

_value_type_refusal

_value_type_refusal(df, feature_names)

At registration (0.3.5.17): the refusal text when a feature has a type a value cannot have (CLOB, BLOB, JSON, XML), else None. Fail-open: unreadable types = no refusal (the run-time check still refuses CLOB/BLOB/JSON).

_type_change_refusal

_type_change_refusal(df, entity_id, feature_names, force_varchar_length)

At registration: the refusal text when a pre-existing feature's source type is not held by its stored type, else None. Fail-open (a read failure = no refusal).

_varchar_argument

_varchar_argument(force_varchar_length)

(explicit, value) for an upload_features argument: None = not given (the recorded value, else 1024); 0 or 'none' = exact lengths (value None); a number = it.

_recorded_varchar_for_view

_recorded_varchar_for_view(df)

The FORCE_VARCHAR_LENGTH recorded for the process already registered on this view (a re-registration), else 1024. Fail-open to 1024.

_has_recorded_varchar

_has_recorded_varchar(process_id) -> bool

_record_varchar_length

_record_varchar_length(process_id, force_varchar_length)

Record FORCE_VARCHAR_LENGTH for the process. Never raises: a store without the settings table runs with 1024 (the default every older process used); any other value is then a warning.

_view_text

_view_text(view)

SHOW VIEW text of view, or None (best effort, for the CAST snippets).

_check_truncation

_check_truncation(volatile_table, checks)

One aggregate on the staged batch: for each registered VARCHAR feature whose source is longer than its stored length, the longest staged value and the rows above the stored length. Logs a WARNING; never raises (the batch writes as before).

_dataset_time_state

_dataset_time_state(view_name, tm_location)

'missing' / 'same' / 'current' / 'other' for an existing dataset view.

same: already built with this TimeManager. current: built at CURRENT VALIDTIME. other: any other temporal mode, another manager, or a view that cannot be read as a tdfs4ds dataset. missing: no such view. Never raises (an unreadable state is other: the view is left alone).

_build_process_dataset

_build_process_dataset(entity_id, selected_features, view_name, grouped)

The dataset build of upload_features / run.

Without dataset_time_manager this is exactly the historical call. With it, the dataset is built with build_dataset(time_manager=...) so tm.update() moves it; a dataset that already exists in another mode is not rebuilt silently (a warning names rebuild_dataset).

_detect_enabled

_detect_enabled() -> bool

tdfs4ds.TIME_MANAGER_DETECT (default True): find the TimeManager a view reads when upload_features is given none (0.3.6.0).

_node_manager

_node_manager(node, G=None)

A TimeManager rebuilt (read-only) from a lineage node id DB.VIEW.

_detect_time_manager

_detect_time_manager(view_name)

The TimeManager view_name reads, from its own lineage (deep), or None.

Returns (time_manager_or_None, graph). With a domain clock (0.3.6.0): a view on the clock's dates gets the clock (or the one clone it reads); a view on other dates is a warning (TIME_MANAGER_CHECK='error': _TimeManagerRefused). Without one: the single manager the view reads; several are a warning and nothing is chosen. Fail-open: a lineage that cannot be built chooses nothing.

_soft_clone_for_process

_soft_clone_for_process(process_id, view_name, time_manager, soft_clone, detected=True)

The TimeManager a newly registered process should read (0.3.6.0).

soft_clone=None: when time_manager was found by detection (detected) and is the clock of the data domain, the process gets its own soft clone of it and its view is rewritten to read the clone (data_domain_settings.clone_for_process). A manager passed explicitly is kept, as before 0.3.6.0, even the domain clock. True: a clone for any manager (the domain clock or not, passed or found). Anything else, or a failure, keeps time_manager.

_resolve_dataset_tm

_resolve_dataset_tm(process_id, dataset_time_manager, time_manager, wanted)

'database.view' of the TimeManager the dataset must follow, or None.

dataset_time_manager: True / False override; None = the recorded setting (read only when a dataset is built, wanted). The manager is the time_manager= argument, else the one recorded for the process. Without one: a single warning and the historical build.

_valid_time_column_problem

_valid_time_column_problem(df, column, entity_id, feature_names, is_uaf_art=False)

Why column cannot be the valid time of this process, or None.

A DATE / TIMESTAMP column of the source, neither an entity column nor a feature, and the settings table must exist (or be creatable) to record it.

_compute_features_batch

_compute_features_batch(df, entity_id, feature_names, selected_features, primary_index, partitioning, entity_null_substitute, process_id, filtermanager, dataset_view_name, dataset_already_created, grouped=False, art_sql=None, valid_start=None, close_absent=False, track_refresh=False)

Execute one feature ingestion batch: followup_open → [materialise ART] → prepare → store → followup_close (COMPLETED) → optional dataset build.

Returns (features_infos, dataset_or_None) on success. On failure: logs the error, attempts to record FAILED in the followup table, then re-raises. Callers that want to continue after a failure (e.g. the filtermanager loop) should wrap this call in their own try/except and use continue rather than re-raising.

Does NOT call apply_collect_stats — the caller is responsible for that.

grouped is forwarded to build_dataset — see upload_features for details.

art_sql (UAF ART view mode only): a list of INTO VOLATILE ART statements materialised before ingestion, in this same session — so the session-scoped volatile ART is visible to the ingestion CTAS. Runs after filtermanager.update() (done by the caller), so the series-input view's scalar subquery already points at the current partition. None/empty for the classic path (a no-op).

valid_start: the run's pinned valid start for a real-time run (no FEATURE_STORE_TIME), so every feature of the run shares one start. None keeps the per-statement CURRENT VALIDTIME (see run).

close_absent (process option close_absent_entities, 0.3.3.22): after the values are stored, end the validity of the entities of this process (and of the active FilterManager segment) that this batch no longer produces, at the same valid time. Skipped when the batch staged 0 rows; a failure records the batch FAILED.

track_refresh (process option track_entity_refresh, 0.3.3.30): after the values (and the close of absent entities) are stored, record in the process's admin FS_R_* table that this batch confirmed each of its entities. Skipped when the batch staged 0 / an unknown number of rows. Fail-open: a failed write is a warning, the batch stays COMPLETED.

_compute_features_batch_tagged

_compute_features_batch_tagged(df, entity_id, feature_names, selected_features, primary_index, partitioning, entity_null_substitute, process_id, filtermanager, dataset_view_name, dataset_already_created, grouped=False, art_sql=None, valid_start=None, close_absent=False, track_refresh=False)

Body of :func:_compute_features_batch, run inside the execution's query band.

_resolve_on_failure

_resolve_on_failure(on_failure=None, raise_on_failure=None)

Resolve the effective failure policy from the two spellings.

on_failure is the real setting; raise_on_failure is the shorthand a caller who only wants "make it fail loudly" would reach for. When both are given the explicit on_failure wins and the disagreement is logged rather than silently resolved — a caller who wrote both had a reason to expect each.

Returns one of ON_FAILURE_POLICIES.

_storage_table_types

_storage_table_types(df, feature_names, new_types, force_varchar_length=None, stored=None)

{feature: {'type': ...}} for every feature of the batch, the new ones from new_types.

Gettdtypes returns only the features not registered yet; the storage tables of the registered ones must exist too. With stored ({FEATURE upper: {"type": ...}}, the catalog rows, 0.3.5.1) the registered features take their CATALOG type: re-deriving it from the source with the current rounding created empty tables nothing writes to (seen live). Fail-open: when the source types cannot be read, new_types alone (the historical behaviour).

_upload_features

_upload_features(df, entity_id, feature_names, feature_versions=_FEATURE_VERSION_DEFAULT, primary_index=None, partitioning='', filtermanager=None, entity_null_substitute={}, process_id=None, force_compute=False, force_varchar_length=None, dataset_view_name=None, grouped=False, art_sql=None, on_failure=None, raise_on_failure=None, valid_start=None, close_absent=False, track_refresh=False)

Uploads a set of features into the Feature Store for a given entity.

This function registers an entity and its associated features in the feature catalog if they are not already defined, prepares the data for ingestion, and stores it in the feature store. It also supports incremental feature computation and conditional execution depending on prior runs.

Parameters

df : pandas.DataFrame Input dataframe containing entity keys and feature columns to upload. entity_id : str, list, or dict Identifier(s) for the entity. List/str inputs have their SQL types inferred from df with exact length + character set preserved (e.g. CHAR(14) keys are not truncated); a dict is used verbatim. feature_names : list of str List of feature column names to upload from df. feature_versions : dict or str, optional Feature version(s). Default is _FEATURE_VERSION_DEFAULT ('dev.0.0'). primary_index : str or list, optional Primary index for Teradata feature tables. partitioning : str, optional Partitioning clause. Default is ''. filtermanager : FilterManager, optional If provided, features are built iteratively per filter step. entity_null_substitute : dict, optional Replacement values for nulls in entity keys (applied via COALESCE). A NULL in an entity key column not listed here raises a ValueError during ingestion (NULL keys cause a cartesian-product MERGE). process_id : str, optional Process execution identifier for follow-up logging. force_compute : bool, optional If True, forces recomputation even if already completed. Default is False. force_varchar_length : int, optional If provided, all VARCHAR feature columns are resized to this length. dataset_view_name : str, optional Name of the output dataset view to create after ingestion. grouped : bool, optional Forwarded to build_dataset whenever a dataset view is built. See upload_features for details. Default: False (classic multi-join). art_sql : list of str, optional UAF ART view mode. Forwarded to every _compute_features_batch call so the volatile ART(s) are materialised per partition before ingestion. None for the classic path. See upload_features / _materialise_art. close_absent : bool, optional Process option close_absent_entities: every batch (each FilterManager segment) ends the validity of the stored entities it no longer produces. track_refresh : bool, optional Process option track_entity_refresh: every batch records, in the process's admin FS_R_* table, that it confirmed each of its entities (see entity_refresh).

Returns

pandas.DataFrame or None If BUILD_DATASET_AT_UPLOAD is enabled, returns the built dataset. Otherwise None.

_read_db_now

_read_db_now()

The database's current timestamp, as a FEATURE_STORE_TIME-style string.

Read from the database (not the client) so it agrees with CURRENT VALIDTIME. None when it cannot be read: the caller then keeps the historical per-statement CURRENT VALIDTIME.

_recorded_time_manager

_recorded_time_manager(process_id)

(database, view) of the TimeManager recorded for process_id, or None.

Recorded in FS_TIME_MANAGER by roll_out / run(..., time_manager=) and exposed as TIME_DATABASE_NAME / TIME_VIEW_NAME by the process catalog view. Never raises.

_resolve_run_valid_time

_resolve_run_valid_time(process_id, feature_store_time, time_manager=None)

Decide the valid time of one run(). Returns (source, value, detail).

Precedence:

  1. 'explicit' — tdfs4ds.FEATURE_STORE_TIME is set (a roll_out step or the caller's choice): used as is, nothing else consulted.
  2. 'argument' — run(..., time_manager=tm): the manager's current business date. A manager that cannot give a date is an error (it was asked for explicitly).
  3. 'recorded' — the TimeManager recorded for the process: its current business date. A broken association is a warning, never a failure.
  4. 'realtime' — none of the above: the database time, read once, so that every feature of the run shares one valid start (value may be None if the clock cannot be read: the historical per-statement behaviour).

_managers_read_by_processes

_managers_read_by_processes(proc_df, graph)

({pid: [manager node, ...]}, index): the TimeManagers each registered process reads, from the lineage (deep); the recorded one (catalog TIME_*) when the lineage does not know the process. Pure over its inputs.

_run_many

_run_many(process_id=None, *, at=None, data_domain=None, order='dependencies', time_manager=None, return_dataset=False, on_failure=None, raise_on_failure=None, dataset_view_name=None, **run_kwargs)

Body of run([...]) / run(data_domain=...) / run(..., at=) (0.3.6.0).

Every process is computed at ONE time: at (a date or timestamp), else 'now' (the database clock, read once), or the current date of time_manager. Each TimeManager view the processes read (their soft clones, or a shared manager) is set to that date for the computation and put back on its cursor afterwards (literal_time_managers): no cursor moves. A process reading no TimeManager is computed on the current source data and stored at the same time, with a warning. Processes run one after the other in dependency order; a failed process's downstream processes are skipped.

run

run(process_id=None, return_dataset=False, force_compute=False, force_varchar_length=None, dataset_view_name=None, grouped=False, on_failure=None, raise_on_failure=None, check_upstream=False, strict_upstream=False, time_manager=None, close_absent_entities=None, _time_manager_checked=False, track_entity_refresh=None, dataset_time_manager=None, *, at=None, data_domain=None, order='dependencies')

Execute a specific process from the feature store identified by the process ID. Uses global logger for diagnostics (gated by tdfs4ds.DISPLAY_LOGS).

Several processes at one time (0.3.6.0): process_id may be a list, or pass data_domain='X' (True = tdfs4ds.DATA_DOMAIN) for every process of a data domain (primary store only). They run one after the other in dependency order (from the lineage graph; order='given' keeps yours), all at ONE time: at='2024-03-31', else the database clock read once (at='now', the default for a list), or the current date of time_manager=. Each TimeManager view the processes read (their soft clones) is set to that date for the computation and put back on its cursor afterwards: no cursor moves. A process reading no TimeManager is stored at the same time, with a warning. A failed process's downstream processes are skipped; on_failure applies per process ('raise' raises FeatureIngestionError after the list, 'stop' stops at the first failure). Returns {process_id: 'COMPLETED' | 'FAILED: ...' | 'SKIPPED: ...'}. run('pid', at=...) computes one process at that date and returns what run('pid') returns.

grouped is forwarded to build_dataset whenever a dataset view is (re)built. See upload_features for details. Default: False (classic multi-join, unchanged behaviour). Note: not persisted in the process catalog — re-running an existing process_id without passing grouped=True again reverts to the classic join.

Valid time of the ingested values, decided once per run:

  1. tdfs4ds.FEATURE_STORE_TIME, when set — what roll_out does at each step.
  2. time_manager= — the manager's current business date (the pairing is recorded, as roll_out records it).
  3. the TimeManager recorded for the process (by roll_out or a previous time_manager=), at its current business date.
  4. otherwise real time: the database time, read once, shared by every feature and partition of the run.

For 2 and 3, FEATURE_STORE_TIME is set for the duration of the run (the follow-up row records that date) and restored afterwards. Running without a FEATURE_STORE_TIME or a TimeManager is a fallback, not a best practice.

A time_manager= the process view does not read (checked on the lineage graph, deep) is governed by tdfs4ds.TIME_MANAGER_CHECK: 'warn' (default) runs as before but records no pairing; 'error' raises ValueError before computing anything; 'off' skips the check. A real-time run of a process whose view reads a TimeManager that is not declared logs a warning naming link_time_managers.

close_absent_entities: None (default) applies the option recorded for the process (upload_features(..., close_absent_entities=True) or set_process_options); True / False override it for this call only. When on, the entities the process no longer produces have their validity ended from the run's valid time on (the MERGE's "from t onward" rule).

track_entity_refresh: None (default) applies the option recorded for the process (upload_features(..., track_entity_refresh=True) or set_process_options); True / False override it for this call only. When on, the run records in an admin table (FS_R_*, read by tdfs4ds.entity_refresh) that it confirmed each entity of a batch, whether or not the value changed. A failed write is a warning; the run stays COMPLETED.

dataset_time_manager: None (default) applies the setting recorded for the process (upload_features(..., dataset_time_manager=True) or set_process_options); True / False override it for this call only. When on, the dataset view built by this run (dataset_view_name) follows the process's TimeManager (the time_manager= argument, else the recorded one): it is built with build_dataset(time_manager=...), so tm.update() moves it. A dataset that already exists in another mode is left as it is, with a warning naming rebuild_dataset.

Other parameters:

  • process_id: a PROCESS_ID, or a list of them (0.3.6.0).
  • return_dataset: return the dataset view built by the run (with dataset_view_name or tdfs4ds.BUILD_DATASET_AT_UPLOAD) instead of None.
  • force_compute: recompute even when the follow-up table records the run as COMPLETED at this valid time (default False: such a run is skipped).
  • force_varchar_length: VARCHAR rounding of new text features; None = the value recorded for the process (see upload_features).
  • dataset_view_name, grouped: a dataset to (re)build after the run, and its strategy.
  • on_failure ('continue' | 'stop' | 'raise') / raise_on_failure (True = 'raise'): what a failed FilterManager segment does; 'raise' attempts every segment, then raises FeatureIngestionError.
  • check_upstream / strict_upstream: refuse the run when an upstream process (lineage graph) FAILED at this valid time / is also RUNNING.
  • time_manager: compute at this manager's current date (see above); a process reading a soft clone of it gets the clone set to that date for the run (0.3.6.0).
  • at, data_domain, order (keyword, 0.3.6.0): see "Several processes at one time".

_run

_run(process_id, return_dataset=False, force_compute=False, force_varchar_length=None, dataset_view_name=None, grouped=False, on_failure=None, raise_on_failure=None, check_upstream=False, strict_upstream=False, valid_start=None, close_absent_entities=None, track_entity_refresh=None)

Body of :func:run, once the valid time is decided (valid_start: real-time pin).

_split_schema_object

_split_schema_object(name)

Split schema.object into (schema, object) (both de-quoted, stripped).

Returns ("", object) when no schema qualifier is present — the caller enforces the mandatory-schema rule on the empty schema.

_resolve_feature_source

_resolve_feature_source(df, sql_query=None, target_view_name=None)

Normalise an upload_features source to a teradataml DataFrame.

Accepts three input shapes and returns (df, view_name):

  • a teradataml DataFrame → returned unchanged (back-compat);
  • a fully-qualified schema.view → resolved to a DataFrame over that view;
  • sql_query + target_view_name → the view is CREATED from the SQL, then resolved to a DataFrame (the created view is permanent and becomes the process view re-run by run(process_id)).

On any recoverable problem (missing schema, view already exists, SQL/​view fails to compile or is not executable) it logs a clear, prescriptive message via logger_safe('error', …) and returns (None, None) so the caller aborts without raising a traceback (the users are non-developers).

_resolve_ai_flag

_resolve_ai_flag(value, setting)

Effective value of one AI step of upload_features.

An explicit argument (True/False) always wins. None reads the configured default tdfs4ds.<setting> (TDFS4DS_<setting> in a .env), unless the master switch tdfs4ds.AGENTIC_FEATURES is off, which makes every defaulted step False. The one rule for all five steps.

upload_features

upload_features(df, entity_id, feature_names, metadata={}, primary_index=None, partitioning='', filtermanager=None, entity_null_substitute={}, force_compute=True, force_varchar_length=None, dataset_view_name=None, optimize_query=None, update_view=True, document=None, max_candidates=None, cascade_redocumentation=None, vector_indexing=None, sql_query=None, target_view_name=None, art_sql=None, art_layers=None, grouped=False, return_process_id=False, run_now=True, on_failure=None, raise_on_failure=None, check_upstream=False, strict_upstream=False, explain=None, time_manager=None, close_absent_entities=False, storage_tag=None, track_entity_refresh=False, dataset_time_manager=False, valid_time_column=None, soft_clone=None)

Upload feature data to the feature store for a specified entity. All diagnostics go through logger_safe() which respects tdfs4ds.DISPLAY_LOGS.

The feature source can be supplied in three ways:

  1. A teradataml DataFrame (df=...) — the classic path.
  2. A fully-qualified view name (df='SCHEMA.view') — for SQL users who already have a view. The schema is mandatory; a bare view name (no schema) is rejected. The view must already exist and be executable.
  3. A SQL query (sql_query='SELECT ...') together with a mandatory target_view_name='SCHEMA.view'. The query is validated with EXPLAIN, a view is created at target_view_name (the schema is mandatory; the view must NOT already exist), and that view — which is permanent and becomes the process view re-executed by run(process_id) — is used as the feature source. When sql_query is given it takes precedence over df.

Recoverable input problems (missing schema, target view already exists, SQL or view fails to compile / is not executable) do not raise a traceback: a clear message with a fix is logged via logger_safe('error', …) and the function returns None. Check the log when a call returns None.

Parameters

df : teradataml DataFrame or str The feature source: a DataFrame over a permanent view, or 'SCHEMA.view'. Pass None with sql_query. feature_names : list of str The columns of the source to register as features. metadata : dict, optional Free-form description stored with the process (METADATA JSON). Default: {}. primary_index : list of str, optional Primary index of the storage tables. Default: the entity columns. partitioning : str, optional Partitioning clause of the storage tables. Default: none. filtermanager : FilterManager, optional Segments the process runs one at a time (see the fs-filter skill). force_compute : bool, optional Recompute even when the follow-up table records the run as COMPLETED at this valid time. Default: True. dataset_view_name : str, optional 'SCHEMA.view' of a dataset built from the features after the run. on_failure : {'continue', 'stop', 'raise'}, optional What a failed FilterManager segment does: 'continue' (default) records it and goes on, 'stop' stops at the first one, 'raise' attempts every segment then raises FeatureIngestionError. raise_on_failure : bool, optional Shorthand: True = on_failure='raise'. An explicit on_failure wins. check_upstream : bool, optional Refuse the run when an upstream process (from the lineage graph) FAILED at this valid time. Default: False. strict_upstream : bool, optional With check_upstream, also refuse when an upstream is RUNNING. sql_query : str, optional A SQL SELECT defining the feature source. Requires target_view_name. The view is created from this query (after an EXPLAIN check) and kept. target_view_name : str, optional 'SCHEMA.view' — where to create the view for sql_query (mandatory when sql_query is given; schema required; must not already exist). art_sql : list of str, optional Opt-in UAF ART view mode. A list of solitary SQL statements that materialise a Teradata UAF operator's Analytical Result Table (ART) using EXECUTE FUNCTION ... INTO VOLATILE ART(<name>). When provided, the process is registered with PROCESS_TYPE='uaf art view' and, on every run(), these statements are executed in list order, per FilterManager partition, immediately before the ingestion CTAS (same session, so the session-scoped volatile ART is visible to the CTAS). This unlocks features whose value lives in a secondary ART layer (e.g. ARIMA fit-metrics R_SQUARE/MAPE/AIC in ARTFITMETADATA, residual tests over ARTFITRESIDUALS, TD_PACF) — which a single ingestion statement cannot reach. df/sql_query+target_view_name still define the plain feature view (the one reading the layer via TD_EXTRACT_RESULTS(ART_SPEC(..., LAYER(...)))); art_sql is stored in the process METADATA and never turned into a view (a view cannot contain INTO VOLATILE ART). Order matters — a later statement may read an ART an earlier one created. For this mode optimize_query is force-disabled and the view EXPLAIN in documentation is skipped (the ART does not exist at optimize/document time). Requires art_layers. Default: None (classic 'denormalized view' path, unchanged). art_layers : list of str, optional Required when art_sql is given: the declared LAYER(...) name(s) the feature view reads (e.g. ['ARTFITMETADATA']). Used for documentation and lineage only — it is not validated against the view DDL (the view is authoritative for what is computed). Default: None. entity_id : str or list (recommended), or dict (advanced override) Entity / primary-index key(s). Pass a string for a single-column key or a list for a composite key, e.g. 'CUSTOMER_ID' or ['CUSTOMER_ID', 'EVENT_DATE'] — this is the recommended form. You do not need to specify SQL data types: they are inferred from the source DataFrame with their exact length and character set preserved (a CHAR(14) key stays CHAR(14) in the created feature table, not truncated to CHAR(1)). Only pass a dict (e.g. {'CUSTOMER_ID': 'BIGINT', 'EVENT_DATE': 'DATE'}) in the rare case where you need to override an inferred type; the supplied type strings are then used verbatim. entity_null_substitute : dict, optional Per-column replacement values for NULLs in entity keys (e.g. {'CLI_CD': '-'}), applied via COALESCE. NULL values in an entity key column that is NOT covered here will raise a ValueError during ingestion: a NULL key produces a cartesian-product MERGE (severe skew / storage blow-up). Filter the NULL rows upstream or provide a substitute. Default: {}. optimize_query : bool, optional If True and an instruct model is configured, run the query optimizer on the registered process after ingestion. The full report is saved to a file named tdfs4ds_optim_{timestamp}_{view}_{process_id}.md in the current working directory. Only the score summary is emitted to the log. Default: None = tdfs4ds.UPLOAD_OPTIMIZE_QUERY (False unless configured).

The AI steps (``optimize_query``, ``document``, ``explain``,
``cascade_redocumentation``, ``vector_indexing``) all default to None,
which reads ``tdfs4ds.UPLOAD_<NAME>`` (``TDFS4DS_UPLOAD_<NAME>`` in a .env).
``tdfs4ds.AGENTIC_FEATURES = False`` (``TDFS4DS_AGENTIC_FEATURES=false``)
turns all of them off at once. An explicit argument always wins.

update_view : bool, optional If True and query optimization finds an improvement, replace the process view DDL with the optimized SQL. Default: True. document : bool, optional If True and an instruct model is configured, run incremental documentation on the registered process (and after any view update). If dataset_view_name is also provided, document_dataset_incremental is called after run() so that the dataset-level documentation can propagate the already-generated feature descriptions bottom-up. Default: None = tdfs4ds.UPLOAD_DOCUMENT (True unless configured). explain : bool, optional Part of document: also run the LLM analysis of the view's EXPLAIN plan (scores, warnings, recommendations). False documents the process without it and keeps any stored analysis. Ignored when document is False. Default: None = tdfs4ds.UPLOAD_EXPLAIN (True unless configured). max_candidates : int, optional Maximum number of SQL rewrite candidates to generate during query optimization. Overrides tdfs4ds.QUERY_OPTIMIZER_MAX_CANDIDATES for this call only. Default: None (uses the global value). cascade_redocumentation : bool, optional If True (and document=True with an instruct model configured), re-document every downstream process/dataset that depends on this process — but only when this process's documentation actually changed. The descendant set is read from the persisted lineage graph (FS_LINEAGE_GRAPH). This propagates a changed parent meaning down to everything that consumes it, at the cost of one extra LLM pass per affected descendant; hence it is opt-in. Default: None = tdfs4ds.UPLOAD_CASCADE_REDOCUMENTATION (False unless configured). vector_indexing : bool, optional If True (and document=True with an instruct model configured), rebuild the vector index after documentation is written so the consumer agent's search results reflect the new/updated business descriptions immediately. Uses an additive upsert (force_rebuild=False) — fast but stale entries from deleted/renamed objects persist until a full rebuild_vector_indexing() is run. Non-fatal: a failure logs a warning without aborting the ingestion. Default: None = tdfs4ds.UPLOAD_VECTOR_INDEXING (False unless configured). grouped : bool, optional Forwarded to build_dataset whenever a dataset view is built (i.e. when dataset_view_name is set or tdfs4ds.BUILD_DATASET_AT_UPLOAD is True). If False (default), uses one sub-query per feature joined together — the classic multi-join approach; every feature sub-query can be targeted by a PI-equality filter, keeping single-entity lookups single-AMP. If True, groups features sharing the same storage table and process version into one sub-query with MAX(CASE WHEN …) pivoting, reducing JOIN count from N_features to N_distinct_(table, version) pairs — recommended for wide datasets with many features from the same source table. See build_dataset for the full explanation. Default: False (unchanged behaviour). Not persisted in the process catalog — a later run(process_id) without grouped=True reverts to the classic join for any dataset rebuild. return_process_id : bool, optional If True, return the PROCESS_ID (a UUID string) of the process registered by this call instead of the dataset — so the caller can hold on to it for a later run(process_id) / roll_out([process_id], ...) without having to look it up in the process catalog. Mirrors run(return_dataset=...): the flag toggles what is returned, it does not wrap it in a tuple. Note the default return (dataset) is already None unless tdfs4ds.BUILD_DATASET_AT_UPLOAD is True, so in the common case nothing is given up by setting this. The recoverable input-error paths still return None regardless (check the log). Default: False (unchanged behaviour — the dataset is returned). run_now : bool, optional If False, register the process without executing it — the process catalog row, the data-distribution row and any filtermanager row are written and the view is created, but run() is not called, so no feature values are computed. Use it for a lazy "declare now, compute later" flow: the returned PROCESS_ID (pair with return_process_id=True) can be executed at any later point via run(process_id) or roll_out([process_id], time_manager), which drives every vintage including the first. A dataset_view_name given with it is recorded as a process setting and built by each later run() that passes none (so by roll_out, at each date; 0.3.5.14). Caveat: register_entity / register_features and the FS_T_* table creation happen inside run(), so until the first run the feature catalog has no entry for these features and their storage tables do not exist — get_feature_versions and friends return nothing for them. That is the intended lazy state, not an error. Dataset documentation is also skipped (the dataset view does not exist yet).

**Validation.** Because the run is what normally proves the source executes,
``run_now=False`` first validates it with an ``EXPLAIN`` — **before** any catalog
row is written, so an invalid source never leaves a registered process behind. On
failure nothing is registered: a prescriptive message is logged and ``None`` is
returned (no traceback), like the other recoverable paths. For a **UAF ART view**
only the **first** ``art_sql`` statement is EXPLAINed and the ART is **not**
materialised — later statements may read an ART an earlier one creates, so without
materialisation they would fail for a reason unrelated to their own validity; the
feature view is skipped for the same reason (it reads the ART → Error 3807).

**What EXPLAIN does and does not prove.** It proves the statement compiles and its
objects are reachable. It does **not** prove the process will ingest: ``run()`` also
performs type resolution (``Gettdtypes`` / ``validate_feature_types``) and rejects
NULL entity keys not covered by ``entity_null_substitute``, and the real ingestion
statement is an unpivot CTAS rather than ``SELECT *``. So a lazily-declared process
can EXPLAIN clean and still fail on its first run. Default: True (unchanged
behaviour — register **and** run).

storage_tag : str, optional Store this process's features in a table of their own (the table of their entity and type with __<TAG> appended, same primary index and partitioning), recorded in FS_FEATURE_PLACEMENT before the first run. Two processes of one entity under different tags write different tables, so a parallel run does not serialise them. A feature already registered in another table, or shared with another process, is refused: relocate_features moves features with their history. Default None: nothing changes. track_entity_refresh : bool, optional Process option (0.3.3.30), recorded in FS_PROCESS_SETTINGS and applied by every later run() / roll_out() of the process. The ingestion MERGE writes nothing when a value is unchanged, so a feature row only tells when a value last changed. When True, each batch also records, in an admin table of its own (FS_R_*, never a feature, exposed by no catalog or view), that the process confirmed each entity it produced, with a valid-time history. Read it with tdfs4ds.entity_refresh(process_id) and tdfs4ds.entity_refresh_summary(process_id) (entities by last refresh, and those the latest run did not confirm). Cost: one SELECT DISTINCT over the staged batch and one MERGE per batch. A failed write is a warning; the ingestion stays COMPLETED. A batch that staged 0 rows records nothing. Default False: the ingestion statements are unchanged. dataset_time_manager : bool, optional Setting (Part D), recorded in FS_PROCESS_SETTINGS and applied by every later run() / roll_out(). When True and the process has a TimeManager (time_manager= here, else the recorded one), the dataset of dataset_view_name is built with build_dataset(time_manager=...) (grouped or not): it shows the business date of the manager, so tm.update(i) moves it without a re-run. Without a TimeManager: a warning and the usual current dataset. A dataset that already exists at CURRENT VALIDTIME (or in another mode) is not rebuilt silently: a warning names tdfs4ds.rebuild_dataset(<name>, time_manager=..., replace=True). Default False: unchanged. force_varchar_length : int, optional Process setting (0.3.5.1), recorded in FS_PROCESS_SETTINGS and applied by every later run() / roll_out(). The VARCHAR features being registered take one type per character set: the stored type of a registered text feature of the process that holds them, else VARCHAR(ceil(longest / N) * N) over the new features. None (default): the value recorded for this view's process, else 1024 (a recorded value is never reset by the default). 0 or 'none': exact lengths. A registered feature keeps its stored type; a source type it does not hold refuses the registration with the alternatives (cast, or tdfs4ds.plan_type_change). valid_time_column : str, optional Process setting (0.3.5.0), recorded in FS_PROCESS_SETTINGS and applied by every later run() / roll_out(). A DATE or TIMESTAMP column of the source (neither an entity column nor a feature) giving each row its own valid time: the row's values are valid from it until the entity's next row (or 9999-01-01), and one run writes a whole history. The source may then hold several rows per entity, one per valid time. Equal consecutive values are merged; each entity's stored history is replaced from its earliest valid time in the load onward and kept before it, so a re-run is a no-op and an incremental load rewrites only from its own dates. FEATURE_STORE_TIME and the TimeManager date no longer set the values' valid time (a TimeManager can still bound the rows the view returns). With close_absent_entities, an entity absent from a load has no value from the load's earliest valid time on; with track_entity_refresh, the load's latest valid time is recorded. Not for a UAF ART view. A tdfs4ds older than 0.3.5.0 running the process ignores the setting. Default None: unchanged. time_manager : TimeManager, optional The TimeManager the process view reads. The pairing is recorded at registration (FS_TIME_MANAGER, as roll_out records it), so run(process_id) later needs no argument and computes at the manager's business date; with run_now=True the first run already does. The view is checked first: a manager it does not read is a warning under tdfs4ds.TIME_MANAGER_CHECK='warn' (default; the pairing is not recorded) and refused under 'error' (nothing registered, None returned). An explicit manager is paired as before 0.3.6.0, even when it is the clock of the data domain (no soft clone). None (default, 0.3.6.0): the view's lineage is walked and the manager it reads is recorded: the clock of the data domain (set_domain_time_manager), which then gets its own soft clone (see soft_clone), or the one manager it reads (several: a warning, nothing recorded). tdfs4ds.TIME_MANAGER_DETECT = False restores the pre-0.3.6.0 behaviour (nothing recorded until a roll_out). soft_clone : bool, optional (0.3.6.0) None (default): a process whose view reads the clock of its data domain, found by detection, gets its own soft clone <view>_TM (same dates, own cursor) and its view is rewritten to read it. True: a soft clone of any manager, passed or found. False: never. close_absent_entities : bool, optional Process option (0.3.3.22), recorded in FS_PROCESS_OPTIONS and applied by every later run() / roll_out() of the process. When True, each run ends the validity of the stored entities the process no longer produces, from the run's valid time on (the TimeManager date under roll_out) — the same "from t onward" rule as the MERGE for the entities still produced. A re-run at the same date is a no-op, and an entity that comes back gets a new period (the absence stays a gap). Replay a history in date order, from its first date. A batch that staged 0 rows closes nothing; a failed close records the batch FAILED. With a filtermanager, every filter column must be an entity column (a segment closes only its own entities), else nothing is registered and None is returned. False (default): registration unchanged, and an option recorded by an earlier registration of the same view is switched off. tdfs4ds.set_process_options changes it without re-registering.

Returns

teradataml DataFrame or str or None By default the dataset view (None unless tdfs4ds.BUILD_DATASET_AT_UPLOAD is True); the PROCESS_ID string when return_process_id=True; None on a recoverable input error, with a prescriptive message logged.

upload_tdstone2_scores

upload_tdstone2_scores(model)

Upload features from a tdstone2 model's predictions to the feature store.

Handles the full workflow: extract feature names/types, register in the feature catalog, prepare for ingestion, store in the feature store, and build a dataset view.

Parameters: - model: The tdstone2 model object whose predictions contain features to upload.

Precondition — the model must expose one of two output accessors. This function dispatches on whether the model has a score member: if it does, it reads model.get_model_predictions(); if it does not, it reads model.get_computed_features(). A model class exposing neither is not supported by this bridge and will fail with an AttributeError. The entity is likewise taken purely from the model's mapper (tdstone2_entity_id reads mapper_scoring.id_row / mapper.id_partition / mapper.id_row) — tdfs4ds injects no origin/as-of column, so a contract keyed on an origin date only gets one if the model's own mapper already carries it. For a model that does not fit this shape, register a permanent view over its output table with upload_features instead — that path has no such requirement.

Returns: - DataFrame: A DataFrame representing the dataset view created in the feature store.

_attached_time_manager

_attached_time_manager(process_list)

The TimeManager that drives process_list when roll_out is given none (0.3.5.15).

Read from the managers attached to the processes (process catalog TIME_*). They must share one table of dates: one manager, or a manager and its soft clones (whose cursors roll_out then moves with it). Raises ValueError naming what does not fit.

_guard_history_start

_guard_history_start(process_list, time_manager, time_id_start, force_compute, rebuild_history)

Refuse a roll-out whose first date is before the stored values of a process (0.3.5.16), or, with rebuild_history, delete those values first. Returns the force_compute to use.

roll_out

roll_out(process_list=None, time_manager=None, time_id_start=1, time_id_end=None, force_compute=False, force_display_logs=False, on_failure=None, raise_on_failure=None, check_upstream=False, strict_upstream=False, close_absent_entities=None, track_entity_refresh=None, dataset_time_manager=None, rebuild_history=False, *, data_domain=None, order='dependencies')

Execute a series of processes for each date in a time manager, managing time, computation settings, and logging.

Iterates over a range of time steps, updating the TimeManager with each step, and executes all processes in process_list for that time step.

Parameters: - process_list (list): List of process IDs to execute for each time step. - time_manager (TimeManager, optional): the manager whose dates are rolled out. None (0.3.5.15) = the TimeManager attached to the processes; they must share one table of dates (one manager, or a manager and its soft clones), else ValueError. - time_id_start (int, optional): Starting time step ID. Default is 1. - time_id_end (int, optional): Ending time step ID. If None, runs until last step. - force_compute (bool, optional): Force recomputation even if results exist. Default False. - force_display_logs (bool, optional): Force log display during rollout. Default False.

Each process is first checked against the lineage graph, before any step runs:

  • its view reads the manager: fine;
  • its view reads a soft clone of the manager (same table of dates, own cursor): at each step the clone's cursor is moved to the same step before the processes run, so the values stay consistent (0.3.5.15); its own pairing is kept;
  • its view reads another manager (other dates): ValueError, also under TIME_MANAGER_CHECK='warn' (0.3.5.15; it used to warn and write values stamped with this manager's dates but computed at the other one's cursor);
  • its view reads no manager: a warning under 'warn' (default; the pairing is not recorded), a ValueError under 'error'. 'off' skips the check (and the alignment).

  • close_absent_entities (bool, optional): None (default) applies each process's recorded option; True / False override it for this roll-out. With it on, each date ends the validity of the entities a process no longer produces at that date; a later date where they come back opens a new period. Replay a history in date order (from its first date).

  • track_entity_refresh (bool, optional): None (default) applies each process's recorded option; True / False override it for this roll-out. With it on, each date records which entities each process confirmed (tdfs4ds.entity_refresh).
  • rebuild_history (bool, optional): before step 1, roll_out reads where each process's stored values start (0.3.5.16). A run writes from its date onward but never before the first value already stored, so when they start after the first date rolled out (a first run in real time, or at a later date), the roll-out would add nothing: it is refused with ValueError and nothing runs. True deletes the stored values of those processes from the first date rolled out onward (logged in FS_REMOVAL_LOG) and replays every date with force_compute=True; with nothing to delete it only forces the recomputation. A process whose valid time comes from a source column is not checked; a start that cannot be read is a warning and the roll-out goes on.
  • on_failure / raise_on_failure: what a failed FilterManager segment does in each run ('continue' default, 'stop', 'raise' = attempt every segment then raise FeatureIngestionError; raise_on_failure=True is the shorthand). A raised failure stops the roll-out at that date.
  • check_upstream / strict_upstream: refuse a process when an upstream process (lineage graph) FAILED at that date / is also RUNNING.
  • dataset_time_manager (bool, optional): None (default) applies each process's recorded setting; True / False override it: the dataset a run builds follows the process's TimeManager.
  • data_domain (str or True, keyword, 0.3.6.0): roll out every process of a data domain (True = tdfs4ds.DATA_DOMAIN; primary store only), driven by the domain clock (set_domain_time_manager) when time_manager is not given. process_list=None means the processes of tdfs4ds.DATA_DOMAIN. Passing both a list and data_domain is a ValueError.
  • order (keyword, 0.3.6.0): 'dependencies' (default) runs the processes of each date in dependency order, from the lineage graph; the sort is stable, so a list already in a valid order is unchanged. 'given' keeps the list's order (the behaviour before 0.3.6.0).