refactor(budget-optimizer): collapse default_constraints into constraints#2570
refactor(budget-optimizer): collapse default_constraints into constraints#2570anevolbap wants to merge 6 commits into
Conversation
…ints Drop default_constraints and rename custom_constraints to constraints on BudgetOptimizer. Empty constraints auto-adds the default sum constraint; non-empty means the caller is in charge. Pass build_default_sum_constraint() explicitly to keep the default alongside customs. Old kwargs stay as deprecated aliases that warn and preserve current behavior for one release. On MMM.optimize_budget, default_constraints is now bool | None and only triggers the legacy path when explicitly set. Closes pymc-labs#1416.
93540f3 to
58f539c
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2570 +/- ##
==========================================
+ Coverage 93.89% 93.91% +0.01%
==========================================
Files 92 92
Lines 14062 14091 +29
==========================================
+ Hits 13204 13234 +30
+ Misses 858 857 -1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
… path Add tests for the two uncovered branches of the legacy translation in BudgetOptimizer._migrate_legacy_constraint_kwargs and for the legacy forwarding path in MMM.optimize_budget. Also pin the deprecation/removal versions in the warning message and docstrings to match the project convention (deprecated in 0.20.0, removed in 0.21.0).
…, deprecate set_constraints default kwarg The "Using default equality constraint" UserWarning fired on the documented happy path (empty constraints auto-add the default sum), turning it into noise. Drop it and clean up the 11 test assertion sites. The new contract is in the docstring instead. Also: deprecate the `default` kwarg of `set_constraints`, since it is now redundant under the new contract. Preserve the legacy strict behaviour for `default_constraints=False` with empty custom_constraints by raising a ValueError in the migration shim instead of silently auto-adding the default. Add tests for: the deprecated `set_constraints(default=...)` kwarg, the strict-no-constraint edge case, and Constraint round-trip through the legacy migrator.
…pe in docstring Add an inline comment in the migration validator explaining why the conflict path raises TypeError (re-raised as-is by Pydantic) while the edge case raises ValueError (wrapped into ValidationError, which is itself a ValueError so callers are unaffected). Also fix the docstring type for `default_constraints` on MMM.optimize_budget from `bool, optional` to `bool or None, optional` to match the actual annotation.
anevolbap
left a comment
There was a problem hiding this comment.
Adding a few inline notes to ease review.
| _constraints: dict = PrivateAttr() | ||
| _compiled_constraints: list[dict] = PrivateAttr() | ||
|
|
||
| @model_validator(mode="before") |
There was a problem hiding this comment.
Pydantic v2 idiom for renaming a Pydantic field at construction time. Field(deprecated=...) only fires on attribute access, not when kwargs are passed.
| # value error. | ||
| raise TypeError( | ||
| "Pass either `constraints` or the deprecated " | ||
| "`custom_constraints`/`default_constraints`, not both." |
There was a problem hiding this comment.
The last branch (empty custom_constraints with default_constraints=False) preserves the pre-PR error instead of silently auto-adding the default.
| ) | ||
| self.set_constraints(constraints=self.constraints) | ||
|
|
||
| def set_constraints(self, constraints, default=None) -> None: |
There was a problem hiding this comment.
default is reachable only from internal callers after this PR. Deprecating it now keeps the removal in the same cycle.
| model=self, | ||
| compile_kwargs=self.compile_kwargs, | ||
| ) | ||
| if default_constraints is None: |
There was a problem hiding this comment.
Two branches so the DeprecationWarning has one source of truth (BudgetOptimizer's validator).
Closes #1416. See the issue thread for design discussion. Notebook updates land in a follow-up PR.
Summary
custom_constraintstoconstraintsonBudgetOptimizer.default_constraintsfield. Emptyconstraintsauto-adds the default sum constraint; non-empty means the caller is in charge. Passbuild_default_sum_constraint()explicitly to keep the default alongside customs.MMM.optimize_budget:default_constraints: bool | None = None. Legacy path only runs when explicitly passed.UserWarning("Using default equality constraint"). It fired on the documented happy path under the new contract.defaultkwarg ofset_constraints(in-scope cleanup).default_constraints=Falsewith emptycustom_constraintsstill raises.Test plan
tests/mmm/test_budget_optimizer.py(29 pass, 8 new)tests/mmm/test_budget_optimizer_mmm.py+tests/mmm/test_cost_per_unit.py(78 pass, 1 new)