Skip to content

chore(skore): Switch from mypy to ty#2461

Draft
Sharkyii wants to merge 18 commits intoprobabl-ai:mainfrom
Sharkyii:chore/replace-mypy-to-ty
Draft

chore(skore): Switch from mypy to ty#2461
Sharkyii wants to merge 18 commits intoprobabl-ai:mainfrom
Sharkyii:chore/replace-mypy-to-ty

Conversation

@Sharkyii
Copy link
Contributor

@Sharkyii Sharkyii commented Feb 14, 2026

Since ty surfaced a large number of pre-existing diagnostics, I added scoped ignore rules in each project’s pyproject.toml to establish a stable baseline:

• skore/: 12 rules ignored
• skore-hub-project/: 5 rules ignored
• skore-local-project/: 5 rules ignored

Fixes: #2376, replaces #2455.

@Sharkyii
Copy link
Contributor Author

Sharkyii commented Feb 14, 2026

@thomass-dev When you have some time, I would appreciate another review. I’ve updated the PR to address the earlier concerns and verified the CI behavior.

@thomasloux
Copy link
Contributor

@Sharkyii you probably tagged the wrong person :)

@glemaitre glemaitre changed the title Chore/replace mypy to ty chore(skore): Swtich from mypy to ty Feb 15, 2026
@Sharkyii Sharkyii changed the title chore(skore): Swtich from mypy to ty chore(skore): Swtich from mypy with ty Feb 15, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Feb 15, 2026

Documentation preview @ 9b733ce

@github-actions
Copy link
Contributor

github-actions bot commented Feb 15, 2026

Coverage

Coverage Report for skore-hub-project/
FileStmtsMissCoverMissing
skore-hub-project/src/skore_hub_project
   __init__.py12191%34
   exception.py20100% 
   json.py10190%16
   protocol.py470100% 
skore-hub-project/src/skore_hub_project/artifact
   __init__.py00100% 
   artifact.py250100% 
   serializer.py280100% 
   upload.py36488%175, 177–178, 180
skore-hub-project/src/skore_hub_project/artifact/media
   __init__.py50100% 
   data.py200100% 
   inspection.py46197%33
   media.py100100% 
   model.py100100% 
   performance.py450100% 
skore-hub-project/src/skore_hub_project/artifact/pickle
   __init__.py20100% 
   pickle.py240100% 
skore-hub-project/src/skore_hub_project/authentication
   __init__.py00100% 
   apikey.py70100% 
   login.py24387%32–33, 42
   token.py800100% 
   uri.py50100% 
skore-hub-project/src/skore_hub_project/client
   __init__.py00100% 
   client.py630100% 
skore-hub-project/src/skore_hub_project/metric
   __init__.py100100% 
   accuracy.py350100% 
   brier_score.py350100% 
   log_loss.py350100% 
   metric.py55492%38, 77–78, 84
   precision.py530100% 
   r2.py350100% 
   recall.py550100% 
   rmse.py350100% 
   roc_auc.py350100% 
   timing.py76494%45–46, 104–105
skore-hub-project/src/skore_hub_project/project
   __init__.py00100% 
   project.py144695%86, 111, 126, 314, 394, 424
skore-hub-project/src/skore_hub_project/report
   __init__.py30100% 
   cross_validation_report.py730100% 
   estimator_report.py100100% 
   report.py590100% 
TOTAL12492498% 

Tests Skipped Failures Errors Time
249 0 💤 0 ❌ 0 🔥 2m 1s ⏱️

@github-actions
Copy link
Contributor

github-actions bot commented Feb 15, 2026

Coverage

Coverage Report for skore-local-project/
FileStmtsMissCoverMissing
skore-local-project/src/skore_local_project
   __init__.py50100% 
   metadata.py94594%28, 36, 49, 165–166
   project.py102199%259
   storage.py40295%45, 187
TOTAL241896% 

Tests Skipped Failures Errors Time
23 0 💤 0 ❌ 0 🔥 7.869s ⏱️

