x4d-devkit 0.53.0rc1__tar.gz → 0.53.0rc2__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 (172) hide show
  1. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/PKG-INFO +1 -1
  2. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/pyproject.toml +1 -1
  3. x4d_devkit-0.53.0rc2/tests/test_image_schema_registry_client.py +161 -0
  4. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_sdk_api.py +1 -1
  5. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/__init__.py +7 -1
  6. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/client.py +16 -0
  7. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/image_schemas.py +155 -1
  8. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit.egg-info/PKG-INFO +1 -1
  9. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit.egg-info/SOURCES.txt +1 -0
  10. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/LICENSE +0 -0
  11. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/README.md +0 -0
  12. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/setup.cfg +0 -0
  13. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_accounts.py +0 -0
  14. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_annotation_contract.py +0 -0
  15. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_annotation_document_hash.py +0 -0
  16. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_annotation_reference.py +0 -0
  17. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_assets_client.py +0 -0
  18. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_boundary.py +0 -0
  19. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_box.py +0 -0
  20. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_build_info.py +0 -0
  21. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_category_audit.py +0 -0
  22. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_clean_basemap.py +0 -0
  23. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_clean_basemap_client.py +0 -0
  24. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_cli_auth.py +0 -0
  25. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_client_json_contract.py +0 -0
  26. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_client_projects.py +0 -0
  27. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_clip_archives.py +0 -0
  28. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_contract_validation.py +0 -0
  29. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_coordinate_frames.py +0 -0
  30. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_current_state.py +0 -0
  31. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_current_state_identity_consumers_example.py +0 -0
  32. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_dataset_contract.py +0 -0
  33. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_dataset_identity.py +0 -0
  34. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_detection_eval.py +0 -0
  35. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_evaluate.py +0 -0
  36. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_export_bundle.py +0 -0
  37. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_image_clip.py +0 -0
  38. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_image_conditional_rules.py +0 -0
  39. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_image_enum_set.py +0 -0
  40. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_image_export.py +0 -0
  41. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_image_geometry.py +0 -0
  42. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_image_groups.py +0 -0
  43. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_image_preannotation.py +0 -0
  44. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_image_reference.py +0 -0
  45. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_image_review.py +0 -0
  46. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_image_schema_migration.py +0 -0
  47. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_image_schema_upgrade.py +0 -0
  48. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_image_work_session.py +0 -0
  49. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_inference_input.py +0 -0
  50. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_inference_schemas.py +0 -0
  51. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_inference_service.py +0 -0
  52. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_label_schemas.py +0 -0
  53. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_lidar_materialization.py +0 -0
  54. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_loader.py +0 -0
  55. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_matching.py +0 -0
  56. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_metrics.py +0 -0
  57. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_models.py +0 -0
  58. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_parse_equivalence.py +0 -0
  59. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_platform_pose.py +0 -0
  60. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_preannotation_client.py +0 -0
  61. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_project_discovery.py +0 -0
  62. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_reconstruction_client.py +0 -0
  63. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_release_gate.py +0 -0
  64. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_roadmark_preview.py +0 -0
  65. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_semantic_scene_authoring.py +0 -0
  66. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_semantic_scene_client.py +0 -0
  67. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_semantic_scene_contract.py +0 -0
  68. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_semantic_scene_independent.py +0 -0
  69. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_semantic_scene_native_clip.py +0 -0
  70. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_source_attributes.py +0 -0
  71. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_time_contract.py +0 -0
  72. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_token.py +0 -0
  73. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_tracking_eval.py +0 -0
  74. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_training_identity.py +0 -0
  75. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_transform.py +0 -0
  76. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_transform_chain.py +0 -0
  77. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_validation.py +0 -0
  78. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_vector_map.py +0 -0
  79. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_vector_map_geometry.py +0 -0
  80. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_vector_map_session.py +0 -0
  81. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_work_session.py +0 -0
  82. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/tests/test_work_session_validation_reuse.py +0 -0
  83. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/__init__.py +0 -0
  84. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/_image_contract.py +0 -0
  85. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/accounts.py +0 -0
  86. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/annotation_contract.py +0 -0
  87. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/annotation_reference.py +0 -0
  88. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/audit.py +0 -0
  89. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/build_info.py +0 -0
  90. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/clean_basemap.py +0 -0
  91. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/cli.py +0 -0
  92. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/_origin.py +0 -0
  93. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/accounts.py +0 -0
  94. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/annotation_reference.py +0 -0
  95. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/assets.py +0 -0
  96. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/bags.py +0 -0
  97. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/capabilities.py +0 -0
  98. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/checkpoints.py +0 -0
  99. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/clean_basemap.py +0 -0
  100. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/clip_work_sessions.py +0 -0
  101. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/clips.py +0 -0
  102. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/dataset_identity.py +0 -0
  103. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/image_clips.py +0 -0
  104. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/image_exports.py +0 -0
  105. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/image_preannotations.py +0 -0
  106. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/image_review.py +0 -0
  107. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/image_work_sessions.py +0 -0
  108. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/label_schemas.py +0 -0
  109. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/preannotation.py +0 -0
  110. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/projects.py +0 -0
  111. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/reconstruction.py +0 -0
  112. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/semantic_scene.py +0 -0
  113. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/semantic_scene_authoring.py +0 -0
  114. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/services.py +0 -0
  115. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/client/test_sets.py +0 -0
  116. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/consumer_identity.py +0 -0
  117. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/coordinate_contract.py +0 -0
  118. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/core/__init__.py +0 -0
  119. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/core/loader.py +0 -0
  120. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/core/models.py +0 -0
  121. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/core/token.py +0 -0
  122. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/core/transform.py +0 -0
  123. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/current_state.py +0 -0
  124. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/dataset_contract.py +0 -0
  125. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/dataset_identity.py +0 -0
  126. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/eval/__init__.py +0 -0
  127. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/eval/api.py +0 -0
  128. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/eval/box.py +0 -0
  129. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/eval/detection.py +0 -0
  130. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/eval/matching.py +0 -0
  131. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/eval/metrics.py +0 -0
  132. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/eval/tracking.py +0 -0
  133. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/export_bundle.py +0 -0
  134. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/image_clip.py +0 -0
  135. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/image_export.py +0 -0
  136. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/image_geometry.py +0 -0
  137. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/image_groups.py +0 -0
  138. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/image_preannotation.py +0 -0
  139. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/image_reference.py +0 -0
  140. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/image_review.py +0 -0
  141. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/image_schema.py +0 -0
  142. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/image_schema_migration.py +0 -0
  143. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/image_schema_upgrade.py +0 -0
  144. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/image_work_session.py +0 -0
  145. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/inference/__init__.py +0 -0
  146. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/inference/input.py +0 -0
  147. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/inference/models.py +0 -0
  148. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/inference/schemas.py +0 -0
  149. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/inference/service.py +0 -0
  150. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/inference/tasks.py +0 -0
  151. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/json_contract.py +0 -0
  152. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/label_schema.py +0 -0
  153. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/lidar_materialization.py +0 -0
  154. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/materialize.py +0 -0
  155. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/project_discovery.py +0 -0
  156. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/roadmark_preview.py +0 -0
  157. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/semantic_scene_authoring.py +0 -0
  158. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/semantic_scene_contract.py +0 -0
  159. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/time_contract.py +0 -0
  160. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/training_identity.py +0 -0
  161. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/validation/__init__.py +0 -0
  162. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/validation/contract.py +0 -0
  163. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/validation/platform_pose.py +0 -0
  164. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/validation/report.py +0 -0
  165. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/validation/validator.py +0 -0
  166. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/vector_map.py +0 -0
  167. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/vector_map_geometry.py +0 -0
  168. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit/work_session.py +0 -0
  169. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit.egg-info/dependency_links.txt +0 -0
  170. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit.egg-info/entry_points.txt +0 -0
  171. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit.egg-info/requires.txt +0 -0
  172. {x4d_devkit-0.53.0rc1 → x4d_devkit-0.53.0rc2}/x4d_devkit.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: x4d-devkit
3
- Version: 0.53.0rc1
3
+ Version: 0.53.0rc2
4
4
  Summary: Official X-4D external SDK and CLI for datasets, platform APIs, training bridges, and automation
5
5
  Author: windzu
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "x4d-devkit"
7
- version = "0.53.0rc1"
7
+ version = "0.53.0rc2"
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"
@@ -0,0 +1,161 @@
1
+ """Typed image Schema authoring against a strict in-memory registry."""
2
+
3
+ from copy import deepcopy
4
+ import hashlib
5
+ import json
6
+
7
+ import httpx
8
+ import pytest
9
+
10
+ from x4d_devkit import X4DClient
11
+ from x4d_devkit._image_contract import canonical
12
+ from x4d_devkit.image_schema import parse_image_schema_body
13
+ from tests.image_fixtures import schema_body
14
+
15
+
16
+ def etag(value):
17
+ return '"sha256:' + hashlib.sha256(canonical(value)).hexdigest() + '"'
18
+
19
+
20
+ class Registry:
21
+ def __init__(self):
22
+ self.rows = {}
23
+ self.project = None
24
+ self.tamper = None
25
+
26
+ def record(self, body, status):
27
+ return {
28
+ "contract_version": "x4d-image-label-schema-record-v1",
29
+ "status": status,
30
+ "body": body,
31
+ "fingerprint": parse_image_schema_body(body).identity.fingerprint,
32
+ }
33
+
34
+ def reply(self, value, status=200):
35
+ if self.tamper:
36
+ value = self.tamper(deepcopy(value))
37
+ return httpx.Response(status, json=value, headers={"ETag": etag(value)})
38
+
39
+ def __call__(self, request):
40
+ path = request.url.path.removeprefix("/api/v1")
41
+ body = json.loads(request.content) if request.content else None
42
+ match = request.headers.get("If-Match")
43
+ if path == "/image-schemas/validate":
44
+ return httpx.Response(200, json=self.record(body["body"], "draft"))
45
+ if path == "/label-schemas" and request.method == "POST":
46
+ key = (body["body"]["schema_id"], body["body"]["version"])
47
+ self.rows[key] = self.record(body["body"], "draft")
48
+ return self.reply(self.rows[key], 201)
49
+ if path.startswith("/label-schemas/"):
50
+ _, _, schema_id, _, version, *action = path.split("/")
51
+ row = self.rows[(schema_id, version)]
52
+ if request.method == "GET":
53
+ return self.reply(row)
54
+ if match != etag(row):
55
+ return httpx.Response(412, json={"detail": "changed"})
56
+ if request.method == "DELETE":
57
+ del self.rows[(schema_id, version)]
58
+ return httpx.Response(204)
59
+ if action == ["publish"]:
60
+ row["status"] = "active"
61
+ elif action == ["deprecate"]:
62
+ row["status"] = "deprecated"
63
+ else:
64
+ row["body"] = body["body"]
65
+ row["fingerprint"] = parse_image_schema_body(body["body"]).identity.fingerprint
66
+ return self.reply(row)
67
+ if path == "/projects/7/label-schema":
68
+ if request.method == "PUT":
69
+ if match != etag(self.project):
70
+ return httpx.Response(412, json={"detail": "changed"})
71
+ self.project = {**self.project, "label_schema": self.rows[(body["schema_id"], body["version"])]}
72
+ return self.reply(self.project)
73
+ raise AssertionError(path)
74
+
75
+
76
+ @pytest.fixture
77
+ def setup():
78
+ registry = Registry()
79
+ with X4DClient("http://x4d.test", token="test") as client:
80
+ client._http.close()
81
+ client._http = httpx.Client(base_url="http://x4d.test", transport=httpx.MockTransport(registry))
82
+ yield client.image_schemas, registry
83
+
84
+
85
+ def draft_body(version="2.0.0"):
86
+ body = schema_body()
87
+ body["version"] = version
88
+ return body
89
+
90
+
91
+ def test_draft_update_publish_and_bind_round_trip(setup):
92
+ api, registry = setup
93
+ body = draft_body()
94
+ assert api.validate(body).to_dict()["status"] == "draft"
95
+ entry = api.create_draft(body)
96
+ assert entry.record.to_dict()["status"] == "draft"
97
+ edited = deepcopy(body)
98
+ edited["description"] = "Edited draft"
99
+ entry = api.update_draft(edited, etag=entry.etag)
100
+ assert entry.record.body["description"] == "Edited draft"
101
+ assert api.get_entry(schema_id="test_image", version="2.0.0") == entry
102
+ entry = api.publish(entry)
103
+ assert entry.record.to_dict()["status"] == "active"
104
+ registry.project = {
105
+ "contract_version": "x4d-image-project-label-schema-v1",
106
+ "project_id": 7,
107
+ "label_schema": registry.record(schema_body(), "active"),
108
+ }
109
+ project = api.get_project_entry(7)
110
+ bound = api.bind_project(project, schema_id="test_image", version="2.0.0")
111
+ assert bound.value.to_dict()["label_schema"]["body"]["version"] == "2.0.0"
112
+ deprecated = api.deprecate(entry, reason="replaced")
113
+ assert deprecated.record.to_dict()["status"] == "deprecated"
114
+
115
+
116
+ def test_stale_etag_is_rejected_by_the_server(setup):
117
+ api, _ = setup
118
+ first = api.create_draft(draft_body())
119
+ api.update_draft({**draft_body(), "description": "one"}, etag=first.etag)
120
+ with pytest.raises(httpx.HTTPStatusError):
121
+ api.update_draft({**draft_body(), "description": "two"}, etag=first.etag)
122
+
123
+
124
+ def test_delete_draft_needs_the_current_etag(setup):
125
+ api, registry = setup
126
+ entry = api.create_draft(draft_body())
127
+ api.delete_draft(entry)
128
+ assert registry.rows == {}
129
+
130
+
131
+ def test_invalid_body_never_reaches_the_server(setup):
132
+ api, registry = setup
133
+ body = draft_body()
134
+ body["categories"][0]["geometry_type"] = "circle"
135
+ with pytest.raises(ValueError):
136
+ api.create_draft(body)
137
+ assert registry.rows == {}
138
+
139
+
140
+ @pytest.mark.parametrize("field", ["status", "body"])
141
+ def test_a_response_for_another_record_or_lifecycle_is_rejected(setup, field):
142
+ api, registry = setup
143
+ entry = api.create_draft(draft_body())
144
+
145
+ def tamper(value):
146
+ if field == "status":
147
+ value["status"] = "draft"
148
+ else:
149
+ value["body"]["description"] = "something else"
150
+ value["fingerprint"] = parse_image_schema_body(value["body"]).identity.fingerprint
151
+ return value
152
+
153
+ registry.tamper = tamper
154
+ with pytest.raises(ValueError, match="another Schema"):
155
+ api.publish(entry)
156
+
157
+
158
+ def test_a_weak_or_missing_etag_is_refused_locally(setup):
159
+ api, _ = setup
160
+ with pytest.raises(ValueError, match="strong ETag"):
161
+ api.update_draft(draft_body(), etag="W/\"x\"")
@@ -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.53.0rc1"
14
+ assert x4d_devkit.__version__ == "0.53.0rc2"
15
15
 
