opensportslib 0.3.1.dev19__tar.gz → 0.3.1.dev21__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.
- {opensportslib-0.3.1.dev19/opensportslib.egg-info → opensportslib-0.3.1.dev21}/PKG-INFO +8 -3
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/README.md +7 -2
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21/opensportslib.egg-info}/PKG-INFO +8 -3
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib.egg-info/SOURCES.txt +3 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/pyproject.toml +1 -1
- opensportslib-0.3.1.dev21/scripts/verify_release_manifests.py +32 -0
- opensportslib-0.3.1.dev21/scripts/write_release_manifest.py +50 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/conftest.py +1 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/release/_release_common.py +79 -4
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/release/test_00_environment.py +16 -6
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/release/test_classification_release.py +39 -11
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/release/test_localization_release.py +33 -10
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/release/test_vqa_release.py +52 -5
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/contracts/test_runner_contract.py +8 -0
- opensportslib-0.3.1.dev21/tests/unit/tools/test_release_manifest.py +25 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/LICENSE +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/LICENSE-COMMERCIAL +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/MANIFEST.in +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/examples/quickstart/basic_classification.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/examples/quickstart/basic_localization.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/examples/quickstart/basic_vqa.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/adaptation/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/adaptation/spotta.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/apis/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/apis/base_task_model.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/apis/classification.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/apis/config.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/apis/configuration.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/apis/localization.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/apis/vqa.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/cli.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/classification/default.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/classification/sngar_frames.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/classification/sngar_tracking.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/classification/video.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/default.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/localization/calf_resnetpca512.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/localization/default.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/localization/e2e_spotta.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/localization/h5_header_distance.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/localization/h5_header_skeleton.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/localization/netvladpp_resnetpca512.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/localization/tracking_action_spotting.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/localization/video_dali.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/localization/video_ocv.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/vqa/default.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/vqa/qwen.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/vqa/qwen3_vl_native.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/vqa/qwen_lora.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/vqa/qwen_sngar_frames.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/configs/vqa/xvars.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/config/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/config/accessors.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/config/conflicts.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/config/editable.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/config/loader.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/config/migrate.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/config/migrations/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/config/migrations/legacy_to_canonical.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/config/rule_variants.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/config/runtime_adapter.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/config/schema.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/config/schemas/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/config/schemas/schema_canonical.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/config/schemas/schema_legacy.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/config/validate.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/loss/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/loss/builder.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/loss/calf.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/loss/ce.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/loss/combine.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/loss/nll.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/optimizer/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/optimizer/builder.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/sampler/weighted_sampler.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/scheduler/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/scheduler/builder.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/trainer/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/trainer/classification_trainer.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/trainer/localization_trainer.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/trainer/vqa_trainer.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/utils/checkpoint.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/utils/config.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/utils/config_normalize.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/utils/data.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/utils/ddp.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/utils/default_args.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/utils/direct_video.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/utils/hf_runtime.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/utils/lightning.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/utils/load_annotations.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/utils/seed.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/utils/video_processing.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/core/utils/wandb.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/datasets/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/datasets/builder.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/datasets/classification_dataset.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/datasets/hf_json.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/datasets/hf_tracking.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/datasets/localization_dataset.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/datasets/utils/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/datasets/utils/h5_tracking.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/datasets/utils/tracking.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/datasets/vqa_dataset.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/legacy_config/classification.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/legacy_config/localization-e2e-ocv.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/legacy_config/localization-json_calf_resnetpca512.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/legacy_config/localization-json_netvlad++_resnetpca512.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/legacy_config/localization.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/legacy_config/sngar-frames.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/legacy_config/sngar-tracking.yaml +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/metrics/classification_metric.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/metrics/localization_metric.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/metrics/vqa_metric.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/backbones/builder.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/base/contextaware.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/base/e2e.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/base/learnablepooling.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/base/qwen_vl_native.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/base/qwen_xvars.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/base/rule_based.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/base/tracking.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/base/vars.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/base/video.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/base/video_chatgpt_compat.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/base/video_mae.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/base/xvars_videochatgpt.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/builder.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/heads/builder.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/neck/builder.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/utils/common.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/utils/impl/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/utils/impl/asformer.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/utils/impl/calf.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/utils/impl/gsm.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/utils/impl/gtad.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/utils/impl/tsm.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/utils/litebase.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/utils/modules.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/utils/shift.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/utils/utils.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/utils/vqa_prediction_priors.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/utils/vqa_prompting.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/models/utils/xvars_clip_index.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/remote_registry.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/setup/setup.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/tools/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/tools/_common.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/tools/hf_transfer.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/tools/osl_json_to_parquet.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib/tools/parquet_to_osl_json.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib.egg-info/dependency_links.txt +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib.egg-info/entry_points.txt +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib.egg-info/requires.txt +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/opensportslib.egg-info/top_level.txt +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/scripts/redact_test_stream.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/scripts/release_versions.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/scripts/run_h5_header_rule_inference.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/scripts/summarize_test_report.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/setup.cfg +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/helpers/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/helpers/configs.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/helpers/pipeline_stubs.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/integration/classification/test_pipeline.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/integration/localization/test_pipeline.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/integration/localization/test_spotta.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/integration/vqa/test_pipeline.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/release/__init__.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/smoke/test_cli.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/smoke/test_config_utils.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/smoke/test_environment.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/smoke/test_package.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/smoke/test_public_apis.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/api/test_remote_registry.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/api/test_remote_sessions.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/api/test_server_jobs.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/api/test_server_registry.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/api/test_server_startup_scripts.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/api/test_task_model_contract.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/api/test_vqa.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/config/test_architecture.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/config/test_editable.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/config/test_optional_hf.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/config/test_pretrained_merge.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/config/test_split_overrides.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/contracts/test_architecture.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/contracts/test_dependencies.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/contracts/test_package.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/contracts/test_release_versions.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/core/test_classification_trainer.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/core/test_localization_hf_backend.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/core/test_training_components.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/core/test_video_processing.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/data/test_classification_paths.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/data/test_h5_tracking.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/data/test_hf_json_spotting.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/data/test_hf_json_tracking_spotting.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/data/test_hf_tracking_dataset.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/data/test_localization_dali.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/data/test_localization_intervals.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/data/test_osl_formats.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/models/test_classification_metrics.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/models/test_header_rule_spotter.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/models/test_header_skeleton_spotter.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/models/test_localization_metrics.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/models/test_temporal_shift.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/models/test_vqa_metrics.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/models/test_vqa_qwen_xvars.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/models/test_vqa_training_lora.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/models/test_vqa_xvars_videochatgpt.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/tools/test_conversion.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/tools/test_extract_xvars_features.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/tools/test_hf_transfer.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/tools/test_report_summary.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/unit/tools/test_setup.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/convert/build_sn_vqa_2026_vqa.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/convert/build_sngar_spotting.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/convert/build_soccernet_gar.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/convert/build_soccernet_gar_action_spotting.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/convert/build_soccernet_gar_vqa.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/convert/build_xvars_indexes.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/convert/extract_xvars_clip_features.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/convert/osl_json_to_parquet_webdataset.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/convert/parquet_webdataset_to_osl_json.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/convert/sngar_dataset_card.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/convert/sngar_events.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/convert/verify_sngar_spotting.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/download/download_hf_repo.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/download/download_osl_hf.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/download/push_sngar_spotting.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/download/upload_osl_hf.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/train/train_config.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/training/classification.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/training/localization.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tools/training/vqa.py +0 -0
- {opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/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.
|
|
3
|
+
Version: 0.3.1.dev21
|
|
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
|
|
@@ -114,8 +114,9 @@ It provides a unified framework to **train, evaluate, and run inference** for ke
|
|
|
114
114
|
- **Action classification**
|
|
115
115
|
- **Action localization / spotting**
|
|
116
116
|
- **Visual Question Answering (VQA)**
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
|
|
118
|
+
Retrieval and action description/captioning are roadmap areas. They do not yet
|
|
119
|
+
have first-class task wrappers or training workflows in this package.
|
|
119
120
|
|
|
120
121
|
OpenSportsLib is designed for **researchers, ML engineers, and sports analytics teams** who want reproducible and extensible workflows for sports video AI.
|
|
121
122
|
|
|
@@ -622,6 +623,10 @@ opensportslib setup --vqa_qwen
|
|
|
622
623
|
|
|
623
624
|
We welcome contributions to OpenSportsLib.
|
|
624
625
|
|
|
626
|
+
All PRs must target `dev`. Before a PR can merge, every GitHub-linked commit
|
|
627
|
+
author must accept the [Individual Contributor License Agreement](.github/CLA.md)
|
|
628
|
+
when prompted by the `CLA check`.
|
|
629
|
+
|
|
625
630
|
Please check:
|
|
626
631
|
|
|
627
632
|
- [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
@@ -75,8 +75,9 @@ It provides a unified framework to **train, evaluate, and run inference** for ke
|
|
|
75
75
|
- **Action classification**
|
|
76
76
|
- **Action localization / spotting**
|
|
77
77
|
- **Visual Question Answering (VQA)**
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
|
|
79
|
+
Retrieval and action description/captioning are roadmap areas. They do not yet
|
|
80
|
+
have first-class task wrappers or training workflows in this package.
|
|
80
81
|
|
|
81
82
|
OpenSportsLib is designed for **researchers, ML engineers, and sports analytics teams** who want reproducible and extensible workflows for sports video AI.
|
|
82
83
|
|
|
@@ -583,6 +584,10 @@ opensportslib setup --vqa_qwen
|
|
|
583
584
|
|
|
584
585
|
We welcome contributions to OpenSportsLib.
|
|
585
586
|
|
|
587
|
+
All PRs must target `dev`. Before a PR can merge, every GitHub-linked commit
|
|
588
|
+
author must accept the [Individual Contributor License Agreement](.github/CLA.md)
|
|
589
|
+
when prompted by the `CLA check`.
|
|
590
|
+
|
|
586
591
|
Please check:
|
|
587
592
|
|
|
588
593
|
- [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opensportslib
|
|
3
|
-
Version: 0.3.1.
|
|
3
|
+
Version: 0.3.1.dev21
|
|
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
|
|
@@ -114,8 +114,9 @@ It provides a unified framework to **train, evaluate, and run inference** for ke
|
|
|
114
114
|
- **Action classification**
|
|
115
115
|
- **Action localization / spotting**
|
|
116
116
|
- **Visual Question Answering (VQA)**
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
|
|
118
|
+
Retrieval and action description/captioning are roadmap areas. They do not yet
|
|
119
|
+
have first-class task wrappers or training workflows in this package.
|
|
119
120
|
|
|
120
121
|
OpenSportsLib is designed for **researchers, ML engineers, and sports analytics teams** who want reproducible and extensible workflows for sports video AI.
|
|
121
122
|
|
|
@@ -622,6 +623,10 @@ opensportslib setup --vqa_qwen
|
|
|
622
623
|
|
|
623
624
|
We welcome contributions to OpenSportsLib.
|
|
624
625
|
|
|
626
|
+
All PRs must target `dev`. Before a PR can merge, every GitHub-linked commit
|
|
627
|
+
author must accept the [Individual Contributor License Agreement](.github/CLA.md)
|
|
628
|
+
when prompted by the `CLA check`.
|
|
629
|
+
|
|
625
630
|
Please check:
|
|
626
631
|
|
|
627
632
|
- [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
@@ -149,6 +149,8 @@ scripts/redact_test_stream.py
|
|
|
149
149
|
scripts/release_versions.py
|
|
150
150
|
scripts/run_h5_header_rule_inference.py
|
|
151
151
|
scripts/summarize_test_report.py
|
|
152
|
+
scripts/verify_release_manifests.py
|
|
153
|
+
scripts/write_release_manifest.py
|
|
152
154
|
tests/__init__.py
|
|
153
155
|
tests/conftest.py
|
|
154
156
|
tests/helpers/__init__.py
|
|
@@ -210,6 +212,7 @@ tests/unit/models/test_vqa_xvars_videochatgpt.py
|
|
|
210
212
|
tests/unit/tools/test_conversion.py
|
|
211
213
|
tests/unit/tools/test_extract_xvars_features.py
|
|
212
214
|
tests/unit/tools/test_hf_transfer.py
|
|
215
|
+
tests/unit/tools/test_release_manifest.py
|
|
213
216
|
tests/unit/tools/test_report_summary.py
|
|
214
217
|
tests/unit/tools/test_setup.py
|
|
215
218
|
tools/convert/build_sn_vqa_2026_vqa.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "opensportslib"
|
|
7
|
-
version = "0.3.1.
|
|
7
|
+
version = "0.3.1.dev21"
|
|
8
8
|
description = "OpenSportsLib is the professional library, designed for advanced video understanding in sports. It provides state-of-the-art tools for action recognition, spotting, retrieval, and captioning, making it ideal for researchers, analysts, and developers working with sports video data."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Verify the Qwen, X-VARS, and GAR release manifests describe one passing commit."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
REQUIRED_PROFILES = {"qwen", "xvars", "gar"}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def main() -> int:
|
|
14
|
+
parser = argparse.ArgumentParser()
|
|
15
|
+
parser.add_argument("manifests", nargs="+", help="release-manifest.json paths copied from release servers")
|
|
16
|
+
args = parser.parse_args()
|
|
17
|
+
records = [json.loads(Path(path).read_text(encoding="utf-8")) for path in args.manifests]
|
|
18
|
+
profiles = {record.get("profile") for record in records}
|
|
19
|
+
commits = {record.get("commit") for record in records}
|
|
20
|
+
failed = [record.get("profile") for record in records if record.get("result") != "passed"]
|
|
21
|
+
if profiles != REQUIRED_PROFILES:
|
|
22
|
+
raise SystemExit(f"Expected manifests for {sorted(REQUIRED_PROFILES)}, got {sorted(profiles)}.")
|
|
23
|
+
if len(commits) != 1 or "unknown" in commits:
|
|
24
|
+
raise SystemExit(f"Release manifests must identify one known commit, got {sorted(commits)}.")
|
|
25
|
+
if failed:
|
|
26
|
+
raise SystemExit(f"Release profiles failed: {failed}.")
|
|
27
|
+
print(f"Release manifests verified for commit {next(iter(commits))}: {', '.join(sorted(profiles))}")
|
|
28
|
+
return 0
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if __name__ == "__main__":
|
|
32
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Write one non-secret, commit-bound release profile manifest."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
import subprocess
|
|
8
|
+
from datetime import datetime, timezone
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main() -> int:
|
|
13
|
+
parser = argparse.ArgumentParser()
|
|
14
|
+
parser.add_argument("--report-dir", required=True)
|
|
15
|
+
parser.add_argument("--profile", required=True, choices=("qwen", "xvars", "gar"))
|
|
16
|
+
parser.add_argument("--scale", required=True, choices=("full", "bounded"))
|
|
17
|
+
parser.add_argument("--exit-code", required=True, type=int)
|
|
18
|
+
args = parser.parse_args()
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
commit = subprocess.check_output(
|
|
22
|
+
["git", "rev-parse", "HEAD"], text=True, stderr=subprocess.DEVNULL
|
|
23
|
+
).strip()
|
|
24
|
+
except subprocess.CalledProcessError:
|
|
25
|
+
commit = "unknown"
|
|
26
|
+
report_dir = Path(args.report_dir)
|
|
27
|
+
metadata = report_dir / "release-metadata.jsonl"
|
|
28
|
+
records = []
|
|
29
|
+
if metadata.exists():
|
|
30
|
+
for line in metadata.read_text(encoding="utf-8").splitlines():
|
|
31
|
+
if line.strip():
|
|
32
|
+
records.append(json.loads(line))
|
|
33
|
+
manifest = {
|
|
34
|
+
"created_at": datetime.now(timezone.utc).isoformat(),
|
|
35
|
+
"commit": commit,
|
|
36
|
+
"profile": args.profile,
|
|
37
|
+
"scale": args.scale,
|
|
38
|
+
"result": "passed" if args.exit_code == 0 else "failed",
|
|
39
|
+
"exit_code": args.exit_code,
|
|
40
|
+
"metadata_records": records,
|
|
41
|
+
}
|
|
42
|
+
(report_dir / "release-manifest.json").write_text(
|
|
43
|
+
json.dumps(manifest, indent=2, sort_keys=True, default=str) + "\n",
|
|
44
|
+
encoding="utf-8",
|
|
45
|
+
)
|
|
46
|
+
return 0
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if __name__ == "__main__":
|
|
50
|
+
raise SystemExit(main())
|
|
@@ -15,6 +15,8 @@ from __future__ import annotations
|
|
|
15
15
|
import importlib.util
|
|
16
16
|
import json
|
|
17
17
|
import os
|
|
18
|
+
import subprocess
|
|
19
|
+
import sys
|
|
18
20
|
from copy import deepcopy
|
|
19
21
|
from pathlib import Path
|
|
20
22
|
from typing import Any
|
|
@@ -24,6 +26,9 @@ import pytest
|
|
|
24
26
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
25
27
|
|
|
26
28
|
RELEASE_ENV_FLAG = "RUN_OSL_RELEASE_TESTS"
|
|
29
|
+
RELEASE_SCALE_ENV = "OSL_RELEASE_SCALE"
|
|
30
|
+
RELEASE_PROFILE_ENV = "OSL_RELEASE_PROFILE"
|
|
31
|
+
RELEASE_PROFILES = {"qwen", "xvars", "gar"}
|
|
27
32
|
|
|
28
33
|
# Where materialized configs / run outputs (checkpoints, logs, predictions)
|
|
29
34
|
# are cached. Override with OSL_RELEASE_CACHE_DIR to point at a disk with
|
|
@@ -111,15 +116,42 @@ def _env_int(name: str, default: int) -> int:
|
|
|
111
116
|
return int(raw)
|
|
112
117
|
|
|
113
118
|
|
|
114
|
-
def
|
|
115
|
-
"""
|
|
116
|
-
value =
|
|
117
|
-
|
|
119
|
+
def release_scale() -> str:
|
|
120
|
+
"""Return ``full`` (the release default) or explicit bounded debug mode."""
|
|
121
|
+
value = os.environ.get(RELEASE_SCALE_ENV, "full").strip().lower()
|
|
122
|
+
if value not in {"full", "bounded"}:
|
|
123
|
+
raise ValueError(f"{RELEASE_SCALE_ENV} must be 'full' or 'bounded', got {value!r}.")
|
|
124
|
+
return value
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def release_profile() -> str:
|
|
128
|
+
value = os.environ.get(RELEASE_PROFILE_ENV, "qwen").strip().lower()
|
|
129
|
+
if value not in RELEASE_PROFILES:
|
|
130
|
+
raise ValueError(f"{RELEASE_PROFILE_ENV} must be one of {sorted(RELEASE_PROFILES)}, got {value!r}.")
|
|
131
|
+
return value
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def training_overrides(bounded_default: int) -> dict[str, int]:
|
|
135
|
+
"""Return an epoch override only when the caller explicitly requests one.
|
|
136
|
+
|
|
137
|
+
Full release runs preserve the canonical preset schedule. ``0`` has the
|
|
138
|
+
same preserve-default meaning; bounded mode retains the previous small
|
|
139
|
+
release schedule unless an explicit positive override is supplied.
|
|
140
|
+
"""
|
|
141
|
+
raw = os.environ.get("OSL_RELEASE_EPOCHS")
|
|
142
|
+
if raw is not None and raw != "":
|
|
143
|
+
value = int(raw)
|
|
144
|
+
if value < 0:
|
|
145
|
+
raise ValueError("OSL_RELEASE_EPOCHS must be zero or a positive integer.")
|
|
146
|
+
return {} if value == 0 else {"epochs": value}
|
|
147
|
+
return {"epochs": bounded_default} if release_scale() == "bounded" else {}
|
|
118
148
|
|
|
119
149
|
|
|
120
150
|
def max_items_for(env_name: str, default: int | None) -> int | None:
|
|
121
151
|
"""Generic dataset-subset-size override. 0 (or 'all') means 'download everything'."""
|
|
122
152
|
raw = os.environ.get(env_name)
|
|
153
|
+
if (raw is None or raw == "") and release_scale() == "full":
|
|
154
|
+
return None
|
|
123
155
|
if raw is None or raw == "":
|
|
124
156
|
return default
|
|
125
157
|
if raw.strip().lower() == "all":
|
|
@@ -289,6 +321,7 @@ def snapshot_dataset(
|
|
|
289
321
|
local_dir: Path,
|
|
290
322
|
*,
|
|
291
323
|
allow_patterns: list[str] | None = None,
|
|
324
|
+
revision: str = "main",
|
|
292
325
|
) -> Path:
|
|
293
326
|
"""Download (or update) a full dataset repo, or a pattern-restricted
|
|
294
327
|
subset of it, into local_dir. Safe to call repeatedly (resumable)."""
|
|
@@ -301,10 +334,52 @@ def snapshot_dataset(
|
|
|
301
334
|
local_dir=str(local_dir),
|
|
302
335
|
token=hf_token(),
|
|
303
336
|
allow_patterns=allow_patterns,
|
|
337
|
+
revision=revision,
|
|
304
338
|
)
|
|
305
339
|
return local_dir
|
|
306
340
|
|
|
307
341
|
|
|
342
|
+
def require_model_repo(repo_id: str) -> None:
|
|
343
|
+
"""Fail with release remediation when a published model cannot be read."""
|
|
344
|
+
require_repo_access(repo_id, repo_type="model")
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def download_model_snapshot(repo_id: str, local_dir: Path, *, revision: str = "main") -> Path:
|
|
348
|
+
"""Download/cache a model repository and write non-secret provenance."""
|
|
349
|
+
from huggingface_hub import snapshot_download
|
|
350
|
+
|
|
351
|
+
local_dir.mkdir(parents=True, exist_ok=True)
|
|
352
|
+
path = Path(snapshot_download(
|
|
353
|
+
repo_id=repo_id, repo_type="model", revision=revision,
|
|
354
|
+
local_dir=str(local_dir), token=hf_token(),
|
|
355
|
+
))
|
|
356
|
+
record_release_metadata("model", repo_id=repo_id, revision=revision, local_path=str(path))
|
|
357
|
+
return path
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def run_xvars_preprocessing(dataset_root: Path, output_root: Path, *, weights_path: Path) -> None:
|
|
361
|
+
"""Run the project-owned X-VARS feature and index builders once per cache."""
|
|
362
|
+
marker = output_root / ".osl_xvars_prepared.json"
|
|
363
|
+
if marker.exists():
|
|
364
|
+
record_release_metadata("xvars_preprocess", status="cached", marker=str(marker))
|
|
365
|
+
return
|
|
366
|
+
output_root.mkdir(parents=True, exist_ok=True)
|
|
367
|
+
extractor = REPO_ROOT / "tools" / "convert" / "extract_xvars_clip_features.py"
|
|
368
|
+
indexer = REPO_ROOT / "tools" / "convert" / "build_xvars_indexes.py"
|
|
369
|
+
command = [
|
|
370
|
+
sys.executable, str(extractor), "--dataset-root", str(dataset_root),
|
|
371
|
+
"--dataset-output-root", str(output_root), "--mode", "strict_xvars",
|
|
372
|
+
"--weights-path", str(weights_path),
|
|
373
|
+
]
|
|
374
|
+
subprocess.check_call(command)
|
|
375
|
+
subprocess.check_call([
|
|
376
|
+
sys.executable, str(indexer), "--dataset-root", str(dataset_root),
|
|
377
|
+
"--features-root", str(output_root),
|
|
378
|
+
])
|
|
379
|
+
marker.write_text(json.dumps({"weights_path": str(weights_path)}), encoding="utf-8")
|
|
380
|
+
record_release_metadata("xvars_preprocess", status="complete", output_root=str(output_root))
|
|
381
|
+
|
|
382
|
+
|
|
308
383
|
def download_files(repo_id: str, filenames: list[str], local_dir: Path) -> list[Path]:
|
|
309
384
|
from huggingface_hub import hf_hub_download
|
|
310
385
|
|
{opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/release/test_00_environment.py
RENAMED
|
@@ -6,7 +6,7 @@ import importlib.util
|
|
|
6
6
|
|
|
7
7
|
import pytest
|
|
8
8
|
|
|
9
|
-
from tests.release._release_common import require_release_enabled
|
|
9
|
+
from tests.release._release_common import release_profile, require_release_enabled
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
pytestmark = [pytest.mark.release, pytest.mark.gpu]
|
|
@@ -19,10 +19,20 @@ def test_release_environment_has_cuda_and_required_training_packages():
|
|
|
19
19
|
assert torch.cuda.is_available(), "Release verification requires an accessible CUDA GPU."
|
|
20
20
|
assert torch.cuda.device_count() >= 1, "CUDA reported available but exposed no devices."
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
profile = release_profile()
|
|
23
|
+
required = {}
|
|
24
|
+
if profile == "qwen":
|
|
25
|
+
required.update({
|
|
26
|
+
"peft": "run `opensportslib setup --vqa_qwen`",
|
|
27
|
+
"nvidia.dali": "run `opensportslib setup --dali`",
|
|
28
|
+
"trl": "run `opensportslib setup --vqa_qwen`",
|
|
29
|
+
})
|
|
30
|
+
elif profile == "xvars":
|
|
31
|
+
required.update({
|
|
32
|
+
"peft": "run `opensportslib setup --vqa_xvars`",
|
|
33
|
+
"trl": "run `opensportslib setup --vqa_xvars`",
|
|
34
|
+
})
|
|
35
|
+
elif profile == "gar":
|
|
36
|
+
required["torch_geometric"] = "run `opensportslib setup --pyg` on a supported platform"
|
|
27
37
|
missing = [f"{name} ({hint})" for name, hint in required.items() if importlib.util.find_spec(name) is None]
|
|
28
38
|
assert not missing, "Release environment is missing required packages: " + ", ".join(missing)
|
{opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/release/test_classification_release.py
RENAMED
|
@@ -66,7 +66,7 @@ from ._release_common import (
|
|
|
66
66
|
DATA_DIR,
|
|
67
67
|
classes_from_osl_json,
|
|
68
68
|
download_shard_split,
|
|
69
|
-
|
|
69
|
+
training_overrides,
|
|
70
70
|
materialize_config,
|
|
71
71
|
max_items_for,
|
|
72
72
|
prefer_osl_ready_dataset,
|
|
@@ -93,6 +93,8 @@ CLS_PRIMARY_REPO = os.environ.get("OSL_RELEASE_CLS_REPO", "OpenSportsLab/OSL-XFo
|
|
|
93
93
|
CLS_PRIMARY_REVISION = os.environ.get("OSL_RELEASE_CLS_REVISION", "224p")
|
|
94
94
|
CLS_FALLBACK_REPO = os.environ.get("OSL_RELEASE_CLS_FALLBACK_REPO", "OpenSportsLab/OSL-cls-UEFA-fouls")
|
|
95
95
|
TRACKING_CLS_REPO = os.environ.get("OSL_RELEASE_TRACKING_CLS_REPO", "OpenSportsLab/SoccerNet-GAR")
|
|
96
|
+
TRACKING_CLS_REVISION = os.environ.get("OSL_RELEASE_TRACKING_CLS_REVISION", "tracking")
|
|
97
|
+
PUBLISHED_CLASSIFICATION_MODEL = "OpenSportsLab/OSL-cls-action-mvitv2"
|
|
96
98
|
|
|
97
99
|
os.environ.setdefault("WANDB_MODE", "disabled")
|
|
98
100
|
os.environ.setdefault("OSL_PRETRAINED_WEIGHTS", "0")
|
|
@@ -321,8 +323,9 @@ def _run_classification_pipeline(config_path: str, dataset: dict, run_name: str)
|
|
|
321
323
|
config_path=config_path, checkpoint_path=str(checkpoint),
|
|
322
324
|
)
|
|
323
325
|
|
|
324
|
-
report_step(f"[{run_name}] infer()")
|
|
325
|
-
|
|
326
|
+
report_step(f"[{run_name}] fresh checkpoint load + infer()")
|
|
327
|
+
restored_model = ClassificationModel(config=config_path, weights=checkpoint)
|
|
328
|
+
predictions = restored_model.infer(test_set=str(split_paths["test"]), use_wandb=False)
|
|
326
329
|
assert isinstance(predictions, dict) and predictions.get("data"), f"[{run_name}] empty predictions"
|
|
327
330
|
|
|
328
331
|
report_step(f"[{run_name}] save_predictions()")
|
|
@@ -332,7 +335,7 @@ def _run_classification_pipeline(config_path: str, dataset: dict, run_name: str)
|
|
|
332
335
|
record_release_metadata("prediction", task="classification", model_family=run_name, prediction_path=str(pred_path))
|
|
333
336
|
|
|
334
337
|
report_step(f"[{run_name}] evaluate()")
|
|
335
|
-
metrics =
|
|
338
|
+
metrics = restored_model.evaluate(test_set=str(split_paths["test"]), predictions=predictions, use_wandb=False)
|
|
336
339
|
assert isinstance(metrics, dict), f"[{run_name}] evaluate() did not return metrics"
|
|
337
340
|
record_release_metadata(
|
|
338
341
|
"result", task="classification", model_family=run_name,
|
|
@@ -341,6 +344,30 @@ def _run_classification_pipeline(config_path: str, dataset: dict, run_name: str)
|
|
|
341
344
|
print(f"[{run_name}] metrics: {metrics}")
|
|
342
345
|
|
|
343
346
|
|
|
347
|
+
@pytest.mark.release
|
|
348
|
+
def test_published_classification_model_inference(classification_dataset):
|
|
349
|
+
"""Published model artifact must load with its canonical inference path."""
|
|
350
|
+
require_release_enabled()
|
|
351
|
+
from ._release_common import require_model_repo
|
|
352
|
+
|
|
353
|
+
require_model_repo(PUBLISHED_CLASSIFICATION_MODEL)
|
|
354
|
+
dataset = classification_dataset
|
|
355
|
+
overrides = system_block("published_classification_mvitv2")
|
|
356
|
+
overrides["DATA"] = {
|
|
357
|
+
"common": {
|
|
358
|
+
"data_root": str(dataset["data_root"]), "classes": dataset["classes"],
|
|
359
|
+
"splits": {split: {"annotation_path": str(path), "source_path": str(dataset["source_paths"][split])}
|
|
360
|
+
for split, path in dataset["split_paths"].items()},
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
config_path = materialize_config("classification", "video", overrides, out_name="published_cls_mvitv2.yaml")
|
|
364
|
+
model = ClassificationModel(config=config_path, weights=PUBLISHED_CLASSIFICATION_MODEL)
|
|
365
|
+
predictions = model.infer(test_set=str(dataset["split_paths"]["test"]), use_wandb=False)
|
|
366
|
+
assert isinstance(predictions, dict) and predictions.get("data")
|
|
367
|
+
metrics = model.evaluate(test_set=str(dataset["split_paths"]["test"]), predictions=predictions, use_wandb=False)
|
|
368
|
+
record_release_metadata("published_model_result", task="classification", model_id=PUBLISHED_CLASSIFICATION_MODEL, metrics=metrics)
|
|
369
|
+
|
|
370
|
+
|
|
344
371
|
@pytest.mark.release
|
|
345
372
|
@pytest.mark.parametrize("backbone", MVNETWORK_BACKBONES)
|
|
346
373
|
def test_classification_mvnetwork_backbone(classification_dataset, backbone):
|
|
@@ -375,7 +402,7 @@ def test_classification_mvnetwork_backbone(classification_dataset, backbone):
|
|
|
375
402
|
"task_head": {"params": {"num_classes": len(dataset["classes"])}},
|
|
376
403
|
}
|
|
377
404
|
}
|
|
378
|
-
overrides["TRAIN"] =
|
|
405
|
+
overrides["TRAIN"] = training_overrides(2)
|
|
379
406
|
|
|
380
407
|
config_path = materialize_config("classification", "video", overrides, out_name=f"cls_{backbone}.yaml")
|
|
381
408
|
_run_classification_pipeline(config_path, dataset, backbone)
|
|
@@ -421,7 +448,7 @@ def test_classification_video_mae_huggingface_backend(classification_dataset):
|
|
|
421
448
|
"task_head": {"params": {"num_classes": len(dataset["classes"])}},
|
|
422
449
|
}
|
|
423
450
|
}
|
|
424
|
-
overrides["TRAIN"] =
|
|
451
|
+
overrides["TRAIN"] = training_overrides(2)
|
|
425
452
|
|
|
426
453
|
config_path = materialize_config("classification", "video", overrides, out_name="cls_video_mae.yaml")
|
|
427
454
|
_run_classification_pipeline(config_path, dataset, "video_mae")
|
|
@@ -480,9 +507,9 @@ def tracking_classification_dataset():
|
|
|
480
507
|
|
|
481
508
|
require_release_enabled()
|
|
482
509
|
require_repo_access(TRACKING_CLS_REPO)
|
|
483
|
-
require_repo_populated(TRACKING_CLS_REPO)
|
|
484
|
-
root = DATA_DIR / "classification" / TRACKING_CLS_REPO.split(
|
|
485
|
-
snapshot_dataset(TRACKING_CLS_REPO, root)
|
|
510
|
+
require_repo_populated(TRACKING_CLS_REPO, revision=TRACKING_CLS_REVISION)
|
|
511
|
+
root = DATA_DIR / "classification" / f"{TRACKING_CLS_REPO.split('/')[-1]}-{TRACKING_CLS_REVISION}"
|
|
512
|
+
snapshot_dataset(TRACKING_CLS_REPO, root, revision=TRACKING_CLS_REVISION)
|
|
486
513
|
split_paths = {}
|
|
487
514
|
for split in ("train", "valid", "test"):
|
|
488
515
|
candidates = sorted(root.rglob(f"*{split}*.json"))
|
|
@@ -500,6 +527,7 @@ def tracking_classification_dataset():
|
|
|
500
527
|
|
|
501
528
|
|
|
502
529
|
@pytest.mark.release
|
|
530
|
+
@pytest.mark.release_gar
|
|
503
531
|
def test_classification_tracking_graph_conv(tracking_classification_dataset):
|
|
504
532
|
"""Tracking-modality classification (graph_conv backbone,
|
|
505
533
|
classification/sngar_tracking.yaml canonical config). Uses
|
|
@@ -521,7 +549,7 @@ def test_classification_tracking_graph_conv(tracking_classification_dataset):
|
|
|
521
549
|
"inputs": {"video": {"params": {"max_samples": max_items_for("OSL_RELEASE_MAX_CLIPS", 40)}}},
|
|
522
550
|
}
|
|
523
551
|
overrides["MODEL"] = {"components": {"task_head": {"params": {"num_classes": len(dataset["classes"])}}}}
|
|
524
|
-
overrides["TRAIN"] =
|
|
552
|
+
overrides["TRAIN"] = training_overrides(1)
|
|
525
553
|
config_path = materialize_config(
|
|
526
554
|
"classification", "sngar_tracking", overrides, out_name="cls_graph_conv.yaml"
|
|
527
555
|
)
|
|
@@ -555,7 +583,7 @@ def test_classification_frames_npy_backbones(frames_npy_dataset, backbone):
|
|
|
555
583
|
"video_adapter": {"params": {"hidden_dim": hidden_dim}},
|
|
556
584
|
"task_head": {"params": {"hidden_dim": hidden_dim, "num_classes": len(dataset["classes"])}},
|
|
557
585
|
}}
|
|
558
|
-
overrides["TRAIN"] =
|
|
586
|
+
overrides["TRAIN"] = training_overrides(1)
|
|
559
587
|
config_path = materialize_config(
|
|
560
588
|
"classification", "sngar_frames", overrides, out_name=f"cls_frames_{backbone}.yaml"
|
|
561
589
|
)
|
{opensportslib-0.3.1.dev19 → opensportslib-0.3.1.dev21}/tests/release/test_localization_release.py
RENAMED
|
@@ -55,7 +55,7 @@ from ._release_common import (
|
|
|
55
55
|
classes_from_osl_json,
|
|
56
56
|
download_files,
|
|
57
57
|
download_shard_split,
|
|
58
|
-
|
|
58
|
+
training_overrides,
|
|
59
59
|
hf_token,
|
|
60
60
|
materialize_config,
|
|
61
61
|
max_items_for,
|
|
@@ -63,6 +63,7 @@ from ._release_common import (
|
|
|
63
63
|
prefer_osl_ready_dataset,
|
|
64
64
|
report_step,
|
|
65
65
|
record_release_metadata,
|
|
66
|
+
release_scale,
|
|
66
67
|
require_release_enabled,
|
|
67
68
|
require_repo_access,
|
|
68
69
|
snapshot_dataset,
|
|
@@ -98,6 +99,7 @@ E2E_FALLBACK_REPO = os.environ.get("OSL_RELEASE_LOC_E2E_FALLBACK_REPO", "OpenSpo
|
|
|
98
99
|
# the (non-sharded, 2210-file) SoccerNet-ActionSpotting-Features dataset only
|
|
99
100
|
# if that branch isn't up.
|
|
100
101
|
FEATURES_PRIMARY_REPO = os.environ.get("OSL_RELEASE_LOC_FEATURES_REPO", "OpenSportsLab/OSL-SoccerNet")
|
|
102
|
+
PUBLISHED_LOCALIZATION_MODEL = "OpenSportsLab/OSL-loc-snbas-2025-e2e"
|
|
101
103
|
FEATURES_PRIMARY_REVISION = os.environ.get("OSL_RELEASE_LOC_FEATURES_REVISION", "ResNET_PCA512")
|
|
102
104
|
FEATURES_FALLBACK_REPO = os.environ.get(
|
|
103
105
|
"OSL_RELEASE_LOC_FEATURES_FALLBACK_REPO", "OpenSportsLab/SoccerNet-ActionSpotting-Features"
|
|
@@ -200,10 +202,10 @@ def _e2e_overrides(run_name: str, dataset: dict, backbone: str, head: str, *, lo
|
|
|
200
202
|
"task_head": {"source": {"name": head}},
|
|
201
203
|
}
|
|
202
204
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
205
|
+
train_overrides = training_overrides(2)
|
|
206
|
+
overrides["TRAIN"] = train_overrides
|
|
207
|
+
if "epochs" in train_overrides:
|
|
208
|
+
overrides["TRAIN"]["scheduler"] = {"num_epochs": train_overrides["epochs"]}
|
|
207
209
|
return overrides
|
|
208
210
|
|
|
209
211
|
|
|
@@ -226,8 +228,9 @@ def _run_localization_pipeline(config_path: str, dataset: dict, run_name: str) -
|
|
|
226
228
|
config_path=config_path, checkpoint_path=str(checkpoint),
|
|
227
229
|
)
|
|
228
230
|
|
|
229
|
-
report_step(f"[{run_name}] infer()")
|
|
230
|
-
|
|
231
|
+
report_step(f"[{run_name}] fresh checkpoint load + infer()")
|
|
232
|
+
restored_model = LocalizationModel(config=config_path, weights=checkpoint)
|
|
233
|
+
predictions = restored_model.infer(test_set=str(split_paths["test"]), use_wandb=False)
|
|
231
234
|
assert isinstance(predictions, dict) and predictions.get("data"), f"[{run_name}] empty predictions"
|
|
232
235
|
|
|
233
236
|
report_step(f"[{run_name}] save_predictions()")
|
|
@@ -237,7 +240,7 @@ def _run_localization_pipeline(config_path: str, dataset: dict, run_name: str) -
|
|
|
237
240
|
record_release_metadata("prediction", task="localization", model_family=run_name, prediction_path=str(pred_path))
|
|
238
241
|
|
|
239
242
|
report_step(f"[{run_name}] evaluate()")
|
|
240
|
-
metrics =
|
|
243
|
+
metrics = restored_model.evaluate(test_set=str(split_paths["test"]), predictions=predictions, use_wandb=False)
|
|
241
244
|
record_release_metadata(
|
|
242
245
|
"result", task="localization", model_family=run_name,
|
|
243
246
|
runtime_seconds=round(time.perf_counter() - started, 3),
|
|
@@ -245,6 +248,22 @@ def _run_localization_pipeline(config_path: str, dataset: dict, run_name: str) -
|
|
|
245
248
|
print(f"[{run_name}] metrics: {metrics}")
|
|
246
249
|
|
|
247
250
|
|
|
251
|
+
@pytest.mark.release
|
|
252
|
+
def test_published_localization_model_inference(e2e_localization_dataset):
|
|
253
|
+
require_release_enabled()
|
|
254
|
+
from ._release_common import require_model_repo
|
|
255
|
+
|
|
256
|
+
require_model_repo(PUBLISHED_LOCALIZATION_MODEL)
|
|
257
|
+
dataset = e2e_localization_dataset
|
|
258
|
+
overrides = _e2e_overrides("published_loc_e2e", dataset, "rny008_gsm", "gru", loader_backend="dali")
|
|
259
|
+
config_path = materialize_config("localization", "video_dali", overrides, out_name="published_loc_e2e.yaml")
|
|
260
|
+
model = LocalizationModel(config=config_path, weights=PUBLISHED_LOCALIZATION_MODEL)
|
|
261
|
+
predictions = model.infer(test_set=str(dataset["split_paths"]["test"]), use_wandb=False)
|
|
262
|
+
assert isinstance(predictions, dict) and predictions.get("data")
|
|
263
|
+
metrics = model.evaluate(test_set=str(dataset["split_paths"]["test"]), predictions=predictions, use_wandb=False)
|
|
264
|
+
record_release_metadata("published_model_result", task="localization", model_id=PUBLISHED_LOCALIZATION_MODEL, metrics=metrics)
|
|
265
|
+
|
|
266
|
+
|
|
248
267
|
# Curated backbone x head coverage. Full cross product of every
|
|
249
268
|
# backbone_type/head_type check_config() allows (see opensportslib/core/utils/
|
|
250
269
|
# load_annotations.py::check_config) would be 9 backbones x 4 heads = 36 runs;
|
|
@@ -253,7 +272,11 @@ def _run_localization_pipeline(config_path: str, dataset: dict, run_name: str) -
|
|
|
253
272
|
# coverage on a dedicated release-test machine.
|
|
254
273
|
E2E_BACKBONES = ["rn18", "rn50", "rny002", "rny008_gsm", "convnextt"]
|
|
255
274
|
E2E_HEADS = ["gru", "deeper_gru", "mstcn", "asformer"]
|
|
256
|
-
E2E_MATRIX =
|
|
275
|
+
E2E_MATRIX = (
|
|
276
|
+
[(backbone, head) for backbone in E2E_BACKBONES for head in E2E_HEADS]
|
|
277
|
+
if release_scale() == "full"
|
|
278
|
+
else [(b, "gru") for b in E2E_BACKBONES] + [("rn18", h) for h in E2E_HEADS if h != "gru"]
|
|
279
|
+
)
|
|
257
280
|
|
|
258
281
|
|
|
259
282
|
@pytest.mark.release
|
|
@@ -364,7 +387,7 @@ def _feature_family_overrides(run_name: str, dataset: dict) -> dict:
|
|
|
364
387
|
},
|
|
365
388
|
},
|
|
366
389
|
}
|
|
367
|
-
overrides["TRAIN"] =
|
|
390
|
+
overrides["TRAIN"] = training_overrides(3)
|
|
368
391
|
return overrides
|
|
369
392
|
|
|
370
393
|
|