diff --git a/.vscode/extensions.json b/.vscode/extensions.json index c59b27c..721f70f 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,7 +1,7 @@ { "recommendations": [ "ms-python.python", - "ms-python.vscode-pylance", + "astral-sh.ty", "charliermarsh.ruff", "esbenp.prettier-vscode", "EditorConfig.EditorConfig", diff --git a/README.md b/README.md index 53fe20f..1c822e1 100644 --- a/README.md +++ b/README.md @@ -327,7 +327,7 @@ All output follows consistent formatting rules so both humans and LLMs can parse ```bash uv run ruff check -uv run pyright +uv run ty check --error-on-warning src/gh_llm tests uv run pytest -q ``` diff --git a/justfile b/justfile index 53f7fea..e07c070 100644 --- a/justfile +++ b/justfile @@ -12,7 +12,7 @@ fmt: prettier --write '**/*.md' lint: - uv run pyright src/gh_llm tests + uv run ty check --error-on-warning src/gh_llm tests uv run ruff check . fmt-docs: diff --git a/pyproject.toml b/pyproject.toml index 08d0e31..530c2fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,17 +30,12 @@ gh-llm = "gh_llm.__main__:main" [dependency-groups] dev = [ - "pyright>=1.1.407", + "ty>=0.0.32", "ruff>=0.14.10", "pytest>=9.0.2", "pytest-rerunfailures>=16.1", ] -[tool.pyright] -include = ["src/gh_llm", "tests"] -pythonVersion = "3.14" -typeCheckingMode = "strict" - [tool.ruff] line-length = 120 target-version = "py314" @@ -85,8 +80,6 @@ select = [ ] ignore = [ "E501", # line too long, duplicate with ruff fmt - "F401", # imported but unused, duplicate with pyright - "F841", # local variable is assigned to but never used, duplicate with pyright ] future-annotations = true diff --git a/src/gh_llm/pr_body.py b/src/gh_llm/pr_body.py index 0a05b6a..b0ed65e 100644 --- a/src/gh_llm/pr_body.py +++ b/src/gh_llm/pr_body.py @@ -79,7 +79,7 @@ def build_pull_request_body_scaffold( existing_titles = {normalize_section_title(title) for title in extract_markdown_section_titles(cleaned_template)} added_sections: list[str] = [] - blocks = [cleaned_template] + blocks: list[str] = [cleaned_template] for section in required_sections: normalized = normalize_section_title(section) diff --git a/tests/test_cli.py b/tests/test_cli.py index e248f4a..54c4554 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1576,7 +1576,7 @@ def test_extract_diff_hunks_prefers_first_added_line_for_right_side() -> None: ] ) - hunks = pr_commands._extract_diff_hunks(diff) # pyright: ignore[reportPrivateUsage] + hunks = pr_commands._extract_diff_hunks(diff) assert len(hunks) == 1 assert hunks[0].path == "paddle/phi/kernels/funcs/abs.h" @@ -1602,7 +1602,7 @@ def test_extract_diff_hunks_uses_real_new_file_line_numbers_on_right_side() -> N ] ) - hunks = pr_commands._extract_diff_hunks(diff) # pyright: ignore[reportPrivateUsage] + hunks = pr_commands._extract_diff_hunks(diff) assert len(hunks) == 1 assert hunks[0].path == "src/gh_llm/commands/pr.py" @@ -1612,7 +1612,7 @@ def test_extract_diff_hunks_uses_real_new_file_line_numbers_on_right_side() -> N def test_render_numbered_hunk_lines_preserves_real_right_side_line_numbers() -> None: - hunk = pr_commands._DiffHunk( # pyright: ignore[reportPrivateUsage] + hunk = pr_commands._DiffHunk( path="src/gh_llm/commands/pr.py", header="@@ -890,6 +890,7 @@ def _extract_diff_hunks(diff: str) -> list[_DiffHunk]:", anchor_line=893, @@ -1631,7 +1631,7 @@ def test_render_numbered_hunk_lines_preserves_real_right_side_line_numbers() -> match_paths={"src/gh_llm/commands/pr.py"}, ) - rendered = pr_commands._render_numbered_hunk_lines(hunk) # pyright: ignore[reportPrivateUsage] + rendered = pr_commands._render_numbered_hunk_lines(hunk) assert "L 890 R 890 | current_hunk_lines: list[str] = []" in rendered assert "L 891 R 891 | current_old_line = 0" in rendered @@ -1640,7 +1640,7 @@ def test_render_numbered_hunk_lines_preserves_real_right_side_line_numbers() -> def test_inline_review_thread_blocks_do_not_fallback_from_current_right_anchor_to_original_left_line() -> None: - current_hunk = pr_commands._DiffHunk( # pyright: ignore[reportPrivateUsage] + current_hunk = pr_commands._DiffHunk( path="paddle/phi/api/include/compat/ATen/ops/from_blob.h", header="@@ -18,3 +80,4 @@", anchor_line=81, @@ -1654,7 +1654,7 @@ def test_inline_review_thread_blocks_do_not_fallback_from_current_right_anchor_t right_commentable_lines={80, 81, 82}, match_paths={"paddle/phi/api/include/compat/ATen/ops/from_blob.h"}, ) - stale_hunk = pr_commands._DiffHunk( # pyright: ignore[reportPrivateUsage] + stale_hunk = pr_commands._DiffHunk( path="paddle/phi/api/include/compat/ATen/ops/from_blob.h", header="@@ -80,4 +210,1 @@", anchor_line=210, @@ -1684,7 +1684,7 @@ def test_inline_review_thread_blocks_do_not_fallback_from_current_right_anchor_t comments=(), ) - blocks_by_hunk = pr_commands._build_inline_review_thread_blocks_for_file( # pyright: ignore[reportPrivateUsage] + blocks_by_hunk = pr_commands._build_inline_review_thread_blocks_for_file( hunks=[current_hunk, stale_hunk], summaries=[summary], extra_contexts=[None, None], @@ -2897,7 +2897,7 @@ def test_pr_body_template_finds_docs_template_directory( def test_decode_repository_contents_text_returns_none_for_invalid_base64() -> None: payload: dict[str, object] = {"encoding": "base64", "content": "A"} - assert github_api._decode_repository_contents_text(payload) is None # pyright: ignore[reportPrivateUsage] + assert github_api._decode_repository_contents_text(payload) is None def test_pr_body_template_surfaces_non_404_lookup_failures( diff --git a/uv.lock b/uv.lock index 8c4a99e..d9a8195 100644 --- a/uv.lock +++ b/uv.lock @@ -18,20 +18,20 @@ source = { editable = "." } [package.dev-dependencies] dev = [ - { name = "pyright" }, { name = "pytest" }, { name = "pytest-rerunfailures" }, { name = "ruff" }, + { name = "ty" }, ] [package.metadata] [package.metadata.requires-dev] dev = [ - { name = "pyright", specifier = ">=1.1.407" }, { name = "pytest", specifier = ">=9.0.2" }, { name = "pytest-rerunfailures", specifier = ">=16.1" }, { name = "ruff", specifier = ">=0.14.10" }, + { name = "ty", specifier = ">=0.0.32" }, ] [[package]] @@ -43,15 +43,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892, upload-time = "2023-01-07T11:08:09.864Z" }, ] -[[package]] -name = "nodeenv" -version = "1.9.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, -] - [[package]] name = "packaging" version = "24.1" @@ -79,19 +70,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] -[[package]] -name = "pyright" -version = "1.1.407" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nodeenv" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a6/1b/0aa08ee42948b61745ac5b5b5ccaec4669e8884b53d31c8ec20b2fcd6b6f/pyright-1.1.407.tar.gz", hash = "sha256:099674dba5c10489832d4a4b2d302636152a9a42d317986c38474c76fe562262", size = 4122872, upload-time = "2025-10-24T23:17:15.145Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/93/b69052907d032b00c40cb656d21438ec00b3a471733de137a3f65a49a0a0/pyright-1.1.407-py3-none-any.whl", hash = "sha256:6dd419f54fcc13f03b52285796d65e639786373f433e243f8b94cf93a7444d21", size = 5997008, upload-time = "2025-10-24T23:17:13.159Z" }, -] - [[package]] name = "pytest" version = "9.0.2" @@ -148,10 +126,25 @@ wheels = [ ] [[package]] -name = "typing-extensions" -version = "4.12.2" +name = "ty" +version = "0.0.32" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321, upload-time = "2024-06-07T18:52:15.995Z" } +sdist = { url = "https://files.pythonhosted.org/packages/85/7e/2aa791c9ae7b8cd5024cd4122e92267f664ca954cea3def3211919fa3c1f/ty-0.0.32.tar.gz", hash = "sha256:8743174c5f920f6700a4a0c9de140109189192ba16226884cd50095b43b8a45c", size = 5522294, upload-time = "2026-04-20T19:29:01.626Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438, upload-time = "2024-06-07T18:52:13.582Z" }, + { url = "https://files.pythonhosted.org/packages/62/eb/1075dc6a49d7acbe2584ae4d5b410c41b1f177a5adcc567e09eca4c69000/ty-0.0.32-py3-none-linux_armv6l.whl", hash = "sha256:dacbc2f6cd698d488ae7436838ff929570455bf94bfa4d9fe57a630c552aff83", size = 10902959, upload-time = "2026-04-20T19:28:31.907Z" }, + { url = "https://files.pythonhosted.org/packages/33/d2/c35fc8bc66e98d1ee9b0f8ed319bf743e450e1f1e997574b178fab75670f/ty-0.0.32-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:914bbc4f605ce2a9e2a78982e28fae1d3359a169d141f9dc3b4c7749cd5eca81", size = 10726172, upload-time = "2026-04-20T19:28:44.765Z" }, + { url = "https://files.pythonhosted.org/packages/96/32/c827da3ca480456fb02d8cea68a2609273b6c220fea0be9a4c8d8470b86e/ty-0.0.32-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4787ac9fe1f86b1f3133f5c6732adbe2df5668b50c679ac6e2d98cd284da812f", size = 10163701, upload-time = "2026-04-20T19:28:27.005Z" }, + { url = "https://files.pythonhosted.org/packages/ba/9e/2734478fbdb90c160cb2813a3916a16a2af5c1e231f87d635f6131d781fb/ty-0.0.32-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8ea0a728af99fe40dd744cba6441a2404f80b7f4bde17aa6da393810af5ea57", size = 10656220, upload-time = "2026-04-20T19:29:03.814Z" }, + { url = "https://files.pythonhosted.org/packages/44/9f/0007da2d35e424debe7e9f86ffbc1ab7f60983cfbc5f0411324ab2de5292/ty-0.0.32-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2850561f9b018ae33d7e5bbfa0ac414d3c518513edcffe43877dc9801446b9c5", size = 10696086, upload-time = "2026-04-20T19:28:46.829Z" }, + { url = "https://files.pythonhosted.org/packages/3b/5e/ce5fd4ec803222ae3e69a76d2a2db2eed55e19f5b131702b9789ef45f93d/ty-0.0.32-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5fa2fb3c614349ee211d36476b49d88c5ef79a687cdb91b2872ad023b94d2f8", size = 11184800, upload-time = "2026-04-20T19:28:42.57Z" }, + { url = "https://files.pythonhosted.org/packages/6c/46/ebcf67a5999421331214aac51a7464db42de2be15bbe929c612a3ed0b039/ty-0.0.32-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b89969307ab2417d41c9be8059dd79feea577234e1e10d35132f5495e0d42c6", size = 11718718, upload-time = "2026-04-20T19:28:36.433Z" }, + { url = "https://files.pythonhosted.org/packages/18/2c/2141c86ed0ce0962b45cefb658a95e734f59759d47f20afdcd9c732910a1/ty-0.0.32-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b59868ede9b1d69a088f0d695df52a0061f95fa7baa1d5e0dc6fc9cf06e1334", size = 11346369, upload-time = "2026-04-20T19:28:48.967Z" }, + { url = "https://files.pythonhosted.org/packages/7a/da/ed6f772339cf29bd9a46def9d6db5084689eb574ee4d150ff704224c1ed8/ty-0.0.32-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8300caf35345498e9b9b03e550bba03cee8f5f5f8ab4c83c3b1ff1b7403b7d3a", size = 11280714, upload-time = "2026-04-20T19:28:51.516Z" }, + { url = "https://files.pythonhosted.org/packages/da/9b/c6813987edf4816a40e0c8e408b555f97d3f267c7b3a1688c8bbdf65609c/ty-0.0.32-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:583c7094f4574b02f724db924f98b804d1387a0bd9405ecb5e078cc0f47fbcfb", size = 10638806, upload-time = "2026-04-20T19:28:29.651Z" }, + { url = "https://files.pythonhosted.org/packages/4e/d4/0cefcbd2ad0f3d51762ccf58e652ec7da146eb6ae34f87228f6254bbb8be/ty-0.0.32-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e44ebe1bb4143a5628bc4db67ac0dfebe14594af671e4ee66f6f2e983da56501", size = 10726106, upload-time = "2026-04-20T19:29:06.3Z" }, + { url = "https://files.pythonhosted.org/packages/32/ad/2c8a97f91f06311f4367400f7d13534bbda2522c73c99a3e4c0757dff9b8/ty-0.0.32-py3-none-musllinux_1_2_i686.whl", hash = "sha256:06f17ada3e069cba6148342ef88e9929156beca8473e8d4f101b68f66c75643e", size = 10872951, upload-time = "2026-04-20T19:28:34.077Z" }, + { url = "https://files.pythonhosted.org/packages/ba/68/42293f9248106dd51875120971a5cc6ea315c2c4dcfb8e59aa063aa0af26/ty-0.0.32-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e96e60fa556cec04f15d7ea62d2ceee5982bd389233e961ab9fd42304e278175", size = 11363334, upload-time = "2026-04-20T19:28:54.036Z" }, + { url = "https://files.pythonhosted.org/packages/df/92/be9abf4d3e589ad5023e2ea965b93e204ec856420d46adf73c5c36c04678/ty-0.0.32-py3-none-win32.whl", hash = "sha256:2ff2ebb4986b24aebcf1444db7db5ca41b36086040e95eea9f8fb851c11e805c", size = 10260689, upload-time = "2026-04-20T19:28:56.541Z" }, + { url = "https://files.pythonhosted.org/packages/14/61/dc86acea899349d2579cb8419aecedd83dc504d7d6a10df65eef546c8300/ty-0.0.32-py3-none-win_amd64.whl", hash = "sha256:ba7284a4a954b598c1b31500352b3ec1f89bff533825592b5958848226fdc7ee", size = 11255371, upload-time = "2026-04-20T19:28:39.917Z" }, + { url = "https://files.pythonhosted.org/packages/43/01/beffec56d71ca25b343ede63adb076456b5b3e211f1c066452a44cd120b3/ty-0.0.32-py3-none-win_arm64.whl", hash = "sha256:7e10aadbdbda989a7d567ee6a37f8b98d4d542e31e3b190a2879fd581f75d658", size = 10658087, upload-time = "2026-04-20T19:28:59.286Z" }, ]