feat: add bzlmod support for gazelle plugin (#1077)

* feat: add optional pkg alias generation to pip_repository

* feat: support using aliases in gazelle

* doc: migrate gazelle example to use user friendly aliases

* feat: gazelle supports bzlmod

* chore: update gazelle plugin deps

* chore: bazel run //:gazelle

* fix: remove deps that are imported as bazel deps

See: bazelbuild/bazel-gazelle#1403

* ci: add build_file_generation to show that we support bzlmod
diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml
index a1b16bb..a0d9a19 100644
--- a/.bazelci/presubmit.yml
+++ b/.bazelci/presubmit.yml
@@ -73,6 +73,14 @@
     build_targets: ["//..."]
     test_targets: ["//..."]
     working_directory: gazelle
+  gazelle_extension_bzlmod:
+    <<: *common_bzlmod_flags
+    name: Test the Gazelle extension under bzlmod
+    platform: ubuntu2004
+    build_targets: ["//..."]
+    test_targets: ["//..."]
+    working_directory: gazelle
+
   ubuntu_min:
     <<: *minimum_supported_version
     <<: *reusable_config
@@ -138,6 +146,32 @@
     working_directory: examples/build_file_generation
     platform: windows
 
+  integration_test_build_file_generation_bzlmod_ubuntu:
+    <<: *minimum_supported_bzlmod_version
+    <<: *common_bzlmod_flags
+    <<: *reusable_build_test_all
+    name: build_file_generation_bzlmod integration tests on Ubuntu
+    working_directory: examples/build_file_generation
+    platform: ubuntu2004
+  integration_test_build_file_generation_bzlmod_debian:
+    <<: *common_bzlmod_flags
+    <<: *reusable_build_test_all
+    name: build_file_generation_bzlmod integration tests on Debian
+    working_directory: examples/build_file_generation
+    platform: debian11
+  integration_test_build_file_generation_bzlmod_macos:
+    <<: *common_bzlmod_flags
+    <<: *reusable_build_test_all
+    name: build_file_generation_bzlmod integration tests on macOS
+    working_directory: examples/build_file_generation
+    platform: macos
+  integration_test_build_file_generation_bzlmod_windows:
+    <<: *common_bzlmod_flags
+    <<: *reusable_build_test_all
+    name: build_file_generation_bzlmod integration tests on Windows
+    working_directory: examples/build_file_generation
+    platform: windows
+
   integration_test_bzlmod_ubuntu_min:
     <<: *minimum_supported_bzlmod_version
     <<: *reusable_build_test_all
diff --git a/docs/pip_repository.md b/docs/pip_repository.md
index 2ccdc64..c02058e 100644
--- a/docs/pip_repository.md
+++ b/docs/pip_repository.md
@@ -8,9 +8,10 @@
 
 <pre>
 pip_repository(<a href="#pip_repository-name">name</a>, <a href="#pip_repository-annotations">annotations</a>, <a href="#pip_repository-download_only">download_only</a>, <a href="#pip_repository-enable_implicit_namespace_pkgs">enable_implicit_namespace_pkgs</a>, <a href="#pip_repository-environment">environment</a>,
-               <a href="#pip_repository-extra_pip_args">extra_pip_args</a>, <a href="#pip_repository-isolated">isolated</a>, <a href="#pip_repository-pip_data_exclude">pip_data_exclude</a>, <a href="#pip_repository-python_interpreter">python_interpreter</a>,
-               <a href="#pip_repository-python_interpreter_target">python_interpreter_target</a>, <a href="#pip_repository-quiet">quiet</a>, <a href="#pip_repository-repo_mapping">repo_mapping</a>, <a href="#pip_repository-repo_prefix">repo_prefix</a>, <a href="#pip_repository-requirements_darwin">requirements_darwin</a>,
-               <a href="#pip_repository-requirements_linux">requirements_linux</a>, <a href="#pip_repository-requirements_lock">requirements_lock</a>, <a href="#pip_repository-requirements_windows">requirements_windows</a>, <a href="#pip_repository-timeout">timeout</a>)
+               <a href="#pip_repository-extra_pip_args">extra_pip_args</a>, <a href="#pip_repository-incompatible_generate_aliases">incompatible_generate_aliases</a>, <a href="#pip_repository-isolated">isolated</a>, <a href="#pip_repository-pip_data_exclude">pip_data_exclude</a>,
+               <a href="#pip_repository-python_interpreter">python_interpreter</a>, <a href="#pip_repository-python_interpreter_target">python_interpreter_target</a>, <a href="#pip_repository-quiet">quiet</a>, <a href="#pip_repository-repo_mapping">repo_mapping</a>, <a href="#pip_repository-repo_prefix">repo_prefix</a>,
+               <a href="#pip_repository-requirements_darwin">requirements_darwin</a>, <a href="#pip_repository-requirements_linux">requirements_linux</a>, <a href="#pip_repository-requirements_lock">requirements_lock</a>, <a href="#pip_repository-requirements_windows">requirements_windows</a>,
+               <a href="#pip_repository-timeout">timeout</a>)
 </pre>
 
 A rule for importing `requirements.txt` dependencies into Bazel.
