Skip to content

lightkube fails to import lightkube.models when wheels are on separate sys.path entries (e.g., Bazel rules_python) #107

@ashtuchkin

Description

@ashtuchkin

Summary

When lightkube and lightkube-models are installed into different directories on sys.path (common with Bazel rules_python, PEX/zipapp, layered containers, or custom PYTHONPATH setups), imports inside lightkube that rely on lightkube.models fail with: ModuleNotFoundError: No module named 'lightkube.models'

How to reproduce

# Create fresh venv
python3 -m venv lk-venv
. lk-venv/bin/activate

# Install the two packages into SEPARATE directories (simulates Bazel/rules_python layout)
mkdir -p lk-repro/a lk-repro/b
pip install --target lk-repro/a 'lightkube==0.17.2'
rm -rf lk-repro/a/lightkube/{models,resources}  # Remove lightkube-models from the first directory to simulate split-layout

pip install --target lk-repro/b 'lightkube-models==1.31.1.8'

# Reproduce the failure: lightkube can't see models from the other root
PYTHONPATH=lk-repro/a:lk-repro/b python -c "import lightkube"
# Observe ModuleNotFoundError: No module named 'lightkube.models'

Root cause

  • lightkube and lightkube-models both provide modules under the same top-level package name lightkube/.
  • The lightkube/__init__.py in the lightkube wheel prevents implicit namespace package behavior, so Python does not merge the lightkube package tree across multiple directories.
  • Thus, lightkube.__path__ points only to the first directory containing lightkube, and subpackages from the other wheel (e.g., lightkube.models, lightkube.resources) are invisible.

Proposed fix (backward-compatible, minimal)

Make lightkube a pkgutil-style namespace package by extending its package path in lightkube/__init__.py. This preserves the existing public API re-exports and works even when wheels are installed to different directories.

Add these two lines at the very top of lightkube/__init__.py:

from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)

Why this works:

  • pkgutil.extend_path tells Python to treat lightkube as a namespace spanning all lightkube/ directories on sys.path.
  • It’s compatible with current packaging and does not require removing __init__.py or altering the public API.

Alternatives

  • PEP 420 implicit namespace package: remove lightkube/__init__.py. Not great here because lightkube/__init__.py re-exports the public API; removing it would be a breaking change or require moving those symbols.
  • Runtime workaround in user code (not ideal): mutate lightkube.__path__ or add a custom MetaPathFinder before importing lightkube to merge paths. This is what some users do under Bazel, but it’s brittle and belongs in the package.

Affected versions

  • lightkube: 0.17.2 (and likely earlier)
  • lightkube-models: 1.31.x
  • Python: 3.12 (also reproducible on 3.10–3.11)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions