opensportslib 0.3.3.dev3__tar.gz → 0.3.4.dev1__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 (252) hide show
  1. {opensportslib-0.3.3.dev3/opensportslib.egg-info → opensportslib-0.3.4.dev1}/PKG-INFO +17 -1
  2. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/README.md +16 -0
  3. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/apis/base_task_model.py +1 -1
  4. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/apis/classification.py +8 -0
  5. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/apis/localization.py +9 -0
  6. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/loader.py +5 -1
  7. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/trainer/classification_trainer.py +1 -0
  8. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/load_annotations.py +47 -11
  9. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/classification_dataset.py +13 -8
  10. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/hf_json.py +7 -4
  11. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/hf_tracking.py +77 -11
  12. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/localization_dataset.py +22 -7
  13. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/utils/tracking.py +61 -10
  14. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/tools/hf_transfer.py +45 -18
  15. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/tools/osl_json_to_parquet.py +45 -60
  16. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/tools/parquet_to_osl_json.py +22 -13
  17. opensportslib-0.3.4.dev1/opensportslib/tracking/__init__.py +5 -0
  18. opensportslib-0.3.4.dev1/opensportslib/tracking/native.py +252 -0
  19. opensportslib-0.3.4.dev1/opensportslib/tracking/tracab.py +391 -0
  20. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1/opensportslib.egg-info}/PKG-INFO +17 -1
  21. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib.egg-info/SOURCES.txt +5 -0
  22. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/pyproject.toml +1 -1
  23. opensportslib-0.3.4.dev1/tests/helpers/tracab.py +47 -0
  24. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/api/test_remote_sessions.py +23 -0
  25. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/config/test_architecture.py +10 -0
  26. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/data/test_hf_json_tracking_spotting.py +24 -11
  27. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/data/test_hf_tracking_dataset.py +71 -4
  28. opensportslib-0.3.4.dev1/tests/unit/data/test_tracking_tracab.py +258 -0
  29. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/tools/test_conversion.py +26 -0
  30. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/tools/test_hf_transfer.py +164 -1
  31. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/LICENSE +0 -0
  32. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/LICENSE-COMMERCIAL +0 -0
  33. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/MANIFEST.in +0 -0
  34. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/examples/quickstart/basic_classification.py +0 -0
  35. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/examples/quickstart/basic_localization.py +0 -0
  36. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/examples/quickstart/basic_vqa.py +0 -0
  37. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/__init__.py +0 -0
  38. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/adaptation/__init__.py +0 -0
  39. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/adaptation/spotta.py +0 -0
  40. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/apis/__init__.py +0 -0
  41. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/apis/config.py +0 -0
  42. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/apis/configuration.py +0 -0
  43. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/apis/vqa.py +0 -0
  44. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/cli.py +0 -0
  45. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/classification/default.yaml +0 -0
  46. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/classification/sngar_frames.yaml +0 -0
  47. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/classification/sngar_tracking.yaml +0 -0
  48. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/classification/video.yaml +0 -0
  49. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/default.yaml +0 -0
  50. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/calf_resnetpca512.yaml +0 -0
  51. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/default.yaml +0 -0
  52. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/e2e_spotta.yaml +0 -0
  53. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/h5_header_distance.yaml +0 -0
  54. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/h5_header_skeleton.yaml +0 -0
  55. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/netvladpp_resnetpca512.yaml +0 -0
  56. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/tracking_action_spotting.yaml +0 -0
  57. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/video_dali.yaml +0 -0
  58. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/localization/video_ocv.yaml +0 -0
  59. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/vqa/default.yaml +0 -0
  60. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/vqa/qwen.yaml +0 -0
  61. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/vqa/qwen3_vl_native.yaml +0 -0
  62. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/vqa/qwen_lora.yaml +0 -0
  63. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/vqa/qwen_sngar_frames.yaml +0 -0
  64. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/configs/vqa/xvars.yaml +0 -0
  65. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/__init__.py +0 -0
  66. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/__init__.py +0 -0
  67. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/accessors.py +0 -0
  68. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/conflicts.py +0 -0
  69. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/editable.py +0 -0
  70. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/migrate.py +0 -0
  71. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/migrations/__init__.py +0 -0
  72. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/migrations/legacy_to_canonical.py +0 -0
  73. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/rule_variants.py +0 -0
  74. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/runtime_adapter.py +0 -0
  75. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/schema.py +0 -0
  76. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/schemas/__init__.py +0 -0
  77. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/schemas/schema_canonical.py +0 -0
  78. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/schemas/schema_legacy.py +0 -0
  79. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/config/validate.py +0 -0
  80. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/loss/__init__.py +0 -0
  81. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/loss/builder.py +0 -0
  82. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/loss/calf.py +0 -0
  83. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/loss/ce.py +0 -0
  84. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/loss/combine.py +0 -0
  85. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/loss/nll.py +0 -0
  86. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/optimizer/__init__.py +0 -0
  87. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/optimizer/builder.py +0 -0
  88. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/sampler/weighted_sampler.py +0 -0
  89. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/scheduler/__init__.py +0 -0
  90. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/scheduler/builder.py +0 -0
  91. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/trainer/__init__.py +0 -0
  92. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/trainer/localization_trainer.py +0 -0
  93. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/trainer/vqa_trainer.py +0 -0
  94. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/checkpoint.py +0 -0
  95. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/config.py +0 -0
  96. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/config_normalize.py +0 -0
  97. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/data.py +0 -0
  98. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/ddp.py +0 -0
  99. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/default_args.py +0 -0
  100. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/direct_video.py +0 -0
  101. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/hf_runtime.py +0 -0
  102. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/lightning.py +0 -0
  103. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/seed.py +0 -0
  104. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/video_processing.py +0 -0
  105. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/core/utils/wandb.py +0 -0
  106. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/__init__.py +0 -0
  107. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/builder.py +0 -0
  108. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/utils/__init__.py +0 -0
  109. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/utils/h5_tracking.py +0 -0
  110. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/datasets/vqa_dataset.py +0 -0
  111. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/legacy_config/classification.yaml +0 -0
  112. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/legacy_config/localization-e2e-ocv.yaml +0 -0
  113. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/legacy_config/localization-json_calf_resnetpca512.yaml +0 -0
  114. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/legacy_config/localization-json_netvlad++_resnetpca512.yaml +0 -0
  115. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/legacy_config/localization.yaml +0 -0
  116. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/legacy_config/sngar-frames.yaml +0 -0
  117. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/legacy_config/sngar-tracking.yaml +0 -0
  118. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/metrics/classification_metric.py +0 -0
  119. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/metrics/localization_metric.py +0 -0
  120. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/metrics/vqa_metric.py +0 -0
  121. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/__init__.py +0 -0
  122. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/backbones/builder.py +0 -0
  123. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/contextaware.py +0 -0
  124. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/e2e.py +0 -0
  125. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/learnablepooling.py +0 -0
  126. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/qwen_vl_native.py +0 -0
  127. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/qwen_xvars.py +0 -0
  128. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/rule_based.py +0 -0
  129. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/tracking.py +0 -0
  130. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/vars.py +0 -0
  131. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/video.py +0 -0
  132. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/video_chatgpt_compat.py +0 -0
  133. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/video_mae.py +0 -0
  134. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/base/xvars_videochatgpt.py +0 -0
  135. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/builder.py +0 -0
  136. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/heads/builder.py +0 -0
  137. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/neck/builder.py +0 -0
  138. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/common.py +0 -0
  139. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/impl/__init__.py +0 -0
  140. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/impl/asformer.py +0 -0
  141. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/impl/calf.py +0 -0
  142. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/impl/gsm.py +0 -0
  143. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/impl/gtad.py +0 -0
  144. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/impl/tsm.py +0 -0
  145. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/litebase.py +0 -0
  146. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/modules.py +0 -0
  147. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/shift.py +0 -0
  148. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/utils.py +0 -0
  149. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/vqa_prediction_priors.py +0 -0
  150. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/vqa_prompting.py +0 -0
  151. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/models/utils/xvars_clip_index.py +0 -0
  152. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/remote_registry.py +0 -0
  153. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/setup/setup.py +0 -0
  154. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/tools/__init__.py +0 -0
  155. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib/tools/_common.py +0 -0
  156. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib.egg-info/dependency_links.txt +0 -0
  157. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib.egg-info/entry_points.txt +0 -0
  158. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib.egg-info/requires.txt +0 -0
  159. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/opensportslib.egg-info/top_level.txt +0 -0
  160. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/scripts/redact_test_stream.py +0 -0
  161. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/scripts/release_versions.py +0 -0
  162. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/scripts/run_h5_header_rule_inference.py +0 -0
  163. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/scripts/summarize_test_report.py +0 -0
  164. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/scripts/verify_release_manifests.py +0 -0
  165. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/scripts/write_release_manifest.py +0 -0
  166. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/setup.cfg +0 -0
  167. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/__init__.py +0 -0
  168. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/conftest.py +0 -0
  169. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/helpers/__init__.py +0 -0
  170. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/helpers/causal_lm.py +0 -0
  171. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/helpers/configs.py +0 -0
  172. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/helpers/pipeline_stubs.py +0 -0
  173. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/integration/classification/test_pipeline.py +0 -0
  174. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/integration/localization/test_pipeline.py +0 -0
  175. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/integration/localization/test_spotta.py +0 -0
  176. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/integration/vqa/test_pipeline.py +0 -0
  177. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/release/__init__.py +0 -0
  178. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/release/_release_common.py +0 -0
  179. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/release/test_00_environment.py +0 -0
  180. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/release/test_classification_release.py +0 -0
  181. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/release/test_localization_release.py +0 -0
  182. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/release/test_vqa_release.py +0 -0
  183. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/smoke/test_cli.py +0 -0
  184. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/smoke/test_config_utils.py +0 -0
  185. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/smoke/test_environment.py +0 -0
  186. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/smoke/test_package.py +0 -0
  187. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/smoke/test_public_apis.py +0 -0
  188. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/api/test_remote_registry.py +0 -0
  189. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/api/test_server_jobs.py +0 -0
  190. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/api/test_server_registry.py +0 -0
  191. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/api/test_server_startup_scripts.py +0 -0
  192. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/api/test_task_model_contract.py +0 -0
  193. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/api/test_vqa.py +0 -0
  194. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/config/test_editable.py +0 -0
  195. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/config/test_optional_hf.py +0 -0
  196. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/config/test_pretrained_merge.py +0 -0
  197. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/config/test_split_overrides.py +0 -0
  198. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/contracts/test_architecture.py +0 -0
  199. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/contracts/test_dependencies.py +0 -0
  200. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/contracts/test_package.py +0 -0
  201. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/contracts/test_release_versions.py +0 -0
  202. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/contracts/test_runner_contract.py +0 -0
  203. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/core/test_classification_trainer.py +0 -0
  204. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/core/test_hf_runtime.py +0 -0
  205. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/core/test_localization_hf_backend.py +0 -0
  206. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/core/test_training_components.py +0 -0
  207. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/core/test_video_processing.py +0 -0
  208. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/data/test_classification_paths.py +0 -0
  209. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/data/test_h5_tracking.py +0 -0
  210. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/data/test_hf_json_spotting.py +0 -0
  211. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/data/test_localization_dali.py +0 -0
  212. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/data/test_localization_intervals.py +0 -0
  213. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/data/test_osl_formats.py +0 -0
  214. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_classification_metrics.py +0 -0
  215. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_header_rule_spotter.py +0 -0
  216. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_header_skeleton_spotter.py +0 -0
  217. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_localization_metrics.py +0 -0
  218. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_temporal_shift.py +0 -0
  219. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_vqa_metrics.py +0 -0
  220. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_vqa_qwen_xvars.py +0 -0
  221. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_vqa_training_lora.py +0 -0
  222. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/models/test_vqa_xvars_videochatgpt.py +0 -0
  223. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/tools/test_extract_xvars_features.py +0 -0
  224. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/tools/test_release_manifest.py +0 -0
  225. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/tools/test_report_summary.py +0 -0
  226. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/tools/test_setup.py +0 -0
  227. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tests/unit/tools/test_spotting_classification.py +0 -0
  228. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/build_sn_vqa_2026_vqa.py +0 -0
  229. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/build_sngar_spotting.py +0 -0
  230. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/build_soccernet_gar.py +0 -0
  231. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/build_soccernet_gar_action_spotting.py +0 -0
  232. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/build_soccernet_gar_vqa.py +0 -0
  233. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/build_xvars_indexes.py +0 -0
  234. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/extract_xvars_clip_features.py +0 -0
  235. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/osl_json_to_parquet_webdataset.py +0 -0
  236. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/parquet_webdataset_to_osl_json.py +0 -0
  237. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/sngar_dataset_card.py +0 -0
  238. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/sngar_events.py +0 -0
  239. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/spotting_to_classification.py +0 -0
  240. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/spotting_tracking_to_classification.py +0 -0
  241. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/convert/verify_sngar_spotting.py +0 -0
  242. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/download/download_hf_repo.py +0 -0
  243. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/download/download_osl_hf.py +0 -0
  244. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/download/push_sngar_spotting.py +0 -0
  245. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/download/upload_osl_hf.py +0 -0
  246. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/train/train_config.py +0 -0
  247. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/training/classification.py +0 -0
  248. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/training/localization.py +0 -0
  249. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/training/vqa.py +0 -0
  250. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/upload/upload_model_hf.py +0 -0
  251. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/upload/upload_sngar_tracking_full.py +0 -0
  252. {opensportslib-0.3.3.dev3 → opensportslib-0.3.4.dev1}/tools/upload/upload_sngar_videos.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opensportslib
