From f4bac7152d7905abd84160ab7d44e2e4e86e1e01 Mon Sep 17 00:00:00 2001 From: "David H. Irving" Date: Wed, 16 Oct 2024 14:20:26 -0700 Subject: [PATCH] Allow numpy integers to be used as literals Fix an issue where the new query system was rejecting numpy integers used in data IDs or bind values. --- doc/changes/DM-46711.bugfix.md | 1 + .../butler/queries/tree/_column_literal.py | 4 +++ .../lsst/daf/butler/tests/butler_queries.py | 25 +++++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 doc/changes/DM-46711.bugfix.md diff --git a/doc/changes/DM-46711.bugfix.md b/doc/changes/DM-46711.bugfix.md new file mode 100644 index 0000000000..ae9e9aa222 --- /dev/null +++ b/doc/changes/DM-46711.bugfix.md @@ -0,0 +1 @@ +Fix an issue where the new query system was rejecting numpy integers used in data IDs or bind values. diff --git a/python/lsst/daf/butler/queries/tree/_column_literal.py b/python/lsst/daf/butler/queries/tree/_column_literal.py index ba1444b901..4b6cab6f43 100644 --- a/python/lsst/daf/butler/queries/tree/_column_literal.py +++ b/python/lsst/daf/butler/queries/tree/_column_literal.py @@ -34,6 +34,7 @@ ) import datetime +import numbers import uuid import warnings from base64 import b64decode, b64encode @@ -400,6 +401,9 @@ def make_column_literal(value: LiteralValue) -> ColumnLiteral: dec = icrs.dec.degree lon_lat = lsst.sphgeom.LonLat.fromDegrees(ra, dec) return _make_region_literal_from_lonlat(lon_lat) + case numbers.Integral(): + # numpy.int64 and other integer-like values. + return IntColumnLiteral.from_value(int(value)) raise TypeError(f"Invalid type {type(value).__name__!r} of value {value!r} for column literal.") diff --git a/python/lsst/daf/butler/tests/butler_queries.py b/python/lsst/daf/butler/tests/butler_queries.py index 9178a1d0bd..0410afcef5 100644 --- a/python/lsst/daf/butler/tests/butler_queries.py +++ b/python/lsst/daf/butler/tests/butler_queries.py @@ -40,6 +40,7 @@ import astropy.coordinates import astropy.time from lsst.sphgeom import LonLat, Region +from numpy import int64 from .._butler import Butler from .._collection_type import CollectionType @@ -1964,6 +1965,30 @@ def test_default_data_id(self) -> None: names = [x.name for x in result] self.assertCountEqual(names, ["Cam2-G"]) + def test_unusual_column_literals(self) -> None: + butler = self.make_butler("base.yaml") + + # Users frequently use numpy integer types as literals in queries. + result = butler.query_dimension_records( + "detector", data_id={"instrument": "Cam1", "detector": int64(1)} + ) + names = [x.full_name for x in result] + self.assertEqual(names, ["Aa"]) + + result = butler.query_dimension_records( + "detector", where="instrument='Cam1' and detector=an_integer", bind={"an_integer": int64(2)} + ) + names = [x.full_name for x in result] + self.assertEqual(names, ["Ab"]) + + with butler.query() as query: + x = query.expression_factory + result = list( + query.dimension_records("detector").where(x.instrument == "Cam1", x.detector == int64(3)) + ) + names = [x.full_name for x in result] + self.assertEqual(names, ["Ba"]) + def _get_exposure_ids_from_dimension_records(dimension_records: Iterable[DimensionRecord]) -> list[int]: output = []