opensportslib 0.3.1.dev14__tar.gz → 0.3.1.dev16__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 (232) hide show
  1. {opensportslib-0.3.1.dev14/opensportslib.egg-info → opensportslib-0.3.1.dev16}/PKG-INFO +13 -9
  2. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/README.md +10 -8
  3. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/adaptation/spotta.py +4 -38
  4. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/localization/e2e_spotta.yaml +1 -10
  5. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/config/loader.py +18 -0
  6. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/utils/video_processing.py +2 -3
  7. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/datasets/localization_dataset.py +44 -6
  8. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/remote_registry.py +29 -11
  9. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/setup/setup.py +61 -25
  10. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16/opensportslib.egg-info}/PKG-INFO +13 -9
  11. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib.egg-info/SOURCES.txt +56 -31
  12. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib.egg-info/requires.txt +2 -0
  13. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/pyproject.toml +7 -2
  14. opensportslib-0.3.1.dev16/scripts/redact_test_stream.py +49 -0
  15. opensportslib-0.3.1.dev16/scripts/summarize_test_report.py +147 -0
  16. opensportslib-0.3.1.dev16/tests/__init__.py +1 -0
  17. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tests/conftest.py +110 -3
  18. opensportslib-0.3.1.dev16/tests/helpers/__init__.py +1 -0
  19. opensportslib-0.3.1.dev16/tests/helpers/configs.py +16 -0
  20. opensportslib-0.3.1.dev16/tests/helpers/pipeline_stubs.py +71 -0
  21. opensportslib-0.3.1.dev16/tests/integration/classification/test_pipeline.py +31 -0
  22. opensportslib-0.3.1.dev16/tests/integration/localization/test_pipeline.py +26 -0
  23. opensportslib-0.3.1.dev16/tests/integration/vqa/test_pipeline.py +46 -0
  24. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tests/release/_release_common.py +46 -15
  25. opensportslib-0.3.1.dev16/tests/release/test_00_environment.py +28 -0
  26. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tests/release/test_classification_release.py +153 -35
  27. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tests/release/test_localization_release.py +18 -16
  28. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tests/release/test_vqa_release.py +23 -17
  29. opensportslib-0.3.1.dev16/tests/smoke/test_cli.py +31 -0
  30. opensportslib-0.3.1.dev16/tests/smoke/test_environment.py +45 -0
  31. opensportslib-0.3.1.dev14/tests/test_remote_model_registry.py → opensportslib-0.3.1.dev16/tests/unit/api/test_remote_registry.py +26 -3
  32. opensportslib-0.3.1.dev16/tests/unit/api/test_remote_sessions.py +56 -0
  33. opensportslib-0.3.1.dev16/tests/unit/api/test_server_jobs.py +63 -0
  34. opensportslib-0.3.1.dev14/tests/test_server_model_registry.py → opensportslib-0.3.1.dev16/tests/unit/api/test_server_registry.py +20 -2
  35. opensportslib-0.3.1.dev16/tests/unit/api/test_server_startup_scripts.py +50 -0
  36. opensportslib-0.3.1.dev14/tests/test_task_model_api_contract.py → opensportslib-0.3.1.dev16/tests/unit/api/test_task_model_contract.py +50 -12
  37. opensportslib-0.3.1.dev14/tests/test_vqa_api.py → opensportslib-0.3.1.dev16/tests/unit/api/test_vqa.py +27 -133
  38. opensportslib-0.3.1.dev14/tests/test_config_architecture.py → opensportslib-0.3.1.dev16/tests/unit/config/test_architecture.py +27 -1
  39. opensportslib-0.3.1.dev14/tests/test_editable_config.py → opensportslib-0.3.1.dev16/tests/unit/config/test_editable.py +1 -1
  40. opensportslib-0.3.1.dev14/tests/test_pretrained_config_merge_policy.py → opensportslib-0.3.1.dev16/tests/unit/config/test_pretrained_merge.py +1 -1
  41. opensportslib-0.3.1.dev16/tests/unit/contracts/test_architecture.py +73 -0
  42. opensportslib-0.3.1.dev16/tests/unit/contracts/test_dependencies.py +71 -0
  43. opensportslib-0.3.1.dev16/tests/unit/contracts/test_package.py +64 -0
  44. {opensportslib-0.3.1.dev14/tests → opensportslib-0.3.1.dev16/tests/unit/contracts}/test_release_versions.py +1 -1
  45. opensportslib-0.3.1.dev16/tests/unit/contracts/test_runner_contract.py +37 -0
  46. opensportslib-0.3.1.dev16/tests/unit/core/test_training_components.py +63 -0
  47. opensportslib-0.3.1.dev16/tests/unit/core/test_video_processing.py +66 -0
  48. {opensportslib-0.3.1.dev14/tests → opensportslib-0.3.1.dev16/tests/unit/data}/test_localization_intervals.py +20 -0
  49. opensportslib-0.3.1.dev16/tests/unit/data/test_osl_formats.py +56 -0
  50. opensportslib-0.3.1.dev16/tests/unit/models/test_classification_metrics.py +21 -0
  51. opensportslib-0.3.1.dev16/tests/unit/models/test_localization_metrics.py +25 -0
  52. opensportslib-0.3.1.dev16/tests/unit/models/test_temporal_shift.py +29 -0
  53. opensportslib-0.3.1.dev16/tests/unit/tools/test_report_summary.py +50 -0
  54. opensportslib-0.3.1.dev14/tests/test_setup_cli.py → opensportslib-0.3.1.dev16/tests/unit/tools/test_setup.py +76 -2
  55. opensportslib-0.3.1.dev14/tests/test_subset_train_infer_integration.py +0 -292
  56. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/LICENSE +0 -0
  57. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/LICENSE-COMMERCIAL +0 -0
  58. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/MANIFEST.in +0 -0
  59. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/examples/quickstart/basic_classification.py +0 -0
  60. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/examples/quickstart/basic_localization.py +0 -0
  61. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/examples/quickstart/basic_vqa.py +0 -0
  62. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/__init__.py +0 -0
  63. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/adaptation/__init__.py +0 -0
  64. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/apis/__init__.py +0 -0
  65. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/apis/base_task_model.py +0 -0
  66. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/apis/classification.py +0 -0
  67. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/apis/config.py +0 -0
  68. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/apis/configuration.py +0 -0
  69. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/apis/localization.py +0 -0
  70. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/apis/vqa.py +0 -0
  71. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/cli.py +0 -0
  72. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/classification/default.yaml +0 -0
  73. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/classification/sngar_frames.yaml +0 -0
  74. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/classification/sngar_tracking.yaml +0 -0
  75. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/classification/video.yaml +0 -0
  76. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/default.yaml +0 -0
  77. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/localization/calf_resnetpca512.yaml +0 -0
  78. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/localization/default.yaml +0 -0
  79. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/localization/h5_header_distance.yaml +0 -0
  80. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/localization/h5_header_skeleton.yaml +0 -0
  81. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/localization/netvladpp_resnetpca512.yaml +0 -0
  82. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/localization/tracking_action_spotting.yaml +0 -0
  83. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/localization/video_dali.yaml +0 -0
  84. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/localization/video_ocv.yaml +0 -0
  85. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/vqa/default.yaml +0 -0
  86. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/vqa/qwen.yaml +0 -0
  87. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/vqa/qwen3_vl_native.yaml +0 -0
  88. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/vqa/qwen_lora.yaml +0 -0
  89. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/vqa/qwen_sngar_frames.yaml +0 -0
  90. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/configs/vqa/xvars.yaml +0 -0
  91. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/__init__.py +0 -0
  92. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/config/__init__.py +0 -0
  93. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/config/accessors.py +0 -0
  94. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/config/conflicts.py +0 -0
  95. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/config/editable.py +0 -0
  96. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/config/migrate.py +0 -0
  97. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/config/migrations/__init__.py +0 -0
  98. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/config/migrations/legacy_to_canonical.py +0 -0
  99. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/config/rule_variants.py +0 -0
  100. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/config/runtime_adapter.py +0 -0
  101. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/config/schema.py +0 -0
  102. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/config/schemas/__init__.py +0 -0
  103. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/config/schemas/schema_canonical.py +0 -0
  104. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/config/schemas/schema_legacy.py +0 -0
  105. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/config/validate.py +0 -0
  106. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/loss/__init__.py +0 -0
  107. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/loss/builder.py +0 -0
  108. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/loss/calf.py +0 -0
  109. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/loss/ce.py +0 -0
  110. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/loss/combine.py +0 -0
  111. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/loss/nll.py +0 -0
  112. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/optimizer/__init__.py +0 -0
  113. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/optimizer/builder.py +0 -0
  114. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/sampler/weighted_sampler.py +0 -0
  115. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/scheduler/__init__.py +0 -0
  116. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/scheduler/builder.py +0 -0
  117. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/trainer/__init__.py +0 -0
  118. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/trainer/classification_trainer.py +0 -0
  119. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/trainer/localization_trainer.py +0 -0
  120. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/trainer/vqa_trainer.py +0 -0
  121. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/utils/checkpoint.py +0 -0
  122. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/utils/config.py +0 -0
  123. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/utils/config_normalize.py +0 -0
  124. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/utils/data.py +0 -0
  125. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/utils/ddp.py +0 -0
  126. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/utils/default_args.py +0 -0
  127. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/utils/direct_video.py +0 -0
  128. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/utils/hf_runtime.py +0 -0
  129. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/utils/lightning.py +0 -0
  130. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/utils/load_annotations.py +0 -0
  131. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/utils/seed.py +0 -0
  132. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/core/utils/wandb.py +0 -0
  133. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/datasets/__init__.py +0 -0
  134. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/datasets/builder.py +0 -0
  135. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/datasets/classification_dataset.py +0 -0
  136. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/datasets/utils/__init__.py +0 -0
  137. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/datasets/utils/h5_tracking.py +0 -0
  138. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/datasets/utils/tracking.py +0 -0
  139. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/datasets/vqa_dataset.py +0 -0
  140. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/legacy_config/classification.yaml +0 -0
  141. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/legacy_config/localization-e2e-ocv.yaml +0 -0
  142. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/legacy_config/localization-json_calf_resnetpca512.yaml +0 -0
  143. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/legacy_config/localization-json_netvlad++_resnetpca512.yaml +0 -0
  144. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/legacy_config/localization.yaml +0 -0
  145. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/legacy_config/sngar-frames.yaml +0 -0
  146. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/legacy_config/sngar-tracking.yaml +0 -0
  147. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/metrics/classification_metric.py +0 -0
  148. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/metrics/localization_metric.py +0 -0
  149. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/metrics/vqa_metric.py +0 -0
  150. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/__init__.py +0 -0
  151. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/backbones/builder.py +0 -0
  152. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/base/contextaware.py +0 -0
  153. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/base/e2e.py +0 -0
  154. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/base/learnablepooling.py +0 -0
  155. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/base/qwen_vl_native.py +0 -0
  156. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/base/qwen_xvars.py +0 -0
  157. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/base/rule_based.py +0 -0
  158. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/base/tracking.py +0 -0
  159. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/base/vars.py +0 -0
  160. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/base/video.py +0 -0
  161. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/base/video_chatgpt_compat.py +0 -0
  162. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/base/video_mae.py +0 -0
  163. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/base/xvars_videochatgpt.py +0 -0
  164. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/builder.py +0 -0
  165. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/heads/builder.py +0 -0
  166. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/neck/builder.py +0 -0
  167. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/utils/common.py +0 -0
  168. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/utils/impl/__init__.py +0 -0
  169. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/utils/impl/asformer.py +0 -0
  170. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/utils/impl/calf.py +0 -0
  171. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/utils/impl/gsm.py +0 -0
  172. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/utils/impl/gtad.py +0 -0
  173. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/utils/impl/tsm.py +0 -0
  174. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/utils/litebase.py +0 -0
  175. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/utils/modules.py +0 -0
  176. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/utils/shift.py +0 -0
  177. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/utils/utils.py +0 -0
  178. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/utils/vqa_prediction_priors.py +0 -0
  179. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/utils/vqa_prompting.py +0 -0
  180. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/models/utils/xvars_clip_index.py +0 -0
  181. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/tools/__init__.py +0 -0
  182. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/tools/_common.py +0 -0
  183. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/tools/hf_transfer.py +0 -0
  184. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/tools/osl_json_to_parquet.py +0 -0
  185. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib/tools/parquet_to_osl_json.py +0 -0
  186. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib.egg-info/dependency_links.txt +0 -0
  187. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib.egg-info/entry_points.txt +0 -0
  188. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/opensportslib.egg-info/top_level.txt +0 -0
  189. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/scripts/release_versions.py +0 -0
  190. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/scripts/run_h5_header_rule_inference.py +0 -0
  191. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/setup.cfg +0 -0
  192. /opensportslib-0.3.1.dev14/tests/test_spotta_e2e.py → /opensportslib-0.3.1.dev16/tests/integration/localization/test_spotta.py +0 -0
  193. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tests/release/__init__.py +0 -0
  194. /opensportslib-0.3.1.dev14/tests/test_config_utils_smoke.py → /opensportslib-0.3.1.dev16/tests/smoke/test_config_utils.py +0 -0
  195. /opensportslib-0.3.1.dev14/tests/test_package_smoke.py → /opensportslib-0.3.1.dev16/tests/smoke/test_package.py +0 -0
  196. /opensportslib-0.3.1.dev14/tests/test_public_apis_smoke.py → /opensportslib-0.3.1.dev16/tests/smoke/test_public_apis.py +0 -0
  197. /opensportslib-0.3.1.dev14/tests/test_optional_hf_config.py → /opensportslib-0.3.1.dev16/tests/unit/config/test_optional_hf.py +0 -0
  198. /opensportslib-0.3.1.dev14/tests/test_config_split_override_sync.py → /opensportslib-0.3.1.dev16/tests/unit/config/test_split_overrides.py +0 -0
  199. /opensportslib-0.3.1.dev14/tests/test_classification_trainer_dataloader.py → /opensportslib-0.3.1.dev16/tests/unit/core/test_classification_trainer.py +0 -0
  200. /opensportslib-0.3.1.dev14/tests/test_localization_hf_backend_override.py → /opensportslib-0.3.1.dev16/tests/unit/core/test_localization_hf_backend.py +0 -0
  201. /opensportslib-0.3.1.dev14/tests/test_classification_dataset_paths.py → /opensportslib-0.3.1.dev16/tests/unit/data/test_classification_paths.py +0 -0
  202. /opensportslib-0.3.1.dev14/tests/test_h5_tracking_dataset.py → /opensportslib-0.3.1.dev16/tests/unit/data/test_h5_tracking.py +0 -0
  203. /opensportslib-0.3.1.dev14/tests/test_localization_dali_filenames.py → /opensportslib-0.3.1.dev16/tests/unit/data/test_localization_dali.py +0 -0
  204. /opensportslib-0.3.1.dev14/tests/test_h5_header_rule_spotter.py → /opensportslib-0.3.1.dev16/tests/unit/models/test_header_rule_spotter.py +0 -0
  205. /opensportslib-0.3.1.dev14/tests/test_h5_header_skeleton_spotter.py → /opensportslib-0.3.1.dev16/tests/unit/models/test_header_skeleton_spotter.py +0 -0
  206. /opensportslib-0.3.1.dev14/tests/test_vqa_metrics_semantic.py → /opensportslib-0.3.1.dev16/tests/unit/models/test_vqa_metrics.py +0 -0
  207. {opensportslib-0.3.1.dev14/tests → opensportslib-0.3.1.dev16/tests/unit/models}/test_vqa_qwen_xvars.py +0 -0
  208. {opensportslib-0.3.1.dev14/tests → opensportslib-0.3.1.dev16/tests/unit/models}/test_vqa_training_lora.py +0 -0
  209. {opensportslib-0.3.1.dev14/tests → opensportslib-0.3.1.dev16/tests/unit/models}/test_vqa_xvars_videochatgpt.py +0 -0
  210. /opensportslib-0.3.1.dev14/tests/test_conversion_tools.py → /opensportslib-0.3.1.dev16/tests/unit/tools/test_conversion.py +0 -0
  211. {opensportslib-0.3.1.dev14/tests → opensportslib-0.3.1.dev16/tests/unit/tools}/test_extract_xvars_features.py +0 -0
  212. /opensportslib-0.3.1.dev14/tests/test_hf_transfer_tools.py → /opensportslib-0.3.1.dev16/tests/unit/tools/test_hf_transfer.py +0 -0
  213. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/convert/build_sn_vqa_2026_vqa.py +0 -0
  214. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/convert/build_sngar_spotting.py +0 -0
  215. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/convert/build_soccernet_gar.py +0 -0
  216. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/convert/build_soccernet_gar_action_spotting.py +0 -0
  217. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/convert/build_soccernet_gar_vqa.py +0 -0
  218. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/convert/build_xvars_indexes.py +0 -0
  219. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/convert/extract_xvars_clip_features.py +0 -0
  220. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/convert/osl_json_to_parquet_webdataset.py +0 -0
  221. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/convert/parquet_webdataset_to_osl_json.py +0 -0
  222. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/convert/sngar_dataset_card.py +0 -0
  223. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/convert/sngar_events.py +0 -0
  224. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/convert/verify_sngar_spotting.py +0 -0
  225. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/download/download_hf_repo.py +0 -0
  226. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/download/download_osl_hf.py +0 -0
  227. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/download/push_sngar_spotting.py +0 -0
  228. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/download/upload_osl_hf.py +0 -0
  229. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/training/classification.py +0 -0
  230. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/training/localization.py +0 -0
  231. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/tools/training/vqa.py +0 -0
  232. {opensportslib-0.3.1.dev14 → opensportslib-0.3.1.dev16}/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.dev14
