backend.ai-plugin 24.3.9b1__py3-none-any.whl → 25.15.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of backend.ai-plugin might be problematic. Click here for more details.
- ai/backend/plugin/VERSION +1 -1
- ai/backend/plugin/cli.py +152 -0
- ai/backend/plugin/entrypoint.py +114 -22
- {backend.ai_plugin-24.3.9b1.dist-info → backend_ai_plugin-25.15.5.dist-info}/METADATA +22 -5
- backend_ai_plugin-25.15.5.dist-info/RECORD +11 -0
- {backend.ai_plugin-24.3.9b1.dist-info → backend_ai_plugin-25.15.5.dist-info}/WHEEL +1 -1
- backend_ai_plugin-25.15.5.dist-info/entry_points.txt +2 -0
- backend.ai_plugin-24.3.9b1.dist-info/RECORD +0 -9
- {backend.ai_plugin-24.3.9b1.dist-info → backend_ai_plugin-25.15.5.dist-info}/namespace_packages.txt +0 -0
- {backend.ai_plugin-24.3.9b1.dist-info → backend_ai_plugin-25.15.5.dist-info}/top_level.txt +0 -0
ai/backend/plugin/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
25.15.5
|
ai/backend/plugin/cli.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import enum
|
|
4
|
+
import itertools
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
from collections import defaultdict
|
|
8
|
+
from typing import Self
|
|
9
|
+
|
|
10
|
+
import click
|
|
11
|
+
import colorama
|
|
12
|
+
import tabulate
|
|
13
|
+
from colorama import Fore, Style
|
|
14
|
+
|
|
15
|
+
from ai.backend.logging import AbstractLogger, LocalLogger, LogLevel
|
|
16
|
+
|
|
17
|
+
from .entrypoint import (
|
|
18
|
+
prepare_wheelhouse,
|
|
19
|
+
scan_entrypoint_from_buildscript,
|
|
20
|
+
scan_entrypoint_from_package_metadata,
|
|
21
|
+
scan_entrypoint_from_plugin_checkouts,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
log = logging.getLogger(__spec__.name)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class FormatOptions(enum.StrEnum):
|
|
28
|
+
CONSOLE = "console"
|
|
29
|
+
JSON = "json"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class CLIContext:
|
|
33
|
+
_logger: AbstractLogger
|
|
34
|
+
|
|
35
|
+
def __init__(self, log_level: LogLevel) -> None:
|
|
36
|
+
self.log_level = log_level
|
|
37
|
+
|
|
38
|
+
def __enter__(self) -> Self:
|
|
39
|
+
self._logger = LocalLogger(log_level=self.log_level)
|
|
40
|
+
self._logger.__enter__()
|
|
41
|
+
return self
|
|
42
|
+
|
|
43
|
+
def __exit__(self, *exc_info) -> None:
|
|
44
|
+
self._logger.__exit__()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@click.group()
|
|
48
|
+
@click.option(
|
|
49
|
+
"--debug",
|
|
50
|
+
is_flag=True,
|
|
51
|
+
help="Set the logging level to DEBUG",
|
|
52
|
+
)
|
|
53
|
+
@click.pass_context
|
|
54
|
+
def main(
|
|
55
|
+
ctx: click.Context,
|
|
56
|
+
debug: bool,
|
|
57
|
+
) -> None:
|
|
58
|
+
"""The root entrypoint for unified CLI of the plugin subsystem"""
|
|
59
|
+
log_level = LogLevel.DEBUG if debug else LogLevel.NOTSET
|
|
60
|
+
ctx.obj = ctx.with_resource(CLIContext(log_level))
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@main.command()
|
|
64
|
+
@click.argument("group_name")
|
|
65
|
+
@click.option(
|
|
66
|
+
"--format",
|
|
67
|
+
type=click.Choice([*FormatOptions]),
|
|
68
|
+
default=FormatOptions.CONSOLE,
|
|
69
|
+
show_default=True,
|
|
70
|
+
help="Set the output format.",
|
|
71
|
+
)
|
|
72
|
+
def scan(
|
|
73
|
+
group_name: str,
|
|
74
|
+
format: FormatOptions,
|
|
75
|
+
) -> None:
|
|
76
|
+
sources: dict[str, set[str]] = defaultdict(set)
|
|
77
|
+
rows = []
|
|
78
|
+
|
|
79
|
+
prepare_wheelhouse()
|
|
80
|
+
for source, entrypoint in itertools.chain(
|
|
81
|
+
(("buildscript", item) for item in scan_entrypoint_from_buildscript(group_name)),
|
|
82
|
+
(("plugin-checkout", item) for item in scan_entrypoint_from_plugin_checkouts(group_name)),
|
|
83
|
+
(("python-package", item) for item in scan_entrypoint_from_package_metadata(group_name)),
|
|
84
|
+
):
|
|
85
|
+
sources[entrypoint.name].add(source)
|
|
86
|
+
rows.append((source, entrypoint.name, entrypoint.module))
|
|
87
|
+
rows.sort(key=lambda row: (row[2], row[1], row[0]))
|
|
88
|
+
|
|
89
|
+
match format:
|
|
90
|
+
case FormatOptions.CONSOLE:
|
|
91
|
+
if not rows:
|
|
92
|
+
print(f"No plugins found for the entrypoint {group_name!r}")
|
|
93
|
+
return
|
|
94
|
+
colorama.init(autoreset=True)
|
|
95
|
+
ITALIC = colorama.ansi.code_to_chars(3)
|
|
96
|
+
STRIKETHR = colorama.ansi.code_to_chars(9)
|
|
97
|
+
src_style = {
|
|
98
|
+
"buildscript": Fore.LIGHTYELLOW_EX,
|
|
99
|
+
"plugin-checkout": Fore.LIGHTGREEN_EX,
|
|
100
|
+
"python-package": Fore.LIGHTBLUE_EX,
|
|
101
|
+
}
|
|
102
|
+
display_headers = (
|
|
103
|
+
f"{ITALIC}Source{Style.RESET_ALL}",
|
|
104
|
+
f"{ITALIC}Name{Style.RESET_ALL}",
|
|
105
|
+
f"{ITALIC}Module Path{Style.RESET_ALL}",
|
|
106
|
+
f"{ITALIC}Note{Style.RESET_ALL}",
|
|
107
|
+
)
|
|
108
|
+
display_rows = []
|
|
109
|
+
duplicates = set()
|
|
110
|
+
warnings: dict[str, str] = dict()
|
|
111
|
+
for source, name, module_path in rows:
|
|
112
|
+
note = ""
|
|
113
|
+
name_style = Style.BRIGHT
|
|
114
|
+
has_plugin_checkout = "plugin-checkout" in sources[name]
|
|
115
|
+
duplication_threshold = 2 if has_plugin_checkout else 1
|
|
116
|
+
if len(sources[name]) > duplication_threshold:
|
|
117
|
+
duplicates.add(name)
|
|
118
|
+
name_style = Fore.RED + Style.BRIGHT
|
|
119
|
+
if source == "plugin-checkout":
|
|
120
|
+
name_style = Style.DIM + STRIKETHR
|
|
121
|
+
if "python-package" in sources[name]:
|
|
122
|
+
note = "Loaded via the python-package source"
|
|
123
|
+
else:
|
|
124
|
+
note = "Ignored when loading plugins unless installed as editable"
|
|
125
|
+
display_rows.append((
|
|
126
|
+
f"{src_style[source]}{source}{Style.RESET_ALL}",
|
|
127
|
+
f"{name_style}{name}{Style.RESET_ALL}",
|
|
128
|
+
module_path,
|
|
129
|
+
note,
|
|
130
|
+
))
|
|
131
|
+
print(tabulate.tabulate(display_rows, display_headers))
|
|
132
|
+
for name, msg in warnings.items():
|
|
133
|
+
print(msg)
|
|
134
|
+
if duplicates:
|
|
135
|
+
duplicate_list = ", ".join(duplicates)
|
|
136
|
+
print(
|
|
137
|
+
f"\n{Fore.LIGHTRED_EX}\u26a0 Detected duplicated entrypoint(s): {Style.BRIGHT}{duplicate_list}{Style.RESET_ALL}"
|
|
138
|
+
)
|
|
139
|
+
if "accelerator" in group_name:
|
|
140
|
+
print(
|
|
141
|
+
f"{Fore.LIGHTRED_EX} You should check [agent].allow-compute-plugins in "
|
|
142
|
+
f"agent.toml to activate only one accelerator implementation for each name.{Style.RESET_ALL}"
|
|
143
|
+
)
|
|
144
|
+
case FormatOptions.JSON:
|
|
145
|
+
output_rows = []
|
|
146
|
+
for source, name, module_path in rows:
|
|
147
|
+
output_rows.append({
|
|
148
|
+
"source": source,
|
|
149
|
+
"name": name,
|
|
150
|
+
"module_path": module_path,
|
|
151
|
+
})
|
|
152
|
+
print(json.dumps(output_rows, indent=2))
|
ai/backend/plugin/entrypoint.py
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import ast
|
|
2
4
|
import collections
|
|
3
5
|
import configparser
|
|
4
6
|
import itertools
|
|
5
7
|
import logging
|
|
6
8
|
import os
|
|
9
|
+
import sys
|
|
10
|
+
import zipfile
|
|
7
11
|
from importlib.metadata import EntryPoint, entry_points
|
|
8
12
|
from pathlib import Path
|
|
9
13
|
from typing import Iterable, Iterator, Optional
|
|
@@ -19,9 +23,10 @@ def scan_entrypoints(
|
|
|
19
23
|
if blocklist is None:
|
|
20
24
|
blocklist = set()
|
|
21
25
|
existing_names: dict[str, EntryPoint] = {}
|
|
26
|
+
|
|
27
|
+
prepare_wheelhouse()
|
|
22
28
|
for entrypoint in itertools.chain(
|
|
23
29
|
scan_entrypoint_from_buildscript(group_name),
|
|
24
|
-
scan_entrypoint_from_plugin_checkouts(group_name),
|
|
25
30
|
scan_entrypoint_from_package_metadata(group_name),
|
|
26
31
|
):
|
|
27
32
|
if allowlist is not None and not match_plugin_list(entrypoint.value, allowlist):
|
|
@@ -62,6 +67,8 @@ def match_plugin_list(entry_path: str, plugin_list: set[str]) -> bool:
|
|
|
62
67
|
|
|
63
68
|
|
|
64
69
|
def scan_entrypoint_from_package_metadata(group_name: str) -> Iterator[EntryPoint]:
|
|
70
|
+
log.debug("scan_entrypoint_from_package_metadata(%r)", group_name)
|
|
71
|
+
|
|
65
72
|
yield from entry_points().select(group=group_name)
|
|
66
73
|
|
|
67
74
|
|
|
@@ -70,27 +77,82 @@ _default_glob_excluded_patterns = [
|
|
|
70
77
|
"ai/backend/web/static",
|
|
71
78
|
"ai/backend/runner",
|
|
72
79
|
"ai/backend/kernel",
|
|
80
|
+
"wheelhouse",
|
|
81
|
+
"tools",
|
|
73
82
|
]
|
|
74
83
|
|
|
84
|
+
_optimized_glob_search_patterns = {
|
|
85
|
+
# These patterns only apply to scanning BUILD files in dev setups and pex distributions.
|
|
86
|
+
# They do not affect standard package entrypoint searches.
|
|
87
|
+
# NOTE: most entrypoint declaration in BUILD files are in the package's top-level only!
|
|
88
|
+
"backendai_cli_v10": ["ai/backend/*", "ai/backend/appproxy/*"],
|
|
89
|
+
"backendai_network_manager_v1": ["ai/backend/*"],
|
|
90
|
+
"backendai_event_dispatcher_v20": ["ai/backend/*", "ai/backend/appproxy/*"],
|
|
91
|
+
"backendai_stats_monitor_v20": ["ai/backend/*", "ai/backend/appproxy/*"],
|
|
92
|
+
"backendai_error_monitor_v20": ["ai/backend/*", "ai/backend/appproxy/*"],
|
|
93
|
+
"backendai_hook_v20": ["ai/backend/*"],
|
|
94
|
+
"backendai_webapp_v20": ["ai/backend/*"],
|
|
95
|
+
"backendai_scheduler_v10": ["ai/backend/manager"],
|
|
96
|
+
"backendai_agentselector_v10": ["ai/backend/manager"],
|
|
97
|
+
}
|
|
75
98
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
99
|
+
|
|
100
|
+
def _glob(
|
|
101
|
+
base_path: Path,
|
|
102
|
+
filename: str,
|
|
103
|
+
excluded_patterns: Iterable[str],
|
|
104
|
+
match_patterns: Iterable[str] | None = None,
|
|
105
|
+
) -> Iterator[Path]:
|
|
106
|
+
q: collections.deque[tuple[Path, bool]] = collections.deque()
|
|
107
|
+
assert base_path.is_dir()
|
|
108
|
+
q.append((base_path, False))
|
|
79
109
|
while q:
|
|
80
|
-
search_path = q.pop()
|
|
81
|
-
|
|
110
|
+
search_path, suffix_match = q.pop()
|
|
111
|
+
|
|
112
|
+
# Check if current directory matches any pattern and we should yield files from it
|
|
113
|
+
current_matches = False
|
|
114
|
+
if match_patterns is not None:
|
|
115
|
+
current_matches = any(search_path.match(pattern) for pattern in match_patterns)
|
|
116
|
+
|
|
82
117
|
for item in search_path.iterdir():
|
|
83
118
|
if item.is_dir():
|
|
84
|
-
if
|
|
119
|
+
if item.name == "__pycache__":
|
|
85
120
|
continue
|
|
86
|
-
if
|
|
121
|
+
if item.name.startswith("."):
|
|
87
122
|
continue
|
|
88
|
-
if any(
|
|
123
|
+
if any(item.match(pattern) for pattern in excluded_patterns):
|
|
89
124
|
continue
|
|
90
|
-
|
|
125
|
+
|
|
126
|
+
# Determine if we should queue this directory
|
|
127
|
+
should_queue = False
|
|
128
|
+
new_suffix_match = False
|
|
129
|
+
|
|
130
|
+
if match_patterns is None:
|
|
131
|
+
# No patterns specified - queue all non-excluded directories
|
|
132
|
+
should_queue = True
|
|
133
|
+
new_suffix_match = False
|
|
134
|
+
elif not suffix_match:
|
|
135
|
+
# Haven't found a matching directory yet - check if this one matches
|
|
136
|
+
if any(item.match(pattern) for pattern in match_patterns):
|
|
137
|
+
should_queue = True
|
|
138
|
+
new_suffix_match = True
|
|
139
|
+
else:
|
|
140
|
+
# Keep searching - queue without suffix match
|
|
141
|
+
should_queue = True
|
|
142
|
+
new_suffix_match = False
|
|
143
|
+
else:
|
|
144
|
+
# Already found a matching directory - only queue if this also matches
|
|
145
|
+
if any(item.match(pattern) for pattern in match_patterns):
|
|
146
|
+
should_queue = True
|
|
147
|
+
new_suffix_match = True
|
|
148
|
+
|
|
149
|
+
if should_queue:
|
|
150
|
+
q.append((item, new_suffix_match))
|
|
91
151
|
else:
|
|
92
152
|
if item.name == filename:
|
|
93
|
-
|
|
153
|
+
# Yield file if no patterns or current directory matches
|
|
154
|
+
if match_patterns is None or current_matches:
|
|
155
|
+
yield item
|
|
94
156
|
|
|
95
157
|
|
|
96
158
|
def scan_entrypoint_from_buildscript(group_name: str) -> Iterator[EntryPoint]:
|
|
@@ -100,20 +162,36 @@ def scan_entrypoint_from_buildscript(group_name: str) -> Iterator[EntryPoint]:
|
|
|
100
162
|
log.debug(
|
|
101
163
|
"scan_entrypoint_from_buildscript(%r): Namespace path: %s", group_name, ai_backend_ns_path
|
|
102
164
|
)
|
|
103
|
-
|
|
165
|
+
match_patterns = _optimized_glob_search_patterns.get(group_name, None)
|
|
166
|
+
# First, it is invoked in PEX or temporary test environment generated by Pantsbuild.
|
|
167
|
+
# In the test environment, BUILD files are NOT copied, so the plugin discovery will rely on the
|
|
168
|
+
# followed build-root search below.
|
|
169
|
+
for buildscript_path in _glob(
|
|
170
|
+
ai_backend_ns_path, "BUILD", _default_glob_excluded_patterns, match_patterns
|
|
171
|
+
):
|
|
104
172
|
for entrypoint in extract_entrypoints_from_buildscript(group_name, buildscript_path):
|
|
105
173
|
entrypoints[entrypoint.name] = entrypoint
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
174
|
+
if os.environ.get("SCIE", None) is None:
|
|
175
|
+
# Override with the entrypoints found in the current build-root directory.
|
|
176
|
+
try:
|
|
177
|
+
build_root = find_build_root()
|
|
178
|
+
except ValueError:
|
|
179
|
+
pass
|
|
180
|
+
else:
|
|
181
|
+
src_path = build_root / "src"
|
|
182
|
+
log.debug("scan_entrypoint_from_buildscript(%r): current src: %s", group_name, src_path)
|
|
183
|
+
for buildscript_path in _glob(
|
|
184
|
+
src_path, "BUILD", _default_glob_excluded_patterns, match_patterns
|
|
185
|
+
):
|
|
186
|
+
for entrypoint in extract_entrypoints_from_buildscript(
|
|
187
|
+
group_name, buildscript_path
|
|
188
|
+
):
|
|
189
|
+
entrypoints[entrypoint.name] = entrypoint
|
|
111
190
|
else:
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
entrypoints[entrypoint.name] = entrypoint
|
|
191
|
+
log.debug(
|
|
192
|
+
"scan_entrypoint_from_buildscript(%r): skipping 'src' when executed inside the SCIE environment",
|
|
193
|
+
group_name,
|
|
194
|
+
)
|
|
117
195
|
yield from entrypoints.values()
|
|
118
196
|
|
|
119
197
|
|
|
@@ -143,6 +221,20 @@ def scan_entrypoint_from_plugin_checkouts(group_name: str) -> Iterator[EntryPoin
|
|
|
143
221
|
yield from entrypoints.values()
|
|
144
222
|
|
|
145
223
|
|
|
224
|
+
def prepare_wheelhouse(base_dir: Path | None = None) -> None:
|
|
225
|
+
if base_dir is None:
|
|
226
|
+
base_dir = Path.cwd()
|
|
227
|
+
for whl_path in (base_dir / "wheelhouse").glob("*.whl"):
|
|
228
|
+
extracted_path = whl_path.with_suffix("") # strip the extension
|
|
229
|
+
log.debug("prepare_wheelhouse(): loading %s", whl_path)
|
|
230
|
+
if not extracted_path.exists():
|
|
231
|
+
with zipfile.ZipFile(whl_path, "r") as z:
|
|
232
|
+
z.extractall(extracted_path)
|
|
233
|
+
decoded_path = os.fsdecode(extracted_path)
|
|
234
|
+
if decoded_path not in sys.path:
|
|
235
|
+
sys.path.append(decoded_path)
|
|
236
|
+
|
|
237
|
+
|
|
146
238
|
def find_build_root(path: Optional[Path] = None) -> Path:
|
|
147
239
|
if env_build_root := os.environ.get("BACKEND_BUILD_ROOT", None):
|
|
148
240
|
return Path(env_build_root)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: backend.ai-plugin
|
|
3
|
-
Version:
|
|
3
|
+
Version: 25.15.5
|
|
4
4
|
Summary: Backend.AI Plugin Subsystem
|
|
5
5
|
Home-page: https://github.com/lablup/backend.ai
|
|
6
6
|
Author: Lablup Inc. and contributors
|
|
@@ -15,11 +15,28 @@ Classifier: Programming Language :: Python :: 3
|
|
|
15
15
|
Classifier: Environment :: No Input/Output (Daemon)
|
|
16
16
|
Classifier: Topic :: Scientific/Engineering
|
|
17
17
|
Classifier: Topic :: Software Development
|
|
18
|
-
Classifier: Development Status ::
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.
|
|
18
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
20
|
Classifier: License :: OSI Approved :: MIT License
|
|
21
|
-
Requires-Python: >=3.
|
|
21
|
+
Requires-Python: >=3.13,<3.14
|
|
22
22
|
Description-Content-Type: text/markdown
|
|
23
|
+
Requires-Dist: backend.ai-common==25.15.5
|
|
24
|
+
Requires-Dist: backend.ai-logging==25.15.5
|
|
25
|
+
Requires-Dist: click~=8.1.7
|
|
26
|
+
Requires-Dist: colorama>=0.4.6
|
|
27
|
+
Requires-Dist: tabulate~=0.8.9
|
|
28
|
+
Requires-Dist: types-colorama
|
|
29
|
+
Requires-Dist: types-tabulate
|
|
30
|
+
Dynamic: author
|
|
31
|
+
Dynamic: classifier
|
|
32
|
+
Dynamic: description
|
|
33
|
+
Dynamic: description-content-type
|
|
34
|
+
Dynamic: home-page
|
|
35
|
+
Dynamic: license
|
|
36
|
+
Dynamic: project-url
|
|
37
|
+
Dynamic: requires-dist
|
|
38
|
+
Dynamic: requires-python
|
|
39
|
+
Dynamic: summary
|
|
23
40
|
|
|
24
41
|
Backend.AI Plugin Subsystem
|
|
25
42
|
===========================
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
ai/backend/plugin/VERSION,sha256=Q0grptxKHmGs0zbrjO9Pd6vBscOXL2Wus3WF9nw9xXI,8
|
|
2
|
+
ai/backend/plugin/__init__.py,sha256=HKBIEWtrpEk2KY3fB3Xb72N0xz5zoYUyn2HfZ75bTsc,96
|
|
3
|
+
ai/backend/plugin/cli.py,sha256=7SLUJy-8uPd_tSBOEZPYw1566QwrJJmCngoVyqrPAWE,5182
|
|
4
|
+
ai/backend/plugin/entrypoint.py,sha256=lFqz-QNcWfYBlFoDTGEU5sY0CgYD0NWEHhhtmXs4840,12083
|
|
5
|
+
ai/backend/plugin/py.typed,sha256=L3M0nPxGMCVTGcbI38G0aomWrOnRTY4HVjsWWRWRjsI,12
|
|
6
|
+
backend_ai_plugin-25.15.5.dist-info/METADATA,sha256=T3J6Ia6qIrr4bjQi-S2ZFUq6sxQXAG5nBcFL35uSROs,1528
|
|
7
|
+
backend_ai_plugin-25.15.5.dist-info/WHEEL,sha256=ooBFpIzZCPdw3uqIQsOo4qqbA4ZRPxHnOH7peeONza0,91
|
|
8
|
+
backend_ai_plugin-25.15.5.dist-info/entry_points.txt,sha256=XxdR8AJRnWYCT-BgkqvFySRw_WjL0r9M43fRAVszaqY,56
|
|
9
|
+
backend_ai_plugin-25.15.5.dist-info/namespace_packages.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
10
|
+
backend_ai_plugin-25.15.5.dist-info/top_level.txt,sha256=TJAp5TUfTUztZSUatbygths7CWRrFfnOMCtZ-DIcw6c,3
|
|
11
|
+
backend_ai_plugin-25.15.5.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
ai/backend/plugin/VERSION,sha256=nbYJZmVl6PFYyLMBzO0xWpgVCdtDsJkASxzXmRELNaM,10
|
|
2
|
-
ai/backend/plugin/__init__.py,sha256=HKBIEWtrpEk2KY3fB3Xb72N0xz5zoYUyn2HfZ75bTsc,96
|
|
3
|
-
ai/backend/plugin/entrypoint.py,sha256=7VU_dl8QnrR7n2kTRsmdy0VCIqwtrUcrTMti2hWM6xk,8172
|
|
4
|
-
ai/backend/plugin/py.typed,sha256=L3M0nPxGMCVTGcbI38G0aomWrOnRTY4HVjsWWRWRjsI,12
|
|
5
|
-
backend.ai_plugin-24.3.9b1.dist-info/METADATA,sha256=ZvGGReukg1pHCSdFxLbDdbQHyhqA1N_vsRf4ruyhj-8,1068
|
|
6
|
-
backend.ai_plugin-24.3.9b1.dist-info/WHEEL,sha256=Z4pYXqR_rTB7OWNDYFOm1qRk0RX6GFP2o8LgvP453Hk,91
|
|
7
|
-
backend.ai_plugin-24.3.9b1.dist-info/namespace_packages.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
8
|
-
backend.ai_plugin-24.3.9b1.dist-info/top_level.txt,sha256=TJAp5TUfTUztZSUatbygths7CWRrFfnOMCtZ-DIcw6c,3
|
|
9
|
-
backend.ai_plugin-24.3.9b1.dist-info/RECORD,,
|
{backend.ai_plugin-24.3.9b1.dist-info → backend_ai_plugin-25.15.5.dist-info}/namespace_packages.txt
RENAMED
|
File without changes
|
|
File without changes
|