lsst-daf-butler 29.2025.3100__tar.gz → 29.2025.3300__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.
- {lsst_daf_butler-29.2025.3100/python/lsst_daf_butler.egg-info → lsst_daf_butler-29.2025.3300}/PKG-INFO +1 -1
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_limited_butler.py +1 -6
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_storage_class.py +66 -174
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastore/record_data.py +22 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastore/stored_file_info.py +2 -4
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/_record_set.py +49 -2
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/server/_config.py +9 -1
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/server/_dependencies.py +24 -3
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/server/_server.py +4 -1
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/server/handlers/_external_query.py +3 -4
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/server/handlers/_query_limits.py +7 -5
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/server/handlers/_query_streaming.py +3 -3
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/_examplePythonTypes.py +1 -6
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/server.py +2 -2
- lsst_daf_butler-29.2025.3300/python/lsst/daf/butler/version.py +2 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300/python/lsst_daf_butler.egg-info}/PKG-INFO +1 -1
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_datasets.py +0 -13
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_dimension_record_containers.py +19 -9
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_quantumBackedButler.py +18 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_server.py +1 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_storageClass.py +4 -13
- lsst_daf_butler-29.2025.3100/python/lsst/daf/butler/version.py +0 -2
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/COPYRIGHT +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/LICENSE +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/MANIFEST.in +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/README.md +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/bsd_license.txt +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/doc/lsst.daf.butler/CHANGES.rst +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/doc/lsst.daf.butler/concreteStorageClasses.rst +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/doc/lsst.daf.butler/configuring.rst +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/doc/lsst.daf.butler/datastores.rst +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/doc/lsst.daf.butler/dimensions.rst +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/doc/lsst.daf.butler/formatters.rst +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/doc/lsst.daf.butler/index.rst +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/doc/lsst.daf.butler/organizing.rst +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/doc/lsst.daf.butler/queries.rst +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/doc/lsst.daf.butler/use-in-tests.rst +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/doc/lsst.daf.butler/writing-subcommands.rst +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/gpl-v3.0.txt +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/pyproject.toml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_butler.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_butler_collections.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_butler_config.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_butler_instance_options.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_butler_metrics.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_butler_repo_index.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_collection_type.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_column_categorization.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_column_tags.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_column_type_info.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_config.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_config_support.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_dataset_association.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_dataset_existence.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_dataset_provenance.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_dataset_ref.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_dataset_type.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_deferredDatasetHandle.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_exceptions.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_exceptions_legacy.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_file_dataset.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_file_descriptor.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_formatter.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_labeled_butler_factory.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_location.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_named.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_quantum.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_quantum_backed.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_query_all_datasets.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_registry_shim.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_storage_class_delegate.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_timespan.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_topology.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_utilities/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_utilities/locked_object.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_utilities/named_locks.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/_utilities/thread_safe_cache.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/arrow_utils.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/cli/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/cli/butler.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/cli/cliLog.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/cli/cmd/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/cli/cmd/_remove_collections.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/cli/cmd/_remove_runs.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/cli/cmd/commands.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/cli/opt/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/cli/opt/arguments.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/cli/opt/optionGroups.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/cli/opt/options.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/cli/progress.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/cli/utils.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/column_spec.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/datastore.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/datastores/composites.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/datastores/fileDatastore.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/datastores/formatters.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/datastores/writeRecipes.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/dimensions.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/old_dimensions/daf_butler_universe0.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/old_dimensions/daf_butler_universe1.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/old_dimensions/daf_butler_universe2.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/old_dimensions/daf_butler_universe3.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/old_dimensions/daf_butler_universe4.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/old_dimensions/daf_butler_universe5.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/old_dimensions/daf_butler_universe6.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/old_dimensions/daf_butler_universe7.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/registry.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/repo_transfer_formats.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/configs/storageClasses.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastore/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastore/_datastore.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastore/_transfer.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastore/cache_manager.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastore/composites.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastore/constraints.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastore/file_templates.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastore/generic_base.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastores/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastores/chainedDatastore.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastores/fileDatastore.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastores/file_datastore/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastores/file_datastore/get.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastores/file_datastore/retrieve_artifacts.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastores/file_datastore/transfer.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/datastores/inMemoryDatastore.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/ddl.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/delegates/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/delegates/arrowtable.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/_config.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/_coordinate.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/_data_coordinate_iterable.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/_database.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/_elements.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/_governor.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/_group.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/_packer.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/_record_table.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/_records.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/_schema.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/_skypix.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/_universe.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/construction.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/dimensions/record_cache.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/direct_butler/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/direct_butler/_direct_butler.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/direct_butler/_direct_butler_collections.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/direct_query_driver/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/direct_query_driver/_driver.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/direct_query_driver/_postprocessing.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/direct_query_driver/_query_analysis.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/direct_query_driver/_query_builder.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/direct_query_driver/_result_page_converter.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/direct_query_driver/_sql_builders.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/direct_query_driver/_sql_column_visitor.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/formatters/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/formatters/astropyTable.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/formatters/file.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/formatters/json.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/formatters/logs.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/formatters/matplotlib.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/formatters/packages.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/formatters/parquet.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/formatters/pickle.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/formatters/typeless.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/formatters/yaml.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/json.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/logging.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/mapping_factory.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/name_shrinker.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/nonempty_mapping.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/persistence_context.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/progress.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/py.typed +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/pydantic_utils.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/_base.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/_data_coordinate_query_results.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/_dataset_query_results.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/_dimension_record_query_results.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/_expression_strings.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/_general_query_results.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/_identifiers.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/_query.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/convert_args.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/driver.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/expression_factory.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/overlaps.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/predicate_constraints_summary.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/result_specs.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/tree/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/tree/_base.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/tree/_column_expression.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/tree/_column_literal.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/tree/_column_reference.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/tree/_column_set.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/tree/_predicate.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/tree/_query_tree.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/queries/visitors.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/_caching_context.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/_collection_record_cache.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/_collection_summary.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/_collection_summary_cache.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/_config.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/_defaults.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/_exceptions.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/_registry.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/_registry_factory.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/attributes.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/bridge/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/bridge/ephemeral.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/bridge/monolithic.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/collections/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/collections/_base.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/collections/nameKey.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/collections/synthIntKey.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/connectionString.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/databases/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/databases/postgresql.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/databases/sqlite.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/datasets/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/datasets/byDimensions/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/datasets/byDimensions/_dataset_type_cache.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/datasets/byDimensions/_manager.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/datasets/byDimensions/summaries.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/datasets/byDimensions/tables.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/dimensions/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/dimensions/static.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/interfaces/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/interfaces/_attributes.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/interfaces/_bridge.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/interfaces/_collections.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/interfaces/_database.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/interfaces/_database_explain.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/interfaces/_datasets.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/interfaces/_dimensions.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/interfaces/_obscore.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/interfaces/_opaque.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/interfaces/_versioning.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/managers.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/nameShrinker.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/obscore/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/obscore/_config.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/obscore/_manager.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/obscore/_records.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/obscore/_schema.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/obscore/_spatial.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/obscore/default_spatial.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/obscore/pgsphere.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/opaque.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/_builder.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/_query.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/_query_backend.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/_query_context.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/_readers.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/_results.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/_sql_query_backend.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/_sql_query_context.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/_structs.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/butler_sql_engine.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/expressions/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/expressions/_predicate.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/expressions/categorize.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/expressions/check.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/expressions/normalForm.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/expressions/parser/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/expressions/parser/exprTree.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/expressions/parser/parser.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/expressions/parser/parserLex.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/expressions/parser/parserYacc.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/expressions/parser/ply/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/expressions/parser/ply/lex.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/expressions/parser/ply/yacc.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/expressions/parser/treeVisitor.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/queries/find_first_dataset.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/sql_registry.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/tests/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/tests/_database.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/tests/_registry.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/versions.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/registry/wildcards.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/_collection_args.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/_config.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/_defaults.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/_errors.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/_factory.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/_get.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/_http_connection.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/_query_driver.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/_query_results.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/_ref_utils.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/_registry.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/_remote_butler.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/_remote_butler_collections.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/_remote_file_transfer_source.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/authentication/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/authentication/cadc.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/authentication/interface.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/authentication/rubin.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/registry/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/registry/_query_common.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/registry/_query_data_coordinates.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/registry/_query_datasets.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/registry/_query_dimension_records.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/server/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/server/_factory.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/server/_gafaelfawr.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/server/_telemetry.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/server/handlers/_external.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/server/handlers/_file_info.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/server/handlers/_internal.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/server/handlers/_query_serialization.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/server/handlers/_utils.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/remote_butler/server_models.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/repo_relocation.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/_associate.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/_pruneDatasets.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/butlerImport.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/certifyCalibrations.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/collectionChain.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/configDump.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/configValidate.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/createRepo.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/exportCalibs.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/ingest_files.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/ingest_zip.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/queryCollections.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/queryDataIds.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/queryDatasetTypes.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/queryDatasets.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/queryDimensionRecords.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/register_dataset_type.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/removeCollections.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/removeDatasetType.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/removeRuns.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/retrieveArtifacts.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/script/transferDatasets.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/_datasetsHelper.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/_dummyRegistry.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/_testRepo.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/butler_queries.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/cliCmdTestBase.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/cliLogTestBase.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/deferredFormatter.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/dict_convertible_model.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/hybrid_butler.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/hybrid_butler_collections.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/hybrid_butler_registry.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/postgresql.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/registry_data/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/registry_data/base.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/registry_data/ci_hsc-subset-skymap.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/registry_data/ci_hsc-subset.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/registry_data/datasets.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/registry_data/hsc-rc2-subset-v0.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/registry_data/spatial.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/registry_data/spatial.yaml +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/server_utils.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/testFormatters.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/tests/utils.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/time_utils.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/timespan_database_representation.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/transfers/__init__.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/transfers/_context.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/transfers/_interfaces.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/transfers/_yaml.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst/daf/butler/utils.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst_daf_butler.egg-info/SOURCES.txt +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst_daf_butler.egg-info/dependency_links.txt +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst_daf_butler.egg-info/entry_points.txt +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst_daf_butler.egg-info/requires.txt +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst_daf_butler.egg-info/top_level.txt +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/python/lsst_daf_butler.egg-info/zip-safe +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/setup.cfg +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_astropyTableFormatter.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_authentication.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_butler.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_butler_factory.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliCmdAssociate.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliCmdConfigDump.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliCmdConfigValidate.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliCmdCreate.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliCmdImport.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliCmdIngestFiles.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliCmdPruneDatasets.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliCmdQueryCollections.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliCmdQueryDataIds.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliCmdQueryDatasetTypes.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliCmdQueryDatasets.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliCmdQueryDimensionRecords.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliCmdRemoveCollections.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliCmdRemoveRuns.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliCmdRetrieveArtifacts.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliLog.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliPluginLoader.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliUtilSplitCommas.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliUtilSplitKv.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliUtilToUpper.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_cliUtils.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_column_spec.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_composites.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_config.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_connectionString.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_constraints.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_datastore.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_ddl.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_dimensions.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_exprParserLex.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_exprParserYacc.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_expressions.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_formatter.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_gafaelfawr.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_location.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_logFormatter.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_logging.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_matplotlibFormatter.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_nonempty_mapping.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_normalFormExpression.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_obscore.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_packages.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_parquet.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_postgresql.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_progress.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_pydantic_utils.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_quantum.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_query_direct_postgresql.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_query_direct_sqlite.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_query_interface.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_query_relations.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_query_remote.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_query_utilities.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_remote_butler.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_simpleButler.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_sqlite.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_templates.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_testRepo.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_thread_utils.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_time_utils.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_timespan.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_utils.py +0 -0
- {lsst_daf_butler-29.2025.3100 → lsst_daf_butler-29.2025.3300}/tests/test_versioning.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lsst-daf-butler
|
|
3
|
-
Version: 29.2025.
|
|
3
|
+
Version: 29.2025.3300
|
|
4
4
|
Summary: An abstraction layer for reading and writing astronomical data to datastores.
|
|
5
5
|
Author-email: Rubin Observatory Data Management <dm-admin@lists.lsst.org>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -129,11 +129,6 @@ class LimitedButler(ABC):
|
|
|
129
129
|
obj : `object`
|
|
130
130
|
The dataset.
|
|
131
131
|
|
|
132
|
-
Raises
|
|
133
|
-
------
|
|
134
|
-
AmbiguousDatasetError
|
|
135
|
-
Raised if the supplied `DatasetRef` is unresolved.
|
|
136
|
-
|
|
137
132
|
Notes
|
|
138
133
|
-----
|
|
139
134
|
In a `LimitedButler` the only allowable way to specify a dataset is
|
|
@@ -326,7 +321,7 @@ class LimitedButler(ABC):
|
|
|
326
321
|
Whether the dataset artifact exists in the datastore and can be
|
|
327
322
|
retrieved.
|
|
328
323
|
"""
|
|
329
|
-
return self.
|
|
324
|
+
return self.stored_many([ref])[ref]
|
|
330
325
|
|
|
331
326
|
def stored_many(
|
|
332
327
|
self,
|
|
@@ -39,6 +39,8 @@ from collections.abc import Callable, Collection, Mapping, Sequence, Set
|
|
|
39
39
|
from threading import RLock
|
|
40
40
|
from typing import Any
|
|
41
41
|
|
|
42
|
+
import pydantic
|
|
43
|
+
|
|
42
44
|
from lsst.utils import doImportType
|
|
43
45
|
from lsst.utils.classes import Singleton
|
|
44
46
|
from lsst.utils.introspection import get_full_type_name
|
|
@@ -57,6 +59,18 @@ class StorageClassConfig(ConfigSubset):
|
|
|
57
59
|
defaultConfigFile = "storageClasses.yaml"
|
|
58
60
|
|
|
59
61
|
|
|
62
|
+
class _StorageClassModel(pydantic.BaseModel):
|
|
63
|
+
"""Model class used to validate storage class configuration."""
|
|
64
|
+
|
|
65
|
+
pytype: str | None = None
|
|
66
|
+
inheritsFrom: str | None = None
|
|
67
|
+
components: dict[str, str] = pydantic.Field(default_factory=dict)
|
|
68
|
+
derivedComponents: dict[str, str] = pydantic.Field(default_factory=dict)
|
|
69
|
+
parameters: list[str] = pydantic.Field(default_factory=list)
|
|
70
|
+
delegate: str | None = None
|
|
71
|
+
converters: dict[str, str] = pydantic.Field(default_factory=dict)
|
|
72
|
+
|
|
73
|
+
|
|
60
74
|
class StorageClass:
|
|
61
75
|
"""Class describing how a label maps to a particular Python type.
|
|
62
76
|
|
|
@@ -81,17 +95,9 @@ class StorageClass:
|
|
|
81
95
|
that python type to the valid type of this storage class.
|
|
82
96
|
"""
|
|
83
97
|
|
|
84
|
-
_cls_name: str = "BaseStorageClass"
|
|
85
|
-
_cls_components: dict[str, StorageClass] | None = None
|
|
86
|
-
_cls_derivedComponents: dict[str, StorageClass] | None = None
|
|
87
|
-
_cls_parameters: Set[str] | Sequence[str] | None = None
|
|
88
|
-
_cls_delegate: str | None = None
|
|
89
|
-
_cls_pytype: type | str | None = None
|
|
90
|
-
_cls_converters: dict[str, str] | None = None
|
|
91
|
-
|
|
92
98
|
def __init__(
|
|
93
99
|
self,
|
|
94
|
-
name: str
|
|
100
|
+
name: str = "",
|
|
95
101
|
pytype: type | str | None = None,
|
|
96
102
|
components: dict[str, StorageClass] | None = None,
|
|
97
103
|
derivedComponents: dict[str, StorageClass] | None = None,
|
|
@@ -99,23 +105,8 @@ class StorageClass:
|
|
|
99
105
|
delegate: str | None = None,
|
|
100
106
|
converters: dict[str, str] | None = None,
|
|
101
107
|
):
|
|
102
|
-
if name is None:
|
|
103
|
-
name = self._cls_name
|
|
104
|
-
if pytype is None:
|
|
105
|
-
pytype = self._cls_pytype
|
|
106
|
-
if components is None:
|
|
107
|
-
components = self._cls_components
|
|
108
|
-
if derivedComponents is None:
|
|
109
|
-
derivedComponents = self._cls_derivedComponents
|
|
110
|
-
if parameters is None:
|
|
111
|
-
parameters = self._cls_parameters
|
|
112
|
-
if delegate is None:
|
|
113
|
-
delegate = self._cls_delegate
|
|
114
|
-
|
|
115
108
|
# Merge converters with class defaults.
|
|
116
109
|
self._converters = {}
|
|
117
|
-
if self._cls_converters is not None:
|
|
118
|
-
self._converters.update(self._cls_converters)
|
|
119
110
|
if converters:
|
|
120
111
|
self._converters.update(converters)
|
|
121
112
|
|
|
@@ -634,7 +625,6 @@ class StorageClassFactory(metaclass=Singleton):
|
|
|
634
625
|
|
|
635
626
|
def __init__(self, config: StorageClassConfig | str | None = None):
|
|
636
627
|
self._storageClasses: dict[str, StorageClass] = {}
|
|
637
|
-
self._configs: list[StorageClassConfig] = []
|
|
638
628
|
self._lock = RLock()
|
|
639
629
|
|
|
640
630
|
# Always seed with the default config
|
|
@@ -657,40 +647,15 @@ class StorageClassFactory(metaclass=Singleton):
|
|
|
657
647
|
|
|
658
648
|
StorageClasses
|
|
659
649
|
--------------
|
|
660
|
-
{sep.join(f"{
|
|
650
|
+
{sep.join(f"{self._storageClasses[s]!r}" for s in sorted(self._storageClasses))}
|
|
661
651
|
"""
|
|
662
652
|
|
|
663
|
-
def __contains__(self, storageClassOrName:
|
|
664
|
-
"""Indicate whether the storage class exists in the factory.
|
|
665
|
-
|
|
666
|
-
Parameters
|
|
667
|
-
----------
|
|
668
|
-
storageClassOrName : `str` or `StorageClass`
|
|
669
|
-
If `str` is given existence of the named StorageClass
|
|
670
|
-
in the factory is checked. If `StorageClass` is given
|
|
671
|
-
existence and equality are checked.
|
|
672
|
-
|
|
673
|
-
Returns
|
|
674
|
-
-------
|
|
675
|
-
in : `bool`
|
|
676
|
-
True if the supplied string is present, or if the supplied
|
|
677
|
-
`StorageClass` is present and identical.
|
|
678
|
-
|
|
679
|
-
Notes
|
|
680
|
-
-----
|
|
681
|
-
The two different checks (one for "key" and one for "value") based on
|
|
682
|
-
the type of the given argument mean that it is possible for
|
|
683
|
-
StorageClass.name to be in the factory but StorageClass to not be
|
|
684
|
-
in the factory.
|
|
685
|
-
"""
|
|
653
|
+
def __contains__(self, storageClassOrName: object) -> bool:
|
|
686
654
|
with self._lock:
|
|
687
655
|
if isinstance(storageClassOrName, str):
|
|
688
656
|
return storageClassOrName in self._storageClasses
|
|
689
|
-
elif (
|
|
690
|
-
|
|
691
|
-
and storageClassOrName.name in self._storageClasses
|
|
692
|
-
):
|
|
693
|
-
return storageClassOrName == self._storageClasses[storageClassOrName.name]
|
|
657
|
+
elif isinstance(storageClassOrName, StorageClass):
|
|
658
|
+
return storageClassOrName.name in self._storageClasses
|
|
694
659
|
return False
|
|
695
660
|
|
|
696
661
|
def addFromConfig(self, config: StorageClassConfig | Config | str) -> None:
|
|
@@ -708,68 +673,54 @@ StorageClasses
|
|
|
708
673
|
# components or parents before their classes are defined
|
|
709
674
|
# we have a helper function that we can call recursively
|
|
710
675
|
# to extract definitions from the configuration.
|
|
711
|
-
def processStorageClass(name: str, _sconfig: StorageClassConfig, msg: str = "") ->
|
|
712
|
-
#
|
|
676
|
+
def processStorageClass(name: str, _sconfig: StorageClassConfig, msg: str = "") -> StorageClass:
|
|
677
|
+
# This might have already been processed through recursion, or
|
|
678
|
+
# already present in the factory.
|
|
713
679
|
if name not in _sconfig:
|
|
714
|
-
return
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
if
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
baseName,
|
|
759
|
-
)
|
|
760
|
-
processStorageClass(baseName, sconfig, msg)
|
|
761
|
-
else:
|
|
762
|
-
processStorageClass(baseName, sconfig, msg)
|
|
763
|
-
baseClass = type(self.getStorageClass(baseName))
|
|
764
|
-
if baseClass is StorageClass:
|
|
765
|
-
raise TypeError(
|
|
766
|
-
f"Configuration for storage class {name} requests to inherit from "
|
|
767
|
-
f" storage class {baseName} but that class is not defined correctly."
|
|
768
|
-
)
|
|
769
|
-
|
|
770
|
-
newStorageClassType = self.makeNewStorageClass(name, baseClass, **storageClassKwargs)
|
|
771
|
-
newStorageClass = newStorageClassType()
|
|
772
|
-
self.registerStorageClass(newStorageClass, msg=msg)
|
|
680
|
+
return self.getStorageClass(name)
|
|
681
|
+
try:
|
|
682
|
+
model = _StorageClassModel.model_validate(_sconfig.pop(name))
|
|
683
|
+
except Exception as err:
|
|
684
|
+
err.add_note(msg)
|
|
685
|
+
raise
|
|
686
|
+
components: dict[str, StorageClass] = {}
|
|
687
|
+
derivedComponents: dict[str, StorageClass] = {}
|
|
688
|
+
parameters: set[str] = set()
|
|
689
|
+
delegate: str | None = None
|
|
690
|
+
converters: dict[str, str] = {}
|
|
691
|
+
if model.inheritsFrom is not None:
|
|
692
|
+
base = processStorageClass(model.inheritsFrom, _sconfig, msg + f"; processing base of {name}")
|
|
693
|
+
pytype = base._pytypeName
|
|
694
|
+
components.update(base.components)
|
|
695
|
+
derivedComponents.update(base.derivedComponents)
|
|
696
|
+
parameters.update(base.parameters)
|
|
697
|
+
delegate = base._delegateClassName
|
|
698
|
+
converters.update(base.converters)
|
|
699
|
+
if model.pytype is not None:
|
|
700
|
+
pytype = model.pytype
|
|
701
|
+
for k, v in model.components.items():
|
|
702
|
+
components[k] = processStorageClass(
|
|
703
|
+
v, _sconfig, msg + f"; processing component {k} of {name}"
|
|
704
|
+
)
|
|
705
|
+
for k, v in model.derivedComponents.items():
|
|
706
|
+
derivedComponents[k] = processStorageClass(
|
|
707
|
+
v, _sconfig, msg + f"; processing derivedCmponent {k} of {name}"
|
|
708
|
+
)
|
|
709
|
+
parameters.update(model.parameters)
|
|
710
|
+
if model.delegate is not None:
|
|
711
|
+
delegate = model.delegate
|
|
712
|
+
converters.update(model.converters)
|
|
713
|
+
result = StorageClass(
|
|
714
|
+
name=name,
|
|
715
|
+
pytype=pytype,
|
|
716
|
+
components=components,
|
|
717
|
+
derivedComponents=derivedComponents,
|
|
718
|
+
parameters=parameters,
|
|
719
|
+
delegate=delegate,
|
|
720
|
+
converters=converters,
|
|
721
|
+
)
|
|
722
|
+
self.registerStorageClass(result, msg=msg)
|
|
723
|
+
return result
|
|
773
724
|
|
|
774
725
|
# In case there is a problem, construct a context message for any
|
|
775
726
|
# error reporting.
|
|
@@ -778,68 +729,9 @@ StorageClasses
|
|
|
778
729
|
log.debug("Adding definitions from config %s", ", ".join(files))
|
|
779
730
|
|
|
780
731
|
with self._lock:
|
|
781
|
-
self._configs.append(sconfig)
|
|
782
732
|
for name in list(sconfig.keys()):
|
|
783
733
|
processStorageClass(name, sconfig, context)
|
|
784
734
|
|
|
785
|
-
@staticmethod
|
|
786
|
-
def makeNewStorageClass(
|
|
787
|
-
name: str, baseClass: type[StorageClass] | None = StorageClass, **kwargs: Any
|
|
788
|
-
) -> type[StorageClass]:
|
|
789
|
-
"""Create a new Python class as a subclass of `StorageClass`.
|
|
790
|
-
|
|
791
|
-
Parameters
|
|
792
|
-
----------
|
|
793
|
-
name : `str`
|
|
794
|
-
Name to use for this class.
|
|
795
|
-
baseClass : `type`, optional
|
|
796
|
-
Base class for this `StorageClass`. Must be either `StorageClass`
|
|
797
|
-
or a subclass of `StorageClass`. If `None`, `StorageClass` will
|
|
798
|
-
be used.
|
|
799
|
-
**kwargs
|
|
800
|
-
Additional parameter values to use as defaults for this class.
|
|
801
|
-
This can include ``components``, ``parameters``,
|
|
802
|
-
``derivedComponents``, and ``converters``.
|
|
803
|
-
|
|
804
|
-
Returns
|
|
805
|
-
-------
|
|
806
|
-
newtype : `type` subclass of `StorageClass`
|
|
807
|
-
Newly created Python type.
|
|
808
|
-
"""
|
|
809
|
-
if baseClass is None:
|
|
810
|
-
baseClass = StorageClass
|
|
811
|
-
if not issubclass(baseClass, StorageClass):
|
|
812
|
-
raise ValueError(f"Base class must be a StorageClass not {baseClass}")
|
|
813
|
-
|
|
814
|
-
# convert the arguments to use different internal names
|
|
815
|
-
clsargs = {f"_cls_{k}": v for k, v in kwargs.items() if v is not None}
|
|
816
|
-
clsargs["_cls_name"] = name
|
|
817
|
-
|
|
818
|
-
# Some container items need to merge with the base class values
|
|
819
|
-
# so that a child can inherit but override one bit.
|
|
820
|
-
# lists (which you get from configs) are treated as sets for this to
|
|
821
|
-
# work consistently.
|
|
822
|
-
for k in ("components", "parameters", "derivedComponents", "converters"):
|
|
823
|
-
classKey = f"_cls_{k}"
|
|
824
|
-
if classKey in clsargs:
|
|
825
|
-
baseValue = getattr(baseClass, classKey, None)
|
|
826
|
-
if baseValue is not None:
|
|
827
|
-
currentValue = clsargs[classKey]
|
|
828
|
-
if isinstance(currentValue, dict):
|
|
829
|
-
newValue = baseValue.copy()
|
|
830
|
-
else:
|
|
831
|
-
newValue = set(baseValue)
|
|
832
|
-
newValue.update(currentValue)
|
|
833
|
-
clsargs[classKey] = newValue
|
|
834
|
-
|
|
835
|
-
# If we have parameters they should be a frozen set so that the
|
|
836
|
-
# parameters in the class can not be modified.
|
|
837
|
-
pk = "_cls_parameters"
|
|
838
|
-
if pk in clsargs:
|
|
839
|
-
clsargs[pk] = frozenset(clsargs[pk])
|
|
840
|
-
|
|
841
|
-
return type(f"StorageClass{name}", (baseClass,), clsargs)
|
|
842
|
-
|
|
843
735
|
def getStorageClass(self, storageClassName: str) -> StorageClass:
|
|
844
736
|
"""Get a StorageClass instance associated with the supplied name.
|
|
845
737
|
|
|
@@ -111,6 +111,28 @@ class DatastoreRecordData:
|
|
|
111
111
|
"""Opaque table data, indexed by dataset ID and grouped by opaque table
|
|
112
112
|
name."""
|
|
113
113
|
|
|
114
|
+
@staticmethod
|
|
115
|
+
def merge_mappings(*args: Mapping[str, DatastoreRecordData]) -> dict[str, DatastoreRecordData]:
|
|
116
|
+
"""Merge mappings of datastore record data.
|
|
117
|
+
|
|
118
|
+
Parameters
|
|
119
|
+
----------
|
|
120
|
+
*args : `~collections.abc.Mapping` [ `str`, `DatastoreRecordData` ]
|
|
121
|
+
Mappings of record data, keyed by datastore name.
|
|
122
|
+
|
|
123
|
+
Returns
|
|
124
|
+
-------
|
|
125
|
+
merged : `~collections.abc.Mapping` [ `str`, `DatastoreRecordData` ]
|
|
126
|
+
Merged mapping of record data, keyed by datastore name.
|
|
127
|
+
"""
|
|
128
|
+
result: dict[str, DatastoreRecordData] = {}
|
|
129
|
+
for arg in args:
|
|
130
|
+
for datastore_name, record_data in arg.items():
|
|
131
|
+
if datastore_name not in result:
|
|
132
|
+
result[datastore_name] = DatastoreRecordData()
|
|
133
|
+
result[datastore_name].update(record_data)
|
|
134
|
+
return result
|
|
135
|
+
|
|
114
136
|
def update(self, other: DatastoreRecordData) -> None:
|
|
115
137
|
"""Update contents of this instance with data from another instance.
|
|
116
138
|
|
|
@@ -32,7 +32,7 @@ __all__ = ("SerializedStoredFileInfo", "StoredDatastoreItemInfo", "StoredFileInf
|
|
|
32
32
|
import inspect
|
|
33
33
|
from collections.abc import Iterable, Mapping
|
|
34
34
|
from dataclasses import dataclass
|
|
35
|
-
from typing import TYPE_CHECKING, Any
|
|
35
|
+
from typing import TYPE_CHECKING, Any
|
|
36
36
|
|
|
37
37
|
import pydantic
|
|
38
38
|
|
|
@@ -209,8 +209,6 @@ class StoredFileInfo(StoredDatastoreItemInfo):
|
|
|
209
209
|
compatibility, it remains a positional argument with no default).
|
|
210
210
|
"""
|
|
211
211
|
|
|
212
|
-
storageClassFactory: ClassVar[StorageClassFactory] = StorageClassFactory()
|
|
213
|
-
|
|
214
212
|
def __init__(
|
|
215
213
|
self,
|
|
216
214
|
formatter: FormatterParameter,
|
|
@@ -268,7 +266,7 @@ class StoredFileInfo(StoredDatastoreItemInfo):
|
|
|
268
266
|
@property
|
|
269
267
|
def storageClass(self) -> StorageClass:
|
|
270
268
|
"""Storage class associated with this dataset."""
|
|
271
|
-
return
|
|
269
|
+
return StorageClassFactory().getStorageClass(self.storage_class_name)
|
|
272
270
|
|
|
273
271
|
def rebase(self, ref: DatasetRef) -> StoredFileInfo:
|
|
274
272
|
"""Return a copy of the record suitable for a specified reference.
|
|
@@ -753,7 +753,6 @@ class SerializableDimensionData(pydantic.RootModel):
|
|
|
753
753
|
]
|
|
754
754
|
|
|
755
755
|
|
|
756
|
-
@dataclasses.dataclass
|
|
757
756
|
class DimensionDataAttacher:
|
|
758
757
|
"""A helper class for attaching dimension records to data IDs.
|
|
759
758
|
|
|
@@ -786,7 +785,7 @@ class DimensionDataAttacher:
|
|
|
786
785
|
dimensions: DimensionGroup | None = None,
|
|
787
786
|
):
|
|
788
787
|
self.records = {record_set.element.name: record_set for record_set in records}
|
|
789
|
-
self.deserializers = {}
|
|
788
|
+
self.deserializers: dict[str, DimensionRecordSetDeserializer] = {}
|
|
790
789
|
for deserializer in deserializers:
|
|
791
790
|
self.deserializers[deserializer.element.name] = deserializer
|
|
792
791
|
if deserializer.element.name not in self.records:
|
|
@@ -851,6 +850,54 @@ class DimensionDataAttacher:
|
|
|
851
850
|
|
|
852
851
|
return [r.data_id.expanded(r.done) for r in records]
|
|
853
852
|
|
|
853
|
+
def serialized(
|
|
854
|
+
self, *, ignore: Iterable[str] = (), ignore_cached: bool = False, include_skypix: bool = False
|
|
855
|
+
) -> SerializableDimensionData:
|
|
856
|
+
"""Serialize all dimension data in this attacher, with deduplication
|
|
857
|
+
across fully- and partially-deserialized records.
|
|
858
|
+
|
|
859
|
+
Parameters
|
|
860
|
+
----------
|
|
861
|
+
ignore : `~collections.abc.Iterable` [ `str` ], optional
|
|
862
|
+
Names of dimension elements that should not be serialized.
|
|
863
|
+
ignore_cached : `bool`, optional
|
|
864
|
+
If `True`, ignore all dimension elements for which
|
|
865
|
+
`DimensionElement.is_cached` is `True`.
|
|
866
|
+
include_skypix : `bool`, optional
|
|
867
|
+
If `True`, include skypix dimensions. These are ignored by default
|
|
868
|
+
because they can always be recomputed from their IDs on-the-fly.
|
|
869
|
+
|
|
870
|
+
Returns
|
|
871
|
+
-------
|
|
872
|
+
serialized : `SerializedDimensionData`
|
|
873
|
+
Serialized dimension records.
|
|
874
|
+
"""
|
|
875
|
+
from ._skypix import SkyPixDimension
|
|
876
|
+
|
|
877
|
+
ignore = set(ignore)
|
|
878
|
+
result = SerializableDimensionData()
|
|
879
|
+
for record_set in self.records.values():
|
|
880
|
+
if record_set.element.name in ignore:
|
|
881
|
+
continue
|
|
882
|
+
if not include_skypix and isinstance(record_set.element, SkyPixDimension):
|
|
883
|
+
continue
|
|
884
|
+
if ignore_cached and record_set.element.is_cached:
|
|
885
|
+
continue
|
|
886
|
+
serialized_records: dict[tuple[DataIdValue, ...], SerializedKeyValueDimensionRecord] = {}
|
|
887
|
+
if (deserializer := self.deserializers.get(record_set.element.name)) is not None:
|
|
888
|
+
for key, value in deserializer._mapping.items():
|
|
889
|
+
serialized_record = list(key)
|
|
890
|
+
serialized_record.extend(value)
|
|
891
|
+
serialized_records[key] = serialized_record
|
|
892
|
+
for key, record in record_set._by_required_values.items():
|
|
893
|
+
if key not in serialized_records:
|
|
894
|
+
serialized_records[key] = record.serialize_key_value()
|
|
895
|
+
result.root[record_set.element.name] = list(serialized_records.values())
|
|
896
|
+
if self.cache is not None and not ignore_cached:
|
|
897
|
+
for record_set in self.cache.values():
|
|
898
|
+
result.root[record_set.element.name] = record_set.serialize_records()
|
|
899
|
+
return result
|
|
900
|
+
|
|
854
901
|
|
|
855
902
|
@dataclasses.dataclass
|
|
856
903
|
class _InProgressRecordDicts:
|
|
@@ -30,6 +30,7 @@ from __future__ import annotations
|
|
|
30
30
|
from collections.abc import Iterator
|
|
31
31
|
from contextlib import contextmanager
|
|
32
32
|
from functools import cache
|
|
33
|
+
from typing import Literal
|
|
33
34
|
|
|
34
35
|
from pydantic import AnyHttpUrl, BaseModel
|
|
35
36
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
@@ -57,9 +58,12 @@ class ButlerServerConfig(BaseSettings):
|
|
|
57
58
|
repositories: dict[str, RepositoryConfig]
|
|
58
59
|
"""Mapping from repository name to configuration for the repository."""
|
|
59
60
|
|
|
60
|
-
gafaelfawr_url: AnyHttpUrl
|
|
61
|
+
gafaelfawr_url: AnyHttpUrl | Literal["DISABLED"]
|
|
61
62
|
"""URL to the top-level HTTP path where Gafaelfawr can be found (e.g.
|
|
62
63
|
"https://data-int.lsst.cloud").
|
|
64
|
+
|
|
65
|
+
This can instead be the special string "DISABLED" to turn off all features
|
|
66
|
+
requiring Gafaelfawr integration.
|
|
63
67
|
"""
|
|
64
68
|
|
|
65
69
|
authentication: AuthenticationMode
|
|
@@ -69,6 +73,10 @@ class ButlerServerConfig(BaseSettings):
|
|
|
69
73
|
as static files from the `configs/` HTTP route.
|
|
70
74
|
"""
|
|
71
75
|
|
|
76
|
+
@property
|
|
77
|
+
def gafaelfawr_enabled(self) -> bool:
|
|
78
|
+
return self.gafaelfawr_url != "DISABLED"
|
|
79
|
+
|
|
72
80
|
|
|
73
81
|
_config: ButlerServerConfig | None = None
|
|
74
82
|
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
|
|
28
28
|
from typing import Annotated
|
|
29
29
|
|
|
30
|
-
from fastapi import Depends, HTTPException
|
|
31
|
-
from safir.dependencies.gafaelfawr import auth_delegated_token_dependency
|
|
30
|
+
from fastapi import Depends, Header, HTTPException
|
|
31
|
+
from safir.dependencies.gafaelfawr import auth_delegated_token_dependency
|
|
32
32
|
|
|
33
33
|
from lsst.daf.butler import LabeledButlerFactory
|
|
34
34
|
|
|
@@ -65,9 +65,29 @@ async def authorizer_dependency() -> GafaelfawrGroupAuthorizer:
|
|
|
65
65
|
return _authorizer
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
async def user_name_dependency(x_auth_request_user: Annotated[str | None, Header()] = None) -> str | None:
|
|
69
|
+
"""Retrieve the user name from Gafaelfawr authentication headers.
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
x_auth_request_user : FastAPI header
|
|
74
|
+
Header provided by FastAPI.
|
|
75
|
+
|
|
76
|
+
Returns
|
|
77
|
+
-------
|
|
78
|
+
user_name : `str` | `None`
|
|
79
|
+
The user name, if Gafaelfawr is available on this environment. `None`
|
|
80
|
+
if Gafaelfawr is not available.
|
|
81
|
+
"""
|
|
82
|
+
if x_auth_request_user is None and load_config().gafaelfawr_enabled:
|
|
83
|
+
raise HTTPException(status_code=403, detail="Required X-Auth-Request-User header was not provided")
|
|
84
|
+
|
|
85
|
+
return x_auth_request_user
|
|
86
|
+
|
|
87
|
+
|
|
68
88
|
async def repository_authorization_dependency(
|
|
69
89
|
repository: str,
|
|
70
|
-
user_name: Annotated[str, Depends(
|
|
90
|
+
user_name: Annotated[str | None, Depends(user_name_dependency)],
|
|
71
91
|
user_token: Annotated[str, Depends(auth_delegated_token_dependency)],
|
|
72
92
|
authorizer: Annotated[GafaelfawrGroupAuthorizer, Depends(authorizer_dependency)],
|
|
73
93
|
) -> None:
|
|
@@ -87,6 +107,7 @@ async def repository_authorization_dependency(
|
|
|
87
107
|
authorizer : `GafaelfawrGroupAuthorizer`
|
|
88
108
|
Authorization client that will be used to verify group membership.
|
|
89
109
|
"""
|
|
110
|
+
assert user_name is not None, "Gafaelfawr user name header should have been populated."
|
|
90
111
|
if not await authorizer.is_user_authorized_for_repository(
|
|
91
112
|
repository=repository, user_name=user_name, user_token=user_token
|
|
92
113
|
):
|
|
@@ -62,13 +62,16 @@ def create_app() -> FastAPI:
|
|
|
62
62
|
# factory_dependency().
|
|
63
63
|
default_api_path = "/api/butler"
|
|
64
64
|
prefix = f"{default_api_path}/repo/{{repository}}"
|
|
65
|
+
auth_dependencies = [Depends(repository_authorization_dependency)]
|
|
66
|
+
if not config.gafaelfawr_enabled:
|
|
67
|
+
auth_dependencies = []
|
|
65
68
|
for router in (external_router, query_router):
|
|
66
69
|
app.include_router(
|
|
67
70
|
router,
|
|
68
71
|
prefix=prefix,
|
|
69
72
|
# Verify that users have permission to access repository-specific
|
|
70
73
|
# resources.
|
|
71
|
-
dependencies=
|
|
74
|
+
dependencies=auth_dependencies,
|
|
72
75
|
# document that 422 responses will include a JSON-formatted error
|
|
73
76
|
# message, from `butler_exception_handler()` below.
|
|
74
77
|
responses={422: {"model": ErrorResponseModel}},
|
|
@@ -35,7 +35,6 @@ from typing import Annotated, NamedTuple
|
|
|
35
35
|
|
|
36
36
|
from fastapi import APIRouter, Depends
|
|
37
37
|
from fastapi.responses import StreamingResponse
|
|
38
|
-
from safir.dependencies.gafaelfawr import auth_dependency
|
|
39
38
|
|
|
40
39
|
from lsst.daf.butler import Butler, DataCoordinate, DimensionGroup
|
|
41
40
|
from lsst.daf.butler.remote_butler.server_models import (
|
|
@@ -56,7 +55,7 @@ from ...._exceptions import InvalidQueryError
|
|
|
56
55
|
from ...._query_all_datasets import QueryAllDatasetsParameters, query_all_datasets
|
|
57
56
|
from ....queries import Query
|
|
58
57
|
from ....queries.driver import QueryDriver, QueryTree
|
|
59
|
-
from .._dependencies import factory_dependency
|
|
58
|
+
from .._dependencies import factory_dependency, user_name_dependency
|
|
60
59
|
from .._factory import Factory
|
|
61
60
|
from ._query_serialization import convert_query_page
|
|
62
61
|
from ._query_streaming import StreamingQuery, execute_streaming_query
|
|
@@ -93,7 +92,7 @@ class _StreamQueryDriverExecute(StreamingQuery[_QueryContext]):
|
|
|
93
92
|
async def query_execute(
|
|
94
93
|
request: QueryExecuteRequestModel,
|
|
95
94
|
factory: Annotated[Factory, Depends(factory_dependency)],
|
|
96
|
-
user_name: Annotated[str, Depends(
|
|
95
|
+
user_name: Annotated[str | None, Depends(user_name_dependency)],
|
|
97
96
|
) -> StreamingResponse:
|
|
98
97
|
query = _StreamQueryDriverExecute(request, factory)
|
|
99
98
|
return await execute_streaming_query(query, user_name)
|
|
@@ -140,7 +139,7 @@ class _StreamQueryAllDatasets(StreamingQuery[_QueryAllDatasetsContext]):
|
|
|
140
139
|
async def query_all_datasets_execute(
|
|
141
140
|
request: QueryAllDatasetsRequestModel,
|
|
142
141
|
factory: Annotated[Factory, Depends(factory_dependency)],
|
|
143
|
-
user_name: Annotated[str, Depends(
|
|
142
|
+
user_name: Annotated[str | None, Depends(user_name_dependency)],
|
|
144
143
|
) -> StreamingResponse:
|
|
145
144
|
query = _StreamQueryAllDatasets(request, factory)
|
|
146
145
|
return await execute_streaming_query(query, user_name)
|
|
@@ -56,7 +56,7 @@ class QueryLimits:
|
|
|
56
56
|
self._active_queries = 0
|
|
57
57
|
self._active_users: Counter[str] = Counter()
|
|
58
58
|
|
|
59
|
-
async def enforce_query_limits(self, user: str) -> None:
|
|
59
|
+
async def enforce_query_limits(self, user: str | None) -> None:
|
|
60
60
|
if self._active_queries >= _MAXIMUM_CONCURRENT_STREAMING_QUERIES:
|
|
61
61
|
await _block_retry_for_unit_test()
|
|
62
62
|
raise HTTPException(
|
|
@@ -70,7 +70,7 @@ class QueryLimits:
|
|
|
70
70
|
# replica, which is a non-deterministic but small number.
|
|
71
71
|
# There will be some backpressure from the 429 responses as they
|
|
72
72
|
# attempt to bounce to other replicas on retry.
|
|
73
|
-
if self._active_users[user] >= 2:
|
|
73
|
+
if user is not None and self._active_users[user] >= 2:
|
|
74
74
|
_LOG.warning(f"User '{user}' is running many queries simultaneously.")
|
|
75
75
|
raise HTTPException(
|
|
76
76
|
status_code=429, # too many requests
|
|
@@ -80,14 +80,16 @@ class QueryLimits:
|
|
|
80
80
|
)
|
|
81
81
|
|
|
82
82
|
@asynccontextmanager
|
|
83
|
-
async def track_query(self, user: str) -> AsyncIterator[None]:
|
|
83
|
+
async def track_query(self, user: str | None) -> AsyncIterator[None]:
|
|
84
84
|
try:
|
|
85
85
|
self._active_queries += 1
|
|
86
|
-
|
|
86
|
+
if user is not None:
|
|
87
|
+
self._active_users[user] += 1
|
|
87
88
|
await _block_query_for_unit_test()
|
|
88
89
|
yield
|
|
89
90
|
finally:
|
|
90
|
-
|
|
91
|
+
if user is not None:
|
|
92
|
+
self._active_users[user] -= 1
|
|
91
93
|
self._active_queries -= 1
|
|
92
94
|
|
|
93
95
|
|
|
@@ -73,7 +73,7 @@ class StreamingQuery(Protocol[_TContext]):
|
|
|
73
73
|
"""
|
|
74
74
|
|
|
75
75
|
|
|
76
|
-
async def execute_streaming_query(query: StreamingQuery, user: str) -> StreamingResponse:
|
|
76
|
+
async def execute_streaming_query(query: StreamingQuery, user: str | None) -> StreamingResponse:
|
|
77
77
|
"""Run a query, streaming the response incrementally, one page at a time,
|
|
78
78
|
as newline-separated chunks of JSON.
|
|
79
79
|
|
|
@@ -83,7 +83,7 @@ async def execute_streaming_query(query: StreamingQuery, user: str) -> Streaming
|
|
|
83
83
|
Callers should define a class implementing the ``StreamingQuery``
|
|
84
84
|
protocol to specify the inner logic that will be called during
|
|
85
85
|
query execution.
|
|
86
|
-
user : `str
|
|
86
|
+
user : `str`, optional
|
|
87
87
|
Name of user running the query -- used to enforce usage limits.
|
|
88
88
|
|
|
89
89
|
Returns
|
|
@@ -125,7 +125,7 @@ async def execute_streaming_query(query: StreamingQuery, user: str) -> Streaming
|
|
|
125
125
|
)
|
|
126
126
|
|
|
127
127
|
|
|
128
|
-
async def _stream_query_pages(query: StreamingQuery, user: str) -> AsyncIterator[str]:
|
|
128
|
+
async def _stream_query_pages(query: StreamingQuery, user: str | None) -> AsyncIterator[str]:
|
|
129
129
|
"""Stream the query output with one page object per line, as
|
|
130
130
|
newline-delimited JSON records in the "JSON Lines" format
|
|
131
131
|
(https://jsonlines.org/).
|