ap-client 0.6.1.dev3__tar.gz → 0.6.1.dev5__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.1.dev3 → ap_client-0.6.1.dev5}/PKG-INFO +3 -3
  2. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/dataset_commands.py +2 -2
  3. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/dataset_register.py +55 -1
  4. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/dfs_commands.py +23 -1
  5. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/irepo_sdk.py +15 -0
  6. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/pyproject.toml +3 -3
  7. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/__init__.py +0 -0
  8. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/akpool_commands.py +0 -0
  9. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/api.py +0 -0
  10. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/cli.py +0 -0
  11. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/config.py +0 -0
  12. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/dataset_name.py +0 -0
  13. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/exporter.py +0 -0
  14. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/fs_commands.py +0 -0
  15. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/instance_commands.py +0 -0
  16. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/instance_options.py +0 -0
  17. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/managed_ak.py +0 -0
  18. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/manifest_view.py +0 -0
  19. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/ossutil_hash.py +0 -0
  20. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/ossutil_io.py +0 -0
  21. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/profile_commands.py +0 -0
  22. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/repo_read_guard.py +0 -0
  23. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/share_api.py +0 -0
  24. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/split_publish.py +0 -0
  25. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/tbb.py +0 -0
  26. {ap_client-0.6.1.dev3 → ap_client-0.6.1.dev5}/ap_client/waiter.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ap-client
3
- Version: 0.6.1.dev3
3
+ Version: 0.6.1.dev5
4
4
  Summary: Agent Platform API Client & CLI
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: irepo-artifact==0.2.2
@@ -10,9 +10,9 @@ Requires-Dist: rich>=13.0.0
10
10
  Requires-Dist: typer>=0.9.0
11
11
  Requires-Dist: websockets>=13.0
12
12
  Provides-Extra: all
13
- Requires-Dist: instance-repo[oss]<2.0.0,>=1.4.0.dev4; extra == 'all'
13
+ Requires-Dist: instance-repo[oss]<2.0.0,>=1.4.0.dev5; extra == 'all'
14
14
  Provides-Extra: dataset
15
- Requires-Dist: instance-repo[oss]<2.0.0,>=1.4.0.dev4; extra == 'dataset'
15
+ Requires-Dist: instance-repo[oss]<2.0.0,>=1.4.0.dev5; extra == 'dataset'
16
16
  Description-Content-Type: text/markdown
17
17
 
18
18
  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.
@@ -795,12 +795,12 @@ def _split_names(detail: dict) -> list[str]:
795
795
  return names
796
796
 
797
797
 
798
- def _dataset_repo() -> "Repo":
798
+ def _dataset_repo(*, request_timeout: float | None = None) -> "Repo":
799
799
  """dataset 写路径统一走 InstanceRepo SDK;未装 ``dataset`` extra 时退出 2。"""
800
800
  from .irepo_sdk import SdkMissing, load_repo
801
801
 
802
802
  try:
803
- return load_repo()
803
+ return load_repo(request_timeout=request_timeout)
804
804
  except SdkMissing as exc:
805
805
  typer.echo(str(exc), err=True)
806
806
  raise typer.Exit(2) from exc
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import json
6
6
  import math
7
+ import os
7
8
  import sys
8
9
  from typing import Any, List, Optional
9
10
  from urllib.parse import quote
@@ -33,6 +34,42 @@ def _emit_preview_stderr(payload: dict, output_format: str) -> None:
33
34
  typer.echo(json.dumps(payload, ensure_ascii=False, indent=2), err=True)
34
35
 
35
36
 
37
+ def _parse_request_timeout() -> float:
38
+ """Read ``AP_REQUEST_TIMEOUT`` from the environment, falling back to 30 s.
39
+
40
+ Empty, missing, or non-numeric values all resolve to the default rather
41
+ than raising ``ValueError`` at import time (which would break ``ap --help``).
42
+ """
43
+ raw = os.environ.get("AP_REQUEST_TIMEOUT", "").strip()
44
+ if not raw:
45
+ return 30.0
46
+ try:
47
+ value = float(raw)
48
+ except (TypeError, ValueError):
49
+ return 30.0
50
+ return value if math.isfinite(value) and value > 0 else 30.0
51
+
52
+
53
+ def _set_sdk_request_timeout(repo: Any, timeout: float) -> None:
54
+ """Override the IR SDK per-request HTTP timeout on the shared Transport.
55
+
56
+ All sub-clients (``datasets``, ``versions``, ``instances``) share
57
+ ``repo.transport``, so a single assignment covers every control-plane
58
+ call the register command makes (preview and submission alike).
59
+ Falls back to setting the attribute on each sub-client's ``_t`` when the
60
+ ``transport`` attribute is absent (older SDK shapes).
61
+ """
62
+ transport = getattr(repo, "transport", None)
63
+ if transport is not None and hasattr(transport, "timeout"):
64
+ transport.timeout = timeout
65
+ return
66
+ for name in ("datasets", "versions", "instances", "images"):
67
+ client = getattr(repo, name, None)
68
+ t = getattr(client, "_t", None)
69
+ if t is not None and hasattr(t, "timeout"):
70
+ t.timeout = timeout
71
+
72
+
36
73
  def _confirm(dataset: str, *, yes: bool) -> None:
37
74
  if yes:
38
75
  return
