feat(python): add Pyrefly language server (#911)

Pyrefly (`pyrefly lsp`) joins basedpyright, Pyright and ty as a fallback Python language server. It is installable from Tools as a managed virtualenv tool and is listed among the interchangeable type checkers, before Ruff, so Ruff still runs after them.

Pyrefly only reports type errors in projects with a Pyrefly configuration (`pyrefly.toml` or `[tool.pyrefly]`); hover, completion and navigation work without one. A real-server test (ignored by default, needs `pyrefly` on PATH) covers startup, go-to-definition and diagnostics.

Co-authored-by: pcastro93 <[email protected]>
Цей коміт міститься в:
Piettro authored and GitHub committed 2026-11-03 14:42:45 +08:00
1 джерело 038c23a2c8
коміт b55c398fb5
9 files changed
+83 -10

No files matched your search

+4 -3
Переглянути файл
@@ -89,7 +89,7 @@ describe("Language Servers page settings", () => {
const ty = details("ty (Python)");
expect(within(ty).getByRole("button", { name: "Language server for Python" })).toHaveTextContent("Automatic");
// The language is in the label already, so names drop a "(Python)" suffix.
expect(within(ty).getByText(/basedpyright → Pyright → ty\.$/)).toBeInTheDocument();
expect(within(ty).getByText(/basedpyright → Pyright → ty → Pyrefly\.$/)).toBeInTheDocument();
await user.click(listItem("gopls")!);
expect(within(details("gopls")).getByRole("checkbox", { name: /Use gopls/ })).toBeInTheDocument();
expect(within(details("gopls")).queryByRole("button", { name: /^Language server for/ })).toBeNull();
@@ -108,7 +108,7 @@ describe("Language Servers page settings", () => {
expect(picker).toHaveTextContent("ty");
await user.click(picker);
await user.click(screen.getByRole("option", { name: /Automatic/ }));
for (const name of ["basedpyright", "pyright", "ty"]) {
for (const name of ["basedpyright", "pyright", "ty", "pyrefly"]) {
expect(stagedFor(`languageServers.${name}.enabled`)).toBeNull();
expect(useTestForm.getState().values).not.toHaveProperty(`languageServers.${name}.enabled`);
}
@@ -127,10 +127,11 @@ describe("Language Servers page settings", () => {
expect(stagedFor("languageServers.basedpyright.enabled")).toBe(false);
expect(stagedFor("languageServers.pyright.enabled")).toBe(true);
expect(stagedFor("languageServers.ty.enabled")).toBe(false);
expect(stagedFor("languageServers.pyrefly.enabled")).toBe(false);
expect(picker).toHaveTextContent("Pyright");
await user.click(picker);
await user.click(screen.getByRole("option", { name: /Automatic/ }));
for (const name of ["basedpyright", "pyright", "ty"]) {
for (const name of ["basedpyright", "pyright", "ty", "pyrefly"]) {
expect(stagedFor(`languageServers.${name}.enabled`)).toBe(true);
}
});
+10 -3
Переглянути файл
@@ -94,13 +94,20 @@ export function sampleTools(): ToolInfo[] {
version: "4.3.3",
path: "/opt/homebrew/bin/typescript-language-server",
}),
...["basedpyright", "pyright", "ty"].map((name) =>
...["basedpyright", "pyright", "ty", "pyrefly"].map((name) =>
tool({
name,
displayName: name === "pyright" ? "Pyright" : name === "ty" ? "ty (Python)" : name,
displayName:
name === "pyright"
? "Pyright"
: name === "ty"
? "ty (Python)"
: name === "pyrefly"
? "Pyrefly (Python)"
: name,
languages: ["Python"],
installMethod: "uv (virtualenv)",
alternatives: ["basedpyright", "pyright", "ty"],
alternatives: ["basedpyright", "pyright", "ty", "pyrefly"],
}),
),
tool({ name: "gopls", languages: ["Go"], installMethod: "go install" }),
+1
Переглянути файл
@@ -149,6 +149,7 @@ const UNTRANSLATED = new Set<string>([
"OpenIDEA",
"Spring Boot",
"PostgreSQL",
"Pyrefly",
"Pyright",
"pytest",
"Rust",