Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions gazelle/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,6 +147,12 @@ Python-specific directives are as follows:
| Controls the `py_test` naming convention. Follows the same interpolation rules as `python_library_naming_convention`. | |
| `# gazelle:resolve py ...` | n/a |
| Instructs the plugin what target to add as a dependency to satisfy a given import statement. The syntax is `# gazelle:resolve py import-string label` where `import-string` is the symbol in the python `import` statement, and `label` is the Bazel label that Gazelle should write in `deps`. | |
| `# gazelle:python_pip_repo_naming_convention` | `$repo_name$_$distribution_name$` |
| Controls the external dependency label naming convention. It interpolates `$repo_name$` and `$distribution_name$` with the Bazel external pip repository name and the sanitized Python package name respectively. E.g. if the Bazel external pip repository name is `my_pip_deps` and we are resolving external Python package named `flake-bugbear`, setting this to `$repo_name$_host_$distribution_name$` would result in a generated target named `my_pip_deps_host_flake8_bugbear`. | |
| `# gazelle:python_pip_package_naming_convention` | n/a |
| Controls the external dependency label naming convention. It interpolates `$distribution_name$` with the sanitized Python package name. See `gazelle:python_pip_repo_naming_convention` for details. This may be useful if you have `alias` targets which point to platform specific Python wheels in your repo, e.g. `//third_party/pip:flake8_bugbear_alias`. | |
| `# gazelle:python_pip_target_naming_convention` | `pkg` |
| Controls the external dependency label naming convention. It interpolates `$distribution_name$` with the sanitized Python package name respectively. See `gazelle:python_pip_repo_naming_convention` for details. This may be useful if you have `alias` targets which point to platform specific Python wheels in your repo, e.g. `//third_party/pip:flake8_bugbear_alias` or if you are using `gazelle` with `bzlmod`. | |

### Libraries

Expand Down
9 changes: 9 additions & 0 deletions gazelle/configure.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,9 @@ func (py *Configurer) KnownDirectives() []string {
pythonconfig.LibraryNamingConvention,
pythonconfig.BinaryNamingConvention,
pythonconfig.TestNamingConvention,
pythonconfig.PipRepoNamingConvention,
pythonconfig.PipPackageNamingConvention,
pythonconfig.PipTargetNamingConvention,
}
}

Expand DownExpand Up@@ -136,6 +139,12 @@ func (py *Configurer) Configure(c *config.Config, rel string, f *rule.File) {
config.SetBinaryNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.TestNamingConvention:
config.SetTestNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipRepoNamingConvention:
config.SetPipRepoNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipPackageNamingConvention:
config.SetPipPackageNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipTargetNamingConvention:
config.SetPipTargetNamingConvention(strings.TrimSpace(d.Value))
}
}

Expand Down
8 changes: 7 additions & 1 deletion gazelle/pythonconfig/BUILD.bazel
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "pythonconfig",
Expand All@@ -20,3 +20,9 @@ filegroup(
srcs = glob(["**"]),
visibility = ["//gazelle:__pkg__"],
)

go_test(
name = "pythonconfig_test",
srcs = ["pythonconfig_test.go"],
embed = [":pythonconfig"],
)
135 changes: 98 additions & 37 deletions gazelle/pythonconfig/pythonconfig.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,6 +49,17 @@ const (
// naming convention. See python_library_naming_convention for more info on
// the package name interpolation.
TestNamingConvention = "python_test_naming_convention"
// PipRepoNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. E.g. if the Python package name is `foo` and the
// pip repository is named `my_pip`, setting this
// to `$repo_name$_$distribution_name$` would render to `@my_pip_foo`.
PipRepoNamingConvention = "python_pip_repo_naming_convention"
// PipPackageNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. By default it is ``
PipPackageNamingConvention = "python_pip_package_naming_convention"
// PipTargetNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. By default it is `pkg`
PipTargetNamingConvention = "python_pip_target_naming_convention"
)

// GenerationModeType represents one of the generation modes for the Python
Expand All@@ -67,7 +78,9 @@ const (
)

const (
packageNameNamingConventionSubstitution = "$package_name$"
repoNamePipRepoNamingConventionSubstitution = "$repo_name$"
distributionNamePipRepoNamingConventionSubstitution = "$distribution_name$"
packageNameNamingConventionSubstitution = "$package_name$"
)

// defaultIgnoreFiles is the list of default values used in the
Expand DownExpand Up@@ -99,14 +112,17 @@ type Config struct {
pythonProjectRoot string
gazelleManifest *manifest.Manifest

excludedPatterns *singlylinkedlist.List
ignoreFiles map[string]struct{}
ignoreDependencies map[string]struct{}
validateImportStatements bool
coarseGrainedGeneration bool
libraryNamingConvention string
binaryNamingConvention string
testNamingConvention string
excludedPatterns *singlylinkedlist.List
ignoreFiles map[string]struct{}
ignoreDependencies map[string]struct{}
validateImportStatements bool
coarseGrainedGeneration bool
libraryNamingConvention string
binaryNamingConvention string
testNamingConvention string
pipRepoNamingConvention string
pipPackageNamingConvention string
pipTargetNamingConvention string
}

// New creates a new Config.
Expand All@@ -115,17 +131,20 @@ func New(
pythonProjectRoot string,
) *Config {
return &Config{
extensionEnabled: true,
repoRoot: repoRoot,
pythonProjectRoot: pythonProjectRoot,
excludedPatterns: singlylinkedlist.New(),
ignoreFiles: make(map[string]struct{}),
ignoreDependencies: make(map[string]struct{}),
validateImportStatements: true,
coarseGrainedGeneration: false,
libraryNamingConvention: packageNameNamingConventionSubstitution,
binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
extensionEnabled: true,
repoRoot: repoRoot,
pythonProjectRoot: pythonProjectRoot,
excludedPatterns: singlylinkedlist.New(),
ignoreFiles: make(map[string]struct{}),
ignoreDependencies: make(map[string]struct{}),
validateImportStatements: true,
coarseGrainedGeneration: false,
libraryNamingConvention: packageNameNamingConventionSubstitution,
binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
pipRepoNamingConvention: fmt.Sprintf("%s_%s", repoNamePipRepoNamingConventionSubstitution, distributionNamePipRepoNamingConventionSubstitution),
pipPackageNamingConvention: "",
pipTargetNamingConvention: "pkg",
}
}

Expand All@@ -150,6 +169,9 @@ func (c *Config) NewChild() *Config {
libraryNamingConvention: c.libraryNamingConvention,
binaryNamingConvention: c.binaryNamingConvention,
testNamingConvention: c.testNamingConvention,
pipRepoNamingConvention: c.pipRepoNamingConvention,
pipPackageNamingConvention: c.pipPackageNamingConvention,
pipTargetNamingConvention: c.pipTargetNamingConvention,
}
}

