blob: 5d1f478dfe350c2c1d310bb4e7d750b2facb6cea [file] [log] [blame]
Raymond Hettinger8a99b502003-06-23 13:36:57 +00001import unittest
Raymond Hettinger8a99b502003-06-23 13:36:57 +00002import sys
Martin v. Löwis618dc5e2008-03-30 20:03:44 +00003import _ast
Benjamin Petersonee8712c2008-05-20 21:35:26 +00004from test import support
Peter Schneider-Kampfdee0f02000-07-25 22:15:45 +00005
Raymond Hettinger8a99b502003-06-23 13:36:57 +00006class TestSpecifics(unittest.TestCase):
Jeremy Hylton778e2652001-11-09 19:50:08 +00007
Raymond Hettinger8a99b502003-06-23 13:36:57 +00008 def test_debug_assignment(self):
9 # catch assignments to __debug__
10 self.assertRaises(SyntaxError, compile, '__debug__ = 1', '?', 'single')
Georg Brandl1a3284e2007-12-02 09:40:06 +000011 import builtins
12 prev = builtins.__debug__
13 setattr(builtins, '__debug__', 'sure')
14 setattr(builtins, '__debug__', prev)
Jeremy Hylton778e2652001-11-09 19:50:08 +000015
Raymond Hettinger8a99b502003-06-23 13:36:57 +000016 def test_argument_handling(self):
17 # detect duplicate positional and keyword arguments
18 self.assertRaises(SyntaxError, eval, 'lambda a,a:0')
19 self.assertRaises(SyntaxError, eval, 'lambda a,a=1:0')
20 self.assertRaises(SyntaxError, eval, 'lambda a=1,a=1:0')
Benjamin Petersonec19d952008-06-30 15:01:21 +000021 self.assertRaises(SyntaxError, exec, 'def f(a, a): pass')
22 self.assertRaises(SyntaxError, exec, 'def f(a = 0, a = 1): pass')
23 self.assertRaises(SyntaxError, exec, 'def f(a): global a; a = 1')
Jeremy Hylton778e2652001-11-09 19:50:08 +000024
Raymond Hettinger8a99b502003-06-23 13:36:57 +000025 def test_syntax_error(self):
26 self.assertRaises(SyntaxError, compile, "1+*3", "filename", "exec")
Peter Schneider-Kampfdee0f02000-07-25 22:15:45 +000027
Guido van Rossumcd16bf62007-06-13 18:07:49 +000028 def test_none_keyword_arg(self):
29 self.assertRaises(SyntaxError, compile, "f(None=1)", "<string>", "exec")
30
Raymond Hettinger8a99b502003-06-23 13:36:57 +000031 def test_duplicate_global_local(self):
Benjamin Petersonec19d952008-06-30 15:01:21 +000032 self.assertRaises(SyntaxError, exec, 'def f(a): global a; a = 1')
Peter Schneider-Kampfdee0f02000-07-25 22:15:45 +000033
Raymond Hettinger66bd2332004-08-02 08:30:07 +000034 def test_exec_with_general_mapping_for_locals(self):
35
36 class M:
37 "Test mapping interface versus possible calls from eval()."
38 def __getitem__(self, key):
39 if key == 'a':
40 return 12
41 raise KeyError
42 def __setitem__(self, key, value):
43 self.results = (key, value)
Guido van Rossum63eecc72007-02-22 23:55:25 +000044 def keys(self):
45 return list('xyz')
Raymond Hettinger66bd2332004-08-02 08:30:07 +000046
47 m = M()
48 g = globals()
Georg Brandl7cae87c2006-09-06 06:51:57 +000049 exec('z = a', g, m)
Raymond Hettinger66bd2332004-08-02 08:30:07 +000050 self.assertEqual(m.results, ('z', 12))
51 try:
Georg Brandl7cae87c2006-09-06 06:51:57 +000052 exec('z = b', g, m)
Raymond Hettinger66bd2332004-08-02 08:30:07 +000053 except NameError:
54 pass
55 else:
56 self.fail('Did not detect a KeyError')
Georg Brandl7cae87c2006-09-06 06:51:57 +000057 exec('z = dir()', g, m)
Raymond Hettinger66bd2332004-08-02 08:30:07 +000058 self.assertEqual(m.results, ('z', list('xyz')))
Georg Brandl7cae87c2006-09-06 06:51:57 +000059 exec('z = globals()', g, m)
Raymond Hettinger66bd2332004-08-02 08:30:07 +000060 self.assertEqual(m.results, ('z', g))
Georg Brandl7cae87c2006-09-06 06:51:57 +000061 exec('z = locals()', g, m)
Raymond Hettinger66bd2332004-08-02 08:30:07 +000062 self.assertEqual(m.results, ('z', m))
Benjamin Petersonec19d952008-06-30 15:01:21 +000063 self.assertRaises(TypeError, exec, 'z = b', m)
Raymond Hettinger66bd2332004-08-02 08:30:07 +000064
65 class A:
66 "Non-mapping"
67 pass
68 m = A()
Benjamin Petersonec19d952008-06-30 15:01:21 +000069 self.assertRaises(TypeError, exec, 'z = a', g, m)
Raymond Hettinger66bd2332004-08-02 08:30:07 +000070
71 # Verify that dict subclasses work as well
72 class D(dict):
73 def __getitem__(self, key):
74 if key == 'a':
75 return 12
76 return dict.__getitem__(self, key)
77 d = D()
Georg Brandl7cae87c2006-09-06 06:51:57 +000078 exec('z = a', g, d)
Raymond Hettinger66bd2332004-08-02 08:30:07 +000079 self.assertEqual(d['z'], 12)
80
Neal Norwitz6ab080c2005-10-24 00:08:10 +000081 def test_extended_arg(self):
82 longexpr = 'x = x or ' + '-x' * 2500
Georg Brandl7cae87c2006-09-06 06:51:57 +000083 g = {}
Neal Norwitz6ab080c2005-10-24 00:08:10 +000084 code = '''
85def f(x):
86 %s
87 %s
88 %s
89 %s
90 %s
91 %s
92 %s
93 %s
94 %s
95 %s
96 # the expressions above have no effect, x == argument
97 while x:
98 x -= 1
99 # EXTENDED_ARG/JUMP_ABSOLUTE here
100 return x
101''' % ((longexpr,)*10)
Georg Brandl7cae87c2006-09-06 06:51:57 +0000102 exec(code, g)
103 self.assertEqual(g['f'](5), 0)
Neal Norwitz6ab080c2005-10-24 00:08:10 +0000104
Raymond Hettinger8a99b502003-06-23 13:36:57 +0000105 def test_argument_order(self):
Benjamin Petersonec19d952008-06-30 15:01:21 +0000106 self.assertRaises(SyntaxError, exec, 'def f(a=1, b): pass')
Jeremy Hylton121b6eb2001-02-19 23:53:42 +0000107
Raymond Hettinger8a99b502003-06-23 13:36:57 +0000108 def test_float_literals(self):
109 # testing bad float literals
110 self.assertRaises(SyntaxError, eval, "2e")
111 self.assertRaises(SyntaxError, eval, "2.0e+")
112 self.assertRaises(SyntaxError, eval, "1e-")
113 self.assertRaises(SyntaxError, eval, "3-4e/21")
Jeremy Hylton121b6eb2001-02-19 23:53:42 +0000114
Raymond Hettinger8a99b502003-06-23 13:36:57 +0000115 def test_indentation(self):
116 # testing compile() of indented block w/o trailing newline"
117 s = """
Guido van Rossum4b499dd32003-02-13 22:07:59 +0000118if 1:
119 if 2:
120 pass"""
Raymond Hettinger8a99b502003-06-23 13:36:57 +0000121 compile(s, "<string>", "exec")
122
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000123 # This test is probably specific to CPython and may not generalize
124 # to other implementations. We are trying to ensure that when
125 # the first line of code starts after 256, correct line numbers
126 # in tracebacks are still produced.
127 def test_leading_newlines(self):
128 s256 = "".join(["\n"] * 256 + ["spam"])
129 co = compile(s256, 'fn', 'exec')
130 self.assertEqual(co.co_firstlineno, 257)
Guido van Rossum98297ee2007-11-06 21:34:58 +0000131 self.assertEqual(co.co_lnotab, bytes())
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000132
Raymond Hettinger8a99b502003-06-23 13:36:57 +0000133 def test_literals_with_leading_zeroes(self):
134 for arg in ["077787", "0xj", "0x.", "0e", "090000000000000",
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000135 "080000000000000", "000000000000009", "000000000000008",
136 "0b42", "0BADCAFE", "0o123456789", "0b1.1", "0o4.2",
137 "0b101j2", "0o153j2", "0b100e1", "0o777e1", "0777",
138 "000777", "000000000000007"]:
Raymond Hettinger8a99b502003-06-23 13:36:57 +0000139 self.assertRaises(SyntaxError, eval, arg)
140
Raymond Hettinger8a99b502003-06-23 13:36:57 +0000141 self.assertEqual(eval("0xff"), 255)
Raymond Hettinger8a99b502003-06-23 13:36:57 +0000142 self.assertEqual(eval("0777."), 777)
143 self.assertEqual(eval("0777.0"), 777)
144 self.assertEqual(eval("000000000000000000000000000000000000000000000000000777e0"), 777)
145 self.assertEqual(eval("0777e1"), 7770)
146 self.assertEqual(eval("0e0"), 0)
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000147 self.assertEqual(eval("0000e-012"), 0)
Raymond Hettinger8a99b502003-06-23 13:36:57 +0000148 self.assertEqual(eval("09.5"), 9.5)
149 self.assertEqual(eval("0777j"), 777j)
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000150 self.assertEqual(eval("000"), 0)
Raymond Hettinger8a99b502003-06-23 13:36:57 +0000151 self.assertEqual(eval("00j"), 0j)
152 self.assertEqual(eval("00.0"), 0)
153 self.assertEqual(eval("0e3"), 0)
154 self.assertEqual(eval("090000000000000."), 90000000000000.)
155 self.assertEqual(eval("090000000000000.0000000000000000000000"), 90000000000000.)
156 self.assertEqual(eval("090000000000000e0"), 90000000000000.)
157 self.assertEqual(eval("090000000000000e-0"), 90000000000000.)
158 self.assertEqual(eval("090000000000000j"), 90000000000000j)
Raymond Hettinger8a99b502003-06-23 13:36:57 +0000159 self.assertEqual(eval("000000000000008."), 8.)
160 self.assertEqual(eval("000000000000009."), 9.)
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000161 self.assertEqual(eval("0b101010"), 42)
162 self.assertEqual(eval("-0b000000000010"), -2)
163 self.assertEqual(eval("0o777"), 511)
164 self.assertEqual(eval("-0o0000010"), -8)
Raymond Hettinger8a99b502003-06-23 13:36:57 +0000165
166 def test_unary_minus(self):
167 # Verify treatment of unary minus on negative numbers SF bug #660455
Christian Heimesa37d4c62007-12-04 23:02:19 +0000168 if sys.maxsize == 2147483647:
Guido van Rossum6c9e1302003-11-29 23:52:13 +0000169 # 32-bit machine
170 all_one_bits = '0xffffffff'
Guido van Rossume2a383d2007-01-15 16:59:06 +0000171 self.assertEqual(eval(all_one_bits), 4294967295)
172 self.assertEqual(eval("-" + all_one_bits), -4294967295)
Christian Heimesa37d4c62007-12-04 23:02:19 +0000173 elif sys.maxsize == 9223372036854775807:
Guido van Rossum6c9e1302003-11-29 23:52:13 +0000174 # 64-bit machine
Raymond Hettinger8a99b502003-06-23 13:36:57 +0000175 all_one_bits = '0xffffffffffffffff'
Guido van Rossume2a383d2007-01-15 16:59:06 +0000176 self.assertEqual(eval(all_one_bits), 18446744073709551615)
177 self.assertEqual(eval("-" + all_one_bits), -18446744073709551615)
Guido van Rossum6c9e1302003-11-29 23:52:13 +0000178 else:
179 self.fail("How many bits *does* this machine have???")
Christian Heimesa37d4c62007-12-04 23:02:19 +0000180 # Verify treatment of contant folding on -(sys.maxsize+1)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000181 # i.e. -2147483648 on 32 bit platforms. Should return int, not long.
Christian Heimesa37d4c62007-12-04 23:02:19 +0000182 self.assertTrue(isinstance(eval("%s" % (-sys.maxsize - 1)), int))
183 self.assertTrue(isinstance(eval("%s" % (-sys.maxsize - 2)), int))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000184
Christian Heimesa37d4c62007-12-04 23:02:19 +0000185 if sys.maxsize == 9223372036854775807:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000186 def test_32_63_bit_values(self):
187 a = +4294967296 # 1 << 32
188 b = -4294967296 # 1 << 32
189 c = +281474976710656 # 1 << 48
190 d = -281474976710656 # 1 << 48
191 e = +4611686018427387904 # 1 << 62
192 f = -4611686018427387904 # 1 << 62
193 g = +9223372036854775807 # 1 << 63 - 1
194 h = -9223372036854775807 # 1 << 63 - 1
195
Neal Norwitz221085d2007-02-25 20:55:47 +0000196 for variable in self.test_32_63_bit_values.__code__.co_consts:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000197 if variable is not None:
198 self.assertTrue(isinstance(variable, int))
Raymond Hettinger8a99b502003-06-23 13:36:57 +0000199
200 def test_sequence_unpacking_error(self):
201 # Verify sequence packing/unpacking with "or". SF bug #757818
202 i,j = (1, -1) or (-1, 1)
203 self.assertEqual(i, 1)
204 self.assertEqual(j, -1)
Guido van Rossum4b499dd32003-02-13 22:07:59 +0000205
Raymond Hettinger11a70c72004-07-17 21:46:25 +0000206 def test_none_assignment(self):
207 stmts = [
208 'None = 0',
209 'None += 0',
210 '__builtins__.None = 0',
211 'def None(): pass',
212 'class None: pass',
213 '(a, None) = 0, 0',
214 'for None in range(10): pass',
215 'def f(None): pass',
216 ]
217 for stmt in stmts:
218 stmt += "\n"
219 self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'single')
220 self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec')
Tim Petersd507dab2001-08-30 20:51:59 +0000221
Anthony Baxter1a4ddae2004-08-31 10:07:13 +0000222 def test_import(self):
223 succeed = [
224 'import sys',
225 'import os, sys',
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000226 'import os as bar',
227 'import os.path as bar',
Anthony Baxter1a4ddae2004-08-31 10:07:13 +0000228 'from __future__ import nested_scopes, generators',
229 'from __future__ import (nested_scopes,\ngenerators)',
230 'from __future__ import (nested_scopes,\ngenerators,)',
231 'from sys import stdin, stderr, stdout',
232 'from sys import (stdin, stderr,\nstdout)',
233 'from sys import (stdin, stderr,\nstdout,)',
234 'from sys import (stdin\n, stderr, stdout)',
235 'from sys import (stdin\n, stderr, stdout,)',
236 'from sys import stdin as si, stdout as so, stderr as se',
237 'from sys import (stdin as si, stdout as so, stderr as se)',
238 'from sys import (stdin as si, stdout as so, stderr as se,)',
239 ]
240 fail = [
241 'import (os, sys)',
242 'import (os), (sys)',
243 'import ((os), (sys))',
244 'import (sys',
245 'import sys)',
246 'import (os,)',
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000247 'import os As bar',
248 'import os.path a bar',
249 'from sys import stdin As stdout',
250 'from sys import stdin a stdout',
Anthony Baxter1a4ddae2004-08-31 10:07:13 +0000251 'from (sys) import stdin',
252 'from __future__ import (nested_scopes',
253 'from __future__ import nested_scopes)',
254 'from __future__ import nested_scopes,\ngenerators',
255 'from sys import (stdin',
256 'from sys import stdin)',
257 'from sys import stdin, stdout,\nstderr',
258 'from sys import stdin si',
259 'from sys import stdin,'
260 'from sys import (*)',
261 'from sys import (stdin,, stdout, stderr)',
262 'from sys import (stdin, stdout),',
263 ]
264 for stmt in succeed:
265 compile(stmt, 'tmp', 'exec')
266 for stmt in fail:
267 self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec')
268
Raymond Hettinger9047c8f2004-10-24 00:10:06 +0000269 def test_for_distinct_code_objects(self):
270 # SF bug 1048870
271 def f():
272 f1 = lambda x=1: x
273 f2 = lambda x=2: x
274 return f1, f2
275 f1, f2 = f()
Neal Norwitz221085d2007-02-25 20:55:47 +0000276 self.assertNotEqual(id(f1.__code__), id(f2.__code__))
Raymond Hettinger9047c8f2004-10-24 00:10:06 +0000277
Guido van Rossumf8761c72007-07-22 20:01:13 +0000278## def test_unicode_encoding(self):
279## code = "# -*- coding: utf-8 -*-\npass\n"
280## self.assertRaises(SyntaxError, compile, code, "tmp", "exec")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000281
Nick Coghlaneadee9a2006-03-13 12:31:58 +0000282 def test_subscripts(self):
283 # SF bug 1448804
284 # Class to make testing subscript results easy
285 class str_map(object):
286 def __init__(self):
287 self.data = {}
288 def __getitem__(self, key):
289 return self.data[str(key)]
290 def __setitem__(self, key, value):
291 self.data[str(key)] = value
292 def __delitem__(self, key):
293 del self.data[str(key)]
294 def __contains__(self, key):
295 return str(key) in self.data
296 d = str_map()
297 # Index
298 d[1] = 1
299 self.assertEqual(d[1], 1)
300 d[1] += 1
301 self.assertEqual(d[1], 2)
302 del d[1]
303 self.assertEqual(1 in d, False)
304 # Tuple of indices
305 d[1, 1] = 1
306 self.assertEqual(d[1, 1], 1)
307 d[1, 1] += 1
308 self.assertEqual(d[1, 1], 2)
309 del d[1, 1]
310 self.assertEqual((1, 1) in d, False)
311 # Simple slice
312 d[1:2] = 1
313 self.assertEqual(d[1:2], 1)
314 d[1:2] += 1
315 self.assertEqual(d[1:2], 2)
316 del d[1:2]
317 self.assertEqual(slice(1, 2) in d, False)
318 # Tuple of simple slices
319 d[1:2, 1:2] = 1
320 self.assertEqual(d[1:2, 1:2], 1)
321 d[1:2, 1:2] += 1
322 self.assertEqual(d[1:2, 1:2], 2)
323 del d[1:2, 1:2]
324 self.assertEqual((slice(1, 2), slice(1, 2)) in d, False)
325 # Extended slice
326 d[1:2:3] = 1
327 self.assertEqual(d[1:2:3], 1)
328 d[1:2:3] += 1
329 self.assertEqual(d[1:2:3], 2)
330 del d[1:2:3]
331 self.assertEqual(slice(1, 2, 3) in d, False)
332 # Tuple of extended slices
333 d[1:2:3, 1:2:3] = 1
334 self.assertEqual(d[1:2:3, 1:2:3], 1)
335 d[1:2:3, 1:2:3] += 1
336 self.assertEqual(d[1:2:3, 1:2:3], 2)
337 del d[1:2:3, 1:2:3]
338 self.assertEqual((slice(1, 2, 3), slice(1, 2, 3)) in d, False)
339 # Ellipsis
340 d[...] = 1
341 self.assertEqual(d[...], 1)
342 d[...] += 1
343 self.assertEqual(d[...], 2)
344 del d[...]
345 self.assertEqual(Ellipsis in d, False)
346 # Tuple of Ellipses
347 d[..., ...] = 1
348 self.assertEqual(d[..., ...], 1)
349 d[..., ...] += 1
350 self.assertEqual(d[..., ...], 2)
351 del d[..., ...]
352 self.assertEqual((Ellipsis, Ellipsis) in d, False)
353
Guido van Rossum0240b922007-02-26 21:23:50 +0000354 def test_annotation_limit(self):
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000355 # 16 bits are available for # of annotations, but only 8 bits are
356 # available for the parameter count, hence 255
Guido van Rossum0240b922007-02-26 21:23:50 +0000357 # is the max. Ensure the result of too many annotations is a
358 # SyntaxError.
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000359 s = "def f(%s): pass"
360 s %= ', '.join('a%d:%d' % (i,i) for i in range(256))
Guido van Rossum0240b922007-02-26 21:23:50 +0000361 self.assertRaises(SyntaxError, compile, s, '?', 'exec')
362 # Test that the max # of annotations compiles.
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000363 s = "def f(%s): pass"
364 s %= ', '.join('a%d:%d' % (i,i) for i in range(255))
Guido van Rossum0240b922007-02-26 21:23:50 +0000365 compile(s, '?', 'exec')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000366
367 def test_mangling(self):
368 class A:
369 def f():
370 __mangled = 1
371 __not_mangled__ = 2
372 import __mangled_mod
373 import __package__.module
374
Georg Brandlab91fde2009-08-13 08:51:18 +0000375 self.assertTrue("_A__mangled" in A.f.__code__.co_varnames)
376 self.assertTrue("__not_mangled__" in A.f.__code__.co_varnames)
377 self.assertTrue("_A__mangled_mod" in A.f.__code__.co_varnames)
378 self.assertTrue("__package__" in A.f.__code__.co_varnames)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000379
Martin v. Löwis618dc5e2008-03-30 20:03:44 +0000380 def test_compile_ast(self):
381 fname = __file__
382 if fname.lower().endswith(('pyc', 'pyo')):
383 fname = fname[:-1]
384 with open(fname, 'r') as f:
385 fcontents = f.read()
386 sample_code = [
387 ['<assign>', 'x = 5'],
388 ['<ifblock>', """if True:\n pass\n"""],
389 ['<forblock>', """for n in [1, 2, 3]:\n print(n)\n"""],
390 ['<deffunc>', """def foo():\n pass\nfoo()\n"""],
391 [fname, fcontents],
392 ]
393
394 for fname, code in sample_code:
395 co1 = compile(code, '%s1' % fname, 'exec')
396 ast = compile(code, '%s2' % fname, 'exec', _ast.PyCF_ONLY_AST)
Georg Brandlab91fde2009-08-13 08:51:18 +0000397 self.assertTrue(type(ast) == _ast.Module)
Martin v. Löwis618dc5e2008-03-30 20:03:44 +0000398 co2 = compile(ast, '%s3' % fname, 'exec')
399 self.assertEqual(co1, co2)
Neal Norwitzdb4115f2008-03-31 04:20:05 +0000400 # the code object's filename comes from the second compilation step
401 self.assertEqual(co2.co_filename, '%s3' % fname)
402
403 # raise exception when node type doesn't match with compile mode
404 co1 = compile('print(1)', '<string>', 'exec', _ast.PyCF_ONLY_AST)
405 self.assertRaises(TypeError, compile, co1, '<ast>', 'eval')
406
407 # raise exception when node type is no start node
408 self.assertRaises(TypeError, compile, _ast.If(), '<ast>', 'exec')
409
410 # raise exception when node has invalid children
411 ast = _ast.Module()
412 ast.body = [_ast.BoolOp()]
413 self.assertRaises(TypeError, compile, ast, '<ast>', 'exec')
Martin v. Löwis618dc5e2008-03-30 20:03:44 +0000414
415
Raymond Hettinger8a99b502003-06-23 13:36:57 +0000416def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000417 support.run_unittest(TestSpecifics)
Tim Petersd507dab2001-08-30 20:51:59 +0000418
Raymond Hettinger8a99b502003-06-23 13:36:57 +0000419if __name__ == "__main__":
420 test_main()