13e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton"""This module includes tests of the code object representation.
23e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton
33e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton>>> def f(x):
43e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton...     def g(y):
53e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton...         return x + y
63e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton...     return g
73e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton...
83e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton
9221085de89afa861c49ff4306979dbbad949d393Neal Norwitz>>> dump(f.__code__)
103e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonname: f
113e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonargcount: 1
124f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumkwonlyargcount: 0
133e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonnames: ()
143e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonvarnames: ('x', 'g')
153e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltoncellvars: ('x',)
163e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonfreevars: ()
173e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonnlocals: 2
183e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonflags: 3
1986a36b500a7f7581194382ce4df914e4bb487873Antoine Pitrouconsts: ('None', '<code object g>', "'f.<locals>.g'")
203e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton
21221085de89afa861c49ff4306979dbbad949d393Neal Norwitz>>> dump(f(4).__code__)
223e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonname: g
233e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonargcount: 1
244f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumkwonlyargcount: 0
253e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonnames: ()
263e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonvarnames: ('y',)
273e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltoncellvars: ()
283e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonfreevars: ('x',)
293e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonnlocals: 1
303e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonflags: 19
313e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonconsts: ('None',)
323e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton
333e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton>>> def h(x, y):
343e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton...     a = x + y
353e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton...     b = x - y
363e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton...     c = a * b
373e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton...     return c
38536cf99536bce562cfcb44a856fac1c84b9de4c3Tim Peters...
394f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossum
40221085de89afa861c49ff4306979dbbad949d393Neal Norwitz>>> dump(h.__code__)
413e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonname: h
423e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonargcount: 2
434f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumkwonlyargcount: 0
443e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonnames: ()
453e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonvarnames: ('x', 'y', 'a', 'b', 'c')
463e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltoncellvars: ()
473e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonfreevars: ()
483e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonnlocals: 5
493e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonflags: 67
503e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonconsts: ('None',)
513e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton
523e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton>>> def attrs(obj):
537131f84400d85d35d0323c262cc0926bef5a18cfGuido van Rossum...     print(obj.attr1)
547131f84400d85d35d0323c262cc0926bef5a18cfGuido van Rossum...     print(obj.attr2)
557131f84400d85d35d0323c262cc0926bef5a18cfGuido van Rossum...     print(obj.attr3)
563e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton
57221085de89afa861c49ff4306979dbbad949d393Neal Norwitz>>> dump(attrs.__code__)
583e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonname: attrs
593e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonargcount: 1
604f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumkwonlyargcount: 0
6188fc6646d1b97cb3ba6188808e7c016884d44a73Georg Brandlnames: ('print', 'attr1', 'attr2', 'attr3')
623e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonvarnames: ('obj',)
633e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltoncellvars: ()
643e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonfreevars: ()
653e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonnlocals: 1
663e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonflags: 67
673e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonconsts: ('None',)
683e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton
690e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters>>> def optimize_away():
700e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters...     'doc string'
710e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters...     'not a docstring'
720e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters...     53
73e2a383d062434c05b73031f0da57fe82b9da8942Guido van Rossum...     0x53
740e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters
75221085de89afa861c49ff4306979dbbad949d393Neal Norwitz>>> dump(optimize_away.__code__)
760e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Woutersname: optimize_away
770e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Woutersargcount: 0
784f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumkwonlyargcount: 0
790e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Woutersnames: ()
800e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Woutersvarnames: ()
810e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouterscellvars: ()
820e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Woutersfreevars: ()
830e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Woutersnlocals: 0
840e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Woutersflags: 67
850e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Woutersconsts: ("'doc string'", 'None')
860e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters
874f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossum>>> def keywordonly_args(a,b,*,k1):
884f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossum...     return a,b,k1
894f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossum...
904f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossum
91221085de89afa861c49ff4306979dbbad949d393Neal Norwitz>>> dump(keywordonly_args.__code__)
924f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumname: keywordonly_args
934f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumargcount: 2
944f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumkwonlyargcount: 1
954f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumnames: ()
964f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumvarnames: ('a', 'b', 'k1')
974f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumcellvars: ()
984f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumfreevars: ()
994f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumnlocals: 3
1004f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumflags: 67
1014f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumconsts: ('None',)
1024f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossum
1033e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton"""
1043e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton
10500a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchakaimport sys
1067b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalottiimport unittest
1074222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winterimport weakref
1085cfc79deaeabf4af3c767665098a37da9f375edaSerhiy Storchakafrom test.support import run_doctest, run_unittest, cpython_only
1097b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalotti
1104222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter
1113e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltondef consts(t):
1123e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton    """Yield a doctest-safe sequence of object reprs."""
1133e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton    for elt in t:
1143e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton        r = repr(elt)
1153e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton        if r.startswith("<code object"):
1163e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton            yield "<code object %s>" % elt.co_name
1173e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton        else:
1183e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton            yield r
1193e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton
1203e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltondef dump(co):
1213e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton    """Print out a text representation of a code object."""
1224f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossum    for attr in ["name", "argcount", "kwonlyargcount", "names", "varnames",
1234f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossum                 "cellvars", "freevars", "nlocals", "flags"]:
124be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum        print("%s: %s" % (attr, getattr(co, "co_" + attr)))
125be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum    print("consts:", tuple(consts(co.co_consts)))
1263e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton
1277b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalotti
1287b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalotticlass CodeTest(unittest.TestCase):
1297b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalotti
1305cfc79deaeabf4af3c767665098a37da9f375edaSerhiy Storchaka    @cpython_only
1317b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalotti    def test_newempty(self):
1325cfc79deaeabf4af3c767665098a37da9f375edaSerhiy Storchaka        import _testcapi
1337b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalotti        co = _testcapi.code_newempty("filename", "funcname", 15)
134b3aedd48621ed9d33b5f42f946b256bce4a50673Ezio Melotti        self.assertEqual(co.co_filename, "filename")
135b3aedd48621ed9d33b5f42f946b256bce4a50673Ezio Melotti        self.assertEqual(co.co_name, "funcname")
136b3aedd48621ed9d33b5f42f946b256bce4a50673Ezio Melotti        self.assertEqual(co.co_firstlineno, 15)
1377b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalotti
13809f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka
13909f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchakadef isinterned(s):
14009f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka    return s is sys.intern(('_' + s + '_')[1:-1])
14109f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka
14200a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchakaclass CodeConstsTest(unittest.TestCase):
14300a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka
14400a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka    def find_const(self, consts, value):
14500a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka        for v in consts:
14600a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka            if v == value:
14700a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka                return v
14809f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka        self.assertIn(value, consts)  # raises an exception
14909f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka        self.fail('Should never be reached')
15000a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka
15100a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka    def assertIsInterned(self, s):
15209f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka        if not isinterned(s):
15300a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka            self.fail('String %r is not interned' % (s,))
15400a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka
15509f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka    def assertIsNotInterned(self, s):
15609f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka        if isinterned(s):
15709f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka            self.fail('String %r is interned' % (s,))
15809f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka
15900a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka    @cpython_only
16000a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka    def test_interned_string(self):
16100a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka        co = compile('res = "str_value"', '?', 'exec')
16200a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka        v = self.find_const(co.co_consts, 'str_value')
16300a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka        self.assertIsInterned(v)
16400a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka
16500a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka    @cpython_only
16600a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka    def test_interned_string_in_tuple(self):
16700a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka        co = compile('res = ("str_value",)', '?', 'exec')
16800a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka        v = self.find_const(co.co_consts, ('str_value',))
16900a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka        self.assertIsInterned(v[0])
17000a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka
17100a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka    @cpython_only
17200a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka    def test_interned_string_in_frozenset(self):
17300a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka        co = compile('res = a in {"str_value"}', '?', 'exec')
17400a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka        v = self.find_const(co.co_consts, frozenset(('str_value',)))
17500a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka        self.assertIsInterned(tuple(v)[0])
17600a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka
17700a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka    @cpython_only
17800a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka    def test_interned_string_default(self):
17900a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka        def f(a='str_value'):
18000a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka            return a
18100a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka        self.assertIsInterned(f())
18200a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka
18309f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka    @cpython_only
18409f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka    def test_interned_string_with_null(self):
18509f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka        co = compile(r'res = "str\0value!"', '?', 'exec')
18609f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka        v = self.find_const(co.co_consts, 'str\0value!')
18709f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka        self.assertIsNotInterned(v)
18809f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka
1897b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalotti
1904222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winterclass CodeWeakRefTest(unittest.TestCase):
1914222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter
1924222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter    def test_basic(self):
1934222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        # Create a code object in a clean environment so that we know we have
1944222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        # the only reference to it left.
1954222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        namespace = {}
1964222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        exec("def f(): pass", globals(), namespace)
1974222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        f = namespace["f"]
1984222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        del namespace
1994222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter
2004222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        self.called = False
2014222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        def callback(code):
2024222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter            self.called = True
2034222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter
2044222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        # f is now the last reference to the function, and through it, the code
2054222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        # object.  While we hold it, check that we can create a weakref and
2064222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        # deref it.  Then delete it, and check that the callback gets called and
2074222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        # the reference dies.
2084222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        coderef = weakref.ref(f.__code__, callback)
2094222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        self.assertTrue(bool(coderef()))
2104222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        del f
2114222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        self.assertFalse(bool(coderef()))
2124222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter        self.assertTrue(self.called)
2134222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter
2144222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter
2153e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltondef test_main(verbose=None):
2163e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton    from test import test_code
2173e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton    run_doctest(test_code, verbose)
21800a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka    run_unittest(CodeTest, CodeConstsTest, CodeWeakRefTest)
219ad9d48d865706a76e86b8929be5f981971206657Benjamin Peterson
220ad9d48d865706a76e86b8929be5f981971206657Benjamin Peterson
2214222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winterif __name__ == "__main__":
222ad9d48d865706a76e86b8929be5f981971206657Benjamin Peterson    test_main()
223