mlodaAPI

The mlodaAPI class serves as the primary interface for interacting with the core system, streamlining the setup and execution of computational workflows

Major components (and steps)

  1. Configuration

    Initialize the mloda with features, compute frameworks, and other settings to configure your environment.

  2. Engine Setup

    Create an execution plan by setting up the engine, which orchestrates the computation based on the defined features and configurations.

  3. Runner Setup

    Prepare the runner that will execute the plan, ensuring that all components are ready for computation.

  4. Run Engine Computation

    Apply the runner to execute the computations based on the prepared execution plan, managing the lifecycle of the computational process.

This means, depending on your needs, you can run them all at once (batch run) or split them up, e.g. for realtime needs (inference). For incremental result delivery see Streaming.

Configuration for mlodaAPI

  • requested_features: Specify the features to process (as names, Feature objects, or a Features container).
  • compute_frameworks (optional): Limit the compute frameworks using framework types or names.
  • links (optional): Define dataset merging links with Link objects.
  • data_access_collection (optional): Provide data sources for feature identification.

Runner & Execution Configuration

  • function_extender (optional): Add function extenders to customize computations.
  • parallelization_modes (optional): Choose between sync, threading, or multiprocessing modes. (Default: sync)
  • flight_server (optional): Specify a flight server for multiprocessing only.
  • column_ordering (optional): Control the ordering of result columns. Accepts "alphabetical" (sort columns A-Z) or "request_order" (preserve the order features were requested). Default: None (no guaranteed order).
from mloda.user import mloda

api_data = {"SampleData": {"FeatureA": [1], "FeatureB": [2], "FeatureC": [3]}}

# Alphabetical ordering
result = mloda.run_all(
    ["FeatureC", "FeatureA", "FeatureB"],
    compute_frameworks=["PandasDataFrame"],
    api_data=api_data,
    column_ordering="alphabetical"  # Result columns: FeatureA, FeatureB, FeatureC
)

# Preserve request order
result = mloda.run_all(
    ["FeatureC", "FeatureA", "FeatureB"],
    compute_frameworks=["PandasDataFrame"],
    api_data=api_data,
    column_ordering="request_order"  # Result columns: FeatureC, FeatureA, FeatureB
)

Two-Phase Execution: prepare() + run()

For realtime or inference scenarios, split configuration from execution. prepare() builds the execution plan once; run() executes it with fresh data each time.

from mloda.user import mloda

# 1. Prepare once, with a representative shape of the data
session = mloda.prepare(
    ["col__mean_aggr"],
    compute_frameworks=["PandasDataFrame"],
    api_data={"MyKey": {"col": [0.0]}},
)

# 2. Run multiple times with different data
result_1 = session.run(api_data={"MyKey": {"col": [1.0, 2.0]}})
result_2 = session.run(api_data={"MyKey": {"col": [3.0, 4.0]}})

run() also accepts an artifacts parameter for switching between artifact save and load modes across calls. See Artifacts for details.

run_all() is equivalent to prepare() followed by a single run(). stream_all() is equivalent to prepare() followed by a single stream_run().

For per-group streaming with plan reuse, call session.stream_run() instead of session.run() -- it yields each feature group's result as it completes. See Streaming for details.

Plugin Discovery

mloda provides functions to discover and inspect available plugins. Import them from mloda.steward:

from mloda.steward import (
    get_feature_group_docs,
    get_compute_framework_docs,
    get_extender_docs,
    resolve_feature,
)
resolve_feature

Resolve a single feature name (or a Feature) to its matching FeatureGroup without running the request, reporting failures in result.error instead of raising. It takes feature (str | Feature) positionally plus keyword-only options, plugin_collector, feature_group, links, data_access_collection, and compute_frameworks, and returns a ResolvedFeature (8 fields, including candidates, error, supported_compute_frameworks, subtype).

from mloda.steward import resolve_feature

result = resolve_feature("my_feature_name")
if result.feature_group:
    print(f"Resolved to: {result.feature_group.__name__}")
else:
    print(f"Error: {result.error}")

See Discover Plugins for the full signature, every ResolvedFeature field, and worked examples (options-gated groups, scoping, broken framework declarations). resolve_feature is exported from mloda.provider, mloda.user, and mloda.steward; the ResolvedFeature return type is exported from mloda.steward.

explain and resolved_plan

The runtime counterpart to resolve_feature: mlodaAPI.explain(...) builds the execution plan for a request without running it, and session.resolved_plan() returns the same records for a prepared session (before or after run()). Both return a list[PlanStep] in execution-plan order. Every explain parameter after features is keyword-only.

