irepo-artifact 0.2.3.dev0__tar.gz → 0.2.4.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 (20) hide show
  1. {irepo_artifact-0.2.3.dev0/src/irepo_artifact.egg-info → irepo_artifact-0.2.4.dev0}/PKG-INFO +6 -5
  2. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/README.md +5 -4
  3. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/pyproject.toml +1 -1
  4. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/src/irepo_artifact/client.py +25 -8
  5. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/src/irepo_artifact/download.py +2 -2
  6. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0/src/irepo_artifact.egg-info}/PKG-INFO +6 -5
  7. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/MANIFEST.in +0 -0
  8. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/setup.cfg +0 -0
  9. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/setup.py +0 -0
  10. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/src/irepo_artifact/__init__.py +0 -0
  11. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/src/irepo_artifact/api.py +0 -0
  12. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/src/irepo_artifact/diagnostics.py +0 -0
  13. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/src/irepo_artifact/errors.py +0 -0
  14. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/src/irepo_artifact/layout.py +0 -0
  15. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/src/irepo_artifact/manifest_wait.py +0 -0
  16. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/src/irepo_artifact/models.py +0 -0
  17. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/src/irepo_artifact/probe.py +0 -0
  18. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/src/irepo_artifact.egg-info/SOURCES.txt +0 -0
  19. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/src/irepo_artifact.egg-info/dependency_links.txt +0 -0
  20. {irepo_artifact-0.2.3.dev0 → irepo_artifact-0.2.4.dev0}/src/irepo_artifact.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: irepo-artifact
3
- Version: 0.2.3.dev0
3
+ Version: 0.2.4.dev0
4
4
  Summary: Standalone HTTP artifact downloads
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -11,10 +11,10 @@ Python 3.10+ 的独立产物下载包。通过 AP 获取链接后 HTTP 下载,
11
11
  `instance-repo`、`ap-client`、`oss2` 或 STS。完整 SDK 与未来的 ap-client
12
12
  均可单向依赖此包。
13
13
 
14
- 安装发布版本:
14
+ 发布后安装:
15
15
 
16
16
  ```bash
17
- python -m pip install 'irepo-artifact==0.2.3.dev0'
17
+ python -m pip install 'irepo-artifact==0.2.4.dev0'
18
18
  ```
19
19
 
20
20
  源码开发安装:
@@ -65,8 +65,9 @@ group = client.download_group("group-a", output_dir="group-out")
65
65
 
66
66
  ## 传输与输出
67
67
 
68
- 完整包先请求 `download_mode=oss`。取得 OSS 链接后探测内网端点;不可达时另行请求
69
- `download_mode=proxy`,可达时使用 OSS。OSS 实际下载发生远端故障时,为该 Job
68
+ 完整包先请求 `download_mode=oss`。OSS 链接签发返回 502/503 时按需请求
69
+ `download_mode=proxy`;取得 OSS 链接后探测内网端点,不可达时也请求 proxy,
70
+ 可达时使用 OSS。OSS 实际下载发生远端故障时,为该 Job
70
71
  另行请求 proxy 链接并从头下载。单 Job 与批量下载使用相同策略。
71
72
  未返回 `downloads`(或为 null/空对象)时使用旧版单 `url`,也支持 dataplane 地址。
72
73
  单 URL 仅在 hostname 匹配标准 OSS 域名时标记 `channel='oss'`;其余返回
@@ -4,10 +4,10 @@ Python 3.10+ 的独立产物下载包。通过 AP 获取链接后 HTTP 下载,
4
4
  `instance-repo`、`ap-client`、`oss2` 或 STS。完整 SDK 与未来的 ap-client
5
5
  均可单向依赖此包。
6
6
 
7
- 安装发布版本:
7
+ 发布后安装:
8
8
 
9
9
  ```bash
10
- python -m pip install 'irepo-artifact==0.2.3.dev0'
10
+ python -m pip install 'irepo-artifact==0.2.4.dev0'
11
11
  ```
12
12
 
13
13
  源码开发安装:
@@ -58,8 +58,9 @@ group = client.download_group("group-a", output_dir="group-out")
58
58
 
