Skip to content

Commit 9f17b51

Browse files
authored
Merge branch 'main' into always-gen-buildfile
2 parents d4c362b + cd6948a commit 9f17b51

File tree

107 files changed

+1064
-50
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+1064
-50
lines changed

.bazelrc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
# (Note, we cannot use `common --deleted_packages` because the bazel version command doesn't support it)
55
# To update these lines, execute
66
# `bazel run @rules_bazel_integration_test//tools:update_deleted_packages`
7-
build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered,tests/modules/another_module,tests/modules/other,tests/modules/other/nspkg_delta,tests/modules/other/nspkg_gamma,tests/modules/other/nspkg_single,tests/modules/other/simple_v1,tests/modules/other/simple_v2,tests/modules/other/with_external_data
8-
query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered,tests/modules/another_module,tests/modules/other,tests/modules/other/nspkg_delta,tests/modules/other/nspkg_gamma,tests/modules/other/nspkg_single,tests/modules/other/simple_v1,tests/modules/other/simple_v2,tests/modules/other/with_external_data
7+
build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered,tests/modules/another_module,tests/modules/other,tests/modules/other/nspkg_delta,tests/modules/other/nspkg_gamma,tests/modules/other/nspkg_single,tests/modules/other/simple_v1,tests/modules/other/simple_v2,tests/modules/other/with_external_data,tests/whl_with_build_files/testdata,tests/whl_with_build_files/testdata/somepkg,tests/whl_with_build_files/testdata/somepkg-1.0.dist-info,tests/whl_with_build_files/testdata/somepkg/subpkg
8+
query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered,tests/modules/another_module,tests/modules/other,tests/modules/other/nspkg_delta,tests/modules/other/nspkg_gamma,tests/modules/other/nspkg_single,tests/modules/other/simple_v1,tests/modules/other/simple_v2,tests/modules/other/with_external_data,tests/whl_with_build_files/testdata,tests/whl_with_build_files/testdata/somepkg,tests/whl_with_build_files/testdata/somepkg-1.0.dist-info,tests/whl_with_build_files/testdata/somepkg/subpkg
99

