Skip to content
Sarj Code Standards

no-redundant-module-alias-exports

Do not manufacture public APIs from private names or replace the current module.

Why

Binding a public name to a private implementation creates two names for one API and disguises the intended visibility boundary. Replacing the current module similarly mutates import identity at runtime in a way static tools cannot model. Both forms make navigation, introspection, and compatibility ownership surprising.

Fix

Define maintained APIs under their public names and update local callers directly. Import the canonical path inside maintained code. If a compatibility module is still required, expose its supported names with explicit same-name imports grouped by source module. Preserve a required compatibility or module-identity contract with a reasoned exact suppression rather than renaming automatically.

Examples

Before — flagged Do not replace a compatibility module at runtime
legacy/settings.py
import sys
from canonical import settings as _canonical
sys.modules[__name__] = _canonical
After — preferred Expose the supported compatibility surface explicitly
legacy/settings.py
from canonical.settings import (
Settings as Settings,
load as load,
)
Before — flagged Native syntax preserves the existing ownership contract
app/pagination.py
def _encode_cursor(value: str) -> str:
return value
encode_phone_number_cursor = _encode_cursor
After — preferred Existing semantic ownership exclusions remain valid
app/pagination.py
__version__ = "value"
public_version = __version__
Before — flagged Define a public helper under its public name
pagination.py
def _encode_cursor(value: str) -> str:
return value
encode_phone_number_cursor = _encode_cursor
After — preferred Give the implementation its intended public name
pagination.py
def encode_phone_number_cursor(value: str) -> str:
return value