RyanCodrai/turbovec · error · AttributeError

module {__name__!r} has no attribute {name!r}

Error message

module {__name__!r} has no attribute {name!r}

What it means

turbovec uses PEP 562 module-level __getattr__ to lazily expose __version__ (read from installed distribution metadata) and cache it in globals(). If the requested attribute is not __version__ and not already defined on the module, __getattr__ raises AttributeError. This is the standard mechanism Python itself uses for genuinely missing module attributes, so it surfaces whenever you access a name that does not exist on the turbovec package.

Source

Thrown at turbovec-python/python/turbovec/__init__.py:42

__all__ = ["BATCH_CHUNK_SIZE", "IdMapIndex", "TurboQuantIndex", "__version__"]


def __getattr__(name: str) -> str:
    # PEP 562: resolve __version__ lazily on first access. Importing
    # importlib.metadata costs ~20 ms — an order of magnitude more than
    # the rest of `import turbovec` — so it must not run at import time.
    if name == "__version__":
        from importlib.metadata import PackageNotFoundError, version

        try:
            v = version("turbovec")
        except PackageNotFoundError:
            # Source tree without installed dist metadata (e.g. the
            # extension built in place); an obviously-dev marker.
            v = "0.0.0.dev0"
        globals()["__version__"] = v  # cache: __getattr__ never fires again
        return v
    raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


def __dir__() -> list:
    # PEP 562 companion: advertise the lazy attribute before its first
    # access (the set-union keeps it single once cached in globals()).
    return sorted(set(globals()) | {"__version__"})

View on GitHub (pinned to ccab9f325e)

Solutions

  1. Check the spelling of the attribute against `dir(turbovec)` (which via __dir__ already includes the lazy __version__).
  2. Verify the symbol exists in your installed turbovec version (`pip show turbovec`, or inspect python/turbovec/__init__.py).
  3. If you need __version__ and it is not resolving, install the package so importlib.metadata finds the distribution, or accept the 0.0.0.dev0 dev marker.
  4. If the symbol was renamed in a newer version, update call sites or pin the older version.

Example fix

// before
from turbovec import deduplcate
// after
from turbovec import deduplicate  # or: import turbovec; dir(turbovec) to list names
Defensive patterns

Strategy: type-guard

Validate before calling

import turbovec
name = 'deduplicate'
assert name in dir(turbovec), f'turbovec has no attribute {name}'

Type guard

def has_attr(mod, name: str) -> bool:
    return name in dir(mod)

Try / catch

try:
    fn = getattr(turbovec, name)
except AttributeError:
    fn = None  # or log and fall back
if fn is None:
    ...

Prevention

When it happens

Trigger: Accessing any undefined attribute of the turbovec module, e.g. `turbovec.vecor` (typo), `from turbovec import nonexistent_fn`, or introspection/probing by tooling (getattr with a default of no sentinel, IDE plugins, pickling probes for __dunder__ names).

Common situations: Typo'd imports after a rename; code written against a different library version where the symbol moved or was removed; dynamic attribute access frameworks (pickle, copy, IDE autocomplete) probing common names like __path__ or __version__ on a source-tree install without dist metadata.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of RyanCodrai/turbovec@ccab9f325e (2026-09-06). Data as JSON: /api/errors/dbc5d87d70dffff3. Report an issue: GitHub.