{"record":{"id":"f8f9e68fa99281b2","repo":"Textualize/textual","slug":"module-name-r-has-no-attribute-name-r","errorCode":null,"errorMessage":"module {__name__!r} has no attribute {name!r}","messagePattern":"module (.+?) has no attribute (.+?)","errorType":"exception","errorClass":"AttributeError","httpStatus":null,"severity":"error","filePath":"src/textual/__init__.py","lineNumber":52,"sourceCode":"\n\nif TYPE_CHECKING:\n    from importlib.metadata import version\n\n    from textual.app import App as _App\n\n    __version__ = version(\"textual\")\n    \"\"\"The version of Textual.\"\"\"\n\nelse:\n\n    def __getattr__(name: str) -> str:\n        \"\"\"Lazily get the version.\"\"\"\n        if name == \"__version__\":\n            from importlib.metadata import version\n\n            return version(\"textual\")\n        raise AttributeError(f\"module {__name__!r} has no attribute {name!r}\")\n\n\nclass LoggerError(Exception):\n    \"\"\"Raised when the logger failed.\"\"\"\n\n\n@rich.repr.auto\nclass Logger:\n    \"\"\"A [logger class](/guide/devtools/#logging-handler) that logs to the Textual [console](/guide/devtools#console).\"\"\"\n\n    def __init__(\n        self,\n        log_callable: LogCallable | None,\n        group: LogGroup = LogGroup.INFO,\n        verbosity: LogVerbosity = LogVerbosity.NORMAL,\n        app: _App | None = None,\n    ) -> None:\n        self._log = log_callable","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/Textualize/textual/blob/06dbeef4bb70fb718236aa418ed658ef4667a126/src/textual/__init__.py#L34-L70","documentation":"Textual defines a module-level __getattr__ in src/textual/__init__.py solely to lazily resolve __version__ from importlib.metadata. Any other attribute access on the textual module that isn't a real module attribute falls through to this hook and raises AttributeError. This is standard Python behavior for module-level __getattr__ (PEP 562).","triggerScenarios":"Accessing any attribute on the textual module that does not exist, e.g. `textual.something` where `something` is neither an import in __init__.py nor '__version__'. Also triggered by hasattr/getattr fallbacks, mock.patch('textual.foo'), or copy/pickle introspecting module attributes.","commonSituations":"Typos in attribute names (textual.app vs textual.Application), forgetting to import the submodule first (import textual; textual.app without `import textual.app` on some setups), or tooling that walks all module attributes (autocomplete, sphinx, pickle).","solutions":["Import the correct symbol explicitly: `from textual.app import App` instead of `textual.App`","Ensure the submodule is imported: `import textual.app` before using `textual.app`","Check spelling of the attribute against the textual API docs","If introspecting the module, guard with getattr(textual, name, None) or try/except AttributeError"],"exampleFix":"# before\nimport textual\napp = textual.App()  # AttributeError\n\n# after\nfrom textual.app import App\napp = App()","handlingStrategy":"type-guard","validationCode":"import textual\nname = 'foo'\nhas_it = name == '__version__' or hasattr(textual, name)","typeGuard":"def textual_has(name: str) -> bool:\n    import textual\n    return name == '__version__' or hasattr(textual, name)","tryCatchPattern":null,"preventionTips":["Always import symbols explicitly (from textual.app import App) instead of attribute access on the package","Run a linter/IDE that flags unresolved attributes","Guard dynamic access with getattr(textual, name, None)"],"tags":["python","attribute-access","lazy-import","module-getattr"],"backgroundTag":"attribute-error-missing-attribute","analyzedSha":"06dbeef4bb70fb718236aa418ed658ef4667a126","analyzedAt":"2026-08-27T02:36:57.214Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}