Coverage for tests/test_chain.py: 22%
37 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-21 09:39 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-21 09:39 +0000
1# This file is part of daf_relation.
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/>.
22from __future__ import annotations
24import unittest
26from lsst.daf.relation import BinaryOperationRelation, Chain, ColumnError, EngineError, iteration, tests
29class ChainTestCase(tests.RelationTestCase):
30 """Tests for the Chain operation and relations based on it."""
32 def setUp(self) -> None:
33 self.a = tests.ColumnTag("a")
34 self.b = tests.ColumnTag("b")
35 self.engine = iteration.Engine(name="preferred")
36 self.leaf_1 = self.engine.make_leaf(
37 {self.a, self.b},
38 payload=iteration.RowSequence([{self.a: 0, self.b: 5}, {self.a: 1, self.b: 10}]),
39 name="leaf_1",
40 )
41 self.leaf_2 = self.engine.make_leaf(
42 {self.a, self.b},
43 payload=iteration.RowSequence([{self.a: 2, self.b: 15}, {self.a: 3, self.b: 20}]),
44 name="leaf_2",
45 )
47 def test_attributes(self) -> None:
48 """Check that all Relation attributes have the expected values."""
49 relation = self.leaf_1.chain(self.leaf_2)
50 assert isinstance(relation, BinaryOperationRelation)
51 self.assertEqual(relation.columns, {self.a, self.b})
52 self.assertEqual(relation.engine, self.engine)
53 self.assertEqual(relation.min_rows, 4)
54 self.assertEqual(relation.max_rows, 4)
55 self.assertFalse(relation.is_locked)
56 operation = relation.operation
57 assert isinstance(operation, Chain)
59 def test_apply_failures(self) -> None:
60 """Test failure modes of constructing and applying Chains."""
61 new_engine = iteration.Engine(name="other")
62 leaf_3 = new_engine.make_leaf(
63 {self.a, self.b},
64 payload=iteration.RowSequence([{self.a: 3, self.b: 4}]),
65 name="leaf_3",
66 )
67 with self.assertRaises(EngineError):
68 self.leaf_1.chain(leaf_3)
69 leaf_4 = self.engine.make_leaf(
70 {self.a},
71 payload=iteration.RowSequence([{self.a: 3}]),
72 name="leaf_4",
73 )
74 with self.assertRaises(ColumnError):
75 self.leaf_1.chain(leaf_4)
77 def test_iteration(self) -> None:
78 """Test Chain execution in the iteration engine."""
79 relation = self.leaf_1.chain(self.leaf_2)
80 self.assertEqual(
81 list(self.engine.execute(relation)),
82 list(self.leaf_1.payload) + list(self.leaf_2.payload),
83 )
85 def test_str(self) -> None:
86 """Test str(Chain) and str(BinaryOperationRelation[Chain])."""
87 relation = self.leaf_1.chain(self.leaf_2)
88 self.assertEqual(str(relation), "leaf_1 ∪ leaf_2")
89 # Nested operations get parentheses, unless they're chains or leaves.
90 leaf_3 = self.engine.make_leaf(
91 {self.a, self.b},
92 payload=iteration.RowSequence([{self.a: 3, self.b: 4}]),
93 name="leaf_3",
94 )
95 self.assertEqual(str(relation.chain(leaf_3)), "leaf_1 ∪ leaf_2 ∪ leaf_3")
96 self.assertEqual(str(self.leaf_1.join(self.leaf_2).chain(leaf_3)), "(leaf_1 ⋈ leaf_2) ∪ leaf_3")
99if __name__ == "__main__":
100 unittest.main()