explain re-resolves the plan from scratch. It answers "what would this request resolve to", it is not a record of a prior run_all execution. For the plan of a run that actually happened, use the return value directly: run_all returns a RunResult (a list with a read-only plan property) and stream_all returns a ResultStream (generator-compatible, plan available before consuming). One planning pass serves both the results and the plan, unlike explain, which re-resolves.

from mloda.user import mloda

sales_data = {"SalesData": {"sales": [10.0, 20.0, 30.0]}}

results = mloda.run_all(["sales__mean_aggr"], compute_frameworks=["PandasDataFrame"], api_data=sales_data)
for step in results.plan:
    print(step.step_kind, step.feature_names)

To match a run_all resolution, pass the same parallelization_modes: run_all defaults to {ParallelizationMode.SYNC}, prepare/explain default to None, and compute frameworks are filtered by mode.

from mloda.user import mloda

# "sales" arrives through api_data here; in your own request it can come from any FeatureGroup.
for step in mloda.explain(["sales__mean_aggr"], compute_frameworks=["PandasDataFrame"], api_data=sales_data):
    print(step.step_kind, step.feature_names, step.feature_group_name, step.compute_framework_name)

Returns: PlanStep dataclass (frozen) with fields:

  • step_kind (Literal["compute", "join", "transform"]).
  • feature_names (tuple[str, ...]): Features computed by a compute step, empty otherwise. This includes engine-injected features (link index features, global-filter features); use the requested/injected split below to tell them apart.
  • requested_feature_names (tuple[str, ...]): The user-requested subset of feature_names on a compute step, empty for join and transform steps.
  • injected_feature_names (tuple[str, ...]): The engine-injected/dependency remainder of feature_names on a compute step, empty for join and transform steps.
  • feature_group (type[FeatureGroup] | None): Resolved FeatureGroup; the destination for a transform step; the link's declared left side for a join.
  • compute_framework (type[ComputeFramework] | None): Selected ComputeFramework; the destination for a transform step; the merge destination for a join.
  • source_feature_group / source_compute_framework: Origin of a transform step. For a join: the link's declared right side, and the framework merged in.
  • join_type (str | None): The link's join type ("inner", "left", ...) for a join step, None otherwise.
  • join_destination_side (Literal["left", "right"] | None): the declared side that holds the merge destination, for a join step; None otherwise.
  • join_inverted (bool | None, property): join_destination_side == "right", None without a side.
  • join_token (UUID | None): the join's completion token, the uuid the scheduler tracks, for a join step; None otherwise. Excluded from equality (fresh per planning run).
  • declared_left_frameworks / declared_right_frameworks (tuple[type[ComputeFramework], ...]): the compute frameworks each declared side's parent features declared as candidates, sorted by class name, for a join step; empty otherwise, and empty when the plan recorded no candidates for the side. APPEND/UNION sides carry only the index-bearing parent.
  • feature_group_name / compute_framework_name / source_feature_group_name / source_compute_framework_name (str | None): Class names of the above, None when unset.
  • declared_left_framework_names / declared_right_framework_names (tuple[str, ...]): class names of the two tuples above, same order.

Join semantics: for a join step the *_feature_group fields are the link's declared left/right sides, while compute_framework/source_compute_framework are the merge destination and the framework merged in, which may belong to the declared right side. join_destination_side is resolved from the two declared sides' framework candidates for every join type except APPEND and UNION, which always report "left"; a right join queues its destination on the declared right side, so it reports "right" in the common case.

How the engine tracks request provenance

The requested/injected split above is derived from a per-feature flag, not from re-matching names against the request.

  • Feature.initial_requested_data (bool, default False) marks a feature that the user asked for directly. It also decides which features come back in the run result, which is why a FeatureGroup may set it on a feature it created itself.
  • mlodaAPI._process_features sets it to True on every feature of the incoming request, before resolution. Features created during resolution (input features of a FeatureGroup, link index features, global-filter features) keep the False default, unless a FeatureGroup opts one in explicitly: input_features may construct a Feature with initial_requested_data=True to surface it in the results, and then it counts as requested in the split too.
  • FeatureSet.get_initial_requested_features() returns the sorted, deduplicated names of the flagged features in that set.
  • PlanStep.requested_feature_names is that accessor's output for a compute step's FeatureSet; injected_feature_names is the rest of feature_names. Both are sorted, so they do not follow the order of feature_names, and both are empty on join and transform steps, which carry no FeatureSet.
from mloda.user import mloda

