You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Audit-round polish: 5 real bugs found in the v0.7.1 work, all fixed
Full audit of the 17 commits landed today surfaced five genuine issues
plus a dozen purely cosmetic ones. This commit fixes the real five
and adds targeted regression tests for each.
1. `_df_to_booktabs` LaTeX escape was non-idempotent.
Old code replaced `\` with `\textbackslash{}` first, then replaced
`{` → `\{` and `}` → `\}` in a second pass — which re-escaped the
braces just inserted, producing `\textbackslash\{\}` instead of the
correct `\textbackslash{}`. Same failure mode for `~` and `^`.
Fix: single-pass `re.sub` with a lookup table so each character is
escaped exactly once.
(Latent in the DiD report path — our tables never carried
backslashes — but would bite any user passing string labels.)
2. `cs_report(save_to='~/study/cs_v1')` didn't expand `~`.
`os.path.dirname('~/study/cs_v1')` returns `"~/study"`, so the
pre-fix code created a literal `./~/study` directory. Fix:
`os.path.expanduser()` before anything else.
3. `_save_report_bundle` forced `matplotlib.use('Agg')` unconditionally,
which prints a warning when pyplot is already imported (common in
Jupyter). Fix: only switch backend if pyplot hasn't been loaded
yet; otherwise honour whatever backend the user had.
4. `bjs_pretrend_joint` swallowed `except Exception` silently.
If `did_imputation` had a real bug, users would just see
"not enough reps succeeded" with no clue why. Fix: narrow to
`(ValueError, RuntimeError, LinAlgError)` for expected
pathological resamples; track the last unexpected exception and
include its type + message in the failure.
5. `sp.did()` silently ignored `aggregation=`, `panel=False`, and
`anticipation=` when `method` resolved to anything other than CS.
Fix: (a) auto-upgrade `method='auto'` → `'callaway_santanna'`
when `aggregation` is supplied with an `id`; (b) raise
`ValueError` if any CS-only argument is paired with a non-CS
`method`.
Regression tests (4 new):
- LaTeX backslash round-trip (brace mangling guard)
- `save_to` expands `~` to `$HOME`
- `sp.did(method='2x2', aggregation='dynamic')` raises
- `sp.did(method='2x2', anticipation=1)` raises
Full DiD suite: 165/165 (was 161).
Also noted but left alone (cosmetic / not correctness):
- SA's `(g_val, e) in {m for m in interact_meta}` builds a
throwaway set comprehension; `in interact_meta` would suffice.
Performance only matters on huge event windows.
- SA's `XtX + 1e-10 * I` ridge term slightly biases β̂ in
well-conditioned cases (~1 ppm); matches common practice.
- `_two_way_demean(x)` calls `x.astype(float).copy()` — `.copy()`
is redundant once `.astype()` already returns a fresh array.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0 commit comments