@@ -64,6 +65,7 @@
 | <a id="pip_repository-enable_implicit_namespace_pkgs"></a>enable_implicit_namespace_pkgs |  If true, disables conversion of native namespace packages into pkg-util style namespace packages. When set all py_binary and py_test targets must specify either <code>legacy_create_init=False</code> or the global Bazel option <code>--incompatible_default_to_explicit_init_py</code> to prevent <code>__init__.py</code> being automatically generated in every directory.<br><br>This option is required to support some packages which cannot handle the conversion to pkg-util style.   | Boolean | optional | <code>False</code> |
 | <a id="pip_repository-environment"></a>environment |  Environment variables to set in the pip subprocess. Can be used to set common variables such as <code>http_proxy</code>, <code>https_proxy</code> and <code>no_proxy</code> Note that pip is run with "--isolated" on the CLI so <code>PIP_&lt;VAR&gt;_&lt;NAME&gt;</code> style env vars are ignored, but env vars that control requests and urllib3 can be passed.   | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | <code>{}</code> |
 | <a id="pip_repository-extra_pip_args"></a>extra_pip_args |  Extra arguments to pass on to pip. Must not contain spaces.   | List of strings | optional | <code>[]</code> |
+| <a id="pip_repository-incompatible_generate_aliases"></a>incompatible_generate_aliases |  Allow generating aliases '@pip//&lt;pkg&gt;' -&gt; '@pip_&lt;pkg&gt;//:pkg'.   | Boolean | optional | <code>False</code> |
 | <a id="pip_repository-isolated"></a>isolated |  Whether or not to pass the [--isolated](https://pip.pypa.io/en/stable/cli/pip/#cmdoption-isolated) flag to the underlying pip command. Alternatively, the <code>RULES_PYTHON_PIP_ISOLATED</code> enviornment varaible can be used to control this flag.   | Boolean | optional | <code>True</code> |
 | <a id="pip_repository-pip_data_exclude"></a>pip_data_exclude |  Additional data exclusion parameters to add to the pip packages BUILD file.   | List of strings | optional | <code>[]</code> |
 | <a id="pip_repository-python_interpreter"></a>python_interpreter |  The python interpreter to use. This can either be an absolute path or the name of a binary found on the host's <code>PATH</code> environment variable. If no value is set <code>python3</code> is defaulted for Unix systems and <code>python.exe</code> for Windows.   | String | optional | <code>""</code> |
@@ -83,8 +85,8 @@
 ## pip_repository_bzlmod
 
 <pre>
-pip_repository_bzlmod(<a href="#pip_repository_bzlmod-name">name</a>, <a href="#pip_repository_bzlmod-repo_mapping">repo_mapping</a>, <a href="#pip_repository_bzlmod-requirements_darwin">requirements_darwin</a>, <a href="#pip_repository_bzlmod-requirements_linux">requirements_linux</a>,
-                      <a href="#pip_repository_bzlmod-requirements_lock">requirements_lock</a>, <a href="#pip_repository_bzlmod-requirements_windows">requirements_windows</a>)
+pip_repository_bzlmod(<a href="#pip_repository_bzlmod-name">name</a>, <a href="#pip_repository_bzlmod-incompatible_generate_aliases">incompatible_generate_aliases</a>, <a href="#pip_repository_bzlmod-repo_mapping">repo_mapping</a>, <a href="#pip_repository_bzlmod-requirements_darwin">requirements_darwin</a>,
+                      <a href="#pip_repository_bzlmod-requirements_linux">requirements_linux</a>, <a href="#pip_repository_bzlmod-requirements_lock">requirements_lock</a>, <a href="#pip_repository_bzlmod-requirements_windows">requirements_windows</a>)
 </pre>
 
 A rule for bzlmod pip_repository creation. Intended for private use only.
@@ -95,6 +97,7 @@
 | Name  | Description | Type | Mandatory | Default |
 | :------------- | :------------- | :------------- | :------------- | :------------- |
 | <a id="pip_repository_bzlmod-name"></a>name |  A unique name for this repository.   | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required |  |
+| <a id="pip_repository_bzlmod-incompatible_generate_aliases"></a>incompatible_generate_aliases |  Allow generating aliases in '@pip//:&lt;pkg&gt;' -&gt; '@pip_&lt;pkg&gt;//:pkg'. This replaces the aliases generated by the <code>bzlmod</code> tooling.   | Boolean | optional | <code>False</code> |
 | <a id="pip_repository_bzlmod-repo_mapping"></a>repo_mapping |  A dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.&lt;p&gt;For example, an entry <code>"@foo": "@bar"</code> declares that, for any time this repository depends on <code>@foo</code> (such as a dependency on <code>@foo//some:target</code>, it should actually resolve that dependency within globally-declared <code>@bar</code> (<code>@bar//some:target</code>).   | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | required |  |
 | <a id="pip_repository_bzlmod-requirements_darwin"></a>requirements_darwin |  Override the requirements_lock attribute when the host platform is Mac OS   | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
 | <a id="pip_repository_bzlmod-requirements_linux"></a>requirements_linux |  Override the requirements_lock attribute when the host platform is Linux   | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
diff --git a/examples/build_file_generation/BUILD.bazel b/examples/build_file_generation/BUILD.bazel
index 6419ef2..7c88d92 100644
--- a/examples/build_file_generation/BUILD.bazel
+++ b/examples/build_file_generation/BUILD.bazel
@@ -43,6 +43,9 @@
     modules_mapping = ":modules_map",
     pip_repository_name = "pip",
     requirements = "//:requirements_lock.txt",
+    # NOTE: we can use this flag in order to make our setup compatible with
+    # bzlmod.
+    use_pip_repository_aliases = True,
 )
 
 # Our gazelle target points to the python gazelle binary.
@@ -65,7 +68,7 @@
     visibility = ["//:__subpackages__"],
     deps = [
         "//random_number_generator",
-        "@pip_flask//:pkg",
+        "@pip//flask",
     ],
 )
 
