Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f6d3e8e

Browse files
committed
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).
1 parent 5d43cff commit f6d3e8e

2 files changed

Lines changed: 37 additions & 4 deletions

File tree

Lib/collections/__init__.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,6 @@ def __eq__(self, other):
234234
################################################################################
235235

236236
_class_template = '''\
237-
__name__ = 'namedtuple_{typename}'
238-
239237
from builtins import property as _property, tuple as _tuple
240238
from operator import itemgetter as _itemgetter
241239
from collections import OrderedDict
@@ -353,8 +351,9 @@ def namedtuple(typename, field_names, verbose=False, rename=False):
353351
for index, name in enumerate(field_names))
354352
)
355353

356-
# Execute the class definition string in a temporary namespace
357-
namespace = {}
354+
# Execute the template string in a temporary namespace and
355+
# support tracing utilities by setting a value for frame.f_globals['__name__']
356+
namespace = dict(__name__='namedtuple_%s' % typename)
358357
try:
359358
exec(class_definition, namespace)
360359
except SyntaxError as e:

Lib/test/test_collections.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Unit tests for collections.py."""
22

33
import unittest, doctest, operator
4+
from test.support import TESTFN, forget, unlink
45
import inspect
56
from test import support
67
from collections import namedtuple, Counter, OrderedDict, _count_elements
@@ -327,6 +328,39 @@ class B(A):
327328
pass
328329
self.assertEqual(repr(B(1)), 'B(x=1)')
329330

331+
def test_source(self):
332+
# verify that _source can be run through exec()
333+
tmp = namedtuple('Color', 'red green blue')
334+
self.assertNotIn('Color', globals())
335+
exec(tmp._source, globals())
336+
self.assertIn('Color', globals())
337+
c = Color(10, 20, 30)
338+
self.assertEqual((c.red, c.green, c.blue), (10, 20, 30))
339+
self.assertEqual(Color._fields, ('red', 'green', 'blue'))
340+
341+
def test_source_importable(self):
342+
tmp = namedtuple('Color', 'hue sat val')
343+
344+
compiled = None
345+
source = TESTFN + '.py'
346+
with open(source, 'w') as f:
347+
print(tmp._source, file=f)
348+
349+
if TESTFN in sys.modules:
350+
del sys.modules[TESTFN]
351+
try:
352+
mod = __import__(TESTFN)
353+
compiled = mod.__file__
354+
Color = mod.Color
355+
c = Color(10, 20, 30)
356+
self.assertEqual((c.hue, c.sat, c.val), (10, 20, 30))
357+
self.assertEqual(Color._fields, ('hue', 'sat', 'val'))
358+
finally:
359+
forget(TESTFN)
360+
if compiled:
361+
unlink(compiled)
362+
unlink(source)
363+
330364

331365
################################################################################
332366
### Abstract Base Classes

0 commit comments

Comments
 (0)