Files
myhloli d0cc0c4f3d refactor(sdk): resolve lazy exports without mutating module globals
__getattr__ 不再把解析出的符号写回 globals():运行时改模块命名空间
违反 AGENTS.md 确定性优先(禁 globals() 动态模式),且首次访问后模块
属性集发生静态不可见的变化。改为每次经 _LAZY_EXPORTS 显式映射解析,
import_module 命中 sys.modules 后开销可忽略,重复访问仍返回同一对象。

Refs #5528
2026-09-18 19:27:43 +08:00

72 lines
2.0 KiB
Python

# Copyright (c) Opendatalab. All rights reserved.
"""MinerU 公开入口:文档类型即时导入,解析 API 与 SDK 客户端惰性导出。
类型(Block/PageInfo/...)保持 `import mineru` 即可用且不触发依赖加载;
解析入口(parse/MinerUParser/...)与 SDK 客户端(DoclibClient)通过 PEP 562
的显式映射惰性提供,首次访问才导入对应子包(如 mineru.parser、mineru.doclib)。
"""
from typing import TYPE_CHECKING, Any as _Any
from .types import (
Block,
CodeInlineSpan,
EquationInlineSpan,
HyperlinkSpan,
InlineSpan,
MiddleJson,
ModelJson,
PageInfo,
TextSpan,
)
if TYPE_CHECKING:
from .doclib import DoclibClient
from .parser import DocumentParser, MinerUApiParser, MinerUParser, ParseResult, parse, parse_async
__all__ = [
"Block",
"CodeInlineSpan",
"DoclibClient",
"DocumentParser",
"EquationInlineSpan",
"HyperlinkSpan",
"InlineSpan",
"MiddleJson",
"MinerUApiParser",
"MinerUParser",
"ModelJson",
"PageInfo",
"ParseResult",
"TextSpan",
"parse",
"parse_async",
]
# PEP 562 惰性导出的显式映射:名字 -> mineru 包内子模块。静态可查,
# 新增导出时在此登记,不要在模块体顶部直接 import 以免引入重依赖。
_LAZY_EXPORTS: dict[str, str] = {
"DoclibClient": "doclib",
"DocumentParser": "parser",
"MinerUApiParser": "parser",
"MinerUParser": "parser",
"ParseResult": "parser",
"parse": "parser",
"parse_async": "parser",
}
def __getattr__(name: str) -> _Any:
module = _LAZY_EXPORTS.get(name)
if module is None:
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
import importlib
# 不写回 globals():运行时改模块命名空间违反确定性优先约定,
# 重复访问经 sys.modules 命中的 import_module 解析,开销可忽略。
return getattr(importlib.import_module(f".{module}", package=__name__), name)
def __dir__() -> list[str]:
return sorted({*globals(), *_LAZY_EXPORTS})