From: Raymond Hettinger Date: Thu, 24 Mar 2011 03:33:30 +0000 (-0700) Subject: Add tests for _source to importable and exec'able. X-Git-Tag: v3.3.0a1~2773 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f6d3e8eaef83c82416c2ca9d639ed59beba1f877;p=python Add tests for _source to importable and exec'able. Move __name__ back out of the template; the responsibility for setting __name__ lies with the caller (which knows something about the new namespace), not with the class definition (which doesn't know about the namespace it is being built in). --- diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index 5f11f6a4f4..122dfb6be3 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -234,8 +234,6 @@ class OrderedDict(dict): ################################################################################ _class_template = '''\ -__name__ = 'namedtuple_{typename}' - from builtins import property as _property, tuple as _tuple from operator import itemgetter as _itemgetter from collections import OrderedDict @@ -353,8 +351,9 @@ def namedtuple(typename, field_names, verbose=False, rename=False): for index, name in enumerate(field_names)) ) - # Execute the class definition string in a temporary namespace - namespace = {} + # Execute the template string in a temporary namespace and + # support tracing utilities by setting a value for frame.f_globals['__name__'] + namespace = dict(__name__='namedtuple_%s' % typename) try: exec(class_definition, namespace) except SyntaxError as e: diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index cdc7db9a7f..4ef27ce2c5 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -1,6 +1,7 @@ """Unit tests for collections.py.""" import unittest, doctest, operator +from test.support import TESTFN, forget, unlink import inspect from test import support from collections import namedtuple, Counter, OrderedDict, _count_elements @@ -327,6 +328,39 @@ class TestNamedTuple(unittest.TestCase): pass self.assertEqual(repr(B(1)), 'B(x=1)') + def test_source(self): + # verify that _source can be run through exec() + tmp = namedtuple('Color', 'red green blue') + self.assertNotIn('Color', globals()) + exec(tmp._source, globals()) + self.assertIn('Color', globals()) + c = Color(10, 20, 30) + self.assertEqual((c.red, c.green, c.blue), (10, 20, 30)) + self.assertEqual(Color._fields, ('red', 'green', 'blue')) + + def test_source_importable(self): + tmp = namedtuple('Color', 'hue sat val') + + compiled = None + source = TESTFN + '.py' + with open(source, 'w') as f: + print(tmp._source, file=f) + + if TESTFN in sys.modules: + del sys.modules[TESTFN] + try: + mod = __import__(TESTFN) + compiled = mod.__file__ + Color = mod.Color + c = Color(10, 20, 30) + self.assertEqual((c.hue, c.sat, c.val), (10, 20, 30)) + self.assertEqual(Color._fields, ('hue', 'sat', 'val')) + finally: + forget(TESTFN) + if compiled: + unlink(compiled) + unlink(source) + ################################################################################ ### Abstract Base Classes