Skip to content

build: add ty type checking alongside mypy - #1505

Draft
s3alfisc wants to merge 6 commits into
masterfrom
build/ty-type-check
Draft

build: add ty type checking alongside mypy#1505
s3alfisc wants to merge 6 commits into
masterfrom
build/ty-type-check

Conversation

@s3alfisc

@s3alfisc s3alfisc commented Sep 4, 2026

Copy link
Copy Markdown
Member

Adds ty 0.0.78 as a blocking CI type check alongside the existing mypy pre-commit hook, as the first step of #1104. ty lives in a typecheck pixi feature on the py311 to py314 environments (conda-forge's ty needs CPython 3.11+), with a type-check task and a [tool.ty] configuration; CI runs pixi run -e py312 type-check.

Of 169 diagnostics on master, 60 are fixed for real (formulaic formula sides read through typed accessors, honest annotations in the DiD, decomposition, and plotting entries, real narrowing fixes) and 11 unused-ignore warnings are silenced because mypy still owns those comments. The files rewritten by the open estimation-state stack (#1499 to #1501) are excluded temporarily and will be un-excluded, together with removing mypy, in a follow-up layer on top of that stack. Every remaining suppression is a # ty: ignore[rule] with a reason naming the third-party gap. No runtime behavior changes.

Verification

Passed locally at the head: ty check clean, mypy, ruff, release contract 1355/1355, targeted formula, DiD, decomposition, and plotting suites, broad Python-only suite (pre-existing torch_mps failures excluded), fast live-R 22/22. pixi.lock adds only ty. Deferred to CI: the type-check job itself, R suites, docs.

ty resolves imports from the environment it runs in, so it ships with the
runtime dependencies rather than with the lint environment. conda-forge's ty
requires CPython >= 3.11, which rules out the shared default dependency table
and the py310 environment.

The exclude list keeps ty away from the files the open estimation-state stack
rewrites; the mypy-to-ty migration layer that lands on top of that stack
removes them. mypy still owns the `# type: ignore` comments, so ty must not
report them as unused.
`StructuredFormula` serves `lhs`, `rhs` and `root` from `Structured.__getattr__`,
so a type checker sees none of them on the `Formula` base class the parser
returns. Two accessors in the compat module carry that knowledge, and the
parser's properties now declare the `SimpleFormula` they actually return
instead of the abstract base, which is neither sized nor iterable.

`is_structured_formula` is gone: `exogenous` needs the narrowing that only a
direct `isinstance` provides, and two spellings of the same check are worse
than one.
`panelview` returns the Axes its docstring already promises, `lpdid` and
`LPDID` accept the optional `xfml` their runtime checks and base class allow,
and `_coefplot_matplotlib` reads the "jet" colormap through the registry
rather than the dynamically populated `pyplot.cm` namespace.

Rebinding the saturated event-study methods onto a plain `Feols` keeps a
targeted suppression: replacing `Feols.iplot`, a `functools.partial`
attribute, needs a result class of its own rather than an annotation change.
The separation loop fits exactly one model, the CRV path needs a pandas frame
rather than any narwhals-native one, the torch demeaner's inner implementation
handles the `None` factor list its wrapper passes, and the Gelbach
decomposition indexes and multiplies compressed sparse matrices, which scipy's
`spmatrix` matrix-semantics mixin does not provide.

The remaining suppressions name a third-party gap each: numba's `prange`
marker class, and rpy2, which ships only with the `r` pixi feature.
@codecov

codecov Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.88889% with 7 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pyfixest/utils/set_rpy2_path.py 0.00% 2 Missing ⚠️
pyfixest/estimation/internals/separation.py 50.00% 1 Missing ⚠️
pyfixest/estimation/numba/demean_nb.py 0.00% 1 Missing ⚠️
pyfixest/estimation/numba/nested_fixef_nb.py 0.00% 1 Missing ⚠️
...fixest/estimation/post_estimation/decomposition.py 87.50% 1 Missing ⚠️
pyfixest/report/visualize.py 66.66% 1 Missing ⚠️
Flag Coverage Δ
core-tests 77.25% <85.71%> (+0.03%) ⬆️
test-r-core-other 47.97% <79.36%> (+0.09%) ⬆️
test-r-extended 22.14% <39.68%> (+0.01%) ⬆️
test-r-fixest 38.70% <75.40%> (?)
tests-extended ?

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
pyfixest/did/did2s.py 89.71% <100.00%> (+0.09%) ⬆️
pyfixest/did/estimation.py 94.66% <100.00%> (ø)
pyfixest/did/lpdid.py 18.27% <ø> (ø)
pyfixest/did/visualize.py 100.00% <100.00%> (ø)
pyfixest/estimation/formula/formulaic_compat.py 96.34% <100.00%> (+0.23%) ⬆️
pyfixest/estimation/formula/parse.py 94.48% <100.00%> (+0.07%) ⬆️
...ation/formula/transforms/fixed_effects_encoding.py 100.00% <100.00%> (ø)
pyfixest/estimation/internals/vcov_utils.py 92.92% <100.00%> (ø)
...fixest/estimation/post_estimation/fixed_effects.py 97.11% <100.00%> (+0.02%) ⬆️
pyfixest/estimation/torch/demean_torch_.py 80.45% <ø> (ø)
... and 8 more

... and 10 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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