@@ -220,6 +257,13 @@ def dataset_register(
220
257
  yes: bool = typer.Option(False, "--yes", "-y", help="Skip the registration confirmation"),
221
258
  wait: bool = typer.Option(False, "--wait", help="Wait for the ingest task to finish"),
222
259
  timeout: float = typer.Option(1800.0, "--timeout", help="Local wait timeout in seconds"),
260
+ request_timeout: float = typer.Option(
261
+ _parse_request_timeout(),
262
+ "--request-timeout",
263
+ help="Per-request HTTP timeout in seconds for control-plane calls "
264
+ "(env: AP_REQUEST_TIMEOUT, default: 30). "
265
+ "Increase for datasets with many objects where the preview scan takes longer.",
266
+ ),
223
267
  output_format: Optional[str] = typer.Option(None, "--format", help=datasets._FORMAT_HELP),
224
268
  owner: Optional[str] = typer.Option(
225
269
  None, "--owner", help="Ensure ownership before ingest; the only supported value is @me"
@@ -273,7 +317,17 @@ def dataset_register(
273
317
  )
274
318
 
275
319
  env = datasets._environment(environment)
276
- repo = datasets._dataset_repo()
320
+ repo = datasets._dataset_repo(request_timeout=request_timeout)
321
+ # Override the IR SDK per-request HTTP timeout. All sub-clients
322
+ # (datasets, versions, instances) share repo.transport, so one
323
+ # assignment covers preview and submission alike.
324
+ if not math.isfinite(request_timeout) or request_timeout <= 0:
325
+ raise datasets._fail(
326
+ "--request-timeout must be a positive finite number",
327
+ "Pass a positive number of seconds",
328
+ exit_code=2,
329
+ )
330
+ _set_sdk_request_timeout(repo, request_timeout)
277
331
  datasets._check_storage_side(repo, env)
278
332
  ingest = getattr(getattr(repo, "versions", None), "ingest", None)
279
333
  if not callable(ingest):
@@ -32,12 +32,34 @@ def register(app: typer.Typer) -> None:
32
32
  app.add_typer(dfs_app, name="dfs")
33
33
 
34
34
 
35
+ _DFS_ACCESS_DENIED_CODES = frozenset({94016, 94018, 10002})
36
+
37
+
35
38
  def _files() -> OssFiles:
36
39
  from .cli import app
37
40
  from .irepo_sdk import load_ossutil_repo
38
41
 
39
42
  app.pretty_exceptions_show_locals = False
40
- repo, config = load_ossutil_repo()
43
+ try:
44
+ repo, config = load_ossutil_repo()
45
+ except Exception as exc:
46
+ biz_code = getattr(exc, "biz_code", None)
47
+ status = getattr(exc, "status", None) or getattr(exc, "status_code", None)
48
+ msg = str(exc).lower()
49
+ is_forbidden = (
50
+ biz_code in _DFS_ACCESS_DENIED_CODES
51
+ or status == 403
52
+ or "forbidden" in msg
53
+ or "permission" in msg
54
+ or "not allowed" in msg
55
+ )
56
+ if is_forbidden:
57
+ typer.echo(
58
+ "ap dfs is currently available to platform admins and allow-listed users only.",
59
+ err=True,
60
+ )
61
+ raise typer.Exit(1) from exc
62
+ raise
41
63
  return OssFiles(repo, OssBinding.from_payload(config))
42
64
 
43
65
 
@@ -884,6 +884,7 @@ def load_repo(
884
884
  cluster: str | None = None,
885
885
  storage_env: str | None = None,
886
886
  environment: str | None = None,
887
+ request_timeout: float | None = None,
887
888
  ) -> "Repo":
888
889
  """按 AP ``Config`` 构造 ``instance_repo.Repo``。
889
890
 
@@ -942,7 +943,21 @@ def load_repo(
942
943
  if cfg.verbose and "transport" in supported:
943
944
  transport = _verbose_sdk_transport(cfg, api_env)
944
945
  if transport is not None:
946
+ if request_timeout is not None:
947
+ transport.timeout = request_timeout
945
948
  kwargs["transport"] = transport
949
+ elif request_timeout is not None and "transport" in supported:
950
+ # Inject a pre-configured Transport so the custom timeout is effective
951
+ # from the very first HTTP call inside Repo.__init__ / _bind_dataset_profile.
952
+ try:
953
+ from instance_repo.transport import Transport as _Transport
954
+ except ImportError:
955
+ _Transport = None
956
+ if _Transport is not None:
957
+ kwargs["transport"] = _Transport(
958
+ cfg.base_url, cfg.token_key or "", env=api_env,
959
+ timeout=request_timeout,
960
+ )
946
961
 
947
962
  if "api_base" not in supported or "cluster" not in supported:
948
963
  # 0.8.x 兼容路径:构造参数缺位,只能退回环境变量契约。
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ap-client"
7
- version = "0.6.1.dev3"
7
+ version = "0.6.1.dev5"
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"
@@ -19,10 +19,10 @@ dependencies = [
19
19
 
20
20
  [project.optional-dependencies]
21
21
  dataset = [
22
- "instance-repo[oss]>=1.4.0.dev4,<2.0.0",
22
+ "instance-repo[oss]>=1.4.0.dev5,<2.0.0",
23
23
  ]
24
24
  all = [
25
- "instance-repo[oss]>=1.4.0.dev4,<2.0.0",
25
+ "instance-repo[oss]>=1.4.0.dev5,<2.0.0",
26
26
  ]
27
27
 
28
28
  [project.scripts]