for step in mloda.explain(["sales__mean_aggr"], compute_frameworks=["PandasDataFrame"], api_data=sales_data):
    print(step.requested_feature_names, step.injected_feature_names)
diagnose and resolution_report

diagnose and resolution_report() are the non-raising counterparts to explain and resolved_plan(): where the plan-based pair returns PlanStep records, these return the resolution facts a failing request would otherwise raise.

mlodaAPI.diagnose(features, ...) runs the whole-request preflight without raising and returns a single ResolutionDiagnosis. It takes the same arguments as explain (every parameter after features is keyword-only). On success its records equal session.resolution_report() and complete is True; on a resolution failure it carries the records resolved before the failing feature plus feature_name, failed_result, and message; on an environment or config failure (redefinition conflict, framework-declaration error, compute-framework pin) it returns records=[], complete=False, and only message.

session.resolution_report() returns the list[ResolutionRecord] captured while prepare() planned the request, one per feature, available before or after run().

from mloda.user import mlodaAPI

diagnosis = mlodaAPI.diagnose(["sales__mean_aggr"], compute_frameworks=["PandasDataFrame"])
if diagnosis.complete:
    for record in diagnosis.records:
        print(record.feature_name, record.requested)
else:
    print(diagnosis.feature_name, diagnosis.message)

When the same request is run rather than diagnosed, the failure raises FeatureResolutionError (below).

Resolution result types

Import the typed resolution surfaces from mloda.provider (also re-exported from mloda.user and mloda.steward):

from mloda.provider import FeatureResolutionError, ResolutionDiagnosis, ResolutionRecord
  • FeatureResolutionError (a ValueError subclass): raised during planning (mlodaAPI(...) / prepare() / run_all()) when a feature does not resolve to exactly one FeatureGroup. Attributes: feature_name (str), result (EvaluationResult, the captured per-candidate elimination facts), partial_records (tuple[ResolutionRecord, ...], features resolved before the failure, capped at the last 1000). Because it subclasses ValueError, existing except ValueError handlers keep working; catch FeatureResolutionError to read the attributes. See Feature Group Resolution Errors.
  • ResolutionDiagnosis (frozen dataclass): the return value of diagnose, never raised. Fields: records (list[ResolutionRecord]), complete (bool), feature_name (str | None), failed_result (EvaluationResult | None), message (str | None).
  • ResolutionRecord (frozen dataclass): one per feature, returned inside resolution_report(), ResolutionDiagnosis.records, and FeatureResolutionError.partial_records; never raised. Fields: feature_name (str), requested (bool), result (EvaluationResult).

EvaluationResult is the captured matcher outcome carried by the fields above; it is defined in mloda.core.prepare.resolution_types and is not part of the public __init__ exports.

get_feature_group_docs

Get documentation for feature groups with optional filtering.

from mloda.steward import get_feature_group_docs

# Get all feature groups
all_fgs = get_feature_group_docs()

# Filter by name
fgs = get_feature_group_docs(name="timestamp")

# Filter by compute framework
fgs = get_feature_group_docs(compute_framework="PandasDataFrame")

Parameters:

  • name (str, optional): Filter by name (case-insensitive partial match).
  • search (str, optional): Search in description (case-insensitive partial match).
  • compute_framework (str | Type[ComputeFramework], optional): Filter by compute framework.
  • version_contains (str, optional): Filter by version substring.

Returns: List[FeatureGroupInfo] sorted by name.

get_compute_framework_docs

Get documentation for compute frameworks with optional filtering.

from mloda.steward import get_compute_framework_docs

# List every framework (is_available flags whether its backend library is installed)
frameworks = get_compute_framework_docs()

# Only frameworks whose backend library is installed
available_frameworks = get_compute_framework_docs(available_only=True)

Parameters:

  • name (str, optional): Filter by name (case-insensitive partial match).
  • search (str, optional): Search in description (case-insensitive partial match).
  • available_only (bool, default False): By default all frameworks are listed (with is_available as the flag); set available_only=True to filter to available frameworks only.

Returns: List[ComputeFrameworkInfo] sorted by name.

get_extender_docs

Get documentation for extenders with optional filtering.

from mloda.steward import get_extender_docs

# Get all extenders
extenders = get_extender_docs()

# Filter by wrapped function type
extenders = get_extender_docs(wraps="formula")

Parameters:

  • name (str, optional): Filter by name (case-insensitive partial match).
  • search (str, optional): Search in description (case-insensitive partial match).
  • wraps (str, optional): Filter by wrapped function type (case-insensitive exact match).

Returns: List[ExtenderInfo] sorted by name.