1 # SPDX-License-Identifier: LGPL-3-or-later
2 # Copyright 2022 Jacob Lifshay programmerjake@gmail.com
7 from nmutil
.plain_data
import (FrozenPlainDataError
, plain_data
,
11 @plain_data(order
=True)
16 @plain_data(order
=True)
18 __slots__
= "a", "b", "x", "y"
20 def __init__(self
, a
, b
, *, x
, y
):
27 @plain_data(order
=True)
28 class PlainData2(PlainData1
):
31 def __init__(self
, a
, b
, *, x
, y
, z
):
32 super().__init
__(a
, b
, x
=x
, y
=y
)
36 @plain_data(order
=True, frozen
=True, unsafe_hash
=True)
41 @plain_data(order
=True, frozen
=True, unsafe_hash
=True)
43 __slots__
= "a", "b", "x", "y"
45 def __init__(self
, a
, b
, *, x
, y
):
52 @plain_data(order
=True, frozen
=True, unsafe_hash
=True)
53 class PlainDataF2(PlainDataF1
):
56 def __init__(self
, a
, b
, *, x
, y
, z
):
57 super().__init
__(a
, b
, x
=x
, y
=y
)
61 class TestPlainData(unittest
.TestCase
):
62 def test_fields(self
):
63 self
.assertEqual(fields(PlainData0
), ())
64 self
.assertEqual(fields(PlainData0()), ())
65 self
.assertEqual(fields(PlainData1
), ("a", "b", "x", "y"))
66 self
.assertEqual(fields(PlainData1(1, 2, x
="x", y
="y")),
68 self
.assertEqual(fields(PlainData2
), ("a", "b", "x", "y", "z"))
69 self
.assertEqual(fields(PlainData2(1, 2, x
="x", y
="y", z
=3)),
70 ("a", "b", "x", "y", "z"))
71 self
.assertEqual(fields(PlainDataF0
), ())
72 self
.assertEqual(fields(PlainDataF0()), ())
73 self
.assertEqual(fields(PlainDataF1
), ("a", "b", "x", "y"))
74 self
.assertEqual(fields(PlainDataF1(1, 2, x
="x", y
="y")),
76 self
.assertEqual(fields(PlainDataF2
), ("a", "b", "x", "y", "z"))
77 self
.assertEqual(fields(PlainDataF2(1, 2, x
="x", y
="y", z
=3)),
78 ("a", "b", "x", "y", "z"))
79 with self
.assertRaisesRegex(
81 r
"the passed-in object must be a class or an instance of a "
82 r
"class decorated with @plain_data\(\)"):
85 def test_replace(self
):
86 with self
.assertRaisesRegex(
88 r
"the passed-in object must be a class or an instance of a "
89 r
"class decorated with @plain_data\(\)"):
91 with self
.assertRaisesRegex(TypeError, "can't set unknown field 'a'"):
92 replace(PlainData0(), a
=1)
93 with self
.assertRaisesRegex(TypeError, "can't set unknown field 'z'"):
94 replace(PlainDataF1(1, 2, x
="x", y
="y"), a
=3, z
=1)
95 self
.assertEqual(replace(PlainData0()), PlainData0())
96 self
.assertEqual(replace(PlainDataF1(1, 2, x
="x", y
="y")),
97 PlainDataF1(1, 2, x
="x", y
="y"))
98 self
.assertEqual(replace(PlainDataF1(1, 2, x
="x", y
="y"), a
=3),
99 PlainDataF1(3, 2, x
="x", y
="y"))
100 self
.assertEqual(replace(PlainDataF1(1, 2, x
="x", y
="y"), x
=5, a
=3),
101 PlainDataF1(3, 2, x
=5, y
="y"))
104 self
.assertTrue(PlainData0() == PlainData0())
105 self
.assertFalse('a' == PlainData0())
106 self
.assertFalse(PlainDataF0() == PlainData0())
107 self
.assertTrue(PlainData1(1, 2, x
="x", y
="y")
108 == PlainData1(1, 2, x
="x", y
="y"))
109 self
.assertFalse(PlainData1(1, 2, x
="x", y
="y")
110 == PlainData1(1, 2, x
="x", y
="z"))
111 self
.assertFalse(PlainData1(1, 2, x
="x", y
="y")
112 == PlainData2(1, 2, x
="x", y
="y", z
=3))
115 def check_op(v
, tuple_v
):
116 with self
.subTest(v
=v
, tuple_v
=tuple_v
):
117 self
.assertEqual(hash(v
), hash(tuple_v
))
119 def check(a
, b
, x
, y
, z
):
120 tuple_v
= a
, b
, x
, y
, z
121 v
= PlainDataF2(a
=a
, b
=b
, x
=x
, y
=y
, z
=z
)
124 check(1, 2, "x", "y", "z")
126 check(1, 2, "x", "y", "a")
127 check(1, 2, "x", "y", "zz")
129 check(1, 2, "x", "a", "z")
130 check(1, 2, "x", "zz", "z")
132 check(1, 2, "a", "y", "z")
133 check(1, 2, "zz", "y", "z")
135 check(1, -10, "x", "y", "z")
136 check(1, 10, "x", "y", "z")
138 check(-10, 2, "x", "y", "z")
139 check(10, 2, "x", "y", "z")
141 def test_order(self
):
142 def check_op(l
, r
, tuple_l
, tuple_r
, op
):
143 with self
.subTest(l
=l
, r
=r
,
144 tuple_l
=tuple_l
, tuple_r
=tuple_r
, op
=op
):
145 self
.assertEqual(op(l
, r
), op(tuple_l
, tuple_r
))
146 self
.assertEqual(op(r
, l
), op(tuple_r
, tuple_l
))
148 def check(a
, b
, x
, y
, z
):
149 tuple_l
= 1, 2, "x", "y", "z"
150 l
= PlainData2(a
=1, b
=2, x
="x", y
="y", z
="z")
151 tuple_r
= a
, b
, x
, y
, z
152 r
= PlainData2(a
=a
, b
=b
, x
=x
, y
=y
, z
=z
)
153 check_op(l
, r
, tuple_l
, tuple_r
, operator
.eq
)
154 check_op(l
, r
, tuple_l
, tuple_r
, operator
.ne
)
155 check_op(l
, r
, tuple_l
, tuple_r
, operator
.lt
)
156 check_op(l
, r
, tuple_l
, tuple_r
, operator
.le
)
157 check_op(l
, r
, tuple_l
, tuple_r
, operator
.gt
)
158 check_op(l
, r
, tuple_l
, tuple_r
, operator
.ge
)
160 check(1, 2, "x", "y", "z")
162 check(1, 2, "x", "y", "a")
163 check(1, 2, "x", "y", "zz")
165 check(1, 2, "x", "a", "z")
166 check(1, 2, "x", "zz", "z")
168 check(1, 2, "a", "y", "z")
169 check(1, 2, "zz", "y", "z")
171 check(1, -10, "x", "y", "z")
172 check(1, 10, "x", "y", "z")
174 check(-10, 2, "x", "y", "z")
175 check(10, 2, "x", "y", "z")
178 self
.assertEqual(repr(PlainData0()), "PlainData0()")
179 self
.assertEqual(repr(PlainData1(1, 2, x
="x", y
="y")),
180 "PlainData1(a=1, b=2, x='x', y='y')")
181 self
.assertEqual(repr(PlainData2(1, 2, x
="x", y
="y", z
=3)),
182 "PlainData2(a=1, b=2, x='x', y='y', z=3)")
183 self
.assertEqual(repr(PlainDataF2(1, 2, x
="x", y
="y", z
=3)),
184 "PlainDataF2(a=1, b=2, x='x', y='y', z=3)")
186 def test_frozen(self
):
187 not_frozen
= PlainData0()
189 frozen0
= PlainDataF0()
190 with self
.assertRaises(AttributeError):
192 frozen1
= PlainDataF1(1, 2, x
="x", y
="y")
193 with self
.assertRaises(FrozenPlainDataError
):
196 def test_pickle(self
):
198 with self
.subTest(v
=v
):
199 self
.assertEqual(v
, pickle
.loads(pickle
.dumps(v
)))
202 check(PlainData1(a
=1, b
=2, x
="x", y
="y"))
203 check(PlainData2(a
=1, b
=2, x
="x", y
="y", z
="z"))
205 check(PlainDataF1(a
=1, b
=2, x
="x", y
="y"))
206 check(PlainDataF2(a
=1, b
=2, x
="x", y
="y", z
="z"))
209 if __name__
== "__main__":