refactor(toolchains): split the implementation of toolchain rules to separate files (#2232)

This makes the dependency management in WORKSPACE much easier to do.

Summary:
- refactor: split out the py_repositories call to a separate file
- refactor: split out the python_repository rule to a separate file
- refactor: split out the standalone interpreter utility function
- refactor: split out the python_register_toolchains function
- refactor: rename the remaining file

Work towards #2081.
diff --git a/examples/bzlmod/MODULE.bazel.lock b/examples/bzlmod/MODULE.bazel.lock
index f0144e8..234dc46 100644
--- a/examples/bzlmod/MODULE.bazel.lock
+++ b/examples/bzlmod/MODULE.bazel.lock
@@ -1231,7 +1231,7 @@
     },
     "@@rules_python~//python/extensions:pip.bzl%pip": {
       "general": {
-        "bzlTransitiveDigest": "jb9c5l3dvSB2MHd/zfkT8Yr8efvg+K/YHtiRHU3aU6o=",
+        "bzlTransitiveDigest": "Cca+OPIA5xqQl5ND8j44y5jBkjQfz+36h8Hgq0N26I0=",
         "usagesDigest": "MChlcSw99EuW3K7OOoMcXQIdcJnEh6YmfyjJm+9mxIg=",
         "recordedFileInputs": {
           "@@other_module~//requirements_lock_3_11.txt": "a7d0061366569043d5efcf80e34a32c732679367cb3c831c4cdc606adc36d314",
@@ -6140,7 +6140,7 @@
     },
     "@@rules_python~//python/private/pypi:pip.bzl%pip_internal": {
       "general": {
-        "bzlTransitiveDigest": "cLqaqCEOdhle6//lX1Kcs2hfkmSerh2fk0izwhV8/GU=",
+        "bzlTransitiveDigest": "wkQNgti5fKONsAUn77ZyTWdfaJfI2cSDrSI0b4JzmI8=",
         "usagesDigest": "Y8ihY+R57BAFhalrVLVdJFrpwlbsiKz9JPJ99ljF7HA=",
         "recordedFileInputs": {
           "@@rules_python~//tools/publish/requirements.txt": "031e35d03dde03ae6305fe4b3d1f58ad7bdad857379752deede0f93649991b8a",
diff --git a/python/BUILD.bazel b/python/BUILD.bazel
index 6fcde38..b7a2172 100644
--- a/python/BUILD.bazel
+++ b/python/BUILD.bazel
@@ -229,7 +229,11 @@
     name = "repositories_bzl",
     srcs = ["repositories.bzl"],
     deps = [
-        "//python/private:python_repositories_bzl",
+        "//python/private:is_standalone_interpreter_bzl",
+        "//python/private:py_repositories_bzl",
+        "//python/private:python_register_multi_toolchains_bzl",
+        "//python/private:python_register_toolchains_bzl",
+        "//python/private:python_repository_bzl",
     ],
 )
 
diff --git a/python/private/BUILD.bazel b/python/private/BUILD.bazel
index 1e05b92..5fa5514 100644
--- a/python/private/BUILD.bazel
+++ b/python/private/BUILD.bazel
@@ -124,6 +124,14 @@
 )
 
 bzl_library(
+    name = "is_standalone_interpreter_bzl",
+    srcs = ["is_standalone_interpreter.bzl"],
+    deps = [
+        ":repo_utils_bzl",
+    ],
+)
+
+bzl_library(
     name = "normalize_name_bzl",
     srcs = ["normalize_name.bzl"],
 )
@@ -143,23 +151,54 @@
 )
 
 bzl_library(
-    name = "python_repositories_bzl",
-    srcs = ["python_repositories.bzl"],
+    name = "py_repositories_bzl",
+    srcs = ["py_repositories.bzl"],
     deps = [
-        "//python:versions_bzl",
-        "//python/private:auth_bzl",
-        "//python/private:bazel_tools_bzl",
-        "//python/private:bzlmod_enabled_bzl",
-        "//python/private:coverage_deps_bzl",
-        "//python/private:full_version_bzl",
-        "//python/private:internal_config_repo_bzl",
-        "//python/private:repo_utils_bzl",
-        "//python/private:toolchains_repo_bzl",
+        ":bazel_tools_bzl",
+        ":internal_config_repo_bzl",
         "//python/private/pypi:deps_bzl",
     ],
 )
 
 bzl_library(
+    name = "python_register_toolchains_bzl",
+    srcs = ["python_register_toolchains.bzl"],
+    deps = [
+        ":auth_bzl",
+        ":bazel_tools_bzl",
+        ":bzlmod_enabled_bzl",
+        ":coverage_deps_bzl",
+        ":full_version_bzl",
+        ":internal_config_repo_bzl",
+        ":python_repository_bzl",
+        ":toolchains_repo_bzl",
+        "//python:versions_bzl",
+        "//python/private/pypi:deps_bzl",
+    ],
+)
+
+bzl_library(
+    name = "python_repository_bzl",
+    srcs = ["python_repository.bzl"],
+    deps = [
+        ":auth_bzl",
+        ":repo_utils_bzl",
+        ":text_util_bzl",
+        "//python:versions_bzl",
+    ],
+)
+
+bzl_library(
+    name = "python_register_multi_toolchains_bzl",
+    srcs = ["python_register_multi_toolchains.bzl"],
+    deps = [
+        ":python_register_toolchains_bzl",
+        ":toolchains_repo_bzl",
+        "//python:versions_bzl",
+    ],
+)
+
+bzl_library(
     name = "pythons_hub_bzl",
     srcs = ["pythons_hub.bzl"],
     deps = [
diff --git a/python/private/is_standalone_interpreter.bzl b/python/private/is_standalone_interpreter.bzl
new file mode 100644
index 0000000..5da7389
--- /dev/null
+++ b/python/private/is_standalone_interpreter.bzl
@@ -0,0 +1,50 @@
+# Copyright 2024 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""This file contains repository rules and macros to support toolchain registration.
+"""
+
+load(":repo_utils.bzl", "repo_utils")
+
+STANDALONE_INTERPRETER_FILENAME = "STANDALONE_INTERPRETER"
+
+def is_standalone_interpreter(rctx, python_interpreter_path, *, logger = None):
+    """Query a python interpreter target for whether or not it's a rules_rust provided toolchain
+
+    Args:
+        rctx: {type}`repository_ctx` The repository rule's context object.
+        python_interpreter_path: {type}`path` A path representing the interpreter.
+        logger: Optional logger to use for operations.
+
+    Returns:
+        {type}`bool` Whether or not the target is from a rules_python generated toolchain.
+    """
+
+    # Only update the location when using a hermetic toolchain.
+    if not python_interpreter_path:
+        return False
+
+    # This is a rules_python provided toolchain.
+    return repo_utils.execute_unchecked(
+        rctx,
+        op = "IsStandaloneInterpreter",
+        arguments = [
+            "ls",
+            "{}/{}".format(
+                python_interpreter_path.dirname,
+                STANDALONE_INTERPRETER_FILENAME,
+            ),
+        ],
+        logger = logger,
+    ).return_code == 0
diff --git a/python/private/py_repositories.bzl b/python/private/py_repositories.bzl
new file mode 100644
index 0000000..ace3750
--- /dev/null
+++ b/python/private/py_repositories.bzl
@@ -0,0 +1,49 @@
+# Copyright 2024 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""This file contains macros to be called during WORKSPACE evaluation."""
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_archive = "http_archive")
+load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
+load("//python/private/pypi:deps.bzl", "pypi_deps")
+load(":internal_config_repo.bzl", "internal_config_repo")
+
+def http_archive(**kwargs):
+    maybe(_http_archive, **kwargs)
+
+def py_repositories():
+    """Runtime dependencies that users must install.
+
+    This function should be loaded and called in the user's WORKSPACE.
+    With bzlmod enabled, this function is not needed since MODULE.bazel handles transitive deps.
+    """
+    maybe(
+        internal_config_repo,
+        name = "rules_python_internal",
+    )
+    http_archive(
+        name = "bazel_skylib",
+        sha256 = "74d544d96f4a5bb630d465ca8bbcfe231e3594e5aae57e1edbf17a6eb3ca2506",
+        urls = [
+            "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz",
+            "https://github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz",
+        ],
+    )
+    http_archive(
+        name = "rules_cc",
+        urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.0.9/rules_cc-0.0.9.tar.gz"],
+        sha256 = "2037875b9a4456dce4a79d112a8ae885bbc4aad968e6587dca6e64f3a0900cdf",
+        strip_prefix = "rules_cc-0.0.9",
+    )
+    pypi_deps()
diff --git a/python/private/pypi/BUILD.bazel b/python/private/pypi/BUILD.bazel
index 1db50af..2b25bfb 100644
--- a/python/private/pypi/BUILD.bazel
+++ b/python/private/pypi/BUILD.bazel
@@ -306,9 +306,9 @@
         ":patch_whl_bzl",
         ":pypi_repo_utils_bzl",
         ":whl_target_platforms_bzl",
-        "//python:repositories_bzl",
         "//python/private:auth_bzl",
         "//python/private:envsubst_bzl",
+        "//python/private:is_standalone_interpreter_bzl",
         "//python/private:repo_utils_bzl",
     ],
 )
diff --git a/python/private/pypi/whl_library.bzl b/python/private/pypi/whl_library.bzl
index 5b14151..309316b 100644
--- a/python/private/pypi/whl_library.bzl
+++ b/python/private/pypi/whl_library.bzl
@@ -16,7 +16,7 @@
 
 load("//python/private:auth.bzl", "AUTH_ATTRS", "get_auth")
 load("//python/private:envsubst.bzl", "envsubst")
-load("//python/private:python_repositories.bzl", "is_standalone_interpreter")
+load("//python/private:is_standalone_interpreter.bzl", "is_standalone_interpreter")
 load("//python/private:repo_utils.bzl", "REPO_DEBUG_ENV_VAR", "repo_utils")
 load(":attrs.bzl", "ATTRS", "use_isolated")
 load(":deps.bzl", "all_repo_names")
diff --git a/python/private/python.bzl b/python/private/python.bzl
index 9a9a240..98b089f 100644
--- a/python/private/python.bzl
+++ b/python/private/python.bzl
@@ -15,9 +15,9 @@
 "Python toolchain module extensions for use with bzlmod"
 
 load("@bazel_features//:features.bzl", "bazel_features")
-load("//python:repositories.bzl", "python_register_toolchains")
 load("//python:versions.bzl", "MINOR_MAPPING", "TOOL_VERSIONS")
 load(":full_version.bzl", "full_version")
+load(":python_register_toolchains.bzl", "python_register_toolchains")
 load(":pythons_hub.bzl", "hub_repo")
 load(":repo_utils.bzl", "repo_utils")
 load(":text_util.bzl", "render")
diff --git a/python/private/python_register_multi_toolchains.bzl b/python/private/python_register_multi_toolchains.bzl
new file mode 100644
index 0000000..68f5249
--- /dev/null
+++ b/python/private/python_register_multi_toolchains.bzl
@@ -0,0 +1,75 @@
+# Copyright 2024 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""This file contains repository rules and macros to support toolchain registration.
+"""
+
+load("//python:versions.bzl", "MINOR_MAPPING")
+load(":python_register_toolchains.bzl", "python_register_toolchains")
+load(":toolchains_repo.bzl", "multi_toolchain_aliases")
+
+def python_register_multi_toolchains(
+        name,
+        python_versions,
+        default_version = None,
+        minor_mapping = None,
+        **kwargs):
+    """Convenience macro for registering multiple Python toolchains.
+
+    Args:
+        name: {type}`str` base name for each name in {obj}`python_register_toolchains` call.
+        python_versions: {type}`list[str]` the Python versions.
+        default_version: {type}`str` the default Python version. If not set,
+            the first version in python_versions is used.
+        minor_mapping: {type}`dict[str, str]` mapping between `X.Y` to `X.Y.Z`
+            format. Defaults to the value in `//python:versions.bzl`.
+        **kwargs: passed to each {obj}`python_register_toolchains` call.
+    """
+    if len(python_versions) == 0:
+        fail("python_versions must not be empty")
+
+    minor_mapping = minor_mapping or MINOR_MAPPING
+
+    if not default_version:
+        default_version = python_versions.pop(0)
+    for python_version in python_versions:
+        if python_version == default_version:
+            # We register the default version lastly so that it's not picked first when --platforms
+            # is set with a constraint during toolchain resolution. This is due to the fact that
+            # Bazel will match the unconstrained toolchain if we register it before the constrained
+            # ones.
+            continue
+        python_register_toolchains(
+            name = name + "_" + python_version.replace(".", "_"),
+            python_version = python_version,
+            set_python_version_constraint = True,
+            minor_mapping = minor_mapping,
+            **kwargs
+        )
+    python_register_toolchains(
+        name = name + "_" + default_version.replace(".", "_"),
+        python_version = default_version,
+        set_python_version_constraint = False,
+        minor_mapping = minor_mapping,
+        **kwargs
+    )
+
+    multi_toolchain_aliases(
+        name = name,
+        python_versions = {
+            python_version: name + "_" + python_version.replace(".", "_")
+            for python_version in (python_versions + [default_version])
+        },
+        minor_mapping = minor_mapping,
+    )
diff --git a/python/private/python_register_toolchains.bzl b/python/private/python_register_toolchains.bzl
new file mode 100644
index 0000000..7638d76
--- /dev/null
+++ b/python/private/python_register_toolchains.bzl
@@ -0,0 +1,176 @@
+# Copyright 2024 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""This file contains repository rules and macros to support toolchain registration.
+"""
+
+load(
+    "//python:versions.bzl",
+    "DEFAULT_RELEASE_BASE_URL",
+    "MINOR_MAPPING",
+    "PLATFORMS",
+    "TOOL_VERSIONS",
+    "get_release_info",
+)
+load(":bzlmod_enabled.bzl", "BZLMOD_ENABLED")
+load(":coverage_deps.bzl", "coverage_dep")
+load(":full_version.bzl", "full_version")
+load(":python_repository.bzl", "python_repository")
+load(
+    ":toolchains_repo.bzl",
+    "host_toolchain",
+    "toolchain_aliases",
+    "toolchains_repo",
+)
+
+# Wrapper macro around everything above, this is the primary API.
+def python_register_toolchains(
+        name,
+        python_version,
+        register_toolchains = True,
+        register_coverage_tool = False,
+        set_python_version_constraint = False,
+        tool_versions = None,
+        minor_mapping = None,
+        **kwargs):
+    """Convenience macro for users which does typical setup.
+
+    - Create a repository for each built-in platform like "python_3_8_linux_amd64" -
+      this repository is lazily fetched when Python is needed for that platform.
+    - Create a repository exposing toolchains for each platform like
+      "python_platforms".
+    - Register a toolchain pointing at each platform.
+
+    Users can avoid this macro and do these steps themselves, if they want more
+    control.
+
+    Args:
+        name: {type}`str` base name for all created repos, e.g. "python_3_8".
+        python_version: {type}`str` the Python version.
+        register_toolchains: {type}`bool` Whether or not to register the downloaded toolchains.
+        register_coverage_tool: {type}`bool` Whether or not to register the
+            downloaded coverage tool to the toolchains.
+        set_python_version_constraint: {type}`bool` When set to `True`,
+            `target_compatible_with` for the toolchains will include a version
+            constraint.
+        tool_versions: {type}`dict` contains a mapping of version with SHASUM
+            and platform info. If not supplied, the defaults in
+            python/versions.bzl will be used.
+        minor_mapping: {type}`dict[str, str]` contains a mapping from `X.Y` to `X.Y.Z`
+            version.
+        **kwargs: passed to each {obj}`python_repository` call.
+    """
+
+    if BZLMOD_ENABLED:
+        # you cannot used native.register_toolchains when using bzlmod.
+        register_toolchains = False
+
+    base_url = kwargs.pop("base_url", DEFAULT_RELEASE_BASE_URL)
+    tool_versions = tool_versions or TOOL_VERSIONS
+    minor_mapping = minor_mapping or MINOR_MAPPING
+
+    python_version = full_version(version = python_version, minor_mapping = minor_mapping)
+
+    toolchain_repo_name = "{name}_toolchains".format(name = name)
+
+    # When using unreleased Bazel versions, the version is an empty string
+    if native.bazel_version:
+        bazel_major = int(native.bazel_version.split(".")[0])
+        if bazel_major < 6:
+            if register_coverage_tool:
+                # buildifier: disable=print
+                print((
+                    "WARNING: ignoring register_coverage_tool=True when " +
+                    "registering @{name}: Bazel 6+ required, got {version}"
+                ).format(
+                    name = name,
+                    version = native.bazel_version,
+                ))
+            register_coverage_tool = False
+
+    loaded_platforms = []
+    for platform in PLATFORMS.keys():
+        sha256 = tool_versions[python_version]["sha256"].get(platform, None)
+        if not sha256:
+            continue
+
+        loaded_platforms.append(platform)
+        (release_filename, urls, strip_prefix, patches, patch_strip) = get_release_info(platform, python_version, base_url, tool_versions)
+
+        # allow passing in a tool version
+        coverage_tool = None
+        coverage_tool = tool_versions[python_version].get("coverage_tool", {}).get(platform, None)
+        if register_coverage_tool and coverage_tool == None:
+            coverage_tool = coverage_dep(
+                name = "{name}_{platform}_coverage".format(
+                    name = name,
+                    platform = platform,
+                ),
+                python_version = python_version,
+                platform = platform,
+                visibility = ["@{name}_{platform}//:__subpackages__".format(
+                    name = name,
+                    platform = platform,
+                )],
+            )
+
+        python_repository(
+            name = "{name}_{platform}".format(
+                name = name,
+                platform = platform,
+            ),
+            sha256 = sha256,
+            patches = patches,
+            patch_strip = patch_strip,
+            platform = platform,
+            python_version = python_version,
+            release_filename = release_filename,
+            urls = urls,
+            strip_prefix = strip_prefix,
+            coverage_tool = coverage_tool,
+            **kwargs
+        )
+        if register_toolchains:
+            native.register_toolchains("@{toolchain_repo_name}//:{platform}_toolchain".format(
+                toolchain_repo_name = toolchain_repo_name,
+                platform = platform,
+            ))
+            native.register_toolchains("@{toolchain_repo_name}//:{platform}_py_cc_toolchain".format(
+                toolchain_repo_name = toolchain_repo_name,
+                platform = platform,
+            ))
+            native.register_toolchains("@{toolchain_repo_name}//:{platform}_py_exec_tools_toolchain".format(
+                toolchain_repo_name = toolchain_repo_name,
+                platform = platform,
+            ))
+
+    host_toolchain(name = name + "_host")
+
+    toolchain_aliases(
+        name = name,
+        python_version = python_version,
+        user_repository_name = name,
+        platforms = loaded_platforms,
+    )
+
+    # in bzlmod we write out our own toolchain repos
+    if BZLMOD_ENABLED:
+        return
+
+    toolchains_repo(
+        name = toolchain_repo_name,
+        python_version = python_version,
+        set_python_version_constraint = set_python_version_constraint,
+        user_repository_name = name,
+    )
diff --git a/python/private/python_repositories.bzl b/python/private/python_repository.bzl
similarity index 61%
rename from python/private/python_repositories.bzl
rename to python/private/python_repository.bzl
index 0286160..28a2c95 100644
--- a/python/private/python_repositories.bzl
+++ b/python/private/python_repository.bzl
@@ -1,4 +1,4 @@
-# Copyright 2022 The Bazel Authors. All rights reserved.
+# Copyright 2024 The Bazel Authors. All rights reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,69 +12,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""This file contains macros to be called during WORKSPACE evaluation.
-
-For historic reasons, pip_repositories() is defined in //python:pip.bzl.
+"""This file contains repository rules and macros to support toolchain registration.
 """
 
-load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_archive = "http_archive")
-load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
-load(
-    "//python:versions.bzl",
-    "DEFAULT_RELEASE_BASE_URL",
-    "MINOR_MAPPING",
-    "PLATFORMS",
-    "TOOL_VERSIONS",
-    "get_release_info",
-)
-load("//python/private/pypi:deps.bzl", "pypi_deps")
+load("//python:versions.bzl", "PLATFORMS")
 load(":auth.bzl", "get_auth")