3
+ Version: 0.3.1.dev16
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
@@ -32,6 +32,8 @@ Requires-Dist: easydict
32
32
  Provides-Extra: test
33
33
  Requires-Dist: pytest; extra == "test"
34
34
  Requires-Dist: pytest-cov; extra == "test"
35
+ Requires-Dist: pytest-json-report; extra == "test"
36
+ Requires-Dist: pytest-timeout; extra == "test"
35
37
  Dynamic: license-file
36
38
 
37
39
  # OpenSportsLib
@@ -45,9 +47,9 @@ See the [complete inference server guide](docs/server/inference-server.md) for
45
47
  installation, registry administration, curl requests, single-video inference,
46
48
  full-test-set and per-sample remote inference, job polling, and sessions.
47
49
 
48
- For Docker administration, set `OSL_MODEL_ADMIN_TOKEN` in the private
49
- `server/.env` file, recreate the containers after changes, and use the exact
50
- same value as the Python client's `admin_token`. Never commit the real token.
50
+ Hugging Face registration is authorized by repository access. Set `HF_TOKEN`
51
+ on the worker or pass `hf_token` per request. The optional `OSL_API_KEY`
52
+ protects local-model and general administrative operations.
51
53
 
52
54
  ## Configuration From Hugging Face
53
55
 