59
59
  ## 传输与输出
60
60
 
61
- 完整包先请求 `download_mode=oss`。取得 OSS 链接后探测内网端点;不可达时另行请求
62
- `download_mode=proxy`,可达时使用 OSS。OSS 实际下载发生远端故障时,为该 Job
61
+ 完整包先请求 `download_mode=oss`。OSS 链接签发返回 502/503 时按需请求
62
+ `download_mode=proxy`;取得 OSS 链接后探测内网端点,不可达时也请求 proxy,
63
+ 可达时使用 OSS。OSS 实际下载发生远端故障时,为该 Job
63
64
  另行请求 proxy 链接并从头下载。单 Job 与批量下载使用相同策略。
64
65
  未返回 `downloads`(或为 null/空对象)时使用旧版单 `url`,也支持 dataplane 地址。
65
66
  单 URL 仅在 hostname 匹配标准 OSS 域名时标记 `channel='oss'`;其余返回
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "irepo-artifact"
7
- version = "0.2.3.dev0"
7
+ version = "0.2.4.dev0"
8
8
  description = "Standalone HTTP artifact downloads"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -6,7 +6,7 @@ from pathlib import Path
6
6
  from copy import deepcopy
7
7
  import time
8
8
 
9
- from .api import APAPI, validate_id
9
+ from .api import APAPI, _APStatus, validate_id
10
10
  from .download import download_archive, download_with_refresh
11
11
  from .errors import (ArtifactError, ArtifactNotFound, ConfigurationError,
12
12
  DownloadError, HTTPStatusError, NoMatchingFiles)
@@ -37,6 +37,19 @@ def _deadline(targets):
37
37
  return time.monotonic() + max(0, expiry - min(30, max(1, expiry * 0.1)))
38
38
 
39
39
 
40
+ def _archive_targets(api, job_ids, mode, metadata, *, tolerate_errors=False):
41
+ try:
42
+ targets = api.get_archive_targets(
43
+ job_ids, mode=mode, metadata=metadata, tolerate_errors=tolerate_errors)
44
+ return targets, mode
45
+ except _APStatus as exc:
46
+ if mode != 'oss' or exc.status not in (502, 503):
47
+ raise
48
+ targets = api.get_archive_targets(
49
+ job_ids, mode='proxy', metadata=metadata, tolerate_errors=tolerate_errors)
50
+ return targets, 'proxy'
51
+
52
+
40
53
  class ArtifactClient:
41
54
  """Download AP artifacts without a parent SDK or storage client.
42
55
 
@@ -89,7 +102,8 @@ class ArtifactClient:
89
102
  elif targets is None:
90
103
  raw = {}
91
104
  try:
92
- targets = self._api.get_archive_targets([job_id], mode=link_mode, metadata=raw)[job_id]
105
+ signed, link_mode = _archive_targets(self._api, [job_id], link_mode, raw)
106
+ targets = signed[job_id]
93
107
  finally:
94
108
  metadata['artifacts_response'] = raw.get(job_id)
95
109
  output = JobOutput(job_dir, overwrite,
@@ -102,10 +116,11 @@ class ArtifactClient:
102
116
  if 'proxy' in targets and 'oss' not in targets:
103
117
  link_mode = 'proxy'
104
118
  refreshed_metadata = {}
105
- def refresh():
119
+ def refresh(channel):
106
120
  raw = {}
107
121
  try:
108
- renewed = self._api.get_archive_targets([job_id], mode=link_mode, metadata=raw)[job_id]
122
+ mode = channel if channel in ('oss', 'proxy') else link_mode
123
+ renewed = self._api.get_archive_targets([job_id], mode=mode, metadata=raw)[job_id]
109
124
  except ArtifactError as exc:
110
125
  # A failed refresh must not replace the last usable response.
111
126
  raise self._attach(exc, metadata) from None
@@ -194,8 +209,9 @@ class ArtifactClient:
194
209
  jid = ids[0]
195
210
  raw = {}
196
211
  try:
197
- signed = self._api.get_archive_targets(
198
- [jid], mode='oss', metadata=raw, tolerate_errors=True)[jid]
212
+ signed_targets, link_mode = _archive_targets(
213
+ self._api, [jid], 'oss', raw, tolerate_errors=True)
214
+ signed = signed_targets[jid]
199
215
  except ArtifactError as exc:
200
216
  signed = exc.clone()
201
217
  signed.artifacts_response = deepcopy(raw.get(jid))
@@ -215,8 +231,9 @@ class ArtifactClient:
215
231
  if not (includes or excludes):
216
232
  to_sign = [jid for jid in ready if jid not in prefetched]
217
233
  try:
218
- targets.update(self._api.get_archive_targets(
219
- to_sign, mode=link_mode, metadata=raw, tolerate_errors=True))
234
+ signed_targets, link_mode = _archive_targets(
235
+ self._api, to_sign, link_mode, raw, tolerate_errors=True)
236
+ targets.update(signed_targets)
220
237
  except ArtifactError as exc:
221
238
  if len(to_sign) > 1 and getattr(exc, '_request_status', None) in (403, 404):
222
239
  # No links were issued. Let the existing workers
@@ -108,7 +108,7 @@ def download_with_refresh(target: DownloadTarget, destination: Path,
108
108
 
109
109
 
110
110
  def download_archive(targets: dict[str, DownloadTarget], destination: Path,
111
- refresh_targets: Callable[[], dict[str, DownloadTarget]],
111
+ refresh_targets: Callable[[str], dict[str, DownloadTarget]],
112
112
  timeout: float = 30, *, on_refreshed=None, probe=None,
113
113
  get_proxy_targets=None) -> Literal['oss', 'proxy'] | None:
114
114
  channel = next((kind for kind in ('oss', 'proxy', 'legacy') if kind in targets), None)
@@ -120,7 +120,7 @@ def download_archive(targets: dict[str, DownloadTarget], destination: Path,
120
120
  def refresh():
121
121
  nonlocal refresh_error, channel
122
122
  try:
123
- renewed = dict(refresh_targets())
123
+ renewed = dict(refresh_targets(channel))
124
124
  if channel not in renewed:
125
125
  if channel == 'legacy' and renewed:
126
126
  channel = next((kind for kind in ('oss', 'proxy', 'legacy') if kind in renewed), None)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: irepo-artifact
3
- Version: 0.2.3.dev0
3
+ Version: 0.2.4.dev0
4
4
  Summary: Standalone HTTP artifact downloads
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -11,10 +11,10 @@ Python 3.10+ 的独立产物下载包。通过 AP 获取链接后 HTTP 下载,
11
11
  `instance-repo`、`ap-client`、`oss2` 或 STS。完整 SDK 与未来的 ap-client
12
12
  均可单向依赖此包。
13
13
 
14
- 安装发布版本:
14
+ 发布后安装:
15
15
 
16
16
  ```bash
17
- python -m pip install 'irepo-artifact==0.2.3.dev0'
17
+ python -m pip install 'irepo-artifact==0.2.4.dev0'
18
18
  ```
19
19
 
20
20
  源码开发安装:
@@ -65,8 +65,9 @@ group = client.download_group("group-a", output_dir="group-out")
65
65
 
66
66
  ## 传输与输出
67
67
 
68
- 完整包先请求 `download_mode=oss`。取得 OSS 链接后探测内网端点;不可达时另行请求
69
- `download_mode=proxy`,可达时使用 OSS。OSS 实际下载发生远端故障时,为该 Job
68
+ 完整包先请求 `download_mode=oss`。OSS 链接签发返回 502/503 时按需请求
69
+ `download_mode=proxy`;取得 OSS 链接后探测内网端点,不可达时也请求 proxy,
70
+ 可达时使用 OSS。OSS 实际下载发生远端故障时,为该 Job
70
71
  另行请求 proxy 链接并从头下载。单 Job 与批量下载使用相同策略。
71
72
  未返回 `downloads`(或为 null/空对象)时使用旧版单 `url`,也支持 dataplane 地址。
72
73
  单 URL 仅在 hostname 匹配标准 OSS 域名时标记 `channel='oss'`;其余返回