Coverage for /opt/cloud/slavespace/usr1/096471637100f3de0fcfc01072822a80/dttest/api/python/ge/ge/_internal/plugin_loader.py: 91%
79 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-18 20:50 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-18 20:50 +0800
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# -----------------------------------------------------------------------------------------------------------
4# Copyright (c) 2026 Huawei Technologies Co., Ltd.
5# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
6# CANN Open Software License Agreement Version 2.0 (the "License").
7# Please refer to the License for details. You may not use this file except in compliance with the License.
8# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
9# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
10# See LICENSE in the root of the software repository for the full text of the License.
11# -----------------------------------------------------------------------------------------------------------
13"""Shared Python plugin loading helpers."""
15from __future__ import annotations
17import importlib
18import importlib.util
19import os
20import sys
21from pathlib import Path
22from types import ModuleType
23from typing import Dict, Iterable, List, Optional
26_MODULE_NAME_BY_CANONICAL_PATH: Dict[Path, str] = {}
29def normalize_path_list(path_value: str) -> List[str]:
30 if not path_value:
31 return []
32 return [item.strip() for item in path_value.split(os.pathsep) if item.strip()]
35def _get_loaded_module(canonical_path: Path) -> Optional[ModuleType]:
36 module_name = _MODULE_NAME_BY_CANONICAL_PATH.get(canonical_path)
37 if module_name is None:
38 return None
39 module = sys.modules.get(module_name)
40 if module is None:
41 del _MODULE_NAME_BY_CANONICAL_PATH[canonical_path]
42 return module
45def load_module_from_file(
46 file_path: Path, *, module_prefix: str, plugin_kind: str
47) -> ModuleType:
48 file_path = file_path.resolve()
49 loaded_module = _get_loaded_module(file_path)
50 if loaded_module is not None:
51 return loaded_module
52 module_name = f"{module_prefix}{file_path.stem}_{abs(hash(str(file_path)))}"
53 if module_name in sys.modules:
54 return sys.modules[module_name]
55 spec = importlib.util.spec_from_file_location(module_name, file_path)
56 if spec is None or spec.loader is None:
57 raise ImportError(f"cannot load {plugin_kind} file: {file_path}")
58 module = importlib.util.module_from_spec(spec)
59 sys.modules[module_name] = module
60 try:
61 spec.loader.exec_module(module)
62 except BaseException:
63 del sys.modules[module_name]
64 raise
65 _MODULE_NAME_BY_CANONICAL_PATH[file_path] = module_name
66 return module
69def scan_modules_from_path(
70 path_item: str, *, module_prefix: str, plugin_kind: str
71) -> List[ModuleType]:
72 path = Path(path_item).resolve()
73 if not path.exists():
74 raise FileNotFoundError(f"{plugin_kind} path does not exist: {path}")
75 if path.is_file():
76 if path.suffix != ".py":
77 raise ValueError(f"{plugin_kind} file must end with .py: {path}")
78 return [
79 load_module_from_file(
80 path, module_prefix=module_prefix, plugin_kind=plugin_kind
81 )
82 ]
84 modules: List[ModuleType] = []
85 if str(path) not in sys.path:
86 sys.path.insert(0, str(path))
87 for child in sorted(path.iterdir(), key=lambda item: item.name):
88 if child.name.startswith("_"):
89 continue
90 if child.is_file() and child.suffix == ".py":
91 modules.append(
92 load_module_from_file(
93 child, module_prefix=module_prefix, plugin_kind=plugin_kind
94 )
95 )
96 continue
97 if child.is_dir() and (child / "__init__.py").exists():
98 package_init = (child / "__init__.py").resolve()
99 module = _get_loaded_module(package_init)
100 if module is None:
101 module = importlib.import_module(child.name)
102 _MODULE_NAME_BY_CANONICAL_PATH[package_init] = module.__name__
103 modules.append(module)
104 return modules
107def load_plugins_from_env(
108 env_name: str, *, module_prefix: str, plugin_kind: str
109) -> List[ModuleType]:
110 loaded_modules: List[ModuleType] = []
111 seen_module_names = set()
113 def append_modules(modules: Iterable[ModuleType]) -> None:
114 for module in modules:
115 module_name = getattr(module, "__name__", "")
116 if module_name in seen_module_names:
117 continue
118 seen_module_names.add(module_name)
119 loaded_modules.append(module)
121 for path_item in normalize_path_list(os.getenv(env_name, "")):
122 append_modules(
123 scan_modules_from_path(
124 path_item, module_prefix=module_prefix, plugin_kind=plugin_kind
125 )
126 )
127 return loaded_modules