ap-client 0.6.0.dev1__tar.gz → 0.6.1.dev0__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.
Files changed (26) hide show
  1. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/PKG-INFO +5 -3
  2. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/api.py +5 -0
  3. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/cli.py +8 -0
  4. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/dataset_commands.py +46 -12
  5. ap_client-0.6.1.dev0/ap_client/dataset_name.py +53 -0
  6. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/dataset_register.py +20 -6
  7. ap_client-0.6.1.dev0/ap_client/dfs_commands.py +680 -0
  8. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/instance_commands.py +519 -52
  9. ap_client-0.6.1.dev0/ap_client/instance_options.py +94 -0
  10. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/irepo_sdk.py +69 -1
  11. ap_client-0.6.1.dev0/ap_client/ossutil_hash.py +329 -0
  12. ap_client-0.6.1.dev0/ap_client/ossutil_io.py +1168 -0
  13. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/repo_read_guard.py +6 -2
  14. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/split_publish.py +1 -1
  15. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/pyproject.toml +6 -3
  16. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/__init__.py +0 -0
  17. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/akpool_commands.py +0 -0
  18. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/config.py +0 -0
  19. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/exporter.py +0 -0
  20. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/fs_commands.py +0 -0
  21. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/managed_ak.py +0 -0
  22. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/manifest_view.py +0 -0
  23. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/profile_commands.py +0 -0
  24. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/share_api.py +0 -0
  25. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/tbb.py +0 -0
  26. {ap_client-0.6.0.dev1 → ap_client-0.6.1.dev0}/ap_client/waiter.py +0 -0
@@ -1,18 +1,20 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ap-client
3
- Version: 0.6.0.dev1
3
+ Version: 0.6.1.dev0
4
4
  Summary: Agent Platform API Client & CLI
5
5
  Requires-Python: >=3.10
6
+ Requires-Dist: click>=8.0.0
6
7
  Requires-Dist: irepo-artifact==0.2.1
7
8
  Requires-Dist: pyyaml>=6.0
8
9
  Requires-Dist: requests>=2.28.0
9
10
  Requires-Dist: rich>=13.0.0
10
11
  Requires-Dist: typer>=0.9.0
12
+ Requires-Dist: urllib3>=1.26
11
13
  Requires-Dist: websockets>=13.0
12
14
  Provides-Extra: all
13
- Requires-Dist: instance-repo[oss]<2.0.0,>=1.3.2; extra == 'all'
15
+ Requires-Dist: instance-repo[oss]<2.0.0,>=1.4.0.dev3; extra == 'all'
14
16
  Provides-Extra: dataset
15
- Requires-Dist: instance-repo[oss]<2.0.0,>=1.3.2; extra == 'dataset'
17
+ Requires-Dist: instance-repo[oss]<2.0.0,>=1.4.0.dev3; extra == 'dataset'
16
18
  Description-Content-Type: text/markdown
17
19
 
18
20
  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.
@@ -1881,9 +1881,12 @@ class APIClient:
1881
1881
  meta_job_type: Optional[str] = None,
1882
1882
  meta_teacher_direction: Optional[str] = None,
1883
1883
  meta_train_stage: Optional[str] = None,
1884
+ benchmark: Optional[str] = None,
1884
1885
  ) -> dict:
1885
1886
  """Update group properties.
1886
1887
 
1888
+ ``benchmark`` is omitted when None; pass an empty string to clear it.
1889
+
1887
1890
  ``tags``(`key:value` 数组)在客户端先与 Group 现有 tags 合并,再以
1888
1891
  全量替换语义提交(服务端 PATCH 是整体替换);同名 key 覆盖,未提及
1889
1892
  的 key 保留。服务端会从 tags 同步 meta_* 等派生字段。
@@ -1906,6 +1909,8 @@ class APIClient:
1906
1909
  body["model"] = model
1907
1910
  if scaffold is not None:
1908
1911
  body["scaffold"] = scaffold
1912
+ if benchmark is not None:
1913
+ body["benchmark"] = benchmark
1909
1914
  meta_attr_tags = _merge_meta_tags(
1910
1915
  None,
1911
1916
  meta_model=meta_model,
@@ -25,6 +25,7 @@ from ap_client.api import (
25
25
  )
26
26
  from ap_client.config import ENV_VAR_SPECS, ConfigurationError, _parse_bool, normalize_output_format
27
27
  from ap_client.dataset_commands import register as _register_dataset_commands
28
+ from ap_client.dfs_commands import register as _register_dfs_commands
28
29
  from ap_client.exporter import export_group, export_job, export_jobs
29
30
  from ap_client.fs_commands import register as _register_fs_commands
30
31
  from ap_client.instance_commands import register as _register_instance_commands
@@ -167,6 +168,7 @@ app.add_typer(checkpoint_app, name="checkpoint")
167
168
  # ap dataset version/split/access 嵌套在 dataset 下;instance/fs 是一等资源。
168
169
  _register_dataset_commands(dataset_app)
169
170
  _register_instance_commands(app)
171
+ _register_dfs_commands(app)
170
172
  _register_fs_commands(app)
171
173
  _register_akpool_commands(app)
172
174
 
@@ -6066,6 +6068,9 @@ def group_update(
6066
6068
  scaffold: Optional[str] = typer.Option(
6067
6069
  None, "--scaffold", "-s", help="Scaffold/agent name (benchmark perspective)"
6068
6070
  ),
6071
+ benchmark: Optional[str] = typer.Option(
6072
+ None, "--benchmark", help="Benchmark name; pass an empty string to clear"
6073
+ ),
6069
6074
  tags: Optional[str] = typer.Option(
6070
6075
  None,
6071
6076
  "--tags",
@@ -6127,6 +6132,7 @@ def group_update(
6127
6132
  dataset,
6128
6133
  model_name,
6129
6134
  scaffold,
6135
+ benchmark,
6130
6136
  tags_list,
6131
6137
  )
6132
6138
  ):
@@ -6141,6 +6147,7 @@ def group_update(
6141
6147
  dataset=dataset,
6142
6148
  model=model_name,
6143
6149
  scaffold=scaffold,
6150
+ **({"benchmark": benchmark} if benchmark is not None else {}),
6144
6151
  **({"tags": tags_list} if tags_list is not None else {}),
6145
6152
  )
6146
6153
  if output_format == "plain":
@@ -6155,6 +6162,7 @@ def group_update(
6155
6162
  "dataset",
6156
6163
  "model",
6157
6164
  "scaffold",
6165
+ "benchmark",
6158
6166
  "updated_at",
6159
6167
  ],
6160
6168
  )
@@ -123,7 +123,10 @@ _NO_BENCHMARK = "none"
123
123
  _FORMAT_HELP = "Output format: plain/table/json/yaml (default: AP_FORMAT or command default)"
124
124
 
125
125
  _METADATA_MODELS = ("version_first", "split_first")
126
- _VERSION_SPLIT_METADATA_MODEL = "version_first"
126
+ # IR SDK >= 1.4.0.dev3 的业务入口固定 split_first:business_metadata_model 拒绝
127
+ # version_first(仅保留给低层 legacy 读)。带 version 的 split 查询在两种模型下
128
+ # 结果一致(实测),显式 split_first 与 SDK 归一值一致且新旧 SDK 均接受。
129
+ _VERSION_SPLIT_METADATA_MODEL = "split_first"
127
130
 
128
131
  #: CLI **不替 SDK 决定元数据模型**:不下发 ``metadata_model``,由 SDK 按 profile 归一
129
132
  #: (当前为 ``split_first``)。
@@ -1186,9 +1189,26 @@ def dataset_get(
1186
1189
  "dataset_name": dataset,
1187
1190
  "registered": False,
1188
1191
  }
1189
- parts = dataset.split("/")
1190
- if len(parts) == 2 and all(parts):
1191
- rendered.update(dataset_l1=parts[0], dataset_l2=parts[1])
1192
+ from .dataset_name import (
1193
+ DatasetNameError,
1194
+ DatasetNameUpgradeRequired,
1195
+ parse_dataset_name,
1196
+ )
1197
+
1198
+ try:
1199
+ name = parse_dataset_name(dataset)
1200
+ except DatasetNameUpgradeRequired as exc:
1201
+ raise _fail(
1202
+ f"Failed to query dataset {dataset}: {exc}",
1203
+ "pip install 'ap-client[dataset]' --upgrade",
1204
+ exit_code=2,
1205
+ ) from exc
1206
+ except DatasetNameError:
1207
+ # 非规范名:不凭空发明 level 字段(与历史行为一致)。
1208
+ pass
1209
+ else:
1210
+ rendered["dataset_l1"] = name.l1
1211
+ rendered["dataset_l2"] = name.l2
1192
1212
  else:
1193
1213
  rendered = _registered_dict(detail)
1194
1214
  _emit_detail(rendered, output_format, order=_DATASET_DETAIL_ORDER, always=("status",))
@@ -1197,7 +1217,9 @@ def dataset_get(
1197
1217
 
1198
1218
 
1199
1219
  def dataset_create(
1200
- dataset: str = typer.Argument(..., help="Dataset name (e.g. alibaba/my-bench)"),
1220
+ dataset: str = typer.Argument(
1221
+ ..., help="Dataset name: L1 or L1/L2 (e.g. my-bench or alibaba/my-bench)"
1222
+ ),
1201
1223
  benchmark: str = typer.Option(..., "--benchmark", help="Benchmark name or source_id"),
1202
1224
  description: Optional[str] = typer.Option(None, "--description", help="Dataset description"),
1203
1225
  visibility: str = typer.Option(
@@ -1216,20 +1238,32 @@ def dataset_create(
1216
1238
 
1217
1239
  from instance_repo.models import DatasetSeries
1218
1240
 
1241
+ from .dataset_name import (
1242
+ DatasetNameError,
1243
+ DatasetNameUpgradeRequired,
1244
+ parse_dataset_name,
1245
+ )
1219
1246
  from .irepo_sdk import _reason
1220
1247
 
1221
- parts = dataset.split("/")
1222
- if len(parts) != 2 or not all(parts):
1248
+ try:
1249
+ name = parse_dataset_name(dataset)
1250
+ except DatasetNameUpgradeRequired as exc:
1251
+ raise _fail(
1252
+ f"Failed to create dataset {dataset}: {exc}",
1253
+ "pip install 'ap-client[dataset]' --upgrade",
1254
+ exit_code=2,
1255
+ ) from exc
1256
+ except DatasetNameError:
1223
1257
  raise _fail(
1224
- f"Failed to create dataset {dataset}: the name must be two segments <team>/<name>",
1225
- "e.g. your-team/my-bench",
1258
+ f"Failed to create dataset {dataset}: the name must be one segment (L1) "
1259
+ "or two segments (L1/L2)",
1260
+ "e.g. my-bench or your-team/my-bench",
1226
1261
  exit_code=2,
1227
1262
  )
1228
- l1, l2 = parts
1229
1263
  series = DatasetSeries(
1230
1264
  dataset_name=dataset,
1231
- dataset_l1=l1,
1232
- dataset_l2=l2,
1265
+ dataset_l1=name.l1,
1266
+ dataset_l2=name.l2,
1233
1267
  benchmark_id=benchmark_id,
1234
1268
  visibility=resolved_visibility,
1235
1269
  description=description or None,
@@ -0,0 +1,53 @@
1
+ """DatasetName 解析 Adapter:唯一入口委托给已安装的 InstanceRepo SDK。
2
+
3
+ AP CLI 不维护第三套 dataset 名解析:``instance_repo.paths.DatasetName`` 是客户端
4
+ 路径契约的唯一事实源(L1 单段 ``A`` / 两段 ``A/B``,与 apiserver 的 namespace
5
+ guard 及 conformance 契约对齐)。SDK 缺失或过旧(没有 ``DatasetName.parse``
6
+ 能力)时,给出明确的升级提示,不静默降级、不本地重写解析规则。
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from typing import Any
12
+
13
+ __all__ = [
14
+ "DatasetNameError",
15
+ "DatasetNameUpgradeRequired",
16
+ "parse_dataset_name",
17
+ ]
18
+
19
+ #: SDK 缺失/无 DatasetName 能力时的升级提示(与 irepo_sdk 的 SdkMissing 同范式)。
20
+ _UPGRADE_HINT = (
21
+ "The installed instance-repo SDK does not provide DatasetName parsing "
22
+ "(single-segment L1 dataset names need it).\n"
23
+ "Install it with: pip install 'ap-client[dataset]' --upgrade"
24
+ )
25
+
26
+
27
+ class DatasetNameUpgradeRequired(RuntimeError):
28
+ """已安装的 instance-repo SDK 缺少 DatasetName 能力,必须升级。"""
29
+
30
+
31
+ class DatasetNameError(ValueError):
32
+ """Dataset 名不符合 IR DatasetName 契约(单段或两段、无非法段)。"""
33
+
34
+
35
+ def parse_dataset_name(value: str) -> Any:
36
+ """Parse ``value`` through the installed IR ``DatasetName`` capability.
37
+
38
+ Returns the SDK ``DatasetName`` (``canonical`` / ``l1`` / ``l2`` /
39
+ ``segments`` / ``leaf``)。Raises :class:`DatasetNameUpgradeRequired` when the
40
+ installed SDK lacks the capability; raises :class:`DatasetNameError` when
41
+ the value is not a valid L1 or L1/L2 name.
42
+ """
43
+ try:
44
+ from instance_repo.paths import DatasetName
45
+ except ImportError as exc:
46
+ raise DatasetNameUpgradeRequired(_UPGRADE_HINT) from exc
47
+ parse = getattr(DatasetName, "parse", None)
48
+ if not callable(parse):
49
+ raise DatasetNameUpgradeRequired(_UPGRADE_HINT)
50
+ try:
51
+ return parse(value)
52
+ except Exception as exc: # noqa: BLE001 - SDK 校验失败统一转成 CLI 契约
53
+ raise DatasetNameError(str(exc)) from exc
@@ -66,11 +66,25 @@ def _claim_without_workspace(
66
66
 
67
67
 
68
68
  def _create_owned_dataset(repo: Any, dataset: str, benchmark_id: str) -> dict:
69
- parts = dataset.split("/")
70
- if len(parts) != 2 or not all(parts):
69
+ from .dataset_name import (
70
+ DatasetNameError,
71
+ DatasetNameUpgradeRequired,
72
+ parse_dataset_name,
73
+ )
74
+
75
+ try:
76
+ name = parse_dataset_name(dataset)
77
+ except DatasetNameUpgradeRequired as exc:
78
+ raise datasets._fail(
79
+ f"Failed to create dataset {dataset}: {exc}",
80
+ "pip install 'ap-client[dataset]' --upgrade",
81
+ exit_code=2,
82
+ ) from exc
83
+ except DatasetNameError:
71
84
  raise datasets._fail(
72
- f"Failed to create dataset {dataset}: the name must be two segments <team>/<name>",
73
- "Use a dataset name such as your-team/my-bench",
85
+ f"Failed to create dataset {dataset}: the name must be one segment (L1) "
86
+ "or two segments (L1/L2)",
87
+ "Use a dataset name such as my-bench or your-team/my-bench",
74
88
  exit_code=2,
75
89
  )
76
90
 
@@ -78,8 +92,8 @@ def _create_owned_dataset(repo: Any, dataset: str, benchmark_id: str) -> dict:
78
92
 
79
93
  fields: dict[str, Any] = {
80
94
  "dataset_name": dataset,
81
- "dataset_l1": parts[0],
82
- "dataset_l2": parts[1],
95
+ "dataset_l1": name.l1,
96
+ "dataset_l2": name.l2,
83
97
  "visibility": "private",
84
98
  }
85
99
  if benchmark_id: