Skip to content

feat(v4): deprecate the 8 estimator wrappers + alias diet via module __getattr__; SCM alias (2(d) PR-A, M-070..M-077/M-132..M-135/M-062) - #752

Merged
igerber merged 1 commit into
mainfrom
feat/v4-2d-wrappers-alias-diet
Aug 7, 2026
Merged

feat(v4): deprecate the 8 estimator wrappers + alias diet via module __getattr__; SCM alias (2(d) PR-A, M-070..M-077/M-132..M-135/M-062)#752
igerber merged 1 commit into
mainfrom
feat/v4-2d-wrappers-alias-diet

Conversation

@igerber

@igerber igerber commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

  • Deprecate the 8 module-level estimator convenience wrappers (imputation_did, two_stage_did, stacked_did, trop, synthetic_control, triple_difference, bacon_decompose, chaisemartin_dhaultfoeuille) for 3.9 → removed in 4.0 (ledger rows [M-070]..[M-077] → shimmed, phase 5): every call emits a FutureWarning naming the class successor on one uniform template (diagnostic wording for Bacon — BaconDecompositionResults subclasses the Diagnostic marker), and each docstring gains a deprecation note rendered by the kept autofunction pages. Wrappers stay pure construct+fit relays — bit-exact equivalence vs the class path is pinned across the full inference quintet at zero tolerance (assert_allclose(rtol=0, atol=0, equal_nan=True); Bacon compares an enumerated diagnostic field list + the comparisons payload) in the new tests/test_v4_wrapper_shims.py.
  • Alias diet ([M-132]..[M-134] via the new mechanism row [M-135] → done): CDiD/Gardner/Stacked leave module globals (gone from dir()/vars() and static autocomplete) but stay importable and in __all__ through 3.9, served by a new PEP 562 module __getattr__ that warns and returns ContinuousDiD/TwoStageDiD/StackedDiD. The package import protocol resolves each missing __all__ name twice, so a star-import records six warnings for the three aliases — the tests assert the message set, covering both access routes.
  • New introduce-only alias SCM = SyntheticControl ([M-062] → done, silent).
  • Sentinel forwarding unchanged: a plain wrapper call fires exactly ONE warning (the wrapper deprecation, never the fit-time aggregate one); four plain-call no-warn test pins flipped BY DESIGN. DiagnosticReport's internal Bacon runner migrated to the class (weights= → ctor, survey_design= → fit; the two mock-based threading tests re-pointed accordingly).
  • Emitted-guidance register: practitioner recommendation rosters use full class names (e.g. "CallawaySantAnna, SunAbraham, or TwoStageDiD"), practitioner_next_steps()'s TwoStageDiD display label drops the dying "(Gardner)" parenthetical (kept-alias parentheticals stay), and the report Bacon caveats name classes.
  • Ledger/docs: [M-021]/[M-022] notes + their REGISTRY twins amended (plain wrapper calls now warn); docs/v4-design.md records the 2(d) two-PR split (§9) and PR-B's locked [M-081]/[M-096] implementation decisions (§7); guides annotate the dying **Alias:** lines and drop them from the use-this roster; docs/api/estimators.rst carries the RST deprecation note; three api-page convenience blocks and four tutorials (02/08/09/10) migrated to the class quick-form.

Methodology references (required if estimator / math changes)

  • Method name(s): N/A — no methodology changes. Estimator mathematics, weights, variance estimators, and defaults are untouched; the wrappers were pure construct+fit relays and their bit-exact equivalence to the class path is pinned per wrapper.
  • Paper / source link(s): N/A
  • Any intentional deviations from the source (and why): None

Validation

  • Tests added/updated: tests/test_v4_wrapper_shims.py (new — warning pins on re.escaped full messages, zero-tolerance quintet equivalence gate, sentinel-forwarding pins), tests/test_aliases.py (rewritten — dual-route warn pins, set-wise star-import, dir()/vars() absence, SCM), ~140 wrapper call sites migrated to the class API via suite-local helpers (test_methodology_synthetic_control.py, test_bacon.py, test_methodology_bacon.py, test_trop.py, report/fixture suites), ~40 wrapper-specific keeps updated for the new warning, 6 forwarded-shim pins updated for dual warnings, per-site emitted-guidance pins in test_practitioner.py/test_business_report.py/test_diagnostic_report.py, matrix/naming-guard green (M-070..M-077 flips, M-062/M-135 done).
  • Backtest / simulation / notebook evidence (if applicable): tutorials 02/08/09/10 re-executed via nbmake against the new code (numbers unchanged — the wrappers were pure relays); Sphinx -W build + the docs CI's four post-build HTML guards pass.

Security / privacy

  • Confirm no secrets/PII in this PR: Yes

@igerber

igerber commented Aug 6, 2026

Copy link
Copy Markdown
Owner Author

/ai-review

…__getattr__; SCM alias (2(d) PR-A, M-070..M-077/M-132..M-135/M-062)

