Skip to content

types: annotate metrics, utils, inspection and visualisation, and start the mypy ratchet - #167

Merged
shivamlalakiya merged 4 commits into
mainfrom
types/annotate-metrics-utils-inspection-viz
Sep 5, 2026
Merged

types: annotate metrics, utils, inspection and visualisation, and start the mypy ratchet#167
shivamlalakiya merged 4 commits into
mainfrom
types/annotate-metrics-utils-inspection-viz

Conversation

@shivamlalakiya

Copy link
Copy Markdown
Contributor

Part 1 of #166.

Why

py.typed ships in the wheel, so a user's type checker treats every unannotated function in this
package as Any. That is worse than shipping no type information at all: it silently disables
checking at the boundary instead of admitting there is nothing to check. mypy has been in CI since
the beginning without disallow_untyped_defs, so nothing stopped the backlog growing. An AST count
puts it at 159 functions.

What changed

Annotated the five subpackages that were nearly there already: datasets (already clean),
inspection (1), visualisation (2), utils (5), metrics (6).

Added the ratchet. A [[tool.mypy.overrides]] block turns disallow_untyped_defs = true on for
exactly those modules. The list only ever grows, one subpackage per PR, and collapses into a
top-level flag when it covers everything. The comment in pyproject.toml says that, and carries the
remaining counts so the next person does not have to re-derive them.

The ratchet actually bites

A config block that looks strict but is not is worse than no block, so this was checked rather than
assumed:

$ printf '\n\ndef _unannotated_probe(x):\n    return x\n' >> philanthropy/metrics/_fairness.py
$ python -m mypy philanthropy
philanthropy/metrics/_fairness.py:113: error: Function is missing a type annotation  [no-untyped-def]
Found 1 error in 1 file (checked 49 source files)
$ git checkout philanthropy/metrics/_fairness.py
$ python -m mypy philanthropy
Success: no issues found in 49 source files

One annotation is a fix, not a transcription

ensure_local_path was declared -> str while returning its argument unchanged, and both call sites
(cli.py, _grateful_patient.py) may hand it a Path. It is now generic in that argument via a
TypeVar, which is what its docstring already claimed ("the unchanged path"). The docstring's
Returns type is corrected to match.

Idiom

Plain typing (Collection, Sequence, Optional, Any), matching the rest of the package.
numpy.typing.ArrayLike appears nowhere here, and one PR in the middle of a ratchet is the wrong
place to introduce a second vocabulary. #166 says so too, so the remaining PRs stay consistent.

Verification

$ python -m mypy philanthropy
Success: no issues found in 49 source files
$ python -m flake8 philanthropy tests examples
(clean)

Full suite runs in the pre-push hook and in CI on this PR.

…rt the mypy ratchet

py.typed ships in the wheel, so a user's type checker treats every unannotated
function here as Any. That is worse than shipping no type information at all:
it silently disables checking at the boundary instead of admitting there is
nothing to check. mypy has been in CI since the beginning without
disallow_untyped_defs, so nothing stopped the backlog growing.

Annotates the five subpackages that were nearly there already (datasets was
already clean; inspection 1, visualisation 2, utils 5, metrics 6) and adds a
[[tool.mypy.overrides]] block turning disallow_untyped_defs on for exactly
those. A new unannotated function in a listed subpackage now fails CI, which is
the point: the list only grows.

Verified the ratchet actually bites rather than merely being present:

    printf 'def _probe(x):\n    return x\n' >> philanthropy/metrics/_fairness.py
    python -m mypy philanthropy
    philanthropy/metrics/_fairness.py:113: error: Function is missing a type
    annotation  [no-untyped-def]

One annotation is a fix rather than a transcription. ensure_local_path was
declared -> str while returning its argument unchanged, and both call sites may
hand it a Path. It is now generic in that argument, which is what the docstring
already said.

Idiom follows the surrounding code: plain typing (Collection, Sequence,
Optional, Any). numpy.typing appears nowhere in this package and one PR in the
middle of a ratchet is the wrong place to introduce it.

model_selection, experimental, cli, models and preprocessing remain. Counts and
the order to do them in are in #166.
@shivamlalakiya
shivamlalakiya enabled auto-merge (squash) September 5, 2026 21:04
@shivamlalakiya
shivamlalakiya merged commit 8bd7381 into main Sep 5, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant