Summary
philanthropy/preprocessing/_encounter_recency.py is at 82% branch
coverage, the lowest of any file in the risk tier make riskcov enforces at
a 93% floor — this file alone is dragging that subtree's average down. Unlike
the other coverage-gap issues in this repo, which name one or two specific
guards, this one is a cluster spanning both fit and transform on
EncounterRecencyTransformer, plus its private helpers. Filing it as one
issue rather than several because the branches share a theme (timezone- and
NaN-handling edge cases) and a contributor working through them will end up
reading the whole fit/transform pair anyway.
Untested regions, grouped by what triggers them (confirm current line numbers
with the coverage command below — they will drift as other work touches this
file):
_parse_dates's tz-localise fallback. parsed.dt.tz_convert(self.timezone)
is wrapped in try/except Exception, falling back to
parsed.dt.tz_localize(self.timezone). No test parses a tz-naive series
through a timezone-configured transformer, so the fallback never runs.
_compute_recency_features's tz-mismatch branches. The three-way branch
comparing dates.dt.tz against ref.tzinfo (tz-aware dates vs tz-naive
reference, and the reverse) — only the "both match" case is exercised today.
fit's reference-date inference paths. Both UserWarning branches —
"no parseable dates found in training data" and "X is not a DataFrame" —
defaulting reference_date_ to today.
transform's ndarray-fallback and missing-date-column paths. The
branch that rebuilds a DataFrame from feature_names_in_ when X isn't
already one, the "cannot resolve column names" branch returning an
all-NaN array, and the per-column "date column not found in X" warning
inside the for col in cols loop.
_days_since_day_resolution, the overflow-safe fallback for date spans
beyond ~292 years — entirely unreached, since no test constructs dates that
overflow int64 nanosecond resolution.
Where
| File |
Locate with |
philanthropy/preprocessing/_encounter_recency.py |
grep -n "def _parse_dates|def _compute_recency_features|def _days_since_day_resolution|def fit|def transform" philanthropy/preprocessing/_encounter_recency.py |
What to change
No source change — this is test-only. Start by running coverage to see the
current exact Missing line/branch list, since the numbering above is
described by behaviour, not frozen lines:
python -m pytest tests/test_preprocessing.py tests/test_encounter_timezone.py \
--cov=philanthropy.preprocessing._encounter_recency --cov-report=term-missing -q
Then, working through the five groups above:
- Fit/transform with a tz-naive date series and a
timezone param set, to
force the tz_localize fallback in _parse_dates.
- Construct one fixture with tz-aware
dates and a tz-naive
reference_date, and one with the reverse, to hit both branches in
_compute_recency_features.
- Fit with a DataFrame containing only unparseable dates in every date
column (to hit "no parseable dates"), and fit with a bare ndarray (to
hit "X is not a DataFrame") — both should warn and default to today.
- Transform with a bare
ndarray after fitting on a DataFrame (exercises the
feature_names_in_ rebuild path), transform without ever having resolved
column names (the all-NaN fallback), and transform a DataFrame missing
one of the configured date_col columns (the per-column warning).
- Construct two
pd.Timestamps roughly 300+ years apart and call
_days_since_day_resolution directly (it's a @staticmethod, callable
without fitting anything) to confirm it returns a finite day count instead
of raising OverflowError/OutOfBoundsTimedelta.
Tests to add or extend
- File:
tests/test_encounter_timezone.py (for the tz-specific branches in
groups 1–2) or tests/test_preprocessing.py (for groups 3–5) — check
tests/test_encounter_timezone.py's existing scope first
(grep -n "class \|def test_" tests/test_encounter_timezone.py) before
deciding which file a given test belongs in.
- Add tests named to match the existing
TestEncounterRecencyTransformer*
conventions in whichever file you extend.
Done when
python -m pytest tests/test_preprocessing.py tests/test_encounter_timezone.py \
--cov=philanthropy.preprocessing._encounter_recency --cov-report=term-missing -q
philanthropy/preprocessing/_encounter_recency.py reads at or above the 93%
risk-tier floor.
Summary
philanthropy/preprocessing/_encounter_recency.pyis at 82% branchcoverage, the lowest of any file in the risk tier
make riskcovenforces ata 93% floor — this file alone is dragging that subtree's average down. Unlike
the other coverage-gap issues in this repo, which name one or two specific
guards, this one is a cluster spanning both
fitandtransformonEncounterRecencyTransformer, plus its private helpers. Filing it as oneissue rather than several because the branches share a theme (timezone- and
NaN-handling edge cases) and a contributor working through them will end up
reading the whole
fit/transformpair anyway.Untested regions, grouped by what triggers them (confirm current line numbers
with the coverage command below — they will drift as other work touches this
file):
_parse_dates's tz-localise fallback.parsed.dt.tz_convert(self.timezone)is wrapped in
try/except Exception, falling back toparsed.dt.tz_localize(self.timezone). No test parses a tz-naive seriesthrough a
timezone-configured transformer, so the fallback never runs._compute_recency_features's tz-mismatch branches. The three-way branchcomparing
dates.dt.tzagainstref.tzinfo(tz-aware dates vs tz-naivereference, and the reverse) — only the "both match" case is exercised today.
fit's reference-date inference paths. BothUserWarningbranches —"no parseable dates found in training data" and "
Xis not a DataFrame" —defaulting
reference_date_to today.transform's ndarray-fallback and missing-date-column paths. Thebranch that rebuilds a DataFrame from
feature_names_in_whenXisn'talready one, the "cannot resolve column names" branch returning an
all-
NaNarray, and the per-column "date column not found in X" warninginside the
for col in colsloop._days_since_day_resolution, the overflow-safe fallback for date spansbeyond ~292 years — entirely unreached, since no test constructs dates that
overflow
int64nanosecond resolution.Where
philanthropy/preprocessing/_encounter_recency.pygrep -n "def _parse_dates|def _compute_recency_features|def _days_since_day_resolution|def fit|def transform" philanthropy/preprocessing/_encounter_recency.pyWhat to change
No source change — this is test-only. Start by running coverage to see the
current exact
Missingline/branch list, since the numbering above isdescribed by behaviour, not frozen lines:
Then, working through the five groups above:
timezoneparam set, toforce the
tz_localizefallback in_parse_dates.datesand a tz-naivereference_date, and one with the reverse, to hit both branches in_compute_recency_features.column (to hit "no parseable dates"), and fit with a bare
ndarray(tohit "X is not a DataFrame") — both should warn and default to today.
ndarrayafter fitting on a DataFrame (exercises thefeature_names_in_rebuild path), transform without ever having resolvedcolumn names (the all-
NaNfallback), and transform a DataFrame missingone of the configured
date_colcolumns (the per-column warning).pd.Timestamps roughly 300+ years apart and call_days_since_day_resolutiondirectly (it's a@staticmethod, callablewithout fitting anything) to confirm it returns a finite day count instead
of raising
OverflowError/OutOfBoundsTimedelta.Tests to add or extend
tests/test_encounter_timezone.py(for the tz-specific branches ingroups 1–2) or
tests/test_preprocessing.py(for groups 3–5) — checktests/test_encounter_timezone.py's existing scope first(
grep -n "class \|def test_" tests/test_encounter_timezone.py) beforedeciding which file a given test belongs in.
TestEncounterRecencyTransformer*conventions in whichever file you extend.
Done when
philanthropy/preprocessing/_encounter_recency.pyreads at or above the 93%risk-tier floor.