ADR 003: Unified StratifiedResultMixin and Elimination of Dynamic getattr¶
- Status: Accepted
- Date: 2026-10-14
Context¶
Previously, Aggregator and BaseEstimator duplicated nearly 150 lines of metadata properties and data-slicing methods:
- Both defined target_col, target_name, target_title, strata_cols, strata_names, strata_titles, n_strata, is_stratified, is_single_stratum, single_stratum_col, single_stratum_title, infer_single_stratum_value, filter(), and split().
- Despite self.strata_ and self.target_ being known domain objects, Aggregator used defensive getattr(s, "title", s.name.replace("_", " ").title()) calls, while BaseEstimator downgraded strata_ and target_ to raw strings (list[str] and str | None) and re-implemented string formatting from scratch.
Decision¶
- Extract
StratifiedResultMixininseroepi.models: - Inherited by both
AggregatorandBaseEstimator. - Standardizes fitted metadata attributes across both classes:
is_fitted_: bool = Falsevariables_: dict[str, Variable]target_: Variablestrata_: tuple[Variable, ...]adjust_for_: Variable | Noneis_compositional_: boolis_padded_: bool
-
Defines an abstract/overridable
_frameproperty (self.data_onAggregator,self.estimates_onBaseEstimator) so.filter(),.split(), and.infer_single_stratum_value()are implemented once. -
Direct Typed Property Access (Zero
getattr): target_col -> str:return self.target_.columntarget_title -> str:return self.target_.titlestrata_cols -> tuple[str, ...]:return tuple(s.column for s in self.strata_)strata_titles -> tuple[str, ...]:return tuple(s.title for s in self.strata_)adjust_for_col -> str | None:return self.adjust_for_.column if self.adjust_for_ is not None else Noneadjust_for_title -> str | None:return self.adjust_for_.title if self.adjust_for_ is not None else None- Delete
target_name,strata_names, andadjust_for_name.
Consequences¶
- Positive: Shrinks
src/seroepi/aggregate.pyandsrc/seroepi/estimators/base.pysignificantly by consolidating all shared metadata,.var(),.filter(), and.split()logic in one place. - Positive: Eliminates all
getattr()duck-typing and.replace("_", " ").title()string manipulation outsidevariables.py. - Positive: Strict static type checking (
ty check) is enforced acrosstarget_,strata_, andadjust_for_withouttyping.cast().