{"record":{"id":"3a03865034aaf946","repo":"D4Vinci/Scrapling","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":"scrapling/__init__.py","lineNumber":33,"sourceCode":"    \"Fetcher\": (\"scrapling.fetchers\", \"Fetcher\"),\n    \"Selector\": (\"scrapling.parser\", \"Selector\"),\n    \"Selectors\": (\"scrapling.parser\", \"Selectors\"),\n    \"AttributesHandler\": (\"scrapling.core.custom_types\", \"AttributesHandler\"),\n    \"TextHandler\": (\"scrapling.core.custom_types\", \"TextHandler\"),\n    \"AsyncFetcher\": (\"scrapling.fetchers\", \"AsyncFetcher\"),\n    \"StealthyFetcher\": (\"scrapling.fetchers\", \"StealthyFetcher\"),\n    \"DynamicFetcher\": (\"scrapling.fetchers\", \"DynamicFetcher\"),\n}\n__all__ = [\"Selector\", \"Fetcher\", \"AsyncFetcher\", \"StealthyFetcher\", \"DynamicFetcher\"]\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(__all__ + [\"fetchers\", \"parser\", \"cli\", \"core\", \"__author__\", \"__version__\", \"__copyright__\"])\n","sourceCodeStart":15,"sourceCodeEnd":39,"githubUrl":"https://github.com/D4Vinci/Scrapling/blob/5d213a2d4764002bfc4fed33c32fe09fa8b0bf7f/scrapling/__init__.py#L15-L39","documentation":"Scrapling uses a lazy-import __getattr__ in its package __init__: only names listed in the internal _LAZY_IMPORTS map (Selector, Fetcher, AsyncFetcher, StealthyFetcher, DynamicFetcher) are resolved on first access. Any other attribute access on the top-level `scrapling` module falls through to this AttributeError, because the submodules (fetchers, parser, cli, core) are not imported eagerly. This is by design to keep import time low.","triggerScenarios":"Accessing any attribute not in _LAZY_IMPORTS/__all__, e.g. `scrapling.Selectors`, `scrapling.session`, `scrapling.tools`, or a typo like `scrapling.StealthFetcher`. It also fires for names that exist only in submodules, e.g. `scrapling.Fetch` instead of `scrapling.fetchers.Fetch`.","commonSituations":"Autocomplete-driven guesses (IDE suggests submodule names), copy-pasting code from older/newer Scrapling versions where public names moved, or assuming a helper like `scrapling.Selectors` (the container class) is top-level when it lives in scrapling.parser.","solutions":["Check the valid top-level names with `dir(scrapling)` or __all__: Selector, Fetcher, AsyncFetcher, StealthyFetcher, DynamicFetcher","Import the name from its submodule, e.g. `from scrapling.parser import Selectors` or `from scrapling.fetchers import Fetcher`","Fix typos in the attribute name (e.g. StealthyFetcher, not StealthFetcher)","If code worked before, check the Scrapling changelog for renamed/moved public API and pin the version you tested against"],"exampleFix":"# before\nimport scrapling\nfetcher = scrapling.StealthFetcher()\n\n# after\nfrom scrapling import StealthyFetcher  # or scrapling.fetchers.StealthyFetcher\nfetcher = StealthyFetcher()","handlingStrategy":"validation","validationCode":"import scrapling\n\nname = 'StealthyFetcher'\nif not hasattr(scrapling, name):\n    raise SystemExit(f'{name} is not a public top-level API; see dir(scrapling)')","typeGuard":"from typing import Any\n\nPUBLIC = {\"Selector\", \"Fetcher\", \"AsyncFetcher\", \"StealthyFetcher\", \"DynamicFetcher\"}\n\ndef is_public_scrapling_attr(name: Any) -> bool:\n    return isinstance(name, str) and name in PUBLIC","tryCatchPattern":null,"preventionTips":["Import public names explicitly (from scrapling import X) so failures happen at import time with clear errors","Pin the scrapling version you developed against so API moves do not introduce unknown attributes","Use dir(scrapling) when scripting against the package dynamically"],"tags":["api-misuse","lazy-import","attributeerror"],"backgroundTag":null,"analyzedSha":"5d213a2d4764002bfc4fed33c32fe09fa8b0bf7f","analyzedAt":"2026-08-14T22:23:09.440Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}