opensportslib 0.3.1.dev24__tar.gz → 0.3.1.dev26__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 (247) hide show
  1. {opensportslib-0.3.1.dev24/opensportslib.egg-info → opensportslib-0.3.1.dev26}/PKG-INFO +7 -1
  2. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/README.md +6 -0
  3. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26/opensportslib.egg-info}/PKG-INFO +7 -1
  4. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib.egg-info/SOURCES.txt +6 -1
  5. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/pyproject.toml +1 -1
  6. opensportslib-0.3.1.dev26/scripts/release_versions.py +181 -0
  7. opensportslib-0.3.1.dev26/tests/unit/contracts/test_release_versions.py +118 -0
  8. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/tools/test_hf_transfer.py +178 -0
  9. opensportslib-0.3.1.dev26/tests/unit/tools/test_spotting_classification.py +489 -0
  10. opensportslib-0.3.1.dev26/tools/convert/spotting_to_classification.py +902 -0
  11. opensportslib-0.3.1.dev26/tools/convert/spotting_tracking_to_classification.py +414 -0
  12. opensportslib-0.3.1.dev26/tools/upload/upload_sngar_tracking_full.py +107 -0
  13. opensportslib-0.3.1.dev26/tools/upload/upload_sngar_videos.py +130 -0
  14. opensportslib-0.3.1.dev24/scripts/release_versions.py +0 -84
  15. opensportslib-0.3.1.dev24/tests/unit/contracts/test_release_versions.py +0 -56
  16. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/LICENSE +0 -0
  17. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/LICENSE-COMMERCIAL +0 -0
  18. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/MANIFEST.in +0 -0
  19. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/examples/quickstart/basic_classification.py +0 -0
  20. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/examples/quickstart/basic_localization.py +0 -0
  21. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/examples/quickstart/basic_vqa.py +0 -0
  22. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/__init__.py +0 -0
  23. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/adaptation/__init__.py +0 -0
  24. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/adaptation/spotta.py +0 -0
  25. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/apis/__init__.py +0 -0
  26. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/apis/base_task_model.py +0 -0
  27. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/apis/classification.py +0 -0
  28. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/apis/config.py +0 -0
  29. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/apis/configuration.py +0 -0
  30. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/apis/localization.py +0 -0
  31. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/apis/vqa.py +0 -0
  32. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/cli.py +0 -0
  33. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/classification/default.yaml +0 -0
  34. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/classification/sngar_frames.yaml +0 -0
  35. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/classification/sngar_tracking.yaml +0 -0
  36. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/classification/video.yaml +0 -0
  37. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/default.yaml +0 -0
  38. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/localization/calf_resnetpca512.yaml +0 -0
  39. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/localization/default.yaml +0 -0
  40. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/localization/e2e_spotta.yaml +0 -0
  41. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/localization/h5_header_distance.yaml +0 -0
  42. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/localization/h5_header_skeleton.yaml +0 -0
  43. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/localization/netvladpp_resnetpca512.yaml +0 -0
  44. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/localization/tracking_action_spotting.yaml +0 -0
  45. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/localization/video_dali.yaml +0 -0
  46. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/localization/video_ocv.yaml +0 -0
  47. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/vqa/default.yaml +0 -0
  48. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/vqa/qwen.yaml +0 -0
  49. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/vqa/qwen3_vl_native.yaml +0 -0
  50. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/vqa/qwen_lora.yaml +0 -0
  51. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/vqa/qwen_sngar_frames.yaml +0 -0
  52. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/configs/vqa/xvars.yaml +0 -0
  53. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/__init__.py +0 -0
  54. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/config/__init__.py +0 -0
  55. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/config/accessors.py +0 -0
  56. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/config/conflicts.py +0 -0
  57. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/config/editable.py +0 -0
  58. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/config/loader.py +0 -0
  59. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/config/migrate.py +0 -0
  60. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/config/migrations/__init__.py +0 -0
  61. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/config/migrations/legacy_to_canonical.py +0 -0
  62. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/config/rule_variants.py +0 -0
  63. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/config/runtime_adapter.py +0 -0
  64. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/config/schema.py +0 -0
  65. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/config/schemas/__init__.py +0 -0
  66. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/config/schemas/schema_canonical.py +0 -0
  67. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/config/schemas/schema_legacy.py +0 -0
  68. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/config/validate.py +0 -0
  69. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/loss/__init__.py +0 -0
  70. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/loss/builder.py +0 -0
  71. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/loss/calf.py +0 -0
  72. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/loss/ce.py +0 -0
  73. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/loss/combine.py +0 -0
  74. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/loss/nll.py +0 -0
  75. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/optimizer/__init__.py +0 -0
  76. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/optimizer/builder.py +0 -0
  77. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/sampler/weighted_sampler.py +0 -0
  78. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/scheduler/__init__.py +0 -0
  79. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/scheduler/builder.py +0 -0
  80. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/trainer/__init__.py +0 -0
  81. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/trainer/classification_trainer.py +0 -0
  82. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/trainer/localization_trainer.py +0 -0
  83. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/trainer/vqa_trainer.py +0 -0
  84. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/utils/checkpoint.py +0 -0
  85. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/utils/config.py +0 -0
  86. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/utils/config_normalize.py +0 -0
  87. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/utils/data.py +0 -0
  88. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/utils/ddp.py +0 -0
  89. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/utils/default_args.py +0 -0
  90. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/utils/direct_video.py +0 -0
  91. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/utils/hf_runtime.py +0 -0
  92. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/utils/lightning.py +0 -0
  93. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/utils/load_annotations.py +0 -0
  94. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/utils/seed.py +0 -0
  95. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/utils/video_processing.py +0 -0
  96. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/core/utils/wandb.py +0 -0
  97. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/datasets/__init__.py +0 -0
  98. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/datasets/builder.py +0 -0
  99. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/datasets/classification_dataset.py +0 -0
  100. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/datasets/hf_json.py +0 -0
  101. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/datasets/hf_tracking.py +0 -0
  102. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/datasets/localization_dataset.py +0 -0
  103. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/datasets/utils/__init__.py +0 -0
  104. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/datasets/utils/h5_tracking.py +0 -0
  105. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/datasets/utils/tracking.py +0 -0
  106. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/datasets/vqa_dataset.py +0 -0
  107. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/legacy_config/classification.yaml +0 -0
  108. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/legacy_config/localization-e2e-ocv.yaml +0 -0
  109. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/legacy_config/localization-json_calf_resnetpca512.yaml +0 -0
  110. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/legacy_config/localization-json_netvlad++_resnetpca512.yaml +0 -0
  111. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/legacy_config/localization.yaml +0 -0
  112. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/legacy_config/sngar-frames.yaml +0 -0
  113. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/legacy_config/sngar-tracking.yaml +0 -0
  114. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/metrics/classification_metric.py +0 -0
  115. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/metrics/localization_metric.py +0 -0
  116. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/metrics/vqa_metric.py +0 -0
  117. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/__init__.py +0 -0
  118. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/backbones/builder.py +0 -0
  119. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/base/contextaware.py +0 -0
  120. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/base/e2e.py +0 -0
  121. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/base/learnablepooling.py +0 -0
  122. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/base/qwen_vl_native.py +0 -0
  123. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/base/qwen_xvars.py +0 -0
  124. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/base/rule_based.py +0 -0
  125. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/base/tracking.py +0 -0
  126. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/base/vars.py +0 -0
  127. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/base/video.py +0 -0
  128. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/base/video_chatgpt_compat.py +0 -0
  129. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/base/video_mae.py +0 -0
  130. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/base/xvars_videochatgpt.py +0 -0
  131. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/builder.py +0 -0
  132. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/heads/builder.py +0 -0
  133. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/neck/builder.py +0 -0
  134. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/utils/common.py +0 -0
  135. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/utils/impl/__init__.py +0 -0
  136. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/utils/impl/asformer.py +0 -0
  137. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/utils/impl/calf.py +0 -0
  138. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/utils/impl/gsm.py +0 -0
  139. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/utils/impl/gtad.py +0 -0
  140. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/utils/impl/tsm.py +0 -0
  141. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/utils/litebase.py +0 -0
  142. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/utils/modules.py +0 -0
  143. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/utils/shift.py +0 -0
  144. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/utils/utils.py +0 -0
  145. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/utils/vqa_prediction_priors.py +0 -0
  146. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/utils/vqa_prompting.py +0 -0
  147. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/models/utils/xvars_clip_index.py +0 -0
  148. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/remote_registry.py +0 -0
  149. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/setup/setup.py +0 -0
  150. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/tools/__init__.py +0 -0
  151. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/tools/_common.py +0 -0
  152. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/tools/hf_transfer.py +0 -0
  153. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/tools/osl_json_to_parquet.py +0 -0
  154. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib/tools/parquet_to_osl_json.py +0 -0
  155. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib.egg-info/dependency_links.txt +0 -0
  156. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib.egg-info/entry_points.txt +0 -0
  157. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib.egg-info/requires.txt +0 -0
  158. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/opensportslib.egg-info/top_level.txt +0 -0
  159. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/scripts/redact_test_stream.py +0 -0
  160. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/scripts/run_h5_header_rule_inference.py +0 -0
  161. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/scripts/summarize_test_report.py +0 -0
  162. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/scripts/verify_release_manifests.py +0 -0
  163. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/scripts/write_release_manifest.py +0 -0
  164. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/setup.cfg +0 -0
  165. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/__init__.py +0 -0
  166. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/conftest.py +0 -0
  167. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/helpers/__init__.py +0 -0
  168. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/helpers/configs.py +0 -0
  169. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/helpers/pipeline_stubs.py +0 -0
  170. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/integration/classification/test_pipeline.py +0 -0
  171. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/integration/localization/test_pipeline.py +0 -0
  172. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/integration/localization/test_spotta.py +0 -0
  173. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/integration/vqa/test_pipeline.py +0 -0
  174. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/release/__init__.py +0 -0
  175. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/release/_release_common.py +0 -0
  176. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/release/test_00_environment.py +0 -0
  177. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/release/test_classification_release.py +0 -0
  178. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/release/test_localization_release.py +0 -0
  179. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/release/test_vqa_release.py +0 -0
  180. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/smoke/test_cli.py +0 -0
  181. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/smoke/test_config_utils.py +0 -0
  182. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/smoke/test_environment.py +0 -0
  183. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/smoke/test_package.py +0 -0
  184. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/smoke/test_public_apis.py +0 -0
  185. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/api/test_remote_registry.py +0 -0
  186. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/api/test_remote_sessions.py +0 -0
  187. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/api/test_server_jobs.py +0 -0
  188. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/api/test_server_registry.py +0 -0
  189. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/api/test_server_startup_scripts.py +0 -0
  190. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/api/test_task_model_contract.py +0 -0
  191. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/api/test_vqa.py +0 -0
  192. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/config/test_architecture.py +0 -0
  193. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/config/test_editable.py +0 -0
  194. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/config/test_optional_hf.py +0 -0
  195. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/config/test_pretrained_merge.py +0 -0
  196. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/config/test_split_overrides.py +0 -0
  197. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/contracts/test_architecture.py +0 -0
  198. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/contracts/test_dependencies.py +0 -0
  199. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/contracts/test_package.py +0 -0
  200. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/contracts/test_runner_contract.py +0 -0
  201. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/core/test_classification_trainer.py +0 -0
  202. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/core/test_localization_hf_backend.py +0 -0
  203. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/core/test_training_components.py +0 -0
  204. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/core/test_video_processing.py +0 -0
  205. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/data/test_classification_paths.py +0 -0
  206. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/data/test_h5_tracking.py +0 -0
  207. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/data/test_hf_json_spotting.py +0 -0
  208. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/data/test_hf_json_tracking_spotting.py +0 -0
  209. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/data/test_hf_tracking_dataset.py +0 -0
  210. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/data/test_localization_dali.py +0 -0
  211. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/data/test_localization_intervals.py +0 -0
  212. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/data/test_osl_formats.py +0 -0
  213. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/models/test_classification_metrics.py +0 -0
  214. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/models/test_header_rule_spotter.py +0 -0
  215. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/models/test_header_skeleton_spotter.py +0 -0
  216. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/models/test_localization_metrics.py +0 -0
  217. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/models/test_temporal_shift.py +0 -0
  218. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/models/test_vqa_metrics.py +0 -0
  219. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/models/test_vqa_qwen_xvars.py +0 -0
  220. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/models/test_vqa_training_lora.py +0 -0
  221. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/models/test_vqa_xvars_videochatgpt.py +0 -0
  222. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/tools/test_conversion.py +0 -0
  223. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/tools/test_extract_xvars_features.py +0 -0
  224. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/tools/test_release_manifest.py +0 -0
  225. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/tools/test_report_summary.py +0 -0
  226. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tests/unit/tools/test_setup.py +0 -0
  227. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/convert/build_sn_vqa_2026_vqa.py +0 -0
  228. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/convert/build_sngar_spotting.py +0 -0
  229. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/convert/build_soccernet_gar.py +0 -0
  230. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/convert/build_soccernet_gar_action_spotting.py +0 -0
  231. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/convert/build_soccernet_gar_vqa.py +0 -0
  232. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/convert/build_xvars_indexes.py +0 -0
  233. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/convert/extract_xvars_clip_features.py +0 -0
  234. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/convert/osl_json_to_parquet_webdataset.py +0 -0
  235. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/convert/parquet_webdataset_to_osl_json.py +0 -0
  236. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/convert/sngar_dataset_card.py +0 -0
  237. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/convert/sngar_events.py +0 -0
  238. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/convert/verify_sngar_spotting.py +0 -0
  239. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/download/download_hf_repo.py +0 -0
  240. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/download/download_osl_hf.py +0 -0
  241. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/download/push_sngar_spotting.py +0 -0
  242. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/download/upload_osl_hf.py +0 -0
  243. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/train/train_config.py +0 -0
  244. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/training/classification.py +0 -0
  245. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/training/localization.py +0 -0
  246. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/training/vqa.py +0 -0
  247. {opensportslib-0.3.1.dev24 → opensportslib-0.3.1.dev26}/tools/upload/upload_model_hf.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opensportslib