@@ -138,7 +140,7 @@ OpenSportsLib is designed for **researchers, ML engineers, and sports analytics
138
140
 
139
141
  > Requires **Python 3.12+**.
140
142
  > Supports CUDA 12.6 / 12.8 / 13.0 (with CPU fallback).
141
- > PyTorch Geometric is supported up to PyTorch 2.10.*.
143
+ > PyTorch Geometric uses a dedicated PyTorch 2.12.1 compatibility profile.
142
144
 
143
145
  ### Create conda env
144
146
 
@@ -170,7 +172,8 @@ pip install -e .
170
172
  # Install PyTorch (CPU/GPU auto-detected)
171
173
  opensportslib setup
172
174
 
173
- # Optional: install PyTorch Geometric support
175
+ # Optional: install PyTorch Geometric support. This replaces the installed
176
+ # Torch stack with the PyG-compatible PyTorch 2.12.1 profile.
174
177
  opensportslib setup --pyg
175
178
 
176
179
  # Optional: install for DALI support
@@ -554,7 +557,8 @@ pip install -e .
554
557
  # Install PyTorch (CPU/GPU auto-detected)
555
558
  opensportslib setup
556
559
 
557
- # Optional: install PyTorch Geometric support
560
+ # Optional: install PyTorch Geometric support. This replaces the installed
561
+ # Torch stack with the PyG-compatible PyTorch 2.12.1 profile.
558
562
  opensportslib setup --pyg
