From 7005ac1112deb89375871b3a9b2673be81a68014 Mon Sep 17 00:00:00 2001 From: Joshua Cannon Date: Fri, 27 Feb 2026 15:57:08 +0000 Subject: [PATCH 1/4] Add Python tree-sitter-grammer --- MODULE.bazel | 13 ++++++ common/treesitter/grammars/python/BUILD.bazel | 20 +++++++++ common/treesitter/grammars/python/binding.go | 17 ++++++++ .../grammars/python/binding_test.go | 43 +++++++++++++++++++ common/treesitter/parser.go | 4 ++ 5 files changed, 97 insertions(+) create mode 100644 common/treesitter/grammars/python/BUILD.bazel create mode 100644 common/treesitter/grammars/python/binding.go create mode 100644 common/treesitter/grammars/python/binding_test.go diff --git a/MODULE.bazel b/MODULE.bazel index 13636ddc..ca7a3bc6 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -101,6 +101,19 @@ visibility = ["//visibility:public"], urls = ["https://github.com/tree-sitter/tree-sitter-typescript/archive/v0.23.2.tar.gz"], ) +http_archive( + name = "tree-sitter-python", + build_file_content = """ +filegroup( + name = "srcs", + srcs = glob(["src/**/*.c", "src/**/*.h"]), + visibility = ["//visibility:public"], +) +""", + sha256 = "bc7c1c922b14cb0edd75c0400a63ff260e09bd02684351ed5d38586b5771cd69", + urls = ["https://github.com/tree-sitter/tree-sitter-python/releases/download/v0.23.6/tree-sitter-python.tar.xz"], +) + http_archive( name = "tree-sitter-ruby", build_file_content = """ diff --git a/common/treesitter/grammars/python/BUILD.bazel b/common/treesitter/grammars/python/BUILD.bazel new file mode 100644 index 00000000..456bc170 --- /dev/null +++ b/common/treesitter/grammars/python/BUILD.bazel @@ -0,0 +1,20 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "python", + srcs = [ + "binding.go", + "@tree-sitter-python//:srcs", #keep + ], + cgo = True, + copts = ["-Iexternal/*tree-sitter-python"], #keep + importpath = "github.com/aspect-build/aspect-gazelle/common/treesitter/grammars/python", + visibility = ["//visibility:public"], + deps = ["//common/treesitter"], +) + +go_test( + name = "binding_test", + srcs = ["binding_test.go"], + embed = [":python"], +) diff --git a/common/treesitter/grammars/python/binding.go b/common/treesitter/grammars/python/binding.go new file mode 100644 index 00000000..7e491eb7 --- /dev/null +++ b/common/treesitter/grammars/python/binding.go @@ -0,0 +1,17 @@ +package python + +//#include "tree_sitter/parser.h" +//TSLanguage *tree_sitter_python(); +import "C" +import ( + "unsafe" + + "github.com/aspect-build/aspect-gazelle/common/treesitter" +) + +func NewLanguage() treesitter.Language { + return treesitter.NewLanguage( + treesitter.Python, + unsafe.Pointer(C.tree_sitter_python()), + ) +} diff --git a/common/treesitter/grammars/python/binding_test.go b/common/treesitter/grammars/python/binding_test.go new file mode 100644 index 00000000..0226d91a --- /dev/null +++ b/common/treesitter/grammars/python/binding_test.go @@ -0,0 +1,43 @@ +package python + +import ( + "testing" + + treeutils "github.com/aspect-build/aspect-gazelle/common/treesitter" +) + +func TestParsePython(t *testing.T) { + for _, tc := range []struct { + desc string + src string + }{ + { + desc: "empty file", + src: "", + }, + { + desc: "function definition", + src: ` +def hello(): + return "hello" +`, + }, + { + desc: "import statement", + src: `import os`, + }, + { + desc: "from import statement", + src: `from os import path`, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + lang := NewLanguage() + tree, err := treeutils.ParseSourceCode(lang, "test.py", []byte(tc.src)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + tree.Close() + }) + } +} diff --git a/common/treesitter/parser.go b/common/treesitter/parser.go index 04ebce6d..2298f6de 100644 --- a/common/treesitter/parser.go +++ b/common/treesitter/parser.go @@ -54,6 +54,7 @@ const ( Go = "go" Rust = "rust" Ruby = "ruby" + Python = "python" ) type Language any @@ -154,6 +155,9 @@ var extLanguages = map[string]LanguageGrammar{ "thor": Ruby, "jbuilder": Ruby, "rabl": Ruby, + + "py": Python, + "pyi": Python, } // In theory, this is a mirror of From 943ae55ddb7af7b11b6265c2a56769f5b46d0075 Mon Sep 17 00:00:00 2001 From: Joshua Cannon Date: Fri, 27 Feb 2026 16:09:18 +0000 Subject: [PATCH 2/4] remove the test --- common/treesitter/grammars/python/BUILD.bazel | 8 +--- .../grammars/python/binding_test.go | 43 ------------------- 2 files changed, 1 insertion(+), 50 deletions(-) delete mode 100644 common/treesitter/grammars/python/binding_test.go diff --git a/common/treesitter/grammars/python/BUILD.bazel b/common/treesitter/grammars/python/BUILD.bazel index 456bc170..c40a71ea 100644 --- a/common/treesitter/grammars/python/BUILD.bazel +++ b/common/treesitter/grammars/python/BUILD.bazel @@ -1,4 +1,4 @@ -load("@rules_go//go:def.bzl", "go_library", "go_test") +load("@rules_go//go:def.bzl", "go_library") go_library( name = "python", @@ -12,9 +12,3 @@ go_library( visibility = ["//visibility:public"], deps = ["//common/treesitter"], ) - -go_test( - name = "binding_test", - srcs = ["binding_test.go"], - embed = [":python"], -) diff --git a/common/treesitter/grammars/python/binding_test.go b/common/treesitter/grammars/python/binding_test.go deleted file mode 100644 index 0226d91a..00000000 --- a/common/treesitter/grammars/python/binding_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package python - -import ( - "testing" - - treeutils "github.com/aspect-build/aspect-gazelle/common/treesitter" -) - -func TestParsePython(t *testing.T) { - for _, tc := range []struct { - desc string - src string - }{ - { - desc: "empty file", - src: "", - }, - { - desc: "function definition", - src: ` -def hello(): - return "hello" -`, - }, - { - desc: "import statement", - src: `import os`, - }, - { - desc: "from import statement", - src: `from os import path`, - }, - } { - t.Run(tc.desc, func(t *testing.T) { - lang := NewLanguage() - tree, err := treeutils.ParseSourceCode(lang, "test.py", []byte(tc.src)) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - tree.Close() - }) - } -} From 57dc1f1f3069832ecdd84c26e7fa767fafc4ae48 Mon Sep 17 00:00:00 2001 From: Joshua Cannon Date: Mon, 2 Mar 2026 16:00:56 +0000 Subject: [PATCH 3/4] add tests --- language/orion/queries/BUILD.bazel | 1 + language/orion/queries/ast.go | 3 ++ .../tests/starzelle/query-python/BUILD.in | 1 + .../tests/starzelle/query-python/BUILD.out | 24 ++++++++++ .../tests/starzelle/query-python/WORKSPACE | 1 + .../orion/tests/starzelle/query-python/a.py | 2 + .../orion/tests/starzelle/query-python/b.py | 1 + .../tests/starzelle/query-python/imports.axl | 46 +++++++++++++++++++ .../tests/starzelle/query-python/lib/BUILD.in | 0 .../starzelle/query-python/lib/BUILD.out | 6 +++ .../tests/starzelle/query-python/lib/l.py | 1 + .../tests/starzelle/query-python/sub/s.py | 3 ++ 12 files changed, 89 insertions(+) create mode 100644 language/orion/tests/starzelle/query-python/BUILD.in create mode 100644 language/orion/tests/starzelle/query-python/BUILD.out create mode 100644 language/orion/tests/starzelle/query-python/WORKSPACE create mode 100644 language/orion/tests/starzelle/query-python/a.py create mode 100644 language/orion/tests/starzelle/query-python/b.py create mode 100644 language/orion/tests/starzelle/query-python/imports.axl create mode 100644 language/orion/tests/starzelle/query-python/lib/BUILD.in create mode 100644 language/orion/tests/starzelle/query-python/lib/BUILD.out create mode 100644 language/orion/tests/starzelle/query-python/lib/l.py create mode 100644 language/orion/tests/starzelle/query-python/sub/s.py diff --git a/language/orion/queries/BUILD.bazel b/language/orion/queries/BUILD.bazel index ff184ee4..766e4415 100644 --- a/language/orion/queries/BUILD.bazel +++ b/language/orion/queries/BUILD.bazel @@ -19,6 +19,7 @@ go_library( "@aspect_gazelle//common/treesitter/grammars/golang", "@aspect_gazelle//common/treesitter/grammars/java", "@aspect_gazelle//common/treesitter/grammars/json", + "@aspect_gazelle//common/treesitter/grammars/python", "@aspect_gazelle//common/treesitter/grammars/kotlin", "@aspect_gazelle//common/treesitter/grammars/ruby", "@aspect_gazelle//common/treesitter/grammars/rust", diff --git a/language/orion/queries/ast.go b/language/orion/queries/ast.go index 92671f75..f218d2e9 100644 --- a/language/orion/queries/ast.go +++ b/language/orion/queries/ast.go @@ -10,6 +10,7 @@ import ( "github.com/aspect-build/aspect-gazelle/common/treesitter/grammars/java" "github.com/aspect-build/aspect-gazelle/common/treesitter/grammars/json" "github.com/aspect-build/aspect-gazelle/common/treesitter/grammars/kotlin" + "github.com/aspect-build/aspect-gazelle/common/treesitter/grammars/python" "github.com/aspect-build/aspect-gazelle/common/treesitter/grammars/ruby" "github.com/aspect-build/aspect-gazelle/common/treesitter/grammars/rust" "github.com/aspect-build/aspect-gazelle/common/treesitter/grammars/starlark" @@ -72,6 +73,8 @@ func toTreeLanguage(fileName string, queries plugin.NamedQueries) treesitter.Lan return json.NewLanguage() case treesitter.Kotlin: return kotlin.NewLanguage() + case treesitter.Python: + return python.NewLanguage() case treesitter.Ruby: return ruby.NewLanguage() case treesitter.Rust: diff --git a/language/orion/tests/starzelle/query-python/BUILD.in b/language/orion/tests/starzelle/query-python/BUILD.in new file mode 100644 index 00000000..8ec211d9 --- /dev/null +++ b/language/orion/tests/starzelle/query-python/BUILD.in @@ -0,0 +1 @@ +# gazelle:generation_mode update_only diff --git a/language/orion/tests/starzelle/query-python/BUILD.out b/language/orion/tests/starzelle/query-python/BUILD.out new file mode 100644 index 00000000..38b36217 --- /dev/null +++ b/language/orion/tests/starzelle/query-python/BUILD.out @@ -0,0 +1,24 @@ +load("@deps-test//my:rules.bzl", "x_lib") + +# gazelle:generation_mode update_only + +x_lib( + name = "a_lib", + srcs = ["a.py"], + deps = [ + ":b_lib", + ":s_lib", + ], +) + +x_lib( + name = "b_lib", + srcs = ["b.py"], + deps = ["//lib:l_lib"], +) + +x_lib( + name = "s_lib", + srcs = ["sub/s.py"], + deps = ["//lib:l_lib"], +) diff --git a/language/orion/tests/starzelle/query-python/WORKSPACE b/language/orion/tests/starzelle/query-python/WORKSPACE new file mode 100644 index 00000000..90b3a660 --- /dev/null +++ b/language/orion/tests/starzelle/query-python/WORKSPACE @@ -0,0 +1 @@ +workspace(name = "query-python") diff --git a/language/orion/tests/starzelle/query-python/a.py b/language/orion/tests/starzelle/query-python/a.py new file mode 100644 index 00000000..411d99f1 --- /dev/null +++ b/language/orion/tests/starzelle/query-python/a.py @@ -0,0 +1,2 @@ +import b +import sub.s diff --git a/language/orion/tests/starzelle/query-python/b.py b/language/orion/tests/starzelle/query-python/b.py new file mode 100644 index 00000000..af58f369 --- /dev/null +++ b/language/orion/tests/starzelle/query-python/b.py @@ -0,0 +1 @@ +import lib.l diff --git a/language/orion/tests/starzelle/query-python/imports.axl b/language/orion/tests/starzelle/query-python/imports.axl new file mode 100644 index 00000000..3a87f961 --- /dev/null +++ b/language/orion/tests/starzelle/query-python/imports.axl @@ -0,0 +1,46 @@ +aspect.gazelle_rule_kind("x_lib", { + "From": "@deps-test//my:rules.bzl", + "MergeableAttrs": ["srcs"], + "ResolveAttrs": ["deps"], +}) + +def prepare(_): + return aspect.PrepareResult( + sources = [aspect.SourceExtensions(".py")], + queries = { + "imports": aspect.AstQuery( + grammar = "python", + filter = "**/*.py", + query = "(import_statement name: (dotted_name) @imp)", + ), + }, + ) + +def declare(ctx): + for file in ctx.sources: + rel_modname = file.path[:file.path.rindex(".")].replace("/", ".") + ctx.targets.add( + name = path.base(file.path[:file.path.rindex(".")]) + "_lib", + kind = "x_lib", + attrs = { + "srcs": [file.path], + "deps": [ + aspect.Import( + id = i.captures["imp"], + provider = "x", + src = file.path, + ) + for i in file.query_results["imports"] + ], + }, + symbols = [aspect.Symbol( + id = ".".join([ctx.rel, rel_modname]) if ctx.rel else rel_modname, + provider = "x", + )], + ) + +aspect.orion_extension( + id = "python-test", + prepare = prepare, + declare = declare, +) diff --git a/language/orion/tests/starzelle/query-python/lib/BUILD.in b/language/orion/tests/starzelle/query-python/lib/BUILD.in new file mode 100644 index 00000000..e69de29b diff --git a/language/orion/tests/starzelle/query-python/lib/BUILD.out b/language/orion/tests/starzelle/query-python/lib/BUILD.out new file mode 100644 index 00000000..269b2d3c --- /dev/null +++ b/language/orion/tests/starzelle/query-python/lib/BUILD.out @@ -0,0 +1,6 @@ +load("@deps-test//my:rules.bzl", "x_lib") + +x_lib( + name = "l_lib", + srcs = ["l.py"], +) diff --git a/language/orion/tests/starzelle/query-python/lib/l.py b/language/orion/tests/starzelle/query-python/lib/l.py new file mode 100644 index 00000000..296d5492 --- /dev/null +++ b/language/orion/tests/starzelle/query-python/lib/l.py @@ -0,0 +1 @@ +console.log(1); diff --git a/language/orion/tests/starzelle/query-python/sub/s.py b/language/orion/tests/starzelle/query-python/sub/s.py new file mode 100644 index 00000000..fb5ba935 --- /dev/null +++ b/language/orion/tests/starzelle/query-python/sub/s.py @@ -0,0 +1,3 @@ +import lib.l + +print(1) From 8377b2c904f6755f675efcf5a08725ae3db0b175 Mon Sep 17 00:00:00 2001 From: Joshua Cannon Date: Mon, 2 Mar 2026 16:04:15 +0000 Subject: [PATCH 4/4] reorder --- language/orion/queries/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/language/orion/queries/BUILD.bazel b/language/orion/queries/BUILD.bazel index 766e4415..9c493ddc 100644 --- a/language/orion/queries/BUILD.bazel +++ b/language/orion/queries/BUILD.bazel @@ -19,8 +19,8 @@ go_library( "@aspect_gazelle//common/treesitter/grammars/golang", "@aspect_gazelle//common/treesitter/grammars/java", "@aspect_gazelle//common/treesitter/grammars/json", - "@aspect_gazelle//common/treesitter/grammars/python", "@aspect_gazelle//common/treesitter/grammars/kotlin", + "@aspect_gazelle//common/treesitter/grammars/python", "@aspect_gazelle//common/treesitter/grammars/ruby", "@aspect_gazelle//common/treesitter/grammars/rust", "@aspect_gazelle//common/treesitter/grammars/starlark",