-load(":bzlmod_enabled.bzl", "BZLMOD_ENABLED")
-load(":coverage_deps.bzl", "coverage_dep")
-load(":full_version.bzl", "full_version")
-load(":internal_config_repo.bzl", "internal_config_repo")
 load(":repo_utils.bzl", "REPO_DEBUG_ENV_VAR", "repo_utils")
 load(":text_util.bzl", "render")
-load(
-    ":toolchains_repo.bzl",
-    "host_toolchain",
-    "multi_toolchain_aliases",
-    "toolchain_aliases",
-    "toolchains_repo",
-)
-
-def http_archive(**kwargs):
-    maybe(_http_archive, **kwargs)
-
-def py_repositories():
-    """Runtime dependencies that users must install.
-
-    This function should be loaded and called in the user's WORKSPACE.
-    With bzlmod enabled, this function is not needed since MODULE.bazel handles transitive deps.
-    """
-    maybe(
-        internal_config_repo,
-        name = "rules_python_internal",
-    )
-    http_archive(
-        name = "bazel_skylib",
-        sha256 = "74d544d96f4a5bb630d465ca8bbcfe231e3594e5aae57e1edbf17a6eb3ca2506",
-        urls = [
-            "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz",
-            "https://github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz",
-        ],
-    )
-    http_archive(
-        name = "rules_cc",
-        urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.0.9/rules_cc-0.0.9.tar.gz"],
-        sha256 = "2037875b9a4456dce4a79d112a8ae885bbc4aad968e6587dca6e64f3a0900cdf",
-        strip_prefix = "rules_cc-0.0.9",
-    )
-    pypi_deps()
-
-########
-# Remaining content of the file is only used to support toolchains.
-########
 
 STANDALONE_INTERPRETER_FILENAME = "STANDALONE_INTERPRETER"
 
@@ -458,199 +402,3 @@
     },
     environ = [REPO_DEBUG_ENV_VAR],
 )
-
-# Wrapper macro around everything above, this is the primary API.
-def python_register_toolchains(
-        name,
-        python_version,
-        register_toolchains = True,
-        register_coverage_tool = False,
-        set_python_version_constraint = False,
-        tool_versions = None,
-        minor_mapping = None,
-        **kwargs):
-    """Convenience macro for users which does typical setup.
-
-    - Create a repository for each built-in platform like "python_3_8_linux_amd64" -
-      this repository is lazily fetched when Python is needed for that platform.
-    - Create a repository exposing toolchains for each platform like
-      "python_platforms".
-    - Register a toolchain pointing at each platform.
-
-    Users can avoid this macro and do these steps themselves, if they want more
-    control.
-
-    Args:
-        name: {type}`str` base name for all created repos, e.g. "python_3_8".
-        python_version: {type}`str` the Python version.
-        register_toolchains: {type}`bool` Whether or not to register the downloaded toolchains.
-        register_coverage_tool: {type}`bool` Whether or not to register the
-            downloaded coverage tool to the toolchains.
-        set_python_version_constraint: {type}`bool` When set to `True`,
-            `target_compatible_with` for the toolchains will include a version
-            constraint.
-        tool_versions: {type}`dict` contains a mapping of version with SHASUM
-            and platform info. If not supplied, the defaults in
-            python/versions.bzl will be used.
-        minor_mapping: {type}`dict[str, str]` contains a mapping from `X.Y` to `X.Y.Z`
-            version.
-        **kwargs: passed to each {obj}`python_repository` call.
-    """
-
-    if BZLMOD_ENABLED:
-        # you cannot used native.register_toolchains when using bzlmod.
-        register_toolchains = False
-
-    base_url = kwargs.pop("base_url", DEFAULT_RELEASE_BASE_URL)
-    tool_versions = tool_versions or TOOL_VERSIONS
-    minor_mapping = minor_mapping or MINOR_MAPPING
-
-    python_version = full_version(version = python_version, minor_mapping = minor_mapping)
-
-    toolchain_repo_name = "{name}_toolchains".format(name = name)
-
-    # When using unreleased Bazel versions, the version is an empty string
-    if native.bazel_version:
-        bazel_major = int(native.bazel_version.split(".")[0])
-        if bazel_major < 6:
-            if register_coverage_tool:
-                # buildifier: disable=print
-                print((
-                    "WARNING: ignoring register_coverage_tool=True when " +
-                    "registering @{name}: Bazel 6+ required, got {version}"
-                ).format(
-                    name = name,
-                    version = native.bazel_version,
-                ))
-            register_coverage_tool = False
-
-    loaded_platforms = []
-    for platform in PLATFORMS.keys():
-        sha256 = tool_versions[python_version]["sha256"].get(platform, None)
-        if not sha256:
-            continue
-
-        loaded_platforms.append(platform)
-        (release_filename, urls, strip_prefix, patches, patch_strip) = get_release_info(platform, python_version, base_url, tool_versions)
-
-        # allow passing in a tool version
-        coverage_tool = None
-        coverage_tool = tool_versions[python_version].get("coverage_tool", {}).get(platform, None)
-        if register_coverage_tool and coverage_tool == None:
-            coverage_tool = coverage_dep(
-                name = "{name}_{platform}_coverage".format(
-                    name = name,
-                    platform = platform,
-                ),
-                python_version = python_version,
-                platform = platform,
-                visibility = ["@{name}_{platform}//:__subpackages__".format(
-                    name = name,
-                    platform = platform,
-                )],
-            )
-
-        python_repository(
-            name = "{name}_{platform}".format(
-                name = name,
-                platform = platform,
-            ),
-            sha256 = sha256,
-            patches = patches,
-            patch_strip = patch_strip,
-            platform = platform,
-            python_version = python_version,
-            release_filename = release_filename,
-            urls = urls,
-            strip_prefix = strip_prefix,
-            coverage_tool = coverage_tool,
-            **kwargs
-        )
-        if register_toolchains:
-            native.register_toolchains("@{toolchain_repo_name}//:{platform}_toolchain".format(
-                toolchain_repo_name = toolchain_repo_name,
-                platform = platform,
-            ))
-            native.register_toolchains("@{toolchain_repo_name}//:{platform}_py_cc_toolchain".format(
-                toolchain_repo_name = toolchain_repo_name,
-                platform = platform,
-            ))
-            native.register_toolchains("@{toolchain_repo_name}//:{platform}_py_exec_tools_toolchain".format(
-                toolchain_repo_name = toolchain_repo_name,
-                platform = platform,
-            ))
-
-    host_toolchain(name = name + "_host")
-
-    toolchain_aliases(
-        name = name,
-        python_version = python_version,
-        user_repository_name = name,
-        platforms = loaded_platforms,
-    )
-
-    # in bzlmod we write out our own toolchain repos
-    if BZLMOD_ENABLED:
-        return
-
-    toolchains_repo(
-        name = toolchain_repo_name,
-        python_version = python_version,
-        set_python_version_constraint = set_python_version_constraint,
-        user_repository_name = name,
-    )
-
-def python_register_multi_toolchains(
-        name,
-        python_versions,
-        default_version = None,
-        minor_mapping = None,
-        **kwargs):
-    """Convenience macro for registering multiple Python toolchains.
-
-    Args:
-        name: {type}`str` base name for each name in {obj}`python_register_toolchains` call.
-        python_versions: {type}`list[str]` the Python versions.
-        default_version: {type}`str` the default Python version. If not set,
-            the first version in python_versions is used.
-        minor_mapping: {type}`dict[str, str]` mapping between `X.Y` to `X.Y.Z`
-            format. Defaults to the value in `//python:versions.bzl`.
-        **kwargs: passed to each {obj}`python_register_toolchains` call.
-    """
-    if len(python_versions) == 0:
-        fail("python_versions must not be empty")
-
-    minor_mapping = minor_mapping or MINOR_MAPPING
-
-    if not default_version:
-        default_version = python_versions.pop(0)
-    for python_version in python_versions:
-        if python_version == default_version:
-            # We register the default version lastly so that it's not picked first when --platforms
-            # is set with a constraint during toolchain resolution. This is due to the fact that
-            # Bazel will match the unconstrained toolchain if we register it before the constrained
-            # ones.
-            continue
-        python_register_toolchains(
-            name = name + "_" + python_version.replace(".", "_"),
-            python_version = python_version,
-            set_python_version_constraint = True,
-            minor_mapping = minor_mapping,
-            **kwargs
-        )
-    python_register_toolchains(
-        name = name + "_" + default_version.replace(".", "_"),
-        python_version = default_version,
-        set_python_version_constraint = False,
-        minor_mapping = minor_mapping,
-        **kwargs
-    )
-
-    multi_toolchain_aliases(
-        name = name,
-        python_versions = {
-            python_version: name + "_" + python_version.replace(".", "_")
-            for python_version in (python_versions + [default_version])
-        },
-        minor_mapping = minor_mapping,
-    )
diff --git a/python/repositories.bzl b/python/repositories.bzl
index 88c00e2..768b587 100644
--- a/python/repositories.bzl
+++ b/python/repositories.bzl
@@ -16,14 +16,14 @@
 """
 
 load(
-    "//python/private:python_repositories.bzl",
+    "//python/private:is_standalone_interpreter.bzl",
     _STANDALONE_INTERPRETER_FILENAME = "STANDALONE_INTERPRETER_FILENAME",
     _is_standalone_interpreter = "is_standalone_interpreter",
-    _py_repositories = "py_repositories",
-    _python_register_multi_toolchains = "python_register_multi_toolchains",
-    _python_register_toolchains = "python_register_toolchains",
-    _python_repository = "python_repository",
 )
+load("//python/private:py_repositories.bzl", _py_repositories = "py_repositories")
+load("//python/private:python_register_multi_toolchains.bzl", _python_register_multi_toolchains = "python_register_multi_toolchains")
+load("//python/private:python_register_toolchains.bzl", _python_register_toolchains = "python_register_toolchains")
+load("//python/private:python_repository.bzl", _python_repository = "python_repository")
 
 py_repositories = _py_repositories
 python_register_multi_toolchains = _python_register_multi_toolchains