diff --git a/examples/build_file_generation/MODULE.bazel b/examples/build_file_generation/MODULE.bazel
new file mode 100644
index 0000000..5f79fec
--- /dev/null
+++ b/examples/build_file_generation/MODULE.bazel
@@ -0,0 +1,43 @@
+module(
+    name = "example_bzlmod",
+    version = "0.0.0",
+    compatibility_level = 1,
+)
+
+bazel_dep(name = "rules_python", version = "0.19.0")
+bazel_dep(name = "rules_python_gazelle_plugin", version = "0.19.0")
+bazel_dep(name = "gazelle", version = "0.29.0", repo_name = "bazel_gazelle")
+
+# local overrides for the packages for CI purposes.
+# for usual setups you should remove this block.
+local_path_override(
+    module_name = "rules_python",
+    path = "../..",
+)
+
+local_path_override(
+    module_name = "rules_python_gazelle_plugin",
+    path = "../../gazelle",
+)
+
+# Register python toolchain
+python = use_extension("@rules_python//python:extensions.bzl", "python")
+python.toolchain(
+    name = "python3_9",
+    python_version = "3.9",
+)
+use_repo(python, "python3_9_toolchains")
+
+register_toolchains(
+    "@python3_9_toolchains//:all",
+)
+
+pip = use_extension("@rules_python//python:extensions.bzl", "pip")
+pip.parse(
+    name = "pip",
+    # Generate user friendly alias labels for each dependency that we have.
+    incompatible_generate_aliases = True,
+    requirements_lock = "//:requirements_lock.txt",
+    requirements_windows = "//:requirements_windows.txt",
+)
+use_repo(pip, "pip")
diff --git a/examples/build_file_generation/WORKSPACE b/examples/build_file_generation/WORKSPACE
index 9f1dae8..65e0a6e 100644
--- a/examples/build_file_generation/WORKSPACE
+++ b/examples/build_file_generation/WORKSPACE
@@ -90,6 +90,8 @@
 # You can instead check this `requirements.bzl` file into your repo.
 pip_parse(
     name = "pip",
+    # Generate user friendly alias labels for each dependency that we have.
+    incompatible_generate_aliases = True,
     # (Optional) You can provide a python_interpreter (path) or a python_interpreter_target (a Bazel target, that
     # acts as an executable). The latter can be anything that could be used as Python interpreter. E.g.:
     # 1. Python interpreter that you compile in the build file.
diff --git a/examples/build_file_generation/gazelle_python.yaml b/examples/build_file_generation/gazelle_python.yaml
index 847d1ec..b57e9f0 100644
--- a/examples/build_file_generation/gazelle_python.yaml
+++ b/examples/build_file_generation/gazelle_python.yaml
@@ -114,4 +114,5 @@
     zipp.py310compat: zipp
   pip_repository:
     name: pip
-integrity: 2c84a3cabeaff134a1d045e5a173a3178086f236ab20f895ffbd7f3b7a6e5bb0
+    use_pip_repository_aliases: true
+integrity: 85f073e37e31339508aaaf5e0d5472adae5148fd5f054e9cc586343c026660e1
diff --git a/gazelle/MODULE.bazel b/gazelle/MODULE.bazel
new file mode 100644
index 0000000..bd63402
--- /dev/null
+++ b/gazelle/MODULE.bazel
@@ -0,0 +1,20 @@
+module(
+    name = "rules_python_gazelle_plugin",
+    version = "0.0.0",
+    compatibility_level = 1,
+)
+
+bazel_dep(name = "rules_python", version = "0.18.0")
+bazel_dep(name = "rules_go", version = "0.38.1", repo_name = "io_bazel_rules_go")
+bazel_dep(name = "gazelle", version = "0.29.0", repo_name = "bazel_gazelle")
+
+go_deps = use_extension("@bazel_gazelle//:extensions.bzl", "go_deps")
+go_deps.from_file(go_mod = "//:go.mod")
+use_repo(
+    go_deps,
+    "com_github_bazelbuild_buildtools",
+    "com_github_bmatcuk_doublestar",
+    "com_github_emirpasic_gods",
+    "com_github_ghodss_yaml",
+    "in_gopkg_yaml_v2",
+)
diff --git a/gazelle/deps.bzl b/gazelle/deps.bzl
index 3579443..26f8c66 100644
--- a/gazelle/deps.bzl
+++ b/gazelle/deps.bzl
@@ -28,12 +28,7 @@
         sum = "h1:/hemPrYIhOhy8zYrNj+069zDB68us2sMGsfkFJO0iZs=",
         version = "v0.0.0-20190523083050-ea95bdfd59fc",
     )
