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