3
- Version: 0.3.1.dev24
3
+ Version: 0.3.1.dev26
4
4
  Summary: OpenSportsLib is the professional library, designed for advanced video understanding in sports. It provides state-of-the-art tools for action recognition, spotting, retrieval, and captioning, making it ideal for researchers, analysts, and developers working with sports video data.
5
5
  Author: Jeet Vora
6
6
  Requires-Python: >=3.12
@@ -324,3 +324,9 @@ video understanding. Core contributors affiliated with KAUST include:
324
324
  - [Jeet Vora](https://jeetv.github.io/) — Remote Research Engineer
325
325
  - [Dr. Merey Ramazanova](https://meryusha.github.io/) — Post-Doc
326
326
  - [Dr. Silvio Giancola](https://www.silviogiancola.com/) — Research Scientist
327
+
328
+ For synchronized native-FPS GAR action clips and optional exact frame reproduction, see the
329
+ [spotting-to-classification converter](docs/tools/spotting-to-classification.md).
330
+
331
+ For full-rate tracking clips with the same classification sample IDs, see the
332
+ [tracking conversion script](docs/tools/spotting-tracking-to-classification.md).
@@ -285,3 +285,9 @@ video understanding. Core contributors affiliated with KAUST include:
285
285
  - [Jeet Vora](https://jeetv.github.io/) — Remote Research Engineer
286
286
  - [Dr. Merey Ramazanova](https://meryusha.github.io/) — Post-Doc
287
287
  - [Dr. Silvio Giancola](https://www.silviogiancola.com/) — Research Scientist
288
+
289
+ For synchronized native-FPS GAR action clips and optional exact frame reproduction, see the
290
+ [spotting-to-classification converter](docs/tools/spotting-to-classification.md).
291
+
292
+ For full-rate tracking clips with the same classification sample IDs, see the
293
+ [tracking conversion script](docs/tools/spotting-tracking-to-classification.md).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opensportslib
3
- Version: 0.3.1.dev24
3
+ Version: 0.3.1.dev26
4
4
  Summary: OpenSportsLib is the professional library, designed for advanced video understanding in sports. It provides state-of-the-art tools for action recognition, spotting, retrieval, and captioning, making it ideal for researchers, analysts, and developers working with sports video data.
5
5
  Author: Jeet Vora
6
6
  Requires-Python: >=3.12
@@ -324,3 +324,9 @@ video understanding. Core contributors affiliated with KAUST include:
324
324
  - [Jeet Vora](https://jeetv.github.io/) — Remote Research Engineer
325
325
  - [Dr. Merey Ramazanova](https://meryusha.github.io/) — Post-Doc
326
326
  - [Dr. Silvio Giancola](https://www.silviogiancola.com/) — Research Scientist
327
+
328
+ For synchronized native-FPS GAR action clips and optional exact frame reproduction, see the
329
+ [spotting-to-classification converter](docs/tools/spotting-to-classification.md).
330
+
331
+ For full-rate tracking clips with the same classification sample IDs, see the
332
+ [tracking conversion script](docs/tools/spotting-tracking-to-classification.md).
@@ -215,6 +215,7 @@ tests/unit/tools/test_hf_transfer.py
215
215
  tests/unit/tools/test_release_manifest.py
216
216
  tests/unit/tools/test_report_summary.py
217
217
  tests/unit/tools/test_setup.py
218
+ tests/unit/tools/test_spotting_classification.py
218
219
  tools/convert/build_sn_vqa_2026_vqa.py
219
220
  tools/convert/build_sngar_spotting.py
220
221
  tools/convert/build_soccernet_gar.py
@@ -226,6 +227,8 @@ tools/convert/osl_json_to_parquet_webdataset.py
226
227
  tools/convert/parquet_webdataset_to_osl_json.py
227
228
  tools/convert/sngar_dataset_card.py
228
229
  tools/convert/sngar_events.py
230
+ tools/convert/spotting_to_classification.py
231
+ tools/convert/spotting_tracking_to_classification.py
229
232
  tools/convert/verify_sngar_spotting.py
230
233
  tools/download/download_hf_repo.py
231
234
  tools/download/download_osl_hf.py
@@ -235,4 +238,6 @@ tools/train/train_config.py
235
238
  tools/training/classification.py
236
239
  tools/training/localization.py
237
240
  tools/training/vqa.py
238
- tools/upload/upload_model_hf.py
241
+ tools/upload/upload_model_hf.py
242
+ tools/upload/upload_sngar_tracking_full.py
243
+ tools/upload/upload_sngar_videos.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "opensportslib"
7
- version = "0.3.1.dev24"
7
+ version = "0.3.1.dev26"
8
8
  description = "OpenSportsLib is the professional library, designed for advanced video understanding in sports. It provides state-of-the-art tools for action recognition, spotting, retrieval, and captioning, making it ideal for researchers, analysts, and developers working with sports video data."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -0,0 +1,181 @@
1
+ """Keep the library version and the server's library pin in sync."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import re
7
+ from pathlib import Path
8
+
9
+
10
+ STABLE_VERSION = re.compile(r"^(?P<version>\d+\.\d+\.\d+)$")
11
+ DEV_VERSION = re.compile(r"^(?P<base>\d+\.\d+\.\d+)\.dev(?P<number>\d+)$")
12
+ PROJECT_VERSION = re.compile(
13
+ r'(?ms)(^\[project\]\s*.*?^version\s*=\s*")[^"]+("\s*$)'
14
+ )
15
+ SERVER_PIN = re.compile(r'("opensportslib==)([^"]+)(")')
16
+
17
+
18
+ def next_dev_version(current: str) -> str:
19
+ """Return the next development release for an existing dev version."""
20
+ match = DEV_VERSION.fullmatch(current)
21
+ if not match:
22
+ raise ValueError(f"expected X.Y.Z.devN, got {current!r}")
23
+ return f"{match.group('base')}.dev{int(match.group('number')) + 1}"
24
+
25
+
26
+ def stable_version(tag: str) -> str:
27
+ """Return a stable version from a vX.Y.Z release tag."""
28
+ if not tag.startswith("v"):
29
+ raise ValueError(f"release tag must start with 'v', got {tag!r}")
30
+ version = tag[1:]
31
+ if not STABLE_VERSION.fullmatch(version):
32
+ raise ValueError(f"release tag must have the form vX.Y.Z, got {tag!r}")
33
+ return version
34
+
35
+
36
+ def development_version(tag: str) -> str:
37
+ """Return the initial development version for a stable release tag."""
38
+ return f"{stable_version(tag)}.dev0"
39
+
40
+
41
+ def next_patch_development_version(tag: str) -> str:
42
+ """Return the next patch's initial development version for a release tag."""
43
+ major, minor, patch = (int(part) for part in stable_version(tag).split("."))
44
+ return f"{major}.{minor}.{patch + 1}.dev0"
45
+
46
+
47
+ def version_base(version: str) -> str:
48
+ """Return X.Y.Z from either a stable or development package version."""
49
+ dev_match = DEV_VERSION.fullmatch(version)
50
+ if dev_match:
51
+ return dev_match.group("base")
52
+ if STABLE_VERSION.fullmatch(version):
53
+ return version
54
+ raise ValueError(f"unsupported release version {version!r}")
55
+
56
+
57
+ def read_project_version(pyproject: Path) -> str:
58
+ text = pyproject.read_text()
59
+ match = PROJECT_VERSION.search(text)
60
+ if not match:
61
+ raise ValueError(f"project.version not found in {pyproject}")
62
+ return text[match.start(0) + len(match.group(1)) : match.end(0) - len(match.group(2))]
63
+
64
+
65
+ def read_server_pin(pyproject: Path) -> str:
66
+ """Return the OpenSportsLib dependency pin from the server metadata."""
67
+ text = pyproject.read_text()
68
+ matches = SERVER_PIN.findall(text)
69
+ if len(matches) != 1:
70
+ raise ValueError(f"expected one opensportslib dependency pin in {pyproject}")
71
+ return matches[0][1]
72
+
73
+
74
+ def assert_synchronized(root_pyproject: Path, server_pyproject: Path) -> str:
75
+ """Ensure the package version and server dependency pin are identical."""
76
+ version = read_project_version(root_pyproject)
77
+ pin = read_server_pin(server_pyproject)
78
+ if version != pin:
79
+ raise ValueError(
80
+ f"version metadata is not synchronized: {root_pyproject} has {version!r}, "
81
+ f"but {server_pyproject} pins {pin!r}"
82
+ )
83
+ return version
84
+
85
+
86
+ def validate_release(tag: str, root_pyproject: Path, server_pyproject: Path) -> str:
87
+ """Validate that metadata is the prepared prerelease for *tag*."""
88
+ expected = development_version(tag)
89
+ current = assert_synchronized(root_pyproject, server_pyproject)
90
+ if not DEV_VERSION.fullmatch(current) or version_base(current) != stable_version(tag):
91
+ raise ValueError(
92
+ f"release tag {tag!r} requires prepared version {expected[:-1]}N, got {current!r}"
93
+ )
94
+ return current
95
+
96
+
97
+ def prepare_development(tag: str, root_pyproject: Path, server_pyproject: Path) -> str:
98
+ """Start the requested release line at X.Y.Z.dev0."""
99
+ target = development_version(tag)
100
+ current = assert_synchronized(root_pyproject, server_pyproject)
101
+ if tuple(map(int, stable_version(tag).split("."))) <= tuple(map(int, version_base(current).split("."))):
102
+ raise ValueError(f"target release {tag!r} must be newer than current version {current!r}")
103
+ synchronize(target, root_pyproject, server_pyproject)
104
+ return target
105
+
106
+
107
+ def advance_development(tag: str, root_pyproject: Path, server_pyproject: Path) -> str:
108
+ """Advance a released development line to its next patch development base."""
109
+ validate_release(tag, root_pyproject, server_pyproject)
110
+ target = next_patch_development_version(tag)
111
+ synchronize(target, root_pyproject, server_pyproject)
112
+ return target
113
+
114
+
115
+ def synchronize(version: str, root_pyproject: Path, server_pyproject: Path) -> None:
116
+ """Write one OpenSportsLib version to both release metadata files."""
117
+ if not (STABLE_VERSION.fullmatch(version) or DEV_VERSION.fullmatch(version)):
118
+ raise ValueError(f"unsupported release version {version!r}")
119
+
120
+ root_text = root_pyproject.read_text()
121
+ server_text = server_pyproject.read_text()
122
+ if len(PROJECT_VERSION.findall(root_text)) != 1:
123
+ raise ValueError(f"expected one project.version in {root_pyproject}")
124
+ if len(SERVER_PIN.findall(server_text)) != 1:
125
+ raise ValueError(f"expected one opensportslib dependency pin in {server_pyproject}")
126
+
127
+ root_updated = PROJECT_VERSION.sub(rf"\g<1>{version}\g<2>", root_text)
128
+ server_updated = SERVER_PIN.sub(rf"\g<1>{version}\g<3>", server_text)
129
+ root_pyproject.write_text(root_updated)
130
+ server_pyproject.write_text(server_updated)
131
+
132
+
133
+ def main() -> None:
134
+ parser = argparse.ArgumentParser()
135
+ parser.add_argument(
136
+ "command",
137
+ choices=(
138
+ "bump-dev",
139
+ "set-stable",
140
+ "prepare-dev",
141
+ "validate-release",
142
+ "advance-dev",
143
+ "assert-synchronized",
144
+ ),
145
+ )
146
+ parser.add_argument("value", nargs="?", help="vX.Y.Z tag for set-stable")
147
+ parser.add_argument("--root", type=Path, default=Path("pyproject.toml"))
148
+ parser.add_argument("--server", type=Path, default=Path("server/pyproject.toml"))
149
+ args = parser.parse_args()
150
+
151
+ if args.command == "bump-dev":
152
+ if args.value is not None:
153
+ parser.error("bump-dev does not accept a value")
154
+ version = next_dev_version(assert_synchronized(args.root, args.server))
155
+ synchronize(version, args.root, args.server)
156
+ elif args.command == "set-stable":
157
+ if args.value is None:
158
+ parser.error("set-stable requires a vX.Y.Z tag")
159
+ version = stable_version(args.value)
160
+ synchronize(version, args.root, args.server)
161
+ elif args.command == "prepare-dev":
162
+ if args.value is None:
163
+ parser.error("prepare-dev requires a vX.Y.Z tag")
164
+ version = prepare_development(args.value, args.root, args.server)
165
+ elif args.command == "validate-release":
166
+ if args.value is None:
167
+ parser.error("validate-release requires a vX.Y.Z tag")
168
+ version = validate_release(args.value, args.root, args.server)
169
+ elif args.command == "advance-dev":
170
+ if args.value is None:
171
+ parser.error("advance-dev requires a vX.Y.Z tag")
172
+ version = advance_development(args.value, args.root, args.server)
173
+ else:
174
+ if args.value is not None:
175
+ parser.error("assert-synchronized does not accept a value")
176
+ version = assert_synchronized(args.root, args.server)
177
+ print(version)
178
+
179
+
180
+ if __name__ == "__main__":
181
+ main()
@@ -0,0 +1,118 @@
1
+ import importlib.util
2
+ from pathlib import Path
3
+
4
+ import pytest
5
+
6
+
7
+ SCRIPT = Path(__file__).parents[3] / "scripts" / "release_versions.py"
8
+ SPEC = importlib.util.spec_from_file_location("release_versions", SCRIPT)
9
+ release_versions = importlib.util.module_from_spec(SPEC)
10
+ assert SPEC.loader is not None
11
+ SPEC.loader.exec_module(release_versions)
12
+
13
+
14
+ def test_next_dev_version_increments_counter():
15
+ assert release_versions.next_dev_version("0.3.1.dev5") == "0.3.1.dev6"
16
+
17
+
18
+ @pytest.mark.parametrize("version", ["0.3.1", "0.3.1rc1", "invalid"])
19
+ def test_next_dev_version_rejects_non_dev_versions(version):
20
+ with pytest.raises(ValueError, match="expected X.Y.Z.devN"):
21
+ release_versions.next_dev_version(version)
22
+
23
+
24
+ def test_stable_version_requires_stable_v_tag():
25
+ assert release_versions.stable_version("v0.3.1") == "0.3.1"
26
+ with pytest.raises(ValueError, match="vX.Y.Z"):
27
+ release_versions.stable_version("v0.3.1.dev1")
28
+
29
+
30
+ def test_development_version_helpers():
31
+ assert release_versions.development_version("v0.4.0") == "0.4.0.dev0"
32
+ assert release_versions.next_patch_development_version("v0.3.1") == "0.3.2.dev0"
33
+ assert release_versions.version_base("0.3.1.dev5") == "0.3.1"
34
+ assert release_versions.version_base("0.3.1") == "0.3.1"
35
+ with pytest.raises(ValueError, match="unsupported release version"):
36
+ release_versions.version_base("invalid")
37
+
38
+
39
+ def test_synchronize_updates_root_and_server_pin_only(tmp_path):
40
+ root = tmp_path / "pyproject.toml"
41
+ server = tmp_path / "server.toml"
42
+ root.write_text('[project]\nname = "opensportslib"\nversion = "0.3.1.dev5"\n')
43
+ server.write_text(
44
+ '[project]\nname = "opensportslib-server"\nversion = "0.1.0"\n'
45
+ 'dependencies = [\n "opensportslib==0.3.1.dev5",\n "fastapi",\n]\n'
46
+ )
47
+
48
+ release_versions.synchronize("0.3.1.dev6", root, server)
49
+
50
+ assert 'version = "0.3.1.dev6"' in root.read_text()
51
+ assert 'version = "0.1.0"' in server.read_text()
52
+ assert '"opensportslib==0.3.1.dev6"' in server.read_text()
53
+
54
+
55
+ def test_synchronize_fails_before_writing_when_server_pin_is_missing(tmp_path):
56
+ root = tmp_path / "pyproject.toml"
57
+ server = tmp_path / "server.toml"
58
+ original = '[project]\nversion = "0.3.1.dev5"\n'
59
+ root.write_text(original)
60
+ server.write_text('[project]\nversion = "0.1.0"\n')
61
+
62
+ with pytest.raises(ValueError, match="dependency pin"):
63
+ release_versions.synchronize("0.3.1.dev6", root, server)
64
+
65
+ assert root.read_text() == original
66
+
67
+
68
+ def test_assert_synchronized_rejects_mismatched_metadata(tmp_path):
69
+ root = tmp_path / "pyproject.toml"
70
+ server = tmp_path / "server.toml"
71
+ root.write_text('[project]\nversion = "0.3.1.dev5"\n')
72
+ server.write_text('dependencies = ["opensportslib==0.3.1.dev4"]\n')
73
+
74
+ with pytest.raises(ValueError, match="not synchronized"):
75
+ release_versions.assert_synchronized(root, server)
76
+
77
+
78
+ def test_validate_release_requires_matching_prepared_dev_line(tmp_path):
79
+ root = tmp_path / "pyproject.toml"
80
+ server = tmp_path / "server.toml"
81
+ root.write_text('[project]\nversion = "0.3.1.dev5"\n')
82
+ server.write_text('dependencies = ["opensportslib==0.3.1.dev5"]\n')
83
+
84
+ assert release_versions.validate_release("v0.3.1", root, server) == "0.3.1.dev5"
85
+ with pytest.raises(ValueError, match="requires prepared version"):
86
+ release_versions.validate_release("v0.3.2", root, server)
87
+
88
+
89
+ def test_prepare_development_starts_newer_feature_line(tmp_path):
90
+ root = tmp_path / "pyproject.toml"
91
+ server = tmp_path / "server.toml"
92
+ root.write_text('[project]\nversion = "0.3.2.dev8"\n')
93
+ server.write_text('dependencies = ["opensportslib==0.3.2.dev8"]\n')
94
+
95
+ assert release_versions.prepare_development("v0.4.0", root, server) == "0.4.0.dev0"
96
+ assert release_versions.assert_synchronized(root, server) == "0.4.0.dev0"
97
+ with pytest.raises(ValueError, match="must be newer"):
98
+ release_versions.prepare_development("v0.4.0", root, server)
99
+
100
+
101
+ def test_advance_development_moves_to_next_patch_only_from_matching_line(tmp_path):
102
+ root = tmp_path / "pyproject.toml"
103
+ server = tmp_path / "server.toml"
104
+ root.write_text('[project]\nversion = "0.3.1.dev6"\n')
105
+ server.write_text('dependencies = ["opensportslib==0.3.1.dev6"]\n')
106
+
107
+ assert release_versions.advance_development("v0.3.1", root, server) == "0.3.2.dev0"
108
+ assert release_versions.assert_synchronized(root, server) == "0.3.2.dev0"
109
+
110
+
111
+ def test_advance_development_refuses_a_different_release_line(tmp_path):
112
+ root = tmp_path / "pyproject.toml"
113
+ server = tmp_path / "server.toml"
114
+ root.write_text('[project]\nversion = "0.4.0.dev0"\n')
115
+ server.write_text('dependencies = ["opensportslib==0.4.0.dev0"]\n')
116
+
117
+ with pytest.raises(ValueError, match="requires prepared version"):
118
+ release_versions.advance_development("v0.3.1", root, server)
@@ -1942,3 +1942,181 @@ def test_upload_dataset_inputs_from_json_to_hf_can_be_cancelled_before_upload(mo
1942
1942
  )
1943
1943
 
1944
1944
  assert calls["create_commit"] == 0
1945
+
1946
+
1947
+ @pytest.fixture
1948
+ def tracking_full_upload(tmp_path, monkeypatch):
1949
+ import importlib.util
1950
+ import pyarrow as pa
1951
+ import pyarrow.parquet as pq
1952
+
1953
+ script = Path(__file__).resolve().parents[3] / "tools/upload/upload_sngar_tracking_full.py"
1954
+ spec = importlib.util.spec_from_file_location("tracking_full_upload", script)
1955
+ module = importlib.util.module_from_spec(spec)
1956
+ spec.loader.exec_module(module)
1957
+ monkeypatch.setattr(module, "COUNTS", {"train": 1, "valid": 1, "test": 1})
1958
+ root = tmp_path / "tracking"
1959
+ reports = tmp_path / "reports"
1960
+ reports.mkdir()
1961
+ (reports / "build.json").write_text(json.dumps({"status": "passed", "completed": 3, "identity": "build"}))
1962
+ for split in module.COUNTS:
1963
+ (root / split).mkdir(parents=True)
1964
+ pq.write_table(pa.table({"frameNum": range(144), "tracking_valid": [True] * 144}), root / split / "clip.parquet")
1965
+ sample = {"id": split + "_000000", "inputs": [{"type": "tracking_parquet", "path": f"{split}/clip.parquet"}],
1966
+ "metadata": {"conversion": {"identity": "build", "frame_interval": 1,
1967
+ "window_slots": 144, "output_rows": 144, "gap_policy": "pad"}}}
1968
+ (root / f"annotations_{split}.json").write_text(json.dumps({"task": "action_classification", "data": [sample]}))
1969
+ calls = []
1970
+ monkeypatch.setattr(module, "dataset_repo_exists_on_hf", lambda repo: calls.append(("exists", repo)) or True)
1971
+ monkeypatch.setattr(module, "create_dataset_branch_on_hf", lambda *args, **kw: calls.append(("branch", args)))
1972
+ monkeypatch.setattr(module, "upload_dataset_as_parquet_to_hf", lambda *args, **kw: calls.append(("upload", args, kw)) or {})
1973
+ return module, root, calls
1974
+
1975
+
1976
+ def test_tracking_full_check_is_offline(tracking_full_upload):
1977
+ module, root, calls = tracking_full_upload
1978
+ assert module.main(["--data-root", str(root), "--check-only"]) == 0
1979
+ assert calls == []
1980
+
1981
+
1982
+ @pytest.mark.parametrize("failure", ["unfinished", "missing", "downsampled", "wrong_rows"])
1983
+ def test_tracking_full_invalid_build_never_contacts_hub(tracking_full_upload, failure):
1984
+ module, root, calls = tracking_full_upload
1985
+ if failure == "unfinished":
1986
+ (root.parent / "reports/build.json").write_text('{"status": "running"}')
1987
+ elif failure == "missing":
1988
+ (root / "test/clip.parquet").unlink()
1989
+ else:
1990
+ path = root / "annotations_test.json"
1991
+ data = json.loads(path.read_text())
1992
+ conversion = data["data"][0]["metadata"]["conversion"]
1993
+ conversion["frame_interval" if failure == "downsampled" else "output_rows"] = 9
1994
+ path.write_text(json.dumps(data))
1995
+ assert module.main(["--data-root", str(root)]) == 1
1996
+ assert calls == []
1997
+
1998
+
1999
+ def test_tracking_full_routes_to_internal_sharded_uploader(tracking_full_upload):
2000
+ module, root, calls = tracking_full_upload
2001
+ assert module.main(["--data-root", str(root), "--shard-size", "500MB", "--splits", "valid", "test"]) == 0
2002
+ assert calls[1] == ("branch", ("OpenSportsLab/SoccerNet-GAR", "tracking-full"))
2003
+ uploads = calls[2:]
2004
+ assert [call[2]["split"] for call in uploads] == ["valid", "test"]
2005
+ for _, args, kwargs in uploads:
2006
+ assert args[0] == "OpenSportsLab/SoccerNet-GAR"
2007
+ assert Path(args[1]) == root / f"annotations_{kwargs['split']}.json"
2008
+ assert kwargs["revision"] == "tracking-full"
2009
+ assert kwargs["shard_mode"] == "size"
2010
+ assert kwargs["shard_size"] == module.parse_shard_size("500MB")
2011
+
2012
+
2013
+ def test_tracking_full_stops_on_upload_failure(tracking_full_upload, monkeypatch):
2014
+ module, root, calls = tracking_full_upload
2015
+ attempted = []
2016
+ def fail(*args, **kwargs):
2017
+ attempted.append(kwargs["split"])
2018
+ raise RuntimeError("Upload interrupted")
2019
+ monkeypatch.setattr(module, "upload_dataset_as_parquet_to_hf", fail)
2020
+ assert module.main(["--data-root", str(root)]) == 1
2021
+ assert attempted == ["train"]
2022
+
2023
+
2024
+ @pytest.fixture
2025
+ def videos_upload(tracking_full_upload, monkeypatch):
2026
+ import importlib.util
2027
+ from fractions import Fraction
2028
+ import av
2029
+ import numpy as np
2030
+
2031
+ _, root, _ = tracking_full_upload
2032
+ script = Path(__file__).resolve().parents[3] / "tools/upload/upload_sngar_videos.py"
2033
+ spec = importlib.util.spec_from_file_location("videos_upload", script)
2034
+ module = importlib.util.module_from_spec(spec)
2035
+ spec.loader.exec_module(module)
2036
+ monkeypatch.setattr(module, "COUNTS", {"train": 1, "valid": 1, "test": 1})
2037
+ rate = Fraction(30000, 1001)
2038
+ for split in module.COUNTS:
2039
+ path = root / split / "clip.mp4"
2040
+ with av.open(str(path), "w") as output:
2041
+ stream = output.add_stream("libx264", rate=rate)
2042
+ stream.width, stream.height, stream.pix_fmt = 16, 16, "yuv420p"
2043
+ for i in range(144):
2044
+ frame = av.VideoFrame.from_ndarray(np.zeros((16, 16, 3), dtype=np.uint8), format="rgb24")
2045
+ frame.pts, frame.time_base = i, 1 / rate
2046
+ for packet in stream.encode(frame):
2047
+ output.mux(packet)
2048
+ for packet in stream.encode():
2049
+ output.mux(packet)
2050
+ manifest = root / f"annotations_{split}.json"
2051
+ data = json.loads(manifest.read_text())
2052
+ sample = data["data"][0]
2053
+ sample["inputs"] = [{"type": "video", "path": f"{split}/clip.mp4", "fps": float(rate)}]
2054
+ sample["metadata"]["conversion"] = {
2055
+ "identity": "build", "validation": "temporal", "alignment": {"passed": True},
2056
+ "sampled_frame_indices": list(range(90, 234, 9)),
2057
+ "clip": {"start_frame": 90, "end_frame_exclusive": 234, "frame_count": 144,
2058
+ "native_rate": str(rate), "width": 16, "height": 16,
2059
+ "duration_seconds": float(144 / rate)},
2060
+ }
2061
+ manifest.write_text(json.dumps(data))
2062
+ calls = []
2063
+ monkeypatch.setattr(module, "dataset_repo_exists_on_hf", lambda repo: calls.append(("exists", repo)) or True)
2064
+ monkeypatch.setattr(module, "create_dataset_branch_on_hf", lambda *args, **kw: calls.append(("branch", args)))
2065
+ monkeypatch.setattr(module, "upload_dataset_as_parquet_to_hf", lambda *args, **kw: calls.append(("upload", args, kw)) or {})
2066
+ return module, root, calls
2067
+
2068
+
2069
+ def test_videos_upload_offline_fractional_fps(videos_upload):
2070
+ module, root, calls = videos_upload
2071
+ assert module.main(["--data-root", str(root), "--check-only"]) == 0
2072
+ assert calls == []
2073
+
2074
+
2075
+ @pytest.mark.parametrize("failure", ["unfinished", "missing", "corrupt", "alignment", "frame_count", "native_rate", "duration_seconds"])
2076
+ def test_videos_invalid_build_never_contacts_hub(videos_upload, failure, capsys):
2077
+ module, root, calls = videos_upload
2078
+ if failure == "unfinished":
2079
+ (root.parent / "reports/build.json").write_text('{"status": "running"}')
2080
+ elif failure == "missing":
2081
+ (root / "test/clip.mp4").unlink()
2082
+ elif failure == "corrupt":
2083
+ (root / "test/clip.mp4").write_bytes(b"invalid mp4")
2084
+ else:
2085
+ manifest = root / "annotations_test.json"
2086
+ data = json.loads(manifest.read_text())
2087
+ conversion = data["data"][0]["metadata"]["conversion"]
2088
+ if failure == "alignment":
2089
+ conversion["alignment"]["passed"] = False
2090
+ else:
2091
+ conversion["clip"][failure] = 16
2092
+ manifest.write_text(json.dumps(data))
2093
+ assert module.main(["--data-root", str(root)]) == 1
2094
+ assert calls == []
2095
+ assert "Error:" in capsys.readouterr().err
2096
+
2097
+
2098
+ def test_videos_routes_to_internal_uploader(videos_upload):
2099
+ module, root, calls = videos_upload
2100
+ assert module.main(["--data-root", str(root), "--splits", "test", "--shard-size", "500MB"]) == 0
2101
+ assert calls[1] == ("branch", ("OpenSportsLab/SoccerNet-GAR", "videos"))
2102
+ assert len(calls) == 3
2103
+ _, args, kwargs = calls[2]
2104
+ assert args == ("OpenSportsLab/SoccerNet-GAR", str(root / "annotations_test.json"))
2105
+ assert kwargs["revision"] == "videos"
2106
+ assert kwargs["split"] == "test"
2107
+ assert kwargs["shard_mode"] == "size"
2108
+ assert kwargs["shard_size"] == module.parse_shard_size("500MB")
2109
+
2110
+
2111
+ def test_videos_accepts_legacy_timestamp_quantization(videos_upload):
2112
+ module, root, calls = videos_upload
2113
+ from fractions import Fraction
2114
+ # Legacy provenance stores nominal FPS, slightly different from measured
2115
+ # output FPS when the source timestamps include a one-tick correction.
2116
+ path = root / "annotations_test.json"
2117
+ data = json.loads(path.read_text())
2118
+ clip = data["data"][0]["metadata"]["conversion"]["clip"]
2119
+ clip["native_rate"] = str(Fraction(12960000, 432433))
2120
+ path.write_text(json.dumps(data))
2121
+ assert module.main(["--data-root", str(root), "--check-only"]) == 0
2122
+ assert calls == []