@github-actions
Copy link
Contributor

github-actions bot commented Feb 15, 2026

Coverage

Coverage Report for skore/
FileStmtsMissCoverMissing
skore/src/skore
   __init__.py280100% 
   _config.py44197%57
   exceptions.py440%4, 15, 19, 23
skore/src/skore/_project
   __init__.py00100% 
   _summary.py81198%123
   _widget.py1950100% 
   login.py100100% 
   plugin.py120100% 
   project.py54296%148, 157
   types.py30100% 
skore/src/skore/_sklearn
   __init__.py60100% 
   _base.py70888%268–275
   feature_names.py270100% 
   find_ml_task.py610100% 
   types.py28196%30
skore/src/skore/_sklearn/_comparison
   __init__.py70100% 
   inspection_accessor.py40197%195
   metrics_accessor.py155298%179, 1124
   report.py111397%514, 517, 523
   utils.py580100% 
skore/src/skore/_sklearn/_cross_validation
   __init__.py90100% 
   data_accessor.py31196%48
   inspection_accessor.py19194%121
   metrics_accessor.py158497%1046, 1107, 1140–1141
   report.py109496%403, 445, 448, 454
skore/src/skore/_sklearn/_estimator
   __init__.py90100% 
   data_accessor.py45197%167
   inspection_accessor.py58198%321
   metrics_accessor.py352598%427, 431, 446, 476, 1647
   report.py166398%273, 477, 480
skore/src/skore/_sklearn/_plot
   __init__.py30100% 
   base.py59296%60–61
   utils.py121298%273–274
skore/src/skore/_sklearn/_plot/data
   __init__.py20100% 
   table_report.py178199%661
skore/src/skore/_sklearn/_plot/inspection
   __init__.py00100% 
   coefficients.py2040100% 
   impurity_decrease.py84297%365, 409
   permutation_importance.py1490100% 
   utils.py90100% 
skore/src/skore/_sklearn/_plot/metrics
   __init__.py60100% 
   confusion_matrix.py1630100% 
   metrics_summary_display.py80100% 
   precision_recall_curve.py1080100% 
   prediction_error.py1670100% 
   roc_curve.py1120100% 
skore/src/skore/_sklearn/train_test_split
   __init__.py00100% 
   train_test_split.py590100% 
skore/src/skore/_sklearn/train_test_split/warning
   __init__.py80100% 
   high_class_imbalance_too_few_examples_warning.py21195%86
   high_class_imbalance_warning.py220100% 
   random_state_unset_warning.py100100% 
   shuffle_true_warning.py90100% 
   stratify_is_set_warning.py100100% 
   time_based_column_warning.py210100% 
   train_test_split_warning.py30100% 
skore/src/skore/_utils
   __init__.py6266%8, 13
   _accessor.py118496%38, 214, 268, 288
   _cache.py370100% 
   _cache_key.py29389%35, 43, 52
   _dataframe.py34197%43
   _environment.py32293%41, 44
   _fixes.py80100% 
   _index.py50100% 
   _jupyter.py8275%13–14
   _logger.py22481%15–17, 19
   _measure_time.py100100% 
   _parallel.py170100% 
   _patch.py221245%31, 36–40, 43–44, 47–48, 59, 61
   _progress_bar.py41490%55–56, 66–67
   _show_versions.py380100% 
   _testing.py1101190%21, 30, 158, 167, 178–183, 185
skore/src/skore/_utils/repr
   __init__.py20100% 
   base.py540100% 
   data.py1640100% 
   html_repr.py380100% 
   rich_repr.py810100% 
TOTAL43629697% 

Tests Skipped Failures Errors Time
1765 5 💤 0 ❌ 0 🔥 7m 27s ⏱️

@Sharkyii Sharkyii changed the title chore(skore): Swtich from mypy with ty chore(skore): Swtich to mypy with ty Feb 15, 2026
@Sharkyii
Copy link
Contributor Author

