← Files VeraARCHIVED FILE
modules/variance-analysis/scripts/legacy_adapter.py
67.2 KB · Oct 2, 2026 · 00:29 UTC
"""Adapter around the vendored legacy Mparanza variance runtime."""
from __future__ import annotations
import copy
import importlib
import sys
from dataclasses import dataclass
from pathlib import Path
from typing import Any
import polars as pl
__all__ = [
"LegacyVariableBridgeAlternativeRun",
"LegacyVariableBridgeSequence",
"LegacyVariableBridgeRun",
"LegacyVarianceRun",
"cleanup_legacy_imports",
"legacy_date_period_context",
"run_legacy_variable_dimension_component_bridge",
"run_legacy_variable_dimension_bridge",
"run_legacy_variance",
]
TOTAL_DIMENSION = "__total"
BRIDGE_MEASURE_COLUMNS = {
"bridge_level",
"bridge_dimensions",
"variance_type",
"variance_amount",
"amount_baseline",
"amount_comparison",
"units_baseline",
"units_comparison",
"bridge_unique_value_weight",
}
AUTO_DRILLDOWN_MODES = {"none", "single_row", "dominant_row", "all_selected"}
@dataclass(frozen=True)
class LegacyVarianceRun:
"""Legacy runtime outputs normalized for the plugin contract."""
frame: pl.DataFrame
legacy_frame: pl.DataFrame
audit: dict[str, Any]
@dataclass(frozen=True)
class LegacyVariableBridgeRun:
"""Legacy variable-dimension bridge outputs normalized for the plugin contract."""
frame: pl.DataFrame
legacy_frame: pl.DataFrame
details_frame: pl.DataFrame
snapshot_frame: pl.DataFrame
candidate_frame: pl.DataFrame
candidate_legacy_frame: pl.DataFrame
drilldown_runs: dict[int, LegacyVariableBridgeSequence]
moved_run: LegacyVariableBridgeSequence | None
sweep_runs: dict[int, LegacyVariableBridgeAlternativeRun]
param: dict[str, Any]
chart: dict[str, Any]
bridge_dimensions: list[str]
audit: dict[str, Any]
@dataclass(frozen=True)
class LegacyVariableBridgeSequence:
"""One legacy ``process_node_combinations`` sequence and its side outputs."""
frame: pl.DataFrame
legacy_frame: pl.DataFrame
details_frame: pl.DataFrame
snapshot_frame: pl.DataFrame
param: dict[str, Any]
audit: dict[str, Any]
@dataclass(frozen=True)
class LegacyVariableBridgeAlternativeRun:
"""One alternative root-cause start row and optional drilldown outputs."""
alternative_result: int
sequence: LegacyVariableBridgeSequence
drilldown_runs: dict[int, LegacyVariableBridgeSequence]
moved_run: LegacyVariableBridgeSequence | None
audit: dict[str, Any]
@dataclass(frozen=True)
class _LegacyVariableBridgeContext:
"""Prepared legacy bridge state reused across alternative starts."""
imports: dict[str, Any]
names: dict[str, str]
config: dict[str, Any]
report_dimensions: list[str]
requested_calculation_grain: list[str]
bridge_dimensions: list[str]
param: dict[str, Any]
chart: dict[str, Any]
index_cols: list[str]
candidate_frame: pl.DataFrame
candidate_legacy_frame: pl.DataFrame
def _vendor_root() -> Path:
"""Return the plugin-local legacy module root."""
return Path(__file__).resolve().parents[1] / "vendor"
def _shared_vendor_root() -> Path:
"""Return the repo shared legacy module root used during development."""
return (
Path(__file__).resolve().parents[3]
/ "plugins"
/ "_shared"
/ "variance"
/ "vendor"
)
def _legacy_import_parent() -> Path:
"""Return shared plugin modules in dev, otherwise packaged vendor modules."""
shared_root = _shared_vendor_root()
if (shared_root / "modules" / "__init__.py").exists():
return shared_root
return _vendor_root()
def _uses_modules_from(module_root: Path) -> bool:
"""Return whether the currently loaded ``modules`` package uses ``module_root``."""
module = sys.modules.get("modules")
if module is None:
return True
module_file = getattr(module, "__file__", None)
if not module_file:
return False
try:
Path(module_file).resolve().relative_to(module_root.resolve())
except ValueError:
return False
return True
def _ensure_legacy_import_path() -> Path:
"""Put shared/dev or vendored legacy tree first and avoid mixed imports."""
legacy_parent = _legacy_import_parent()
module_root = legacy_parent / "modules"
if module_root.exists():
legacy_text = str(legacy_parent)
if legacy_text in sys.path:
sys.path.remove(legacy_text)
sys.path.insert(0, legacy_text)
if not _uses_modules_from(module_root):
for module_name in list(sys.modules):
if module_name == "modules" or module_name.startswith("modules."):
del sys.modules[module_name]
return legacy_parent
def _module_loaded_from_path(module_name: str, root: Path) -> bool:
"""Return whether ``module_name`` was loaded from ``root``."""
module = sys.modules.get(module_name)
if module is None:
return False
module_file = getattr(module, "__file__", None)
if not module_file:
return False
try:
Path(module_file).resolve().relative_to(root.resolve())
except ValueError:
return False
return True
def cleanup_legacy_imports() -> None:
"""Remove plugin-local legacy modules from global import state."""
vendor_root = _vendor_root()
shared_root = _shared_vendor_root()
removable_roots = (vendor_root, shared_root)
sys.path[:] = [
entry
for entry in sys.path
if entry not in {str(root) for root in removable_roots}
]
for module_name in list(sys.modules):
if module_name == "modules" or module_name.startswith("modules."):
if any(
_module_loaded_from_path(module_name, root) for root in removable_roots
):
del sys.modules[module_name]
def _legacy_imports() -> dict[str, Any]:
"""Import legacy functions after the vendored path has priority."""
vendor_root = _ensure_legacy_import_path()
config = importlib.import_module("modules.utilities.config")
helpers = importlib.import_module("modules.utilities.helpers")
variance_utils = importlib.import_module("modules.variance.variance_utils")
variance_formulas = importlib.import_module("modules.variance.variance_formulas")
index_handling = importlib.import_module("modules.variance.index_handling")
variance_orchestrator = importlib.import_module(
"modules.variance.variance_orchestrator"
)
variance_decomposition = importlib.import_module(
"modules.variance.variance_decomposition"
)
return {
"vendor_root": vendor_root,
"get_naming_params": config.get_naming_params,
"get_config_params": config.get_config_params,
"group_by_df_on_index_cols": helpers.group_by_df_on_index_cols,
"calculate_unit_and_volume_price": helpers.calculate_unit_and_volume_price,
"calculate_discount_per_units_and_volume": (
helpers.calculate_discount_per_units_and_volume
),
"calculate_cogs_per_units_and_volume": (
helpers.calculate_cogs_per_units_and_volume
),
"get_period_length_polars": helpers.get_period_length_polars,
"get_rolling_and_year_to_date_period": (
helpers.get_rolling_and_year_to_date_period
),
"pivot_lazy_periods": helpers.pivot_lazy_periods,
"rename_periods": variance_utils.rename_periods,
"recalculate_price": variance_utils.recalculate_price,
"set_parameters_on_scenario_option": (
variance_utils.set_parameters_on_scenario_option
),
"calculate_variance": variance_formulas.calculate_variance,
"calculate_sales_mix_variance": variance_formulas.calculate_sales_mix_variance,
"process_and_prepare_multidimensional_data": (
index_handling.process_and_prepare_multidimensional_data
),
"process_node_combinations": variance_decomposition.process_node_combinations,
"process_variance_calculation": (
variance_orchestrator.process_variance_calculation
),
}
def legacy_date_period_context(
df: pl.DataFrame,
date_column: str,
) -> dict[str, Any]:
"""Return legacy most-recent-date and rolling/YTD labels for a date column."""
imports = _legacy_imports()
names = imports["get_naming_params"]()
date_name = names["dateName"]
lazy_dates = (
df.select(pl.col(date_column).cast(pl.Date).alias(date_name))
.drop_nulls(date_name)
.lazy()
)
param: dict[str, Any] = {}
chart: dict[str, Any] = {}
param, most_recent_date, least_recent_date, period_length_months = imports[
"get_period_length_polars"
](lazy_dates, param, True)
rolling_symbol = names["rollingPeriodSymbol"]
to_date_symbol = names["toDateSymbol"]
return {
"most_recent_date": most_recent_date,
"least_recent_date": least_recent_date,
"period_length_months": period_length_months,
"rolling_label": imports["get_rolling_and_year_to_date_period"](
rolling_symbol, param, chart, False
),
"rolling_baseline_label": imports["get_rolling_and_year_to_date_period"](
rolling_symbol, param, chart, True
),
"ytd_label": imports["get_rolling_and_year_to_date_period"](
to_date_symbol, param, chart, False
),
"ytd_baseline_label": imports["get_rolling_and_year_to_date_period"](
to_date_symbol, param, chart, True
),
}
def _ordered_unique(values: list[str]) -> list[str]:
"""Return values once, preserving order."""
return list(dict.fromkeys(values))
def _leaf_dimensions(recipe: dict[str, Any], report_dimensions: list[str]) -> list[str]:
"""Return the lowest grain used by the legacy bottom-up calculation."""
mappings = recipe["mappings"]
grain = list(mappings.get("calculation_grain") or report_dimensions)
dimensions = _ordered_unique([*report_dimensions, *grain])
return dimensions or [TOTAL_DIMENSION]
def _metric_aliases(
mappings: dict[str, Any], names: dict[str, str]
) -> dict[str, str | None]:
"""Return plugin mapping fields as legacy metric aliases."""
aliases: dict[str, str | None] = {
"amount": names["monetaryLocalCurrencyName"],
"units": names["unitsName"] if mappings.get("units_column") else None,
"discount": names["discountName"] if mappings.get("discount_column") else None,
"cogs": names["cogsName"] if mappings.get("cogs_column") else None,
"net": names["netOfDiscountName"] if mappings.get("discount_column") else None,
"margin": names["marginName"] if mappings.get("cogs_column") else None,
}
return aliases
def _numeric_expr(source: str, alias: str) -> pl.Expr:
"""Return a numeric column expression with legacy null handling."""
return pl.col(source).cast(pl.Float64, strict=False).fill_null(0.0).alias(alias)
def _canonical_legacy_input(
df: pl.DataFrame,
recipe: dict[str, Any],
names: dict[str, str],
leaf_dimensions: list[str],
) -> tuple[pl.DataFrame, list[str]]:
"""Convert user columns into legacy canonical column names."""
mappings = recipe["mappings"]
aliases = _metric_aliases(mappings, names)
period_name = names["periodName"]
expressions: list[pl.Expr] = []
for dimension in leaf_dimensions:
if dimension == TOTAL_DIMENSION:
expressions.append(pl.lit("Total").alias(TOTAL_DIMENSION))
else:
expressions.append(
pl.col(dimension).cast(pl.Utf8).fill_null("").alias(dimension)
)
expressions.extend(
[
pl.col(mappings["period_column"]).cast(pl.Utf8).alias(period_name),
_numeric_expr(mappings["amount_column"], aliases["amount"] or "Sales"),
]
)
optional_metric_map = (
("units_column", aliases["units"]),
("discount_column", aliases["discount"]),
("cogs_column", aliases["cogs"]),
)
for mapping_key, alias in optional_metric_map:
source = mappings.get(mapping_key)
if source and alias:
expressions.append(_numeric_expr(source, alias))
working = df.select(expressions).filter(
pl.col(period_name).is_in(
[str(mappings["baseline_period"]), str(mappings["comparison_period"])]
)
)
# The legacy bridge assigns row keys before ranking alternatives, so input
# order must be explicit for reproducible alternativeResult behavior.
working = working.sort([*leaf_dimensions, period_name])
value_columns = [aliases["amount"] or "Sales"]
if aliases["units"]:
value_columns.append(aliases["units"])
if aliases["discount"]:
working = working.with_columns(
(pl.col(aliases["amount"] or "Sales") - pl.col(aliases["discount"])).alias(
aliases["net"] or "Sales Net Discount"
)
)
value_columns.extend([aliases["discount"], aliases["net"]])
if aliases["cogs"]:
discount_expr = (
pl.col(aliases["discount"]) if aliases["discount"] else pl.lit(0.0)
)
working = working.with_columns(
(
pl.col(aliases["amount"] or "Sales")
- discount_expr
- pl.col(aliases["cogs"])
).alias(aliases["margin"] or "Margin")
)
value_columns.extend([aliases["cogs"], aliases["margin"]])
return working, _ordered_unique([column for column in value_columns if column])
def _legacy_param_and_chart(
recipe: dict[str, Any],
report_dimensions: list[str],
names: dict[str, str],
) -> tuple[dict[str, Any], dict[str, Any]]:
"""Build the small legacy state dictionaries required by old functions."""
from modules.chart_harness import apply_legacy_filter_title_metadata
mappings = recipe["mappings"]
not_met = names["notMetConditionValue"]
has_units = bool(mappings.get("units_column"))
has_discount = bool(mappings.get("discount_column"))
has_cogs = bool(mappings.get("cogs_column"))
param = {
names["numberOfPeriodsFound"]: 2,
names["unitsColFound"]: has_units,
names["volumeColFound"]: False,
names["discountColFound"]: has_discount,
names["cogsColFound"]: has_cogs,
names["marginColFound"]: has_cogs,
names["monetaryLocalCurrencyColFound"]: True,
names["calculateDriverVariance"]: False,
names["driverArray"]: [],
names["isFilteredKey"]: not_met,
names["selectedPeriods"]: [
str(mappings["baseline_period"]),
str(mappings["comparison_period"]),
],
names["allPeriodsList"]: [
str(mappings["baseline_period"]),
str(mappings["comparison_period"]),
],
names["impossibleToProcessFile"]: False,
names["fileUploadDisabled"]: not_met,
names["dropLowCorrelationCols"]: False,
names["toTitleCase"]: False,
names["reverseSortPeriods"]: False,
names["isColumnMultiplied"]: False,
names["renameTitlesDict"]: {},
}
variance_choice = (
names["mixAndUnitsAggregation"]
if has_units
else names["totalVarianceAggregation"]
)
currency = str(recipe.get("options", {}).get("currency") or "EUR")
chart = {
names["selectedPeriods"]: [
str(mappings["baseline_period"]),
str(mappings["comparison_period"]),
],
names["varianceAggregation"]: variance_choice,
names["processingChoice"]: names["runOneDimensionalAnalysis"],
names["mainDimension"]: report_dimensions,
names["reverseSortPeriods"]: False,
names["showInitialAndFinalValues"]: True,
names["varianceInPercent"]: False,
names["shareOfTotalMarket"]: False,
names["plotSmallMultiplesWaterfall"]: False,
names["filterDates"]: False,
names["compareScenariosOrPeriods"]: names["comparePeriods"],
names["chosenChart"]: names["verticalWaterfallChart"],
names["varianceAnalysisChart"]: True,
names["currencyChoice"]: currency,
names["fullCurrencyName"]: currency,
}
chart = apply_legacy_filter_title_metadata(chart, names, recipe)
return param, chart
def _column_or_zero(schema: dict[str, pl.DataType], column: str) -> pl.Expr:
"""Return a numeric column expression or zero when absent."""
if column in schema:
return pl.col(column).fill_null(0.0)
return pl.lit(0.0)
def _column_or_null(schema: dict[str, pl.DataType], column: str) -> pl.Expr:
"""Return a column expression or null when absent."""
if column in schema:
return pl.col(column)
return pl.lit(None)
def _safe_ratio(numerator: pl.Expr, denominator: pl.Expr) -> pl.Expr:
"""Return a zero-denominator-safe ratio expression."""
return pl.when(denominator == 0).then(0.0).otherwise(numerator / denominator)
def _collapse_legacy_rows(
legacy_frame: pl.DataFrame | pl.LazyFrame,
report_dimensions: list[str],
param: dict[str, Any],
recalculate_price: Any,
) -> tuple[pl.DataFrame, dict[str, Any]]:
"""Collapse duplicate legacy rows after old mix processing."""
schema = (
legacy_frame.collect_schema()
if isinstance(legacy_frame, pl.LazyFrame)
else legacy_frame.schema
)
grouping_dimensions = report_dimensions or (
[TOTAL_DIMENSION] if TOTAL_DIMENSION in schema else []
)
if not grouping_dimensions:
return _collect_if_lazy(legacy_frame), param
numeric_columns = [
column
for column, dtype in schema.items()
if column not in grouping_dimensions and dtype.is_numeric()
]
if not numeric_columns:
return _collect_if_lazy(legacy_frame), param
grouped = (
legacy_frame.lazy()
.group_by(grouping_dimensions)
.agg([pl.col(column).sum().alias(column) for column in numeric_columns])
.collect()
)
grouped, param = recalculate_price(grouped, param)
if isinstance(grouped, pl.LazyFrame):
grouped = grouped.collect()
return grouped, param
def _merge_missing_legacy_columns(
component_frame: pl.DataFrame,
period_totals: pl.DataFrame,
report_dimensions: list[str],
) -> pl.DataFrame:
"""Restore period-total columns that legacy mix output does not carry."""
grouping_dimensions = report_dimensions or (
[TOTAL_DIMENSION] if TOTAL_DIMENSION in component_frame.schema else []
)
if not grouping_dimensions:
return component_frame
missing_columns = [
column
for column in period_totals.columns
if column not in component_frame.columns and column not in grouping_dimensions
]
if not missing_columns:
return component_frame
return component_frame.join(
period_totals.select([*grouping_dimensions, *missing_columns]),
on=grouping_dimensions,
how="left",
)
def _normalize_legacy_output(
legacy_frame: pl.DataFrame,
report_dimensions: list[str],
names: dict[str, str],
) -> pl.DataFrame:
"""Map legacy output columns to the plugin's stable result schema."""
config = _legacy_imports()["get_config_params"]()
periods = config["periodsArray"]
separator = names["separatorString"]
sales_p0 = names["monetaryLocalCurrencyName"] + separator + periods[0]
sales_p1 = names["monetaryLocalCurrencyName"] + separator + periods[1]
units_p0 = names["unitsName"] + separator + periods[0]
units_p1 = names["unitsName"] + separator + periods[1]
unit_price_p0 = names["pricePerUnitName"] + separator + periods[0]
unit_price_p1 = names["pricePerUnitName"] + separator + periods[1]
discount_p0 = names["discountName"] + separator + periods[0]
discount_p1 = names["discountName"] + separator + periods[1]
cogs_p0 = names["cogsName"] + separator + periods[0]
cogs_p1 = names["cogsName"] + separator + periods[1]
schema = legacy_frame.schema
amount0 = _column_or_zero(schema, sales_p0)
amount1 = _column_or_zero(schema, sales_p1)
units0 = _column_or_zero(schema, units_p0)
units1 = _column_or_zero(schema, units_p1)
total_delta = _column_or_zero(schema, names["totalVariance"])
price_variance = _column_or_zero(schema, names["priceVariance"])
volume_source = (
names["pureVolumeVarianceName"]
if names["pureVolumeVarianceName"] in schema
else names["volumeVariance"]
)
volume_variance = _column_or_zero(schema, volume_source)
mix_variance = _column_or_zero(schema, names["mixVariance"])
expressions: list[pl.Expr] = []
for dimension in report_dimensions or [TOTAL_DIMENSION]:
if dimension in schema:
output_name = "segment" if dimension == TOTAL_DIMENSION else dimension
expressions.append(pl.col(dimension).alias(output_name))
expressions.extend(
[
amount0.alias("amount_baseline"),
amount1.alias("amount_comparison"),
(amount1 - amount0).alias("amount_delta"),
total_delta.alias("total_delta"),
pl.when(amount0 <= 0)
.then(None)
.otherwise((amount1 - amount0) / amount0 * 100)
.alias("amount_pct_change"),
_column_or_null(schema, unit_price_p0).alias("price_baseline"),
_column_or_null(schema, unit_price_p1).alias("price_comparison"),
price_variance.alias("price_variance"),
volume_variance.alias("volume_variance"),
mix_variance.alias("mix_variance"),
(total_delta - price_variance - volume_variance - mix_variance).alias(
"component_reconciliation_delta"
),
]
)
if units_p0 in schema and units_p1 in schema:
expressions.extend(
[
units0.alias("units_baseline"),
units1.alias("units_comparison"),
(units1 - units0).alias("units_delta"),
_safe_ratio(amount0, units0).alias("calculated_price_baseline"),
_safe_ratio(amount1, units1).alias("calculated_price_comparison"),
]
)
if discount_p0 in schema and discount_p1 in schema:
discount0 = _column_or_zero(schema, discount_p0)
discount1 = _column_or_zero(schema, discount_p1)
net0 = amount0 - discount0
net1 = amount1 - discount1
expressions.extend(
[
discount0.alias("discount_baseline"),
discount1.alias("discount_comparison"),
(-(discount1 - discount0)).alias("discount_variance"),
net0.alias("net_baseline"),
net1.alias("net_comparison"),
(net1 - net0).alias("net_delta"),
pl.when(net0 == 0)
.then(None)
.otherwise((net1 - net0) / net0 * 100)
.alias("net_pct_change"),
]
)
if cogs_p0 in schema and cogs_p1 in schema:
cogs0 = _column_or_zero(schema, cogs_p0)
cogs1 = _column_or_zero(schema, cogs_p1)
discount0 = _column_or_zero(schema, discount_p0)
discount1 = _column_or_zero(schema, discount_p1)
margin0 = amount0 - discount0 - cogs0
margin1 = amount1 - discount1 - cogs1
expressions.extend(
[
cogs0.alias("cogs_baseline"),
cogs1.alias("cogs_comparison"),
(cogs1 - cogs0).alias("cogs_delta"),
(-(cogs1 - cogs0)).alias("cogs_variance"),
margin0.alias("margin_baseline"),
margin1.alias("margin_comparison"),
(margin1 - margin0).alias("margin_delta"),
pl.when(margin0 == 0)
.then(None)
.otherwise((margin1 - margin0) / margin0 * 100)
.alias("margin_pct_change"),
pl.lit(0.0).alias("margin_component_reconciliation_delta"),
]
)
return legacy_frame.select(expressions).sort("total_delta", descending=True)
def _collect_if_lazy(frame: pl.DataFrame | pl.LazyFrame) -> pl.DataFrame:
"""Collect a lazy frame while preserving eager frames."""
if isinstance(frame, pl.LazyFrame):
return frame.collect()
return frame
def _add_variable_bridge_defaults(
param: dict[str, Any],
canonical: pl.DataFrame,
dimensions: list[str],
names: dict[str, str],
config: dict[str, Any],
) -> dict[str, Any]:
"""Populate legacy bridge metadata normally produced by UI intake."""
if dimensions:
counts = canonical.select(
[pl.col(dimension).n_unique().alias(dimension) for dimension in dimensions]
).to_dicts()[0]
else:
counts = {}
param[names["uniqueValuesInColumnDict"]] = {
dimension: int(counts[dimension]) for dimension in dimensions
}
param[names["uniqueValuesInColumnList"]] = list(dimensions)
param[names["maxIndexArrayLength"]] = min(
len(dimensions),
config[names["maxIndexArrayLength"]],
)
return param
def _active_bridge_dimensions(row: dict[str, Any]) -> str:
"""Return the comma-separated dimensions active in a legacy bridge row."""
inactive = {"", "All", "N/A", "None", "null"}
active = [
dimension
for dimension, value in row.items()
if value is not None and str(value) not in inactive
]
return ",".join(active) if active else "total"
def _normalize_legacy_bridge_output(
legacy_frame: pl.DataFrame,
dimensions: list[str],
names: dict[str, str],
*,
sort_by_variance: bool = True,
has_units: bool = True,
) -> pl.DataFrame:
"""Map legacy variable-dimension bridge rows to a stable plugin schema."""
if legacy_frame.is_empty():
return legacy_frame
config = _legacy_imports()["get_config_params"]()
periods = config["periodsArray"]
separator = names["separatorString"]
sales_p0 = names["monetaryLocalCurrencyName"] + separator + periods[0]
sales_p1 = names["monetaryLocalCurrencyName"] + separator + periods[1]
units_p0 = names["unitsName"] + separator + periods[0]
units_p1 = names["unitsName"] + separator + periods[1]
variance_type = names["varianceTypeName"]
variance_amount = names["varianceAmountName"]
number_of_nodes = names["numberOfNodes"]
unique_values = names["uniqueValuesInCombination"]
schema = legacy_frame.schema
present_dimensions = [dimension for dimension in dimensions if dimension in schema]
expressions: list[pl.Expr] = [
pl.col(dimension).cast(pl.Utf8).fill_null("All").alias(dimension)
for dimension in present_dimensions
]
if number_of_nodes in schema:
expressions.append(
pl.col(number_of_nodes)
.cast(pl.Int64, strict=False)
.fill_null(0)
.alias("bridge_level")
)
if present_dimensions:
expressions.append(
pl.struct(present_dimensions)
.map_elements(_active_bridge_dimensions, return_dtype=pl.Utf8)
.alias("bridge_dimensions")
)
else:
expressions.append(pl.lit("total").alias("bridge_dimensions"))
if variance_type in schema:
type_expression = pl.col(variance_type).cast(pl.Utf8)
if not has_units:
type_expression = type_expression.replace(
{names["totalVariance"]: "Total variance"}
)
expressions.append(type_expression.alias("variance_type"))
if variance_amount in schema:
expressions.append(
pl.col(variance_amount)
.cast(pl.Float64, strict=False)
.fill_null(0.0)
.alias("variance_amount")
)
for legacy_column, output_column in (
(sales_p0, "amount_baseline"),
(sales_p1, "amount_comparison"),
(units_p0, "units_baseline"),
(units_p1, "units_comparison"),
(unique_values, "bridge_unique_value_weight"),
):
if legacy_column in schema:
expressions.append(pl.col(legacy_column).alias(output_column))
normalized = legacy_frame.select(expressions)
if "bridge_level" not in normalized.schema:
normalized = normalized.with_columns(
pl.col("bridge_dimensions").str.split(",").list.len().alias("bridge_level")
)
if sort_by_variance and "variance_amount" in normalized.schema:
tie_breakers = [
column
for column in [*present_dimensions, "variance_type", "bridge_dimensions"]
if column in normalized.schema
]
normalized = normalized.sort(
["variance_amount", *tie_breakers],
descending=[True, *[False for _column in tie_breakers]],
)
return normalized
def _bridge_dimension_audit(
normalized: pl.DataFrame,
report_dimensions: list[str],
requested_calculation_grain: list[str],
effective_bridge_dimensions: list[str],
) -> dict[str, list[str]]:
"""Return requested, emitted, dropped, and added bridge dimension metadata."""
emitted_dimensions = [
column for column in normalized.columns if column not in BRIDGE_MEASURE_COLUMNS
]
dropped_dimensions = [
dimension
for dimension in effective_bridge_dimensions
if dimension not in emitted_dimensions
]
internally_added_dimensions = [
dimension
for dimension in emitted_dimensions
if dimension not in effective_bridge_dimensions
]
dropped_report_dimensions = [
dimension
for dimension in report_dimensions
if dimension not in emitted_dimensions
]
return {
"requested_report_dimensions": report_dimensions,
"requested_calculation_grain": requested_calculation_grain,
"effective_bridge_dimensions": effective_bridge_dimensions,
"emitted_bridge_dimensions": emitted_dimensions,
"dropped_bridge_dimensions": dropped_dimensions,
"internally_added_bridge_dimensions": internally_added_dimensions,
"dropped_report_dimensions": dropped_report_dimensions,
}
def _legacy_sequence_audit(
*,
run_name: str,
frame: pl.DataFrame,
details_frame: pl.DataFrame,
snapshot_frame: pl.DataFrame,
param: dict[str, Any],
names: dict[str, str],
) -> dict[str, Any]:
"""Return audit metadata for one legacy sequence run."""
selected_dimensions: list[str] = []
if not frame.is_empty() and "bridge_dimensions" in frame.schema:
selected_dimensions = frame["bridge_dimensions"].to_list()
unique_selected_dimensions = list(dict.fromkeys(selected_dimensions))
return {
"legacy_sequence_run": run_name,
"row_count": frame.height,
"sequence_row_count": frame.height,
"selected_sequence_bridge_dimensions": selected_dimensions,
"selected_sequence_unique_bridge_dimensions": unique_selected_dimensions,
"selected_sequence_has_mixed_dimensions": len(unique_selected_dimensions) > 1,
"details_row_count": details_frame.height,
"snapshot_row_count": snapshot_frame.height,
"sequence_running_total": param.get(names["runningTotalName"]),
"sequence_rows_until_stop": param.get(names["rowResultsUntilStop"]),
}
def _run_legacy_bridge_sequence(
imports: dict[str, Any],
source_frame: pl.DataFrame,
index_cols: list[str],
param: dict[str, Any],
chart: dict[str, Any],
run_name: str,
bridge_dimensions: list[str],
names: dict[str, str],
*,
sort_by_variance: bool = False,
) -> LegacyVariableBridgeSequence:
"""Run legacy ``process_node_combinations`` and normalize all outputs."""
sequence_param = copy.deepcopy(param)
sequence_frame, details_frame, snapshot_frame, sequence_param = imports[
"process_node_combinations"
](
source_frame,
index_cols,
sequence_param,
copy.deepcopy(chart),
run_name,
)
sequence_legacy_frame = _collect_if_lazy(sequence_frame)
collected_details = _collect_if_lazy(details_frame)
collected_snapshot = _collect_if_lazy(snapshot_frame)
normalized = _normalize_legacy_bridge_output(
sequence_legacy_frame,
bridge_dimensions,
names,
sort_by_variance=sort_by_variance,
has_units=bool(param[names["unitsColFound"]]),
)
return LegacyVariableBridgeSequence(
frame=normalized,
legacy_frame=sequence_legacy_frame,
details_frame=collected_details,
snapshot_frame=collected_snapshot,
param=sequence_param,
audit=_legacy_sequence_audit(
run_name=run_name,
frame=normalized,
details_frame=collected_details,
snapshot_frame=collected_snapshot,
param=sequence_param,
names=names,
),
)
def _root_cause_option_rows(options: dict[str, Any], key: str) -> list[int]:
"""Return normalized positive row numbers from root-cause options."""
raw_value = options.get(key, [])
if raw_value is None:
return []
values = raw_value if isinstance(raw_value, list) else [raw_value]
result: list[int] = []
for value in values:
try:
parsed = int(value)
except (TypeError, ValueError):
continue
if parsed > 0 and parsed not in result:
result.append(parsed)
return result
def _root_cause_move_rows(options: dict[str, Any]) -> dict[int, list[int]]:
"""Return normalized move-row mappings from root-cause options."""
raw_value = options.get("root_cause_bridge_move_rows", {})
if not isinstance(raw_value, dict):
return {}
result: dict[int, list[int]] = {}
for main_row, drilldown_rows in raw_value.items():
try:
parsed_main = int(main_row)
except (TypeError, ValueError):
continue
if parsed_main <= 0:
continue
rows = drilldown_rows if isinstance(drilldown_rows, list) else [drilldown_rows]
parsed_rows: list[int] = []
for row in rows:
try:
parsed_row = int(row)
except (TypeError, ValueError):
continue
if parsed_row > 0 and parsed_row not in parsed_rows:
parsed_rows.append(parsed_row)
if parsed_rows:
result[parsed_main] = parsed_rows
return result
def _requested_drilldown_rows(
*,
selected_row_count: int,
options: dict[str, Any],
move_rows: dict[int, list[int]],
) -> tuple[list[int], list[int]]:
"""Return valid and invalid requested main rows for drilldown processing."""
rows = (
list(range(1, selected_row_count + 1))
if bool(options.get("root_cause_bridge_drilldown_all", False))
else _root_cause_option_rows(options, "root_cause_bridge_drilldown_rows")
)
for main_row in move_rows:
if main_row not in rows:
rows.append(main_row)
valid = [row for row in rows if 1 <= row <= selected_row_count]
invalid = [row for row in rows if row < 1 or row > selected_row_count]
return valid, invalid
def _details_for_main_row(
details_frame: pl.DataFrame,
main_legacy_frame: pl.DataFrame,
main_row: int,
names: dict[str, str],
) -> pl.DataFrame:
"""Return the legacy detail rows for a 1-based main sequence row."""
drilldown_key = names["drilldownKey"]
random_key = names["randomKey"]
if (
details_frame.is_empty()
or main_legacy_frame.is_empty()
or main_row < 1
or main_row > main_legacy_frame.height
or drilldown_key not in details_frame.schema
or random_key not in main_legacy_frame.schema
):
return pl.DataFrame()
row_key = main_legacy_frame[main_row - 1, random_key]
if row_key is None:
return pl.DataFrame()
return details_frame.filter(pl.col(drilldown_key) == row_key)
def _bridge_row_filter_dict(
row: dict[str, Any],
bridge_dimensions: list[str],
names: dict[str, str],
) -> dict[str, Any]:
"""Return a legacy filter dict for a selected bridge row."""
nan_value = names["nanFillValue"]
filter_dict: dict[str, Any] = {}
for dimension in bridge_dimensions:
value = row.get(dimension)
if value is None:
continue
text_value = str(value)
if text_value and text_value != nan_value:
filter_dict[dimension] = value
variance_type = row.get("variance_type")
if variance_type is not None and str(variance_type):
# Normalized amount-only labels must map back to the unchanged legacy
# calculation key when a reviewed drilldown row is inserted.
filter_dict[names["varianceTypeName"]] = (
names["totalVariance"]
if variance_type == "Total variance"
else variance_type
)
return filter_dict
def _next_insert_slot(insert_dict: dict[int, dict[str, Any]], start_slot: int) -> int:
"""Return the next available legacy insertion slot."""
slot = start_slot
while slot in insert_dict:
slot += 1
return slot
def _build_insert_at_row_dict(
*,
move_rows: dict[int, list[int]],
drilldown_runs: dict[int, LegacyVariableBridgeSequence],
bridge_dimensions: list[str],
names: dict[str, str],
) -> tuple[dict[int, dict[str, Any]], dict[str, Any]]:
"""Build legacy ``insertAtRowDict`` from selected drilldown rows."""
insert_dict: dict[int, dict[str, Any]] = {}
invalid: dict[str, list[int]] = {}
inserted: dict[str, list[int]] = {}
slot_map: dict[str, list[int]] = {}
for main_row, drilldown_rows in sorted(move_rows.items()):
drilldown_run = drilldown_runs.get(main_row)
if drilldown_run is None or drilldown_run.frame.is_empty():
invalid[str(main_row)] = drilldown_rows
continue
drilldown_dicts = drilldown_run.frame.to_dicts()
for drilldown_row in drilldown_rows:
if drilldown_row < 1 or drilldown_row > len(drilldown_dicts):
invalid.setdefault(str(main_row), []).append(drilldown_row)
continue
filter_dict = _bridge_row_filter_dict(
drilldown_dicts[drilldown_row - 1],
bridge_dimensions,
names,
)
if not filter_dict:
invalid.setdefault(str(main_row), []).append(drilldown_row)
continue
slot = _next_insert_slot(insert_dict, main_row - 1)
insert_dict[slot] = filter_dict
inserted.setdefault(str(main_row), []).append(drilldown_row)
slot_map.setdefault(str(main_row), []).append(slot)
return insert_dict, {
"inserted": inserted,
"invalid": invalid,
"insert_slots": slot_map,
}
def _bounded_positive_int(value: Any, default: int, *, maximum: int) -> int:
"""Return a positive integer clamped to ``maximum``."""
try:
parsed = int(value)
except (TypeError, ValueError):
parsed = default
if parsed <= 0:
parsed = default
return min(parsed, maximum)
def _root_cause_sweep_values(options: dict[str, Any]) -> list[int]:
"""Return requested alternativeResult values for an automatic sweep."""
if not bool(options.get("root_cause_bridge_alternative_sweep", False)):
return []
start = _bounded_positive_int(
options.get("root_cause_bridge_alternative_sweep_start"), 1, maximum=10
)
end = _bounded_positive_int(
options.get("root_cause_bridge_alternative_sweep_end"), 10, maximum=10
)
if end < start:
start, end = end, start
return list(range(start, end + 1))
def _root_cause_auto_drilldown_mode(options: dict[str, Any]) -> str:
"""Return the normalized automatic drilldown mode."""
raw_value = str(options.get("root_cause_bridge_auto_drilldown") or "none")
mode = raw_value.strip().lower().replace("-", "_")
return mode if mode in AUTO_DRILLDOWN_MODES else "none"
def _root_cause_auto_drilldown_min_share(options: dict[str, Any]) -> float:
"""Return the minimum absolute-variance share for dominant-row drilldown."""
try:
value = float(options.get("root_cause_bridge_auto_drilldown_min_share", 0.75))
except (TypeError, ValueError):
value = 0.75
return min(max(value, 0.0), 1.0)
def _valid_requested_rows(
*,
selected_row_count: int,
rows: list[int],
) -> tuple[list[int], list[int]]:
"""Return valid and invalid 1-based selected sequence rows."""
valid: list[int] = []
invalid: list[int] = []
for row in rows:
if 1 <= row <= selected_row_count:
if row not in valid:
valid.append(row)
else:
invalid.append(row)
return valid, invalid
def _auto_drilldown_rows(
sequence: LegacyVariableBridgeSequence,
mode: str,
*,
min_share: float,
) -> list[int]:
"""Choose selected main rows for automatic legacy drilldown."""
frame = sequence.frame
if mode == "none" or frame.is_empty():
return []
if mode == "single_row":
return [1] if frame.height == 1 else []
if mode == "all_selected":
return list(range(1, frame.height + 1))
if mode != "dominant_row" or "variance_amount" not in frame.schema:
return []
ranked = frame.with_row_index("__row_number").with_columns(
pl.col("variance_amount").abs().alias("__abs_variance")
)
total_abs = ranked.select(pl.col("__abs_variance").sum()).item()
if total_abs is None or float(total_abs) <= 0:
return []
top_row = ranked.sort("__abs_variance", descending=True).row(0, named=True)
share = float(top_row["__abs_variance"]) / float(total_abs)
if share < min_share:
return []
return [int(top_row["__row_number"]) + 1]
def _run_drilldown_sequences(
context: _LegacyVariableBridgeContext,
main_sequence: LegacyVariableBridgeSequence,
requested_rows: list[int],
) -> tuple[dict[int, LegacyVariableBridgeSequence], str, dict[str, str]]:
"""Run legacy drilldowns for selected main sequence rows."""
names = context.names
if not requested_rows:
return {}, "not_requested", {}
if main_sequence.details_frame.is_empty():
return {}, "not_written_details_empty", {}
drilldown_runs: dict[int, LegacyVariableBridgeSequence] = {}
drilldown_row_status: dict[str, str] = {}
drilldown_status = "not_written_no_rows"
for main_row in requested_rows:
detail_frame = _details_for_main_row(
main_sequence.details_frame,
main_sequence.legacy_frame,
main_row,
names,
)
if detail_frame.is_empty():
drilldown_row_status[str(main_row)] = "not_written_no_detail_rows"
continue
drilldown_param = copy.deepcopy(context.param)
drilldown_param[names["alternativeResult"]] = 1
drilldown_run = _run_legacy_bridge_sequence(
context.imports,
detail_frame,
context.index_cols,
drilldown_param,
context.chart,
names["drilldownReportRunName"],
context.bridge_dimensions,
names,
)
drilldown_runs[main_row] = drilldown_run
drilldown_row_status[str(main_row)] = (
"written" if not drilldown_run.frame.is_empty() else "not_written_empty"
)
if drilldown_runs:
drilldown_status = "written"
return drilldown_runs, drilldown_status, drilldown_row_status
def _run_prepared_variable_bridge_alternative(
context: _LegacyVariableBridgeContext,
*,
options: dict[str, Any],
alternative_result: int,
move_rows: dict[int, list[int]],
manual_drilldown_rows: list[int] | None = None,
drilldown_all: bool | None = None,
auto_drilldown_mode: str = "none",
) -> LegacyVariableBridgeAlternativeRun:
"""Run one alternativeResult against a prepared legacy candidate universe."""
names = context.names
alternative_result = _bounded_positive_int(alternative_result, 1, maximum=10)
param = copy.deepcopy(context.param)
param[names["alternativeResult"]] = alternative_result
main_sequence = _run_legacy_bridge_sequence(
context.imports,
context.candidate_legacy_frame,
context.index_cols,
param,
context.chart,
names["mainReportRunName"],
context.bridge_dimensions,
names,
)
if drilldown_all is None:
drilldown_all = bool(options.get("root_cause_bridge_drilldown_all", False))
if manual_drilldown_rows is None:
requested_drilldown_rows, invalid_drilldown_rows = _requested_drilldown_rows(
selected_row_count=main_sequence.frame.height,
options=options,
move_rows=move_rows,
)
else:
requested_drilldown_rows, invalid_drilldown_rows = _valid_requested_rows(
selected_row_count=main_sequence.frame.height,
rows=manual_drilldown_rows,
)
for main_row in move_rows:
if main_row not in requested_drilldown_rows:
requested_drilldown_rows.append(main_row)
requested_drilldown_rows, invalid_from_move_rows = _valid_requested_rows(
selected_row_count=main_sequence.frame.height,
rows=requested_drilldown_rows,
)
invalid_drilldown_rows.extend(invalid_from_move_rows)
if drilldown_all:
requested_drilldown_rows = list(range(1, main_sequence.frame.height + 1))
invalid_drilldown_rows = []
auto_rows = _auto_drilldown_rows(
main_sequence,
auto_drilldown_mode,
min_share=_root_cause_auto_drilldown_min_share(options),
)
for row in auto_rows:
if row not in requested_drilldown_rows:
requested_drilldown_rows.append(row)
drilldown_runs, drilldown_status, drilldown_row_status = _run_drilldown_sequences(
context,
main_sequence,
requested_drilldown_rows,
)
insert_at_row_dict, move_rows_audit = _build_insert_at_row_dict(
move_rows=move_rows,
drilldown_runs=drilldown_runs,
bridge_dimensions=context.bridge_dimensions,
names=names,
)
moved_run: LegacyVariableBridgeSequence | None = None
if insert_at_row_dict:
moved_param = copy.deepcopy(context.param)
moved_param[names["alternativeResult"]] = alternative_result
moved_param[names["insertAtRowDict"]] = insert_at_row_dict
moved_run = _run_legacy_bridge_sequence(
context.imports,
context.candidate_legacy_frame,
context.index_cols,
moved_param,
context.chart,
names["moveRowReportRunName"],
context.bridge_dimensions,
names,
)
moved_rows_status = "written" if not moved_run.frame.is_empty() else "empty"
elif move_rows:
moved_rows_status = "not_written_no_insert_rows"
else:
moved_rows_status = "not_requested"
audit = {
"alternative_result": alternative_result,
"legacy_sequence_run": names["mainReportRunName"],
"row_count": main_sequence.frame.height,
"sequence_row_count": main_sequence.frame.height,
"selected_sequence_bridge_dimensions": main_sequence.audit[
"selected_sequence_bridge_dimensions"
],
"selected_sequence_unique_bridge_dimensions": main_sequence.audit[
"selected_sequence_unique_bridge_dimensions"
],
"selected_sequence_has_mixed_dimensions": main_sequence.audit[
"selected_sequence_has_mixed_dimensions"
],
"details_row_count": main_sequence.details_frame.height,
"snapshot_row_count": main_sequence.snapshot_frame.height,
"sequence_running_total": main_sequence.param.get(names["runningTotalName"]),
"sequence_rows_until_stop": main_sequence.param.get(
names["rowResultsUntilStop"]
),
"drilldown_requested_rows": requested_drilldown_rows,
"drilldown_invalid_rows": invalid_drilldown_rows,
"drilldown_all": drilldown_all,
"automatic_drilldown_mode": auto_drilldown_mode,
"automatic_drilldown_rows": auto_rows,
"drilldown_status": drilldown_status,
"drilldown_row_status": drilldown_row_status,
"drilldown_row_counts": {
str(row): run.frame.height for row, run in drilldown_runs.items()
},
"moved_rows_requested": {
str(row): selected for row, selected in sorted(move_rows.items())
},
"moved_rows_status": moved_rows_status,
"moved_rows_insert_at_row_dict": insert_at_row_dict,
"moved_rows_insert_audit": move_rows_audit,
"moved_rows_row_count": moved_run.frame.height if moved_run else 0,
}
return LegacyVariableBridgeAlternativeRun(
alternative_result=alternative_result,
sequence=main_sequence,
drilldown_runs=drilldown_runs,
moved_run=moved_run,
audit=audit,
)
def _prepare_legacy_variable_bridge_context(
df: pl.DataFrame,
recipe: dict[str, Any],
*,
variance_mode: str = "total_variance",
) -> _LegacyVariableBridgeContext:
"""Build the candidate universe once for root-cause alternatives."""
imports = _legacy_imports()
names = imports["get_naming_params"]()
config = imports["get_config_params"]()
report_dimensions = list(recipe["mappings"].get("dimensions") or [])
requested_calculation_grain = list(
recipe["mappings"].get("calculation_grain") or []
)
bridge_dimensions = _leaf_dimensions(recipe, report_dimensions)
param, chart = _legacy_param_and_chart(recipe, bridge_dimensions, names)
chart[names["processingChoice"]] = names["runVariableDimensionalAnalysis"]
if variance_mode == "component_variance":
chart[names["varianceAggregation"]] = names["mixAndUnitsAggregation"]
chart[names["showInitialAndFinalValues"]] = False
else:
chart[names["varianceAggregation"]] = names["totalVarianceAggregation"]
chart[names["showInitialAndFinalValues"]] = True
chart[names["mainDimension"]] = bridge_dimensions
param[names["parameterSetting"]] = names["largestCombinationOption"]
param = imports["set_parameters_on_scenario_option"](param)
param[names["aggregationChoice"]] = config[names["aggregationChoiceArray"]][0]
canonical, value_columns = _canonical_legacy_input(
df, recipe, names, bridge_dimensions
)
param = _add_variable_bridge_defaults(
param,
canonical,
bridge_dimensions,
names,
config,
)
period_name = names["periodName"]
index_columns = [*bridge_dimensions, period_name]
empty_lazy = pl.DataFrame().lazy()
df_dict, index_cols, _original_value_cols, param, chart = imports[
"process_and_prepare_multidimensional_data"
](
param,
{},
canonical.lazy(),
empty_lazy,
canonical.lazy(),
canonical.lazy(),
empty_lazy,
index_columns,
value_columns,
chart,
[],
value_columns.copy(),
{},
{},
{},
{},
False,
)
candidate_legacy_frame = _collect_if_lazy(
df_dict.get(names["dfName"], pl.DataFrame())
)
candidate_normalized = _normalize_legacy_bridge_output(
candidate_legacy_frame,
bridge_dimensions,
names,
has_units=bool(recipe["mappings"].get("units_column")),
)
return _LegacyVariableBridgeContext(
imports=imports,
names=names,
config=config,
report_dimensions=report_dimensions,
requested_calculation_grain=requested_calculation_grain,
bridge_dimensions=bridge_dimensions,
param=param,
chart=chart,
index_cols=index_cols,
candidate_frame=candidate_normalized,
candidate_legacy_frame=candidate_legacy_frame,
)
def run_legacy_variable_dimension_bridge(
df: pl.DataFrame,
recipe: dict[str, Any],
) -> LegacyVariableBridgeRun:
"""Run the legacy variable-dimension bridge calculation."""
report_dimensions = list(recipe["mappings"].get("dimensions") or [])
requested_calculation_grain = list(
recipe["mappings"].get("calculation_grain") or []
)
bridge_dimensions = _leaf_dimensions(recipe, report_dimensions)
if len(bridge_dimensions) < 2:
empty = pl.DataFrame()
return LegacyVariableBridgeRun(
frame=empty,
legacy_frame=empty,
details_frame=empty,
snapshot_frame=empty,
candidate_frame=empty,
candidate_legacy_frame=empty,
drilldown_runs={},
moved_run=None,
sweep_runs={},
param={},
chart={},
bridge_dimensions=bridge_dimensions,
audit={
"enabled": False,
"reason": "requires at least two dimensions",
"report_dimensions": report_dimensions,
"calculation_grain": bridge_dimensions,
**_bridge_dimension_audit(
empty,
report_dimensions,
requested_calculation_grain,
bridge_dimensions,
),
},
)
options = recipe.get("options") or {}
alternative_result = _bounded_positive_int(
options.get("root_cause_bridge_alternative_result"), 1, maximum=10
)
context = _prepare_legacy_variable_bridge_context(
df,
recipe,
variance_mode="total_variance",
)
names = context.names
move_rows = _root_cause_move_rows(options)
main_run = _run_prepared_variable_bridge_alternative(
context,
options=options,
alternative_result=alternative_result,
move_rows=move_rows,
)
sweep_values = _root_cause_sweep_values(options)
auto_drilldown_mode = _root_cause_auto_drilldown_mode(options)
sweep_runs: dict[int, LegacyVariableBridgeAlternativeRun] = {}
for sweep_alternative in sweep_values:
sweep_runs[sweep_alternative] = _run_prepared_variable_bridge_alternative(
context,
options=options,
alternative_result=sweep_alternative,
move_rows={},
manual_drilldown_rows=[],
drilldown_all=False,
auto_drilldown_mode=auto_drilldown_mode,
)
dimension_audit = _bridge_dimension_audit(
context.candidate_frame,
context.report_dimensions,
context.requested_calculation_grain,
context.bridge_dimensions,
)
audit = {
"enabled": True,
"vendor_root": str(context.imports["vendor_root"]),
"variable_bridge_source": (
"modules.variance.index_handling."
"process_and_prepare_multidimensional_data"
),
"variable_bridge_combination": (
"modules.variance.variance_orchestrator.output_df_with_combinations"
),
"variable_bridge_subtraction": (
"modules.variance.variance_orchestrator."
"delete_duplicate_nodes_and_melt_result"
),
"variable_bridge_filter": (
"modules.variance.variance_utils.filter_by_number_of_nodes"
),
"variable_bridge_sequence": (
"modules.variance.variance_decomposition.process_node_combinations"
),
"variable_bridge_drilldown_sequence": (
"modules.variance.variance_decomposition.process_node_combinations"
),
"variable_bridge_move_rows": (
"modules.variance.variance_decomposition.insert_drilldown_row_in_main_report"
),
"legacy_processing_choice": names["runVariableDimensionalAnalysis"],
"legacy_variance_aggregation": context.chart[names["varianceAggregation"]],
"root_cause_variance_mode": "total_variance",
"plugin_variance_aggregation": "total_variance",
"legacy_sequence_run": names["mainReportRunName"],
"report_dimensions": report_dimensions,
"calculation_grain": bridge_dimensions,
**dimension_audit,
"legacy_periods": context.config["periodsArray"],
"alternative_result": alternative_result,
"candidate_row_count": context.candidate_frame.height,
"row_count": main_run.sequence.frame.height,
"sequence_row_count": main_run.sequence.frame.height,
"selected_sequence_bridge_dimensions": main_run.sequence.audit[
"selected_sequence_bridge_dimensions"
],
"selected_sequence_unique_bridge_dimensions": main_run.sequence.audit[
"selected_sequence_unique_bridge_dimensions"
],
"selected_sequence_has_mixed_dimensions": main_run.sequence.audit[
"selected_sequence_has_mixed_dimensions"
],
"details_row_count": main_run.sequence.details_frame.height,
"snapshot_row_count": main_run.sequence.snapshot_frame.height,
"sequence_running_total": main_run.sequence.param.get(
names["runningTotalName"]
),
"sequence_rows_until_stop": main_run.sequence.param.get(
names["rowResultsUntilStop"]
),
"drilldown_requested_rows": main_run.audit["drilldown_requested_rows"],
"drilldown_invalid_rows": main_run.audit["drilldown_invalid_rows"],
"drilldown_all": main_run.audit["drilldown_all"],
"drilldown_status": main_run.audit["drilldown_status"],
"drilldown_row_status": main_run.audit["drilldown_row_status"],
"drilldown_row_counts": main_run.audit["drilldown_row_counts"],
"moved_rows_requested": main_run.audit["moved_rows_requested"],
"moved_rows_status": main_run.audit["moved_rows_status"],
"moved_rows_insert_at_row_dict": main_run.audit[
"moved_rows_insert_at_row_dict"
],
"moved_rows_insert_audit": main_run.audit["moved_rows_insert_audit"],
"moved_rows_row_count": main_run.audit["moved_rows_row_count"],
"alternative_sweep_enabled": bool(sweep_values),
"alternative_sweep_values": sweep_values,
"alternative_sweep_auto_drilldown": auto_drilldown_mode,
"alternative_sweep": {
str(alternative): run.audit
for alternative, run in sorted(sweep_runs.items())
},
}
return LegacyVariableBridgeRun(
frame=main_run.sequence.frame,
legacy_frame=main_run.sequence.legacy_frame,
details_frame=main_run.sequence.details_frame,
snapshot_frame=main_run.sequence.snapshot_frame,
candidate_frame=context.candidate_frame,
candidate_legacy_frame=context.candidate_legacy_frame,
drilldown_runs=main_run.drilldown_runs,
moved_run=main_run.moved_run,
sweep_runs=sweep_runs,
param=main_run.sequence.param,
chart=context.chart,
bridge_dimensions=context.bridge_dimensions,
audit=audit,
)
def run_legacy_variable_dimension_component_bridge(
df: pl.DataFrame,
recipe: dict[str, Any],
) -> LegacyVariableBridgeRun:
"""Run the legacy component-by-dimension root-cause calculation."""
report_dimensions = list(recipe["mappings"].get("dimensions") or [])
requested_calculation_grain = list(
recipe["mappings"].get("calculation_grain") or []
)
bridge_dimensions = _leaf_dimensions(recipe, report_dimensions)
empty = pl.DataFrame()
if len(bridge_dimensions) < 2:
return LegacyVariableBridgeRun(
frame=empty,
legacy_frame=empty,
details_frame=empty,
snapshot_frame=empty,
candidate_frame=empty,
candidate_legacy_frame=empty,
drilldown_runs={},
moved_run=None,
sweep_runs={},
param={},
chart={},
bridge_dimensions=bridge_dimensions,
audit={
"enabled": False,
"reason": "requires at least two dimensions",
"root_cause_variance_mode": "component_variance",
"report_dimensions": report_dimensions,
"calculation_grain": bridge_dimensions,
**_bridge_dimension_audit(
empty,
report_dimensions,
requested_calculation_grain,
bridge_dimensions,
),
},
)
if not recipe["mappings"].get("units_column"):
return LegacyVariableBridgeRun(
frame=empty,
legacy_frame=empty,
details_frame=empty,
snapshot_frame=empty,
candidate_frame=empty,
candidate_legacy_frame=empty,
drilldown_runs={},
moved_run=None,
sweep_runs={},
param={},
chart={},
bridge_dimensions=bridge_dimensions,
audit={
"enabled": False,
"reason": "requires units to calculate price/unit/mix components",
"root_cause_variance_mode": "component_variance",
"report_dimensions": report_dimensions,
"calculation_grain": bridge_dimensions,
**_bridge_dimension_audit(
empty,
report_dimensions,
requested_calculation_grain,
bridge_dimensions,
),
},
)
context = _prepare_legacy_variable_bridge_context(
df,
recipe,
variance_mode="component_variance",
)
names = context.names
options = recipe.get("options") or {}
alternative_result = _bounded_positive_int(
options.get("root_cause_component_bridge_alternative_result"),
1,
maximum=10,
)
main_run = _run_prepared_variable_bridge_alternative(
context,
options=options,
alternative_result=alternative_result,
move_rows={},
manual_drilldown_rows=[],
drilldown_all=False,
auto_drilldown_mode="none",
)
dimension_audit = _bridge_dimension_audit(
context.candidate_frame,
context.report_dimensions,
context.requested_calculation_grain,
context.bridge_dimensions,
)
audit = {
"enabled": True,
"vendor_root": str(context.imports["vendor_root"]),
"variable_bridge_source": (
"modules.variance.index_handling."
"process_and_prepare_multidimensional_data"
),
"variable_bridge_sequence": (
"modules.variance.variance_decomposition.process_node_combinations"
),
"legacy_processing_choice": names["runVariableDimensionalAnalysis"],
"legacy_variance_aggregation": context.chart[names["varianceAggregation"]],
"root_cause_variance_mode": "component_variance",
"plugin_variance_aggregation": "component_variance",
"legacy_sequence_run": names["mainReportRunName"],
"report_dimensions": report_dimensions,
"calculation_grain": bridge_dimensions,
**dimension_audit,
"legacy_periods": context.config["periodsArray"],
"alternative_result": alternative_result,
"candidate_row_count": context.candidate_frame.height,
"row_count": main_run.sequence.frame.height,
"sequence_row_count": main_run.sequence.frame.height,
"selected_sequence_bridge_dimensions": main_run.sequence.audit[
"selected_sequence_bridge_dimensions"
],
"selected_sequence_unique_bridge_dimensions": main_run.sequence.audit[
"selected_sequence_unique_bridge_dimensions"
],
"selected_sequence_has_mixed_dimensions": main_run.sequence.audit[
"selected_sequence_has_mixed_dimensions"
],
"details_row_count": main_run.sequence.details_frame.height,
"snapshot_row_count": main_run.sequence.snapshot_frame.height,
"sequence_running_total": main_run.sequence.param.get(
names["runningTotalName"]
),
"sequence_rows_until_stop": main_run.sequence.param.get(
names["rowResultsUntilStop"]
),
"drilldown_requested_rows": [],
"drilldown_invalid_rows": [],
"drilldown_all": False,
"drilldown_status": "not_requested",
"drilldown_row_status": {},
"drilldown_row_counts": {},
"moved_rows_requested": {},
"moved_rows_status": "not_requested",
"moved_rows_insert_at_row_dict": {},
"moved_rows_insert_audit": {"inserted": {}, "invalid": {}, "insert_slots": {}},
"moved_rows_row_count": 0,
"alternative_sweep_enabled": False,
"alternative_sweep_values": [],
}
return LegacyVariableBridgeRun(
frame=main_run.sequence.frame,
legacy_frame=main_run.sequence.legacy_frame,
details_frame=main_run.sequence.details_frame,
snapshot_frame=main_run.sequence.snapshot_frame,
candidate_frame=context.candidate_frame,
candidate_legacy_frame=context.candidate_legacy_frame,
drilldown_runs={},
moved_run=None,
sweep_runs={},
param=main_run.sequence.param,
chart=context.chart,
bridge_dimensions=context.bridge_dimensions,
audit=audit,
)
def run_legacy_variance(
df: pl.DataFrame,
recipe: dict[str, Any],
report_dimensions: list[str],
) -> LegacyVarianceRun:
"""Run legacy period splitting, price-volume-mix calculation, and mix calculation."""
imports = _legacy_imports()
names = imports["get_naming_params"]()
param, chart = _legacy_param_and_chart(recipe, report_dimensions, names)
leaf_dimensions = _leaf_dimensions(recipe, report_dimensions)
canonical, value_columns = _canonical_legacy_input(
df, recipe, names, leaf_dimensions
)
period_name = names["periodName"]
index_columns = [*leaf_dimensions, period_name]
grouped, param = imports["group_by_df_on_index_cols"](
canonical.lazy(),
index_columns.copy(),
value_columns,
"sum",
param,
False,
)
grouped, param = imports["rename_periods"](grouped, param, chart, False)
grouped = grouped.sort(index_columns)
grouped, param, _columns = imports["calculate_unit_and_volume_price"](
grouped, param, []
)
grouped, param = imports["calculate_discount_per_units_and_volume"](grouped, param)
grouped, param = imports["calculate_cogs_per_units_and_volume"](grouped, param)
pivoted = imports["pivot_lazy_periods"](
grouped,
index_cols=index_columns.copy(),
agg_func="sum",
).collect()
base_legacy_frame, param = imports["calculate_variance"](pivoted, param, chart)
period_totals, param = _collapse_legacy_rows(
base_legacy_frame,
report_dimensions,
param,
imports["recalculate_price"],
)
legacy_frame = base_legacy_frame
if recipe["mappings"].get("units_column"):
legacy_frame = imports["calculate_sales_mix_variance"](
base_legacy_frame, param, chart, leaf_dimensions
)
legacy_frame, param = _collapse_legacy_rows(
legacy_frame,
report_dimensions,
param,
imports["recalculate_price"],
)
legacy_frame = _merge_missing_legacy_columns(
legacy_frame,
period_totals,
report_dimensions,
)
normalized = _normalize_legacy_output(legacy_frame, report_dimensions, names)
audit = {
"vendor_root": str(imports["vendor_root"]),
"period_split": "modules.variance.variance_utils.rename_periods",
"period_pivot": "modules.utilities.helpers.pivot_lazy_periods",
"variance_formula": "modules.variance.variance_formulas.calculate_variance",
"mix_formula": (
"modules.variance.variance_formulas.calculate_sales_mix_variance"
if recipe["mappings"].get("units_column")
else None
),
"report_dimensions": report_dimensions or ["segment"],
"calculation_grain": leaf_dimensions,
"legacy_periods": imports["get_config_params"]()["periodsArray"],
}
return LegacyVarianceRun(frame=normalized, legacy_frame=legacy_frame, audit=audit)
SHA-256: d12efcce5b761365324103f2e076fac0cccb8d33d39a17b09efeb6a97d1b6aee