559
563
 
560
564
  # Optional: install for DALI support
@@ -635,8 +639,8 @@ this repository, activate a fresh Python 3.12 or newer environment and install t
635
639
 
636
640
  ```bash
637
641
  pip install -e ./server
638
- bash server/scripts/setup_env.sh
639
- bash server/scripts/start_all.sh
642
+ server/scripts/serverctl setup
643
+ server/scripts/serverctl start
640
644
  ```
641
645
 
642
646
  The server installs the OpenSportsLib release from PyPI pinned to the root project
@@ -9,9 +9,9 @@ See the [complete inference server guide](docs/server/inference-server.md) for
9
9
  installation, registry administration, curl requests, single-video inference,
10
10
  full-test-set and per-sample remote inference, job polling, and sessions.
11
11
 
12
- For Docker administration, set `OSL_MODEL_ADMIN_TOKEN` in the private
13
- `server/.env` file, recreate the containers after changes, and use the exact
14
- same value as the Python client's `admin_token`. Never commit the real token.
12
+ Hugging Face registration is authorized by repository access. Set `HF_TOKEN`
13
+ on the worker or pass `hf_token` per request. The optional `OSL_API_KEY`
14
+ protects local-model and general administrative operations.
15
15
 
16
16
  ## Configuration From Hugging Face
17
17
 
@@ -102,7 +102,7 @@ OpenSportsLib is designed for **researchers, ML engineers, and sports analytics
102
102
 
103
103
  > Requires **Python 3.12+**.
104
104
  > Supports CUDA 12.6 / 12.8 / 13.0 (with CPU fallback).
105
- > PyTorch Geometric is supported up to PyTorch 2.10.*.
105
+ > PyTorch Geometric uses a dedicated PyTorch 2.12.1 compatibility profile.
106
106
 
107
107
  ### Create conda env
108
108
 
@@ -134,7 +134,8 @@ pip install -e .
134
134
  # Install PyTorch (CPU/GPU auto-detected)
135
135
  opensportslib setup
136
136
 
137
- # Optional: install PyTorch Geometric support
137
+ # Optional: install PyTorch Geometric support. This replaces the installed
138
+ # Torch stack with the PyG-compatible PyTorch 2.12.1 profile.
138
139
  opensportslib setup --pyg
139
140
 
140
141
  # Optional: install for DALI support
@@ -518,7 +519,8 @@ pip install -e .
518
519
  # Install PyTorch (CPU/GPU auto-detected)
519
520
  opensportslib setup
520
521
 
521
- # Optional: install PyTorch Geometric support
522
+ # Optional: install PyTorch Geometric support. This replaces the installed
523
+ # Torch stack with the PyG-compatible PyTorch 2.12.1 profile.
522
524
  opensportslib setup --pyg
523
525
 
524
526
  # Optional: install for DALI support
@@ -599,8 +601,8 @@ this repository, activate a fresh Python 3.12 or newer environment and install t
599
601
 
600
602
  ```bash
601
603
  pip install -e ./server
602
- bash server/scripts/setup_env.sh
603
- bash server/scripts/start_all.sh
604
+ server/scripts/serverctl setup
605
+ server/scripts/serverctl start
604
606
  ```
605
607
 
606
608
  The server installs the OpenSportsLib release from PyPI pinned to the root project
@@ -59,7 +59,6 @@ class SpoTTAConfig:
59
59
  drift_scale: float = 10.0
60
60
  drift_threshold: float = 1.0
61
61
  drift_gamma: float = 0.2
62
- augmentation: bool = True
63
62
 
64
63
  @classmethod
65
64
  def from_mapping(cls, value: Any) -> "SpoTTAConfig":
@@ -70,7 +69,6 @@ class SpoTTAConfig:
70
69
  memory = _mapping(root.get("memory"))
71
70
  optimizer = _mapping(root.get("optimizer"))
72
71
  teacher = _mapping(root.get("teacher"))
73
- augmentation = _mapping(root.get("augmentation"))
74
72
 