16
16
 
17
17
  def test_loader_exposes_and_enforces_only_current_schema(tmp_path):
@@ -43,9 +43,15 @@ from x4d_devkit.client.reconstruction import (
43
43
  from x4d_devkit.client.services import ServicesAPI
44
44
  from x4d_devkit.client.test_sets import TestSetsAPI
45
45
 
46
- from x4d_devkit.client.image_schemas import ImageSchemasAPI
46
+ from x4d_devkit.client.image_schemas import (
47
+ ImageProjectSchemaEntry,
48
+ ImageSchemaEntry,
49
+ ImageSchemasAPI,
50
+ )
47
51
 
48
52
  __all__ = [
53
+ "ImageProjectSchemaEntry",
54
+ "ImageSchemaEntry",
49
55
  "ImageSchemasAPI",
50
56
  "ImageWorkSessionsAPI",
51
57
  "ImageExportsAPI",
@@ -173,6 +173,22 @@ class X4DClient:
173
173
  resp.raise_for_status()
174
174
  return parse_i_json(resp.content, path=f"POST {self._url(path)} response")
175
175
 
176
+ def put(self, path: str, **kwargs):
177
+ resp = self._http.put(self._url(path), **kwargs)
178
+ resp.raise_for_status()
179
+ return parse_i_json(resp.content, path=f"PUT {self._url(path)} response")
180
+
181
+ def exchange(self, method: str, path: str, **kwargs):
182
+ """One request returning ``(strict JSON or None for 204, ETag or None)``."""
183
+ resp = self._http.request(method, self._url(path), **kwargs)
184
+ resp.raise_for_status()
185
+ value = (
186
+ parse_i_json(resp.content, path=f"{method} {self._url(path)} response")
187
+ if resp.content
188
+ else None
189
+ )
190
+ return value, resp.headers.get("ETag")
191
+
176
192
  def delete(self, path: str, **kwargs):
177
193
  resp = self._http.delete(self._url(path), **kwargs)
178
194
  resp.raise_for_status()
@@ -1,7 +1,12 @@
1
1
  """Separate native image registry reads and explicit admin upgrade/migration adapters."""
2
2
 
3
- from x4d_devkit._image_contract import fields, integer, require
3
+ from dataclasses import dataclass
4
+ import re
5
+
6
+ from x4d_devkit._image_contract import ImageDocument, fields, integer, require, text
4
7
  from x4d_devkit.image_schema import (
8
+ ImageSchemaRecord,
9
+ parse_image_schema_body,
5
10
  parse_image_schema_record,
6
11
  parse_image_project_schema,
7
12
  )
@@ -23,6 +28,39 @@ from x4d_devkit.image_schema_migration import (
23
28
  from x4d_devkit.label_schema import LabelSchemaBinding
24
29
 
25
30
 
31
+ _STRONG_ETAG = re.compile(r'"sha256:[0-9a-f]{64}"')
32
+
33
+
34
+ @dataclass(frozen=True)
35
+ class ImageSchemaEntry:
36
+ """A registry record with the strong ETag its next write must match."""
37
+
38
+ record: ImageSchemaRecord
39
+ etag: str
40
+
41
+
42
+ @dataclass(frozen=True)
43
+ class ImageProjectSchemaEntry:
44
+ """A project's image Schema binding with its strong ETag."""
45
+
46
+ value: ImageDocument
47
+ etag: str
48
+
49
+
50
+ def _etag(value, path):
51
+ require(
52
+ type(value) is str and _STRONG_ETAG.fullmatch(value) is not None,
53
+ "Registry write requires a strong ETag",
54
+ path,
55
+ )
56
+ return value
57
+
58
+
59
+ def _version_path(schema_id, version):
60
+ LabelSchemaBinding(schema_id, version)
61
+ return f"/label-schemas/{schema_id}/versions/{version}"
62
+
63
+
26
64
  class ImageSchemasAPI:
27
65
  def __init__(self, client):
28
66
  self._client = client
@@ -161,3 +199,119 @@ class ImageSchemasAPI:
161
199
 
162
200
  def migration_request(self, preview, idempotency_key):
163
201
  return build_image_schema_migration_request(preview, idempotency_key)
202
+
203
+ # Registry authoring. The server validates with the same Devkit; every
204
+ # response is checked to be exactly the requested record and lifecycle.
205
+
206
+ def _entry(self, method, path, *, expect, status, etag=None, **kwargs):
207
+ headers = {"If-Match": _etag(etag, "image_schemas.etag")} if etag else None
208
+ value, returned = self._client.exchange(method, path, headers=headers, **kwargs)
209
+ record = parse_image_schema_record(value)
210
+ require(
211
+ record.body == expect and record.to_dict()["status"] == status,
212
+ "Registry returned another Schema or lifecycle",
213
+ "image_schemas.record",
214
+ )
215
+ return ImageSchemaEntry(record, _etag(returned, "image_schemas.response_etag"))
216
+
217
+ def validate(self, body):
218
+ """Server-side validation preview; returns the would-be draft record."""
219
+ expect = parse_image_schema_body(body).to_dict()
220
+ record = parse_image_schema_record(
221
+ self._client.post("/image-schemas/validate", json={"body": expect})
222
+ )
223
+ require(
224
+ record.body == expect and record.to_dict()["status"] == "draft",
225
+ "Validation returned another Schema",
226
+ "image_schemas.validate",
227
+ )
228
+ return record
229
+
230
+ def get_entry(self, *, schema_id, version):
231
+ value, etag = self._client.exchange("GET", _version_path(schema_id, version))
232
+ record = parse_image_schema_record(value)
233
+ require(
234
+ (record.schema_id, record.version) == (schema_id, version),
235
+ "Registry returned another Schema",
236
+ "image_schemas.identity",
237
+ )
238
+ return ImageSchemaEntry(record, _etag(etag, "image_schemas.response_etag"))
239
+
240
+ def create_draft(self, body):
241
+ expect = parse_image_schema_body(body).to_dict()
242
+ return self._entry(
243
+ "POST", "/label-schemas", expect=expect, status="draft", json={"body": expect}
244
+ )
245
+
246
+ def update_draft(self, body, *, etag):
247
+ expect = parse_image_schema_body(body).to_dict()
248
+ return self._entry(
249
+ "PUT",
250
+ _version_path(expect["schema_id"], expect["version"]),
251
+ expect=expect,
252
+ status="draft",
253
+ etag=etag,
254
+ json={"body": expect},
255
+ )
256
+
257
+ def publish(self, entry):
258
+ """Publish exactly the draft in ``entry``; published versions are immutable."""
259
+ body = entry.record.body
260
+ return self._entry(
261
+ "POST",
262
+ _version_path(body["schema_id"], body["version"]) + "/publish",
263
+ expect=body,
264
+ status="active",
265
+ etag=entry.etag,
266
+ )
267
+
268
+ def deprecate(self, entry, *, reason):
269
+ body = entry.record.body
270
+ return self._entry(
271
+ "POST",
272
+ _version_path(body["schema_id"], body["version"]) + "/deprecate",
273
+ expect=body,
274
+ status="deprecated",
275
+ etag=entry.etag,
276
+ json={"reason": text(reason, "image_schemas.reason")},
277
+ )
278
+
279
+ def delete_draft(self, entry):
280
+ body = entry.record.body
281
+ value, _ = self._client.exchange(
282
+ "DELETE",
283
+ _version_path(body["schema_id"], body["version"]),
284
+ headers={"If-Match": _etag(entry.etag, "image_schemas.etag")},
285
+ )
286
+ require(value is None, "Draft deletion returns no document", "image_schemas.delete")
287
+
288
+ def get_project_entry(self, project_id):
289
+ integer(project_id, "project_id", minimum=1)
290
+ value, etag = self._client.exchange("GET", f"/projects/{project_id}/label-schema")
291
+ parsed = parse_image_project_schema(value)
292
+ require(parsed.to_dict()["project_id"] == project_id, "Registry returned another project", "image_schemas.project_id")
293
+ return ImageProjectSchemaEntry(parsed, _etag(etag, "image_schemas.response_etag"))
294
+
295
+ def bind_project(self, project_entry, *, schema_id, version):
296
+ """Make an active version the project default; existing Clips keep theirs."""
297
+ project_id = project_entry.value.to_dict()["project_id"]
298
+ LabelSchemaBinding(schema_id, version)
299
+ value, etag = self._client.exchange(
300
+ "PUT",
301
+ f"/projects/{project_id}/label-schema",
302
+ headers={"If-Match": _etag(project_entry.etag, "image_schemas.etag")},
303
+ json={
304
+ "contract_version": "x4d-label-schema-binding-v2",
305
+ "schema_id": schema_id,
306
+ "version": version,
307
+ },
308
+ )
309
+ parsed = parse_image_project_schema(value).to_dict()
310
+ bound = parsed["label_schema"]["body"]
311
+ require(
312
+ parsed["project_id"] == project_id
313
+ and (bound["schema_id"], bound["version"]) == (schema_id, version),
314
+ "Registry bound another Schema",
315
+ "image_schemas.bind_project",
316
+ )
317
+ return ImageProjectSchemaEntry(parse_image_project_schema(parsed), _etag(etag, "image_schemas.response_etag"))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: x4d-devkit
3
- Version: 0.53.0rc1
3
+ Version: 0.53.0rc2
4
4
  Summary: Official X-4D external SDK and CLI for datasets, platform APIs, training bridges, and automation
5
5
  Author: windzu
6
6
  License-Expression: Apache-2.0
@@ -35,6 +35,7 @@ tests/test_image_preannotation.py
35
35
  tests/test_image_reference.py
36
36
  tests/test_image_review.py
37
37
  tests/test_image_schema_migration.py
38
+ tests/test_image_schema_registry_client.py
38
39
  tests/test_image_schema_upgrade.py
39
40
  tests/test_image_work_session.py
40
41
  tests/test_inference_input.py
File without changes
File without changes
File without changes