Conversation
ty (from Astral, makers of ruff/uv) replaces mypy as the project's static type checker. Benchmark on this codebase (631 source files): | Metric | mypy | ty | Speedup | |-------------|----------|-------|---------| | Cold cache | 184.6s | 0.79s | ~234x | | Warm cache | 13.9s | 0.83s | ~17x | Changes: - Add ty to lint deps, remove mypy + mypy-extensions (keep mypy-protobuf for protoc stub generation) - Migrate mypy.ini config to [tool.ty.*] sections in pyproject.toml - Update Makefile type_check target: `uv run ty check` - Downgrade 12 rule categories to "warn" for initial migration; a follow-up PR will fix the 226 warnings and promote them back to errors - Update docs (CLAUDE.md, README.md, CHANGELOG.md, .claude/formatting.md) - Update .gitignore/.dockerignore cache directory references - Replace "mypy" mentions in source comments with generic "type checker" - Delete mypy.ini Co-Authored-By: shubhamvij <25601958+shubhamvij@users.noreply.github.com>
- Pin ty~=0.0.29 for reproducible builds - Add comment clarifying mypy-protobuf is for stub generation only - Exclude notebooks (*.ipynb) from type checking - Add comment about torch lacking inline types/stubs - Promote all ty rules back to default error severity (remove warn downgrades — fixes come in a follow-up PR) - Add [[tool.ty.overrides]] to suppress errors in generated *_pb2.py files that cannot be fixed Co-Authored-By: shubhamvij <25601958+shubhamvij@users.noreply.github.com>
| [tool.ty.src] | ||
| exclude = ["*_pb2.py", "*_pb2.pyi", "**/*.ipynb"] | ||
|
|
||
| [tool.ty.analysis] |
There was a problem hiding this comment.
Migrated from mypy.ini - removed any that could be fixed - thank you robots!
|
|
||
| # Need to do this "backwards" so the parent class can be defined first. | ||
| # Otherwise, mypy complains that: | ||
| # Otherwise, the type checker complains that: |
There was a problem hiding this comment.
Shall we check that ty still complains?
(I am going to leave identical comments on all of the changes like this - that way the robots can pick them up and check automatically)
There was a problem hiding this comment.
I threw bot at it, looks like we still might need these.
|
|
||
| if is_positive: | ||
| # This assert is added to pass mypy type check, in practice we will not see this fail | ||
| # This assert is added to pass the type checker, in practice we will not see this fail |
There was a problem hiding this comment.
Shall we check that ty still complains?
(I am going to leave identical comments on all of the changes like this - that way the robots can pick them up and check automatically)
| self._positive_label_edge_index = None | ||
| else: | ||
| # This assert is added to pass mypy type check, in practice we will not see this fail | ||
| # This assert is added to pass the type checker, in practice we will not see this fail |
There was a problem hiding this comment.
Shall we check that ty still complains?
(I am going to leave identical comments on all of the changes like this - that way the robots can pick them up and check automatically)
| else None, | ||
| # This should be `aiplatform.gapic.Scheduling.Strategy[inferencer_resource_config.scheduling_strategy]` | ||
| # But mypy complains otherwise... | ||
| # But the type checker complains otherwise... |
There was a problem hiding this comment.
Shall we check that ty still complains?
(I am going to leave identical comments on all of the changes like this - that way the robots can pick them up and check automatically)
|
|
||
|
|
||
| # Below type ignores are due to mypy star expansion issues: https://github.com/python/mypy/issues/6799 | ||
| # Below type ignores are due to star expansion issues with the type checker: https://github.com/python/mypy/issues/6799 |
There was a problem hiding this comment.
Shall we check that ty still complains?
(I am going to leave identical comments on all of the changes like this - that way the robots can pick them up and check automatically)
There was a problem hiding this comment.
Wait did we keep the link as is?
| from gigl.src.data_preprocessor.lib.types import InstanceDictPTransform | ||
|
|
||
| # Type hints for abstract dataclasses are currently not supported. https://github.com/python/mypy/issues/5374 | ||
| # Type hints for abstract dataclasses may have limited support in type checkers. https://github.com/python/mypy/issues/5374 |
There was a problem hiding this comment.
Shall we check that ty still complains?
(I am going to leave identical comments on all of the changes like this - that way the robots can pick them up and check automatically)
Also update the TODO from python/mypy?
There was a problem hiding this comment.
this was fixed with ty - updated
| # We cannot at the moment as we type-ignore GLT | ||
| # And adding it as a type here will break the type checker. | ||
| # PartitionBook |
There was a problem hiding this comment.
Shall we check that ty still complains?
(I am going to leave identical comments on all of the changes like this - that way the robots can pick them up and check automatically)
| python-version = "3.11" | ||
|
|
||
| [tool.ty.src] | ||
| exclude = ["*_pb2.py", "*_pb2.pyi", "**/*.ipynb"] |
There was a problem hiding this comment.
should we add a TODO to include our notebooks here eventually?
There was a problem hiding this comment.
Tbh, I think its fine if we don't
Notebooks need not have verbose static type checking
Most act as documentation
| "kfp.**", | ||
| "tensorflow.**", | ||
| "tensorflow_metadata.**", | ||
| "torch.**", |
There was a problem hiding this comment.
hmmmm, we weren't type-ignoring torch before.
IIRC I saw some issues with torch when I looked into this earlier, the ty people suggested to enable some flag - did you try this? astral-sh/ty#2244
Since we're so reliant on torch I'd rather not type-ignore it if possible.
There was a problem hiding this comment.
Unforunately the flag is not the problem
From the robots analysis, there are 200+ issues that were not being caught before; I think we should reserve for a future change?
Seems might just be using the apis in an incorrect way according to types - event hough it seems to be working.
Group 1: Tensor.getitem with NodeType/EdgeType/CondensedNodeType keys (~64 errors)
These happen because dict[NodeType, Tensor] access returns Tensor, and then a second indexing
like result[tensor_index] hits Tensor's strict getitem signature. The custom NewType keys
(NodeType = str, CondensedNodeType = int, EdgeType = NamedTuple) don't satisfy Tensor's index
types.Fix: These are dict-on-dict access patterns — the real issue is that ty is resolving the chained
subscript incorrectly or the intermediate type needs explicit annotation. Likely fixable via
local variable annotations or targeted # type: ignore comments.Group 2: FloatTensor/LongTensor vs Tensor return type mismatches (~25 errors)
Functions annotated to return FloatTensor/LongTensor but torch.gather(), torch.stack(),
torch.cat(), torch.mean(), torch.tensor() all return generic Tensor.Fix: Change return type annotations from FloatTensor/LongTensor to Tensor. These deprecated
aliases are not what torch operations actually return.Group 3: init argument type mismatches (~20 errors)
Parameters using torch.dtype, torch.device, etc. where ty resolves the stub types more strictly.
Fix: Explicit casts or type annotations at call sites.
Group 4: HeteroData/dict access returning object/Unknown (~15 errors)
When iterating over graph data structures, values come back as object rather than typed tensors.
Fix: Add explicit type annotations to loop variables.
Group 5: List invariance issues (~8 errors)
list[Tensor | None] assigned to list[Tensor], or Optional[Tensor] appended to list[FloatTensor].
Fix: Widen the list type annotations.
Group 6: Misc (operators, spawn, call-non-callable, etc.) (~10 errors)
Fix: Case-by-case — spawn import fix, operator type annotations, etc.
There was a problem hiding this comment.
I think I'd prefer to keep the torch typing around (if my reading is correct that this infact is equivalent to type-ignoring torch) and just add a bunch of # type-ignore and TODOs to fix.
IDK how feasible that'd be to setup tho.
| # https://docs.astral.sh/ty/reference/configuration/#replace-imports-with-any | ||
| replace-imports-with-any = [ | ||
| "apache_beam.**", | ||
| "google.cloud.**", |
There was a problem hiding this comment.
likewise, is there a reason we're blanket ignoring all gcp imports?
svij-sc
left a comment
There was a problem hiding this comment.
I updated the downstream PR where I addressed the ty fixes and to it added some new fixes identified by @kmontemayor2-sc below.
Ref: #586
| "kfp.**", | ||
| "tensorflow.**", | ||
| "tensorflow_metadata.**", | ||
| "torch.**", |
There was a problem hiding this comment.
Unforunately the flag is not the problem
From the robots analysis, there are 200+ issues that were not being caught before; I think we should reserve for a future change?
Seems might just be using the apis in an incorrect way according to types - event hough it seems to be working.
Group 1: Tensor.getitem with NodeType/EdgeType/CondensedNodeType keys (~64 errors)
These happen because dict[NodeType, Tensor] access returns Tensor, and then a second indexing
like result[tensor_index] hits Tensor's strict getitem signature. The custom NewType keys
(NodeType = str, CondensedNodeType = int, EdgeType = NamedTuple) don't satisfy Tensor's index
types.Fix: These are dict-on-dict access patterns — the real issue is that ty is resolving the chained
subscript incorrectly or the intermediate type needs explicit annotation. Likely fixable via
local variable annotations or targeted # type: ignore comments.Group 2: FloatTensor/LongTensor vs Tensor return type mismatches (~25 errors)
Functions annotated to return FloatTensor/LongTensor but torch.gather(), torch.stack(),
torch.cat(), torch.mean(), torch.tensor() all return generic Tensor.Fix: Change return type annotations from FloatTensor/LongTensor to Tensor. These deprecated
aliases are not what torch operations actually return.Group 3: init argument type mismatches (~20 errors)
Parameters using torch.dtype, torch.device, etc. where ty resolves the stub types more strictly.
Fix: Explicit casts or type annotations at call sites.
Group 4: HeteroData/dict access returning object/Unknown (~15 errors)
When iterating over graph data structures, values come back as object rather than typed tensors.
Fix: Add explicit type annotations to loop variables.
Group 5: List invariance issues (~8 errors)
list[Tensor | None] assigned to list[Tensor], or Optional[Tensor] appended to list[FloatTensor].
Fix: Widen the list type annotations.
Group 6: Misc (operators, spawn, call-non-callable, etc.) (~10 errors)
Fix: Case-by-case — spawn import fix, operator type annotations, etc.
|
|
||
| # Need to do this "backwards" so the parent class can be defined first. | ||
| # Otherwise, mypy complains that: | ||
| # Otherwise, the type checker complains that: |
There was a problem hiding this comment.
I threw bot at it, looks like we still might need these.
| from gigl.src.data_preprocessor.lib.types import InstanceDictPTransform | ||
|
|
||
| # Type hints for abstract dataclasses are currently not supported. https://github.com/python/mypy/issues/5374 | ||
| # Type hints for abstract dataclasses may have limited support in type checkers. https://github.com/python/mypy/issues/5374 |
There was a problem hiding this comment.
this was fixed with ty - updated
|
|
||
|
|
||
| # Below type ignores are due to mypy star expansion issues: https://github.com/python/mypy/issues/6799 | ||
| # Below type ignores are due to star expansion issues with the type checker: https://github.com/python/mypy/issues/6799 |
| else None, | ||
| # This should be `aiplatform.gapic.Scheduling.Strategy[inferencer_resource_config.scheduling_strategy]` | ||
| # But mypy complains otherwise... | ||
| # But the type checker complains otherwise... |
| self._positive_label_edge_index = None | ||
| else: | ||
| # This assert is added to pass mypy type check, in practice we will not see this fail | ||
| # This assert is added to pass the type checker, in practice we will not see this fail |
|
|
||
| if is_positive: | ||
| # This assert is added to pass mypy type check, in practice we will not see this fail | ||
| # This assert is added to pass the type checker, in practice we will not see this fail |
| python-version = "3.11" | ||
|
|
||
| [tool.ty.src] | ||
| exclude = ["*_pb2.py", "*_pb2.pyi", "**/*.ipynb"] |
There was a problem hiding this comment.
Tbh, I think its fine if we don't
Notebooks need not have verbose static type checking
Most act as documentation
| # https://docs.astral.sh/ty/reference/configuration/#replace-imports-with-any | ||
| replace-imports-with-any = [ | ||
| "apache_beam.**", | ||
| "google.cloud.**", |
ty (from Astral, makers of ruff/uv) replaces mypy as the project's static type checker.
The ty fixes are introduced here: #586
Benchmarked on the code base (631 source files):
Changes:
uv run ty checkScope of work done
Where is the documentation for this feature?: N/A
Did you add automated tests or write a test plan?
Updated Changelog.md? NO
Ready for code review?: YES