ap-client 0.6.1.dev11__tar.gz → 0.6.1.dev12__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.6.1.dev11 → ap_client-0.6.1.dev12}/PKG-INFO +1 -1
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/fs_transfer.py +44 -2
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/pyproject.toml +1 -1
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/__init__.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/akpool_commands.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/api.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/cli.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/config.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/dataset_commands.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/dataset_name.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/dataset_register.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/dfs_commands.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/exporter.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/fs_commands.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/instance_commands.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/instance_options.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/irepo_sdk.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/managed_ak.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/manifest_view.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/ossutil_hash.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/ossutil_io.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/profile_commands.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/repo_read_guard.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/share_api.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/split_publish.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/tbb.py +0 -0
- {ap_client-0.6.1.dev11 → ap_client-0.6.1.dev12}/ap_client/waiter.py +0 -0
|
@@ -24,6 +24,20 @@ from .ossutil_io import OssOperationError, _WriteBucket
|
|
|
24
24
|
PART_SIZE = 8 * 1024 * 1024
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
def _scope_denied(exc: Exception) -> bool:
|
|
28
|
+
"""Only explicit scope refusals allow a more specific authorization request."""
|
|
29
|
+
seen = set()
|
|
30
|
+
cause = exc
|
|
31
|
+
while cause is not None and id(cause) not in seen:
|
|
32
|
+
seen.add(id(cause))
|
|
33
|
+
if getattr(cause, "biz_code", None) == 94023: # user-data has no grant
|
|
34
|
+
return True
|
|
35
|
+
if getattr(cause, "status", None) == 403 and getattr(cause, "code", None) == "AccessDenied":
|
|
36
|
+
return True
|
|
37
|
+
cause = cause.__cause__
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
|
|
27
41
|
class TransferProgress:
|
|
28
42
|
def __init__(self, description: str, enabled: bool | None):
|
|
29
43
|
console = Console(stderr=True, markup=False, highlight=False)
|
|
@@ -125,6 +139,7 @@ class UserDataTransfer:
|
|
|
125
139
|
from instance_repo._routing import _OperationIntent
|
|
126
140
|
|
|
127
141
|
source = Path(source)
|
|
142
|
+
remote = self.repo._clean_user_data_subpath(remote)
|
|
128
143
|
base = self._key(uid, remote)
|
|
129
144
|
directory = source.is_dir()
|
|
130
145
|
files = []
|
|
@@ -145,6 +160,7 @@ class UserDataTransfer:
|
|
|
145
160
|
workers = min(self.concurrency, max(1, len(files)))
|
|
146
161
|
part_threads = max(1, self.concurrency // workers)
|
|
147
162
|
report = TransferProgress("Uploading", self.progress).start(sizes)
|
|
163
|
+
directory_scope = base.rstrip("/") + "/" if directory else None
|
|
148
164
|
|
|
149
165
|
def transfer(item):
|
|
150
166
|
local, key = item
|
|
@@ -170,14 +186,40 @@ class UserDataTransfer:
|
|
|
170
186
|
)
|
|
171
187
|
return {"key": key, "skipped": False}
|
|
172
188
|
|
|
173
|
-
|
|
174
|
-
|
|
189
|
+
scope = directory_scope or key
|
|
190
|
+
try:
|
|
191
|
+
result = self.content._execute_oss(
|
|
192
|
+
_OperationIntent.NON_DOWNLOAD, scope, None, upload
|
|
193
|
+
)
|
|
194
|
+
except Exception as exc:
|
|
195
|
+
if scope == key or not _scope_denied(exc):
|
|
196
|
+
raise
|
|
197
|
+
# A directory token may deny a reader subtree that contains a
|
|
198
|
+
# more specific writer grant. Re-authorize only this object;
|
|
199
|
+
# never ignore a Deny or request a broader ancestor token.
|
|
200
|
+
result = self.content._execute_oss(_OperationIntent.NON_DOWNLOAD, key, None, upload)
|
|
175
201
|
report.finish(key, skipped=result["skipped"])
|
|
176
202
|
return result
|
|
177
203
|
|
|
178
204
|
with report:
|
|
179
205
|
if not files:
|
|
180
206
|
return []
|
|
207
|
+
if directory_scope is not None:
|
|
208
|
+
try:
|
|
209
|
+
# Prime the SDK's thread-safe, expiry-aware credential cache.
|
|
210
|
+
# The server includes descendant reader Deny rules in this
|
|
211
|
+
# directory policy. Never reconstruct that policy locally.
|
|
212
|
+
credentials = self.content._credentials(directory_scope, None)
|
|
213
|
+
except Exception as exc:
|
|
214
|
+
if not _scope_denied(exc):
|
|
215
|
+
raise
|
|
216
|
+
# File-only grants remain usable without a parent grant.
|
|
217
|
+
directory_scope = None
|
|
218
|
+
else:
|
|
219
|
+
if credentials.get("prefix") != directory_scope:
|
|
220
|
+
raise OssOperationError(
|
|
221
|
+
"Directory credential scope differs from the requested directory"
|
|
222
|
+
)
|
|
181
223
|
if workers == 1:
|
|
182
224
|
outcomes = [transfer(item) for item in files]
|
|
183
225
|
else:
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ap-client"
|
|
7
|
-
version = "0.6.1.
|
|
7
|
+
version = "0.6.1.dev12"
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|