1010
test --test_output=errors
1111

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,18 @@ END_UNRELEASED_TEMPLATE
6666
* (pypi) Fixes an issue where builds using a `bazel vendor` vendor directory
6767
would fail if the constraints file contained environment markers. Fixes
6868
[#2996](https://github.com/bazel-contrib/rules_python/issues/2996).
69+
* (pypi) Wheels with BUILD.bazel (or other special Bazel files) no longer
70+
result in missing files at runtime
71+
([#2782](https://github.com/bazel-contrib/rules_python/issues/2782)).
6972

7073
{#v0-0-0-added}
7174
### Added
7275
* (pypi) To configure the environment for `requirements.txt` evaluation, use the newly added
7376
developer preview of the `pip.default` tag class. Only `rules_python` and root modules can use
7477
this feature. You can also configure custom `config_settings` using `pip.default`.
78+
* (gazelle) New directive `gazelle:python_generate_pyi_deps`; when `true`,
79+
dependencies added to satisfy type-only imports (`if TYPE_CHECKING`) and type
80+
stub packages are added to `pyi_deps` instead of `deps`.
7581

7682
{#v0-0-0-removed}
7783
### Removed

MODULE.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ use_repo(
103103
internal_dev_deps,
104104
"buildkite_config",
105105
"rules_python_runtime_env_tc_info",
106+
"somepkg_with_build_files",
107+
"whl_with_build_files",
106108
)
107109

108110
# Add gazelle plugin so that we can run the gazelle example as an e2e integration

gazelle/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ The following documentation covers using bzlmod.
2424

2525
## Adding Gazelle to your project
2626

27-
First, you'll need to add Gazelle to your `MODULES.bazel` file.
27+
First, you'll need to add Gazelle to your `MODULE.bazel` file.
2828
Get the current version of Gazelle from there releases here: https://github.com/bazelbuild/bazel-gazelle/releases/.
2929

3030

@@ -222,6 +222,8 @@ Python-specific directives are as follows:
222222
| Controls how distribution names in labels to third-party deps are normalized. Useful for using Gazelle plugin with other rules with different label conventions (e.g. `rules_pycross` uses PEP-503). Can be "snake_case", "none", or "pep503". |
223223
| `# gazelle:experimental_allow_relative_imports` | `false` |
224224
| Controls whether Gazelle resolves dependencies for import statements that use paths relative to the current package. Can be "true" or "false".|
225+
| `# gazelle:python_generate_pyi_deps` | `false` |
226+
| Controls whether to generate a separate `pyi_deps` attribute for type-checking dependencies or merge them into the regular `deps` attribute. When `false` (default), type-checking dependencies are merged into `deps` for backward compatibility. When `true`, generates separate `pyi_deps`. Imports in blocks with the format `if typing.TYPE_CHECKING:`/`if TYPE_CHECKING:` and type-only stub packages (eg. boto3-stubs) are recognized as type-checking dependencies. |
225227

226228
#### Directive: `python_root`:
227229

gazelle/python/configure.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ func (py *Configurer) KnownDirectives() []string {
6868
pythonconfig.TestFilePattern,
6969
pythonconfig.LabelConvention,
7070
pythonconfig.LabelNormalization,
71+
pythonconfig.GeneratePyiDeps,
7172
pythonconfig.ExperimentalAllowRelativeImports,
7273
}
7374
}
@@ -230,6 +231,12 @@ func (py *Configurer) Configure(c *config.Config, rel string, f *rule.File) {
230231
pythonconfig.ExperimentalAllowRelativeImports, rel, d.Value)
231232
}
232233
config.SetExperimentalAllowRelativeImports(v)
234+
case pythonconfig.GeneratePyiDeps:
235+
v, err := strconv.ParseBool(strings.TrimSpace(d.Value))
236+
if err != nil {
237+
log.Fatal(err)
238+
}
239+
config.SetGeneratePyiDeps(v)
233240
}
234241
}
235242

gazelle/python/file_parser.go

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@ type ParserOutput struct {
4747
}
4848

4949
type FileParser struct {
50-
code []byte
51-
relFilepath string
52-
output ParserOutput
50+
code []byte
51+
relFilepath string
52+
output ParserOutput
53+
inTypeCheckingBlock bool
5354
}
5455

5556
func NewFileParser() *FileParser {
@@ -158,6 +159,7 @@ func (p *FileParser) parseImportStatements(node *sitter.Node) bool {
158159
continue
159160
}
160161
m.Filepath = p.relFilepath
162+
m.TypeCheckingOnly = p.inTypeCheckingBlock
161163
if strings.HasPrefix(m.Name, ".") {
162164
continue
163165
}
@@ -178,6 +180,7 @@ func (p *FileParser) parseImportStatements(node *sitter.Node) bool {
178180
m.Filepath = p.relFilepath
179181
m.From = from
180182
m.Name = fmt.Sprintf("%s.%s", from, m.Name)
183+
m.TypeCheckingOnly = p.inTypeCheckingBlock
181184
p.output.Modules = append(p.output.Modules, m)
182185
}
183186
} else {
@@ -202,10 +205,43 @@ func (p *FileParser) SetCodeAndFile(code []byte, relPackagePath, filename string
202205
p.output.FileName = filename
203206
}
204207

208+
// isTypeCheckingBlock returns true if the given node is an `if TYPE_CHECKING:` block.
209+
func (p *FileParser) isTypeCheckingBlock(node *sitter.Node) bool {
210+
if node.Type() != sitterNodeTypeIfStatement || node.ChildCount() < 2 {
211+
return false
212+
}
213+
214+
condition := node.Child(1)
215+
216+
// Handle `if TYPE_CHECKING:`
217+
if condition.Type() == sitterNodeTypeIdentifier && condition.Content(p.code) == "TYPE_CHECKING" {
218+
return true
219+
}
220+
221+
// Handle `if typing.TYPE_CHECKING:`
222+
if condition.Type() == "attribute" && condition.ChildCount() >= 3 {
223+
object := condition.Child(0)
224+
attr := condition.Child(2)
225+
if object.Type() == sitterNodeTypeIdentifier && object.Content(p.code) == "typing" &&
226+
attr.Type() == sitterNodeTypeIdentifier && attr.Content(p.code) == "TYPE_CHECKING" {
227+
return true
228+
}
229+
}
230+
231+
return false
232+
}
233+
205234
func (p *FileParser) parse(ctx context.Context, node *sitter.Node) {
206235
if node == nil {
207236
return
208237
}
238+
239+
// Check if this is a TYPE_CHECKING block
240+
wasInTypeCheckingBlock := p.inTypeCheckingBlock
241+
if p.isTypeCheckingBlock(node) {
242+
p.inTypeCheckingBlock = true
243+
}
244+
209245
for i := 0; i < int(node.ChildCount()); i++ {
210246
if err := ctx.Err(); err != nil {
211247
return
@@ -219,6 +255,9 @@ func (p *FileParser) parse(ctx context.Context, node *sitter.Node) {
219255
}
220256
p.parse(ctx, child)
221257
}
258+
259+
// Restore the previous state
260+
p.inTypeCheckingBlock = wasInTypeCheckingBlock
222261
}
223262

224263
func (p *FileParser) Parse(ctx context.Context) (*ParserOutput, error) {

gazelle/python/file_parser_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,40 @@ func TestParseFull(t *testing.T) {
254254
FileName: "a.py",
255255
}, *output)
256256
}
257+
258+
func TestTypeCheckingImports(t *testing.T) {
259+
code := `
260+
import sys
261+
from typing import TYPE_CHECKING
262+
263+
if TYPE_CHECKING:
264+
import boto3
265+
from rest_framework import serializers
266+
267+
def example_function():
268+
_ = sys.version_info
269+
`
270+
p := NewFileParser()
271+
p.SetCodeAndFile([]byte(code), "", "test.py")
272+
273+
result, err := p.Parse(context.Background())
274+
if err != nil {
275+
t.Fatalf("Failed to parse: %v", err)
276+
}
277+
278+
// Check that we found the expected modules
279+
expectedModules := map[string]bool{
280+
"sys": false,
281+
"typing.TYPE_CHECKING": false,
282+
"boto3": true,
283+
"rest_framework.serializers": true,
284+
}
285+
286+
for _, mod := range result.Modules {
287+
if expected, exists := expectedModules[mod.Name]; exists {
288+
if mod.TypeCheckingOnly != expected {
289+
t.Errorf("Module %s: expected TypeCheckingOnly=%v, got %v", mod.Name, expected, mod.TypeCheckingOnly)
290+
}
291+
}
292+
}
293+
}

gazelle/python/kinds.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ var pyKinds = map[string]rule.KindInfo{
4646
},
4747
ResolveAttrs: map[string]bool{
4848
"deps": true,
49+
"pyi_deps": true,
4950
},
5051
},
5152
pyLibraryKind: {
@@ -62,6 +63,7 @@ var pyKinds = map[string]rule.KindInfo{
6263
},
6364
ResolveAttrs: map[string]bool{
6465
"deps": true,
66+
"pyi_deps": true,
6567
},
6668
},
6769
pyTestKind: {
@@ -78,6 +80,7 @@ var pyKinds = map[string]rule.KindInfo{
7880
},
7981
ResolveAttrs: map[string]bool{
8082
"deps": true,
83+
"pyi_deps": true,
8184
},
8285
},
8386
}

