instance-repo 1.3.5.dev1__tar.gz → 1.3.5.dev3__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.
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/PKG-INFO +1 -1
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/__init__.py +1 -1
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/clients/instances.py +91 -6
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/transport.py +20 -7
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo.egg-info/PKG-INFO +1 -1
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/pyproject.toml +1 -1
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/README.md +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/_routing.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/_site_defaults.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/artifacts.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/bootstrap.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/cache.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/cli.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/clients/__init__.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/clients/benchmarks.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/clients/config.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/clients/datasets.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/clients/images.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/clients/reports.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/clients/scaffold.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/clients/splits.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/clients/versions.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/clients/workflows.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/concurrency.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/content.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/endpoints.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/errors.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/image.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/layout.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/loader.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/models.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/paths.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/release.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/repo.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/retry.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/store/__init__.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/store/acr.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/store/base.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/store/oss.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/store/oss_discovery.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/store/registry.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/tasktoml.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo/validate.py +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo.egg-info/SOURCES.txt +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo.egg-info/dependency_links.txt +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo.egg-info/entry_points.txt +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo.egg-info/requires.txt +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo.egg-info/top_level.txt +0 -0
- {instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/setup.cfg +0 -0
|
@@ -1175,6 +1175,7 @@ class InstancesClient:
|
|
|
1175
1175
|
validate_instance_id(instance_id, source="pull()")
|
|
1176
1176
|
expected = None
|
|
1177
1177
|
fmt = None # None = 未确定,需要探测
|
|
1178
|
+
dir_manifest = None # manifest 中的 directory 条目(如有)
|
|
1178
1179
|
lay = self._layout()
|
|
1179
1180
|
# 已下载的元数据字节(探测阶段下载一次,swe/custom 路径复用,避免二次网络往返)。
|
|
1180
1181
|
meta_bytes: bytes | None = None
|
|
@@ -1192,15 +1193,27 @@ class InstancesClient:
|
|
|
1192
1193
|
raise
|
|
1193
1194
|
if meta is not None and meta.manifest:
|
|
1194
1195
|
has_tgz = False
|
|
1196
|
+
has_dir = False
|
|
1195
1197
|
for m in meta.manifest:
|
|
1196
1198
|
if m.content_format == "tgz":
|
|
1197
1199
|
expected = m.content_digest
|
|
1198
1200
|
has_tgz = True
|
|
1199
1201
|
break
|
|
1202
|
+
if m.content_type == "directory":
|
|
1203
|
+
has_dir = True
|
|
1204
|
+
dir_manifest = m
|
|
1200
1205
|
if has_tgz:
|
|
1201
1206
|
fmt = "harbor"
|
|
1207
|
+
elif has_dir:
|
|
1208
|
+
# manifest 同时有 json 和 directory 条目 → custom 格式
|
|
1209
|
+
# (directory 条目指向 assets 目录,需逐文件下载)。
|
|
1210
|
+
fmt = "custom"
|
|
1211
|
+
for m in meta.manifest:
|
|
1212
|
+
if m.content_format == "json":
|
|
1213
|
+
expected = m.content_digest
|
|
1214
|
+
break
|
|
1202
1215
|
else:
|
|
1203
|
-
# manifest 有 json entry 但无 tgz → swe 或 custom(需进一步探测)。
|
|
1216
|
+
# manifest 有 json entry 但无 tgz 也无 directory → swe 或 custom(需进一步探测)。
|
|
1204
1217
|
# custom 推的 manifest 由 ingest 扫描生成,与 swe 同形态;
|
|
1205
1218
|
# 唯一区分手段是读 metadata JSON 检查 metadata_model 字段。
|
|
1206
1219
|
for m in meta.manifest:
|
|
@@ -1289,6 +1302,39 @@ class InstancesClient:
|
|
|
1289
1302
|
if isinstance(meta_doc, dict) and isinstance(
|
|
1290
1303
|
meta_doc.get("assets"), list):
|
|
1291
1304
|
asset_rels = [str(x) for x in meta_doc["assets"]]
|
|
1305
|
+
# manifest 有 directory 条目但 JSON 无 assets 字段时,
|
|
1306
|
+
# 用控制面 list_objects API 递归枚举目录下的全部文件作为 asset_rels。
|
|
1307
|
+
if asset_rels is None and dir_manifest is not None:
|
|
1308
|
+
try:
|
|
1309
|
+
env = getattr(self._p, "dataset_environment", None)
|
|
1310
|
+
mm = getattr(self._p, "metadata_model", None)
|
|
1311
|
+
# 递归列举:从根开始,遇到子目录继续深入
|
|
1312
|
+
asset_rels = []
|
|
1313
|
+
stack: list[str | None] = [None] # None = 实例资产根
|
|
1314
|
+
# list_objects 返回的 f.path 包含完整前缀
|
|
1315
|
+
# (如 test-assets/105-creep-forecast/solution/solve.py),
|
|
1316
|
+
# 需要去掉 {split}-assets/{instance_id}/ 前缀得到相对路径。
|
|
1317
|
+
split_str = (split or "default").strip()
|
|
1318
|
+
assets_root = f"{split_str}-assets/{instance_id.strip()}/"
|
|
1319
|
+
while stack:
|
|
1320
|
+
cur_path = stack.pop()
|
|
1321
|
+
objs = self.list_objects(
|
|
1322
|
+
dataset, instance_id, split=split,
|
|
1323
|
+
version=version, path=cur_path,
|
|
1324
|
+
environment=env, metadata_model=mm)
|
|
1325
|
+
for f in objs.files:
|
|
1326
|
+
rel = f.path
|
|
1327
|
+
if rel.startswith(assets_root):
|
|
1328
|
+
rel = rel[len(assets_root):]
|
|
1329
|
+
asset_rels.append(rel)
|
|
1330
|
+
for d in objs.directories:
|
|
1331
|
+
# directory path 也含完整前缀,去掉后入栈
|
|
1332
|
+
d_path = d.path.rstrip("/")
|
|
1333
|
+
if d_path.startswith(assets_root):
|
|
1334
|
+
d_path = d_path[len(assets_root):]
|
|
1335
|
+
stack.append(d_path)
|
|
1336
|
+
except Exception: # noqa: BLE001
|
|
1337
|
+
asset_rels = None # 枚举失败回退到 OSS LIST
|
|
1292
1338
|
self._download_custom_assets(
|
|
1293
1339
|
dataset, instance_id, version, split, dest_dir, lay, sts_prefix,
|
|
1294
1340
|
asset_rels=asset_rels, path=path)
|
|
@@ -1300,11 +1346,50 @@ class InstancesClient:
|
|
|
1300
1346
|
# 已在探测阶段下载,直接写入本地。
|
|
1301
1347
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
1302
1348
|
dest.write_bytes(meta_bytes)
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1349
|
+
else:
|
|
1350
|
+
self._content.get_object(
|
|
1351
|
+
idx_key, dest, expected_digest=expected,
|
|
1352
|
+
sts_prefix=sts_prefix,
|
|
1353
|
+
dataset=dataset)
|
|
1354
|
+
# swe 格式也可能附带 assets 目录(JSON + directory 混合格式)。
|
|
1355
|
+
# 尝试用 list_objects 检查并下载目录内容。
|
|
1356
|
+
try:
|
|
1357
|
+
objs = self.list_objects(
|
|
1358
|
+
dataset, instance_id, split=split,
|
|
1359
|
+
version=version,
|
|
1360
|
+
environment=getattr(self._p, "dataset_environment", None),
|
|
1361
|
+
metadata_model=getattr(self._p, "metadata_model", None))
|
|
1362
|
+
if objs.files or objs.directories:
|
|
1363
|
+
# 有 assets 内容 → 递归枚举并下载
|
|
1364
|
+
asset_rels: list[str] = []
|
|
1365
|
+
stack: list[str | None] = [None]
|
|
1366
|
+
split_str = (split or "default").strip()
|
|
1367
|
+
assets_root = f"{split_str}-assets/{instance_id.strip()}/"
|
|
1368
|
+
while stack:
|
|
1369
|
+
cur = stack.pop()
|
|
1370
|
+
page = self.list_objects(
|
|
1371
|
+
dataset, instance_id, split=split,
|
|
1372
|
+
version=version, path=cur,
|
|
1373
|
+
environment=getattr(self._p, "dataset_environment", None),
|
|
1374
|
+
metadata_model=getattr(self._p, "metadata_model", None))
|
|
1375
|
+
for f in page.files:
|
|
1376
|
+
rel = f.path
|
|
1377
|
+
if rel.startswith(assets_root):
|
|
1378
|
+
rel = rel[len(assets_root):]
|
|
1379
|
+
asset_rels.append(rel)
|
|
1380
|
+
for d in page.directories:
|
|
1381
|
+
d_path = d.path.rstrip("/")
|
|
1382
|
+
if d_path.startswith(assets_root):
|
|
1383
|
+
d_path = d_path[len(assets_root):]
|
|
1384
|
+
stack.append(d_path)
|
|
1385
|
+
if asset_rels:
|
|
1386
|
+
self._download_custom_assets(
|
|
1387
|
+
dataset, instance_id, version, split,
|
|
1388
|
+
dest_dir, lay, sts_prefix,
|
|
1389
|
+
asset_rels=asset_rels, path=path)
|
|
1390
|
+
except Exception: # noqa: BLE001
|
|
1391
|
+
pass # assets 目录不存在或枚举失败 → 仅保留 JSON
|
|
1392
|
+
return dest
|
|
1308
1393
|
|
|
1309
1394
|
# harbor:下载 content.tgz
|
|
1310
1395
|
dest = Path(dest_dir) / instance_id / "content.tgz"
|
|
@@ -327,12 +327,13 @@ class Transport:
|
|
|
327
327
|
dataset_id: str | None = None,
|
|
328
328
|
dataset_name: str | None = None,
|
|
329
329
|
permission: str | None = None,
|
|
330
|
-
list_only: bool = False
|
|
330
|
+
list_only: bool = False,
|
|
331
|
+
dataset_source: str | None = None) -> dict:
|
|
331
332
|
"""换 OSS STS 三元组(收窄到 bucket+prefix)。返回归一化小写字段。
|
|
332
333
|
|
|
333
|
-
同 (bucket,prefix,duration,dataset,permission,list_only)
|
|
334
|
-
|
|
335
|
-
|
|
334
|
+
同 (bucket,prefix,duration,dataset,permission,list_only,dataset_source)
|
|
335
|
+
在有效期内复用缓存,把 N 次签发降到 ~1 次。dataset_id / dataset_name
|
|
336
|
+
至少传一个(细粒度授权场景),二者可并存,服务端校验一致性。
|
|
336
337
|
|
|
337
338
|
``permission``(可选,admin/writer/reader)是**权限封顶**:apiserver 取
|
|
338
339
|
``min(调用方真实角色, permission)``,**只能收窄不能提权**——传 admin 不会把
|
|
@@ -343,12 +344,20 @@ class Transport:
|
|
|
343
344
|
``list_only`` 是**发现模式开关**(与 permission 封顶正交):True 时签发仅含
|
|
344
345
|
oss:ListObjects + oss:GetBucketInfo 的令牌,跳过 DatasetRBAC 检查,用于未注册
|
|
345
346
|
dataset 的 OSS 回退目录探测。二者可并存(list_only 分支优先)。
|
|
347
|
+
|
|
348
|
+
``dataset_source``(可选,"db"/"oss")指定数据集管理源:
|
|
349
|
+
- 空/"db"(默认):走 MongoDB 注册 + RBAC 授权流程
|
|
350
|
+
- "oss":纯 OSS 模式,跳过 RBAC,dataset_name/dataset_id 可不填,
|
|
351
|
+
直接按 bucket+prefix 签发 STS
|
|
346
352
|
"""
|
|
347
353
|
# 空串与 None 一律视为"不封顶"(与 Go 的 Permission == "" 语义对齐)。
|
|
348
354
|
if permission and permission not in PERMISSION_VALUES:
|
|
349
355
|
raise SchemaError(
|
|
350
356
|
f"invalid permission '{permission}'; valid values: "
|
|
351
357
|
f"{', '.join(PERMISSION_VALUES)}")
|
|
358
|
+
if dataset_source and dataset_source not in ("db", "oss"):
|
|
359
|
+
raise SchemaError(
|
|
360
|
+
f"invalid dataset_source '{dataset_source}'; valid values: db, oss")
|
|
352
361
|
|
|
353
362
|
def sign() -> dict:
|
|
354
363
|
body: dict[str, Any] = {"resource": "oss",
|
|
@@ -363,6 +372,8 @@ class Transport:
|
|
|
363
372
|
body["permission"] = permission
|
|
364
373
|
if list_only:
|
|
365
374
|
body["list_only"] = True
|
|
375
|
+
if dataset_source:
|
|
376
|
+
body["dataset_source"] = dataset_source
|
|
366
377
|
r = self.post("/apis/v1/credentials", body, idempotent=True)
|
|
367
378
|
return {
|
|
368
379
|
"access_key_id": self._require(r, "OSS_ACCESS_KEY_ID"),
|
|
@@ -376,11 +387,13 @@ class Transport:
|
|
|
376
387
|
}
|
|
377
388
|
|
|
378
389
|
ttl = float(min(duration_seconds or MIN_STS_DURATION, MAX_STS_DURATION))
|
|
379
|
-
# permission
|
|
390
|
+
# permission、list_only、dataset_source 都必须进缓存 key:否则请求 reader 封顶的调用方可能
|
|
380
391
|
# 命中此前那份未封顶(可写)的缓存令牌,权限收窄被静默绕过;list-only 令牌
|
|
381
|
-
#
|
|
392
|
+
# 也可能被普通请求复用(反之亦然),发现模式与读写模式互相污染;
|
|
393
|
+
# oss 模式凭据不能被 db 模式复用(反之亦然)。
|
|
382
394
|
cache_key = ("oss", bucket, prefix, duration_seconds,
|
|
383
|
-
dataset_id, dataset_name, permission or None, list_only
|
|
395
|
+
dataset_id, dataset_name, permission or None, list_only,
|
|
396
|
+
dataset_source or None)
|
|
384
397
|
return self._cached_cred(cache_key, sign, fallback_ttl=ttl)
|
|
385
398
|
|
|
386
399
|
def get_acr_credentials(self, acr_registry_url: str, *,
|
|
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
|
|
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
|
{instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{instance_repo-1.3.5.dev1 → instance_repo-1.3.5.dev3}/instance_repo.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|