75
73
  _require_supported_value(
76
74
  root,
@@ -78,34 +76,6 @@ class SpoTTAConfig:
78
76
  "adapt_then_predict",
79
77
  "adaptation",
80
78
  )
81
- _require_supported_value(tether, "mode", "bayesian", "robust_bn.tether")
82
- _require_supported_value(
83
- gate,
84
- "uncertainty",
85
- "one_minus_max_probability",
86
- "confidence_gate",
87
- )
88
- _require_supported_value(
89
- gate,
90
- "aggregation",
91
- "min_over_predicted_action_frames",
92
- "confidence_gate",
93
- )
94
- _require_supported_value(optimizer, "type", "Adam", "optimizer")
95
- _require_supported_value(
96
- optimizer,
97
- "trainable_parameters",
98
- "batch_norm_affine_only",
99
- "optimizer",
100
- )
101
- _require_supported_value(teacher, "type", "ema", "teacher")
102
- _require_supported_value(
103
- teacher, "adaptive_from_bn_drift", True, "teacher"
104
- )
105
- _require_supported_value(
106
- augmentation, "mode", "framewise_rotta_strong", "augmentation"
107
- )
108
-
109
79
  config = cls(
110
80
  alpha=float(robust_bn.get("alpha", cls.alpha)),
111
81
  tether_cap=float(tether.get("cap", cls.tether_cap)),
@@ -133,7 +103,6 @@ class SpoTTAConfig:
133
103
  teacher.get("drift_threshold", cls.drift_threshold)
134
104
  ),
135
105
  drift_gamma=float(teacher.get("drift_gamma", cls.drift_gamma)),
136
- augmentation=bool(augmentation.get("enabled", cls.augmentation)),
137
106
  )
138
107
  config.validate()
139
108
  return config
@@ -577,13 +546,10 @@ class SpoTTA:
577
546
  with torch.no_grad():
578
547
  teacher_logits = _logits(self.teacher(clips))
579
548
 
580
- if self.config.augmentation:
581
- batch, time, channels, height, width = clips.shape
582
- augmented = self.augmentation(
583
- clips.reshape(batch * time, channels, height, width)
584
- ).reshape(batch, time, channels, height, width)
585
- else:
586
- augmented = clips
549
+ batch, time, channels, height, width = clips.shape
550
+ augmented = self.augmentation(
551
+ clips.reshape(batch * time, channels, height, width)
552
+ ).reshape(batch, time, channels, height, width)
587
553
 
588
554
  self.student.train()
589
555
  student_logits = _logits(self.student(augmented))
@@ -39,6 +39,7 @@ DATA:
39
39
  resize:
40
40
  height: 224
41
41
  width: 398
42
+ preserve_aspect_ratio: true
42
43
  params:
43
44
  crop_dim: 224
44
45
  dilate_len: 0
@@ -69,13 +70,10 @@ MODEL:
69
70
  robust_bn:
70
71
  alpha: 0.05
71
72
  tether:
72
- mode: bayesian
73
73
  cap: 0.5
74
74
  confidence_gate:
75
75
  action_class_index: 1
76
76
  min_action_frames: 1
77
- uncertainty: one_minus_max_probability
78
- aggregation: min_over_predicted_action_frames
79
77
  threshold: 0.3
80
78
  memory:
81
79
  capacity: 8
@@ -83,21 +81,14 @@ MODEL:
83
81
  lambda_t: 1.0
84
82
  lambda_u: 1.0
85
83
  optimizer:
86
- type: Adam
87
84
  learning_rate: 0.001
88
85
  beta: 0.9
89
- trainable_parameters: batch_norm_affine_only
90
86
  teacher:
91
- type: ema
92
87
  base_nu: 0.001
93
- adaptive_from_bn_drift: true
94
88
  max_nu: 0.02
95
89
  drift_scale: 10.0
96
90
  drift_threshold: 1.0
97
91
  drift_gamma: 0.2
98
- augmentation:
99
- enabled: true
100
- mode: framewise_rotta_strong
101
92
 
102
93
  TRAIN:
103
94
  execution:
@@ -206,9 +206,27 @@ def _preferred_loader_backend(payload: dict[str, Any]) -> str | None:
206
206
  if _declares_opencv_split_types(payload):
207
207
  return "opencv"
208
208
 
209
+ # DALI cannot run on CPU, regardless of an explicit preference in a
210
+ # configuration. This safety fallback also remaps DALI split types below.
209
211
  mode = str(system.get("device", "auto")).lower()
210
212
  if mode == "cpu":
211
213
  return "opencv"
214
+
215
+ data = payload.get("DATA", {})
216
+ common = data.get("common", {}) if isinstance(data, dict) else {}
217
+ runtime = common.get("runtime", {}) if isinstance(common, dict) else {}
218
+ configured_backend = (
219
+ str(runtime.get("loader_backend", "auto")).lower()
220
+ if isinstance(runtime, dict)
221
+ else "auto"
222
+ )
223
+ # An explicit backend is part of the configuration contract. Runtime
224
+ # detection is only a default for configs which leave that choice as auto.
225
+ if configured_backend == "opencv":
226
+ return "opencv"
227
+ if configured_backend == "dali":
228
+ return "dali" if _dali_available() else "opencv"
229
+
212
230
  if mode == "cuda":
213
231
  return "dali" if _dali_available() else "opencv"
214
232
  if mode == "auto":
