Coverage for tests/test_utils.py: 19%
138 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-03-31 02:41 -0700
« prev ^ index » next coverage.py v6.5.0, created at 2023-03-31 02:41 -0700
1# This file is part of daf_butler.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
22import os
23import re
24import unittest
25from collections import namedtuple
27from lsst.daf.butler import NamedKeyDict, NamedValueSet
28from lsst.daf.butler.core.utils import globToRegex
30TESTDIR = os.path.dirname(__file__)
33class NamedKeyDictTest(unittest.TestCase):
34 def setUp(self):
35 self.TestTuple = namedtuple("TestTuple", ("name", "id"))
36 self.a = self.TestTuple(name="a", id=1)
37 self.b = self.TestTuple(name="b", id=2)
38 self.dictionary = {self.a: 10, self.b: 20}
39 self.names = {self.a.name, self.b.name}
41 def check(self, nkd):
42 self.assertEqual(len(nkd), 2)
43 self.assertEqual(nkd.names, self.names)
44 self.assertEqual(nkd.keys(), self.dictionary.keys())
45 self.assertEqual(list(nkd.values()), list(self.dictionary.values()))
46 self.assertEqual(list(nkd.items()), list(self.dictionary.items()))
47 self.assertEqual(list(nkd.byName().values()), list(self.dictionary.values()))
48 self.assertEqual(list(nkd.byName().keys()), list(nkd.names))
50 def testConstruction(self):
51 self.check(NamedKeyDict(self.dictionary))
52 self.check(NamedKeyDict(iter(self.dictionary.items())))
54 def testDuplicateNameConstruction(self):
55 self.dictionary[self.TestTuple(name="a", id=3)] = 30
56 with self.assertRaises(AssertionError):
57 NamedKeyDict(self.dictionary)
58 with self.assertRaises(AssertionError):
59 NamedKeyDict(iter(self.dictionary.items()))
61 def testNoNameConstruction(self):
62 self.dictionary["a"] = 30
63 with self.assertRaises(AttributeError):
64 NamedKeyDict(self.dictionary)
65 with self.assertRaises(AttributeError):
66 NamedKeyDict(iter(self.dictionary.items()))
68 def testGetItem(self):
69 nkd = NamedKeyDict(self.dictionary)
70 self.assertEqual(nkd["a"], 10)
71 self.assertEqual(nkd[self.a], 10)
72 self.assertEqual(nkd["b"], 20)
73 self.assertEqual(nkd[self.b], 20)
74 self.assertIn("a", nkd)
75 self.assertIn(self.b, nkd)
77 def testSetItem(self):
78 nkd = NamedKeyDict(self.dictionary)
79 nkd[self.a] = 30
80 self.assertEqual(nkd["a"], 30)
81 nkd["b"] = 40
82 self.assertEqual(nkd[self.b], 40)
83 with self.assertRaises(KeyError):
84 nkd["c"] = 50
85 with self.assertRaises(AssertionError):
86 nkd[self.TestTuple("a", 3)] = 60
88 def testDelItem(self):
89 nkd = NamedKeyDict(self.dictionary)
90 del nkd[self.a]
91 self.assertNotIn("a", nkd)
92 del nkd["b"]
93 self.assertNotIn(self.b, nkd)
94 self.assertEqual(len(nkd), 0)
96 def testIter(self):
97 self.assertEqual(set(iter(NamedKeyDict(self.dictionary))), set(self.dictionary))
99 def testEquality(self):
100 nkd = NamedKeyDict(self.dictionary)
101 self.assertEqual(nkd, self.dictionary)
102 self.assertEqual(self.dictionary, nkd)
105class NamedValueSetTest(unittest.TestCase):
106 def setUp(self):
107 self.TestTuple = namedtuple("TestTuple", ("name", "id"))
108 self.a = self.TestTuple(name="a", id=1)
109 self.b = self.TestTuple(name="b", id=2)
110 self.c = self.TestTuple(name="c", id=3)
112 def testConstruction(self):
113 for arg in ({self.a, self.b}, (self.a, self.b)):
114 for nvs in (NamedValueSet(arg), NamedValueSet(arg).freeze()):
115 self.assertEqual(len(nvs), 2)
116 self.assertEqual(nvs.names, {"a", "b"})
117 self.assertCountEqual(nvs, {self.a, self.b})
118 self.assertCountEqual(nvs.asMapping().items(), [(self.a.name, self.a), (self.b.name, self.b)])
120 def testNoNameConstruction(self):
121 with self.assertRaises(AttributeError):
122 NamedValueSet([self.a, "a"])
124 def testGetItem(self):
125 nvs = NamedValueSet({self.a, self.b, self.c})
126 self.assertEqual(nvs["a"], self.a)
127 self.assertEqual(nvs[self.a], self.a)
128 self.assertEqual(nvs["b"], self.b)
129 self.assertEqual(nvs[self.b], self.b)
130 self.assertIn("a", nvs)
131 self.assertIn(self.b, nvs)
133 def testEquality(self):
134 s = {self.a, self.b, self.c}
135 nvs = NamedValueSet(s)
136 self.assertEqual(nvs, s)
137 self.assertEqual(s, nvs)
139 def checkOperator(self, result, expected):
140 self.assertIsInstance(result, NamedValueSet)
141 self.assertEqual(result, expected)
143 def testOperators(self):
144 ab = NamedValueSet({self.a, self.b})
145 bc = NamedValueSet({self.b, self.c})
146 self.checkOperator(ab & bc, {self.b})
147 self.checkOperator(ab | bc, {self.a, self.b, self.c})
148 self.checkOperator(ab ^ bc, {self.a, self.c})
149 self.checkOperator(ab - bc, {self.a})
151 def testPop(self):
152 # Construct with list for repeatable ordering.
153 nvs = NamedValueSet([self.a, self.b, self.c])
154 self.assertEqual(nvs.pop("c"), self.c)
155 self.assertEqual(nvs.pop(), self.a)
156 self.assertEqual(nvs.pop(), self.b)
157 self.assertEqual(nvs.pop("d", self.c), self.c)
158 with self.assertRaises(KeyError):
159 nvs.pop()
161 def testRemove(self):
162 nvs = NamedValueSet([self.a, self.b, self.c])
163 nvs.remove("b")
164 self.assertIn("a", nvs)
165 self.assertNotIn("b", nvs)
166 with self.assertRaises(KeyError):
167 nvs.remove("d")
168 nvs.discard("d")
169 nvs.discard("a")
170 self.assertNotIn("a", nvs)
173class GlobToRegexTestCase(unittest.TestCase):
174 def testStarInList(self):
175 """Test that if a one of the items in the expression list is a star
176 (stand-alone) then ``...`` is returned (which implies no restrictions)
177 """
178 self.assertIs(globToRegex(["foo", "*", "bar"]), ...)
180 def testGlobList(self):
181 """Test that a list of glob strings converts as expected to a regex and
182 returns in the expected list.
183 """
184 # These strings should be returned unchanged.
185 strings = ["bar", "😺", "ingésτ", "ex]", "[xe", "[!no", "e[x"]
186 self.assertEqual(globToRegex(strings), strings)
188 # Globs with strings that match the glob and strings that do not.
189 tests = (
190 ("bar", ["bar"], ["baz"]),
191 ("ba*", ["bar", "baz"], ["az"]),
192 ("ba[rz]", ["bar", "baz"], ["bat"]),
193 ("ba[rz]x[y", ["barx[y", "bazx[y"], ["batx[y"]),
194 ("ba[!rz]", ["bat", "baτ"], ["bar", "baz"]),
195 ("b?r", ["bor", "bar", "b😺r"], ["bat"]),
196 ("*.fits", ["boz.fits"], ["boz.fits.gz", "boz.hdf5"]),
197 )
199 for glob, matches, no_matches in tests:
200 patterns = globToRegex(glob)
201 for match in matches:
202 self.assertTrue(bool(re.fullmatch(patterns[0], match)))
203 for no_match in no_matches:
204 self.assertIsNone(re.fullmatch(patterns[0], no_match))
207if __name__ == "__main__":
208 unittest.main()