Skip to content

test: PropensityScorer.predict_proba never exercises its single-class branch #50

Description

@shivamlalakiya

What's wrong

PropensityScorer.predict and PropensityScorer.predict_proba each have a short-circuit for the case where fit only ever saw one class (len(self.classes_) == 1). The one in predict is exercised today — scikit-learn's own check_classifiers_one_label conformance check (run in tests/test_sklearn_compliance.py) fits the estimator on single-label data and calls predict. That check does not call predict_proba, so predict_proba's parallel branch — returning a (n_samples, 1) column of ones, exactly as its own docstring's Returns section promises — has no test at all.

Where

File Locate with
philanthropy/models/_propensity_baseline.py grep -n "def predict_proba" -A 6 philanthropy/models/_propensity_baseline.py

The match on classes_) == 1 a few lines below def predict_proba is the one this issue is about. The identical-looking guard inside def predict (above it in the same file) already has coverage — leave that one alone.

What to change

No source change — this is test-only.

  1. Open tests/test_propensity.py and look at test_propensity_scorer_predict_proba_shape (locate with grep -n "def test_propensity_scorer_predict_proba_shape" tests/test_propensity.py) for the existing fixture/assertion style.
  2. Add a new test after it that fits PropensityScorer on a y containing only one label, then calls predict_proba and checks the shape and values match the docstring's promise.

Tests to add or extend

  • File: tests/test_propensity.py
  • Add: test_propensity_scorer_predict_proba_single_class
def test_propensity_scorer_predict_proba_single_class():
    X = np.ones((5, 3))
    y = np.zeros(5)
    clf = PropensityScorer().fit(X, y)
    proba = clf.predict_proba(X)
    assert proba.shape == (5, 1)
    assert np.all(proba == 1.0)

Done when

python -m pytest tests/test_propensity.py --cov=philanthropy.models._propensity_baseline -q
python -m coverage report --include='philanthropy/models/_propensity_baseline.py' --fail-under=100
make ci
make riskcov

The coverage report --fail-under=100 line exits non-zero until _propensity_baseline.py reads fully covered; make ci and make riskcov must also stay green.

First time here?

Read CONTRIBUTING.md and AGENTS.md. Add a ## [Unreleased] CHANGELOG entry and yourself to CONTRIBUTORS.md in the same PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    beginnerNo fundraising domain knowledge neededeasySmall, well-scoped, single-file changegood first issueGood for newcomershelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions