ruvnet/RuView · error · AttributeError

module 'wifi_densepose.client' has no attribute {name!r}

Error message

module 'wifi_densepose.client' has no attribute {name!r}

What it means

wifi_densepose.client implements PEP 562 lazy exports via a module-level __getattr__. Only a fixed allowlist resolves: SensingClient, SensingMessage, EdgeVitalsMessage, PoseDataMessage, ConnectionEstablishedMessage (from .ws) and RuViewMqttClient (from .mqtt). Any other attribute lookup falls through to `raise AttributeError` naming the missing symbol.

Source

Thrown at python/wifi_densepose/client/__init__.py:93

    `SensingClient` needs `websockets`; `RuViewMqttClient` needs
    `paho-mqtt`. Importing those at package init would make
    `wifi_densepose.client` unusable without the extras installed
    — defeating the point of an *optional* extra. We defer the import
    until the attribute is actually looked up.
    """
    if name in {
        "SensingClient",
        "SensingMessage",
        "EdgeVitalsMessage",
        "PoseDataMessage",
        "ConnectionEstablishedMessage",
    }:
        from wifi_densepose.client import ws as _ws
        return getattr(_ws, name)
    if name == "RuViewMqttClient":
        from wifi_densepose.client.mqtt import RuViewMqttClient as _R
        return _R
    raise AttributeError(f"module 'wifi_densepose.client' has no attribute {name!r}")

View on GitHub (pinned to 4685618388)

Solutions

  1. Use exactly one of the re-exported names (the allowlist is listed in the __getattr__ source)
  2. Import from the submodule directly: `from wifi_densepose.client.ws import SensingClient` or `from wifi_densepose.client.mqtt import RuViewMqttClient`
  3. Run `python -c "import wifi_densepose.client as c; print([n for n in dir(c)])"` against the installed version to see current exports

Example fix

# before
from wifi_densepose.client import MQTTClient  # AttributeError: no attribute 'MQTTClient'

# after
from wifi_densepose.client import RuViewMqttClient
# or directly from the submodule:
from wifi_densepose.client.mqtt import RuViewMqttClient
Defensive patterns

Strategy: type-guard

Type guard

CLIENT_EXPORTS = frozenset({
    "SensingClient", "SensingMessage", "EdgeVitalsMessage",
    "PoseDataMessage", "ConnectionEstablishedMessage",
    "RuViewMqttClient",
})

def is_client_export(name: str) -> bool:
    """True if wifi_densepose.client re-exports `name`."""
    return name in CLIENT_EXPORTS

Try / catch

try:
    obj = getattr(wifi_densepose.client, name)
except AttributeError:
    raise KeyError(
        f"{name!r} is not exported by wifi_densepose.client; "
        f"known exports: {sorted(CLIENT_EXPORTS)}"
    ) from None

Prevention

When it happens

Trigger: `from wifi_densepose.client import RuviewMqttClient` (typo), `wifi_densepose.client.MQTTClient` (wrong name), or dynamic `getattr(wifi_densepose.client, name)` where name is not in the allowlist.

Common situations: Typos; code copied from older versions with different export names; IDE autocomplete drifting from the installed version; plugin systems doing getattr-by-string.

Related errors


AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16). Data as JSON: /api/errors/c0b99bd30b550f8b. Report an issue: GitHub.