@@ -145,9 +145,8 @@ def distribute_elements(batch_size, len_devices):
145
145
  """
146
146
  quotient, remainder = divmod(batch_size, len_devices)
147
147
  distribution = [quotient] * len_devices
148
- if remainder > 0:
149
- for i in range(len(distribution)):
150
- distribution[i] += 1
148
+ for i in range(remainder):
149
+ distribution[i] += 1
151
150
 
152
151
  return distribution
153
152
 
@@ -161,6 +161,7 @@ class LocalizationDataset(Dataset):
161
161
  imagenet_std=normalization.get("std"),
162
162
  target_height=resize.get("height"),
163
163
  target_width=resize.get("width"),
164
+ preserve_aspect_ratio=resize.get("preserve_aspect_ratio", False),
164
165
  )
165
166
  annotation_path = annotations_path or getattr(
166
167
  split_cfg, "annotation_path", getattr(split_cfg, "path", None)
@@ -346,6 +347,7 @@ class LocalizationDataset(Dataset):
346
347
  IMAGENET_STD=self.data_cfg.imagenet_std,
347
348
  TARGET_HEIGHT=self.data_cfg.target_height,
348
349
  TARGET_WIDTH=self.data_cfg.target_width,
350
+ preserve_aspect_ratio=self.data_cfg.preserve_aspect_ratio,
349
351
  )
350
352
  elif dataset_type == "VideoGameWithOpencvVideo":
351
353
  dataset = ActionSpotVideoDataset(
@@ -362,6 +364,7 @@ class LocalizationDataset(Dataset):
362
364
  IMAGENET_STD=self.data_cfg.imagenet_std,
363
365
  TARGET_HEIGHT=self.data_cfg.target_height,
364
366
  TARGET_WIDTH=self.data_cfg.target_width,
367
+ preserve_aspect_ratio=self.data_cfg.preserve_aspect_ratio,
365
368
  )
366
369
  elif dataset_type == "VideoGameWithDali":
367
370
  if not DALI_AVAILABLE:
@@ -543,6 +546,7 @@ class FrameReader:
543
546
  sample_fps=2,
544
547
  TARGET_HEIGHT=224,
545
548
  TARGET_WIDTH=398,
549
+ preserve_aspect_ratio=False,
546
550
  ):
547
551
  self._is_flow = modality == "flow"
548
552
  self._crop_transform = crop_transform
@@ -551,6 +555,37 @@ class FrameReader:
551
555
  self._sample_fps = sample_fps
552
556
  self.TARGET_HEIGHT = TARGET_HEIGHT
553
557
  self.TARGET_WIDTH = TARGET_WIDTH
558
+ self.preserve_aspect_ratio = preserve_aspect_ratio
559
+
560
+ def _resize_frame_ocv(self, frame):
561
+ """Resize an OpenCV frame using the configured spatial policy.
562
+
563
+ With aspect preservation enabled, ``TARGET_HEIGHT`` fixes the output
564
+ height and the width is derived from the source aspect ratio. If no
565
+ target height is configured, ``TARGET_WIDTH`` fixes the output width.
566
+ """
567
+ import cv2
568
+
569
+ height, width = frame.shape[:2]
570
+ if self.preserve_aspect_ratio:
571
+ if self.TARGET_HEIGHT is not None and self.TARGET_HEIGHT > 0:
572
+ scale = self.TARGET_HEIGHT / height
573
+ elif self.TARGET_WIDTH is not None and self.TARGET_WIDTH > 0:
574
+ scale = self.TARGET_WIDTH / width
575
+ else:
576
+ return frame
577
+
578
+ output_height = max(1, round(height * scale))
579
+ output_width = max(1, round(width * scale))
580
+ else:
581
+ output_height = self.TARGET_HEIGHT
582
+ output_width = self.TARGET_WIDTH
583
+
584
+ if output_height is None or output_width is None:
585
+ return frame
586
+ if (height, width) == (output_height, output_width):
587
+ return frame
588
+ return cv2.resize(frame, (output_width, output_height))
554
589
 
555
590
  def adapt_frame_ocv(self, frame):
556
591
  """Apply some modifications to the frame to have the expected shape and format.
@@ -675,8 +710,7 @@ class FrameReader:
675
710
  ret, frame = vc.read()
676
711
  if ret:
677
712
  if i % stride_extract == 0:
678
- if frame.shape[0] != oh or frame.shape[1] != ow:
679
- frame = cv2.resize(frame, (ow, oh))
713
+ frame = self._resize_frame_ocv(frame)
680
714
  img = self.adapt_frame_ocv(frame)
681
715
  if self._crop_transform:
682
716
  if self._same_transform:
@@ -781,6 +815,7 @@ class ActionSpotDataset(Dataset):
781
815
  IMAGENET_STD=[0.229, 0.224, 0.225],
782
816
  TARGET_HEIGHT=224,
783
817
  TARGET_WIDTH=398,
818
+ preserve_aspect_ratio=False,
784
819
  ):
785
820
  import random
786
821
  from opensportslib.core.utils.load_annotations import annotationstoe2eformat
@@ -850,7 +885,8 @@ class ActionSpotDataset(Dataset):
850
885
  same_transform,
851
886
  extract_fps,
852
887
  self.TARGET_HEIGHT,
853
- self.TARGET_WIDTH
888
+ self.TARGET_WIDTH,
889
+ preserve_aspect_ratio,
854
890
  )
855
891
 
856
892
  def load_frame_gpu(self, batch, device):
@@ -973,7 +1009,7 @@ class ActionSpotDataset(Dataset):
973
1009
  return self._dataset_len
974
1010
 
975
1011
  def print_info(self):
976
- from core.utils.config import _print_info_helper
1012
+ from opensportslib.core.utils.config import _print_info_helper
977
1013
  _print_info_helper(self._src_file, self._labels)
978
1014
 
979
1015
 
@@ -1097,6 +1133,7 @@ class ActionSpotVideoDataset(Dataset, DatasetVideoSharedMethods):
1097
1133
  IMAGENET_STD=[0.229, 0.224, 0.225],
1098
1134
  TARGET_HEIGHT=224,
1099
1135
  TARGET_WIDTH=398,
1136
+ preserve_aspect_ratio=False,
1100
1137
  ):
1101
1138
  from opensportslib.core.utils.load_annotations import annotationstoe2eformat, construct_labels
1102
1139
  from opensportslib.core.utils.video_processing import _get_img_transforms
@@ -1138,7 +1175,8 @@ class ActionSpotVideoDataset(Dataset, DatasetVideoSharedMethods):
1138
1175
  False,
1139
1176
  extract_fps,
1140
1177
  self.TARGET_HEIGHT,
1141
- self.TARGET_WIDTH
1178
+ self.TARGET_WIDTH,
1179
+ preserve_aspect_ratio,
1142
1180
  )
1143
1181
 
1144
1182
  self._flip = flip
@@ -1960,7 +1998,7 @@ if DALI_AVAILABLE:
1960
1998
  return labels
