Coverage for tests/test_utils.py: 19%
138 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-08-12 09:20 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-08-12 09:20 +0000
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 """Tests for NamedKeyDict."""
36 def setUp(self):
37 self.TestTuple = namedtuple("TestTuple", ("name", "id"))
38 self.a = self.TestTuple(name="a", id=1)
39 self.b = self.TestTuple(name="b", id=2)
40 self.dictionary = {self.a: 10, self.b: 20}
41 self.names = {self.a.name, self.b.name}
43 def check(self, nkd):
44 self.assertEqual(len(nkd), 2)
45 self.assertEqual(nkd.names, self.names)
46 self.assertEqual(nkd.keys(), self.dictionary.keys())
47 self.assertEqual(list(nkd.values()), list(self.dictionary.values()))
48 self.assertEqual(list(nkd.items()), list(self.dictionary.items()))
49 self.assertEqual(list(nkd.byName().values()), list(self.dictionary.values()))
50 self.assertEqual(list(nkd.byName().keys()), list(nkd.names))
52 def testConstruction(self):
53 self.check(NamedKeyDict(self.dictionary))
54 self.check(NamedKeyDict(iter(self.dictionary.items())))
56 def testDuplicateNameConstruction(self):
57 self.dictionary[self.TestTuple(name="a", id=3)] = 30
58 with self.assertRaises(AssertionError):
59 NamedKeyDict(self.dictionary)
60 with self.assertRaises(AssertionError):
61 NamedKeyDict(iter(self.dictionary.items()))
63 def testNoNameConstruction(self):
64 self.dictionary["a"] = 30
65 with self.assertRaises(AttributeError):
66 NamedKeyDict(self.dictionary)
67 with self.assertRaises(AttributeError):
68 NamedKeyDict(iter(self.dictionary.items()))
70 def testGetItem(self):
71 nkd = NamedKeyDict(self.dictionary)
72 self.assertEqual(nkd["a"], 10)
73 self.assertEqual(nkd[self.a], 10)
74 self.assertEqual(nkd["b"], 20)
75 self.assertEqual(nkd[self.b], 20)
76 self.assertIn("a", nkd)
77 self.assertIn(self.b, nkd)
79 def testSetItem(self):
80 nkd = NamedKeyDict(self.dictionary)
81 nkd[self.a] = 30
82 self.assertEqual(nkd["a"], 30)
83 nkd["b"] = 40
84 self.assertEqual(nkd[self.b], 40)
85 with self.assertRaises(KeyError):
86 nkd["c"] = 50
87 with self.assertRaises(AssertionError):
88 nkd[self.TestTuple("a", 3)] = 60
90 def testDelItem(self):
91 nkd = NamedKeyDict(self.dictionary)
92 del nkd[self.a]
93 self.assertNotIn("a", nkd)
94 del nkd["b"]
95 self.assertNotIn(self.b, nkd)
96 self.assertEqual(len(nkd), 0)
98 def testIter(self):
99 self.assertEqual(set(iter(NamedKeyDict(self.dictionary))), set(self.dictionary))
101 def testEquality(self):
102 nkd = NamedKeyDict(self.dictionary)
103 self.assertEqual(nkd, self.dictionary)
104 self.assertEqual(self.dictionary, nkd)
107class NamedValueSetTest(unittest.TestCase):
108 """Tests for NamedValueSet."""
110 def setUp(self):
111 self.TestTuple = namedtuple("TestTuple", ("name", "id"))
112 self.a = self.TestTuple(name="a", id=1)
113 self.b = self.TestTuple(name="b", id=2)
114 self.c = self.TestTuple(name="c", id=3)
116 def testConstruction(self):
117 for arg in ({self.a, self.b}, (self.a, self.b)):
118 for nvs in (NamedValueSet(arg), NamedValueSet(arg).freeze()):
119 self.assertEqual(len(nvs), 2)
120 self.assertEqual(nvs.names, {"a", "b"})
121 self.assertCountEqual(nvs, {self.a, self.b})
122 self.assertCountEqual(nvs.asMapping().items(), [(self.a.name, self.a), (self.b.name, self.b)])
124 def testNoNameConstruction(self):
125 with self.assertRaises(AttributeError):
126 NamedValueSet([self.a, "a"])
128 def testGetItem(self):
129 nvs = NamedValueSet({self.a, self.b, self.c})
130 self.assertEqual(nvs["a"], self.a)
131 self.assertEqual(nvs[self.a], self.a)
132 self.assertEqual(nvs["b"], self.b)
133 self.assertEqual(nvs[self.b], self.b)
134 self.assertIn("a", nvs)
135 self.assertIn(self.b, nvs)
137 def testEquality(self):
138 s = {self.a, self.b, self.c}
139 nvs = NamedValueSet(s)
140 self.assertEqual(nvs, s)
141 self.assertEqual(s, nvs)
143 def checkOperator(self, result, expected):
144 self.assertIsInstance(result, NamedValueSet)
145 self.assertEqual(result, expected)
147 def testOperators(self):
148 ab = NamedValueSet({self.a, self.b})
149 bc = NamedValueSet({self.b, self.c})
150 self.checkOperator(ab & bc, {self.b})
151 self.checkOperator(ab | bc, {self.a, self.b, self.c})
152 self.checkOperator(ab ^ bc, {self.a, self.c})
153 self.checkOperator(ab - bc, {self.a})
155 def testPop(self):
156 # Construct with list for repeatable ordering.
157 nvs = NamedValueSet([self.a, self.b, self.c])
158 self.assertEqual(nvs.pop("c"), self.c)
159 self.assertEqual(nvs.pop(), self.a)
160 self.assertEqual(nvs.pop(), self.b)
161 self.assertEqual(nvs.pop("d", self.c), self.c)
162 with self.assertRaises(KeyError):
163 nvs.pop()
165 def testRemove(self):
166 nvs = NamedValueSet([self.a, self.b, self.c])
167 nvs.remove("b")
168 self.assertIn("a", nvs)
169 self.assertNotIn("b", nvs)
170 with self.assertRaises(KeyError):
171 nvs.remove("d")
172 nvs.discard("d")
173 nvs.discard("a")
174 self.assertNotIn("a", nvs)
177class GlobToRegexTestCase(unittest.TestCase):
178 """Tests for glob to regex."""
180 def testStarInList(self):
181 """Test that if a one of the items in the expression list is a star
182 (stand-alone) then ``...`` is returned (which implies no restrictions)
183 """
184 self.assertIs(globToRegex(["foo", "*", "bar"]), ...)
186 def testGlobList(self):
187 """Test that a list of glob strings converts as expected to a regex and
188 returns in the expected list.
189 """
190 # These strings should be returned unchanged.
191 strings = ["bar", "😺", "ingésτ", "ex]", "[xe", "[!no", "e[x"]
192 self.assertEqual(globToRegex(strings), strings)
194 # Globs with strings that match the glob and strings that do not.
195 tests = (
196 ("bar", ["bar"], ["baz"]),
197 ("ba*", ["bar", "baz"], ["az"]),
198 ("ba[rz]", ["bar", "baz"], ["bat"]),
199 ("ba[rz]x[y", ["barx[y", "bazx[y"], ["batx[y"]),
200 ("ba[!rz]", ["bat", "baτ"], ["bar", "baz"]),
201 ("b?r", ["bor", "bar", "b😺r"], ["bat"]),
202 ("*.fits", ["boz.fits"], ["boz.fits.gz", "boz.hdf5"]),
203 )
205 for glob, matches, no_matches in tests:
206 patterns = globToRegex(glob)
207 for match in matches:
208 self.assertTrue(bool(re.fullmatch(patterns[0], match)))
209 for no_match in no_matches:
210 self.assertIsNone(re.fullmatch(patterns[0], no_match))
213if __name__ == "__main__":
214 unittest.main()