-    go_repository(
-        name = "com_github_bazelbuild_bazel_gazelle",
-        importpath = "github.com/bazelbuild/bazel-gazelle",
-        sum = "h1:+/ZhUxlDy4XnyMIGeKkbRZoIGssy1eO51GijwIvvuwE=",
-        version = "v0.27.0",
-    )
+
     go_repository(
         name = "com_github_bazelbuild_buildtools",
         build_naming_convention = "go_default_library",
@@ -41,24 +36,14 @@
         sum = "h1:jhiMzJ+8unnLRtV8rpbWBFE9pFNzIqgUTyZU5aA++w8=",
         version = "v0.0.0-20221004120235-7186f635531b",
     )
-    go_repository(
-        name = "com_github_bazelbuild_rules_go",
-        importpath = "github.com/bazelbuild/rules_go",
-        sum = "h1:ViPR65vOrg74JKntAUFY6qZkheBKGB6to7wFd8gCRU4=",
-        version = "v0.35.0",
-    )
+
     go_repository(
         name = "com_github_bmatcuk_doublestar",
         importpath = "github.com/bmatcuk/doublestar",
         sum = "h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=",
         version = "v1.3.4",
     )
-    go_repository(
-        name = "com_github_bmatcuk_doublestar_v4",
-        importpath = "github.com/bmatcuk/doublestar/v4",
-        sum = "h1:Qu+u9wR3Vd89LnlLMHvnZ5coJMWKQamqdz9/p5GNthA=",
-        version = "v4.2.0",
-    )
+
     go_repository(
         name = "com_github_burntsushi_toml",
         importpath = "github.com/BurntSushi/toml",
@@ -113,12 +98,7 @@
         sum = "h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=",
         version = "v0.1.0",
     )