1961
1999
 
1962
2000
  def print_info(self):
1963
- from core.utils.config import _print_info_helper
2001
+ from opensportslib.core.utils.config import _print_info_helper
1964
2002
  _print_info_helper(self._src_file, self._labels)
1965
2003
 
1966
2004
 
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
  import time
5
+ import warnings
5
6
  from pathlib import Path
6
7
  from typing import Any
7
8
  from urllib import error, parse, request
@@ -17,13 +18,23 @@ class RemoteRegistryError(RuntimeError):
17
18
  class RemoteModelRegistry:
18
19
  """Administrative client for an OpenSportsLib server model registry."""
19
20
 
20
- def __init__(self, remote: str, admin_token: str, timeout: float = 30.0):
21
+ def __init__(
22
+ self,
23
+ remote: str,
24
+ api_key: str | None = None,
25
+ timeout: float = 30.0,
26
+ *,
27
+ admin_token: str | None = None,
28
+ ):
21
29
  if not remote:
22
30
  raise ValueError("remote is required.")
23
- if not admin_token:
24
- raise ValueError("admin_token is required.")
31
+ if admin_token is not None:
32
+ warnings.warn("admin_token is deprecated; use api_key.", DeprecationWarning, stacklevel=2)
33
+ if api_key is not None and api_key != admin_token:
34
+ raise ValueError("api_key and admin_token must match when both are provided.")
35
+ api_key = admin_token
25
36
  self.remote = remote.rstrip("/")
26
- self.admin_token = admin_token
37
+ self.api_key = api_key
27
38
  self.timeout = float(timeout)
28
39
  if self.timeout <= 0:
29
40
  raise ValueError("timeout must be positive.")
@@ -36,6 +47,7 @@ class RemoteModelRegistry:
36
47
  weights_path: str | Path | None = None,
37
48
  config_path: str | Path | None = None,
38
49
  model_id: str | None = None,
50
+ hf_token: str | None = None,
39
51
  ) -> dict[str, Any]:
40
52
  """Register exactly one Hugging Face or server-local model source."""
41
53
  if (huggingface_model_id is None) == (weights_path is None):
@@ -45,9 +57,12 @@ class RemoteModelRegistry:
45
57
  raise ValueError("config_path applies only to local models.")
46
58
  if model_id is not None and model_id != huggingface_model_id:
47
59
  raise ValueError("A Hugging Face model uses its repository ID as model_id.")
60
+ source = {"type": "huggingface", "model_id": huggingface_model_id}
61
+ if hf_token is not None:
62
+ source["hf_token"] = hf_token
48
63
  payload = {
49
64
  "task_type": task_type,
50
- "source": {"type": "huggingface", "model_id": huggingface_model_id},
65
+ "source": source,
51
66
  }
52
67
  else:
53
68
  payload = {
@@ -59,7 +74,7 @@ class RemoteModelRegistry:
59
74
  "config_path": str(config_path) if config_path is not None else None,
60
75
  },
61
76
  }
62
- return self._request("POST", "/models", payload, authenticated=True)
77
+ return self._request("POST", "/models", payload, authenticated=weights_path is not None)
63
78
 
64
79
  def list_models(self) -> list[dict[str, Any]]:
65
80
  return self._request("GET", "/models")["models"]
@@ -69,7 +84,7 @@ class RemoteModelRegistry:
69
84
  return self._request("GET", f"/models/status?{query}")
70
85
 
71
86
  def get_operation(self, operation_id: str) -> dict[str, Any]:
72
- return self._request("GET", f"/model-operations/{parse.quote(operation_id, safe='')}", authenticated=True)
87
+ return self._request("GET", f"/model-operations/{parse.quote(operation_id, safe='')}")
73
88
 
