@@ -47,6 +47,17 @@ def test_constructor(self):
4747 with self .assertRaisesRegex (TypeError , 'vars must be a set or None' ):
4848 xbeam .Key (vars = 'foo' )
4949
50+ key = xbeam .Key (indices = {'x' : 0 , 'y' : 1 })
51+ self .assertIsInstance (key .indices , immutabledict .immutabledict )
52+ self .assertEqual (dict (key .indices ), {'x' : 0 , 'y' : 1 })
53+ self .assertEqual (dict (key .offsets ), {})
54+ self .assertIsNone (key .vars )
55+
56+ with self .assertRaisesRegex (
57+ ValueError , 'offsets and indices are mutually exclusive'
58+ ):
59+ xbeam .Key (offsets = {'x' : 0 }, indices = {'x' : 0 })
60+
5061 def test_replace (self ):
5162 key = xbeam .Key ({'x' : 0 }, {'foo' })
5263
@@ -74,6 +85,33 @@ def test_replace(self):
7485 actual = key .replace ({'y' : 1 }, {'bar' })
7586 self .assertEqual (expected , actual )
7687
88+ def test_replace_with_indices (self ):
89+ key_i = xbeam .Key (indices = {'x' : 0 }, vars = {'foo' })
90+
91+ expected = xbeam .Key (indices = {'x' : 1 }, vars = {'foo' })
92+ actual = key_i .replace (indices = {'x' : 1 })
93+ self .assertEqual (expected , actual )
94+
95+ expected = xbeam .Key (indices = {'y' : 1 }, vars = {'foo' })
96+ actual = key_i .replace (indices = {'y' : 1 })
97+ self .assertEqual (expected , actual )
98+
99+ expected = xbeam .Key (indices = {'x' : 0 })
100+ actual = key_i .replace (vars = None )
101+ self .assertEqual (expected , actual )
102+
103+ expected = xbeam .Key (indices = {'x' : 0 }, vars = {'bar' })
104+ actual = key_i .replace (vars = {'bar' })
105+ self .assertEqual (expected , actual )
106+
107+ expected = xbeam .Key (indices = {'y' : 1 }, vars = {'foo' })
108+ actual = key_i .replace (indices = {'y' : 1 }, vars = {'foo' })
109+ self .assertEqual (expected , actual )
110+
111+ expected = xbeam .Key (indices = {'y' : 1 }, vars = {'bar' })
112+ actual = key_i .replace (indices = {'y' : 1 }, vars = {'bar' })
113+ self .assertEqual (expected , actual )
114+
77115 def test_with_offsets (self ):
78116 key = xbeam .Key ({'x' : 0 })
79117
@@ -98,6 +136,42 @@ def test_with_offsets(self):
98136 actual = key2 .with_offsets (x = 1 )
99137 self .assertEqual (expected , actual )
100138
139+ key_i = xbeam .Key (indices = {'x' : 0 })
140+ with self .assertRaisesRegex (
141+ ValueError , 'cannot call with_offsets on a Key with indices'
142+ ):
143+ key_i .with_offsets (x = 1 )
144+
145+ def test_with_indices (self ):
146+ key = xbeam .Key (indices = {'x' : 0 })
147+
148+ expected = xbeam .Key (indices = {'x' : 1 })
149+ actual = key .with_indices (x = 1 )
150+ self .assertEqual (expected , actual )
151+
152+ expected = xbeam .Key (indices = {'x' : 0 , 'y' : 1 })
153+ actual = key .with_indices (y = 1 )
154+ self .assertEqual (expected , actual )
155+
156+ expected = xbeam .Key (indices = {})
157+ actual = key .with_indices (x = None )
158+ self .assertEqual (expected , actual )
159+
160+ expected = xbeam .Key (indices = {'y' : 1 , 'z' : 2 })
161+ actual = key .with_indices (x = None , y = 1 , z = 2 )
162+ self .assertEqual (expected , actual )
163+
164+ key2 = xbeam .Key (indices = {'x' : 0 }, vars = {'foo' })
165+ expected = xbeam .Key (indices = {'x' : 1 }, vars = {'foo' })
166+ actual = key2 .with_indices (x = 1 )
167+ self .assertEqual (expected , actual )
168+
169+ key_o = xbeam .Key (offsets = {'x' : 0 })
170+ with self .assertRaisesRegex (
171+ ValueError , 'cannot call with_indices on a Key with offsets'
172+ ):
173+ key_o .with_indices (x = 1 )
174+
101175 def test_repr (self ):
102176 key = xbeam .Key ({'x' : 0 , 'y' : 10 })
103177 expected = "Key(offsets={'x': 0, 'y': 10})"
@@ -107,6 +181,10 @@ def test_repr(self):
107181 expected = "Key(vars={'foo'})"
108182 self .assertEqual (repr (key ), expected )
109183
184+ key = xbeam .Key (indices = {'x' : 0 , 'y' : 1 })
185+ expected = "Key(indices={'x': 0, 'y': 1})"
186+ self .assertEqual (repr (key ), expected )
187+
110188 def test_dict_key (self ):
111189 first = {xbeam .Key ({'x' : 0 , 'y' : 10 }): 1 }
112190 second = {xbeam .Key ({'x' : 0 , 'y' : 10 }): 1 }
@@ -115,13 +193,25 @@ def test_dict_key(self):
115193 def test_equality (self ):
116194 key = xbeam .Key ({'x' : 0 , 'y' : 10 })
117195 self .assertEqual (key , key )
118- self .assertNotEqual (key , None )
119196
120197 key2 = xbeam .Key ({'x' : 0 , 'y' : 10 }, {'bar' })
121198 self .assertEqual (key2 , key2 )
122199 self .assertNotEqual (key , key2 )
123200 self .assertNotEqual (key2 , key )
124201
202+ key_i = xbeam .Key (indices = {'x' : 0 , 'y' : 1 })
203+ self .assertEqual (key_i , key_i )
204+ self .assertNotEqual (key_i , key )
205+ self .assertNotEqual (key , key_i )
206+
207+ key_o = xbeam .Key (offsets = {'x' : 0 , 'y' : 1 })
208+ self .assertNotEqual (key_i , key_o )
209+
210+ key_i2 = xbeam .Key (indices = {'x' : 0 , 'y' : 1 }, vars = {'bar' })
211+ self .assertEqual (key_i2 , key_i2 )
212+ self .assertNotEqual (key_i , key_i2 )
213+ self .assertNotEqual (key_i2 , key_i )
214+
125215 def test_offsets_as_beam_key (self ):
126216 inputs = [
127217 (xbeam .Key ({'x' : 0 , 'y' : 1 }), 1 ),
@@ -135,6 +225,19 @@ def test_offsets_as_beam_key(self):
135225 actual = inputs | beam .GroupByKey ()
136226 self .assertEqual (actual , expected )
137227
228+ def test_indices_as_beam_key (self ):
229+ inputs = [
230+ (xbeam .Key (indices = {'x' : 0 , 'y' : 1 }), 1 ),
231+ (xbeam .Key (indices = {'x' : 0 , 'y' : 2 }), 2 ),
232+ (xbeam .Key (indices = {'y' : 1 , 'x' : 0 }), 3 ),
233+ ]
234+ expected = [
235+ (xbeam .Key (indices = {'x' : 0 , 'y' : 1 }), [1 , 3 ]),
236+ (xbeam .Key (indices = {'x' : 0 , 'y' : 2 }), [2 ]),
237+ ]
238+ actual = inputs | beam .GroupByKey ()
239+ self .assertEqual (actual , expected )
240+
138241 def test_vars_as_beam_key (self ):
139242 inputs = [
140243 (xbeam .Key (vars = {'foo' }), 1 ),
@@ -155,6 +258,10 @@ def test_pickle(self):
155258 unpickled = pickle .loads (pickle .dumps (key ))
156259 self .assertEqual (key , unpickled )
157260
261+ key_i = xbeam .Key (indices = {'x' : 0 , 'y' : 1 }, vars = {'foo' })
262+ unpickled_i = pickle .loads (pickle .dumps (key_i ))
263+ self .assertEqual (key_i , unpickled_i )
264+
158265
159266class TestOffsetsToSlices (test_util .TestCase ):
160267
0 commit comments