gazelle/python/parser.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,9 @@ func (p *python3Parser) parse(pyFilenames *treeset.Set) (*treeset.Set, map[strin
112112
continue
113113
}
114114

115-
modules.Add(m)
115+
addModuleToTreeSet(modules, m)
116116
if res.HasMain {
117-
mainModules[res.FileName].Add(m)
117+
addModuleToTreeSet(mainModules[res.FileName], m)
118118
}
119119
}
120120

@@ -158,13 +158,24 @@ type Module struct {
158158
// If this was a from import, e.g. from foo import bar, From indicates the module
159159
// from which it is imported.
160160
From string `json:"from"`
161+
// Whether this import is type-checking only (inside if TYPE_CHECKING block).
162+
TypeCheckingOnly bool `json:"type_checking_only"`
161163
}
162164

163165
// moduleComparator compares modules by name.
164166
func moduleComparator(a, b interface{}) int {
165167
return godsutils.StringComparator(a.(Module).Name, b.(Module).Name)
166168
}
167169

170+
// addModuleToTreeSet adds a module to a treeset.Set, ensuring that a TypeCheckingOnly=false module is
171+
// prefered over a TypeCheckingOnly=true module.
172+
func addModuleToTreeSet(set *treeset.Set, mod Module) {
173+
if mod.TypeCheckingOnly && set.Contains(mod) {
174+
return
175+
}
176+
set.Add(mod)
177+
}
178+
168179
// annotationKind represents Gazelle annotation kinds.
169180
type annotationKind string
170181

0 commit comments

Comments
 (0)