Coverage for /opt/cloud/slavespace/usr1/096471637100f3de0fcfc01072822a80/dttest/api/python/ge/ge/_internal/artifact_utils.py: 87%
79 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-27 10:03 +0800
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-27 10:03 +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 artifact discovery helpers for GE Python modules."""
15from __future__ import annotations
17import importlib.util
18import json
19import platform
20import sys
21from dataclasses import dataclass
22from pathlib import Path
23from types import ModuleType
24from typing import Callable, Iterable, Optional
27@dataclass(frozen=True)
28class PythonArtifact:
29 root: Path
30 manifest_path: Path
31 python_tag: str
32 platform_tag: str
33 abi: int
34 native_path: Path
35 bridge_path: Optional[Path] = None
38def current_python_tag() -> str:
39 return f"cp{sys.version_info.major}{sys.version_info.minor}"
42def current_platform_tag() -> str:
43 return f"{platform.system().lower()}-{platform.machine() or 'unknown'}"
46def iter_manifest_paths(root: Path) -> Iterable[Path]:
47 if not root.exists():
48 return
49 root_manifest = root / "manifest.json"
50 if root_manifest.is_file():
51 yield root_manifest
52 for child in sorted(root.iterdir()):
53 manifest_path = child / "manifest.json"
54 if manifest_path.is_file():
55 yield manifest_path
58def load_manifest_json(manifest_path: Path) -> dict:
59 return json.loads(manifest_path.read_text(encoding="utf-8"))
62def _load_artifact_manifest(
63 manifest_path: Path, abi_key: str, require_bridge: bool
64) -> Optional[PythonArtifact]:
65 try:
66 manifest = load_manifest_json(manifest_path)
67 artifacts = manifest["artifacts"]
68 native_path = (manifest_path.parent / artifacts["native"]).resolve()
69 bridge_path = (
70 (manifest_path.parent / artifacts["bridge"]).resolve()
71 if require_bridge
72 else None
73 )
74 artifact = PythonArtifact(
75 root=manifest_path.parent.resolve(),
76 manifest_path=manifest_path.resolve(),
77 python_tag=manifest["python_tag"],
78 platform_tag=manifest["platform"],
79 abi=int(manifest[abi_key]),
80 native_path=native_path,
81 bridge_path=bridge_path,
82 )
83 except (KeyError, TypeError, ValueError, OSError):
84 return None
85 if not artifact.native_path.is_file():
86 return None
87 if require_bridge and (
88 artifact.bridge_path is None or not artifact.bridge_path.is_file()
89 ):
90 return None
91 return artifact
94def load_native_artifact_manifest(manifest_path: Path) -> Optional[PythonArtifact]:
95 return _load_artifact_manifest(manifest_path, "native_abi", False)
98def load_bridge_artifact_manifest(manifest_path: Path) -> Optional[PythonArtifact]:
99 return _load_artifact_manifest(manifest_path, "bridge_abi", True)
102def iter_artifacts(
103 root: Path, load_manifest: Callable[[Path], Optional[PythonArtifact]]
104) -> Iterable[PythonArtifact]:
105 for manifest_path in iter_manifest_paths(root):
106 artifact = load_manifest(manifest_path)
107 if artifact is not None:
108 yield artifact
111def find_compatible_artifact(
112 artifacts: Iterable[PythonArtifact], abi_version: int
113) -> Optional[PythonArtifact]:
114 python_tag = current_python_tag()
115 platform_tag = current_platform_tag()
116 for artifact in artifacts:
117 if (
118 artifact.python_tag == python_tag
119 and artifact.platform_tag == platform_tag
120 and artifact.abi == abi_version
121 ):
122 return artifact
123 return None
126def load_module_from_path(module_name: str, module_path: Path) -> ModuleType:
127 loaded_module = sys.modules.get(module_name)
128 if loaded_module is not None:
129 return loaded_module
130 spec = importlib.util.spec_from_file_location(module_name, module_path)
131 if spec is None or spec.loader is None:
132 raise ImportError(f"Cannot create import spec for {module_path}")
133 module = importlib.util.module_from_spec(spec)
134 sys.modules[module_name] = module
135 try:
136 spec.loader.exec_module(module)
137 except BaseException:
138 sys.modules.pop(module_name, None)
139 raise
140 return module