opensportslib 0.3.1.dev6__tar.gz → 0.3.1.dev8__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.dev6/opensportslib.egg-info → opensportslib-0.3.1.dev8}/PKG-INFO +10 -1
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/README.md +9 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/__init__.py +6 -1
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/apis/__init__.py +3 -0
- opensportslib-0.3.1.dev8/opensportslib/remote_registry.py +124 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8/opensportslib.egg-info}/PKG-INFO +10 -1
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib.egg-info/SOURCES.txt +3 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/pyproject.toml +1 -1
- opensportslib-0.3.1.dev8/tests/test_remote_model_registry.py +94 -0
- opensportslib-0.3.1.dev8/tests/test_server_model_registry.py +100 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/LICENSE +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/LICENSE-COMMERCIAL +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/MANIFEST.in +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/examples/quickstart/basic_classification.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/examples/quickstart/basic_localization.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/examples/quickstart/basic_vqa.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/adaptation/__init__.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/adaptation/spotta.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/apis/base_task_model.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/apis/classification.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/apis/config.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/apis/configuration.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/apis/localization.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/apis/vqa.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/cli.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/classification/default.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/classification/sngar_frames.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/classification/sngar_tracking.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/classification/video.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/default.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/localization/calf_resnetpca512.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/localization/default.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/localization/e2e_spotta.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/localization/h5_header_distance.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/localization/h5_header_skeleton.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/localization/netvladpp_resnetpca512.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/localization/tracking_action_spotting.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/localization/video_dali.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/localization/video_ocv.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/vqa/default.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/vqa/qwen.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/vqa/qwen3_vl_native.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/vqa/qwen_lora.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/vqa/qwen_sngar_frames.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/vqa/xvars.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/__init__.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/__init__.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/accessors.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/conflicts.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/editable.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/loader.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/migrate.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/migrations/__init__.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/migrations/legacy_to_canonical.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/rule_variants.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/runtime_adapter.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/schema.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/schemas/__init__.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/schemas/schema_canonical.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/schemas/schema_legacy.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/validate.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/loss/__init__.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/loss/builder.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/loss/calf.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/loss/ce.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/loss/combine.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/loss/nll.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/optimizer/__init__.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/optimizer/builder.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/sampler/weighted_sampler.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/scheduler/__init__.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/scheduler/builder.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/trainer/__init__.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/trainer/classification_trainer.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/trainer/localization_trainer.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/trainer/vqa_trainer.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/checkpoint.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/config.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/config_normalize.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/data.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/ddp.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/default_args.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/direct_video.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/hf_runtime.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/lightning.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/load_annotations.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/seed.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/video_processing.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/wandb.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/datasets/__init__.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/datasets/builder.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/datasets/classification_dataset.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/datasets/localization_dataset.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/datasets/utils/__init__.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/datasets/utils/h5_tracking.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/datasets/utils/tracking.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/datasets/vqa_dataset.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/legacy_config/classification.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/legacy_config/localization-e2e-ocv.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/legacy_config/localization-json_calf_resnetpca512.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/legacy_config/localization-json_netvlad++_resnetpca512.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/legacy_config/localization.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/legacy_config/sngar-frames.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/legacy_config/sngar-tracking.yaml +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/metrics/classification_metric.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/metrics/localization_metric.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/metrics/vqa_metric.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/__init__.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/backbones/builder.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/base/contextaware.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/base/e2e.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/base/learnablepooling.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/base/qwen_vl_native.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/base/qwen_xvars.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/base/rule_based.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/base/tracking.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/base/vars.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/base/video.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/base/video_chatgpt_compat.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/base/video_mae.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/base/xvars_videochatgpt.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/builder.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/heads/builder.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/neck/builder.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/utils/common.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/utils/impl/__init__.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/utils/impl/asformer.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/utils/impl/calf.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/utils/impl/gsm.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/utils/impl/gtad.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/utils/impl/tsm.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/utils/litebase.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/utils/modules.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/utils/shift.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/utils/utils.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/utils/vqa_prediction_priors.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/utils/vqa_prompting.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/models/utils/xvars_clip_index.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/setup/setup.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/tools/__init__.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/tools/_common.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/tools/hf_transfer.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/tools/osl_json_to_parquet.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/tools/parquet_to_osl_json.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib.egg-info/dependency_links.txt +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib.egg-info/entry_points.txt +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib.egg-info/requires.txt +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib.egg-info/top_level.txt +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/scripts/release_versions.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/scripts/run_h5_header_rule_inference.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/setup.cfg +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/conftest.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/release/__init__.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/release/_release_common.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/release/test_classification_release.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/release/test_localization_release.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/release/test_vqa_release.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_classification_dataset_paths.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_classification_trainer_dataloader.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_config_architecture.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_config_split_override_sync.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_config_utils_smoke.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_conversion_tools.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_editable_config.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_extract_xvars_features.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_h5_header_rule_spotter.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_h5_header_skeleton_spotter.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_h5_tracking_dataset.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_hf_transfer_tools.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_localization_dali_filenames.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_localization_hf_backend_override.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_localization_intervals.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_optional_hf_config.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_package_smoke.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_pretrained_config_merge_policy.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_public_apis_smoke.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_release_versions.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_setup_cli.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_spotta_e2e.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_subset_train_infer_integration.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_task_model_api_contract.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_vqa_api.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_vqa_metrics_semantic.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_vqa_qwen_xvars.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_vqa_training_lora.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tests/test_vqa_xvars_videochatgpt.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/convert/build_sn_vqa_2026_vqa.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/convert/build_sngar_spotting.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/convert/build_soccernet_gar.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/convert/build_soccernet_gar_action_spotting.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/convert/build_soccernet_gar_vqa.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/convert/build_xvars_indexes.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/convert/extract_xvars_clip_features.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/convert/osl_json_to_parquet_webdataset.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/convert/parquet_webdataset_to_osl_json.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/convert/sngar_dataset_card.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/convert/sngar_events.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/convert/verify_sngar_spotting.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/download/download_hf_repo.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/download/download_osl_hf.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/download/push_sngar_spotting.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/download/upload_osl_hf.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/training/classification.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/training/localization.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/tools/training/vqa.py +0 -0
- {opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/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.dev8
|
|
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
|
|
@@ -36,6 +36,15 @@ Dynamic: license-file
|
|
|
36
36
|
|
|
37
37
|
# OpenSportsLib
|
|
38
38
|
|
|
39
|
+
OpenSportsLib inference servers support runtime model registration through
|
|
40
|
+
`RemoteModelRegistry`. Its unified `register_model()` method accepts Hugging
|
|
41
|
+
Face or server-local weights; the returned model ID is then used by the existing
|
|
42
|
+
remote task APIs. Unregistered model IDs are rejected.
|
|
43
|
+
|
|
44
|
+
See the [complete inference server guide](docs/server/inference-server.md) for
|
|
45
|
+
installation, registry administration, curl requests, single-video inference,
|
|
46
|
+
full-test-set and per-sample remote inference, job polling, and sessions.
|
|
47
|
+
|
|
39
48
|
## Configuration From Hugging Face
|
|
40
49
|
|
|
41
50
|
Prepare and inspect configuration before model weights are allocated:
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# OpenSportsLib
|
|
2
2
|
|
|
3
|
+
OpenSportsLib inference servers support runtime model registration through
|
|
4
|
+
`RemoteModelRegistry`. Its unified `register_model()` method accepts Hugging
|
|
5
|
+
Face or server-local weights; the returned model ID is then used by the existing
|
|
6
|
+
remote task APIs. Unregistered model IDs are rejected.
|
|
7
|
+
|
|
8
|
+
See the [complete inference server guide](docs/server/inference-server.md) for
|
|
9
|
+
installation, registry administration, curl requests, single-video inference,
|
|
10
|
+
full-test-set and per-sample remote inference, job polling, and sessions.
|
|
11
|
+
|
|
3
12
|
## Configuration From Hugging Face
|
|
4
13
|
|
|
5
14
|
Prepare and inspect configuration before model weights are allocated:
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import importlib
|
|
2
2
|
|
|
3
|
+
from opensportslib.remote_registry import RemoteModelRegistry, RemoteRegistryError
|
|
4
|
+
|
|
3
5
|
|
|
4
6
|
def __getattr__(name):
|
|
5
7
|
if name == "model":
|
|
@@ -15,4 +17,7 @@ def __getattr__(name):
|
|
|
15
17
|
raise AttributeError(f"module 'opensportslib' has no attribute '{name}'")
|
|
16
18
|
|
|
17
19
|
|
|
18
|
-
__all__ = [
|
|
20
|
+
__all__ = [
|
|
21
|
+
"model", "metrics", "datasets", "core", "tools",
|
|
22
|
+
"RemoteModelRegistry", "RemoteRegistryError",
|
|
23
|
+
]
|
|
@@ -6,6 +6,7 @@ from opensportslib.apis.base_task_model import BaseTaskModel
|
|
|
6
6
|
from opensportslib.apis.classification import ClassificationModel
|
|
7
7
|
from opensportslib.apis.localization import LocalizationModel
|
|
8
8
|
from opensportslib.apis.vqa import VQAModel
|
|
9
|
+
from opensportslib.remote_registry import RemoteModelRegistry, RemoteRegistryError
|
|
9
10
|
import warnings
|
|
10
11
|
warnings.filterwarnings("ignore")
|
|
11
12
|
|
|
@@ -16,4 +17,6 @@ __all__ = [
|
|
|
16
17
|
"ClassificationModel",
|
|
17
18
|
"LocalizationModel",
|
|
18
19
|
"VQAModel",
|
|
20
|
+
"RemoteModelRegistry",
|
|
21
|
+
"RemoteRegistryError",
|
|
19
22
|
]
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import time
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
from urllib import error, parse, request
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RemoteRegistryError(RuntimeError):
|
|
11
|
+
def __init__(self, status_code: int, detail: Any):
|
|
12
|
+
self.status_code = status_code
|
|
13
|
+
self.detail = detail
|
|
14
|
+
super().__init__(f"Remote model registry returned HTTP {status_code}: {detail}")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class RemoteModelRegistry:
|
|
18
|
+
"""Administrative client for an OpenSportsLib server model registry."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, remote: str, admin_token: str, timeout: float = 30.0):
|
|
21
|
+
if not remote:
|
|
22
|
+
raise ValueError("remote is required.")
|
|
23
|
+
if not admin_token:
|
|
24
|
+
raise ValueError("admin_token is required.")
|
|
25
|
+
self.remote = remote.rstrip("/")
|
|
26
|
+
self.admin_token = admin_token
|
|
27
|
+
self.timeout = float(timeout)
|
|
28
|
+
if self.timeout <= 0:
|
|
29
|
+
raise ValueError("timeout must be positive.")
|
|
30
|
+
|
|
31
|
+
def register_model(
|
|
32
|
+
self,
|
|
33
|
+
*,
|
|
34
|
+
task_type: str,
|
|
35
|
+
huggingface_model_id: str | None = None,
|
|
36
|
+
weights_path: str | Path | None = None,
|
|
37
|
+
config_path: str | Path | None = None,
|
|
38
|
+
model_id: str | None = None,
|
|
39
|
+
) -> dict[str, Any]:
|
|
40
|
+
"""Register exactly one Hugging Face or server-local model source."""
|
|
41
|
+
if (huggingface_model_id is None) == (weights_path is None):
|
|
42
|
+
raise ValueError("Provide exactly one of huggingface_model_id or weights_path.")
|
|
43
|
+
if huggingface_model_id is not None:
|
|
44
|
+
if config_path is not None:
|
|
45
|
+
raise ValueError("config_path applies only to local models.")
|
|
46
|
+
if model_id is not None and model_id != huggingface_model_id:
|
|
47
|
+
raise ValueError("A Hugging Face model uses its repository ID as model_id.")
|
|
48
|
+
payload = {
|
|
49
|
+
"task_type": task_type,
|
|
50
|
+
"source": {"type": "huggingface", "model_id": huggingface_model_id},
|
|
51
|
+
}
|
|
52
|
+
else:
|
|
53
|
+
payload = {
|
|
54
|
+
"task_type": task_type,
|
|
55
|
+
"model_id": model_id,
|
|
56
|
+
"source": {
|
|
57
|
+
"type": "local",
|
|
58
|
+
"weights_path": str(weights_path),
|
|
59
|
+
"config_path": str(config_path) if config_path is not None else None,
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
return self._request("POST", "/models", payload, authenticated=True)
|
|
63
|
+
|
|
64
|
+
def list_models(self) -> list[dict[str, Any]]:
|
|
65
|
+
return self._request("GET", "/models")["models"]
|
|
66
|
+
|
|
67
|
+
def get_model(self, model_id: str) -> dict[str, Any]:
|
|
68
|
+
query = parse.urlencode({"model_id": model_id})
|
|
69
|
+
return self._request("GET", f"/models/status?{query}")
|
|
70
|
+
|
|
71
|
+
def get_operation(self, operation_id: str) -> dict[str, Any]:
|
|
72
|
+
return self._request("GET", f"/model-operations/{parse.quote(operation_id, safe='')}", authenticated=True)
|
|
73
|
+
|
|
74
|
+
def wait_for_operation(
|
|
75
|
+
self,
|
|
76
|
+
operation_id: str,
|
|
77
|
+
*,
|
|
78
|
+
timeout: float = 7200.0,
|
|
79
|
+
poll_interval: float = 1.0,
|
|
80
|
+
) -> dict[str, Any]:
|
|
81
|
+
deadline = time.monotonic() + timeout
|
|
82
|
+
while True:
|
|
83
|
+
operation = self.get_operation(operation_id)
|
|
84
|
+
if operation["status"] == "succeeded":
|
|
85
|
+
return operation
|
|
86
|
+
if operation["status"] == "failed":
|
|
87
|
+
raise RuntimeError(operation.get("error") or "Model operation failed.")
|
|
88
|
+
if time.monotonic() >= deadline:
|
|
89
|
+
raise TimeoutError(f"Timed out waiting for model operation `{operation_id}`.")
|
|
90
|
+
time.sleep(poll_interval)
|
|
91
|
+
|
|
92
|
+
def set_default(self, task_type: str, model_id: str) -> dict[str, Any]:
|
|
93
|
+
task = parse.quote(task_type, safe="")
|
|
94
|
+
return self._request("PUT", f"/models/defaults/{task}", {"model_id": model_id}, authenticated=True)
|
|
95
|
+
|
|
96
|
+
def unregister_model(self, model_id: str) -> dict[str, Any]:
|
|
97
|
+
encoded = parse.quote(model_id, safe="")
|
|
98
|
+
return self._request("DELETE", f"/models/{encoded}", authenticated=True)
|
|
99
|
+
|
|
100
|
+
def _request(
|
|
101
|
+
self,
|
|
102
|
+
method: str,
|
|
103
|
+
endpoint: str,
|
|
104
|
+
payload: dict[str, Any] | None = None,
|
|
105
|
+
authenticated: bool = False,
|
|
106
|
+
) -> dict[str, Any]:
|
|
107
|
+
body = json.dumps(payload).encode() if payload is not None else None
|
|
108
|
+
headers = {"Content-Type": "application/json"}
|
|
109
|
+
if authenticated:
|
|
110
|
+
headers["Authorization"] = f"Bearer {self.admin_token}"
|
|
111
|
+
outgoing = request.Request(self.remote + endpoint, data=body, method=method, headers=headers)
|
|
112
|
+
try:
|
|
113
|
+
with request.urlopen(outgoing, timeout=self.timeout) as response:
|
|
114
|
+
return json.loads(response.read().decode())
|
|
115
|
+
except error.HTTPError as exc:
|
|
116
|
+
detail = exc.read().decode(errors="replace")
|
|
117
|
+
try:
|
|
118
|
+
parsed = json.loads(detail)
|
|
119
|
+
detail = parsed.get("detail", parsed)
|
|
120
|
+
except json.JSONDecodeError:
|
|
121
|
+
pass
|
|
122
|
+
raise RemoteRegistryError(exc.code, detail) from exc
|
|
123
|
+
except error.URLError as exc:
|
|
124
|
+
raise ConnectionError(f"Could not reach remote server `{self.remote}`: {exc.reason}") from exc
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opensportslib
|
|
3
|
-
Version: 0.3.1.
|
|
3
|
+
Version: 0.3.1.dev8
|
|
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
|
|
@@ -36,6 +36,15 @@ Dynamic: license-file
|
|
|
36
36
|
|
|
37
37
|
# OpenSportsLib
|
|
38
38
|
|
|
39
|
+
OpenSportsLib inference servers support runtime model registration through
|
|
40
|
+
`RemoteModelRegistry`. Its unified `register_model()` method accepts Hugging
|
|
41
|
+
Face or server-local weights; the returned model ID is then used by the existing
|
|
42
|
+
remote task APIs. Unregistered model IDs are rejected.
|
|
43
|
+
|
|
44
|
+
See the [complete inference server guide](docs/server/inference-server.md) for
|
|
45
|
+
installation, registry administration, curl requests, single-video inference,
|
|
46
|
+
full-test-set and per-sample remote inference, job polling, and sessions.
|
|
47
|
+
|
|
39
48
|
## Configuration From Hugging Face
|
|
40
49
|
|
|
41
50
|
Prepare and inspect configuration before model weights are allocated:
|
|
@@ -8,6 +8,7 @@ examples/quickstart/basic_localization.py
|
|
|
8
8
|
examples/quickstart/basic_vqa.py
|
|
9
9
|
opensportslib/__init__.py
|
|
10
10
|
opensportslib/cli.py
|
|
11
|
+
opensportslib/remote_registry.py
|
|
11
12
|
opensportslib.egg-info/PKG-INFO
|
|
12
13
|
opensportslib.egg-info/SOURCES.txt
|
|
13
14
|
opensportslib.egg-info/dependency_links.txt
|
|
@@ -165,6 +166,8 @@ tests/test_package_smoke.py
|
|
|
165
166
|
tests/test_pretrained_config_merge_policy.py
|
|
166
167
|
tests/test_public_apis_smoke.py
|
|
167
168
|
tests/test_release_versions.py
|
|
169
|
+
tests/test_remote_model_registry.py
|
|
170
|
+
tests/test_server_model_registry.py
|
|
168
171
|
tests/test_setup_cli.py
|
|
169
172
|
tests/test_spotta_e2e.py
|
|
170
173
|
tests/test_subset_train_infer_integration.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.dev8"
|
|
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,94 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from unittest.mock import patch
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
from opensportslib import RemoteModelRegistry, RemoteRegistryError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class FakeResponse:
|
|
10
|
+
def __init__(self, payload):
|
|
11
|
+
self.payload = payload
|
|
12
|
+
|
|
13
|
+
def __enter__(self):
|
|
14
|
+
return self
|
|
15
|
+
|
|
16
|
+
def __exit__(self, *args):
|
|
17
|
+
return False
|
|
18
|
+
|
|
19
|
+
def read(self):
|
|
20
|
+
return json.dumps(self.payload).encode()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_register_huggingface_uses_one_registration_method():
|
|
24
|
+
client = RemoteModelRegistry("http://server", "secret")
|
|
25
|
+
with patch("opensportslib.remote_registry.request.urlopen") as urlopen:
|
|
26
|
+
urlopen.return_value = FakeResponse({"model_id": "org/model", "status": "registering"})
|
|
27
|
+
result = client.register_model(task_type="classification", huggingface_model_id="org/model")
|
|
28
|
+
|
|
29
|
+
outgoing = urlopen.call_args.args[0]
|
|
30
|
+
assert json.loads(outgoing.data) == {
|
|
31
|
+
"task_type": "classification",
|
|
32
|
+
"source": {"type": "huggingface", "model_id": "org/model"},
|
|
33
|
+
}
|
|
34
|
+
assert outgoing.headers["Authorization"] == "Bearer secret"
|
|
35
|
+
assert result["model_id"] == "org/model"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_register_local_supports_custom_or_generated_model_id():
|
|
39
|
+
client = RemoteModelRegistry("http://server", "secret")
|
|
40
|
+
with patch("opensportslib.remote_registry.request.urlopen") as urlopen:
|
|
41
|
+
urlopen.return_value = FakeResponse({"model_id": "custom", "status": "registering"})
|
|
42
|
+
client.register_model(
|
|
43
|
+
task_type="localization",
|
|
44
|
+
model_id="custom",
|
|
45
|
+
weights_path="/models/custom/model.pth",
|
|
46
|
+
config_path="/models/custom/config.yaml",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
payload = json.loads(urlopen.call_args.args[0].data)
|
|
50
|
+
assert payload["model_id"] == "custom"
|
|
51
|
+
assert payload["source"] == {
|
|
52
|
+
"type": "local",
|
|
53
|
+
"weights_path": "/models/custom/model.pth",
|
|
54
|
+
"config_path": "/models/custom/config.yaml",
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@pytest.mark.parametrize(
|
|
59
|
+
"kwargs",
|
|
60
|
+
[
|
|
61
|
+
{},
|
|
62
|
+
{"huggingface_model_id": "org/model", "weights_path": "/models/model"},
|
|
63
|
+
],
|
|
64
|
+
)
|
|
65
|
+
def test_register_model_requires_exactly_one_source(kwargs):
|
|
66
|
+
client = RemoteModelRegistry("http://server", "secret")
|
|
67
|
+
with pytest.raises(ValueError, match="exactly one"):
|
|
68
|
+
client.register_model(task_type="classification", **kwargs)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_huggingface_model_cannot_be_renamed():
|
|
72
|
+
client = RemoteModelRegistry("http://server", "secret")
|
|
73
|
+
with pytest.raises(ValueError, match="repository ID"):
|
|
74
|
+
client.register_model(
|
|
75
|
+
task_type="classification",
|
|
76
|
+
huggingface_model_id="org/model",
|
|
77
|
+
model_id="alias",
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_http_errors_preserve_structured_detail():
|
|
82
|
+
from urllib.error import HTTPError
|
|
83
|
+
from io import BytesIO
|
|
84
|
+
|
|
85
|
+
client = RemoteModelRegistry("http://server", "secret")
|
|
86
|
+
response = HTTPError(
|
|
87
|
+
"http://server/models", 409, "Conflict", {},
|
|
88
|
+
BytesIO(json.dumps({"detail": {"code": "MODEL_NOT_READY"}}).encode()),
|
|
89
|
+
)
|
|
90
|
+
with patch("opensportslib.remote_registry.request.urlopen", side_effect=response):
|
|
91
|
+
with pytest.raises(RemoteRegistryError) as raised:
|
|
92
|
+
client.get_model("model")
|
|
93
|
+
assert raised.value.status_code == 409
|
|
94
|
+
assert raised.value.detail == {"code": "MODEL_NOT_READY"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from types import SimpleNamespace
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
SERVER_ROOT = Path(__file__).parents[1] / "server"
|
|
9
|
+
sys.path.insert(0, str(SERVER_ROOT))
|
|
10
|
+
|
|
11
|
+
from config.model_registry import ( # noqa: E402
|
|
12
|
+
ModelRegistry,
|
|
13
|
+
generated_local_model_id,
|
|
14
|
+
public_record,
|
|
15
|
+
resolve_local_source,
|
|
16
|
+
validate_local_model_id,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class FakeRedis:
|
|
21
|
+
def __init__(self):
|
|
22
|
+
self.hashes = {}
|
|
23
|
+
|
|
24
|
+
def hget(self, key, field):
|
|
25
|
+
return self.hashes.get(key, {}).get(field)
|
|
26
|
+
|
|
27
|
+
def hvals(self, key):
|
|
28
|
+
return list(self.hashes.get(key, {}).values())
|
|
29
|
+
|
|
30
|
+
def hset(self, key, field, value):
|
|
31
|
+
self.hashes.setdefault(key, {})[field] = value
|
|
32
|
+
|
|
33
|
+
def hsetnx(self, key, field, value):
|
|
34
|
+
values = self.hashes.setdefault(key, {})
|
|
35
|
+
if field in values:
|
|
36
|
+
return 0
|
|
37
|
+
values[field] = value
|
|
38
|
+
return 1
|
|
39
|
+
|
|
40
|
+
def hdel(self, key, field):
|
|
41
|
+
self.hashes.get(key, {}).pop(field, None)
|
|
42
|
+
|
|
43
|
+
def hgetall(self, key):
|
|
44
|
+
return dict(self.hashes.get(key, {}))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def record(model_id="model", source="org/model"):
|
|
48
|
+
return {
|
|
49
|
+
"model_id": model_id,
|
|
50
|
+
"task_type": "classification",
|
|
51
|
+
"source_type": "huggingface",
|
|
52
|
+
"source": source,
|
|
53
|
+
"config_path": None,
|
|
54
|
+
"status": "ready",
|
|
55
|
+
"generation": 1,
|
|
56
|
+
"created_at": "now",
|
|
57
|
+
"updated_at": "now",
|
|
58
|
+
"error": None,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_registry_reserves_idempotently_and_rejects_conflicts():
|
|
63
|
+
registry = ModelRegistry(SimpleNamespace(redis_url="redis://unused"), FakeRedis())
|
|
64
|
+
_, created = registry.reserve(record())
|
|
65
|
+
assert created
|
|
66
|
+
existing, created = registry.reserve(record())
|
|
67
|
+
assert not created
|
|
68
|
+
assert existing["source"] == "org/model"
|
|
69
|
+
with pytest.raises(FileExistsError):
|
|
70
|
+
registry.reserve(record(source="other/model"))
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_local_source_stays_inside_model_root(tmp_path):
|
|
74
|
+
root = tmp_path / "models"
|
|
75
|
+
folder = root / "custom"
|
|
76
|
+
folder.mkdir(parents=True)
|
|
77
|
+
(folder / "config.yaml").write_text("MODEL: {}")
|
|
78
|
+
settings = SimpleNamespace(model_root=root)
|
|
79
|
+
|
|
80
|
+
weights, config = resolve_local_source(settings, str(folder), None)
|
|
81
|
+
assert weights == folder
|
|
82
|
+
assert config == folder / "config.yaml"
|
|
83
|
+
assert generated_local_model_id(folder).startswith("local:custom-")
|
|
84
|
+
|
|
85
|
+
outside = tmp_path / "outside"
|
|
86
|
+
outside.mkdir()
|
|
87
|
+
with pytest.raises(ValueError, match="OSL_MODEL_ROOT"):
|
|
88
|
+
resolve_local_source(settings, str(outside), None)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_custom_id_and_public_local_record_validation():
|
|
92
|
+
assert validate_local_model_id("football-model:v2") == "football-model:v2"
|
|
93
|
+
with pytest.raises(ValueError):
|
|
94
|
+
validate_local_model_id("folder/model")
|
|
95
|
+
local = record()
|
|
96
|
+
local.update({"source_type": "local", "source": "/secret/model", "config_path": "/secret/config", "error": "at /secret/model"})
|
|
97
|
+
visible = public_record(local)
|
|
98
|
+
assert "source" not in visible
|
|
99
|
+
assert "config_path" not in visible
|
|
100
|
+
assert "/secret" not in visible["error"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/examples/quickstart/basic_classification.py
RENAMED
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/examples/quickstart/basic_localization.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/vqa/default.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/vqa/qwen3_vl_native.yaml
RENAMED
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/configs/vqa/qwen_lora.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/accessors.py
RENAMED
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/conflicts.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/rule_variants.py
RENAMED
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/runtime_adapter.py
RENAMED
|
File without changes
|
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/config/schemas/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/optimizer/__init__.py
RENAMED
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/optimizer/builder.py
RENAMED
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/sampler/weighted_sampler.py
RENAMED
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/scheduler/__init__.py
RENAMED
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/scheduler/builder.py
RENAMED
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/trainer/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/trainer/vqa_trainer.py
RENAMED
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/checkpoint.py
RENAMED
|
File without changes
|
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/config_normalize.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/default_args.py
RENAMED
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/direct_video.py
RENAMED
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/hf_runtime.py
RENAMED
|
File without changes
|
|
File without changes
|
{opensportslib-0.3.1.dev6 → opensportslib-0.3.1.dev8}/opensportslib/core/utils/load_annotations.py
RENAMED
|
File without changes
|