Coverage for src / c41811 / config / lazy_import.py: 100%

32 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-02-06 06:04 +0000

1# cython: language_level = 3 # noqa: ERA001 

2 

3 

4""" 

5懒加载处理 

6 

7.. versionadded:: 0.3.0 

8""" 

9 

10import inspect 

11from importlib import import_module 

12from typing import TYPE_CHECKING 

13from typing import Any 

14 

15if TYPE_CHECKING: 

16 from collections.abc import Callable 

17else: 

18 from collections.abc import Callable 

19 

20 

21def lazy_import(properties: dict[str, str], /) -> tuple[list[str], Callable[[str], Any]]: 

22 """ 

23 为 `__init__` 文件生成 `__all__` 和 `__getattr__` 

24 

25 :param properties: 属性字典 ``dict[属性, 模块]`` 

26 :type properties: dict[str, str] 

27 

28 :return: 返回 ``tuple[__all__, __getattr__]`` 

29 :rtype: tuple[tuple[str, ...], Callable[[str], Any]] 

30 

31 .. versionadded:: 0.3.0 

32 """ 

33 if (caller_module := inspect.getmodule(inspect.stack()[1][0])) is None: # pragma: no cover 

34 msg = "Cannot find caller module" 

35 raise RuntimeError(msg) 

36 caller_package = caller_module.__name__ 

37 property_list = list(properties.keys()) 

38 

39 def attr_getter(name: str) -> Any: 

40 from .errors import DependencyNotFoundError # noqa: PLC0415 

41 from .errors import UnavailableAttribute # noqa: PLC0415 

42 

43 try: 

44 sub_pkg = properties[name] 

45 except KeyError: 

46 # noinspection PyShadowingNames 

47 msg = f"module '{caller_package}' has no attribute '{name}'" 

48 raise AttributeError(msg) from None 

49 try: 

50 module = import_module(sub_pkg, package=caller_package) 

51 except DependencyNotFoundError as err: 

52 property_list.remove(name) 

53 del properties[name] 

54 return UnavailableAttribute(name, err) 

55 attr = getattr(module, name) 

56 if isinstance(attr, UnavailableAttribute): 

57 property_list.remove(name) 

58 del properties[name] 

59 return attr 

60 

61 attr_getter.__name__ = "__getattr__" 

62 attr_getter.__qualname__ = f"{caller_package}.__getattr__" 

63 attr_getter.__module__ = caller_package 

64 

65 return property_list, attr_getter 

66 

67 

68__all__ = ("lazy_import",)