Why ty flags errors that mypy didn’t

Import & attribute resolution

Errors: unresolved-import, unresolved-attribute, possibly-missing-attribute
mypy often supresses missing or dynamic attributes that are used in the repo as Any.
Docs:
mypy: here

Function call & signature checking

Errors: unknown-argument, invalid-argument-type, missing-argument, no-matching-overload, call-non-callable
mypy skips checking many untyped function bodies and treats unknown types as Any, so invalid calls often pass silently. ty performs stricter call-site checking even when types are incomplete.

Docs:
mypy untyped defs not checked → here
mypy Any behavior → here
ty diagnostics philosophy → here

Assignment & return typing

Errors: invalid-assignment, invalid-return-type, invalid-type-form
mypy widens many inferred types to avoid false positives and accepts more loose assignments. ty keeps stricter inference and flags mismatches instead of widening automatically.

Docs:
mypy assignment rules → here

Hygiene / redundancy checks

Errors: redundant-cast, unused-type-ignore-comment
mypy only reports these if explicitly enabled. ty reports them by default to keep annotations clean.

Docs:
mypy unused ignore behavior → here
ty ignore handling → here

Copy link
Collaborator

@thomass-dev thomass-dev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to ensure i can review.

@auguste-probabl auguste-probabl changed the title chore(skore): Swtich to mypy with ty chore(skore): Switch from mypy to ty Feb 16, 2026

for warning_class in TRAIN_TEST_SPLIT_WARNINGS:
warning = warning_class.check(**kwargs)
warning = cast(Any, warning_class).check(**kwargs)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
warning = cast(Any, warning_class).check(**kwargs)
warning = cast(TrainTestSplitWarning, warning_class).check(**kwargs)

Sharkyii and others added 2 commits February 17, 2026 19:04
Co-authored-by: Auguste Baum <auguste@probabl.ai>
@auguste-probabl
Copy link
Collaborator

Working on it, hope that's okay ^^'

@Sharkyii
Copy link
Contributor Author

Yupp, works for me.

report = cast(EstimatorReport, report)
super().__post_init__(report)

from skore import EstimatorReport
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is redundant with the import in TYPE_CHECKING, isn't?

Copy link
Collaborator

@auguste-probabl auguste-probabl Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I got test failures when this wasn't imported out of TYPE_CHECKING. So it looks like cast statements are not simply removed at runtime...

@auguste-probabl
Copy link
Collaborator

I'm having a lot of trouble with this because I never get the same check results between CI and my machine. I'm going to let this sit for a while and hope that ty matures more and provides a more robust solution.


[tool.mypy]
exclude = ["hatch/", "tests/"]
strict = true
Copy link
Collaborator

@thomass-dev thomass-dev Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change has to be discussed, as ty doesn't have a strict mode for now and we would to be strict as much as possible in skore-hub-project and skore-local-project.

https://docs.astral.sh/ty/reference/typing-faq/#does-ty-have-a-strict-mode

Could you please list me the rules that will not be applied with this change?

return cast_to_float(getattr(report.metrics, name)(data_source="test"))

def __post_init__(self, report: EstimatorReport) -> None: # type: ignore[override]
def __post_init__(self, report: EstimatorReport | CrossValidationReport) -> None:
Copy link
Collaborator

@thomass-dev thomass-dev Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it violates the Liskov substitution principle, but your change is not true. Please revert.

Copy link
Collaborator

@thomass-dev thomass-dev Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can fix the violation in a dedicated issue as we have done in https://github.com/probabl-ai/skore/blob/main/skore-hub-project/src/skore_hub_project/report/estimator_report.py, but it is not important here.

return cast_to_float(series.iloc[0])

def __post_init__(self, report: CrossValidationReport) -> None: # type: ignore[override]
def __post_init__(self, report) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert.

@thomass-dev thomass-dev marked this pull request as draft February 19, 2026 15:24
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.

chore: Switch from mypy to ty

5 participants