Skip to content

Replace mypy with ty for static type checking#585

Open
svij-sc wants to merge 10 commits intomainfrom
svij/use-ty
Open

Replace mypy with ty for static type checking#585
svij-sc wants to merge 10 commits intomainfrom
svij/use-ty

Conversation

@svij-sc
Copy link
Copy Markdown
Collaborator

@svij-sc svij-sc commented Apr 13, 2026

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):

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

Scope 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

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>
svij-sc and others added 3 commits April 15, 2026 00:59
- 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>
@svij-sc svij-sc mentioned this pull request Apr 15, 2026
Comment thread pyproject.toml
[tool.ty.src]
exclude = ["*_pb2.py", "*_pb2.pyi", "**/*.ipynb"]

[tool.ty.analysis]
Copy link
Copy Markdown
Collaborator Author

@svij-sc svij-sc Apr 15, 2026

Choose a reason for hiding this comment

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

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:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I threw bot at it, looks like we still might need these.

Comment thread gigl/distributed/dist_partitioner.py Outdated

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
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

needed

Comment thread gigl/distributed/dist_partitioner.py Outdated
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
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

needed

else None,
# This should be `aiplatform.gapic.Scheduling.Strategy[inferencer_resource_config.scheduling_strategy]`
# But mypy complains otherwise...
# But the type checker complains otherwise...
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

needed



# 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
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

fixed - nice

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

this was fixed with ty - updated

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

ditto on link.

Comment thread gigl/types/graph.py
Comment on lines +390 to 392
# We cannot at the moment as we type-ignore GLT
# And adding it as a type here will break the type checker.
# PartitionBook
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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)

Comment thread pyproject.toml
python-version = "3.11"

[tool.ty.src]
exclude = ["*_pb2.py", "*_pb2.pyi", "**/*.ipynb"]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

should we add a TODO to include our notebooks here eventually?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Tbh, I think its fine if we don't
Notebooks need not have verbose static type checking

Most act as documentation

Comment thread pyproject.toml
"kfp.**",
"tensorflow.**",
"tensorflow_metadata.**",
"torch.**",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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.

Comment thread pyproject.toml Outdated
# https://docs.astral.sh/ty/reference/configuration/#replace-imports-with-any
replace-imports-with-any = [
"apache_beam.**",
"google.cloud.**",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

likewise, is there a reason we're blanket ignoring all gcp imports?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

fixed

Copy link
Copy Markdown
Collaborator Author

@svij-sc svij-sc left a comment

Choose a reason for hiding this comment

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

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

Comment thread pyproject.toml
"kfp.**",
"tensorflow.**",
"tensorflow_metadata.**",
"torch.**",
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

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:
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

fixed - nice

else None,
# This should be `aiplatform.gapic.Scheduling.Strategy[inferencer_resource_config.scheduling_strategy]`
# But mypy complains otherwise...
# But the type checker complains otherwise...
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

needed

Comment thread gigl/distributed/dist_partitioner.py Outdated
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
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

needed

Comment thread gigl/distributed/dist_partitioner.py Outdated

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
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

needed

Comment thread pyproject.toml
python-version = "3.11"

[tool.ty.src]
exclude = ["*_pb2.py", "*_pb2.pyi", "**/*.ipynb"]
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Tbh, I think its fine if we don't
Notebooks need not have verbose static type checking

Most act as documentation

Comment thread pyproject.toml Outdated
# https://docs.astral.sh/ty/reference/configuration/#replace-imports-with-any
replace-imports-with-any = [
"apache_beam.**",
"google.cloud.**",
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

fixed

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.

2 participants