3
- Version: 0.3.3.dev3
3
+ Version: 0.3.4.dev1
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
@@ -199,6 +199,12 @@ and [VQA guide](docs/tools/vqa.md).
199
199
 
200
200
  OpenSportsLib provides APIs and scripts for downloading and uploading OSL datasets with Hugging Face.
201
201
 
202
+ For `tracking_tracab`, both transfer formats include the original DAT and all
203
+ referenced metadata JSON/TF05/TF08 XML files. Uploads reject missing tracking
204
+ assets; full downloads validate completeness. Annotation-only downloads defer
205
+ assets until a sample/input download or missing-file hydration is requested.
206
+ See [TRACAB transfer behavior](docs/tracking_tracab.md#dataset-loading-and-persistence).
207
+
202
208
  For SN-GAR classification and action-spotting configurations, setup, caching,
203
209
  and training commands, see the [SN-GAR examples](examples/sngar/README.md).
204
210
 
@@ -330,3 +336,13 @@ For synchronized native-FPS GAR action clips and optional exact frame reproducti
330
336
 
331
337
  For full-rate tracking clips with the same classification sample IDs, see the
332
338
  [tracking conversion script](docs/tools/spotting-tracking-to-classification.md).
339
+
340
+
341
+ ### Raw TRACAB tracking
342
+
343
+ `tracking_tracab` is supported by classification and localization tracking loaders
344
+ for local OSL JSON, Hugging Face JSON and indexed WebDataset sources. Set the
345
+ input modality to `tracking_tracab`; reference the original metadata JSON with
346
+ `metadata_path` and retain UTC period calibration and team codes in each input. `params.annotation_head` selects a head such as
347
+ `action` or `headers`. See [the DAT contract and loading guide](docs/tracking_tracab.md) for the
348
+ schema, configuration, caching and backward-compatible Parquet behavior.
@@ -160,6 +160,12 @@ and [VQA guide](docs/tools/vqa.md).
160
160
 
161
161
  OpenSportsLib provides APIs and scripts for downloading and uploading OSL datasets with Hugging Face.
162
162
 
163
+ For `tracking_tracab`, both transfer formats include the original DAT and all
164
+ referenced metadata JSON/TF05/TF08 XML files. Uploads reject missing tracking
165
+ assets; full downloads validate completeness. Annotation-only downloads defer
166
+ assets until a sample/input download or missing-file hydration is requested.
167
+ See [TRACAB transfer behavior](docs/tracking_tracab.md#dataset-loading-and-persistence).
168
+
163
169
  For SN-GAR classification and action-spotting configurations, setup, caching,
164
170
  and training commands, see the [SN-GAR examples](examples/sngar/README.md).
165
171
 
@@ -291,3 +297,13 @@ For synchronized native-FPS GAR action clips and optional exact frame reproducti
291
297
 
292
298
  For full-rate tracking clips with the same classification sample IDs, see the
293
299
  [tracking conversion script](docs/tools/spotting-tracking-to-classification.md).
300
+
301
+
302
+ ### Raw TRACAB tracking
303
+
304
+ `tracking_tracab` is supported by classification and localization tracking loaders
305
+ for local OSL JSON, Hugging Face JSON and indexed WebDataset sources. Set the
306
+ input modality to `tracking_tracab`; reference the original metadata JSON with
307
+ `metadata_path` and retain UTC period calibration and team codes in each input. `params.annotation_head` selects a head such as
308
+ `action` or `headers`. See [the DAT contract and loading guide](docs/tracking_tracab.md) for the
309
+ schema, configuration, caching and backward-compatible Parquet behavior.
@@ -48,7 +48,7 @@ def _manifest_media_references(payload: dict[str, Any]):
48
48
  for input_obj in inputs:
49
49
  if not isinstance(input_obj, dict):
50
50
  continue
51
- for key in ("path", "ball_path"):
51
+ for key in ("path", "ball_path", "metadata_path", "tf05_path", "tf08_path"):
52
52
  if isinstance(input_obj.get(key), str):
53
53
  yield input_obj[key], lambda value, input_obj=input_obj, key=key: input_obj.__setitem__(key, value)
54
54
  values = input_obj.get("paths")
@@ -23,6 +23,7 @@ def _is_tracking_graph_modality(modality):
23
23
  return str(modality).lower() in {
24
24
  "tracking",
25
25
  "tracking_parquet",
26
+ "tracking_tracab",
26
27
  "tracking_h5",
27
28
  "player_centroids_h5",
28
29
  "player_joints_h5",
@@ -49,6 +50,13 @@ class ClassificationModel(BaseTaskModel):
49
50
  if override is not None:
50
51
  return expand(override)
51
52
 
53
+ from opensportslib.datasets.hf_json import hf_json_source, prepare_hf_json_split
54
+ if not self.is_remote and hf_json_source(self.config):
55
+ from opensportslib.core.config.accessors import set_split_source_path
56
+ prepared = prepare_hf_json_split(self.config, split)
57
+ set_split_source_path(self.config, split, str(prepared.source_path))
58
+ return str(prepared.annotation_path)
59
+
52
60
  path = get_split_annotation_path(self.config, split)
53
61
  if path:
54
62
  return expand(path)
@@ -59,6 +59,15 @@ class LocalizationModel(BaseTaskModel):
59
59
  set_split_source_path(self.config, "valid_data_frames", str(prepared.source_path))
60
60
  return str(prepared.annotation_path)
61
61
 
62
+ from opensportslib.datasets.hf_tracking import hf_tracking_source, prepare_hf_tracking_split, stage_tracking_files
63
+ if hf_tracking_source(self.config):
64
+ prepared = prepare_hf_tracking_split(self.config, split)
65
+ root = stage_tracking_files(prepared)
66
+ set_split_source_path(self.config, split, str(root))
67
+ if split == "valid":
68
+ set_split_source_path(self.config, "valid_data_frames", str(root))
69
+ return str(prepared.annotations_path)
70
+
62
71
  path = get_split_annotation_path(self.config, split)
63
72
  if path:
64
73
  return expand(path)
@@ -145,7 +145,11 @@ def _torch_cuda_available() -> bool:
145
145
 
146
146
 
147
147
  def _dali_available() -> bool:
148
- return importlib.util.find_spec("nvidia.dali") is not None
148
+ try:
149
+ return importlib.util.find_spec("nvidia.dali") is not None
150
+ except ModuleNotFoundError:
151
+ # find_spec raises when the optional parent namespace is absent.
152
+ return False
149
153
 
150
154
 
151
155
  # DALI decodes video; any other input modality (tracking parquets, features)
@@ -74,6 +74,7 @@ def _is_tracking_graph_modality(modality):
74
74
  return str(modality).lower() in {
75
75
  "tracking",
76
76
  "tracking_parquet",
77
+ "tracking_tracab",
77
78
  "tracking_h5",
78
79
  "player_centroids_h5",
79
80
  "player_joints_h5",
@@ -12,6 +12,14 @@ from opensportslib.core.utils.config import load_json
12
12
  from collections import defaultdict
13
13
 
14
14
 
15
+ def select_annotation_head(document, requested=None):
16
+ heads = document["labels"]
17
+ selected = requested or ("action" if "action" in heads else next(iter(heads)) if len(heads) == 1 else None)
18
+ if selected not in heads:
19
+ raise ValueError(f"Select annotation_head from {list(heads)}; got {requested!r}")
20
+ return selected
21
+
22
+
15
23
  LOCALIZATION_ANNOTATION_STATUSES = {"verified", "unlabeled", "excluded"}
16
24
 
17
25
 
@@ -164,7 +172,7 @@ def expand_localization_intervals(record):
164
172
 
165
173
  def load_annotations(
166
174
  annotations_path,
167
- task_key="action",
175
+ task_key=None,
168
176
  exclude_labels=None,
169
177
  multiview=False,
170
178
  input_type="video",
@@ -175,6 +183,10 @@ def load_annotations(
175
183
  with open(annotations_path, "r") as f:
176
184
  data = json.load(f)
177
185
 
186
+ if not isinstance(data["data"], list):
187
+ raise TypeError("OSL data must be a list")
188
+ task_key = select_annotation_head(data, task_key)
189
+
178
190
  # this is used for data slicing experiments.
179
191
  # and doesn't affect the validation and test sets.
180
192
  # if you haven't added "data_scaling" to the config, this will be ignored.
@@ -517,7 +529,7 @@ def annotationstoe2eformat(
517
529
  return labels_e2e, task_name_list[0]
518
530
 
519
531
 
520
- def annotationstoe2eformat_tracking(label_files, video_dirs, extract_fps):
532
+ def annotationstoe2eformat_tracking(label_files, video_dirs, extract_fps, input_type="tracking_parquet", annotation_head=None):
521
533
  """
522
534
  Adapt tracking-parquet action-spotting annotations to E2E format.
523
535
 
@@ -546,6 +558,7 @@ def annotationstoe2eformat_tracking(label_files, video_dirs, extract_fps):
546
558
  classes use to slice windows out of the cached native features.
547
559
  """
548
560
  from opensportslib.datasets.utils.tracking import load_or_build_game_cache
561
+ from opensportslib.tracking.tracab import parse_utc
549
562
 
550
563
  if not isinstance(label_files, list):
551
564
  label_files = [label_files]
@@ -562,20 +575,26 @@ def annotationstoe2eformat_tracking(label_files, video_dirs, extract_fps):
562
575
 
563
576
  annotations = load_json(label_path)
564
577
 
565
- for task_name, task_data in annotations["labels"].items():
566
- labels = task_data.get("labels", {})
567
- task_name_list.append(task_name)
578
+ task_name = select_annotation_head(annotations, annotation_head)
579
+ labels = annotations["labels"][task_name].get("labels", {})
580
+ task_name_list.append(task_name)
568
581
  classes_by_label_dir.append(labels)
569
582
 
570
583
  videos = annotations["data"]
571
584
 
572
585
  for video in tqdm.tqdm(videos):
573
- video_input = video["inputs"][0]
586
+ candidates = [i for i in video["inputs"] if i.get("type") == input_type]
587
+ if len(candidates) != 1:
588
+ raise ValueError(f"Expected one {input_type} input for {video.get('id')!r}; found {len(candidates)}")
589
+ video_input = dict(candidates[0])
590
+ for key in ("metadata_path", "tf05_path", "tf08_path"):
591
+ if video_input.get(key):
592
+ video_input[key] = os.path.abspath(os.path.join(video_dir, video_input[key]))
574
593
  video_path = video_input["path"]
575
594
  full_video_path = os.path.join(video_dir, video_path)
576
595
  assert os.path.isfile(full_video_path), full_video_path
577
596
 
578
- _, times, _ = load_or_build_game_cache(full_video_path)
597
+ _, times, _ = load_or_build_game_cache(full_video_path, descriptor=video_input)
579
598
  num_frames = len(times)
580
599
 
581
600
  native_fps = video_input.get("fps")
@@ -591,7 +610,18 @@ def annotationstoe2eformat_tracking(label_files, video_dirs, extract_fps):
591
610
 
592
611
  events = []
593
612
  for ann in video.get("events", []):
594
- position_ms = float(ann["position_ms"])
613
+ if ann.get("head", task_name) != task_name:
614
+ continue
615
+ if ann["label"] not in labels:
616
+ raise ValueError(f"Event label {ann['label']!r} absent from head {task_name!r}")
617
+ if ann.get("timestamp_utc"):
618
+ if not video_input.get("UTC_time_start"):
619
+ raise ValueError("UTC events require input.UTC_time_start")
620
+ position_ms = (parse_utc(ann["timestamp_utc"]) - parse_utc(video_input["UTC_time_start"])).total_seconds() * 1000
621
+ else:
622
+ position_ms = float(ann["position_ms"])
623
+ if position_ms < 0 or (video_input.get("duration_ms") and position_ms >= video_input["duration_ms"]):
624
+ raise ValueError(f"Event timestamp {position_ms} outside tracking timeline")
595
625
  native_idx = int(np.searchsorted(times, position_ms))
596
626
  native_idx = min(max(native_idx, 0), num_frames - 1)
597
627
  adj_frame = native_idx // stride
@@ -614,6 +644,7 @@ def annotationstoe2eformat_tracking(label_files, video_dirs, extract_fps):
614
644
  events.sort(key=lambda x: x["frame"])
615
645
 
616
646
  labels_e2e.append({
647
+ "input": dict(video_input),
617
648
  "events": events,
618
649
  "fps": sample_fps,
619
650
  "num_frames": num_frames_after,
@@ -834,7 +865,7 @@ def check_config(cfg, split="train"):
834
865
  if get_loader_backend(cfg) == "dali":
835
866
  cfg.TRAIN.execution.repartitions = get_repartition_gpu(cfg.SYSTEM.gpu.count)
836
867
  primary_modality = get_data_modality(cfg)
837
- assert primary_modality in ["rgb", "video", "tracking_parquet"]
868
+ assert primary_modality in ["rgb", "video", "tracking_parquet", "tracking_tracab"]
838
869
  backbone_type = get_component_name_by_kind(cfg, "encoder")
839
870
  assert backbone_type in [
840
871
  # From torchvision
@@ -900,8 +931,13 @@ def check_config(cfg, split="train"):
900
931
  and data_path.endswith(".json")
901
932
  and "labels" in load_json(data_path).keys()
902
933
  ):
903
- for task_name, task_data in load_json(data_path)["labels"].items():
904
- classes = task_data.get("labels", {})
934
+ document = load_json(data_path)
935
+ if primary_modality in {"tracking_parquet", "tracking_tracab"}:
936
+ head = select_annotation_head(document, get_data_params(cfg).get("annotation_head"))
937
+ classes = document["labels"][head].get("labels", {})
938
+ else:
939
+ for task_data in document["labels"].values():
940
+ classes = task_data.get("labels", {})
905
941
  else:
906
942
  assert isinstance(cfg.DATA.common.classes, (list, ListConfig))
907
943
  classes = cfg.DATA.common.classes
@@ -64,7 +64,7 @@ def build(config, annotations_path, processor=None, split="train"):
64
64
  """
65
65
  modality = get_data_modality(config).lower()
66
66
 
67
- if modality in ("tracking", "tracking_parquet"):
67
+ if modality in ("tracking", "tracking_parquet", "tracking_tracab"):
68
68
  from opensportslib.datasets.hf_tracking import hf_tracking_source
69
69
 
70
70
  if hf_tracking_source(config):
@@ -133,7 +133,8 @@ class ClassificationDataset(Dataset):
133
133
  annotation_input_type = "frames_npy"
134
134
 
135
135
  self.samples, self.label_map = load_annotations(
136
- annotations_path,
136
+ annotations_path,
137
+ task_key=data_params.get("annotation_head"),
137
138
  exclude_labels=self.exclude_labels,
138
139
  multiview=is_multiview,
139
140
  input_type=annotation_input_type,
@@ -540,7 +541,7 @@ class TrackingDataset(ClassificationDataset):
540
541
  continue
541
542
 
542
543
  clip_path = clip_paths[0]
543
- df = self._load_tracking_clip(clip_path)
544
+ df = self._load_tracking_clip(clip_path, item["inputs"][0])
544
545
 
545
546
  num_frames = len(df)
546
547
  all_features = np.zeros(
@@ -568,7 +569,7 @@ class TrackingDataset(ClassificationDataset):
568
569
  # regardless of transforms.
569
570
  edge_indices = []
570
571
  for t in range(num_frames):
571
- edge_index = self.build_edge_index(
572
+ edge_index = self._build_edge_index(
572
573
  all_features[t],
573
574
  all_positions[t],
574
575
  self.edge_type,
@@ -587,7 +588,7 @@ class TrackingDataset(ClassificationDataset):
587
588
 
588
589
  print(f"Loaded {len(self.processed_samples)} {self.split} samples")
589
590
 
590
- def _load_tracking_clip(self, path):
591
+ def _load_tracking_clip(self, path, descriptor=None):
591
592
  """read a single parquet tracking clip.
592
593
 
593
594
  Args:
@@ -600,6 +601,10 @@ class TrackingDataset(ClassificationDataset):
600
601
  import pandas as pd
601
602
 
602
603
  full_path = os.path.join(self.video_path, path)
604
+ if descriptor and descriptor.get("type") == "tracking_tracab":
605
+ from opensportslib.tracking import TracabTrackingReader
606
+ with TracabTrackingReader(full_path, descriptor, metadata_base_dir=self.video_path) as reader:
607
+ return pd.DataFrame(reader.iter_uniform_rows())
603
608
  return pd.read_parquet(full_path)
604
609
 
605
610
  def __getitem__(self, idx):
@@ -687,7 +692,7 @@ class TrackingDataset(ClassificationDataset):
687
692
  raise ValueError(f"No tracking paths found for item {idx}")
688
693
 
689
694
  clip_path = clip_paths[0]
690
- df = self._load_tracking_clip(clip_path)
695
+ df = self._load_tracking_clip(clip_path, item["inputs"][0])
691
696
 
692
697
  num_frames = len(df)
693
698
  all_features = np.zeros(
@@ -765,8 +770,8 @@ class HFTrackingDataset(TrackingDataset):
765
770
  self._hf_reader = HFTarTrackingReader(prepared)
766
771
  super().__init__(config, str(prepared.annotations_path), split)
767
772
 
768
- def _load_tracking_clip(self, path):
769
- return self._hf_reader.read_parquet(path)
773
+ def _load_tracking_clip(self, path, descriptor=None):
774
+ return self._hf_reader.read_tracking(path, descriptor)
770
775
 
771
776
 
772
777
  class H5TrackingDataset(ClassificationDataset):
@@ -130,10 +130,13 @@ def prepare_hf_json_split(config, split: str) -> PreparedHFJsonSplit:
130
130
  f"Expected one {media_type!r} input for sample {sample.get('game_id', sample.get('id'))!r}"
131
131
  )
132
132
  item = dict(selected[0])
133
- filename = _safe_path(str(item.get("path") or ""))
134
- if not filename.startswith(f"{split}/"):
135
- raise ValueError(f"Media path {filename!r} is outside split {split!r}")
136
- filenames.add(filename)
133
+ for key in ("path", "metadata_path", "tf05_path", "tf08_path"):
134
+ if key != "path" and not item.get(key):
135
+ continue
136
+ filename = _safe_path(str(item.get(key) or ""))
137
+ if key == "path" and not filename.startswith(f"{split}/"):
138
+ raise ValueError(f"Media path {filename!r} is outside split {split!r}")
139
+ filenames.add(filename)
137
140
  sample["inputs"] = [item]
138
141
 
139
142
  def stage_media(filename: str) -> None:
@@ -13,7 +13,7 @@ from collections import OrderedDict
13
13
  from dataclasses import dataclass
14
14
  from pathlib import Path
15
15
 
16
- from opensportslib.core.config.accessors import get_input_cfg
16
+ from opensportslib.core.config.accessors import get_input_cfg, get_data_modality
17
17
 
18
18
 
19
19
  logger = logging.getLogger(__name__)
@@ -126,7 +126,14 @@ def prepare_hf_tracking_split(config, split: str) -> PreparedTrackingSplit:
126
126
 
127
127
  _set_resolved_revision(config, resolved)
128
128
  safe_repo = re.sub(r"[^A-Za-z0-9_.-]+", "--", repo_id)
129
+ media_type = str(source.get("input_type") or get_data_modality(config))
130
+ if media_type == "tracking":
131
+ media_type = "tracking_parquet"
132
+ if media_type not in {"tracking_parquet", "tracking_tracab"}:
133
+ raise ValueError(f"Unsupported tracking input type: {media_type}")
129
134
  directory = cache_dir / safe_repo / resolved / split
135
+ if media_type != "tracking_parquet":
136
+ directory = directory / media_type
130
137
  directory.mkdir(parents=True, exist_ok=True)
131
138
  annotations_path = directory / "annotations.json"
132
139
  index_path = directory / "index.json"
@@ -181,7 +188,7 @@ def prepare_hf_tracking_split(config, split: str) -> PreparedTrackingSplit:
181
188
 
182
189
  manifest = {}
183
190
  for row in rows("shard_manifest.parquet"):
184
- if row.get("file_role") not in (None, "", "primary") or row.get("input_type") != "tracking_parquet":
191
+ if row.get("file_role") not in (None, "", "primary", "metadata", "tf05", "tf08") or row.get("input_type") != media_type:
185
192
  continue
186
193
  key = (str(row["sample_id"]), str(row["relative_path"]))
187
194
  if row.get("status") == "ok" and row.get("wds_member"):
@@ -190,17 +197,20 @@ def prepare_hf_tracking_split(config, split: str) -> PreparedTrackingSplit:
190
197
  members = {}
191
198
  for sample_id, (shard_name, sample) in locations.items():
192
199
  for input_item in sample.get("inputs", []):
193
- if input_item.get("type") != "tracking_parquet":
200
+ if input_item.get("type") != media_type:
194
201
  continue
195
- path = str(input_item.get("path") or "")
196
- location = manifest.get((sample_id, path))
197
- if not path or location is None or location[0] != shard_name:
198
- raise ValueError(f"Missing tracking TAR member for {sample_id!r}: {path!r}")
199
- if path in members and members[path] != location:
200
- raise ValueError(f"Tracking path maps to multiple TAR members: {path!r}")
201
- members[path] = location
202
+ for key in ("path", "metadata_path", "tf05_path", "tf08_path"):
203
+ if key != "path" and not input_item.get(key):
204
+ continue
205
+ path = str(input_item.get(key) or "")
206
+ location = manifest.get((sample_id, path))
207
+ if not path or location is None or location[0] != shard_name:
208
+ raise ValueError(f"Missing tracking TAR member for {sample_id!r} ({key}): {path!r}")
209
+ if path in members and members[path] != location:
210
+ raise ValueError(f"Tracking path maps to multiple TAR members: {path!r}")
211
+ members[path] = location
202
212
  if not members:
203
- raise ValueError(f"{split} contains no tracking_parquet inputs")
213
+ raise ValueError(f"{split} contains no {media_type} inputs")
204
214
 
205
215
  _write_json_atomic(annotations_path, {**header, "data": samples})
206
216
  _write_json_atomic(index_path, {"members": members})
@@ -277,10 +287,33 @@ class HFTarTrackingReader:
277
287
  return tar
278
288
 
279
289
  def read_parquet(self, path: str):
290
+ return self.read_tracking(path)
291
+
292
+ def read_tracking(self, path: str, descriptor=None):
280
293
  import pandas as pd
281
294
 
282
295
  if path not in self.members:
283
296
  raise FileNotFoundError(f"Tracking clip is absent from Hub manifest: {path}")
297
+ metadata = None
298
+ xml_metadata = {}
299
+ for key in ("metadata_path", "tf05_path", "tf08_path"):
300
+ if not descriptor or not descriptor.get(key):
301
+ continue
302
+ metadata_path = descriptor[key]
303
+ if metadata_path not in self.members:
304
+ raise FileNotFoundError(f"Tracking metadata is absent from Hub manifest: {metadata_path}")
305
+ metadata_shard, metadata_member = self.members[metadata_path]
306
+ try:
307
+ from opensportslib.tracking.native import read_document
308
+ with self._tar(metadata_shard).extractfile(metadata_member) as stream:
309
+ document = read_document(stream, format="json" if key == "metadata_path" else "xml")
310
+ document.source = metadata_path
311
+ if key == "metadata_path":
312
+ metadata = document
313
+ else:
314
+ xml_metadata[key] = document
315
+ except (KeyError, ValueError, TypeError) as exc:
316
+ raise ValueError(f"TRACAB metadata {metadata_path}: {exc}") from exc
284
317
  shard_name, member_name = self.members[path]
285
318
  tar = self._tar(shard_name)
286
319
  try:
@@ -289,9 +322,42 @@ class HFTarTrackingReader:
289
322
  if stream is None:
290
323
  raise KeyError(member_name)
291
324
  with stream:
325
+ if descriptor and descriptor.get("type") == "tracking_tracab":
326
+ from opensportslib.tracking import TracabTrackingReader
327
+ with TracabTrackingReader(stream, descriptor, metadata=metadata, xml_metadata=xml_metadata) as reader:
328
+ return pd.DataFrame(reader.iter_uniform_rows())
292
329
  contents = stream.read()
293
330
  except KeyError as exc:
294
331
  raise FileNotFoundError(
295
332
  f"Tracking TAR member {member_name!r} is missing from {shard_name!r}"
296
333
  ) from exc
297
334
  return pd.read_parquet(io.BytesIO(contents))
335
+
336
+
337
+ def stage_tracking_files(prepared):
338
+ """Materialize raw members once for localization's mmap feature cache."""
339
+ import shutil
340
+ from opensportslib.datasets.hf_json import _safe_path
341
+
342
+ root = prepared.annotations_path.parent / "media"
343
+ root.mkdir(exist_ok=True)
344
+ with (root / ".stage.lock").open("w") as lock:
345
+ fcntl.flock(lock, fcntl.LOCK_EX)
346
+ reader = HFTarTrackingReader(prepared)
347
+ try:
348
+ for path, (shard, member) in reader.members.items():
349
+ destination = root / _safe_path(path)
350
+ if destination.is_file():
351
+ continue
352
+ destination.parent.mkdir(parents=True, exist_ok=True)
353
+ temporary = destination.with_name(destination.name + f".tmp-{os.getpid()}")
354
+ try:
355
+ with reader._tar(shard).extractfile(member) as source, temporary.open("wb") as target:
356
+ shutil.copyfileobj(source, target)
357
+ os.replace(temporary, destination)
358
+ finally:
359
+ temporary.unlink(missing_ok=True)
360
+ finally:
361
+ for tar in reader._open_tars.values():
362
+ tar.close()
363
+ return root
@@ -470,6 +470,8 @@ class LocalizationDataset(Dataset):
470
470
  dilate_len=self.data_cfg.dilate_len,
471
471
  augmentations=_build_tracking_spotting_augmentations(self.config),
472
472
  normalize=normalize,
473
+ input_type=get_runtime_modality(self.config),
474
+ annotation_head=get_data_params(self.config).get("annotation_head"),
473
475
  )
474
476
  elif dataset_type == "TrackingActionSpotVideo":
475
477
  encoder_params = get_component_params_by_kind(self.config, "encoder")
@@ -485,6 +487,8 @@ class LocalizationDataset(Dataset):
485
487
  r=encoder_params.get("radius"),
486
488
  overlap_len=getattr(cfg, "overlap_len", self.data_cfg.clip_len // 2),
487
489
  normalize=normalize,
490
+ input_type=get_runtime_modality(self.config),
491
+ annotation_head=get_data_params(self.config).get("annotation_head"),
488
492
  )
489
493
  else:
490
494
  dataset = None
@@ -1276,17 +1280,24 @@ class _TrackingGraphWindowMixin:
1276
1280
  """
1277
1281
  return batch["frame"].to(device)
1278
1282
 
1279
- def _get_game_cache(self, video_path):
1283
+ def _get_game_cache(self, video_path, descriptor=None):
1280
1284
  """lazily load (and memoize for the lifetime of this dataset
1281
1285
  instance/worker) a game's cached whole-match features."""
1282
- if video_path not in self._game_cache:
1283
- self._game_cache[video_path] = self._load_or_build_game_cache(video_path)
1284
- return self._game_cache[video_path]
1286
+ companion_signatures = []
1287
+ if descriptor and descriptor.get("type") == "tracking_tracab":
1288
+ for field in ("metadata_path", "tf05_path", "tf08_path"):
1289
+ if descriptor.get(field):
1290
+ stat = os.stat(descriptor[field])
1291
+ companion_signatures.append((field, stat.st_size, stat.st_mtime_ns))
1292
+ key = (video_path, json.dumps(descriptor, sort_keys=True), tuple(companion_signatures))
1293
+ if key not in self._game_cache:
1294
+ self._game_cache[key] = self._load_or_build_game_cache(video_path, descriptor=descriptor)
1295
+ return self._game_cache[key]
1285
1296
 
1286
1297
  def _slice_window(self, video_meta, base_idx):
1287
1298
  """Fetch the game cache and slice a decimated feature window +
1288
1299
  per-frame position lists out of it (see tracking.slice_window)."""
1289
- features_cache, _, positions_cache = self._get_game_cache(video_meta["video"])
1300
+ features_cache, _, positions_cache = self._get_game_cache(video_meta["video"], video_meta.get("input"))
1290
1301
  return self._slice_window_fn(
1291
1302
  features_cache, positions_cache, base_idx, self._clip_len, video_meta["stride"]
1292
1303
  )
@@ -1364,12 +1375,14 @@ class TrackingActionSpotDataset(Dataset, _TrackingGraphWindowMixin):
1364
1375
  fg_upsample=-1,
1365
1376
  augmentations=None,
1366
1377
  normalize=True,
1378
+ input_type="tracking_parquet",
1379
+ annotation_head=None,
1367
1380
  ):
1368
1381
  from opensportslib.core.utils.load_annotations import annotationstoe2eformat_tracking
1369
1382
 
1370
1383
  self._src_file = label_file
1371
1384
  self._labels, self.task_name = annotationstoe2eformat_tracking(
1372
- label_file, video_dir, extract_fps
1385
+ label_file, video_dir, extract_fps, input_type, annotation_head
1373
1386
  )
1374
1387
  self._class_dict = _normalize_class_dict(classes)
1375
1388
  self._video_idxs = {x["video"]: i for i, x in enumerate(self._labels)}
@@ -1528,12 +1541,14 @@ class TrackingActionSpotVideoDataset(Dataset, _TrackingGraphWindowMixin, Dataset
1528
1541
  pad_len=5,
1529
1542
  skip_partial_end=True,
1530
1543
  normalize=True,
1544
+ input_type="tracking_parquet",
1545
+ annotation_head=None,
1531
1546
  ):
1532
1547
  from opensportslib.core.utils.load_annotations import annotationstoe2eformat_tracking
1533
1548
 
1534
1549
  self._src_file = label_file
1535
1550
  self._labels, self.task_name = annotationstoe2eformat_tracking(
1536
- label_file, video_dir, extract_fps
1551
+ label_file, video_dir, extract_fps, input_type, annotation_head
1537
1552
  )
1538
1553
  self._class_dict = _normalize_class_dict(classes)
1539
1554
  self._video_idxs = {x["path"]: i for i, x in enumerate(self._labels)}