{"record":{"id":"23d3b9f2eef5b0d2","repo":"datawhalechina/hello-agents","slug":"module-name-class-name-or-e","errorCode":null,"errorMessage":"无法导入 {module_name}.{class_name or ''}: {e}","messagePattern":"无法导入 (.+?)\\.(.+?): (.+?)","errorType":"exception","errorClass":"ImportError","httpStatus":null,"severity":"error","filePath":"Co-creation-projects/YYHDBL-HelloCodeAgentCli/utils/helpers.py","lineNumber":56,"sourceCode":"\ndef safe_import(module_name: str, class_name: Optional[str] = None) -> Any:\n    \"\"\"\n    安全导入模块或类\n    \n    Args:\n        module_name: 模块名\n        class_name: 类名（可选）\n        \n    Returns:\n        导入的模块或类\n    \"\"\"\n    try:\n        module = importlib.import_module(module_name)\n        if class_name:\n            return getattr(module, class_name)\n        return module\n    except (ImportError, AttributeError) as e:\n        raise ImportError(f\"无法导入 {module_name}.{class_name or ''}: {e}\")\n\ndef ensure_dir(path: Path) -> Path:\n    \"\"\"确保目录存在\"\"\"\n    path.mkdir(parents=True, exist_ok=True)\n    return path\n\ndef get_project_root() -> Path:\n    \"\"\"获取项目根目录\"\"\"\n    return Path(__file__).parent.parent.parent\n\ndef merge_dicts(dict1: Dict, dict2: Dict) -> Dict:\n    \"\"\"深度合并两个字典\"\"\"\n    result = dict1.copy()\n    for key, value in dict2.items():\n        if key in result and isinstance(result[key], dict) and isinstance(value, dict):\n            result[key] = merge_dicts(result[key], value)\n        else:\n            result[key] = value","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/YYHDBL-HelloCodeAgentCli/utils/helpers.py#L38-L74","documentation":"ImportError from utils.helpers.safe_import when importlib.import_module raises ImportError (module missing/broken) or getattr raises AttributeError (class/function not exported) — both are re-raised as one uniform ImportError naming module and class. It exists so plugin-style dynamic loads produce consistent, greppable errors.","triggerScenarios":"safe_import('hello_agents.tools.web_search', 'WebSearchTool') when the module is not installed or the class name is misspelled; circular imports surfacing as ImportError; package restructure renaming the class so getattr fails.","commonSituations":"Plugin registries loading tools by string name from config; version upgrades that moved/renamed classes; optional extras not installed so their modules don't exist.","solutions":["Verify the module is installed/importable: python -c \"import <module>\".","Check the exact class name spelling and that it is exported at module level (not nested or private).","After a dependency upgrade, grep the package for the renamed symbol and update the string.","If the module is optional, catch the ImportError and degrade gracefully."],"exampleFix":"# before\ncls = safe_import('hello_agents.tools.search', 'WebSearch')  # AttributeError path\n\n# after\nimport hello_agents.tools.search as m\nprint([n for n in dir(m) if 'earch' in n])  # find real name, e.g. 'WebSearchTool'\ncls = safe_import('hello_agents.tools.search', 'WebSearchTool')","handlingStrategy":"try-catch","validationCode":"import importlib.util\n\ndef module_importable(name: str) -> bool:\n    return importlib.util.find_spec(name) is not None\n\nif not module_importable('hello_agents.tools.web_search'):\n    disable_plugin('web_search')","typeGuard":"def symbol_exists(module_name: str, class_name: str) -> bool:\n    try:\n        mod = importlib.import_module(module_name)\n    except ImportError:\n        return False\n    return hasattr(mod, class_name)","tryCatchPattern":"try:\n    cls = safe_import(module_name, class_name)\nexcept ImportError as e:\n    logger.warning('plugin %s unavailable: %s', module_name, e)\n    cls = None  # skip plugin, keep core running","preventionTips":["Treat plugin loads as optional: catch ImportError and skip gracefully.","Verify module and symbol names after dependency upgrades.","Cache find_spec checks at startup for configured plugins."],"tags":["import","plugin","dynamic-load","dependency"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}