Skip to content

test: EncounterRecencyTransformer coverage gap — timezone/overflow/ndarray-fallback branches untested (82% coverage, worst in risk tier) #63

Description

@shivamlalakiya

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):

  1. _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.
  2. _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.
  3. 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.
  4. 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.
  5. _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:

  1. Fit/transform with a tz-naive date series and a timezone param set, to
    force the tz_localize fallback in _parse_dates.
  2. 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.
  3. 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.
  4. 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).
  5. 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.

make riskcov

Metadata

Metadata

Assignees

No one assigned

    Labels

    help wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions