x4d-devkit 0.46.0rc2__tar.gz → 0.46.0rc3__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.
- {x4d_devkit-0.46.0rc2/x4d_devkit.egg-info → x4d_devkit-0.46.0rc3}/PKG-INFO +1 -1
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/pyproject.toml +1 -1
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_clean_basemap.py +98 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_sdk_api.py +1 -1
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/clean_basemap.py +40 -9
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3/x4d_devkit.egg-info}/PKG-INFO +1 -1
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/LICENSE +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/README.md +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/setup.cfg +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_annotation_contract.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_annotation_reference.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_assets_client.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_boundary.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_box.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_build_info.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_clean_basemap_client.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_cli_auth.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_client_json_contract.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_client_projects.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_clip_archives.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_contract_validation.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_coordinate_frames.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_current_state.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_current_state_identity_consumers_example.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_dataset_contract.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_dataset_identity.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_detection_eval.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_evaluate.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_export_bundle.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_image_review.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_inference_input.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_inference_schemas.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_inference_service.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_label_schemas.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_lidar_materialization.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_loader.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_matching.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_metrics.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_models.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_platform_pose.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_preannotation_client.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_reconstruction_client.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_release_gate.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_roadmark_preview.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_semantic_scene_authoring.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_semantic_scene_client.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_semantic_scene_contract.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_semantic_scene_independent.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_semantic_scene_native_clip.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_source_attributes.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_time_contract.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_token.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_tracking_eval.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_training_identity.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_transform.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_transform_chain.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_validation.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_vector_map.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_vector_map_geometry.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_vector_map_session.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_work_session.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_work_session_validation_reuse.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/__init__.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/annotation_contract.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/annotation_reference.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/build_info.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/cli.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/__init__.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/_origin.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/annotation_reference.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/assets.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/bags.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/capabilities.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/checkpoints.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/clean_basemap.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/client.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/clip_work_sessions.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/clips.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/dataset_identity.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/image_review.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/label_schemas.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/preannotation.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/projects.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/reconstruction.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/semantic_scene.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/semantic_scene_authoring.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/services.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/client/test_sets.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/consumer_identity.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/coordinate_contract.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/core/__init__.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/core/loader.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/core/models.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/core/token.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/core/transform.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/current_state.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/dataset_contract.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/dataset_identity.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/eval/__init__.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/eval/api.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/eval/box.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/eval/detection.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/eval/matching.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/eval/metrics.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/eval/tracking.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/export_bundle.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/image_review.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/inference/__init__.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/inference/input.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/inference/models.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/inference/schemas.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/inference/service.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/inference/tasks.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/json_contract.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/label_schema.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/lidar_materialization.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/materialize.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/roadmark_preview.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/semantic_scene_authoring.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/semantic_scene_contract.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/time_contract.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/training_identity.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/validation/__init__.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/validation/contract.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/validation/platform_pose.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/validation/report.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/validation/validator.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/vector_map.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/vector_map_geometry.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit/work_session.py +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit.egg-info/SOURCES.txt +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit.egg-info/dependency_links.txt +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit.egg-info/entry_points.txt +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit.egg-info/requires.txt +0 -0
- {x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/x4d_devkit.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "x4d-devkit"
|
|
7
|
-
version = "0.46.
|
|
7
|
+
version = "0.46.0rc3"
|
|
8
8
|
description = "Official X-4D external SDK and CLI for datasets, platform APIs, training bridges, and automation"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -3,6 +3,7 @@ import copy
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
import pytest
|
|
5
5
|
import zstandard
|
|
6
|
+
import x4d_devkit.clean_basemap as clean_basemap
|
|
6
7
|
|
|
7
8
|
from tests.semantic_scene_contract_fixtures import current_semantic_scene_component
|
|
8
9
|
from x4d_devkit.clean_basemap import (
|
|
@@ -189,6 +190,103 @@ def test_complete_scene_and_exact_original_observation_roundtrip():
|
|
|
189
190
|
parsed.data["profile"]["voxel_size_m"] = 1
|
|
190
191
|
|
|
191
192
|
|
|
193
|
+
def test_decision_proof_reuse_is_within_one_validation_call(monkeypatch):
|
|
194
|
+
manifest, assets, _ = fixture()
|
|
195
|
+
decoded = []
|
|
196
|
+
original = clean_basemap.decode_clean_basemap_decisions
|
|
197
|
+
|
|
198
|
+
def count(*args, **kwargs):
|
|
199
|
+
result = original(*args, **kwargs)
|
|
200
|
+
assert not result.flags.writeable
|
|
201
|
+
decoded.append(result.nbytes)
|
|
202
|
+
return result
|
|
203
|
+
|
|
204
|
+
monkeypatch.setattr(clean_basemap, "decode_clean_basemap_decisions", count)
|
|
205
|
+
validate(manifest, assets)
|
|
206
|
+
assert decoded == [5]
|
|
207
|
+
validate(manifest, assets)
|
|
208
|
+
assert decoded == [5, 5]
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@pytest.mark.parametrize("changed", [b"tampered", bytearray, memoryview])
|
|
212
|
+
def test_cached_decision_proof_still_checks_every_carrier_read(changed):
|
|
213
|
+
manifest, assets, _ = fixture()
|
|
214
|
+
original = original_points(manifest, assets)
|
|
215
|
+
path = manifest["sweep_sources"][0]["decisions"]["path"]
|
|
216
|
+
reads = 0
|
|
217
|
+
|
|
218
|
+
def read_asset(name):
|
|
219
|
+
nonlocal reads
|
|
220
|
+
body = assets[name]
|
|
221
|
+
if name == path:
|
|
222
|
+
reads += 1
|
|
223
|
+
if reads > 1:
|
|
224
|
+
return changed(body) if callable(changed) else changed
|
|
225
|
+
return body
|
|
226
|
+
|
|
227
|
+
with pytest.raises(ValueError, match="payload size/hash"):
|
|
228
|
+
validate_clean_basemap_resource(
|
|
229
|
+
manifest,
|
|
230
|
+
read_asset=read_asset,
|
|
231
|
+
observation_to_world=lambda sweep, ordinals, times: original[ordinals],
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def add_second_sweep(manifest, assets):
|
|
236
|
+
source = copy.deepcopy(manifest["sweep_sources"][0])
|
|
237
|
+
source.update(sample_data_token="sweep-1", asset_sha256="sha256:" + "c" * 64)
|
|
238
|
+
carrier = encode_clean_basemap_decisions(
|
|
239
|
+
asset_sha256=source["asset_sha256"], decisions=[1, 0, 3, 18, 33]
|
|
240
|
+
)
|
|
241
|
+
source["decisions"] = carrier.descriptor("decisions")
|
|
242
|
+
assets[source["decisions"]["path"]] = carrier.payload
|
|
243
|
+
manifest["sweep_sources"].append(source)
|
|
244
|
+
manifest["diagnostics"]["source_point_count"] *= 2
|
|
245
|
+
manifest["diagnostics"]["decision_counts"] = {
|
|
246
|
+
key: value * 2
|
|
247
|
+
for key, value in manifest["diagnostics"]["decision_counts"].items()
|
|
248
|
+
}
|
|
249
|
+
manifest["basemap_revision"] = compute_clean_basemap_revision(manifest)
|
|
250
|
+
return source
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
@pytest.mark.parametrize("changed", ["source", "count", "descriptor"])
|
|
254
|
+
def test_decision_cache_never_reuses_a_different_binding(changed):
|
|
255
|
+
manifest, assets, _ = fixture()
|
|
256
|
+
second = add_second_sweep(manifest, assets)
|
|
257
|
+
second["decisions"] = copy.deepcopy(manifest["sweep_sources"][0]["decisions"])
|
|
258
|
+
if changed != "source":
|
|
259
|
+
second["asset_sha256"] = manifest["sweep_sources"][0]["asset_sha256"]
|
|
260
|
+
if changed == "count":
|
|
261
|
+
second["point_count"] += 1
|
|
262
|
+
manifest["diagnostics"]["source_point_count"] += 1
|
|
263
|
+
manifest["diagnostics"]["decision_counts"]["33"] += 1
|
|
264
|
+
if changed == "descriptor":
|
|
265
|
+
second["decisions"]["size_bytes"] += 1
|
|
266
|
+
manifest["basemap_revision"] = compute_clean_basemap_revision(manifest)
|
|
267
|
+
with pytest.raises(ValueError):
|
|
268
|
+
validate(manifest, assets)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
@pytest.mark.parametrize("limit,expected_decodes", [(0, 3), (4, 3), (5, 3), (10, 2)])
|
|
272
|
+
def test_decision_proof_cache_is_bounded_and_evicted_entries_are_revalidated(
|
|
273
|
+
monkeypatch, limit, expected_decodes
|
|
274
|
+
):
|
|
275
|
+
manifest, assets, _ = fixture()
|
|
276
|
+
add_second_sweep(manifest, assets)
|
|
277
|
+
original = clean_basemap.decode_clean_basemap_decisions
|
|
278
|
+
calls = []
|
|
279
|
+
|
|
280
|
+
def count(*args, **kwargs):
|
|
281
|
+
calls.append(kwargs["asset_sha256"])
|
|
282
|
+
return original(*args, **kwargs)
|
|
283
|
+
|
|
284
|
+
monkeypatch.setattr(clean_basemap, "_DECISION_CACHE_BYTES", limit)
|
|
285
|
+
monkeypatch.setattr(clean_basemap, "decode_clean_basemap_decisions", count)
|
|
286
|
+
validate(manifest, assets)
|
|
287
|
+
assert len(calls) == expected_decodes
|
|
288
|
+
|
|
289
|
+
|
|
192
290
|
@pytest.mark.parametrize(
|
|
193
291
|
"overrides,message",
|
|
194
292
|
[
|
|
@@ -11,7 +11,7 @@ from x4d_devkit.eval.matching import MetricData
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def test_package_version_is_current_release():
|
|
14
|
-
assert x4d_devkit.__version__ == "0.46.
|
|
14
|
+
assert x4d_devkit.__version__ == "0.46.0rc3"
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def test_loader_exposes_and_enforces_only_current_schema(tmp_path):
|
|
@@ -7,6 +7,7 @@ their native authorities; this module never guesses ownership from coordinates.
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
import copy
|
|
10
|
+
from collections import OrderedDict
|
|
10
11
|
from dataclasses import dataclass
|
|
11
12
|
import math
|
|
12
13
|
import re
|
|
@@ -39,6 +40,7 @@ CLEAN_BASEMAP_CONTRACT_VERSION = "x4d-clean-static-basemap-v4"
|
|
|
39
40
|
CLEAN_BASEMAP_OPERATION = "reconstruction.prepare_clean_static_basemap"
|
|
40
41
|
CLEAN_BASEMAP_MAPPING_FORMAT = "x4d-clean-static-basemap-mapping-v2"
|
|
41
42
|
CLEAN_BASEMAP_DECISION_FORMAT = "x4d-clean-static-basemap-decisions-v3"
|
|
43
|
+
_DECISION_CACHE_BYTES = 128 << 20
|
|
42
44
|
CLEAN_BASEMAP_INPUT_FIELDS = frozenset(
|
|
43
45
|
{"samples_revision", "sweeps_revision", "calibration_revision", "pose_revision"}
|
|
44
46
|
)
|
|
@@ -611,13 +613,47 @@ def validate_clean_basemap_resource(
|
|
|
611
613
|
for sweep in data["sweep_sources"]
|
|
612
614
|
]
|
|
613
615
|
actual_counts = {str(code): 0 for code in DECISION_CODES}
|
|
614
|
-
|
|
616
|
+
decisions_cache = OrderedDict()
|
|
617
|
+
decisions_bytes = 0
|
|
618
|
+
|
|
619
|
+
def read_decisions(sweep):
|
|
620
|
+
nonlocal decisions_bytes
|
|
621
|
+
descriptor = sweep["decisions"]
|
|
622
|
+
payload = read_asset(descriptor["path"])
|
|
623
|
+
# A cached proof never authorizes changed or non-byte carrier data.
|
|
624
|
+
if (
|
|
625
|
+
type(payload) is not bytes
|
|
626
|
+
or len(payload) != descriptor["size_bytes"]
|
|
627
|
+
or sha256_bytes(payload) != descriptor["sha256"]
|
|
628
|
+
):
|
|
629
|
+
raise ValueError(
|
|
630
|
+
"clean basemap payload size/hash does not match descriptor"
|
|
631
|
+
)
|
|
632
|
+
key = (
|
|
633
|
+
tuple(sorted(descriptor.items())),
|
|
634
|
+
sweep["asset_sha256"],
|
|
635
|
+
sweep["point_count"],
|
|
636
|
+
)
|
|
637
|
+
values = decisions_cache.pop(key, None)
|
|
638
|
+
if values is not None:
|
|
639
|
+
decisions_cache[key] = values
|
|
640
|
+
return values
|
|
615
641
|
values = decode_clean_basemap_decisions(
|
|
616
|
-
|
|
617
|
-
descriptor=
|
|
642
|
+
payload,
|
|
643
|
+
descriptor=descriptor,
|
|
618
644
|
asset_sha256=sweep["asset_sha256"],
|
|
619
645
|
point_count=sweep["point_count"],
|
|
620
646
|
)
|
|
647
|
+
if values.nbytes <= _DECISION_CACHE_BYTES:
|
|
648
|
+
while decisions_bytes + values.nbytes > _DECISION_CACHE_BYTES:
|
|
649
|
+
_, evicted = decisions_cache.popitem(last=False)
|
|
650
|
+
decisions_bytes -= evicted.nbytes
|
|
651
|
+
decisions_cache[key] = values
|
|
652
|
+
decisions_bytes += values.nbytes
|
|
653
|
+
return values
|
|
654
|
+
|
|
655
|
+
for sweep in data["sweep_sources"]:
|
|
656
|
+
values = read_decisions(sweep)
|
|
621
657
|
counts = np.bincount(values, minlength=256)
|
|
622
658
|
for code in DECISION_CODES:
|
|
623
659
|
actual_counts[str(code)] += int(counts[code])
|
|
@@ -661,12 +697,7 @@ def validate_clean_basemap_resource(
|
|
|
661
697
|
if np.any(times < low) or np.any(times > high):
|
|
662
698
|
raise ValueError("mapping exact point time is outside its source sweep")
|
|
663
699
|
_mark_unique(observation_seen[index], ordinals, "original observation")
|
|
664
|
-
values =
|
|
665
|
-
read_asset(sweep["decisions"]["path"]),
|
|
666
|
-
descriptor=sweep["decisions"],
|
|
667
|
-
asset_sha256=sweep["asset_sha256"],
|
|
668
|
-
point_count=sweep["point_count"],
|
|
669
|
-
)
|
|
700
|
+
values = read_decisions(sweep)
|
|
670
701
|
if not np.array_equal(values[ordinals], mapping["decision"][selected]):
|
|
671
702
|
raise ValueError(
|
|
672
703
|
"mapping decision does not match its original observation"
|
|
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
|
{x4d_devkit-0.46.0rc2 → x4d_devkit-0.46.0rc3}/tests/test_current_state_identity_consumers_example.py
RENAMED
|
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
|
|
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
|
|
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
|