The eight module-level convenience wrappers (imputation_did,
two_stage_did, stacked_did, trop, synthetic_control, triple_difference,
bacon_decompose, chaisemartin_dhaultfoeuille) deprecate in 3.9 and are
removed in 4.0: every call emits a FutureWarning naming the class
successor on one uniform template (Bacon says "construct the
DIAGNOSTIC" - BaconDecompositionResults subclasses the Diagnostic
marker), and each docstring gains the deprecation note the kept
autofunction pages render. The wrappers stay pure construct+fit relays:
bit-exact equivalence vs the class path is pinned across the full
inference quintet at zero tolerance (Bacon: an enumerated diagnostic
field list + the comparisons payload), and the aggregate/balance_e
sentinel forwarding is unchanged - a plain wrapper call fires exactly
ONE warning; four plain-call no-warn pins flipped BY DESIGN.
DiagnosticReport's internal Bacon runner migrated to the class
(weights= to the ctor, survey_design= on fit; the two mock-based
threading tests re-pointed to the class split); emitted guidance in
twfe/visualization/practitioner rewords to class form.

ALIAS DIET (M-132..M-134 via mechanism row M-135): CDiD / Gardner /
Stacked leave module globals - gone from dir()/vars() and static
autocomplete - but stay importable and in __all__ through 3.9, served
by a new PEP 562 module __getattr__ that warns and returns
ContinuousDiD / TwoStageDiD / StackedDiD. The package import protocol
resolves each missing __all__ name twice, so a star-import records six
warnings for the three aliases; tests assert the message SET (both
access routes covered). NEW: SCM = SyntheticControl (M-062,
introduce-only, silent). Emitted-guidance register: the practitioner
recommendation rosters use full class names ("CallawaySantAnna,
SunAbraham, or TwoStageDiD"), the TwoStageDiD display label drops its
dying "(Gardner)" parenthetical (kept-alias parentheticals stay), and
the report Bacon caveats name classes.

Ledger: M-070..M-077 shimmed (phase 5, test_ref
tests/test_v4_wrapper_shims.py, api-page code_refs); M-062 + M-135
done; M-132..M-134 notes annotated; M-021/M-022 + their REGISTRY twins
amended (plain wrapper calls now warn); v4-design records the 2(d)
two-PR split in section 9 and PR-B's locked M-081/M-096 implementation
decisions in section 7. Tests: new 30-test shim suite; ~140 wrapper
call sites migrated to the class API via suite-local helpers; ~40
wrapper-specific keeps updated for the new warning; alias suite
rewritten (dual-route pins, set-wise star-import). Docs: guides
annotate the dying Alias lines and drop them from the use-this roster;
estimators.rst carries the RST deprecation note; three api-page
convenience blocks and four tutorials migrated to the class quick-form
(notebooks re-executed; numbers unchanged - the wrappers were pure
relays).
@igerber
igerber force-pushed the feat/v4-2d-wrappers-alias-diet branch from 6840083 to d8c8e04 Compare August 7, 2026 00:03
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

🔁 AI review rerun (requested by @igerber)

Head SHA: d8c8e04e843fb8c00fcb4e1492f26fe6395f3d1a


Overall assessment: ✅ Looks good

Executive summary

  • No estimator math, weighting, variance, SE, assumptions, or defaults changed.
  • Bacon report migration preserves weights="exact" and survey-design forwarding.
  • Wrapper/class equivalence and NaN inference contracts receive strong regression coverage.
  • No unmitigated P0/P1 findings.

Methodology

Finding — P3 informational

  • Impact: The eight wrappers are API shims only. The Bacon report’s class call at diff_diff/diagnostic_report.py:L2048-L2060 is equivalent to the deprecated wrapper at diff_diff/bacon.py:L1400-L1407. This agrees with the Registry and Reporting notes; no methodological deviation exists.
  • Concrete fix: None.

Code Quality

No findings. Warning messages, sentinel forwarding, and PEP 562 alias behavior are consistently implemented and tested.

Performance

No findings. Only negligible warning and attribute-lookup overhead was added.

Maintainability

No findings. Deprecated aliases are centralized in _DEPRECATED_ALIASES at diff_diff/__init__.py:L337-L361.

Tech Debt

No findings. Deprecation work is recorded in docs/v4-deprecations.yaml; no silent correctness debt was introduced.

Security

No findings. No secrets, unsafe runtime evaluation, or new external-input handling was introduced.

Documentation/Tests

Finding — P3 informational

  • Impact: Coverage includes bit-exact wrapper/class comparisons, complete NaN inference checks, sentinel propagation, alias imports, and star-import behavior at tests/test_v4_wrapper_shims.py:L235-L390.
  • Concrete fix: None.

Runtime tests could not be executed because this environment lacks pytest and numpy; static parsing succeeded for all changed Python files.

@igerber igerber added the ready-for-ci Triggers CI test workflows label Aug 7, 2026
@igerber
igerber merged commit 6554a93 into main Aug 7, 2026
39 of 40 checks passed
@igerber
igerber deleted the feat/v4-2d-wrappers-alias-diet branch August 7, 2026 09:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-ci Triggers CI test workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant