From 902cab67af499b196d1b66b7d073783a14411dd6 Mon Sep 17 00:00:00 2001 From: Toby Harradine Date: Fri, 30 Jan 2026 19:09:21 +1100 Subject: [PATCH] `pycross_wheel_library`: enable implicit namespace packages ## Context Currently, `pycross_wheel_library` installs wheels and unconditionally converts any implicit namespace packages into legacy `pkgutil`-style namespace packages. This `pkgutil`-style conversion can be problematic and unexpected in a lot of cases, and should be unnecessary beyond Python 3.3 when the `--incompatible_default_to_explicit_init_py=true` Bazel flag is set. Looking at the `pycross_wheel_library` rule implementation, and the source code of `wheel_installer.py`, it appears as though there was an intention to allow users to disable this `pkgutil`-style conversion, but the option isn't exposed via the Bazel interfaces, and it's also not used inside the script itself. ## Intent Allow users to disable the automatic conversion of PEP 420 implicit namespace packages to `pkgutil`-style namespace packages, whilst maintaining backwards compatibility. ## Changes - Introduce a boolean bazelrc flag, `--@rules_pycross//config_settings:default_enable_implicit_namespace_pkgs`, to configure the default behaviour of enabling implicit namespace packages in `pycross_wheel_library`. - Update the `pycross_wheel_library` rule and ``wheel_installer.py` script to respect the flag. - Document the flag. --- docs/config_settings.md | 11 +++++++++++ docs/rules.md | 2 +- pycross/config_settings/BUILD.bazel | 7 +++++++ pycross/private/BUILD.bazel | 1 + pycross/private/tools/wheel_installer.py | 4 +++- pycross/private/wheel_library.bzl | 16 ++++++++++++---- 6 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 docs/config_settings.md create mode 100644 pycross/config_settings/BUILD.bazel diff --git a/docs/config_settings.md b/docs/config_settings.md new file mode 100644 index 00000000..568678be --- /dev/null +++ b/docs/config_settings.md @@ -0,0 +1,11 @@ +Settings and flags for `rules_pycross`. + + + +## `default_enable_implicit_namespace_packages` + +Flag: `--@rules_pycross//pycross/config_settings:default_enable_implicit_namespace_packages` +Type: `bool` +Default: `false` + +When enabled, [`pycross_wheel_library.enable_implicit_namespace_packages`](./rules.md#pycross_wheel_library-enable_implicit_namespace_pkgs) will default to `True`. diff --git a/docs/rules.md b/docs/rules.md index 7d892410..3cedc84b 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -207,7 +207,7 @@ pycross_wheel_library(name, name | A unique name for this target. | Name | required | | | deps | A list of this wheel's Python library dependencies. | List of labels | optional | `[]` | -| 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 `legacy_create_init=False` or the global Bazel option `--incompatible_default_to_explicit_init_py` to prevent `__init__.py` being automatically generated in every directory. This option is required to support some packages which cannot handle the conversion to pkg-util style. | Boolean | optional | `True` | +| 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 `legacy_create_init=False` or the global Bazel option `--incompatible_default_to_explicit_init_py` to prevent `__init__.py` being automatically generated in every directory. This option is required to support some packages which cannot handle the conversion to pkg-util style. The default is derived from the flag `@rules_pycross//config_settings:default_enable_implicit_namespace_pkgs`. | Integer | optional | `-1` | | install_exclude_globs | A list of globs for files to exclude during installation. | List of strings | optional | `[]` | | post_install_patches | A list of patches to apply after installation. | List of labels | optional | `[]` | | python_version | The python version required for this wheel ('PY2' or 'PY3') | String | optional | `""` | diff --git a/pycross/config_settings/BUILD.bazel b/pycross/config_settings/BUILD.bazel new file mode 100644 index 00000000..bf315421 --- /dev/null +++ b/pycross/config_settings/BUILD.bazel @@ -0,0 +1,7 @@ +load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") + +bool_flag( + name = "default_enable_implicit_namespace_packages", + build_setting_default = False, + visibility = ["//visibility:public"], +) diff --git a/pycross/private/BUILD.bazel b/pycross/private/BUILD.bazel index 2d97e9c3..ec1d3764 100644 --- a/pycross/private/BUILD.bazel +++ b/pycross/private/BUILD.bazel @@ -167,6 +167,7 @@ bzl_library( deps = [ ":providers", "@bazel_skylib//lib:paths", + "@bazel_skylib//rules:common_settings", "@rules_python//python:py_info_bzl", ], ) diff --git a/pycross/private/tools/wheel_installer.py b/pycross/private/tools/wheel_installer.py index d2da19e1..b67f8a77 100644 --- a/pycross/private/tools/wheel_installer.py +++ b/pycross/private/tools/wheel_installer.py @@ -125,7 +125,9 @@ def main(args: Any) -> None: finally: shutil.rmtree(link_dir, ignore_errors=True) - setup_namespace_pkg_compatibility(lib_dir) + if not args.enable_implicit_namespace_pkgs: + setup_namespace_pkg_compatibility(lib_dir) + apply_patches(lib_dir, args.patches) diff --git a/pycross/private/wheel_library.bzl b/pycross/private/wheel_library.bzl index c2b9e77b..401f5603 100644 --- a/pycross/private/wheel_library.bzl +++ b/pycross/private/wheel_library.bzl @@ -1,6 +1,7 @@ """Implementation of the pycross_wheel_library rule.""" load("@bazel_skylib//lib:paths.bzl", "paths") +load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") load("@rules_python//python:py_info.bzl", "PyInfo") load(":providers.bzl", "PycrossWheelInfo") @@ -25,7 +26,10 @@ def _pycross_wheel_library_impl(ctx): inputs.append(name_file) args.add("--wheel-name-file", name_file) - if ctx.attr.enable_implicit_namespace_pkgs: + enable_implicit_namespace_pkgs = ( + ctx.attr.enable_implicit_namespace_pkgs if enable_implicit_namespace_pkgs == -1 else ctx.attr._default_enable_implicit_namespace_pkgs[BuildSettingInfo].value + ) + if enable_implicit_namespace_pkgs: args.add("--enable-implicit-namespace-pkgs") for install_exclude_glob in ctx.attr.install_exclude_globs: @@ -111,13 +115,14 @@ pycross_wheel_library = rule( doc = "A list of patches to apply after installation.", allow_files = True, ), - "enable_implicit_namespace_pkgs": attr.bool( - default = True, + "enable_implicit_namespace_pkgs": attr.int( + default = -1, doc = """ 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 `legacy_create_init=False` or the global Bazel option `--incompatible_default_to_explicit_init_py` to prevent `__init__.py` being automatically generated in every directory. -This option is required to support some packages which cannot handle the conversion to pkg-util style. +This option is required to support some packages which cannot handle the conversion to pkg-util style. The default is +derived from the flag `@rules_pycross//config_settings:default_enable_implicit_namespace_pkgs`. """, ), "python_version": attr.string( @@ -129,5 +134,8 @@ This option is required to support some packages which cannot handle the convers cfg = "exec", executable = True, ), + "_default_enable_implicit_namespace_pkgs": attr.label( + default = "//config_settings:default_enable_implicit_namespace_pkgs", + ), }, )