ap-client 0.5.3.dev2__tar.gz → 0.5.3.dev4__tar.gz
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.
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/PKG-INFO +1 -1
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/ossutil_commands.py +67 -16
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/ossutil_io.py +13 -13
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/pyproject.toml +1 -1
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/__init__.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/akpool_commands.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/api.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/cli.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/config.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/dataset_commands.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/dataset_register.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/exporter.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/fs_commands.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/instance_commands.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/irepo_sdk.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/managed_ak.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/manifest_view.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/profile_commands.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/repo_read_guard.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/share_api.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/split_publish.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/tbb.py +0 -0
- {ap_client-0.5.3.dev2 → ap_client-0.5.3.dev4}/ap_client/waiter.py +0 -0
|
@@ -8,7 +8,7 @@ from typing import Optional
|
|
|
8
8
|
|
|
9
9
|
import typer
|
|
10
10
|
|
|
11
|
-
from .ossutil_io import OssBinding, OssFiles, OssUsageError, safe_error
|
|
11
|
+
from .ossutil_io import OssBinding, OssFiles, OssUsageError, direction_for, safe_error
|
|
12
12
|
|
|
13
13
|
ossutil_app = typer.Typer(
|
|
14
14
|
help="OSS file operations within the server-configured storage prefix", no_args_is_help=True
|
|
@@ -42,16 +42,62 @@ def _format(value: Optional[str]) -> str:
|
|
|
42
42
|
return _normalize_output_format(value, keep_table=True)
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
def
|
|
45
|
+
def _tree(entries: list[dict], root: str) -> None:
|
|
46
|
+
from rich.console import Console
|
|
47
|
+
from rich.text import Text
|
|
48
|
+
from rich.tree import Tree
|
|
49
|
+
|
|
50
|
+
base = root.rstrip("/") + "/" if root else ""
|
|
51
|
+
if entries and not all(row["path"].startswith(base) for row in entries):
|
|
52
|
+
base = root.rsplit("/", 1)[0] + "/" if "/" in root else ""
|
|
53
|
+
tree = Tree(Text(base or "./", style="bold cyan"), guide_style="dim")
|
|
54
|
+
nodes: dict = {}
|
|
55
|
+
for row in entries:
|
|
56
|
+
relative = row["path"][len(base) :] if row["path"].startswith(base) else row["path"]
|
|
57
|
+
if not relative.rstrip("/"):
|
|
58
|
+
continue
|
|
59
|
+
parts = relative.rstrip("/").split("/")
|
|
60
|
+
children = nodes
|
|
61
|
+
for index, part in enumerate(parts):
|
|
62
|
+
directory = (
|
|
63
|
+
index < len(parts) - 1 or row["type"] == "directory" or row["path"].endswith("/")
|
|
64
|
+
)
|
|
65
|
+
key = (part, directory)
|
|
66
|
+
node = children.setdefault(key, {"children": {}})
|
|
67
|
+
if index == len(parts) - 1:
|
|
68
|
+
node["size"] = row.get("size")
|
|
69
|
+
children = node["children"]
|
|
70
|
+
|
|
71
|
+
def add(parent, children):
|
|
72
|
+
for (name, directory), node in sorted(
|
|
73
|
+
children.items(), key=lambda item: (not item[0][1], item[0][0].casefold(), item[0][0])
|
|
74
|
+
):
|
|
75
|
+
label = Text(name + ("/" if directory else ""), style="bold blue" if directory else "")
|
|
76
|
+
if not directory and node.get("size") is not None:
|
|
77
|
+
size = float(node["size"])
|
|
78
|
+
unit = "B"
|
|
79
|
+
for unit in ("B", "KiB", "MiB", "GiB", "TiB"):
|
|
80
|
+
if size < 1024 or unit == "TiB":
|
|
81
|
+
break
|
|
82
|
+
size /= 1024
|
|
83
|
+
label.append(f" {int(size) if unit == 'B' else f'{size:.1f}'} {unit}", style="dim")
|
|
84
|
+
add(parent.add(label), node["children"])
|
|
85
|
+
|
|
86
|
+
add(tree, nodes)
|
|
87
|
+
Console().print(tree)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _emit(value: dict, output_format: str, *, short: bool = False, root: str = "") -> None:
|
|
46
91
|
if output_format in ("json", "yaml"):
|
|
47
92
|
from .cli import _print_formatted
|
|
48
93
|
|
|
49
94
|
_print_formatted(value, output_format)
|
|
50
95
|
elif "entries" in value:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
row["path"]
|
|
54
|
-
|
|
96
|
+
if short:
|
|
97
|
+
for row in value["entries"]:
|
|
98
|
+
typer.echo(row["path"])
|
|
99
|
+
else:
|
|
100
|
+
_tree(value["entries"], root)
|
|
55
101
|
if value["is_truncated"]:
|
|
56
102
|
typer.echo(
|
|
57
103
|
"Listing truncated; continue with --marker " + value["next_marker"], err=True
|
|
@@ -88,6 +134,7 @@ def _fail(exc: Exception) -> None:
|
|
|
88
134
|
def oss_ls(
|
|
89
135
|
path: str = typer.Argument(..., help="Full oss:// URI or prefix relative to repo-config"),
|
|
90
136
|
directory: bool = typer.Option(False, "--directory", "-d", help="List only the current level"),
|
|
137
|
+
recursive: bool = typer.Option(False, "--recursive", "-r", help="Expand all directory levels"),
|
|
91
138
|
short: bool = typer.Option(False, "--short-format", "-s", help="Print only paths"),
|
|
92
139
|
limited_num: Optional[int] = typer.Option(None, "--limited-num", min=1),
|
|
93
140
|
marker: str = typer.Option("", "--marker", help="Resume after this OSS URI or relative path"),
|
|
@@ -97,15 +144,20 @@ def oss_ls(
|
|
|
97
144
|
payer: Optional[str] = typer.Option(None, "--payer"),
|
|
98
145
|
output_format: Optional[str] = typer.Option(None, "--output-format", "--format"),
|
|
99
146
|
):
|
|
100
|
-
"""
|
|
147
|
+
"""Show one directory level as a tree; use -r to expand all levels."""
|
|
101
148
|
try:
|
|
102
149
|
fmt = _format(output_format)
|
|
150
|
+
if recursive and directory:
|
|
151
|
+
raise OssUsageError("Use either --recursive or --directory")
|
|
103
152
|
files = _files()
|
|
104
153
|
_configure(files, encoding_type, payer)
|
|
154
|
+
remote = (
|
|
155
|
+
files.resolve(path, prefix=True) if recursive else files.resolve(path, directory=True)
|
|
156
|
+
)
|
|
105
157
|
_emit(
|
|
106
158
|
files.list(
|
|
107
|
-
|
|
108
|
-
recursive=
|
|
159
|
+
remote,
|
|
160
|
+
recursive=recursive,
|
|
109
161
|
limit=limited_num,
|
|
110
162
|
marker=marker,
|
|
111
163
|
include=tuple(include or ()),
|
|
@@ -113,6 +165,7 @@ def oss_ls(
|
|
|
113
165
|
),
|
|
114
166
|
fmt,
|
|
115
167
|
short=short,
|
|
168
|
+
root=remote.path,
|
|
116
169
|
)
|
|
117
170
|
except Exception as exc:
|
|
118
171
|
_fail(exc)
|
|
@@ -167,11 +220,8 @@ def oss_cat(
|
|
|
167
220
|
|
|
168
221
|
@ossutil_app.command("cp")
|
|
169
222
|
def oss_cp(
|
|
170
|
-
src: str = typer.Argument(..., help="Local path
|
|
171
|
-
dst: str = typer.Argument(..., help="Local path
|
|
172
|
-
direction: Optional[str] = typer.Option(
|
|
173
|
-
None, "--direction", help="AP extension for two relative paths: upload/download/copy"
|
|
174
|
-
),
|
|
223
|
+
src: str = typer.Argument(..., help="Local path or full oss:// URI"),
|
|
224
|
+
dst: str = typer.Argument(..., help="Local path or full oss:// URI"),
|
|
175
225
|
recursive: bool = typer.Option(False, "--recursive", "-r"),
|
|
176
226
|
force: bool = typer.Option(False, "--force", "-f", help="Overwrite without confirmation"),
|
|
177
227
|
update: bool = typer.Option(False, "--update", "-u", help="Copy only missing or older targets"),
|
|
@@ -198,7 +248,8 @@ def oss_cp(
|
|
|
198
248
|
payer: Optional[str] = typer.Option(None, "--payer"),
|
|
199
249
|
output_format: Optional[str] = typer.Option(None, "--output-format", "--format"),
|
|
200
250
|
):
|
|
201
|
-
"""Upload, download or copy objects.
|
|
251
|
+
"""Upload, download or copy objects. One operand must be a full oss:// URI.
|
|
252
|
+
Downloads require private-network access."""
|
|
202
253
|
lock = threading.Lock()
|
|
203
254
|
|
|
204
255
|
def progress(path, done, total):
|
|
@@ -227,6 +278,7 @@ def oss_cp(
|
|
|
227
278
|
fmt = _format(output_format)
|
|
228
279
|
if start_time is not None and end_time is not None and start_time > end_time:
|
|
229
280
|
raise OssUsageError("--start-time cannot be later than --end-time")
|
|
281
|
+
direction_for(src, dst)
|
|
230
282
|
files = _files()
|
|
231
283
|
_configure(files, encoding_type, payer)
|
|
232
284
|
files.disable_crc64 = disable_crc64
|
|
@@ -263,7 +315,6 @@ def oss_cp(
|
|
|
263
315
|
result = files.cp(
|
|
264
316
|
src,
|
|
265
317
|
dst,
|
|
266
|
-
direction=direction,
|
|
267
318
|
recursive=recursive,
|
|
268
319
|
overwrite=force,
|
|
269
320
|
jobs=jobs,
|
|
@@ -140,17 +140,18 @@ class RemotePath:
|
|
|
140
140
|
path: str
|
|
141
141
|
|
|
142
142
|
|
|
143
|
-
def direction_for(src: str, dst: str
|
|
143
|
+
def direction_for(src: str, dst: str) -> str:
|
|
144
|
+
"""Infer cp direction the way ossutil does: at least one operand is an OSS URI."""
|
|
144
145
|
remote_src, remote_dst = src.startswith("oss://"), dst.startswith("oss://")
|
|
145
|
-
if
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
146
|
+
if remote_src and remote_dst:
|
|
147
|
+
return "copy"
|
|
148
|
+
if remote_src:
|
|
149
|
+
return "download"
|
|
150
|
+
if remote_dst:
|
|
151
|
+
return "upload"
|
|
152
|
+
raise OssUsageError(
|
|
153
|
+
"cp requires at least one operand starting with oss://; paths without it are local"
|
|
154
|
+
)
|
|
154
155
|
|
|
155
156
|
|
|
156
157
|
def matches(path: str, include: tuple[str, ...], exclude: tuple[str, ...]) -> bool:
|
|
@@ -415,7 +416,7 @@ class OssFiles:
|
|
|
415
416
|
self,
|
|
416
417
|
remote: RemotePath,
|
|
417
418
|
*,
|
|
418
|
-
recursive: bool =
|
|
419
|
+
recursive: bool = False,
|
|
419
420
|
limit: int | None = None,
|
|
420
421
|
marker: str = "",
|
|
421
422
|
include: tuple[str, ...] = (),
|
|
@@ -796,7 +797,6 @@ class OssFiles:
|
|
|
796
797
|
src: str,
|
|
797
798
|
dst: str,
|
|
798
799
|
*,
|
|
799
|
-
direction: str | None,
|
|
800
800
|
recursive: bool,
|
|
801
801
|
overwrite: bool,
|
|
802
802
|
jobs: int,
|
|
@@ -811,7 +811,7 @@ class OssFiles:
|
|
|
811
811
|
start_time: int | None = None,
|
|
812
812
|
end_time: int | None = None,
|
|
813
813
|
) -> dict:
|
|
814
|
-
direction = direction_for(src, dst
|
|
814
|
+
direction = direction_for(src, dst)
|
|
815
815
|
remote_src = self.resolve(src, directory=recursive) if direction != "upload" else None
|
|
816
816
|
remote_dst = None
|
|
817
817
|
if direction != "download":
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ap-client"
|
|
7
|
-
version = "0.5.3.
|
|
7
|
+
version = "0.5.3.dev4"
|
|
8
8
|
description = "Agent Platform API Client & CLI"
|
|
9
9
|
readme = { text = "A lightweight Python SDK and command line interface for Agent Platform. It provides helpers for configuring API access and managing templates, datasets, jobs, and groups.", content-type = "text/markdown" }
|
|
10
10
|
requires-python = ">=3.10"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|