-
Notifications
You must be signed in to change notification settings - Fork 1.5k
feat: replace mypy with ty for static type analysis #8868
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
ba56a6d
5216b7a
eacd783
c64825f
66b6c17
19cab57
4b8086b
763b7ff
ae31bb2
42ec9b2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -9,7 +9,7 @@ jobs: | |||||
| runs-on: ubuntu-latest | ||||||
| strategy: | ||||||
| matrix: | ||||||
| opt: ["codeformat", "pytype", "mypy"] | ||||||
| opt: ["codeformat", "pytype", "ty"] | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| steps: | ||||||
| - uses: actions/checkout@v4 | ||||||
| - name: Set up Python 3.9 | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -116,6 +116,7 @@ examples/scd_lvsegs.npz | |
| temp/ | ||
| .idea/ | ||
| .dmypy.json | ||
| .ty_cache/ | ||
|
|
||
| *~ | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -52,6 +52,57 @@ extend-ignore = [ | |
| "NPY002", # numpy-legacy-random | ||
| ] | ||
|
|
||
| [tool.ty] | ||
| [tool.ty.environment] | ||
| python-version = "3.9" | ||
|
|
||
| [tool.ty.src] | ||
| exclude = [ | ||
| "**/venv/**", | ||
| "**/.venv/**", | ||
| "versioneer.py", | ||
| "monai/_version.py", | ||
| ] | ||
|
|
||
| [tool.ty.rules] | ||
| # Only rules explicitly listed here; all unlisted rules are ignored. | ||
| # This provides a stable baseline matching mypy's output (zero diagnostics on monai/). | ||
| # Rules can be re-enabled incrementally as the codebase is improved. | ||
|
Comment on lines
+68
to
+70
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: Default behavior: if you configure Citations:
🏁 Script executed: #!/bin/bash
# Verify ty configuration syntax and default behavior
ty --help 2>&1 | head -20Repository: Project-MONAI/MONAI Length of output: 104 🏁 Script executed: #!/bin/bash
# Inspect tool.ty.rules config around the referenced lines
sed -n '1,120p' pyproject.toml | nl -ba | sed -n '1,120p'
rg -n "^\[tool\.ty\.rules\]" -n pyproject.toml || true
rg -n "tool\.ty\.rules|^\s*all\s*=" pyproject.toml || true
# Print the full rules block (up to the next [section])
awk '
BEGIN{inblock=0}
/^\[tool\.ty\.rules\]/{inblock=1; print; next}
inblock && /^\[/{inblock=0}
inblock{print}
' pyproject.toml | nl -baRepository: Project-MONAI/MONAI Length of output: 237 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Show the relevant ty config area with line numbers via `cat -n` (nl isn't available)
sed -n '55,115p' pyproject.toml | cat -n
# Extract just the tool.ty.rules block
awk '
/^\[tool\.ty\.rules\]/{inblock=1}
inblock{print}
inblock && /^\[/{ if($0 !~ /^\[tool\.ty\.rules\]/){exit} }
' pyproject.toml | cat -n
# List rule keys under tool.ty.rules (excluding the header line)
awk '
$0 ~ /^\[tool\.ty\.rules\]/{inblock=1; next}
inblock{
if($0 ~ /^\[/{exit}
if($0 ~ /^[[:space:]]*`#/` || $0 ~ /^[[:space:]]*$/) next
if($0 ~ /=/) print
}
' pyproject.toml | rg -n "^[0-9]+:.*=" || trueRepository: Project-MONAI/MONAI Length of output: 3829 🌐 Web query:
💡 Result: In ty, per-rule configuration works by merging configured rule severities from global rules ([tool.ty.rules] / [rules]) and then applying overrides; later overrides take precedence, and override rules “will be merged with the global rules” ([1], [2]). There’s no statement in the official configuration docs that “unlisted rules are ignored” or that fallback “per-rule default wording” is skipped when [tool.ty.rules] contains an incomplete set; instead, the documented model is that you can specify only the rules you care about, and the rest follow their normal configured defaults unless you disable them globally (for example via all = “ignore”) or enable/disable via CLI flags like --warn/--error/--ignore [1]. Your quoted behavior is more likely to be explained by how ty treats “type: ignore” codes vs “ty: ignore” codes, which can appear as “unlisted rules ignored” in practice. ty’s configuration includes respect-type-ignore-comments (default true): when false, ty treats type: ignore as a normal comment and “can’t be used to suppress ty errors” (you must use ty: ignore instead) [1]. Separately, ty has a rule ignore-comment-unknown-rule that warns when you use ty: ignore[code] or type: ignore[ty:code] with a code that isn’t a known lint rule, i.e., unrecognized codes in ignore comments won’t suppress anything and are likely a mistake [3]. So, based on the current official docs: (1) [tool.ty.rules] doesn’t imply that unlisted rules are ignored; it only sets severities for the rules you name, while other rules use their normal defaults unless you change them globally; and (2) apparent “ignoring fallback/default wording” is commonly due to suppression behavior (especially around type: ignore vs ty: ignore, and unknown ignore codes) rather than a bug in configuration merging [1][3]. Citations:
Fix misleading 🤖 Prompt for AI Agents |
||
| unresolved-import = "ignore" | ||
| unused-ignore-comment = "ignore" | ||
| unused-type-ignore-comment = "ignore" | ||
| unresolved-attribute = "ignore" | ||
| unresolved-reference = "ignore" | ||
| invalid-method-override = "ignore" | ||
| invalid-argument-type = "ignore" | ||
| invalid-assignment = "ignore" | ||
| invalid-return-type = "ignore" | ||
| invalid-type-form = "ignore" | ||
| invalid-declaration = "ignore" | ||
| invalid-yield = "ignore" | ||
| call-non-callable = "ignore" | ||
| call-top-callable = "ignore" | ||
| index-out-of-bounds = "ignore" | ||
| missing-argument = "ignore" | ||
| no-matching-overload = "ignore" | ||
| not-iterable = "ignore" | ||
| not-subscriptable = "ignore" | ||
| parameter-already-assigned = "ignore" | ||
| unsupported-operator = "ignore" | ||
| deprecated = "ignore" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we be ignoring this one, or does it give incorrect feedback? I'd like to minimise how many things we're ignoring so we don't hide real issues like we have in the past. |
||
| division-by-zero = "ignore" | ||
| invalid-enum-member-annotation = "ignore" | ||
| possibly-missing-attribute = "ignore" | ||
| possibly-missing-submodule = "ignore" | ||
| possibly-unresolved-reference = "ignore" | ||
| unknown-argument = "ignore" | ||
| too-many-positional-arguments = "ignore" | ||
|
|
||
| [[tool.ty.overrides]] | ||
| include = ["versioneer.py", "monai/_version.py"] | ||
| [tool.ty.overrides.rules] | ||
| all = "ignore" | ||
|
|
||
| [tool.pytype] | ||
| # Space-separated list of files or directories to exclude. | ||
| exclude = ["versioneer.py", "_version.py"] | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I want to do instead is replace
pytypewithtyand see how that works for us. There's a lot of errors it throws up when I initially tried it, but we can work through those and configure what to ignore. We can then see iftyprovides any value, otherwise we rely on mypy only. Since pytype is essentially deprecated now we should remove it either way from the test process but keep the script option to run it.