74
89
  def wait_for_operation(
75
90
  self,
@@ -93,9 +108,9 @@ class RemoteModelRegistry:
93
108
  task = parse.quote(task_type, safe="")
94
109
  return self._request("PUT", f"/models/defaults/{task}", {"model_id": model_id}, authenticated=True)
95
110
 
96
- def unregister_model(self, model_id: str) -> dict[str, Any]:
111
+ def unregister_model(self, model_id: str, hf_token: str | None = None) -> dict[str, Any]:
97
112
  encoded = parse.quote(model_id, safe="")
98
- return self._request("DELETE", f"/models/{encoded}", authenticated=True)
113
+ return self._request("DELETE", f"/models/{encoded}", authenticated=True, hf_token=hf_token)
99
114
 
100
115
  def reconcile_runtime(
101
116
  self,
@@ -117,11 +132,14 @@ class RemoteModelRegistry:
117
132
  endpoint: str,
118
133
  payload: dict[str, Any] | None = None,
119
134
  authenticated: bool = False,
135
+ hf_token: str | None = None,
120
136
  ) -> dict[str, Any]:
121
137
  body = json.dumps(payload).encode() if payload is not None else None
122
138
  headers = {"Content-Type": "application/json"}
123
- if authenticated:
124
- headers["Authorization"] = f"Bearer {self.admin_token}"
139
+ if authenticated and self.api_key:
140
+ headers["Authorization"] = f"Bearer {self.api_key}"
141
+ if hf_token:
142
+ headers["X-HF-Token"] = hf_token
125
143
  outgoing = request.Request(self.remote + endpoint, data=body, method=method, headers=headers)
126
144
  try:
127
145
  with request.urlopen(outgoing, timeout=self.timeout) as response:
@@ -1,6 +1,7 @@
1
1
  import platform
2
2
  import subprocess
3
3
  import sys
4
+ import tempfile
4
5
 
5
6
 
6
7
  CUDA_WHEEL_VERSIONS = {
@@ -14,6 +15,20 @@ LEGACY_GPU_CUDA_WHEEL = "cu126"
14
15
  LEGACY_GPU_CUDA_WHEEL_MAX_COMPUTE_CAPABILITY = (9, 0)
15
16
  CUDA13_REQUIRED_MIN_COMPUTE_CAPABILITY = (10, 0)
16
17
 
18
+ # PyG extension wheels are published for a narrower PyTorch matrix than the
19
+ # base PyTorch packages. Keep this profile explicit: selecting ``--pyg`` is
20
+ # allowed to replace an otherwise newer PyTorch installation.
21
+ PYG_TORCH_VERSION = "2.12.1"
22
+ PYG_TORCH_PACKAGES = (
23
+ f"torch=={PYG_TORCH_VERSION}",
24
+ "torchvision==0.27.1",
25
+ )
26
+ PYG_EXTENSION_PACKAGES = (
27
+ "pyg-lib",
28
+ "torch-scatter",
29
+ "torch-sparse",
30
+ )
31
+
17
32
  XVARS_DEPENDENCY_PINS = {
18
33
  "transformers": "4.38.2",
19
34
  "peft": "0.9.0",
@@ -154,10 +169,17 @@ def install_xvars_dependencies(DEPENDENCY_PINS):
154
169
  subprocess.check_call([python, "-m", "pip", "install", *pinned_packages])
155
170
  print("Dependencies installed successfully.")
156
171
 
157
- def install_torch():
172
+ def install_torch(*, pyg_compatible=False):
173
+ """Install the default Torch stack or the pinned PyG-compatible stack."""
158
174
  python = sys.executable
159
175
  subprocess.call([python, "-m", "pip", "uninstall", "-y", "torch", "torchvision", "torchaudio"])
160
- packages = select_torch_packages(GPU_COMPUTE_CAPABILITIES)
176
+ packages = PYG_TORCH_PACKAGES if pyg_compatible else select_torch_packages(GPU_COMPUTE_CAPABILITIES)
177
+
178
+ if pyg_compatible:
179
+ print(
180
+ "\nInstalling the PyTorch Geometric compatibility profile: "
181
+ f"PyTorch {PYG_TORCH_VERSION}. This replaces the installed Torch stack.\n"
182
+ )
161
183
 
162
184
  subprocess.check_call([
163
185
  python, "-m", "pip", "install",
@@ -168,6 +190,30 @@ def install_torch():
168
190
  print(f"\nSuccess with {CUDA_TAG}: {', '.join(packages)}")
169
191
  return CUDA_TAG
170
192
 
193
+
194
+ def pyg_wheel_url(torch_version=None, cuda_tag=None):
195
+ torch_version = torch_version or PYG_TORCH_VERSION
196
+ cuda_tag = CUDA_TAG if cuda_tag is None else cuda_tag
197
+ suffix = "cpu" if cuda_tag == "cpu" else cuda_tag
198
+ return f"https://data.pyg.org/whl/torch-{torch_version}+{suffix}.html"
199
+
200
+
201
+ def validate_pyg_wheels():
202
+ """Ensure every required PyG wheel exists before replacing Torch.
203
+
204
+ ``--only-binary`` is intentional: pip otherwise falls back to a source
205
+ build, which is both slow and incompatible with its isolated build
206
+ environment unless Torch is installed there as well.
207
+ """
208
+ python = sys.executable
209
+ url = pyg_wheel_url()
210
+ print("\nChecking PyTorch Geometric wheels before replacing the Torch stack...\n")
211
+ with tempfile.TemporaryDirectory(prefix="opensportslib-pyg-wheel-check-") as download_dir:
212
+ subprocess.check_call([
213
+ python, "-m", "pip", "download", "--no-deps", "--only-binary=:all:",
214
+ "--dest", download_dir, *PYG_EXTENSION_PACKAGES, "-f", url,
215
+ ])
216
+
171
217
  def install_dali():
172
218
 
173
219
  python = sys.executable
@@ -202,36 +248,24 @@ def install_dali():
202
248
 
203
249
  def install_pyg():
204
250
  import torch
205
- from packaging import version
206
251
 
207
252
  python = sys.executable
208
- torch_version = "2.10.0" if version.parse(torch.__version__.split("+")[0]) > version.parse("2.10.0") else torch.__version__.split("+")[0]
209
- cuda_tag = CUDA_TAG
253
+ torch_version = torch.__version__.split("+")[0]
254
+ if torch_version != PYG_TORCH_VERSION:
255
+ raise RuntimeError(
256
+ "PyTorch Geometric extensions require the OpenSportsLib PyG compatibility "
257
+ f"profile (PyTorch {PYG_TORCH_VERSION}); found PyTorch {torch_version}. "
258
+ "Run 'opensportslib setup --pyg' so the matching Torch stack is installed."
259
+ )
210
260
  print("\nInstalling Py-Geometric ecosystem...\n")
211
- if cuda_tag == "cpu":
212
- url = f"https://data.pyg.org/whl/torch-{torch_version}+cpu.html"
213
- else:
214
- url = f"https://data.pyg.org/whl/torch-{torch_version}+{cuda_tag}.html"
261
+ url = pyg_wheel_url(torch_version)
215
262
 
216
263
  subprocess.check_call([
217
- python, "-m", "pip", "install",
218
- "torch-geometric", "-f", url
219
- ])
220
- subprocess.check_call([
221
- python, "-m", "pip", "install",
222
- "torch-scatter", "-f", url
264
+ python, "-m", "pip", "install", "torch-geometric",
223
265
  ])
224
266
  subprocess.check_call([
225
267
  python, "-m", "pip", "install",
226
- "torch-sparse", "-f", url
227
- ])
228
- subprocess.check_call([
229
- python, "-m", "pip", "install",
230
- "torch-cluster", "-f", url
231
- ])
232
- subprocess.check_call([
233
- python, "-m", "pip", "install",
234
- "torch-spline-conv", "-f", url
268
+ *PYG_EXTENSION_PACKAGES, "--only-binary=:all:", "-f", url
235
269
  ])
236
270
 
237
271
  def install_extras(dali=False, pyg=False):
@@ -256,7 +290,9 @@ def verify():
256
290
  print("Running on CPU")
257
291
 
258
292
  def setup(dali=False, pyg=False, vqa_xvars=False, vqa_qwen=False):
259
- install_torch()
293
+ if pyg:
294
+ validate_pyg_wheels()
295
+ install_torch(pyg_compatible=pyg)
260
296
  install_extras(dali=dali, pyg=pyg)
261
297
  if vqa_xvars:
262
298
  install_xvars_dependencies(XVARS_DEPENDENCY_PINS)