-    go_repository(
-        name = "com_github_fsnotify_fsnotify",
-        importpath = "github.com/fsnotify/fsnotify",
-        sum = "h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=",
-        version = "v1.5.4",
-    )
+
     go_repository(
         name = "com_github_ghodss_yaml",
         importpath = "github.com/ghodss/yaml",
@@ -134,14 +114,14 @@
     go_repository(
         name = "com_github_golang_mock",
         importpath = "github.com/golang/mock",
-        sum = "h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=",
-        version = "v1.6.0",
+        sum = "h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8=",
+        version = "v1.1.1",
     )
     go_repository(
         name = "com_github_golang_protobuf",
         importpath = "github.com/golang/protobuf",
-        sum = "h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=",
-        version = "v1.5.2",
+        sum = "h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=",
+        version = "v1.4.3",
     )
     go_repository(
         name = "com_github_google_go_cmp",
@@ -149,18 +129,7 @@
         sum = "h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=",
         version = "v0.5.9",
     )
-    go_repository(
-        name = "com_github_pelletier_go_toml",
-        importpath = "github.com/pelletier/go-toml",
-        sum = "h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=",
-        version = "v1.9.5",
-    )
-    go_repository(
-        name = "com_github_pmezard_go_difflib",
-        importpath = "github.com/pmezard/go-difflib",
-        sum = "h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=",
-        version = "v1.0.0",
-    )
+
     go_repository(
         name = "com_github_prometheus_client_model",
         importpath = "github.com/prometheus/client_model",
@@ -218,8 +187,8 @@
     go_repository(
         name = "org_golang_google_protobuf",
         importpath = "google.golang.org/protobuf",
-        sum = "h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=",
-        version = "v1.28.0",
+        sum = "h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=",
+        version = "v1.25.0",
     )
     go_repository(
         name = "org_golang_x_crypto",
@@ -260,8 +229,8 @@
     go_repository(
         name = "org_golang_x_sync",
         importpath = "golang.org/x/sync",
-        sum = "h1:0SH2R3f1b1VmIMG7BXbEZCBUu2dKmHschSmjqGUrW8A=",
-        version = "v0.0.0-20220907140024-f12130a52804",
+        sum = "h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=",
+        version = "v0.0.0-20220722155255-886fb9371eb4",
     )
     go_repository(
         name = "org_golang_x_sys",
diff --git a/gazelle/go.mod b/gazelle/go.mod
index 6d6f033..94f19e8 100644
--- a/gazelle/go.mod
+++ b/gazelle/go.mod
@@ -3,9 +3,7 @@
 go 1.19
 
 require (
-	github.com/bazelbuild/bazel-gazelle v0.27.0
 	github.com/bazelbuild/buildtools v0.0.0-20221004120235-7186f635531b
-	github.com/bazelbuild/rules_go v0.35.0
 	github.com/bmatcuk/doublestar v1.3.4
 	github.com/emirpasic/gods v1.18.1
 	github.com/ghodss/yaml v1.0.0
diff --git a/gazelle/manifest/defs.bzl b/gazelle/manifest/defs.bzl
index 78e0c27..05562a1 100644
--- a/gazelle/manifest/defs.bzl
+++ b/gazelle/manifest/defs.bzl
@@ -24,13 +24,16 @@
         modules_mapping,
         pip_repository_name = "",
         pip_deps_repository_name = "",
-        manifest = ":gazelle_python.yaml"):
+        manifest = ":gazelle_python.yaml",
+        use_pip_repository_aliases = False):
     """A macro for defining the updating and testing targets for the Gazelle manifest file.
 
     Args:
         name: the name used as a base for the targets.
         requirements: the target for the requirements.txt file.
         pip_repository_name: the name of the pip_install or pip_repository target.
+        use_pip_repository_aliases: boolean flag to enable using user-friendly
+            python package aliases.
         pip_deps_repository_name: deprecated - the old pip_install target name.
         modules_mapping: the target for the generated modules_mapping.json file.
         manifest: the target for the Gazelle manifest file.
@@ -67,6 +70,12 @@
         update_target_label,
     ]
 
+    if use_pip_repository_aliases:
+        update_args += [
+            "--use-pip-repository-aliases",
+            "true",
+        ]
+
     go_binary(
         name = update_target,
         embed = [Label("//manifest/generate:generate_lib")],
diff --git a/gazelle/manifest/generate/generate.go b/gazelle/manifest/generate/generate.go
index 0f429f8..1f56e63 100644
--- a/gazelle/manifest/generate/generate.go
+++ b/gazelle/manifest/generate/generate.go
@@ -38,12 +38,15 @@
 }
 
 func main() {
-	var manifestGeneratorHashPath string
-	var requirementsPath string
-	var pipRepositoryName string
-	var modulesMappingPath string
-	var outputPath string
-	var updateTarget string
+	var (
+		manifestGeneratorHashPath string
+		requirementsPath          string
+		pipRepositoryName         string
+		usePipRepositoryAliases   bool
+		modulesMappingPath        string
+		outputPath                string
+		updateTarget              string
+	)
 	flag.StringVar(
 		&manifestGeneratorHashPath,
 		"manifest-generator-hash",
@@ -60,6 +63,11 @@
 		"pip-repository-name",
 		"",
 		"The name of the pip_install or pip_repository target.")
+	flag.BoolVar(
+		&usePipRepositoryAliases,
+		"use-pip-repository-aliases",
+		false,
+		"Whether to use the pip-repository aliases, which are generated when passing 'incompatible_generate_aliases = True'.")
 	flag.StringVar(
 		&modulesMappingPath,
 		"modules-mapping",
@@ -103,7 +111,8 @@
 	manifestFile := manifest.NewFile(&manifest.Manifest{
 		ModulesMapping: modulesMapping,
 		PipRepository: &manifest.PipRepository{
-			Name:        pipRepositoryName,
+			Name:                    pipRepositoryName,
+			UsePipRepositoryAliases: usePipRepositoryAliases,
 		},
 	})
 	if err := writeOutput(
diff --git a/gazelle/manifest/manifest.go b/gazelle/manifest/manifest.go
index bb48264..c49951d 100644
--- a/gazelle/manifest/manifest.go
+++ b/gazelle/manifest/manifest.go
@@ -144,4 +144,7 @@
 type PipRepository struct {
 	// The name of the pip_install or pip_repository target.
 	Name string
+	// UsePipRepositoryAliases allows to use aliases generated pip_repository
+	// when passing incompatible_generate_aliases = True.
+	UsePipRepositoryAliases bool `yaml:"use_pip_repository_aliases,omitempty"`
 }
diff --git a/gazelle/python/BUILD.bazel b/gazelle/python/BUILD.bazel
index 3b5ded2..ddcad27 100644
--- a/gazelle/python/BUILD.bazel
+++ b/gazelle/python/BUILD.bazel
@@ -61,7 +61,6 @@
     ] + glob(["testdata/**"]),
     deps = [
         "@bazel_gazelle//testtools:go_default_library",
-        "@com_github_emirpasic_gods//lists/singlylinkedlist",
         "@com_github_ghodss_yaml//:yaml",
         "@io_bazel_rules_go//go/tools/bazel:go_default_library",
     ],
diff --git a/gazelle/pythonconfig/pythonconfig.go b/gazelle/pythonconfig/pythonconfig.go
index a2fe7d5..ea2ae65 100644
--- a/gazelle/pythonconfig/pythonconfig.go
+++ b/gazelle/pythonconfig/pythonconfig.go
@@ -220,10 +220,16 @@
 				}
 				sanitizedDistribution := strings.ToLower(distributionName)
 				sanitizedDistribution = strings.ReplaceAll(sanitizedDistribution, "-", "_")
-				var lbl label.Label
+
+				if gazelleManifest.PipRepository != nil && gazelleManifest.PipRepository.UsePipRepositoryAliases {
+					// @<repository_name>//<distribution_name>
+					lbl := label.New(distributionRepositoryName, sanitizedDistribution, sanitizedDistribution)
+					return lbl.String(), true
+				}
+
 				// @<repository_name>_<distribution_name>//:pkg
 				distributionRepositoryName = distributionRepositoryName + "_" + sanitizedDistribution
-				lbl = label.New(distributionRepositoryName, "", "pkg")
+				lbl := label.New(distributionRepositoryName, "", "pkg")
 				return lbl.String(), true
 			}
 		}
diff --git a/python/extensions.bzl b/python/extensions.bzl
index 01f731f..75de415 100644
--- a/python/extensions.bzl
+++ b/python/extensions.bzl
@@ -78,6 +78,7 @@
             pip_repository_bzlmod(
                 name = attr.name,
                 requirements_lock = attr.requirements_lock,
+                incompatible_generate_aliases = attr.incompatible_generate_aliases,
             )
 
             for name, requirement_line in requirements:
diff --git a/python/pip_install/pip_repository.bzl b/python/pip_install/pip_repository.bzl
index 982d853..733142b 100644
--- a/python/pip_install/pip_repository.bzl
+++ b/python/pip_install/pip_repository.bzl
@@ -261,6 +261,52 @@
 def _clean_pkg_name(name):
     return name.replace("-", "_").replace(".", "_").lower()
 
+def _pkg_aliases(rctx, repo_name, bzl_packages):
+    """Create alias declarations for each python dependency.
+
+    The aliases should be appended to the pip_repository BUILD.bazel file. These aliases
+    allow users to use requirement() without needed a corresponding `use_repo()` for each dep
+    when using bzlmod.
+
+    Args:
+        rctx: the repository context.
+        repo_name: the repository name of the parent that is visible to the users.
+        bzl_packages: the list of packages to setup.
+    """
+    for name in bzl_packages:
+        build_content = """package(default_visibility = ["//visibility:public"])
+
+alias(
+    name = "{name}",
+    actual = "@{repo_name}_{dep}//:pkg",
+)
+
+alias(
+    name = "pkg",
+    actual = "@{repo_name}_{dep}//:pkg",
+)
+
+alias(
+    name = "whl",
+    actual = "@{repo_name}_{dep}//:whl",
+)
+
+alias(
+    name = "data",
+    actual = "@{repo_name}_{dep}//:data",
+)
+
+alias(
+    name = "dist_info",
+    actual = "@{repo_name}_{dep}//:dist_info",
+)
+""".format(
+            name = name,
+            repo_name = repo_name,
+            dep = name,
+        )
+        rctx.file("{}/BUILD.bazel".format(name), build_content)
+
 def _bzlmod_pkg_aliases(repo_name, bzl_packages):
     """Create alias declarations for each python dependency.
 
@@ -314,16 +360,21 @@
 
     repo_name = rctx.attr.name.split("~")[-1]
 
-    build_contents = _BUILD_FILE_CONTENTS + _bzlmod_pkg_aliases(repo_name, bzl_packages)
+    build_contents = _BUILD_FILE_CONTENTS
+
+    if rctx.attr.incompatible_generate_aliases:
+        _pkg_aliases(rctx, repo_name, bzl_packages)
+    else:
+        build_contents += _bzlmod_pkg_aliases(repo_name, bzl_packages)
 
     rctx.file("BUILD.bazel", build_contents)
     rctx.template("requirements.bzl", rctx.attr._template, substitutions = {
         "%%ALL_REQUIREMENTS%%": _format_repr_list([
-            "@{}//:{}_pkg".format(repo_name, p)
+            "@@{}//{}".format(repo_name, p) if rctx.attr.incompatible_generate_aliases else "@{}_{}//:pkg".format(rctx.attr.name, p)
             for p in bzl_packages
         ]),
         "%%ALL_WHL_REQUIREMENTS%%": _format_repr_list([
-            "@{}//:{}_whl".format(repo_name, p)
+            "@@{}//{}:whl".format(repo_name, p) if rctx.attr.incompatible_generate_aliases else "@{}_{}//:whl".format(rctx.attr.name, p)
             for p in bzl_packages
         ]),
         "%%NAME%%": rctx.attr.name,
@@ -331,6 +382,10 @@
     })
 
 pip_repository_bzlmod_attrs = {
+    "incompatible_generate_aliases": attr.bool(
+        default = False,
+        doc = "Allow generating aliases in '@pip//:<pkg>' -> '@pip_<pkg>//:pkg'. This replaces the aliases generated by the `bzlmod` tooling.",
+    ),
     "requirements_darwin": attr.label(
         allow_single_file = True,
         doc = "Override the requirements_lock attribute when the host platform is Mac OS",
@@ -405,14 +460,17 @@
     if rctx.attr.python_interpreter_target:
         config["python_interpreter_target"] = str(rctx.attr.python_interpreter_target)
 
+    if rctx.attr.incompatible_generate_aliases:
+        _pkg_aliases(rctx, rctx.attr.name, bzl_packages)
+
     rctx.file("BUILD.bazel", _BUILD_FILE_CONTENTS)
     rctx.template("requirements.bzl", rctx.attr._template, substitutions = {
         "%%ALL_REQUIREMENTS%%": _format_repr_list([
-            "@{}_{}//:pkg".format(rctx.attr.name, p)
+            "@{}//{}".format(rctx.attr.name, p) if rctx.attr.incompatible_generate_aliases else "@{}_{}//:pkg".format(rctx.attr.name, p)
             for p in bzl_packages
         ]),
         "%%ALL_WHL_REQUIREMENTS%%": _format_repr_list([
-            "@{}_{}//:whl".format(rctx.attr.name, p)
+            "@{}//{}:whl".format(rctx.attr.name, p) if rctx.attr.incompatible_generate_aliases else "@{}_{}//:whl".format(rctx.attr.name, p)
             for p in bzl_packages
         ]),
         "%%ANNOTATIONS%%": _format_dict(_repr_dict(annotations)),
@@ -520,6 +578,10 @@
     "annotations": attr.string_dict(
         doc = "Optional annotations to apply to packages",
     ),
+    "incompatible_generate_aliases": attr.bool(
+        default = False,
+        doc = "Allow generating aliases '@pip//<pkg>' -> '@pip_<pkg>//:pkg'.",
+    ),
     "requirements_darwin": attr.label(
         allow_single_file = True,
         doc = "Override the requirements_lock attribute when the host platform is Mac OS",