Expand DownExpand Up@@ -195,24 +217,32 @@ func (c *Config) SetGazelleManifest(gazelleManifest *manifest.Manifest) {
// name.
func (c *Config) FindThirdPartyDependency(modName string) (string, bool) {
for currentCfg := c; currentCfg != nil; currentCfg = currentCfg.parent {
if currentCfg.gazelleManifest != nil {
gazelleManifest := currentCfg.gazelleManifest
if distributionName, ok := gazelleManifest.ModulesMapping[modName]; ok {
var distributionRepositoryName string
if gazelleManifest.PipDepsRepositoryName != "" {
distributionRepositoryName = gazelleManifest.PipDepsRepositoryName
} else if gazelleManifest.PipRepository != nil {
distributionRepositoryName = gazelleManifest.PipRepository.Name
}
sanitizedDistribution := strings.ToLower(distributionName)
sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")
var lbl label.Label
// @<repository_name>_<distribution_name>//:pkg
distributionRepositoryName = distributionRepositoryName + "_" + sanitizedDistribution
lbl = label.New(distributionRepositoryName, "", "pkg")
return lbl.String(), true
}

if currentCfg.gazelleManifest == nil {
continue
}

gazelleManifest := currentCfg.gazelleManifest
distributionName, ok := gazelleManifest.ModulesMapping[modName]
if !ok {
continue
}

var distributionRepositoryName string
if gazelleManifest.PipDepsRepositoryName != "" {
distributionRepositoryName = gazelleManifest.PipDepsRepositoryName
} else if gazelleManifest.PipRepository != nil {
distributionRepositoryName = gazelleManifest.PipRepository.Name
}
sanitizedDistribution := strings.ToLower(distributionName)
sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")

lbl := label.New(
currentCfg.renderPipRepository(distributionRepositoryName, sanitizedDistribution),
currentCfg.renderPipPackage(sanitizedDistribution),
currentCfg.renderPipTarget(sanitizedDistribution),
)
return lbl.String(), true
}
return "", false
}
Expand DownExpand Up@@ -327,6 +357,37 @@ func (c *Config) SetTestNamingConvention(testNamingConvention string) {
c.testNamingConvention = testNamingConvention
}

// SetPipRepoNamingConvention sets the dependency naming convention.
func (c *Config) SetPipRepoNamingConvention(pipRepoNamingConvention string) {
c.pipRepoNamingConvention = pipRepoNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipRepository(distributionRepoName, distributionName string) string {
rendered := strings.ReplaceAll(c.pipRepoNamingConvention, repoNamePipRepoNamingConventionSubstitution, distributionRepoName)
return strings.ReplaceAll(rendered, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// SetPipPackageNamingConvention sets the dependency naming convention.
func (c *Config) SetPipPackageNamingConvention(pipPackageNamingConvention string) {
c.pipPackageNamingConvention = pipPackageNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipPackage(distributionName string) string {
return strings.ReplaceAll(c.pipPackageNamingConvention, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// SetPipTargetNamingConvention sets the dependency naming convention.
func (c *Config) SetPipTargetNamingConvention(pipTargetNamingConvention string) {
c.pipTargetNamingConvention = pipTargetNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipTarget(distributionName string) string {
return strings.ReplaceAll(c.pipTargetNamingConvention, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// RenderTestName returns the py_test target name by performing all
// substitutions.
func (c *Config) RenderTestName(packageName string) string {
Expand Down
19 changes: 19 additions & 0 deletions gazelle/pythonconfig/pythonconfig_test.go
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
package pythonconfig

import (
"reflect"
"testing"
)

func TestConfigNewChild(t *testing.T) {
parent := New("foo", "bar")
child := parent.NewChild()

if child.parent == nil {
t.Error("child parent should not be nil")
}
child.parent = nil
if !reflect.DeepEqual(child, parent) {
t.Errorf("child and should should be equal other than the parent reference. Parent: %#v\nChild: %#v", parent, child)
}
}
2 changes: 1 addition & 1 deletion gazelle/pythonconfig/types.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,4 +100,4 @@ func (sml *StringMapList) Set(s string) error {
func (sml *StringMapList) Get(key string) (string, bool) {
val, exists := sml.mapping[key]
return val, exists
}
}
3 changes: 3 additions & 0 deletions gazelle/testdata/pip_repo_convention/BUILD.in
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
# gazelle:python_pip_repo_naming_convention $repo_name$
# gazelle:python_pip_package_naming_convention $distribution_name$
# gazelle:python_pip_target_naming_convention $distribution_name$_pkg
31 changes: 31 additions & 0 deletions gazelle/testdata/pip_repo_convention/BUILD.out
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
load("@rules_python//python:defs.bzl", "py_binary", "py_library")

# gazelle:python_pip_repo_naming_convention $repo_name$
# gazelle:python_pip_package_naming_convention $distribution_name$
# gazelle:python_pip_target_naming_convention $distribution_name$_pkg

py_library(
name = "pip_repo_convention",
srcs = [
"__init__.py",
"bar.py",
"foo.py",
],
visibility = ["//:__subpackages__"],
deps = [
"@pip_deps//baz:baz_pkg",
"@pip_deps//boto3:boto3_pkg",
"@pip_deps//djangorestframework:djangorestframework_pkg",
],
)

py_binary(
name = "pip_repo_convention_bin",
srcs = ["__main__.py"],
main = "__main__.py",
visibility = ["//:__subpackages__"],
deps = [
":pip_repo_convention",
"@pip_deps//baz:baz_pkg",
],
)
3 changes: 3 additions & 0 deletions gazelle/testdata/pip_repo_convention/README.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
# Pip repo convention

This test case asserts that the dependency labels generated by gazelle follow a particular convention, that can be changed using directives.
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/WORKSPACE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
# This is a Bazel workspace for the Gazelle test data.
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/__init__.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
# For test purposes only.
5 changes: 5 additions & 0 deletions gazelle/testdata/pip_repo_convention/__main__.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
import bar
import foo

_ = bar
_ = foo
11 changes: 11 additions & 0 deletions gazelle/testdata/pip_repo_convention/bar.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
import os

import bar
import boto3
import rest_framework

_ = os

_ = bar
_ = boto3
_ = rest_framework
11 changes: 11 additions & 0 deletions gazelle/testdata/pip_repo_convention/foo.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
import sys

import boto3
import foo
import rest_framework

_ = sys

_ = boto3
_ = foo
_ = rest_framework
8 changes: 8 additions & 0 deletions gazelle/testdata/pip_repo_convention/gazelle_python.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
manifest:
modules_mapping:
boto3: boto3
rest_framework: djangorestframework
foo: baz
bar: baz
pip_repository:
name: pip_deps
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/test.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
---
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions gazelle/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,6 +147,12 @@ Python-specific directives are as follows:
| Controls the `py_test` naming convention. Follows the same interpolation rules as `python_library_naming_convention`. | |
| `# gazelle:resolve py ...` | n/a |
| Instructs the plugin what target to add as a dependency to satisfy a given import statement. The syntax is `# gazelle:resolve py import-string label` where `import-string` is the symbol in the python `import` statement, and `label` is the Bazel label that Gazelle should write in `deps`. | |
| `# gazelle:python_pip_repo_naming_convention` | `$repo_name$_$distribution_name$` |
| Controls the external dependency label naming convention. It interpolates `$repo_name$` and `$distribution_name$` with the Bazel external pip repository name and the sanitized Python package name respectively. E.g. if the Bazel external pip repository name is `my_pip_deps` and we are resolving external Python package named `flake-bugbear`, setting this to `$repo_name$_host_$distribution_name$` would result in a generated target named `my_pip_deps_host_flake8_bugbear`. | |
| `# gazelle:python_pip_package_naming_convention` | n/a |
| Controls the external dependency label naming convention. It interpolates `$distribution_name$` with the sanitized Python package name. See `gazelle:python_pip_repo_naming_convention` for details. This may be useful if you have `alias` targets which point to platform specific Python wheels in your repo, e.g. `//third_party/pip:flake8_bugbear_alias`. | |
| `# gazelle:python_pip_target_naming_convention` | `pkg` |
| Controls the external dependency label naming convention. It interpolates `$distribution_name$` with the sanitized Python package name respectively. See `gazelle:python_pip_repo_naming_convention` for details. This may be useful if you have `alias` targets which point to platform specific Python wheels in your repo, e.g. `//third_party/pip:flake8_bugbear_alias` or if you are using `gazelle` with `bzlmod`. | |

### Libraries

Expand Down
9 changes: 9 additions & 0 deletions gazelle/configure.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,9 @@ func (py *Configurer) KnownDirectives() []string {
pythonconfig.LibraryNamingConvention,
pythonconfig.BinaryNamingConvention,
pythonconfig.TestNamingConvention,
pythonconfig.PipRepoNamingConvention,
pythonconfig.PipPackageNamingConvention,
pythonconfig.PipTargetNamingConvention,
}
}

Expand DownExpand Up@@ -136,6 +139,12 @@ func (py *Configurer) Configure(c *config.Config, rel string, f *rule.File) {
config.SetBinaryNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.TestNamingConvention:
config.SetTestNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipRepoNamingConvention:
config.SetPipRepoNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipPackageNamingConvention:
config.SetPipPackageNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipTargetNamingConvention:
config.SetPipTargetNamingConvention(strings.TrimSpace(d.Value))
}
}

Expand Down
8 changes: 7 additions & 1 deletion gazelle/pythonconfig/BUILD.bazel
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "pythonconfig",
Expand All@@ -20,3 +20,9 @@ filegroup(
srcs = glob(["**"]),
visibility = ["//gazelle:__pkg__"],
)

go_test(
name = "pythonconfig_test",
srcs = ["pythonconfig_test.go"],
embed = [":pythonconfig"],
)
135 changes: 98 additions & 37 deletions gazelle/pythonconfig/pythonconfig.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,6 +49,17 @@ const (
// naming convention. See python_library_naming_convention for more info on
// the package name interpolation.
TestNamingConvention = "python_test_naming_convention"
// PipRepoNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. E.g. if the Python package name is `foo` and the
// pip repository is named `my_pip`, setting this
// to `$repo_name$_$distribution_name$` would render to `@my_pip_foo`.
PipRepoNamingConvention = "python_pip_repo_naming_convention"
// PipPackageNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. By default it is ``
PipPackageNamingConvention = "python_pip_package_naming_convention"
// PipTargetNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. By default it is `pkg`
PipTargetNamingConvention = "python_pip_target_naming_convention"
)

// GenerationModeType represents one of the generation modes for the Python
Expand All@@ -67,7 +78,9 @@ const (
)

const (
packageNameNamingConventionSubstitution = "$package_name$"
repoNamePipRepoNamingConventionSubstitution = "$repo_name$"
distributionNamePipRepoNamingConventionSubstitution = "$distribution_name$"
packageNameNamingConventionSubstitution = "$package_name$"
)

// defaultIgnoreFiles is the list of default values used in the
Expand DownExpand Up@@ -99,14 +112,17 @@ type Config struct {
pythonProjectRoot string
gazelleManifest *manifest.Manifest

excludedPatterns *singlylinkedlist.List
ignoreFiles map[string]struct{}
ignoreDependencies map[string]struct{}
validateImportStatements bool
coarseGrainedGeneration bool
libraryNamingConvention string
binaryNamingConvention string
testNamingConvention string
excludedPatterns *singlylinkedlist.List
ignoreFiles map[string]struct{}
ignoreDependencies map[string]struct{}
validateImportStatements bool
coarseGrainedGeneration bool
libraryNamingConvention string
binaryNamingConvention string
testNamingConvention string
pipRepoNamingConvention string
pipPackageNamingConvention string
pipTargetNamingConvention string
}

// New creates a new Config.
Expand All@@ -115,17 +131,20 @@ func New(
pythonProjectRoot string,
) *Config {
return &Config{
extensionEnabled: true,
repoRoot: repoRoot,
pythonProjectRoot: pythonProjectRoot,
excludedPatterns: singlylinkedlist.New(),
ignoreFiles: make(map[string]struct{}),
ignoreDependencies: make(map[string]struct{}),
validateImportStatements: true,
coarseGrainedGeneration: false,
libraryNamingConvention: packageNameNamingConventionSubstitution,
binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
extensionEnabled: true,
repoRoot: repoRoot,
pythonProjectRoot: pythonProjectRoot,
excludedPatterns: singlylinkedlist.New(),
ignoreFiles: make(map[string]struct{}),
ignoreDependencies: make(map[string]struct{}),
validateImportStatements: true,
coarseGrainedGeneration: false,
libraryNamingConvention: packageNameNamingConventionSubstitution,
binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
pipRepoNamingConvention: fmt.Sprintf("%s_%s", repoNamePipRepoNamingConventionSubstitution, distributionNamePipRepoNamingConventionSubstitution),
pipPackageNamingConvention: "",
pipTargetNamingConvention: "pkg",
}
}

Expand All@@ -150,6 +169,9 @@ func (c *Config) NewChild() *Config {
libraryNamingConvention: c.libraryNamingConvention,
binaryNamingConvention: c.binaryNamingConvention,
testNamingConvention: c.testNamingConvention,
pipRepoNamingConvention: c.pipRepoNamingConvention,
pipPackageNamingConvention: c.pipPackageNamingConvention,
pipTargetNamingConvention: c.pipTargetNamingConvention,
}
}

Expand DownExpand Up@@ -195,24 +217,32 @@ func (c *Config) SetGazelleManifest(gazelleManifest *manifest.Manifest) {
// name.
func (c *Config) FindThirdPartyDependency(modName string) (string, bool) {
for currentCfg := c; currentCfg != nil; currentCfg = currentCfg.parent {
if currentCfg.gazelleManifest != nil {
gazelleManifest := currentCfg.gazelleManifest
if distributionName, ok := gazelleManifest.ModulesMapping[modName]; ok {
var distributionRepositoryName string
if gazelleManifest.PipDepsRepositoryName != "" {
distributionRepositoryName = gazelleManifest.PipDepsRepositoryName
} else if gazelleManifest.PipRepository != nil {
distributionRepositoryName = gazelleManifest.PipRepository.Name
}
sanitizedDistribution := strings.ToLower(distributionName)
sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")
var lbl label.Label
// @<repository_name>_<distribution_name>//:pkg
distributionRepositoryName = distributionRepositoryName + "_" + sanitizedDistribution
lbl = label.New(distributionRepositoryName, "", "pkg")
return lbl.String(), true
}

if currentCfg.gazelleManifest == nil {
continue
}

gazelleManifest := currentCfg.gazelleManifest
distributionName, ok := gazelleManifest.ModulesMapping[modName]
if !ok {
continue
}

var distributionRepositoryName string
if gazelleManifest.PipDepsRepositoryName != "" {
distributionRepositoryName = gazelleManifest.PipDepsRepositoryName
} else if gazelleManifest.PipRepository != nil {
distributionRepositoryName = gazelleManifest.PipRepository.Name
}
sanitizedDistribution := strings.ToLower(distributionName)
sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")

lbl := label.New(
currentCfg.renderPipRepository(distributionRepositoryName, sanitizedDistribution),
currentCfg.renderPipPackage(sanitizedDistribution),
currentCfg.renderPipTarget(sanitizedDistribution),
)
return lbl.String(), true
}
return "", false
}
Expand DownExpand Up@@ -327,6 +357,37 @@ func (c *Config) SetTestNamingConvention(testNamingConvention string) {
c.testNamingConvention = testNamingConvention
}

// SetPipRepoNamingConvention sets the dependency naming convention.
func (c *Config) SetPipRepoNamingConvention(pipRepoNamingConvention string) {
c.pipRepoNamingConvention = pipRepoNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipRepository(distributionRepoName, distributionName string) string {
rendered := strings.ReplaceAll(c.pipRepoNamingConvention, repoNamePipRepoNamingConventionSubstitution, distributionRepoName)
return strings.ReplaceAll(rendered, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// SetPipPackageNamingConvention sets the dependency naming convention.
func (c *Config) SetPipPackageNamingConvention(pipPackageNamingConvention string) {
c.pipPackageNamingConvention = pipPackageNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipPackage(distributionName string) string {
return strings.ReplaceAll(c.pipPackageNamingConvention, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// SetPipTargetNamingConvention sets the dependency naming convention.
func (c *Config) SetPipTargetNamingConvention(pipTargetNamingConvention string) {
c.pipTargetNamingConvention = pipTargetNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipTarget(distributionName string) string {
return strings.ReplaceAll(c.pipTargetNamingConvention, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// RenderTestName returns the py_test target name by performing all
// substitutions.
func (c *Config) RenderTestName(packageName string) string {
Expand Down
19 changes: 19 additions & 0 deletions gazelle/pythonconfig/pythonconfig_test.go
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
package pythonconfig

import (
"reflect"
"testing"
)

func TestConfigNewChild(t *testing.T) {
parent := New("foo", "bar")
child := parent.NewChild()

if child.parent == nil {
t.Error("child parent should not be nil")
}
child.parent = nil
if !reflect.DeepEqual(child, parent) {
t.Errorf("child and should should be equal other than the parent reference. Parent: %#v\nChild: %#v", parent, child)
}
}
2 changes: 1 addition & 1 deletion gazelle/pythonconfig/types.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,4 +100,4 @@ func (sml *StringMapList) Set(s string) error {
func (sml *StringMapList) Get(key string) (string, bool) {
val, exists := sml.mapping[key]
return val, exists
}
}
3 changes: 3 additions & 0 deletions gazelle/testdata/pip_repo_convention/BUILD.in
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
# gazelle:python_pip_repo_naming_convention $repo_name$
# gazelle:python_pip_package_naming_convention $distribution_name$
# gazelle:python_pip_target_naming_convention $distribution_name$_pkg
31 changes: 31 additions & 0 deletions gazelle/testdata/pip_repo_convention/BUILD.out
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
load("@rules_python//python:defs.bzl", "py_binary", "py_library")

# gazelle:python_pip_repo_naming_convention $repo_name$
# gazelle:python_pip_package_naming_convention $distribution_name$
# gazelle:python_pip_target_naming_convention $distribution_name$_pkg

py_library(
name = "pip_repo_convention",
srcs = [
"__init__.py",
"bar.py",
"foo.py",
],
visibility = ["//:__subpackages__"],
deps = [
"@pip_deps//baz:baz_pkg",
"@pip_deps//boto3:boto3_pkg",
"@pip_deps//djangorestframework:djangorestframework_pkg",
],
)

py_binary(
name = "pip_repo_convention_bin",
srcs = ["__main__.py"],
main = "__main__.py",
visibility = ["//:__subpackages__"],
deps = [
":pip_repo_convention",
"@pip_deps//baz:baz_pkg",
],
)
3 changes: 3 additions & 0 deletions gazelle/testdata/pip_repo_convention/README.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
# Pip repo convention

This test case asserts that the dependency labels generated by gazelle follow a particular convention, that can be changed using directives.
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/WORKSPACE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
# This is a Bazel workspace for the Gazelle test data.
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/__init__.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
# For test purposes only.
5 changes: 5 additions & 0 deletions gazelle/testdata/pip_repo_convention/__main__.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
import bar
import foo

_ = bar
_ = foo
11 changes: 11 additions & 0 deletions gazelle/testdata/pip_repo_convention/bar.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
import os

import bar
import boto3
import rest_framework

_ = os

_ = bar
_ = boto3
_ = rest_framework
11 changes: 11 additions & 0 deletions gazelle/testdata/pip_repo_convention/foo.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
import sys

import boto3
import foo
import rest_framework

_ = sys

_ = boto3
_ = foo
_ = rest_framework
8 changes: 8 additions & 0 deletions gazelle/testdata/pip_repo_convention/gazelle_python.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
manifest:
modules_mapping:
boto3: boto3
rest_framework: djangorestframework
foo: baz
bar: baz
pip_repository:
name: pip_deps
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/test.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
---
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions gazelle/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,6 +147,12 @@ Python-specific directives are as follows:
| Controls the `py_test` naming convention. Follows the same interpolation rules as `python_library_naming_convention`. | |
| `# gazelle:resolve py ...` | n/a |
| Instructs the plugin what target to add as a dependency to satisfy a given import statement. The syntax is `# gazelle:resolve py import-string label` where `import-string` is the symbol in the python `import` statement, and `label` is the Bazel label that Gazelle should write in `deps`. | |
| `# gazelle:python_pip_repo_naming_convention` | `$repo_name$_$distribution_name$` |
| Controls the external dependency label naming convention. It interpolates `$repo_name$` and `$distribution_name$` with the Bazel external pip repository name and the sanitized Python package name respectively. E.g. if the Bazel external pip repository name is `my_pip_deps` and we are resolving external Python package named `flake-bugbear`, setting this to `$repo_name$_host_$distribution_name$` would result in a generated target named `my_pip_deps_host_flake8_bugbear`. | |
| `# gazelle:python_pip_package_naming_convention` | n/a |
| Controls the external dependency label naming convention. It interpolates `$distribution_name$` with the sanitized Python package name. See `gazelle:python_pip_repo_naming_convention` for details. This may be useful if you have `alias` targets which point to platform specific Python wheels in your repo, e.g. `//third_party/pip:flake8_bugbear_alias`. | |
| `# gazelle:python_pip_target_naming_convention` | `pkg` |
| Controls the external dependency label naming convention. It interpolates `$distribution_name$` with the sanitized Python package name respectively. See `gazelle:python_pip_repo_naming_convention` for details. This may be useful if you have `alias` targets which point to platform specific Python wheels in your repo, e.g. `//third_party/pip:flake8_bugbear_alias` or if you are using `gazelle` with `bzlmod`. | |

### Libraries

Expand Down
9 changes: 9 additions & 0 deletions gazelle/configure.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,9 @@ func (py *Configurer) KnownDirectives() []string {
pythonconfig.LibraryNamingConvention,
pythonconfig.BinaryNamingConvention,
pythonconfig.TestNamingConvention,
pythonconfig.PipRepoNamingConvention,
pythonconfig.PipPackageNamingConvention,
pythonconfig.PipTargetNamingConvention,
}
}

Expand DownExpand Up@@ -136,6 +139,12 @@ func (py *Configurer) Configure(c *config.Config, rel string, f *rule.File) {
config.SetBinaryNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.TestNamingConvention:
config.SetTestNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipRepoNamingConvention:
config.SetPipRepoNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipPackageNamingConvention:
config.SetPipPackageNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipTargetNamingConvention:
config.SetPipTargetNamingConvention(strings.TrimSpace(d.Value))
}
}

Expand Down
8 changes: 7 additions & 1 deletion gazelle/pythonconfig/BUILD.bazel
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "pythonconfig",
Expand All@@ -20,3 +20,9 @@ filegroup(
srcs = glob(["**"]),
visibility = ["//gazelle:__pkg__"],
)

go_test(
name = "pythonconfig_test",
srcs = ["pythonconfig_test.go"],
embed = [":pythonconfig"],
)
135 changes: 98 additions & 37 deletions gazelle/pythonconfig/pythonconfig.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,6 +49,17 @@ const (
// naming convention. See python_library_naming_convention for more info on
// the package name interpolation.
TestNamingConvention = "python_test_naming_convention"
// PipRepoNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. E.g. if the Python package name is `foo` and the
// pip repository is named `my_pip`, setting this
// to `$repo_name$_$distribution_name$` would render to `@my_pip_foo`.
PipRepoNamingConvention = "python_pip_repo_naming_convention"
// PipPackageNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. By default it is ``
PipPackageNamingConvention = "python_pip_package_naming_convention"
// PipTargetNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. By default it is `pkg`
PipTargetNamingConvention = "python_pip_target_naming_convention"
)

// GenerationModeType represents one of the generation modes for the Python
Expand All@@ -67,7 +78,9 @@ const (
)

const (
packageNameNamingConventionSubstitution = "$package_name$"
repoNamePipRepoNamingConventionSubstitution = "$repo_name$"
distributionNamePipRepoNamingConventionSubstitution = "$distribution_name$"
packageNameNamingConventionSubstitution = "$package_name$"
)

// defaultIgnoreFiles is the list of default values used in the
Expand DownExpand Up@@ -99,14 +112,17 @@ type Config struct {
pythonProjectRoot string
gazelleManifest *manifest.Manifest

excludedPatterns *singlylinkedlist.List
ignoreFiles map[string]struct{}
ignoreDependencies map[string]struct{}
validateImportStatements bool
coarseGrainedGeneration bool
libraryNamingConvention string
binaryNamingConvention string
testNamingConvention string
excludedPatterns *singlylinkedlist.List
ignoreFiles map[string]struct{}
ignoreDependencies map[string]struct{}
validateImportStatements bool
coarseGrainedGeneration bool
libraryNamingConvention string
binaryNamingConvention string
testNamingConvention string
pipRepoNamingConvention string
pipPackageNamingConvention string
pipTargetNamingConvention string
}

// New creates a new Config.
Expand All@@ -115,17 +131,20 @@ func New(
pythonProjectRoot string,
) *Config {
return &Config{
extensionEnabled: true,
repoRoot: repoRoot,
pythonProjectRoot: pythonProjectRoot,
excludedPatterns: singlylinkedlist.New(),
ignoreFiles: make(map[string]struct{}),
ignoreDependencies: make(map[string]struct{}),
validateImportStatements: true,
coarseGrainedGeneration: false,
libraryNamingConvention: packageNameNamingConventionSubstitution,
binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
extensionEnabled: true,
repoRoot: repoRoot,
pythonProjectRoot: pythonProjectRoot,
excludedPatterns: singlylinkedlist.New(),
ignoreFiles: make(map[string]struct{}),
ignoreDependencies: make(map[string]struct{}),
validateImportStatements: true,
coarseGrainedGeneration: false,
libraryNamingConvention: packageNameNamingConventionSubstitution,
binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
pipRepoNamingConvention: fmt.Sprintf("%s_%s", repoNamePipRepoNamingConventionSubstitution, distributionNamePipRepoNamingConventionSubstitution),
pipPackageNamingConvention: "",
pipTargetNamingConvention: "pkg",
}
}

Expand All@@ -150,6 +169,9 @@ func (c *Config) NewChild() *Config {
libraryNamingConvention: c.libraryNamingConvention,
binaryNamingConvention: c.binaryNamingConvention,
testNamingConvention: c.testNamingConvention,
pipRepoNamingConvention: c.pipRepoNamingConvention,
pipPackageNamingConvention: c.pipPackageNamingConvention,
pipTargetNamingConvention: c.pipTargetNamingConvention,
}
}

Expand DownExpand Up@@ -195,24 +217,32 @@ func (c *Config) SetGazelleManifest(gazelleManifest *manifest.Manifest) {
// name.
func (c *Config) FindThirdPartyDependency(modName string) (string, bool) {
for currentCfg := c; currentCfg != nil; currentCfg = currentCfg.parent {
if currentCfg.gazelleManifest != nil {
gazelleManifest := currentCfg.gazelleManifest
if distributionName, ok := gazelleManifest.ModulesMapping[modName]; ok {
var distributionRepositoryName string
if gazelleManifest.PipDepsRepositoryName != "" {
distributionRepositoryName = gazelleManifest.PipDepsRepositoryName
} else if gazelleManifest.PipRepository != nil {
distributionRepositoryName = gazelleManifest.PipRepository.Name
}
sanitizedDistribution := strings.ToLower(distributionName)
sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")
var lbl label.Label
// @<repository_name>_<distribution_name>//:pkg
distributionRepositoryName = distributionRepositoryName + "_" + sanitizedDistribution
lbl = label.New(distributionRepositoryName, "", "pkg")
return lbl.String(), true
}

if currentCfg.gazelleManifest == nil {
continue
}

gazelleManifest := currentCfg.gazelleManifest
distributionName, ok := gazelleManifest.ModulesMapping[modName]
if !ok {
continue
}

var distributionRepositoryName string
if gazelleManifest.PipDepsRepositoryName != "" {
distributionRepositoryName = gazelleManifest.PipDepsRepositoryName
} else if gazelleManifest.PipRepository != nil {
distributionRepositoryName = gazelleManifest.PipRepository.Name
}
sanitizedDistribution := strings.ToLower(distributionName)
sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")

lbl := label.New(
currentCfg.renderPipRepository(distributionRepositoryName, sanitizedDistribution),
currentCfg.renderPipPackage(sanitizedDistribution),
currentCfg.renderPipTarget(sanitizedDistribution),
)
return lbl.String(), true
}
return "", false
}
Expand DownExpand Up@@ -327,6 +357,37 @@ func (c *Config) SetTestNamingConvention(testNamingConvention string) {
c.testNamingConvention = testNamingConvention
}

// SetPipRepoNamingConvention sets the dependency naming convention.
func (c *Config) SetPipRepoNamingConvention(pipRepoNamingConvention string) {
c.pipRepoNamingConvention = pipRepoNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipRepository(distributionRepoName, distributionName string) string {
rendered := strings.ReplaceAll(c.pipRepoNamingConvention, repoNamePipRepoNamingConventionSubstitution, distributionRepoName)
return strings.ReplaceAll(rendered, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// SetPipPackageNamingConvention sets the dependency naming convention.
func (c *Config) SetPipPackageNamingConvention(pipPackageNamingConvention string) {
c.pipPackageNamingConvention = pipPackageNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipPackage(distributionName string) string {
return strings.ReplaceAll(c.pipPackageNamingConvention, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// SetPipTargetNamingConvention sets the dependency naming convention.
func (c *Config) SetPipTargetNamingConvention(pipTargetNamingConvention string) {
c.pipTargetNamingConvention = pipTargetNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipTarget(distributionName string) string {
return strings.ReplaceAll(c.pipTargetNamingConvention, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// RenderTestName returns the py_test target name by performing all
// substitutions.
func (c *Config) RenderTestName(packageName string) string {
Expand Down
19 changes: 19 additions & 0 deletions gazelle/pythonconfig/pythonconfig_test.go
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
package pythonconfig

import (
"reflect"
"testing"
)

func TestConfigNewChild(t *testing.T) {
parent := New("foo", "bar")
child := parent.NewChild()

if child.parent == nil {
t.Error("child parent should not be nil")
}
child.parent = nil
if !reflect.DeepEqual(child, parent) {
t.Errorf("child and should should be equal other than the parent reference. Parent: %#v\nChild: %#v", parent, child)
}
}
2 changes: 1 addition & 1 deletion gazelle/pythonconfig/types.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,4 +100,4 @@ func (sml *StringMapList) Set(s string) error {
func (sml *StringMapList) Get(key string) (string, bool) {
val, exists := sml.mapping[key]
return val, exists
}
}
3 changes: 3 additions & 0 deletions gazelle/testdata/pip_repo_convention/BUILD.in
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
# gazelle:python_pip_repo_naming_convention $repo_name$
# gazelle:python_pip_package_naming_convention $distribution_name$
# gazelle:python_pip_target_naming_convention $distribution_name$_pkg
31 changes: 31 additions & 0 deletions gazelle/testdata/pip_repo_convention/BUILD.out
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
load("@rules_python//python:defs.bzl", "py_binary", "py_library")

# gazelle:python_pip_repo_naming_convention $repo_name$
# gazelle:python_pip_package_naming_convention $distribution_name$
# gazelle:python_pip_target_naming_convention $distribution_name$_pkg

py_library(
name = "pip_repo_convention",
srcs = [
"__init__.py",
"bar.py",
"foo.py",
],
visibility = ["//:__subpackages__"],
deps = [
"@pip_deps//baz:baz_pkg",
"@pip_deps//boto3:boto3_pkg",
"@pip_deps//djangorestframework:djangorestframework_pkg",
],
)

py_binary(
name = "pip_repo_convention_bin",
srcs = ["__main__.py"],
main = "__main__.py",
visibility = ["//:__subpackages__"],
deps = [
":pip_repo_convention",
"@pip_deps//baz:baz_pkg",
],
)
3 changes: 3 additions & 0 deletions gazelle/testdata/pip_repo_convention/README.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
# Pip repo convention

This test case asserts that the dependency labels generated by gazelle follow a particular convention, that can be changed using directives.
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/WORKSPACE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
# This is a Bazel workspace for the Gazelle test data.
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/__init__.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
# For test purposes only.
5 changes: 5 additions & 0 deletions gazelle/testdata/pip_repo_convention/__main__.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
import bar
import foo

_ = bar
_ = foo
11 changes: 11 additions & 0 deletions gazelle/testdata/pip_repo_convention/bar.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
import os

import bar
import boto3
import rest_framework

_ = os

_ = bar
_ = boto3
_ = rest_framework
11 changes: 11 additions & 0 deletions gazelle/testdata/pip_repo_convention/foo.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
import sys

import boto3
import foo
import rest_framework

_ = sys

_ = boto3
_ = foo
_ = rest_framework
8 changes: 8 additions & 0 deletions gazelle/testdata/pip_repo_convention/gazelle_python.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
manifest:
modules_mapping:
boto3: boto3
rest_framework: djangorestframework
foo: baz
bar: baz
pip_repository:
name: pip_deps
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/test.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
---
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions gazelle/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,6 +147,12 @@ Python-specific directives are as follows:
| Controls the `py_test` naming convention. Follows the same interpolation rules as `python_library_naming_convention`. | |
| `# gazelle:resolve py ...` | n/a |
| Instructs the plugin what target to add as a dependency to satisfy a given import statement. The syntax is `# gazelle:resolve py import-string label` where `import-string` is the symbol in the python `import` statement, and `label` is the Bazel label that Gazelle should write in `deps`. | |
| `# gazelle:python_pip_repo_naming_convention` | `$repo_name$_$distribution_name$` |
| Controls the external dependency label naming convention. It interpolates `$repo_name$` and `$distribution_name$` with the Bazel external pip repository name and the sanitized Python package name respectively. E.g. if the Bazel external pip repository name is `my_pip_deps` and we are resolving external Python package named `flake-bugbear`, setting this to `$repo_name$_host_$distribution_name$` would result in a generated target named `my_pip_deps_host_flake8_bugbear`. | |
| `# gazelle:python_pip_package_naming_convention` | n/a |
| Controls the external dependency label naming convention. It interpolates `$distribution_name$` with the sanitized Python package name. See `gazelle:python_pip_repo_naming_convention` for details. This may be useful if you have `alias` targets which point to platform specific Python wheels in your repo, e.g. `//third_party/pip:flake8_bugbear_alias`. | |
| `# gazelle:python_pip_target_naming_convention` | `pkg` |
| Controls the external dependency label naming convention. It interpolates `$distribution_name$` with the sanitized Python package name respectively. See `gazelle:python_pip_repo_naming_convention` for details. This may be useful if you have `alias` targets which point to platform specific Python wheels in your repo, e.g. `//third_party/pip:flake8_bugbear_alias` or if you are using `gazelle` with `bzlmod`. | |

### Libraries

Expand Down
9 changes: 9 additions & 0 deletions gazelle/configure.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,9 @@ func (py *Configurer) KnownDirectives() []string {
pythonconfig.LibraryNamingConvention,
pythonconfig.BinaryNamingConvention,
pythonconfig.TestNamingConvention,
pythonconfig.PipRepoNamingConvention,
pythonconfig.PipPackageNamingConvention,
pythonconfig.PipTargetNamingConvention,
}
}

Expand DownExpand Up@@ -136,6 +139,12 @@ func (py *Configurer) Configure(c *config.Config, rel string, f *rule.File) {
config.SetBinaryNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.TestNamingConvention:
config.SetTestNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipRepoNamingConvention:
config.SetPipRepoNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipPackageNamingConvention:
config.SetPipPackageNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipTargetNamingConvention:
config.SetPipTargetNamingConvention(strings.TrimSpace(d.Value))
}
}

Expand Down
8 changes: 7 additions & 1 deletion gazelle/pythonconfig/BUILD.bazel
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "pythonconfig",
Expand All@@ -20,3 +20,9 @@ filegroup(
srcs = glob(["**"]),
visibility = ["//gazelle:__pkg__"],
)

go_test(
name = "pythonconfig_test",
srcs = ["pythonconfig_test.go"],
embed = [":pythonconfig"],
)
135 changes: 98 additions & 37 deletions gazelle/pythonconfig/pythonconfig.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,6 +49,17 @@ const (
// naming convention. See python_library_naming_convention for more info on
// the package name interpolation.
TestNamingConvention = "python_test_naming_convention"
// PipRepoNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. E.g. if the Python package name is `foo` and the
// pip repository is named `my_pip`, setting this
// to `$repo_name$_$distribution_name$` would render to `@my_pip_foo`.
PipRepoNamingConvention = "python_pip_repo_naming_convention"
// PipPackageNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. By default it is ``
PipPackageNamingConvention = "python_pip_package_naming_convention"
// PipTargetNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. By default it is `pkg`
PipTargetNamingConvention = "python_pip_target_naming_convention"
)

// GenerationModeType represents one of the generation modes for the Python
Expand All@@ -67,7 +78,9 @@ const (
)

const (
packageNameNamingConventionSubstitution = "$package_name$"
repoNamePipRepoNamingConventionSubstitution = "$repo_name$"
distributionNamePipRepoNamingConventionSubstitution = "$distribution_name$"
packageNameNamingConventionSubstitution = "$package_name$"
)

// defaultIgnoreFiles is the list of default values used in the
Expand DownExpand Up@@ -99,14 +112,17 @@ type Config struct {
pythonProjectRoot string
gazelleManifest *manifest.Manifest

excludedPatterns *singlylinkedlist.List
ignoreFiles map[string]struct{}
ignoreDependencies map[string]struct{}
validateImportStatements bool
coarseGrainedGeneration bool
libraryNamingConvention string
binaryNamingConvention string
testNamingConvention string
excludedPatterns *singlylinkedlist.List
ignoreFiles map[string]struct{}
ignoreDependencies map[string]struct{}
validateImportStatements bool
coarseGrainedGeneration bool
libraryNamingConvention string
binaryNamingConvention string
testNamingConvention string
pipRepoNamingConvention string
pipPackageNamingConvention string
pipTargetNamingConvention string
}

// New creates a new Config.
Expand All@@ -115,17 +131,20 @@ func New(
pythonProjectRoot string,
) *Config {
return &Config{
extensionEnabled: true,
repoRoot: repoRoot,
pythonProjectRoot: pythonProjectRoot,
excludedPatterns: singlylinkedlist.New(),
ignoreFiles: make(map[string]struct{}),
ignoreDependencies: make(map[string]struct{}),
validateImportStatements: true,
coarseGrainedGeneration: false,
libraryNamingConvention: packageNameNamingConventionSubstitution,
binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
extensionEnabled: true,
repoRoot: repoRoot,
pythonProjectRoot: pythonProjectRoot,
excludedPatterns: singlylinkedlist.New(),
ignoreFiles: make(map[string]struct{}),
ignoreDependencies: make(map[string]struct{}),
validateImportStatements: true,
coarseGrainedGeneration: false,
libraryNamingConvention: packageNameNamingConventionSubstitution,
binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
pipRepoNamingConvention: fmt.Sprintf("%s_%s", repoNamePipRepoNamingConventionSubstitution, distributionNamePipRepoNamingConventionSubstitution),
pipPackageNamingConvention: "",
pipTargetNamingConvention: "pkg",
}
}

Expand All@@ -150,6 +169,9 @@ func (c *Config) NewChild() *Config {
libraryNamingConvention: c.libraryNamingConvention,
binaryNamingConvention: c.binaryNamingConvention,
testNamingConvention: c.testNamingConvention,
pipRepoNamingConvention: c.pipRepoNamingConvention,
pipPackageNamingConvention: c.pipPackageNamingConvention,
pipTargetNamingConvention: c.pipTargetNamingConvention,
}
}

Expand DownExpand Up@@ -195,24 +217,32 @@ func (c *Config) SetGazelleManifest(gazelleManifest *manifest.Manifest) {
// name.
func (c *Config) FindThirdPartyDependency(modName string) (string, bool) {
for currentCfg := c; currentCfg != nil; currentCfg = currentCfg.parent {
if currentCfg.gazelleManifest != nil {
gazelleManifest := currentCfg.gazelleManifest
if distributionName, ok := gazelleManifest.ModulesMapping[modName]; ok {
var distributionRepositoryName string
if gazelleManifest.PipDepsRepositoryName != "" {
distributionRepositoryName = gazelleManifest.PipDepsRepositoryName
} else if gazelleManifest.PipRepository != nil {
distributionRepositoryName = gazelleManifest.PipRepository.Name
}
sanitizedDistribution := strings.ToLower(distributionName)
sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")
var lbl label.Label
// @<repository_name>_<distribution_name>//:pkg
distributionRepositoryName = distributionRepositoryName + "_" + sanitizedDistribution
lbl = label.New(distributionRepositoryName, "", "pkg")
return lbl.String(), true
}

if currentCfg.gazelleManifest == nil {
continue
}

gazelleManifest := currentCfg.gazelleManifest
distributionName, ok := gazelleManifest.ModulesMapping[modName]
if !ok {
continue
}

var distributionRepositoryName string
if gazelleManifest.PipDepsRepositoryName != "" {
distributionRepositoryName = gazelleManifest.PipDepsRepositoryName
} else if gazelleManifest.PipRepository != nil {
distributionRepositoryName = gazelleManifest.PipRepository.Name
}
sanitizedDistribution := strings.ToLower(distributionName)
sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")

lbl := label.New(
currentCfg.renderPipRepository(distributionRepositoryName, sanitizedDistribution),
currentCfg.renderPipPackage(sanitizedDistribution),
currentCfg.renderPipTarget(sanitizedDistribution),
)
return lbl.String(), true
}
return "", false
}
Expand DownExpand Up@@ -327,6 +357,37 @@ func (c *Config) SetTestNamingConvention(testNamingConvention string) {
c.testNamingConvention = testNamingConvention
}

// SetPipRepoNamingConvention sets the dependency naming convention.
func (c *Config) SetPipRepoNamingConvention(pipRepoNamingConvention string) {
c.pipRepoNamingConvention = pipRepoNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipRepository(distributionRepoName, distributionName string) string {
rendered := strings.ReplaceAll(c.pipRepoNamingConvention, repoNamePipRepoNamingConventionSubstitution, distributionRepoName)
return strings.ReplaceAll(rendered, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// SetPipPackageNamingConvention sets the dependency naming convention.
func (c *Config) SetPipPackageNamingConvention(pipPackageNamingConvention string) {
c.pipPackageNamingConvention = pipPackageNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipPackage(distributionName string) string {
return strings.ReplaceAll(c.pipPackageNamingConvention, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// SetPipTargetNamingConvention sets the dependency naming convention.
func (c *Config) SetPipTargetNamingConvention(pipTargetNamingConvention string) {
c.pipTargetNamingConvention = pipTargetNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipTarget(distributionName string) string {
return strings.ReplaceAll(c.pipTargetNamingConvention, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// RenderTestName returns the py_test target name by performing all
// substitutions.
func (c *Config) RenderTestName(packageName string) string {
Expand Down
19 changes: 19 additions & 0 deletions gazelle/pythonconfig/pythonconfig_test.go
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
package pythonconfig

import (
"reflect"
"testing"
)

func TestConfigNewChild(t *testing.T) {
parent := New("foo", "bar")
child := parent.NewChild()

if child.parent == nil {
t.Error("child parent should not be nil")
}
child.parent = nil
if !reflect.DeepEqual(child, parent) {
t.Errorf("child and should should be equal other than the parent reference. Parent: %#v\nChild: %#v", parent, child)
}
}
2 changes: 1 addition & 1 deletion gazelle/pythonconfig/types.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,4 +100,4 @@ func (sml *StringMapList) Set(s string) error {
func (sml *StringMapList) Get(key string) (string, bool) {
val, exists := sml.mapping[key]
return val, exists
}
}
3 changes: 3 additions & 0 deletions gazelle/testdata/pip_repo_convention/BUILD.in
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
# gazelle:python_pip_repo_naming_convention $repo_name$
# gazelle:python_pip_package_naming_convention $distribution_name$
# gazelle:python_pip_target_naming_convention $distribution_name$_pkg
31 changes: 31 additions & 0 deletions gazelle/testdata/pip_repo_convention/BUILD.out
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
load("@rules_python//python:defs.bzl", "py_binary", "py_library")

# gazelle:python_pip_repo_naming_convention $repo_name$
# gazelle:python_pip_package_naming_convention $distribution_name$
# gazelle:python_pip_target_naming_convention $distribution_name$_pkg

py_library(
name = "pip_repo_convention",
srcs = [
"__init__.py",
"bar.py",
"foo.py",
],
visibility = ["//:__subpackages__"],
deps = [
"@pip_deps//baz:baz_pkg",
"@pip_deps//boto3:boto3_pkg",
"@pip_deps//djangorestframework:djangorestframework_pkg",
],
)

py_binary(
name = "pip_repo_convention_bin",
srcs = ["__main__.py"],
main = "__main__.py",
visibility = ["//:__subpackages__"],
deps = [
":pip_repo_convention",
"@pip_deps//baz:baz_pkg",
],
)
3 changes: 3 additions & 0 deletions gazelle/testdata/pip_repo_convention/README.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
# Pip repo convention

This test case asserts that the dependency labels generated by gazelle follow a particular convention, that can be changed using directives.
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/WORKSPACE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
# This is a Bazel workspace for the Gazelle test data.
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/__init__.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
# For test purposes only.
5 changes: 5 additions & 0 deletions gazelle/testdata/pip_repo_convention/__main__.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
import bar
import foo

_ = bar
_ = foo
11 changes: 11 additions & 0 deletions gazelle/testdata/pip_repo_convention/bar.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
import os

import bar
import boto3
import rest_framework

_ = os

_ = bar
_ = boto3
_ = rest_framework
11 changes: 11 additions & 0 deletions gazelle/testdata/pip_repo_convention/foo.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
import sys

import boto3
import foo
import rest_framework

_ = sys

_ = boto3
_ = foo
_ = rest_framework
8 changes: 8 additions & 0 deletions gazelle/testdata/pip_repo_convention/gazelle_python.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
manifest:
modules_mapping:
boto3: boto3
rest_framework: djangorestframework
foo: baz
bar: baz
pip_repository:
name: pip_deps
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/test.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
---
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions gazelle/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,6 +147,12 @@ Python-specific directives are as follows:
| Controls the `py_test` naming convention. Follows the same interpolation rules as `python_library_naming_convention`. | |
| `# gazelle:resolve py ...` | n/a |
| Instructs the plugin what target to add as a dependency to satisfy a given import statement. The syntax is `# gazelle:resolve py import-string label` where `import-string` is the symbol in the python `import` statement, and `label` is the Bazel label that Gazelle should write in `deps`. | |
| `# gazelle:python_pip_repo_naming_convention` | `$repo_name$_$distribution_name$` |
| Controls the external dependency label naming convention. It interpolates `$repo_name$` and `$distribution_name$` with the Bazel external pip repository name and the sanitized Python package name respectively. E.g. if the Bazel external pip repository name is `my_pip_deps` and we are resolving external Python package named `flake-bugbear`, setting this to `$repo_name$_host_$distribution_name$` would result in a generated target named `my_pip_deps_host_flake8_bugbear`. | |
| `# gazelle:python_pip_package_naming_convention` | n/a |
| Controls the external dependency label naming convention. It interpolates `$distribution_name$` with the sanitized Python package name. See `gazelle:python_pip_repo_naming_convention` for details. This may be useful if you have `alias` targets which point to platform specific Python wheels in your repo, e.g. `//third_party/pip:flake8_bugbear_alias`. | |
| `# gazelle:python_pip_target_naming_convention` | `pkg` |
| Controls the external dependency label naming convention. It interpolates `$distribution_name$` with the sanitized Python package name respectively. See `gazelle:python_pip_repo_naming_convention` for details. This may be useful if you have `alias` targets which point to platform specific Python wheels in your repo, e.g. `//third_party/pip:flake8_bugbear_alias` or if you are using `gazelle` with `bzlmod`. | |

### Libraries

Expand Down
9 changes: 9 additions & 0 deletions gazelle/configure.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,9 @@ func (py *Configurer) KnownDirectives() []string {
pythonconfig.LibraryNamingConvention,
pythonconfig.BinaryNamingConvention,
pythonconfig.TestNamingConvention,
pythonconfig.PipRepoNamingConvention,
pythonconfig.PipPackageNamingConvention,
pythonconfig.PipTargetNamingConvention,
}
}

Expand DownExpand Up@@ -136,6 +139,12 @@ func (py *Configurer) Configure(c *config.Config, rel string, f *rule.File) {
config.SetBinaryNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.TestNamingConvention:
config.SetTestNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipRepoNamingConvention:
config.SetPipRepoNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipPackageNamingConvention:
config.SetPipPackageNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipTargetNamingConvention:
config.SetPipTargetNamingConvention(strings.TrimSpace(d.Value))
}
}

Expand Down
8 changes: 7 additions & 1 deletion gazelle/pythonconfig/BUILD.bazel
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "pythonconfig",
Expand All@@ -20,3 +20,9 @@ filegroup(
srcs = glob(["**"]),
visibility = ["//gazelle:__pkg__"],
)

go_test(
name = "pythonconfig_test",
srcs = ["pythonconfig_test.go"],
embed = [":pythonconfig"],
)
135 changes: 98 additions & 37 deletions gazelle/pythonconfig/pythonconfig.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,6 +49,17 @@ const (
// naming convention. See python_library_naming_convention for more info on
// the package name interpolation.
TestNamingConvention = "python_test_naming_convention"
// PipRepoNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. E.g. if the Python package name is `foo` and the
// pip repository is named `my_pip`, setting this
// to `$repo_name$_$distribution_name$` would render to `@my_pip_foo`.
PipRepoNamingConvention = "python_pip_repo_naming_convention"
// PipPackageNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. By default it is ``
PipPackageNamingConvention = "python_pip_package_naming_convention"
// PipTargetNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. By default it is `pkg`
PipTargetNamingConvention = "python_pip_target_naming_convention"
)

// GenerationModeType represents one of the generation modes for the Python
Expand All@@ -67,7 +78,9 @@ const (
)

const (
packageNameNamingConventionSubstitution = "$package_name$"
repoNamePipRepoNamingConventionSubstitution = "$repo_name$"
distributionNamePipRepoNamingConventionSubstitution = "$distribution_name$"
packageNameNamingConventionSubstitution = "$package_name$"
)

// defaultIgnoreFiles is the list of default values used in the
Expand DownExpand Up@@ -99,14 +112,17 @@ type Config struct {
pythonProjectRoot string
gazelleManifest *manifest.Manifest

excludedPatterns *singlylinkedlist.List
ignoreFiles map[string]struct{}
ignoreDependencies map[string]struct{}
validateImportStatements bool
coarseGrainedGeneration bool
libraryNamingConvention string
binaryNamingConvention string
testNamingConvention string
excludedPatterns *singlylinkedlist.List
ignoreFiles map[string]struct{}
ignoreDependencies map[string]struct{}
validateImportStatements bool
coarseGrainedGeneration bool
libraryNamingConvention string
binaryNamingConvention string
testNamingConvention string
pipRepoNamingConvention string
pipPackageNamingConvention string
pipTargetNamingConvention string
}

// New creates a new Config.
Expand All@@ -115,17 +131,20 @@ func New(
pythonProjectRoot string,
) *Config {
return &Config{
extensionEnabled: true,
repoRoot: repoRoot,
pythonProjectRoot: pythonProjectRoot,
excludedPatterns: singlylinkedlist.New(),
ignoreFiles: make(map[string]struct{}),
ignoreDependencies: make(map[string]struct{}),
validateImportStatements: true,
coarseGrainedGeneration: false,
libraryNamingConvention: packageNameNamingConventionSubstitution,
binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
extensionEnabled: true,
repoRoot: repoRoot,
pythonProjectRoot: pythonProjectRoot,
excludedPatterns: singlylinkedlist.New(),
ignoreFiles: make(map[string]struct{}),
ignoreDependencies: make(map[string]struct{}),
validateImportStatements: true,
coarseGrainedGeneration: false,
libraryNamingConvention: packageNameNamingConventionSubstitution,
binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
pipRepoNamingConvention: fmt.Sprintf("%s_%s", repoNamePipRepoNamingConventionSubstitution, distributionNamePipRepoNamingConventionSubstitution),
pipPackageNamingConvention: "",
pipTargetNamingConvention: "pkg",
}
}

Expand All@@ -150,6 +169,9 @@ func (c *Config) NewChild() *Config {
libraryNamingConvention: c.libraryNamingConvention,
binaryNamingConvention: c.binaryNamingConvention,
testNamingConvention: c.testNamingConvention,
pipRepoNamingConvention: c.pipRepoNamingConvention,
pipPackageNamingConvention: c.pipPackageNamingConvention,
pipTargetNamingConvention: c.pipTargetNamingConvention,
}
}

Expand DownExpand Up@@ -195,24 +217,32 @@ func (c *Config) SetGazelleManifest(gazelleManifest *manifest.Manifest) {
// name.
func (c *Config) FindThirdPartyDependency(modName string) (string, bool) {
for currentCfg := c; currentCfg != nil; currentCfg = currentCfg.parent {
if currentCfg.gazelleManifest != nil {
gazelleManifest := currentCfg.gazelleManifest
if distributionName, ok := gazelleManifest.ModulesMapping[modName]; ok {
var distributionRepositoryName string
if gazelleManifest.PipDepsRepositoryName != "" {
distributionRepositoryName = gazelleManifest.PipDepsRepositoryName
} else if gazelleManifest.PipRepository != nil {
distributionRepositoryName = gazelleManifest.PipRepository.Name
}
sanitizedDistribution := strings.ToLower(distributionName)
sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")
var lbl label.Label
// @<repository_name>_<distribution_name>//:pkg
distributionRepositoryName = distributionRepositoryName + "_" + sanitizedDistribution
lbl = label.New(distributionRepositoryName, "", "pkg")
return lbl.String(), true
}

if currentCfg.gazelleManifest == nil {
continue
}

gazelleManifest := currentCfg.gazelleManifest
distributionName, ok := gazelleManifest.ModulesMapping[modName]
if !ok {
continue
}

var distributionRepositoryName string
if gazelleManifest.PipDepsRepositoryName != "" {
distributionRepositoryName = gazelleManifest.PipDepsRepositoryName
} else if gazelleManifest.PipRepository != nil {
distributionRepositoryName = gazelleManifest.PipRepository.Name
}
sanitizedDistribution := strings.ToLower(distributionName)
sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")

lbl := label.New(
currentCfg.renderPipRepository(distributionRepositoryName, sanitizedDistribution),
currentCfg.renderPipPackage(sanitizedDistribution),
currentCfg.renderPipTarget(sanitizedDistribution),
)
return lbl.String(), true
}
return "", false
}
Expand DownExpand Up@@ -327,6 +357,37 @@ func (c *Config) SetTestNamingConvention(testNamingConvention string) {
c.testNamingConvention = testNamingConvention
}

// SetPipRepoNamingConvention sets the dependency naming convention.
func (c *Config) SetPipRepoNamingConvention(pipRepoNamingConvention string) {
c.pipRepoNamingConvention = pipRepoNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipRepository(distributionRepoName, distributionName string) string {
rendered := strings.ReplaceAll(c.pipRepoNamingConvention, repoNamePipRepoNamingConventionSubstitution, distributionRepoName)
return strings.ReplaceAll(rendered, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// SetPipPackageNamingConvention sets the dependency naming convention.
func (c *Config) SetPipPackageNamingConvention(pipPackageNamingConvention string) {
c.pipPackageNamingConvention = pipPackageNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipPackage(distributionName string) string {
return strings.ReplaceAll(c.pipPackageNamingConvention, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// SetPipTargetNamingConvention sets the dependency naming convention.
func (c *Config) SetPipTargetNamingConvention(pipTargetNamingConvention string) {
c.pipTargetNamingConvention = pipTargetNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipTarget(distributionName string) string {
return strings.ReplaceAll(c.pipTargetNamingConvention, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// RenderTestName returns the py_test target name by performing all
// substitutions.
func (c *Config) RenderTestName(packageName string) string {
Expand Down
19 changes: 19 additions & 0 deletions gazelle/pythonconfig/pythonconfig_test.go
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
package pythonconfig

import (
"reflect"
"testing"
)

func TestConfigNewChild(t *testing.T) {
parent := New("foo", "bar")
child := parent.NewChild()

if child.parent == nil {
t.Error("child parent should not be nil")
}
child.parent = nil
if !reflect.DeepEqual(child, parent) {
t.Errorf("child and should should be equal other than the parent reference. Parent: %#v\nChild: %#v", parent, child)
}
}
2 changes: 1 addition & 1 deletion gazelle/pythonconfig/types.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,4 +100,4 @@ func (sml *StringMapList) Set(s string) error {
func (sml *StringMapList) Get(key string) (string, bool) {
val, exists := sml.mapping[key]
return val, exists
}
}
3 changes: 3 additions & 0 deletions gazelle/testdata/pip_repo_convention/BUILD.in
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
# gazelle:python_pip_repo_naming_convention $repo_name$
# gazelle:python_pip_package_naming_convention $distribution_name$
# gazelle:python_pip_target_naming_convention $distribution_name$_pkg
31 changes: 31 additions & 0 deletions gazelle/testdata/pip_repo_convention/BUILD.out
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
load("@rules_python//python:defs.bzl", "py_binary", "py_library")

# gazelle:python_pip_repo_naming_convention $repo_name$
# gazelle:python_pip_package_naming_convention $distribution_name$
# gazelle:python_pip_target_naming_convention $distribution_name$_pkg

py_library(
name = "pip_repo_convention",
srcs = [
"__init__.py",
"bar.py",
"foo.py",
],
visibility = ["//:__subpackages__"],
deps = [
"@pip_deps//baz:baz_pkg",
"@pip_deps//boto3:boto3_pkg",
"@pip_deps//djangorestframework:djangorestframework_pkg",
],
)

py_binary(
name = "pip_repo_convention_bin",
srcs = ["__main__.py"],
main = "__main__.py",
visibility = ["//:__subpackages__"],
deps = [
":pip_repo_convention",
"@pip_deps//baz:baz_pkg",
],
)
3 changes: 3 additions & 0 deletions gazelle/testdata/pip_repo_convention/README.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
# Pip repo convention

This test case asserts that the dependency labels generated by gazelle follow a particular convention, that can be changed using directives.
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/WORKSPACE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
# This is a Bazel workspace for the Gazelle test data.
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/__init__.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
# For test purposes only.
5 changes: 5 additions & 0 deletions gazelle/testdata/pip_repo_convention/__main__.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
import bar
import foo

_ = bar
_ = foo
11 changes: 11 additions & 0 deletions gazelle/testdata/pip_repo_convention/bar.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
import os

import bar
import boto3
import rest_framework

_ = os

_ = bar
_ = boto3
_ = rest_framework
11 changes: 11 additions & 0 deletions gazelle/testdata/pip_repo_convention/foo.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
import sys

import boto3
import foo
import rest_framework

_ = sys

_ = boto3
_ = foo
_ = rest_framework
8 changes: 8 additions & 0 deletions gazelle/testdata/pip_repo_convention/gazelle_python.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
manifest:
modules_mapping:
boto3: boto3
rest_framework: djangorestframework
foo: baz
bar: baz
pip_repository:
name: pip_deps
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/test.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
---
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions gazelle/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,6 +147,12 @@ Python-specific directives are as follows:
| Controls the `py_test` naming convention. Follows the same interpolation rules as `python_library_naming_convention`. | |
| `# gazelle:resolve py ...` | n/a |
| Instructs the plugin what target to add as a dependency to satisfy a given import statement. The syntax is `# gazelle:resolve py import-string label` where `import-string` is the symbol in the python `import` statement, and `label` is the Bazel label that Gazelle should write in `deps`. | |
| `# gazelle:python_pip_repo_naming_convention` | `$repo_name$_$distribution_name$` |
| Controls the external dependency label naming convention. It interpolates `$repo_name$` and `$distribution_name$` with the Bazel external pip repository name and the sanitized Python package name respectively. E.g. if the Bazel external pip repository name is `my_pip_deps` and we are resolving external Python package named `flake-bugbear`, setting this to `$repo_name$_host_$distribution_name$` would result in a generated target named `my_pip_deps_host_flake8_bugbear`. | |
| `# gazelle:python_pip_package_naming_convention` | n/a |
| Controls the external dependency label naming convention. It interpolates `$distribution_name$` with the sanitized Python package name. See `gazelle:python_pip_repo_naming_convention` for details. This may be useful if you have `alias` targets which point to platform specific Python wheels in your repo, e.g. `//third_party/pip:flake8_bugbear_alias`. | |
| `# gazelle:python_pip_target_naming_convention` | `pkg` |
| Controls the external dependency label naming convention. It interpolates `$distribution_name$` with the sanitized Python package name respectively. See `gazelle:python_pip_repo_naming_convention` for details. This may be useful if you have `alias` targets which point to platform specific Python wheels in your repo, e.g. `//third_party/pip:flake8_bugbear_alias` or if you are using `gazelle` with `bzlmod`. | |

### Libraries

Expand Down
9 changes: 9 additions & 0 deletions gazelle/configure.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,9 @@ func (py *Configurer) KnownDirectives() []string {
pythonconfig.LibraryNamingConvention,
pythonconfig.BinaryNamingConvention,
pythonconfig.TestNamingConvention,
pythonconfig.PipRepoNamingConvention,
pythonconfig.PipPackageNamingConvention,
pythonconfig.PipTargetNamingConvention,
}
}

Expand DownExpand Up@@ -136,6 +139,12 @@ func (py *Configurer) Configure(c *config.Config, rel string, f *rule.File) {
config.SetBinaryNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.TestNamingConvention:
config.SetTestNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipRepoNamingConvention:
config.SetPipRepoNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipPackageNamingConvention:
config.SetPipPackageNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipTargetNamingConvention:
config.SetPipTargetNamingConvention(strings.TrimSpace(d.Value))
}
}

Expand Down
8 changes: 7 additions & 1 deletion gazelle/pythonconfig/BUILD.bazel
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "pythonconfig",
Expand All@@ -20,3 +20,9 @@ filegroup(
srcs = glob(["**"]),
visibility = ["//gazelle:__pkg__"],
)

go_test(
name = "pythonconfig_test",
srcs = ["pythonconfig_test.go"],
embed = [":pythonconfig"],
)
135 changes: 98 additions & 37 deletions gazelle/pythonconfig/pythonconfig.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,6 +49,17 @@ const (
// naming convention. See python_library_naming_convention for more info on
// the package name interpolation.
TestNamingConvention = "python_test_naming_convention"
// PipRepoNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. E.g. if the Python package name is `foo` and the
// pip repository is named `my_pip`, setting this
// to `$repo_name$_$distribution_name$` would render to `@my_pip_foo`.
PipRepoNamingConvention = "python_pip_repo_naming_convention"
// PipPackageNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. By default it is ``
PipPackageNamingConvention = "python_pip_package_naming_convention"
// PipTargetNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. By default it is `pkg`
PipTargetNamingConvention = "python_pip_target_naming_convention"
)

// GenerationModeType represents one of the generation modes for the Python
Expand All@@ -67,7 +78,9 @@ const (
)

const (
packageNameNamingConventionSubstitution = "$package_name$"
repoNamePipRepoNamingConventionSubstitution = "$repo_name$"
distributionNamePipRepoNamingConventionSubstitution = "$distribution_name$"
packageNameNamingConventionSubstitution = "$package_name$"
)

// defaultIgnoreFiles is the list of default values used in the
Expand DownExpand Up@@ -99,14 +112,17 @@ type Config struct {
pythonProjectRoot string
gazelleManifest *manifest.Manifest

excludedPatterns *singlylinkedlist.List
ignoreFiles map[string]struct{}
ignoreDependencies map[string]struct{}
validateImportStatements bool
coarseGrainedGeneration bool
libraryNamingConvention string
binaryNamingConvention string
testNamingConvention string
excludedPatterns *singlylinkedlist.List
ignoreFiles map[string]struct{}
ignoreDependencies map[string]struct{}
validateImportStatements bool
coarseGrainedGeneration bool
libraryNamingConvention string
binaryNamingConvention string
testNamingConvention string
pipRepoNamingConvention string
pipPackageNamingConvention string
pipTargetNamingConvention string
}

// New creates a new Config.
Expand All@@ -115,17 +131,20 @@ func New(
pythonProjectRoot string,
) *Config {
return &Config{
extensionEnabled: true,
repoRoot: repoRoot,
pythonProjectRoot: pythonProjectRoot,
excludedPatterns: singlylinkedlist.New(),
ignoreFiles: make(map[string]struct{}),
ignoreDependencies: make(map[string]struct{}),
validateImportStatements: true,
coarseGrainedGeneration: false,
libraryNamingConvention: packageNameNamingConventionSubstitution,
binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
extensionEnabled: true,
repoRoot: repoRoot,
pythonProjectRoot: pythonProjectRoot,
excludedPatterns: singlylinkedlist.New(),
ignoreFiles: make(map[string]struct{}),
ignoreDependencies: make(map[string]struct{}),
validateImportStatements: true,
coarseGrainedGeneration: false,
libraryNamingConvention: packageNameNamingConventionSubstitution,
binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
pipRepoNamingConvention: fmt.Sprintf("%s_%s", repoNamePipRepoNamingConventionSubstitution, distributionNamePipRepoNamingConventionSubstitution),
pipPackageNamingConvention: "",
pipTargetNamingConvention: "pkg",
}
}

Expand All@@ -150,6 +169,9 @@ func (c *Config) NewChild() *Config {
libraryNamingConvention: c.libraryNamingConvention,
binaryNamingConvention: c.binaryNamingConvention,
testNamingConvention: c.testNamingConvention,
pipRepoNamingConvention: c.pipRepoNamingConvention,
pipPackageNamingConvention: c.pipPackageNamingConvention,
pipTargetNamingConvention: c.pipTargetNamingConvention,
}
}

Expand DownExpand Up@@ -195,24 +217,32 @@ func (c *Config) SetGazelleManifest(gazelleManifest *manifest.Manifest) {
// name.
func (c *Config) FindThirdPartyDependency(modName string) (string, bool) {
for currentCfg := c; currentCfg != nil; currentCfg = currentCfg.parent {
if currentCfg.gazelleManifest != nil {
gazelleManifest := currentCfg.gazelleManifest
if distributionName, ok := gazelleManifest.ModulesMapping[modName]; ok {
var distributionRepositoryName string
if gazelleManifest.PipDepsRepositoryName != "" {
distributionRepositoryName = gazelleManifest.PipDepsRepositoryName
} else if gazelleManifest.PipRepository != nil {
distributionRepositoryName = gazelleManifest.PipRepository.Name
}
sanitizedDistribution := strings.ToLower(distributionName)
sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")
var lbl label.Label
// @<repository_name>_<distribution_name>//:pkg
distributionRepositoryName = distributionRepositoryName + "_" + sanitizedDistribution
lbl = label.New(distributionRepositoryName, "", "pkg")
return lbl.String(), true
}

if currentCfg.gazelleManifest == nil {
continue
}

gazelleManifest := currentCfg.gazelleManifest
distributionName, ok := gazelleManifest.ModulesMapping[modName]
if !ok {
continue
}

var distributionRepositoryName string
if gazelleManifest.PipDepsRepositoryName != "" {
distributionRepositoryName = gazelleManifest.PipDepsRepositoryName
} else if gazelleManifest.PipRepository != nil {
distributionRepositoryName = gazelleManifest.PipRepository.Name
}
sanitizedDistribution := strings.ToLower(distributionName)
sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")

lbl := label.New(
currentCfg.renderPipRepository(distributionRepositoryName, sanitizedDistribution),
currentCfg.renderPipPackage(sanitizedDistribution),
currentCfg.renderPipTarget(sanitizedDistribution),
)
return lbl.String(), true
}
return "", false
}
Expand DownExpand Up@@ -327,6 +357,37 @@ func (c *Config) SetTestNamingConvention(testNamingConvention string) {
c.testNamingConvention = testNamingConvention
}

// SetPipRepoNamingConvention sets the dependency naming convention.
func (c *Config) SetPipRepoNamingConvention(pipRepoNamingConvention string) {
c.pipRepoNamingConvention = pipRepoNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipRepository(distributionRepoName, distributionName string) string {
rendered := strings.ReplaceAll(c.pipRepoNamingConvention, repoNamePipRepoNamingConventionSubstitution, distributionRepoName)
return strings.ReplaceAll(rendered, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// SetPipPackageNamingConvention sets the dependency naming convention.
func (c *Config) SetPipPackageNamingConvention(pipPackageNamingConvention string) {
c.pipPackageNamingConvention = pipPackageNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipPackage(distributionName string) string {
return strings.ReplaceAll(c.pipPackageNamingConvention, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// SetPipTargetNamingConvention sets the dependency naming convention.
func (c *Config) SetPipTargetNamingConvention(pipTargetNamingConvention string) {
c.pipTargetNamingConvention = pipTargetNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipTarget(distributionName string) string {
return strings.ReplaceAll(c.pipTargetNamingConvention, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// RenderTestName returns the py_test target name by performing all
// substitutions.
func (c *Config) RenderTestName(packageName string) string {
Expand Down
19 changes: 19 additions & 0 deletions gazelle/pythonconfig/pythonconfig_test.go
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
package pythonconfig

import (
"reflect"
"testing"
)

func TestConfigNewChild(t *testing.T) {
parent := New("foo", "bar")
child := parent.NewChild()

if child.parent == nil {
t.Error("child parent should not be nil")
}
child.parent = nil
if !reflect.DeepEqual(child, parent) {
t.Errorf("child and should should be equal other than the parent reference. Parent: %#v\nChild: %#v", parent, child)
}
}
2 changes: 1 addition & 1 deletion gazelle/pythonconfig/types.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,4 +100,4 @@ func (sml *StringMapList) Set(s string) error {
func (sml *StringMapList) Get(key string) (string, bool) {
val, exists := sml.mapping[key]
return val, exists
}
}
3 changes: 3 additions & 0 deletions gazelle/testdata/pip_repo_convention/BUILD.in
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
# gazelle:python_pip_repo_naming_convention $repo_name$
# gazelle:python_pip_package_naming_convention $distribution_name$
# gazelle:python_pip_target_naming_convention $distribution_name$_pkg
31 changes: 31 additions & 0 deletions gazelle/testdata/pip_repo_convention/BUILD.out
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
load("@rules_python//python:defs.bzl", "py_binary", "py_library")

# gazelle:python_pip_repo_naming_convention $repo_name$
# gazelle:python_pip_package_naming_convention $distribution_name$
# gazelle:python_pip_target_naming_convention $distribution_name$_pkg

py_library(
name = "pip_repo_convention",
srcs = [
"__init__.py",
"bar.py",
"foo.py",
],
visibility = ["//:__subpackages__"],
deps = [
"@pip_deps//baz:baz_pkg",
"@pip_deps//boto3:boto3_pkg",
"@pip_deps//djangorestframework:djangorestframework_pkg",
],
)

py_binary(
name = "pip_repo_convention_bin",
srcs = ["__main__.py"],
main = "__main__.py",
visibility = ["//:__subpackages__"],
deps = [
":pip_repo_convention",
"@pip_deps//baz:baz_pkg",
],
)
3 changes: 3 additions & 0 deletions gazelle/testdata/pip_repo_convention/README.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
# Pip repo convention

This test case asserts that the dependency labels generated by gazelle follow a particular convention, that can be changed using directives.
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/WORKSPACE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
# This is a Bazel workspace for the Gazelle test data.
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/__init__.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
# For test purposes only.
5 changes: 5 additions & 0 deletions gazelle/testdata/pip_repo_convention/__main__.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
import bar
import foo

_ = bar
_ = foo
11 changes: 11 additions & 0 deletions gazelle/testdata/pip_repo_convention/bar.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
import os

import bar
import boto3
import rest_framework

_ = os

_ = bar
_ = boto3
_ = rest_framework
11 changes: 11 additions & 0 deletions gazelle/testdata/pip_repo_convention/foo.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
import sys

import boto3
import foo
import rest_framework

_ = sys

_ = boto3
_ = foo
_ = rest_framework
8 changes: 8 additions & 0 deletions gazelle/testdata/pip_repo_convention/gazelle_python.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
manifest:
modules_mapping:
boto3: boto3
rest_framework: djangorestframework
foo: baz
bar: baz
pip_repository:
name: pip_deps
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/test.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
---
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions gazelle/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,6 +147,12 @@ Python-specific directives are as follows:
| Controls the `py_test` naming convention. Follows the same interpolation rules as `python_library_naming_convention`. | |
| `# gazelle:resolve py ...` | n/a |
| Instructs the plugin what target to add as a dependency to satisfy a given import statement. The syntax is `# gazelle:resolve py import-string label` where `import-string` is the symbol in the python `import` statement, and `label` is the Bazel label that Gazelle should write in `deps`. | |
| `# gazelle:python_pip_repo_naming_convention` | `$repo_name$_$distribution_name$` |
| Controls the external dependency label naming convention. It interpolates `$repo_name$` and `$distribution_name$` with the Bazel external pip repository name and the sanitized Python package name respectively. E.g. if the Bazel external pip repository name is `my_pip_deps` and we are resolving external Python package named `flake-bugbear`, setting this to `$repo_name$_host_$distribution_name$` would result in a generated target named `my_pip_deps_host_flake8_bugbear`. | |
| `# gazelle:python_pip_package_naming_convention` | n/a |
| Controls the external dependency label naming convention. It interpolates `$distribution_name$` with the sanitized Python package name. See `gazelle:python_pip_repo_naming_convention` for details. This may be useful if you have `alias` targets which point to platform specific Python wheels in your repo, e.g. `//third_party/pip:flake8_bugbear_alias`. | |
| `# gazelle:python_pip_target_naming_convention` | `pkg` |
| Controls the external dependency label naming convention. It interpolates `$distribution_name$` with the sanitized Python package name respectively. See `gazelle:python_pip_repo_naming_convention` for details. This may be useful if you have `alias` targets which point to platform specific Python wheels in your repo, e.g. `//third_party/pip:flake8_bugbear_alias` or if you are using `gazelle` with `bzlmod`. | |

### Libraries

Expand Down
9 changes: 9 additions & 0 deletions gazelle/configure.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,9 @@ func (py *Configurer) KnownDirectives() []string {
pythonconfig.LibraryNamingConvention,
pythonconfig.BinaryNamingConvention,
pythonconfig.TestNamingConvention,
pythonconfig.PipRepoNamingConvention,
pythonconfig.PipPackageNamingConvention,
pythonconfig.PipTargetNamingConvention,
}
}

Expand DownExpand Up@@ -136,6 +139,12 @@ func (py *Configurer) Configure(c *config.Config, rel string, f *rule.File) {
config.SetBinaryNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.TestNamingConvention:
config.SetTestNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipRepoNamingConvention:
config.SetPipRepoNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipPackageNamingConvention:
config.SetPipPackageNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipTargetNamingConvention:
config.SetPipTargetNamingConvention(strings.TrimSpace(d.Value))
}
}

Expand Down
8 changes: 7 additions & 1 deletion gazelle/pythonconfig/BUILD.bazel
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "pythonconfig",
Expand All@@ -20,3 +20,9 @@ filegroup(
srcs = glob(["**"]),
visibility = ["//gazelle:__pkg__"],
)

go_test(
name = "pythonconfig_test",
srcs = ["pythonconfig_test.go"],
embed = [":pythonconfig"],
)
135 changes: 98 additions & 37 deletions gazelle/pythonconfig/pythonconfig.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,6 +49,17 @@ const (
// naming convention. See python_library_naming_convention for more info on
// the package name interpolation.
TestNamingConvention = "python_test_naming_convention"
// PipRepoNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. E.g. if the Python package name is `foo` and the
// pip repository is named `my_pip`, setting this
// to `$repo_name$_$distribution_name$` would render to `@my_pip_foo`.
PipRepoNamingConvention = "python_pip_repo_naming_convention"
// PipPackageNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. By default it is ``
PipPackageNamingConvention = "python_pip_package_naming_convention"
// PipTargetNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. By default it is `pkg`
PipTargetNamingConvention = "python_pip_target_naming_convention"
)

// GenerationModeType represents one of the generation modes for the Python
Expand All@@ -67,7 +78,9 @@ const (
)

const (
packageNameNamingConventionSubstitution = "$package_name$"
repoNamePipRepoNamingConventionSubstitution = "$repo_name$"
distributionNamePipRepoNamingConventionSubstitution = "$distribution_name$"
packageNameNamingConventionSubstitution = "$package_name$"
)

// defaultIgnoreFiles is the list of default values used in the
Expand DownExpand Up@@ -99,14 +112,17 @@ type Config struct {
pythonProjectRoot string
gazelleManifest *manifest.Manifest

excludedPatterns *singlylinkedlist.List
ignoreFiles map[string]struct{}
ignoreDependencies map[string]struct{}
validateImportStatements bool
coarseGrainedGeneration bool
libraryNamingConvention string
binaryNamingConvention string
testNamingConvention string
excludedPatterns *singlylinkedlist.List
ignoreFiles map[string]struct{}
ignoreDependencies map[string]struct{}
validateImportStatements bool
coarseGrainedGeneration bool
libraryNamingConvention string
binaryNamingConvention string
testNamingConvention string
pipRepoNamingConvention string
pipPackageNamingConvention string
pipTargetNamingConvention string
}

// New creates a new Config.
Expand All@@ -115,17 +131,20 @@ func New(
pythonProjectRoot string,
) *Config {
return &Config{
extensionEnabled: true,
repoRoot: repoRoot,
pythonProjectRoot: pythonProjectRoot,
excludedPatterns: singlylinkedlist.New(),
ignoreFiles: make(map[string]struct{}),
ignoreDependencies: make(map[string]struct{}),
validateImportStatements: true,
coarseGrainedGeneration: false,
libraryNamingConvention: packageNameNamingConventionSubstitution,
binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
extensionEnabled: true,
repoRoot: repoRoot,
pythonProjectRoot: pythonProjectRoot,
excludedPatterns: singlylinkedlist.New(),
ignoreFiles: make(map[string]struct{}),
ignoreDependencies: make(map[string]struct{}),
validateImportStatements: true,
coarseGrainedGeneration: false,
libraryNamingConvention: packageNameNamingConventionSubstitution,
binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
pipRepoNamingConvention: fmt.Sprintf("%s_%s", repoNamePipRepoNamingConventionSubstitution, distributionNamePipRepoNamingConventionSubstitution),
pipPackageNamingConvention: "",
pipTargetNamingConvention: "pkg",
}
}

Expand All@@ -150,6 +169,9 @@ func (c *Config) NewChild() *Config {
libraryNamingConvention: c.libraryNamingConvention,
binaryNamingConvention: c.binaryNamingConvention,
testNamingConvention: c.testNamingConvention,
pipRepoNamingConvention: c.pipRepoNamingConvention,
pipPackageNamingConvention: c.pipPackageNamingConvention,
pipTargetNamingConvention: c.pipTargetNamingConvention,
}
}

Expand DownExpand Up@@ -195,24 +217,32 @@ func (c *Config) SetGazelleManifest(gazelleManifest *manifest.Manifest) {
// name.
func (c *Config) FindThirdPartyDependency(modName string) (string, bool) {
for currentCfg := c; currentCfg != nil; currentCfg = currentCfg.parent {
if currentCfg.gazelleManifest != nil {
gazelleManifest := currentCfg.gazelleManifest
if distributionName, ok := gazelleManifest.ModulesMapping[modName]; ok {
var distributionRepositoryName string
if gazelleManifest.PipDepsRepositoryName != "" {
distributionRepositoryName = gazelleManifest.PipDepsRepositoryName
} else if gazelleManifest.PipRepository != nil {
distributionRepositoryName = gazelleManifest.PipRepository.Name
}
sanitizedDistribution := strings.ToLower(distributionName)
sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")
var lbl label.Label
// @<repository_name>_<distribution_name>//:pkg
distributionRepositoryName = distributionRepositoryName + "_" + sanitizedDistribution
lbl = label.New(distributionRepositoryName, "", "pkg")
return lbl.String(), true
}

if currentCfg.gazelleManifest == nil {
continue
}

gazelleManifest := currentCfg.gazelleManifest
distributionName, ok := gazelleManifest.ModulesMapping[modName]
if !ok {
continue
}

var distributionRepositoryName string
if gazelleManifest.PipDepsRepositoryName != "" {
distributionRepositoryName = gazelleManifest.PipDepsRepositoryName
} else if gazelleManifest.PipRepository != nil {
distributionRepositoryName = gazelleManifest.PipRepository.Name
}
sanitizedDistribution := strings.ToLower(distributionName)
sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")

lbl := label.New(
currentCfg.renderPipRepository(distributionRepositoryName, sanitizedDistribution),
currentCfg.renderPipPackage(sanitizedDistribution),
currentCfg.renderPipTarget(sanitizedDistribution),
)
return lbl.String(), true
}
return "", false
}
Expand DownExpand Up@@ -327,6 +357,37 @@ func (c *Config) SetTestNamingConvention(testNamingConvention string) {
c.testNamingConvention = testNamingConvention
}

// SetPipRepoNamingConvention sets the dependency naming convention.
func (c *Config) SetPipRepoNamingConvention(pipRepoNamingConvention string) {
c.pipRepoNamingConvention = pipRepoNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipRepository(distributionRepoName, distributionName string) string {
rendered := strings.ReplaceAll(c.pipRepoNamingConvention, repoNamePipRepoNamingConventionSubstitution, distributionRepoName)
return strings.ReplaceAll(rendered, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// SetPipPackageNamingConvention sets the dependency naming convention.
func (c *Config) SetPipPackageNamingConvention(pipPackageNamingConvention string) {
c.pipPackageNamingConvention = pipPackageNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipPackage(distributionName string) string {
return strings.ReplaceAll(c.pipPackageNamingConvention, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// SetPipTargetNamingConvention sets the dependency naming convention.
func (c *Config) SetPipTargetNamingConvention(pipTargetNamingConvention string) {
c.pipTargetNamingConvention = pipTargetNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipTarget(distributionName string) string {
return strings.ReplaceAll(c.pipTargetNamingConvention, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// RenderTestName returns the py_test target name by performing all
// substitutions.
func (c *Config) RenderTestName(packageName string) string {
Expand Down
19 changes: 19 additions & 0 deletions gazelle/pythonconfig/pythonconfig_test.go
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
package pythonconfig

import (
"reflect"
"testing"
)

func TestConfigNewChild(t *testing.T) {
parent := New("foo", "bar")
child := parent.NewChild()

if child.parent == nil {
t.Error("child parent should not be nil")
}
child.parent = nil
if !reflect.DeepEqual(child, parent) {
t.Errorf("child and should should be equal other than the parent reference. Parent: %#v\nChild: %#v", parent, child)
}
}
2 changes: 1 addition & 1 deletion gazelle/pythonconfig/types.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,4 +100,4 @@ func (sml *StringMapList) Set(s string) error {
func (sml *StringMapList) Get(key string) (string, bool) {
val, exists := sml.mapping[key]
return val, exists
}
}
3 changes: 3 additions & 0 deletions gazelle/testdata/pip_repo_convention/BUILD.in
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
# gazelle:python_pip_repo_naming_convention $repo_name$
# gazelle:python_pip_package_naming_convention $distribution_name$
# gazelle:python_pip_target_naming_convention $distribution_name$_pkg
31 changes: 31 additions & 0 deletions gazelle/testdata/pip_repo_convention/BUILD.out
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
load("@rules_python//python:defs.bzl", "py_binary", "py_library")

# gazelle:python_pip_repo_naming_convention $repo_name$
# gazelle:python_pip_package_naming_convention $distribution_name$
# gazelle:python_pip_target_naming_convention $distribution_name$_pkg

py_library(
name = "pip_repo_convention",
srcs = [
"__init__.py",
"bar.py",
"foo.py",
],
visibility = ["//:__subpackages__"],
deps = [
"@pip_deps//baz:baz_pkg",
"@pip_deps//boto3:boto3_pkg",
"@pip_deps//djangorestframework:djangorestframework_pkg",
],
)

py_binary(
name = "pip_repo_convention_bin",
srcs = ["__main__.py"],
main = "__main__.py",
visibility = ["//:__subpackages__"],
deps = [
":pip_repo_convention",
"@pip_deps//baz:baz_pkg",
],
)
3 changes: 3 additions & 0 deletions gazelle/testdata/pip_repo_convention/README.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
# Pip repo convention

This test case asserts that the dependency labels generated by gazelle follow a particular convention, that can be changed using directives.
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/WORKSPACE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
# This is a Bazel workspace for the Gazelle test data.
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/__init__.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
# For test purposes only.
5 changes: 5 additions & 0 deletions gazelle/testdata/pip_repo_convention/__main__.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
import bar
import foo

_ = bar
_ = foo
11 changes: 11 additions & 0 deletions gazelle/testdata/pip_repo_convention/bar.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
import os

import bar
import boto3
import rest_framework

_ = os

_ = bar
_ = boto3
_ = rest_framework
11 changes: 11 additions & 0 deletions gazelle/testdata/pip_repo_convention/foo.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
import sys

import boto3
import foo
import rest_framework

_ = sys

_ = boto3
_ = foo
_ = rest_framework
8 changes: 8 additions & 0 deletions gazelle/testdata/pip_repo_convention/gazelle_python.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
manifest:
modules_mapping:
boto3: boto3
rest_framework: djangorestframework
foo: baz
bar: baz
pip_repository:
name: pip_deps
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/test.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
---
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions gazelle/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,6 +147,12 @@ Python-specific directives are as follows:
| Controls the `py_test` naming convention. Follows the same interpolation rules as `python_library_naming_convention`. | |
| `# gazelle:resolve py ...` | n/a |
| Instructs the plugin what target to add as a dependency to satisfy a given import statement. The syntax is `# gazelle:resolve py import-string label` where `import-string` is the symbol in the python `import` statement, and `label` is the Bazel label that Gazelle should write in `deps`. | |
| `# gazelle:python_pip_repo_naming_convention` | `$repo_name$_$distribution_name$` |
| Controls the external dependency label naming convention. It interpolates `$repo_name$` and `$distribution_name$` with the Bazel external pip repository name and the sanitized Python package name respectively. E.g. if the Bazel external pip repository name is `my_pip_deps` and we are resolving external Python package named `flake-bugbear`, setting this to `$repo_name$_host_$distribution_name$` would result in a generated target named `my_pip_deps_host_flake8_bugbear`. | |
| `# gazelle:python_pip_package_naming_convention` | n/a |
| Controls the external dependency label naming convention. It interpolates `$distribution_name$` with the sanitized Python package name. See `gazelle:python_pip_repo_naming_convention` for details. This may be useful if you have `alias` targets which point to platform specific Python wheels in your repo, e.g. `//third_party/pip:flake8_bugbear_alias`. | |
| `# gazelle:python_pip_target_naming_convention` | `pkg` |
| Controls the external dependency label naming convention. It interpolates `$distribution_name$` with the sanitized Python package name respectively. See `gazelle:python_pip_repo_naming_convention` for details. This may be useful if you have `alias` targets which point to platform specific Python wheels in your repo, e.g. `//third_party/pip:flake8_bugbear_alias` or if you are using `gazelle` with `bzlmod`. | |

### Libraries

Expand Down
9 changes: 9 additions & 0 deletions gazelle/configure.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,9 @@ func (py *Configurer) KnownDirectives() []string {
pythonconfig.LibraryNamingConvention,
pythonconfig.BinaryNamingConvention,
pythonconfig.TestNamingConvention,
pythonconfig.PipRepoNamingConvention,
pythonconfig.PipPackageNamingConvention,
pythonconfig.PipTargetNamingConvention,
}
}

Expand DownExpand Up@@ -136,6 +139,12 @@ func (py *Configurer) Configure(c *config.Config, rel string, f *rule.File) {
config.SetBinaryNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.TestNamingConvention:
config.SetTestNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipRepoNamingConvention:
config.SetPipRepoNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipPackageNamingConvention:
config.SetPipPackageNamingConvention(strings.TrimSpace(d.Value))
case pythonconfig.PipTargetNamingConvention:
config.SetPipTargetNamingConvention(strings.TrimSpace(d.Value))
}
}

Expand Down
8 changes: 7 additions & 1 deletion gazelle/pythonconfig/BUILD.bazel
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "pythonconfig",
Expand All@@ -20,3 +20,9 @@ filegroup(
srcs = glob(["**"]),
visibility = ["//gazelle:__pkg__"],
)

go_test(
name = "pythonconfig_test",
srcs = ["pythonconfig_test.go"],
embed = [":pythonconfig"],
)
135 changes: 98 additions & 37 deletions gazelle/pythonconfig/pythonconfig.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,6 +49,17 @@ const (
// naming convention. See python_library_naming_convention for more info on
// the package name interpolation.
TestNamingConvention = "python_test_naming_convention"
// PipRepoNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. E.g. if the Python package name is `foo` and the
// pip repository is named `my_pip`, setting this
// to `$repo_name$_$distribution_name$` would render to `@my_pip_foo`.
PipRepoNamingConvention = "python_pip_repo_naming_convention"
// PipPackageNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. By default it is ``
PipPackageNamingConvention = "python_pip_package_naming_convention"
// PipTargetNamingConvention represents the directive that controls the
// mapping between Python modules and the repos. By default it is `pkg`
PipTargetNamingConvention = "python_pip_target_naming_convention"
)

// GenerationModeType represents one of the generation modes for the Python
Expand All@@ -67,7 +78,9 @@ const (
)

const (
packageNameNamingConventionSubstitution = "$package_name$"
repoNamePipRepoNamingConventionSubstitution = "$repo_name$"
distributionNamePipRepoNamingConventionSubstitution = "$distribution_name$"
packageNameNamingConventionSubstitution = "$package_name$"
)

// defaultIgnoreFiles is the list of default values used in the
Expand DownExpand Up@@ -99,14 +112,17 @@ type Config struct {
pythonProjectRoot string
gazelleManifest *manifest.Manifest

excludedPatterns *singlylinkedlist.List
ignoreFiles map[string]struct{}
ignoreDependencies map[string]struct{}
validateImportStatements bool
coarseGrainedGeneration bool
libraryNamingConvention string
binaryNamingConvention string
testNamingConvention string
excludedPatterns *singlylinkedlist.List
ignoreFiles map[string]struct{}
ignoreDependencies map[string]struct{}
validateImportStatements bool
coarseGrainedGeneration bool
libraryNamingConvention string
binaryNamingConvention string
testNamingConvention string
pipRepoNamingConvention string
pipPackageNamingConvention string
pipTargetNamingConvention string
}

// New creates a new Config.
Expand All@@ -115,17 +131,20 @@ func New(
pythonProjectRoot string,
) *Config {
return &Config{
extensionEnabled: true,
repoRoot: repoRoot,
pythonProjectRoot: pythonProjectRoot,
excludedPatterns: singlylinkedlist.New(),
ignoreFiles: make(map[string]struct{}),
ignoreDependencies: make(map[string]struct{}),
validateImportStatements: true,
coarseGrainedGeneration: false,
libraryNamingConvention: packageNameNamingConventionSubstitution,
binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
extensionEnabled: true,
repoRoot: repoRoot,
pythonProjectRoot: pythonProjectRoot,
excludedPatterns: singlylinkedlist.New(),
ignoreFiles: make(map[string]struct{}),
ignoreDependencies: make(map[string]struct{}),
validateImportStatements: true,
coarseGrainedGeneration: false,
libraryNamingConvention: packageNameNamingConventionSubstitution,
binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution),
testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution),
pipRepoNamingConvention: fmt.Sprintf("%s_%s", repoNamePipRepoNamingConventionSubstitution, distributionNamePipRepoNamingConventionSubstitution),
pipPackageNamingConvention: "",
pipTargetNamingConvention: "pkg",
}
}

Expand All@@ -150,6 +169,9 @@ func (c *Config) NewChild() *Config {
libraryNamingConvention: c.libraryNamingConvention,
binaryNamingConvention: c.binaryNamingConvention,
testNamingConvention: c.testNamingConvention,
pipRepoNamingConvention: c.pipRepoNamingConvention,
pipPackageNamingConvention: c.pipPackageNamingConvention,
pipTargetNamingConvention: c.pipTargetNamingConvention,
}
}

Expand DownExpand Up@@ -195,24 +217,32 @@ func (c *Config) SetGazelleManifest(gazelleManifest *manifest.Manifest) {
// name.
func (c *Config) FindThirdPartyDependency(modName string) (string, bool) {
for currentCfg := c; currentCfg != nil; currentCfg = currentCfg.parent {
if currentCfg.gazelleManifest != nil {
gazelleManifest := currentCfg.gazelleManifest
if distributionName, ok := gazelleManifest.ModulesMapping[modName]; ok {
var distributionRepositoryName string
if gazelleManifest.PipDepsRepositoryName != "" {
distributionRepositoryName = gazelleManifest.PipDepsRepositoryName
} else if gazelleManifest.PipRepository != nil {
distributionRepositoryName = gazelleManifest.PipRepository.Name
}
sanitizedDistribution := strings.ToLower(distributionName)
sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")
var lbl label.Label
// @<repository_name>_<distribution_name>//:pkg
distributionRepositoryName = distributionRepositoryName + "_" + sanitizedDistribution
lbl = label.New(distributionRepositoryName, "", "pkg")
return lbl.String(), true
}

if currentCfg.gazelleManifest == nil {
continue
}

gazelleManifest := currentCfg.gazelleManifest
distributionName, ok := gazelleManifest.ModulesMapping[modName]
if !ok {
continue
}

var distributionRepositoryName string
if gazelleManifest.PipDepsRepositoryName != "" {
distributionRepositoryName = gazelleManifest.PipDepsRepositoryName
} else if gazelleManifest.PipRepository != nil {
distributionRepositoryName = gazelleManifest.PipRepository.Name
}
sanitizedDistribution := strings.ToLower(distributionName)
sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")

lbl := label.New(
currentCfg.renderPipRepository(distributionRepositoryName, sanitizedDistribution),
currentCfg.renderPipPackage(sanitizedDistribution),
currentCfg.renderPipTarget(sanitizedDistribution),
)
return lbl.String(), true
}
return "", false
}
Expand DownExpand Up@@ -327,6 +357,37 @@ func (c *Config) SetTestNamingConvention(testNamingConvention string) {
c.testNamingConvention = testNamingConvention
}

// SetPipRepoNamingConvention sets the dependency naming convention.
func (c *Config) SetPipRepoNamingConvention(pipRepoNamingConvention string) {
c.pipRepoNamingConvention = pipRepoNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipRepository(distributionRepoName, distributionName string) string {
rendered := strings.ReplaceAll(c.pipRepoNamingConvention, repoNamePipRepoNamingConventionSubstitution, distributionRepoName)
return strings.ReplaceAll(rendered, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// SetPipPackageNamingConvention sets the dependency naming convention.
func (c *Config) SetPipPackageNamingConvention(pipPackageNamingConvention string) {
c.pipPackageNamingConvention = pipPackageNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipPackage(distributionName string) string {
return strings.ReplaceAll(c.pipPackageNamingConvention, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// SetPipTargetNamingConvention sets the dependency naming convention.
func (c *Config) SetPipTargetNamingConvention(pipTargetNamingConvention string) {
c.pipTargetNamingConvention = pipTargetNamingConvention
}

// Accepts sanitized input.
func (c *Config) renderPipTarget(distributionName string) string {
return strings.ReplaceAll(c.pipTargetNamingConvention, distributionNamePipRepoNamingConventionSubstitution, distributionName)
}

// RenderTestName returns the py_test target name by performing all
// substitutions.
func (c *Config) RenderTestName(packageName string) string {
Expand Down
19 changes: 19 additions & 0 deletions gazelle/pythonconfig/pythonconfig_test.go
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
package pythonconfig

import (
"reflect"
"testing"
)

func TestConfigNewChild(t *testing.T) {
parent := New("foo", "bar")
child := parent.NewChild()

if child.parent == nil {
t.Error("child parent should not be nil")
}
child.parent = nil
if !reflect.DeepEqual(child, parent) {
t.Errorf("child and should should be equal other than the parent reference. Parent: %#v\nChild: %#v", parent, child)
}
}
2 changes: 1 addition & 1 deletion gazelle/pythonconfig/types.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,4 +100,4 @@ func (sml *StringMapList) Set(s string) error {
func (sml *StringMapList) Get(key string) (string, bool) {
val, exists := sml.mapping[key]
return val, exists
}
}
3 changes: 3 additions & 0 deletions gazelle/testdata/pip_repo_convention/BUILD.in
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
# gazelle:python_pip_repo_naming_convention $repo_name$
# gazelle:python_pip_package_naming_convention $distribution_name$
# gazelle:python_pip_target_naming_convention $distribution_name$_pkg
31 changes: 31 additions & 0 deletions gazelle/testdata/pip_repo_convention/BUILD.out
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
load("@rules_python//python:defs.bzl", "py_binary", "py_library")

# gazelle:python_pip_repo_naming_convention $repo_name$
# gazelle:python_pip_package_naming_convention $distribution_name$
# gazelle:python_pip_target_naming_convention $distribution_name$_pkg

py_library(
name = "pip_repo_convention",
srcs = [
"__init__.py",
"bar.py",
"foo.py",
],
visibility = ["//:__subpackages__"],
deps = [
"@pip_deps//baz:baz_pkg",
"@pip_deps//boto3:boto3_pkg",
"@pip_deps//djangorestframework:djangorestframework_pkg",
],
)

py_binary(
name = "pip_repo_convention_bin",
srcs = ["__main__.py"],
main = "__main__.py",
visibility = ["//:__subpackages__"],
deps = [
":pip_repo_convention",
"@pip_deps//baz:baz_pkg",
],
)
3 changes: 3 additions & 0 deletions gazelle/testdata/pip_repo_convention/README.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
# Pip repo convention

This test case asserts that the dependency labels generated by gazelle follow a particular convention, that can be changed using directives.
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/WORKSPACE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
# This is a Bazel workspace for the Gazelle test data.
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/__init__.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
# For test purposes only.
5 changes: 5 additions & 0 deletions gazelle/testdata/pip_repo_convention/__main__.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
import bar
import foo

_ = bar
_ = foo
11 changes: 11 additions & 0 deletions gazelle/testdata/pip_repo_convention/bar.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
import os

import bar
import boto3
import rest_framework

_ = os

_ = bar
_ = boto3
_ = rest_framework
11 changes: 11 additions & 0 deletions gazelle/testdata/pip_repo_convention/foo.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
import sys

import boto3
import foo
import rest_framework

_ = sys

_ = boto3
_ = foo
_ = rest_framework
8 changes: 8 additions & 0 deletions gazelle/testdata/pip_repo_convention/gazelle_python.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
manifest:
modules_mapping:
boto3: boto3
rest_framework: djangorestframework
foo: baz
bar: baz
pip_repository:
name: pip_deps
1 change: 1 addition & 0 deletions gazelle/testdata/pip_repo_convention/test.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
---