1import unittest
2import pickle
3import sys
4
5from test import support
6
7py_operator = support.import_fresh_module('operator', blocked=['_operator'])
8c_operator = support.import_fresh_module('operator', fresh=['_operator'])
9
10class Seq1:
11    def __init__(self, lst):
12        self.lst = lst
13    def __len__(self):
14        return len(self.lst)
15    def __getitem__(self, i):
16        return self.lst[i]
17    def __add__(self, other):
18        return self.lst + other.lst
19    def __mul__(self, other):
20        return self.lst * other
21    def __rmul__(self, other):
22        return other * self.lst
23
24class Seq2(object):
25    def __init__(self, lst):
26        self.lst = lst
27    def __len__(self):
28        return len(self.lst)
29    def __getitem__(self, i):
30        return self.lst[i]
31    def __add__(self, other):
32        return self.lst + other.lst
33    def __mul__(self, other):
34        return self.lst * other
35    def __rmul__(self, other):
36        return other * self.lst
37
38
39class OperatorTestCase:
40    def test_lt(self):
41        operator = self.module
42        self.assertRaises(TypeError, operator.lt)
43        self.assertRaises(TypeError, operator.lt, 1j, 2j)
44        self.assertFalse(operator.lt(1, 0))
45        self.assertFalse(operator.lt(1, 0.0))
46        self.assertFalse(operator.lt(1, 1))
47        self.assertFalse(operator.lt(1, 1.0))
48        self.assertTrue(operator.lt(1, 2))
49        self.assertTrue(operator.lt(1, 2.0))
50
51    def test_le(self):
52        operator = self.module
53        self.assertRaises(TypeError, operator.le)
54        self.assertRaises(TypeError, operator.le, 1j, 2j)
55        self.assertFalse(operator.le(1, 0))
56        self.assertFalse(operator.le(1, 0.0))
57        self.assertTrue(operator.le(1, 1))
58        self.assertTrue(operator.le(1, 1.0))
59        self.assertTrue(operator.le(1, 2))
60        self.assertTrue(operator.le(1, 2.0))
61
62    def test_eq(self):
63        operator = self.module
64        class C(object):
65            def __eq__(self, other):
66                raise SyntaxError
67        self.assertRaises(TypeError, operator.eq)
68        self.assertRaises(SyntaxError, operator.eq, C(), C())
69        self.assertFalse(operator.eq(1, 0))
70        self.assertFalse(operator.eq(1, 0.0))
71        self.assertTrue(operator.eq(1, 1))
72        self.assertTrue(operator.eq(1, 1.0))
73        self.assertFalse(operator.eq(1, 2))
74        self.assertFalse(operator.eq(1, 2.0))
75
76    def test_ne(self):
77        operator = self.module
78        class C(object):
79            def __ne__(self, other):
80                raise SyntaxError
81        self.assertRaises(TypeError, operator.ne)
82        self.assertRaises(SyntaxError, operator.ne, C(), C())
83        self.assertTrue(operator.ne(1, 0))
84        self.assertTrue(operator.ne(1, 0.0))
85        self.assertFalse(operator.ne(1, 1))
86        self.assertFalse(operator.ne(1, 1.0))
87        self.assertTrue(operator.ne(1, 2))
88        self.assertTrue(operator.ne(1, 2.0))
89
90    def test_ge(self):
91        operator = self.module
92        self.assertRaises(TypeError, operator.ge)
93        self.assertRaises(TypeError, operator.ge, 1j, 2j)
94        self.assertTrue(operator.ge(1, 0))
95        self.assertTrue(operator.ge(1, 0.0))
96        self.assertTrue(operator.ge(1, 1))
97        self.assertTrue(operator.ge(1, 1.0))
98        self.assertFalse(operator.ge(1, 2))
99        self.assertFalse(operator.ge(1, 2.0))
100
101    def test_gt(self):
102        operator = self.module
103        self.assertRaises(TypeError, operator.gt)
104        self.assertRaises(TypeError, operator.gt, 1j, 2j)
105        self.assertTrue(operator.gt(1, 0))
106        self.assertTrue(operator.gt(1, 0.0))
107        self.assertFalse(operator.gt(1, 1))
108        self.assertFalse(operator.gt(1, 1.0))
109        self.assertFalse(operator.gt(1, 2))
110        self.assertFalse(operator.gt(1, 2.0))
111
112    def test_abs(self):
113        operator = self.module
114        self.assertRaises(TypeError, operator.abs)
115        self.assertRaises(TypeError, operator.abs, None)
116        self.assertEqual(operator.abs(-1), 1)
117        self.assertEqual(operator.abs(1), 1)
118
119    def test_add(self):
120        operator = self.module
121        self.assertRaises(TypeError, operator.add)
122        self.assertRaises(TypeError, operator.add, None, None)
123        self.assertEqual(operator.add(3, 4), 7)
124
125    def test_bitwise_and(self):
126        operator = self.module
127        self.assertRaises(TypeError, operator.and_)
128        self.assertRaises(TypeError, operator.and_, None, None)
129        self.assertEqual(operator.and_(0xf, 0xa), 0xa)
130
131    def test_concat(self):
132        operator = self.module
133        self.assertRaises(TypeError, operator.concat)
134        self.assertRaises(TypeError, operator.concat, None, None)
135        self.assertEqual(operator.concat('py', 'thon'), 'python')
136        self.assertEqual(operator.concat([1, 2], [3, 4]), [1, 2, 3, 4])
137        self.assertEqual(operator.concat(Seq1([5, 6]), Seq1([7])), [5, 6, 7])
138        self.assertEqual(operator.concat(Seq2([5, 6]), Seq2([7])), [5, 6, 7])
139        self.assertRaises(TypeError, operator.concat, 13, 29)
140
141    def test_countOf(self):
142        operator = self.module
143        self.assertRaises(TypeError, operator.countOf)
144        self.assertRaises(TypeError, operator.countOf, None, None)
145        self.assertEqual(operator.countOf([1, 2, 1, 3, 1, 4], 3), 1)
146        self.assertEqual(operator.countOf([1, 2, 1, 3, 1, 4], 5), 0)
147
148    def test_delitem(self):
149        operator = self.module
150        a = [4, 3, 2, 1]
151        self.assertRaises(TypeError, operator.delitem, a)
152        self.assertRaises(TypeError, operator.delitem, a, None)
153        self.assertIsNone(operator.delitem(a, 1))
154        self.assertEqual(a, [4, 2, 1])
155
156    def test_floordiv(self):
157        operator = self.module
158        self.assertRaises(TypeError, operator.floordiv, 5)
159        self.assertRaises(TypeError, operator.floordiv, None, None)
160        self.assertEqual(operator.floordiv(5, 2), 2)
161
162    def test_truediv(self):
163        operator = self.module
164        self.assertRaises(TypeError, operator.truediv, 5)
165        self.assertRaises(TypeError, operator.truediv, None, None)
166        self.assertEqual(operator.truediv(5, 2), 2.5)
167
168    def test_getitem(self):
169        operator = self.module
170        a = range(10)
171        self.assertRaises(TypeError, operator.getitem)
172        self.assertRaises(TypeError, operator.getitem, a, None)
173        self.assertEqual(operator.getitem(a, 2), 2)
174
175    def test_indexOf(self):
176        operator = self.module
177        self.assertRaises(TypeError, operator.indexOf)
178        self.assertRaises(TypeError, operator.indexOf, None, None)
179        self.assertEqual(operator.indexOf([4, 3, 2, 1], 3), 1)
180        self.assertRaises(ValueError, operator.indexOf, [4, 3, 2, 1], 0)
181
182    def test_invert(self):
183        operator = self.module
184        self.assertRaises(TypeError, operator.invert)
185        self.assertRaises(TypeError, operator.invert, None)
186        self.assertEqual(operator.inv(4), -5)
187
188    def test_lshift(self):
189        operator = self.module
190        self.assertRaises(TypeError, operator.lshift)
191        self.assertRaises(TypeError, operator.lshift, None, 42)
192        self.assertEqual(operator.lshift(5, 1), 10)
193        self.assertEqual(operator.lshift(5, 0), 5)
194        self.assertRaises(ValueError, operator.lshift, 2, -1)
195
196    def test_mod(self):
197        operator = self.module
198        self.assertRaises(TypeError, operator.mod)
199        self.assertRaises(TypeError, operator.mod, None, 42)
200        self.assertEqual(operator.mod(5, 2), 1)
201
202    def test_mul(self):
203        operator = self.module
204        self.assertRaises(TypeError, operator.mul)
205        self.assertRaises(TypeError, operator.mul, None, None)
206        self.assertEqual(operator.mul(5, 2), 10)
207
208    def test_matmul(self):
209        operator = self.module
210        self.assertRaises(TypeError, operator.matmul)
211        self.assertRaises(TypeError, operator.matmul, 42, 42)
212        class M:
213            def __matmul__(self, other):
214                return other - 1
215        self.assertEqual(M() @ 42, 41)
216
217    def test_neg(self):
218        operator = self.module
219        self.assertRaises(TypeError, operator.neg)
220        self.assertRaises(TypeError, operator.neg, None)
221        self.assertEqual(operator.neg(5), -5)
222        self.assertEqual(operator.neg(-5), 5)
223        self.assertEqual(operator.neg(0), 0)
224        self.assertEqual(operator.neg(-0), 0)
225
226    def test_bitwise_or(self):
227        operator = self.module
228        self.assertRaises(TypeError, operator.or_)
229        self.assertRaises(TypeError, operator.or_, None, None)
230        self.assertEqual(operator.or_(0xa, 0x5), 0xf)
231
232    def test_pos(self):
233        operator = self.module
234        self.assertRaises(TypeError, operator.pos)
235        self.assertRaises(TypeError, operator.pos, None)
236        self.assertEqual(operator.pos(5), 5)
237        self.assertEqual(operator.pos(-5), -5)
238        self.assertEqual(operator.pos(0), 0)
239        self.assertEqual(operator.pos(-0), 0)
240
241    def test_pow(self):
242        operator = self.module
243        self.assertRaises(TypeError, operator.pow)
244        self.assertRaises(TypeError, operator.pow, None, None)
245        self.assertEqual(operator.pow(3,5), 3**5)
246        self.assertRaises(TypeError, operator.pow, 1)
247        self.assertRaises(TypeError, operator.pow, 1, 2, 3)
248
249    def test_rshift(self):
250        operator = self.module
251        self.assertRaises(TypeError, operator.rshift)
252        self.assertRaises(TypeError, operator.rshift, None, 42)
253        self.assertEqual(operator.rshift(5, 1), 2)
254        self.assertEqual(operator.rshift(5, 0), 5)
255        self.assertRaises(ValueError, operator.rshift, 2, -1)
256
257    def test_contains(self):
258        operator = self.module
259        self.assertRaises(TypeError, operator.contains)
260        self.assertRaises(TypeError, operator.contains, None, None)
261        self.assertTrue(operator.contains(range(4), 2))
262        self.assertFalse(operator.contains(range(4), 5))
263
264    def test_setitem(self):
265        operator = self.module
266        a = list(range(3))
267        self.assertRaises(TypeError, operator.setitem, a)
268        self.assertRaises(TypeError, operator.setitem, a, None, None)
269        self.assertIsNone(operator.setitem(a, 0, 2))
270        self.assertEqual(a, [2, 1, 2])
271        self.assertRaises(IndexError, operator.setitem, a, 4, 2)
272
273    def test_sub(self):
274        operator = self.module
275        self.assertRaises(TypeError, operator.sub)
276        self.assertRaises(TypeError, operator.sub, None, None)
277        self.assertEqual(operator.sub(5, 2), 3)
278
279    def test_truth(self):
280        operator = self.module
281        class C(object):
282            def __bool__(self):
283                raise SyntaxError
284        self.assertRaises(TypeError, operator.truth)
285        self.assertRaises(SyntaxError, operator.truth, C())
286        self.assertTrue(operator.truth(5))
287        self.assertTrue(operator.truth([0]))
288        self.assertFalse(operator.truth(0))
289        self.assertFalse(operator.truth([]))
290
291    def test_bitwise_xor(self):
292        operator = self.module
293        self.assertRaises(TypeError, operator.xor)
294        self.assertRaises(TypeError, operator.xor, None, None)
295        self.assertEqual(operator.xor(0xb, 0xc), 0x7)
296
297    def test_is(self):
298        operator = self.module
299        a = b = 'xyzpdq'
300        c = a[:3] + b[3:]
301        self.assertRaises(TypeError, operator.is_)
302        self.assertTrue(operator.is_(a, b))
303        self.assertFalse(operator.is_(a,c))
304
305    def test_is_not(self):
306        operator = self.module
307        a = b = 'xyzpdq'
308        c = a[:3] + b[3:]
309        self.assertRaises(TypeError, operator.is_not)
310        self.assertFalse(operator.is_not(a, b))
311        self.assertTrue(operator.is_not(a,c))
312
313    def test_attrgetter(self):
314        operator = self.module
315        class A:
316            pass
317        a = A()
318        a.name = 'arthur'
319        f = operator.attrgetter('name')
320        self.assertEqual(f(a), 'arthur')
321        self.assertRaises(TypeError, f)
322        self.assertRaises(TypeError, f, a, 'dent')
323        self.assertRaises(TypeError, f, a, surname='dent')
324        f = operator.attrgetter('rank')
325        self.assertRaises(AttributeError, f, a)
326        self.assertRaises(TypeError, operator.attrgetter, 2)
327        self.assertRaises(TypeError, operator.attrgetter)
328
329        # multiple gets
330        record = A()
331        record.x = 'X'
332        record.y = 'Y'
333        record.z = 'Z'
334        self.assertEqual(operator.attrgetter('x','z','y')(record), ('X', 'Z', 'Y'))
335        self.assertRaises(TypeError, operator.attrgetter, ('x', (), 'y'))
336
337        class C(object):
338            def __getattr__(self, name):
339                raise SyntaxError
340        self.assertRaises(SyntaxError, operator.attrgetter('foo'), C())
341
342        # recursive gets
343        a = A()
344        a.name = 'arthur'
345        a.child = A()
346        a.child.name = 'thomas'
347        f = operator.attrgetter('child.name')
348        self.assertEqual(f(a), 'thomas')
349        self.assertRaises(AttributeError, f, a.child)
350        f = operator.attrgetter('name', 'child.name')
351        self.assertEqual(f(a), ('arthur', 'thomas'))
352        f = operator.attrgetter('name', 'child.name', 'child.child.name')
353        self.assertRaises(AttributeError, f, a)
354        f = operator.attrgetter('child.')
355        self.assertRaises(AttributeError, f, a)
356        f = operator.attrgetter('.child')
357        self.assertRaises(AttributeError, f, a)
358
359        a.child.child = A()
360        a.child.child.name = 'johnson'
361        f = operator.attrgetter('child.child.name')
362        self.assertEqual(f(a), 'johnson')
363        f = operator.attrgetter('name', 'child.name', 'child.child.name')
364        self.assertEqual(f(a), ('arthur', 'thomas', 'johnson'))
365
366    def test_itemgetter(self):
367        operator = self.module
368        a = 'ABCDE'
369        f = operator.itemgetter(2)
370        self.assertEqual(f(a), 'C')
371        self.assertRaises(TypeError, f)
372        self.assertRaises(TypeError, f, a, 3)
373        self.assertRaises(TypeError, f, a, size=3)
374        f = operator.itemgetter(10)
375        self.assertRaises(IndexError, f, a)
376
377        class C(object):
378            def __getitem__(self, name):
379                raise SyntaxError
380        self.assertRaises(SyntaxError, operator.itemgetter(42), C())
381
382        f = operator.itemgetter('name')
383        self.assertRaises(TypeError, f, a)
384        self.assertRaises(TypeError, operator.itemgetter)
385
386        d = dict(key='val')
387        f = operator.itemgetter('key')
388        self.assertEqual(f(d), 'val')
389        f = operator.itemgetter('nonkey')
390        self.assertRaises(KeyError, f, d)
391
392        # example used in the docs
393        inventory = [('apple', 3), ('banana', 2), ('pear', 5), ('orange', 1)]
394        getcount = operator.itemgetter(1)
395        self.assertEqual(list(map(getcount, inventory)), [3, 2, 5, 1])
396        self.assertEqual(sorted(inventory, key=getcount),
397            [('orange', 1), ('banana', 2), ('apple', 3), ('pear', 5)])
398
399        # multiple gets
400        data = list(map(str, range(20)))
401        self.assertEqual(operator.itemgetter(2,10,5)(data), ('2', '10', '5'))
402        self.assertRaises(TypeError, operator.itemgetter(2, 'x', 5), data)
403
404    def test_methodcaller(self):
405        operator = self.module
406        self.assertRaises(TypeError, operator.methodcaller)
407        self.assertRaises(TypeError, operator.methodcaller, 12)
408        class A:
409            def foo(self, *args, **kwds):
410                return args[0] + args[1]
411            def bar(self, f=42):
412                return f
413            def baz(*args, **kwds):
414                return kwds['name'], kwds['self']
415        a = A()
416        f = operator.methodcaller('foo')
417        self.assertRaises(IndexError, f, a)
418        f = operator.methodcaller('foo', 1, 2)
419        self.assertEqual(f(a), 3)
420        self.assertRaises(TypeError, f)
421        self.assertRaises(TypeError, f, a, 3)
422        self.assertRaises(TypeError, f, a, spam=3)
423        f = operator.methodcaller('bar')
424        self.assertEqual(f(a), 42)
425        self.assertRaises(TypeError, f, a, a)
426        f = operator.methodcaller('bar', f=5)
427        self.assertEqual(f(a), 5)
428        f = operator.methodcaller('baz', name='spam', self='eggs')
429        self.assertEqual(f(a), ('spam', 'eggs'))
430
431    def test_inplace(self):
432        operator = self.module
433        class C(object):
434            def __iadd__     (self, other): return "iadd"
435            def __iand__     (self, other): return "iand"
436            def __ifloordiv__(self, other): return "ifloordiv"
437            def __ilshift__  (self, other): return "ilshift"
438            def __imod__     (self, other): return "imod"
439            def __imul__     (self, other): return "imul"
440            def __imatmul__  (self, other): return "imatmul"
441            def __ior__      (self, other): return "ior"
442            def __ipow__     (self, other): return "ipow"
443            def __irshift__  (self, other): return "irshift"
444            def __isub__     (self, other): return "isub"
445            def __itruediv__ (self, other): return "itruediv"
446            def __ixor__     (self, other): return "ixor"
447            def __getitem__(self, other): return 5  # so that C is a sequence
448        c = C()
449        self.assertEqual(operator.iadd     (c, 5), "iadd")
450        self.assertEqual(operator.iand     (c, 5), "iand")
451        self.assertEqual(operator.ifloordiv(c, 5), "ifloordiv")
452        self.assertEqual(operator.ilshift  (c, 5), "ilshift")
453        self.assertEqual(operator.imod     (c, 5), "imod")
454        self.assertEqual(operator.imul     (c, 5), "imul")
455        self.assertEqual(operator.imatmul  (c, 5), "imatmul")
456        self.assertEqual(operator.ior      (c, 5), "ior")
457        self.assertEqual(operator.ipow     (c, 5), "ipow")
458        self.assertEqual(operator.irshift  (c, 5), "irshift")
459        self.assertEqual(operator.isub     (c, 5), "isub")
460        self.assertEqual(operator.itruediv (c, 5), "itruediv")
461        self.assertEqual(operator.ixor     (c, 5), "ixor")
462        self.assertEqual(operator.iconcat  (c, c), "iadd")
463
464    def test_length_hint(self):
465        operator = self.module
466        class X(object):
467            def __init__(self, value):
468                self.value = value
469
470            def __length_hint__(self):
471                if type(self.value) is type:
472                    raise self.value
473                else:
474                    return self.value
475
476        self.assertEqual(operator.length_hint([], 2), 0)
477        self.assertEqual(operator.length_hint(iter([1, 2, 3])), 3)
478
479        self.assertEqual(operator.length_hint(X(2)), 2)
480        self.assertEqual(operator.length_hint(X(NotImplemented), 4), 4)
481        self.assertEqual(operator.length_hint(X(TypeError), 12), 12)
482        with self.assertRaises(TypeError):
483            operator.length_hint(X("abc"))
484        with self.assertRaises(ValueError):
485            operator.length_hint(X(-2))
486        with self.assertRaises(LookupError):
487            operator.length_hint(X(LookupError))
488
489    def test_dunder_is_original(self):
490        operator = self.module
491
492        names = [name for name in dir(operator) if not name.startswith('_')]
493        for name in names:
494            orig = getattr(operator, name)
495            dunder = getattr(operator, '__' + name.strip('_') + '__', None)
496            if dunder:
497                self.assertIs(dunder, orig)
498
499class PyOperatorTestCase(OperatorTestCase, unittest.TestCase):
500    module = py_operator
501
502@unittest.skipUnless(c_operator, 'requires _operator')
503class COperatorTestCase(OperatorTestCase, unittest.TestCase):
504    module = c_operator
505
506
507class OperatorPickleTestCase:
508    def copy(self, obj, proto):
509        with support.swap_item(sys.modules, 'operator', self.module):
510            pickled = pickle.dumps(obj, proto)
511        with support.swap_item(sys.modules, 'operator', self.module2):
512            return pickle.loads(pickled)
513
514    def test_attrgetter(self):
515        attrgetter = self.module.attrgetter
516        class A:
517            pass
518        a = A()
519        a.x = 'X'
520        a.y = 'Y'
521        a.z = 'Z'
522        a.t = A()
523        a.t.u = A()
524        a.t.u.v = 'V'
525        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
526            with self.subTest(proto=proto):
527                f = attrgetter('x')
528                f2 = self.copy(f, proto)
529                self.assertEqual(repr(f2), repr(f))
530                self.assertEqual(f2(a), f(a))
531                # multiple gets
532                f = attrgetter('x', 'y', 'z')
533                f2 = self.copy(f, proto)
534                self.assertEqual(repr(f2), repr(f))
535                self.assertEqual(f2(a), f(a))
536                # recursive gets
537                f = attrgetter('t.u.v')
538                f2 = self.copy(f, proto)
539                self.assertEqual(repr(f2), repr(f))
540                self.assertEqual(f2(a), f(a))
541
542    def test_itemgetter(self):
543        itemgetter = self.module.itemgetter
544        a = 'ABCDE'
545        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
546            with self.subTest(proto=proto):
547                f = itemgetter(2)
548                f2 = self.copy(f, proto)
549                self.assertEqual(repr(f2), repr(f))
550                self.assertEqual(f2(a), f(a))
551                # multiple gets
552                f = itemgetter(2, 0, 4)
553                f2 = self.copy(f, proto)
554                self.assertEqual(repr(f2), repr(f))
555                self.assertEqual(f2(a), f(a))
556
557    def test_methodcaller(self):
558        methodcaller = self.module.methodcaller
559        class A:
560            def foo(self, *args, **kwds):
561                return args[0] + args[1]
562            def bar(self, f=42):
563                return f
564            def baz(*args, **kwds):
565                return kwds['name'], kwds['self']
566        a = A()
567        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
568            with self.subTest(proto=proto):
569                f = methodcaller('bar')
570                f2 = self.copy(f, proto)
571                self.assertEqual(repr(f2), repr(f))
572                self.assertEqual(f2(a), f(a))
573                # positional args
574                f = methodcaller('foo', 1, 2)
575                f2 = self.copy(f, proto)
576                self.assertEqual(repr(f2), repr(f))
577                self.assertEqual(f2(a), f(a))
578                # keyword args
579                f = methodcaller('bar', f=5)
580                f2 = self.copy(f, proto)
581                self.assertEqual(repr(f2), repr(f))
582                self.assertEqual(f2(a), f(a))
583                f = methodcaller('baz', self='eggs', name='spam')
584                f2 = self.copy(f, proto)
585                # Can't test repr consistently with multiple keyword args
586                self.assertEqual(f2(a), f(a))
587
588class PyPyOperatorPickleTestCase(OperatorPickleTestCase, unittest.TestCase):
589    module = py_operator
590    module2 = py_operator
591
592@unittest.skipUnless(c_operator, 'requires _operator')
593class PyCOperatorPickleTestCase(OperatorPickleTestCase, unittest.TestCase):
594    module = py_operator
595    module2 = c_operator
596
597@unittest.skipUnless(c_operator, 'requires _operator')
598class CPyOperatorPickleTestCase(OperatorPickleTestCase, unittest.TestCase):
599    module = c_operator
600    module2 = py_operator
601
602@unittest.skipUnless(c_operator, 'requires _operator')
603class CCOperatorPickleTestCase(OperatorPickleTestCase, unittest.TestCase):
604    module = c_operator
605    module2 = c_operator
606
607
608if __name__ == "__main__":
609    unittest.main()
610