Skip to content

Add namespaceOverridePaths configOption for fragmented package support #11257

@q4rk

Description

@q4rk

This is a request to introduce a new configuration setting, namespaceOverridePaths, designed to align Pyright’s static analysis with the complex runtime import behaviors of modern build systems (like Bazel) and legacy Python namespace patterns.

Problem

Currently, the ImportResolver strictly adheres to standard PEP 484/561 logic: if an init.py file is found, that directory is classified as a Regular Package. The search immediately terminates at that root, and the resolver ignores any subsequent entries in the sys.path.

While this is correct for standard environments, it creates significant "shadowing" issues in environments where a single logical package is physically fragmented across multiple directories.

The Shadowing Problem

  1. Bazel & rules_python
    Bazel constructs a virtual execroot (runfiles tree) by symlinking targets from various locations. A project might have:
src/pkg/core/__init__.py (Main Repo)
gen/pkg/core/__init__.py (Generated Code)
external/pip_dep/pkg/__init__.py (Third-party)

In the Bazel runtime, all three directories are added to the PYTHONPATH. However, after adding these directories to the python.analyzer.extraPaths if the ImportResolver finds the __init__.py in src/pkg/core, it stops. It shadows the generated protos and the third-party utils, leading to "Module not found" errors in the IDE that do not exist at runtime.

  1. Legacy pkgutil / pkg_resources Namespaces
    Many enterprise libraries (e.g., google-cloud-sdk, azure-namespace) still use legacy namespace declarations:
__path__ = __import__('pkgutil').extend_path(__path__, __name__)

These libraries contain an __init__.py specifically to allow merging with other directories. Currently, the resolver treats these as terminal Regular Packages, effectively breaking the discovery of sub-packages distributed across multiple installed wheels.

Solution

The proposed change is to introduces a configuration array that allows users to explicitly define transparent namespaces. When the resolver encounters a directory within these paths, it treats it as a namespace segment even if an init.py is present.

I have a draft pr #11256 open that addresses this enhancement with a full implementation, schema updates, and comprehensive test coverage.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions