{"record":{"id":"f07c0418603182ba","repo":"D4Vinci/Scrapling","slug":"module-name-r-has-no-attribute-name-r-f07c04","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":"scrapling/fetchers/__init__.py","lineNumber":43,"sourceCode":"    \"AsyncFetcher\",\n    \"ProxyRotator\",\n    \"FetcherSession\",\n    \"DynamicFetcher\",\n    \"DynamicSession\",\n    \"AsyncDynamicSession\",\n    \"StealthyFetcher\",\n    \"StealthySession\",\n    \"AsyncStealthySession\",\n]\n\n\ndef __getattr__(name: str) -> Any:\n    if name in _LAZY_IMPORTS:\n        module_path, class_name = _LAZY_IMPORTS[name]\n        module = __import__(module_path, fromlist=[class_name])\n        return getattr(module, class_name)\n    else:\n        raise AttributeError(f\"module {__name__!r} has no attribute {name!r}\")\n\n\ndef __dir__() -> list[str]:\n    \"\"\"Support for dir() and autocomplete.\"\"\"\n    return sorted(list(_LAZY_IMPORTS.keys()))\n","sourceCodeStart":25,"sourceCodeEnd":49,"githubUrl":"https://github.com/D4Vinci/Scrapling/blob/5d213a2d4764002bfc4fed33c32fe09fa8b0bf7f/scrapling/fetchers/__init__.py#L25-L49","documentation":"Standard AttributeError raised by the module-level `__getattr__` in scrapling/fetchers/__init__.py. This module lazily imports its fetcher classes; when you access an attribute that is not in the `_LAZY_IMPORTS` mapping (e.g. a misspelled class name or a name that moved), the fallback `__getattr__` raises with the exact module and attribute names. Note this is normal Python behavior for unknown attributes, not a corruption of the package.","triggerScenarios":"`from scrapling.fetchers import Fetcher` when the class is actually named something else (e.g. `Fetcher` vs the real exported names like StealthyFetcher/StealthySession), `scrapling.fetchers.AsyncFetcher` for a name not in _LAZY_IMPORTS, or accessing a name that was renamed across a version bump.","commonSituations":"Upgrading scrapling and using an old class name that was removed/renamed; IDE autocompleting a plausible-but-wrong name; tutorials targeting a different scrapling version; `dir()` shows only lazily exported names.","solutions":["Run `dir(scrapling.fetchers)` — the __dir__ hook lists exactly what is exported — and use one of those names.","Check the changelog/release notes if the name worked in a previous version; it may have been renamed.","Import the module directly and use getattr with a guarded default if you support multiple versions.","Verify you are not looking for a helper that lives elsewhere (e.g. scrapling.engines...) rather than in scrapling.fetchers."],"exampleFix":"# before\nfrom scrapling.fetchers import AsyncFetcher  # AttributeError\n\n# after\nimport scrapling.fetchers as sf\nprint(dir(sf))  # see valid names, e.g. StealthyFetcher, StealthySession, AsyncStealthySession\nfrom scrapling.fetchers import StealthyFetcher","handlingStrategy":"type-guard","validationCode":"import scrapling.fetchers as sf\n\nname = \"StealthyFetcher\"\nfetcher_cls = getattr(sf, name, None) or getattr(sf, \"DynamicFetcher\")  # explicit fallback\nif fetcher_cls is None:\n    raise ImportError(f\"scrapling.fetchers has no {name}; available: {dir(sf)}\")","typeGuard":"def fetcher_exists(name: str) -> bool:\n    import scrapling.fetchers as sf\n    return name in dir(sf)  # __dir__ lists lazily exported names","tryCatchPattern":"try:\n    from scrapling.fetchers import StealthyFetcher\nexcept AttributeError as e:\n    raise ImportError(f\"name moved/renamed in this scrapling version: {e}\") from e","preventionTips":["Call dir(scrapling.fetchers) to see the real export list.","Pin the scrapling version in requirements to avoid renames.","Check the changelog when upgrading before keeping old class names."],"tags":["import","lazy-loading","attribute-error","api-surface","versioning"],"backgroundTag":null,"analyzedSha":"5d213a2d4764002bfc4fed33c32fe09fa8b0bf7f","analyzedAt":"2026-08-14T22:23:09.440Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}