instance-repo 1.3.2.dev2__tar.gz → 1.3.2.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.2.dev2 → instance_repo-1.3.2.dev3}/PKG-INFO +1 -1
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/__init__.py +1 -1
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/_routing.py +4 -4
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/clients/datasets.py +7 -3
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/clients/splits.py +23 -3
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/clients/versions.py +13 -3
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/repo.py +2 -1
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/store/oss_discovery.py +145 -86
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo.egg-info/PKG-INFO +1 -1
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/pyproject.toml +1 -1
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/README.md +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/_site_defaults.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/artifacts.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/bootstrap.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/cache.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/cli.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/clients/__init__.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/clients/benchmarks.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/clients/config.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/clients/images.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/clients/instances.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/clients/reports.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/clients/scaffold.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/clients/workflows.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/concurrency.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/content.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/endpoints.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/errors.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/image.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/layout.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/loader.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/models.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/paths.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/release.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/retry.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/store/__init__.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/store/acr.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/store/base.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/store/oss.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/store/registry.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/tasktoml.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/transport.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo/validate.py +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo.egg-info/SOURCES.txt +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo.egg-info/dependency_links.txt +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo.egg-info/entry_points.txt +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo.egg-info/requires.txt +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo.egg-info/top_level.txt +0 -0
- {instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/setup.cfg +0 -0
|
@@ -45,14 +45,14 @@ def _split_scheme(endpoint: str) -> tuple[str, str]:
|
|
|
45
45
|
return "", endpoint
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
def _probe_private_endpoint(endpoint: str, timeout: float =
|
|
48
|
+
def _probe_private_endpoint(endpoint: str, timeout: float = 0.5) -> bool:
|
|
49
49
|
"""Quick TCP connect probe to decide whether a private endpoint is reachable.
|
|
50
50
|
|
|
51
51
|
Performs a raw TCP connect (no TLS handshake) to the endpoint host/port.
|
|
52
52
|
Returns True if the connect succeeds, False on any error. The default
|
|
53
|
-
timeout is
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
timeout is 0.5 seconds — 内网 TCP 握手通常在几十毫秒内完成,0.5s 足够
|
|
54
|
+
判定可达性,同时把公网环境下私网不可达的探测开销从 3s 压到 0.5s
|
|
55
|
+
(结果按 store 缓存 5 分钟,仅端点变更或缓存过期才重探)。
|
|
56
56
|
"""
|
|
57
57
|
_, host = _split_scheme(endpoint)
|
|
58
58
|
# Determine port: default 443 for https, 80 for http.
|
|
@@ -16,10 +16,13 @@ class DatasetsClient:
|
|
|
16
16
|
_BASE = "/apis/v1/datasets/series"
|
|
17
17
|
|
|
18
18
|
def __init__(self, transport, *, content_store=None,
|
|
19
|
-
oss_prefix: str = "swe/datasets"
|
|
19
|
+
oss_prefix: str = "swe/datasets",
|
|
20
|
+
metadata_model: str | None = None) -> None:
|
|
20
21
|
self._t = transport
|
|
21
22
|
self._content = content_store
|
|
22
23
|
self._oss_prefix = oss_prefix
|
|
24
|
+
# OSS 回退探测的布局语义(split_first 默认;version_first 显式切换)
|
|
25
|
+
self._metadata_model = metadata_model or "split_first"
|
|
23
26
|
|
|
24
27
|
def list(self, l1: str | None = None) -> list[DatasetSeries]:
|
|
25
28
|
"""列出 dataset(便利语义:自动翻页取全量,见 :meth:`list_paged` 单页对照)。
|
|
@@ -398,9 +401,10 @@ class DatasetsClient:
|
|
|
398
401
|
parse_dataset_level, build_synthetic_dataset_detail,
|
|
399
402
|
_warn_if_truncated)
|
|
400
403
|
info = parse_dataset_level(
|
|
401
|
-
self._content, name, oss_prefix=self._oss_prefix
|
|
404
|
+
self._content, name, oss_prefix=self._oss_prefix,
|
|
405
|
+
metadata_model=self._metadata_model)
|
|
402
406
|
_warn_if_truncated(info, name, 500)
|
|
403
|
-
if not info.versions:
|
|
407
|
+
if not info.versions and not info.unversioned_splits:
|
|
404
408
|
from ..errors import DatasetNotFound
|
|
405
409
|
raise DatasetNotFound(f"dataset {name!r} not found in OSS")
|
|
406
410
|
return build_synthetic_dataset_detail(
|
|
@@ -264,16 +264,23 @@ class SplitsClient:
|
|
|
264
264
|
注意:回退场景(dataset 未注册)下 ``version_scope`` 是 MongoDB 语义,
|
|
265
265
|
OSS 探测无从区分 versioned/unversioned——**忽略 scope 并返回全部探测结果**
|
|
266
266
|
(G4:否则 ap CLI 无 --version 的 split list 恒空)。``version`` 非空时
|
|
267
|
-
仍精确匹配该 version
|
|
267
|
+
仍精确匹配该 version;version 为空时额外包含 split_first 无版本 split
|
|
268
|
+
(version="" 归属)。
|
|
268
269
|
"""
|
|
269
270
|
from ..store.oss_discovery import (
|
|
270
271
|
parse_dataset_level, build_synthetic_split,
|
|
271
272
|
_in_memory_paged, _warn_if_truncated,
|
|
272
273
|
)
|
|
273
274
|
info = parse_dataset_level(
|
|
274
|
-
self._content, dataset, oss_prefix=self._oss_prefix
|
|
275
|
+
self._content, dataset, oss_prefix=self._oss_prefix,
|
|
276
|
+
metadata_model=self._discovery_mm())
|
|
275
277
|
_warn_if_truncated(info, dataset, 500)
|
|
276
278
|
splits: list[DatasetSplit] = []
|
|
279
|
+
# split_first 无版本布局:dataset 根下直接是 split 目录
|
|
280
|
+
if not version:
|
|
281
|
+
for us in info.unversioned_splits:
|
|
282
|
+
splits.append(build_synthetic_split(
|
|
283
|
+
dataset, "", us.name, instance_count=us.instance_count))
|
|
277
284
|
for v in info.versions:
|
|
278
285
|
if version and v.version != version:
|
|
279
286
|
continue
|
|
@@ -295,8 +302,14 @@ class SplitsClient:
|
|
|
295
302
|
parse_dataset_level, build_synthetic_split, _warn_if_truncated,
|
|
296
303
|
)
|
|
297
304
|
info = parse_dataset_level(
|
|
298
|
-
self._content, dataset, oss_prefix=self._oss_prefix
|
|
305
|
+
self._content, dataset, oss_prefix=self._oss_prefix,
|
|
306
|
+
metadata_model=self._discovery_mm())
|
|
299
307
|
_warn_if_truncated(info, dataset, 500)
|
|
308
|
+
if not version:
|
|
309
|
+
for us in info.unversioned_splits:
|
|
310
|
+
if us.name == split_name:
|
|
311
|
+
return build_synthetic_split(
|
|
312
|
+
dataset, "", us.name, instance_count=us.instance_count)
|
|
300
313
|
for v in info.versions:
|
|
301
314
|
if version and v.version != version:
|
|
302
315
|
continue
|
|
@@ -309,6 +322,13 @@ class SplitsClient:
|
|
|
309
322
|
dataset, v.version, split_name)
|
|
310
323
|
return None
|
|
311
324
|
|
|
325
|
+
def _discovery_mm(self) -> str:
|
|
326
|
+
"""OSS 回退探测的布局语义(split_first 默认;version_first 显式切换)。"""
|
|
327
|
+
from ..layout import normalize_metadata_model
|
|
328
|
+
return normalize_metadata_model(
|
|
329
|
+
getattr(self._p, "metadata_model", None)
|
|
330
|
+
if self._p is not None else None)
|
|
331
|
+
|
|
312
332
|
# ── 写 ──
|
|
313
333
|
|
|
314
334
|
def _post_create(self, dataset: str, split: str, version: str,
|
|
@@ -895,9 +895,11 @@ class VersionsClient:
|
|
|
895
895
|
from ..store.oss_discovery import (
|
|
896
896
|
parse_dataset_level, build_synthetic_version, _warn_if_truncated)
|
|
897
897
|
info = parse_dataset_level(
|
|
898
|
-
self._content, dataset, oss_prefix=self._oss_prefix
|
|
898
|
+
self._content, dataset, oss_prefix=self._oss_prefix,
|
|
899
|
+
metadata_model=self._discovery_mm())
|
|
899
900
|
_warn_if_truncated(info, dataset, 500)
|
|
900
|
-
|
|
901
|
+
# split_first 无版本布局(只有 split)也是发现成功,只是没有版本可列
|
|
902
|
+
if not info.versions and not info.unversioned_splits:
|
|
901
903
|
from ..errors import DatasetNotFound
|
|
902
904
|
raise DatasetNotFound(f"dataset {dataset!r} not found in OSS")
|
|
903
905
|
return [build_synthetic_version(dataset, v) for v in info.versions]
|
|
@@ -915,7 +917,8 @@ class VersionsClient:
|
|
|
915
917
|
from ..store.oss_discovery import (
|
|
916
918
|
parse_dataset_level, build_synthetic_version, _warn_if_truncated)
|
|
917
919
|
info = parse_dataset_level(
|
|
918
|
-
self._content, dataset, oss_prefix=self._oss_prefix
|
|
920
|
+
self._content, dataset, oss_prefix=self._oss_prefix,
|
|
921
|
+
metadata_model=self._discovery_mm())
|
|
919
922
|
_warn_if_truncated(info, dataset, 500)
|
|
920
923
|
for v in info.versions:
|
|
921
924
|
if v.version == version:
|
|
@@ -924,6 +927,13 @@ class VersionsClient:
|
|
|
924
927
|
raise DatasetNotFound(
|
|
925
928
|
f"version {version!r} not found in OSS for dataset {dataset!r}")
|
|
926
929
|
|
|
930
|
+
def _discovery_mm(self) -> str:
|
|
931
|
+
"""OSS 回退探测的布局语义(split_first 默认;version_first 显式切换)。"""
|
|
932
|
+
from ..layout import normalize_metadata_model
|
|
933
|
+
return normalize_metadata_model(
|
|
934
|
+
getattr(self._p, "metadata_model", None)
|
|
935
|
+
if self._p is not None else None)
|
|
936
|
+
|
|
927
937
|
|
|
928
938
|
# 与 apiserver `DatasetVersionListItem`(pkg/server/dataset_service.go:315)对齐:
|
|
929
939
|
# 列表项带 instance_count/split_count/updated_at/last_ingested_at,详情接口才带
|
|
@@ -84,7 +84,8 @@ class Repo:
|
|
|
84
84
|
self.datasets = DatasetsClient(
|
|
85
85
|
self.transport,
|
|
86
86
|
content_store=self._content,
|
|
87
|
-
oss_prefix=self.profile.oss_prefix
|
|
87
|
+
oss_prefix=self.profile.oss_prefix,
|
|
88
|
+
metadata_model=self.profile.metadata_model)
|
|
88
89
|
self.versions = VersionsClient(
|
|
89
90
|
self.transport, self.profile,
|
|
90
91
|
content_store=self._content,
|
|
@@ -63,6 +63,14 @@ class OssVersionInfo:
|
|
|
63
63
|
default_instance_count: int = 0
|
|
64
64
|
|
|
65
65
|
|
|
66
|
+
@dataclass
|
|
67
|
+
class OssUnversionedSplit:
|
|
68
|
+
"""split_first 无版本布局:dataset 根下直接是 split 目录(无 version 层)。"""
|
|
69
|
+
name: str
|
|
70
|
+
has_assets: bool # 同层 {name}-assets/ 存在(split 级 content)
|
|
71
|
+
instance_count: int # {name}/ 下直接 .json 数
|
|
72
|
+
|
|
73
|
+
|
|
66
74
|
@dataclass
|
|
67
75
|
class OssDatasetLevelInfo:
|
|
68
76
|
"""Overall dataset structure discovered from OSS directory layout."""
|
|
@@ -70,6 +78,12 @@ class OssDatasetLevelInfo:
|
|
|
70
78
|
versions: list[OssVersionInfo]
|
|
71
79
|
total_instance_count: int
|
|
72
80
|
truncated: bool = False
|
|
81
|
+
# split_first 无版本布局下的 split(version="" 语义)
|
|
82
|
+
unversioned_splits: list[OssUnversionedSplit] = None # type: ignore[assignment]
|
|
83
|
+
|
|
84
|
+
def __post_init__(self):
|
|
85
|
+
if self.unversioned_splits is None:
|
|
86
|
+
self.unversioned_splits = []
|
|
73
87
|
|
|
74
88
|
|
|
75
89
|
# ---------------------------------------------------------------------------
|
|
@@ -185,11 +199,18 @@ def parse_dataset_level(
|
|
|
185
199
|
*,
|
|
186
200
|
oss_prefix: str = "swe/datasets",
|
|
187
201
|
max_versions: int = 500,
|
|
202
|
+
metadata_model: str = "split_first",
|
|
188
203
|
) -> OssDatasetLevelInfo:
|
|
189
204
|
"""Discover version/split structure from OSS directory layout.
|
|
190
205
|
|
|
191
|
-
Performs
|
|
192
|
-
|
|
206
|
+
Performs ``1 + min(N, max_versions)`` LIST calls where *N* is the number
|
|
207
|
+
of Level 1 entries; the per-group probes run concurrently (8-way).
|
|
208
|
+
|
|
209
|
+
语义消歧(``metadata_model``):
|
|
210
|
+
- ``split_first``(SDK 默认):level-1 目录 `X/` 下**只有 .json、无子目录**
|
|
211
|
+
时,`X` 是无版本 split(`{split}/{id}.json` 契约形态);含子目录时是
|
|
212
|
+
version(子目录为其 split)。
|
|
213
|
+
- ``version_first``(显式切换):level-1 目录一律视为 version(旧行为)。
|
|
193
214
|
|
|
194
215
|
Args:
|
|
195
216
|
content_store: :class:`~instance_repo.store.oss.OssContentStore` instance.
|
|
@@ -197,6 +218,8 @@ def parse_dataset_level(
|
|
|
197
218
|
oss_prefix: Root prefix inside the bucket (default ``"swe/datasets"``).
|
|
198
219
|
max_versions: Upper bound on the number of versions to probe. When
|
|
199
220
|
exceeded the result is truncated and ``truncated=True`` is set.
|
|
221
|
+
metadata_model: ``split_first``(默认)or ``version_first``;决定
|
|
222
|
+
level-1 目录的语义归属(见上)。
|
|
200
223
|
|
|
201
224
|
Returns:
|
|
202
225
|
:class:`OssDatasetLevelInfo` with the discovered version/split tree.
|
|
@@ -231,90 +254,104 @@ def parse_dataset_level(
|
|
|
231
254
|
f"dataset {dataset!r} not found in OSS under {root!r}"
|
|
232
255
|
)
|
|
233
256
|
|
|
234
|
-
# -- Group level 1 names into
|
|
257
|
+
# -- Group level 1 names into candidates -------------------------------
|
|
235
258
|
l1_groups = _group_level_names(level1_names)
|
|
236
259
|
|
|
237
|
-
if not l1_groups
|
|
260
|
+
if not l1_groups:
|
|
261
|
+
if level1_json_keys:
|
|
262
|
+
# 实例 .json 直接位于 dataset 根下(无 version/split 层)是**非法布局**:
|
|
263
|
+
# paths.py 契约要求 metadata 至少带 version 层(version_first)或
|
|
264
|
+
# split 层(split_first)。不兼容识别,明确报错引导上传方修正。
|
|
265
|
+
raise DatasetNotFound(
|
|
266
|
+
f"dataset {dataset!r} exists in OSS but has no recognizable "
|
|
267
|
+
f"version/split structure: {len(level1_json_keys)} .json file(s) "
|
|
268
|
+
f"directly under {root!r} (expected {root!r}{{version}}/[{{split}}/] "
|
|
269
|
+
f"layout per paths.py contract)")
|
|
238
270
|
raise DatasetNotFound(
|
|
239
271
|
f"dataset {dataset!r} exists in OSS but has no recognizable "
|
|
240
272
|
f"version/split structure under {root!r}"
|
|
241
273
|
)
|
|
242
274
|
|
|
243
275
|
# Sort for deterministic output.
|
|
244
|
-
|
|
276
|
+
names = sorted(l1_groups.keys())
|
|
245
277
|
|
|
246
278
|
# -- Truncation protection ---------------------------------------------
|
|
247
279
|
truncated = False
|
|
248
|
-
if len(
|
|
249
|
-
|
|
280
|
+
if len(names) > max_versions:
|
|
281
|
+
names = names[:max_versions]
|
|
250
282
|
truncated = True
|
|
251
283
|
|
|
252
|
-
|
|
253
|
-
versions: list[OssVersionInfo] = []
|
|
254
|
-
total_instance_count = 0
|
|
255
|
-
|
|
256
|
-
for v_name in version_names:
|
|
257
|
-
grp = l1_groups[v_name]
|
|
258
|
-
version_dir = f"{root}{v_name}/"
|
|
259
|
-
|
|
260
|
-
# 3-layer content/report siblings at level 1.
|
|
261
|
-
has_three_layer_content = grp.has_assets # {version}-assets/ exists
|
|
284
|
+
split_first = (metadata_model or "split_first") != "version_first"
|
|
262
285
|
|
|
263
|
-
|
|
286
|
+
# -- Level 2: probe each candidate (concurrent) ------------------------
|
|
287
|
+
# 每个 group 的完整分析(level-2 列举 + 逐 split 计数)都在 probe 内完成,
|
|
288
|
+
# 使大 version 数数据集的探测全程并行,避免串行逐 split 计数拖慢整链。
|
|
289
|
+
def probe(name: str):
|
|
290
|
+
"""分析单个 level-1 group,返回 OssVersionInfo / OssUnversionedSplit。"""
|
|
291
|
+
grp = l1_groups[name]
|
|
292
|
+
group_dir = f"{root}{name}/"
|
|
264
293
|
try:
|
|
265
|
-
level2_names = content_store.
|
|
294
|
+
level2_names, level2_keys = content_store.list_level(
|
|
295
|
+
group_dir, list_only=True)
|
|
266
296
|
except Exception: # noqa: BLE001
|
|
267
|
-
level2_names = []
|
|
268
|
-
|
|
297
|
+
level2_names, level2_keys = [], []
|
|
269
298
|
l2_groups = _group_level_names(level2_names)
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
instance_count = len(v_json_keys)
|
|
286
|
-
except Exception: # noqa: BLE001
|
|
287
|
-
has_default_instances = False
|
|
288
|
-
default_instance_count = 0
|
|
289
|
-
instance_count = 0
|
|
290
|
-
|
|
291
|
-
# Count instances in each named split directory.
|
|
299
|
+
direct_json = _direct_json_keys(level2_keys, group_dir)
|
|
300
|
+
subdirs = [g for g in l2_groups.values() if g.has_dir or g.has_assets]
|
|
301
|
+
|
|
302
|
+
# split_first 无版本布局:`{name}/` 下只有 .json、无子目录 →
|
|
303
|
+
# 无版本 split(contract: {split}/{id}.json + {split}-assets/)。
|
|
304
|
+
if split_first and grp.has_dir and not subdirs and direct_json:
|
|
305
|
+
return OssUnversionedSplit(
|
|
306
|
+
name=name,
|
|
307
|
+
has_assets=grp.has_assets,
|
|
308
|
+
instance_count=len(direct_json),
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
# version 路径(version_first 或含子目录的 split_first 形态)。
|
|
312
|
+
splits: list[str] = sorted(g.name for g in subdirs)
|
|
313
|
+
instance_count = len(direct_json)
|
|
292
314
|
for s_name in splits:
|
|
293
|
-
split_dir = f"{
|
|
315
|
+
split_dir = f"{group_dir}{s_name}/"
|
|
294
316
|
try:
|
|
295
317
|
_s_dirs, s_keys = content_store.list_level(
|
|
296
318
|
split_dir, list_only=True)
|
|
297
|
-
|
|
298
|
-
instance_count += len(s_json)
|
|
319
|
+
instance_count += len(_direct_json_keys(s_keys, split_dir))
|
|
299
320
|
except Exception: # noqa: BLE001
|
|
300
321
|
pass # best-effort
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
versions.append(OssVersionInfo(
|
|
305
|
-
version=v_name,
|
|
306
|
-
has_three_layer_content=has_three_layer_content,
|
|
322
|
+
return OssVersionInfo(
|
|
323
|
+
version=name,
|
|
324
|
+
has_three_layer_content=grp.has_assets,
|
|
307
325
|
splits=splits,
|
|
308
|
-
has_default_instances=
|
|
326
|
+
has_default_instances=len(direct_json) > 0,
|
|
309
327
|
instance_count=instance_count,
|
|
310
|
-
default_instance_count=
|
|
311
|
-
)
|
|
328
|
+
default_instance_count=len(direct_json),
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
try:
|
|
332
|
+
from ..concurrency import map_concurrent
|
|
333
|
+
results = map_concurrent(probe, names, concurrency=16)
|
|
334
|
+
except Exception: # noqa: BLE001 - 并发不可用时退化为串行
|
|
335
|
+
results = [probe(n) for n in names]
|
|
336
|
+
|
|
337
|
+
versions: list[OssVersionInfo] = []
|
|
338
|
+
unversioned_splits: list[OssUnversionedSplit] = []
|
|
339
|
+
total_instance_count = 0
|
|
340
|
+
|
|
341
|
+
for entry in results:
|
|
342
|
+
if isinstance(entry, OssUnversionedSplit):
|
|
343
|
+
unversioned_splits.append(entry)
|
|
344
|
+
total_instance_count += entry.instance_count
|
|
345
|
+
else:
|
|
346
|
+
versions.append(entry)
|
|
347
|
+
total_instance_count += entry.instance_count
|
|
312
348
|
|
|
313
349
|
return OssDatasetLevelInfo(
|
|
314
350
|
dataset=dataset,
|
|
315
351
|
versions=versions,
|
|
316
352
|
total_instance_count=total_instance_count,
|
|
317
353
|
truncated=truncated,
|
|
354
|
+
unversioned_splits=unversioned_splits,
|
|
318
355
|
)
|
|
319
356
|
|
|
320
357
|
|
|
@@ -323,9 +360,10 @@ def _warn_if_truncated(info: OssDatasetLevelInfo, dataset: str, max_versions: in
|
|
|
323
360
|
if info.truncated:
|
|
324
361
|
import logging
|
|
325
362
|
logging.getLogger(__name__).warning(
|
|
326
|
-
"dataset %r has more than %d
|
|
363
|
+
"dataset %r has more than %d level-1 entries; OSS discovery results "
|
|
327
364
|
"are truncated (showing %d of >%d)",
|
|
328
|
-
dataset, max_versions,
|
|
365
|
+
dataset, max_versions,
|
|
366
|
+
len(info.versions) + len(info.unversioned_splits), max_versions)
|
|
329
367
|
|
|
330
368
|
|
|
331
369
|
# ---------------------------------------------------------------------------
|
|
@@ -389,6 +427,10 @@ def build_synthetic_dataset_detail(
|
|
|
389
427
|
if v.has_default_instances:
|
|
390
428
|
all_splits.add("default")
|
|
391
429
|
total_instances += v.instance_count
|
|
430
|
+
# split_first 无版本布局:level-1 目录即 split
|
|
431
|
+
for us in info.unversioned_splits:
|
|
432
|
+
all_splits.add(us.name)
|
|
433
|
+
total_instances += us.instance_count
|
|
392
434
|
|
|
393
435
|
available_envs: list[str] = [storage_env] if storage_env else []
|
|
394
436
|
|
|
@@ -450,10 +492,11 @@ def build_synthetic_split(
|
|
|
450
492
|
instance_count: int = 0,
|
|
451
493
|
) -> DatasetSplit:
|
|
452
494
|
"""Build a :class:`DatasetSplit` from OSS discovery (``registered=False``)."""
|
|
495
|
+
base = f"swe/datasets/{dataset}" + (f"/{version}" if version else "")
|
|
453
496
|
if split_name == "default":
|
|
454
|
-
storage_path = f"
|
|
497
|
+
storage_path = f"{base}/"
|
|
455
498
|
else:
|
|
456
|
-
storage_path = f"
|
|
499
|
+
storage_path = f"{base}/{split_name}/"
|
|
457
500
|
|
|
458
501
|
return DatasetSplit(
|
|
459
502
|
dataset=dataset,
|
|
@@ -468,6 +511,16 @@ def build_synthetic_split(
|
|
|
468
511
|
)
|
|
469
512
|
|
|
470
513
|
|
|
514
|
+
def _metadata_prefix(dataset: str, version: str, split: str | None,
|
|
515
|
+
oss_prefix: str) -> str:
|
|
516
|
+
"""拼接 metadata 列举前缀;version 为空时表示 split_first 无版本布局。"""
|
|
517
|
+
l1, l2 = P.split_dataset(dataset)
|
|
518
|
+
base = f"{oss_prefix}/{l1}/{l2}" + (f"/{version}" if version else "")
|
|
519
|
+
if split and split != "default":
|
|
520
|
+
return f"{base}/{split}/"
|
|
521
|
+
return f"{base}/"
|
|
522
|
+
|
|
523
|
+
|
|
471
524
|
def build_synthetic_instances(
|
|
472
525
|
content_store,
|
|
473
526
|
dataset: str,
|
|
@@ -475,20 +528,16 @@ def build_synthetic_instances(
|
|
|
475
528
|
split: str | None = None,
|
|
476
529
|
*,
|
|
477
530
|
oss_prefix: str = "swe/datasets",
|
|
531
|
+
read_content: bool = False,
|
|
478
532
|
) -> list[DatasetInstance]:
|
|
479
533
|
"""List and build :class:`DatasetInstance` objects from OSS metadata JSONs.
|
|
480
534
|
|
|
481
535
|
For each ``{instance_id}.json`` found directly under the target prefix, a
|
|
482
|
-
``DatasetInstance`` is constructed.
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
left at their defaults (best-effort).
|
|
536
|
+
``DatasetInstance`` is constructed. ``read_content=True`` 时尝试读 JSON
|
|
537
|
+
回填 tags/difficulty/docker_image;默认 False——发现模式(list-only STS)
|
|
538
|
+
无 GetObject,逐实例 GET 必然失败,跳过可省 N 次无谓的 STS 签发与下载。
|
|
486
539
|
"""
|
|
487
|
-
|
|
488
|
-
if split and split != "default":
|
|
489
|
-
metadata_prefix = f"{oss_prefix}/{l1}/{l2}/{version}/{split}/"
|
|
490
|
-
else:
|
|
491
|
-
metadata_prefix = f"{oss_prefix}/{l1}/{l2}/{version}/"
|
|
540
|
+
metadata_prefix = _metadata_prefix(dataset, version, split, oss_prefix)
|
|
492
541
|
|
|
493
542
|
all_keys = content_store.list_objects(metadata_prefix, list_only=True)
|
|
494
543
|
json_keys = _direct_json_keys(all_keys, metadata_prefix)
|
|
@@ -503,15 +552,13 @@ def build_synthetic_instances(
|
|
|
503
552
|
split=split or "default",
|
|
504
553
|
registered=False,
|
|
505
554
|
)
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
inst.docker_image = data.get("docker_image")
|
|
514
|
-
inst.extend_meta = data.get("extend_meta", {})
|
|
555
|
+
if read_content:
|
|
556
|
+
data = _read_json_object(content_store, key)
|
|
557
|
+
if data:
|
|
558
|
+
inst.tags = data.get("tags", {})
|
|
559
|
+
inst.difficulty = data.get("difficulty")
|
|
560
|
+
inst.docker_image = data.get("docker_image")
|
|
561
|
+
inst.extend_meta = data.get("extend_meta", {})
|
|
515
562
|
instances.append(inst)
|
|
516
563
|
|
|
517
564
|
return instances
|
|
@@ -525,13 +572,24 @@ def build_synthetic_instance(
|
|
|
525
572
|
split: str | None = None,
|
|
526
573
|
*,
|
|
527
574
|
oss_prefix: str = "swe/datasets",
|
|
575
|
+
read_content: bool = False,
|
|
528
576
|
) -> DatasetInstance | None:
|
|
529
577
|
"""Build a single :class:`DatasetInstance` by exact key lookup in OSS.
|
|
530
578
|
|
|
531
|
-
Returns ``None`` if the metadata JSON does not exist.
|
|
579
|
+
Returns ``None`` if the metadata JSON does not exist. ``read_content``
|
|
580
|
+
语义同 :func:`build_synthetic_instances`(发现模式默认跳过 JSON 回填)。
|
|
532
581
|
"""
|
|
533
|
-
|
|
534
|
-
|
|
582
|
+
if version:
|
|
583
|
+
key = P.metadata_key(
|
|
584
|
+
dataset, version, instance_id, split, prefix=oss_prefix)
|
|
585
|
+
else:
|
|
586
|
+
# split_first 无版本布局:{split}/{id}.json(split=None/default 不合
|
|
587
|
+
# 此形态,调用方须传真实 split 名)
|
|
588
|
+
l1, l2 = P.split_dataset(dataset)
|
|
589
|
+
base = f"{oss_prefix}/{l1}/{l2}"
|
|
590
|
+
key = (f"{base}/{split}/{instance_id}.json"
|
|
591
|
+
if split and split != "default"
|
|
592
|
+
else f"{base}/{instance_id}.json")
|
|
535
593
|
|
|
536
594
|
# 存在性判定用 LIST(list_only=True 仅需 ListObjects)而非 HEAD——
|
|
537
595
|
# list-only STS 无 oss:GetObject,object_exists 的 HEAD 会在 STS 签发或
|
|
@@ -551,11 +609,12 @@ def build_synthetic_instance(
|
|
|
551
609
|
split=split or "default",
|
|
552
610
|
registered=False,
|
|
553
611
|
)
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
612
|
+
if read_content:
|
|
613
|
+
data = _read_json_object(content_store, key)
|
|
614
|
+
if data:
|
|
615
|
+
inst.tags = data.get("tags", {})
|
|
616
|
+
inst.difficulty = data.get("difficulty")
|
|
617
|
+
inst.docker_image = data.get("docker_image")
|
|
618
|
+
inst.extend_meta = data.get("extend_meta", {})
|
|
560
619
|
|
|
561
620
|
return inst
|
|
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.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{instance_repo-1.3.2.dev2 → instance_repo-1.3.2.dev3}/instance_repo.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|