summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2007-10-16 21:28:32 (GMT)
committerRaymond Hettinger <python@rcn.com>2007-10-16 21:28:32 (GMT)
commitabfd8dff3bd6bd2836e824b185a367c4b6c8e1f4 (patch)
treead46b5d3eab55be40c315627ad575217dfc7e7fd
parent050afbf214ae4066722c966ad653c199ad9c15ec (diff)
downloadcpython-abfd8dff3bd6bd2836e824b185a367c4b6c8e1f4.zip
cpython-abfd8dff3bd6bd2836e824b185a367c4b6c8e1f4.tar.gz
cpython-abfd8dff3bd6bd2836e824b185a367c4b6c8e1f4.tar.bz2
More docs, error messages, and tests
-rw-r--r--Doc/library/collections.rst10
-rw-r--r--Lib/collections.py3
-rw-r--r--Lib/test/test_collections.py17
3 files changed, 21 insertions, 9 deletions
diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst
index 4e93b15..8d24e23 100644
--- a/Doc/library/collections.rst
+++ b/Doc/library/collections.rst
@@ -365,9 +365,13 @@ they add the ability to access fields by name instead of position index.
The *fieldnames* are a single string with each fieldname separated by whitespace
and/or commas (for example 'x y' or 'x, y'). Alternatively, the *fieldnames*
- can be specified as a list of strings (such as ['x', 'y']). Any valid
- Python identifier may be used for a fieldname except for names starting and
- ending with double underscores.
+ can be specified as a list of strings (such as ['x', 'y']).
+
+ Any valid Python identifier may be used for a fieldname except for names
+ starting and ending with double underscores. Valid identifiers consist of
+ letters, digits, and underscores but do not start with a digit and cannot be
+ a :mod:`keyword` such as *class*, *for*, *return*, *global*, *pass*, *print*,
+ or *raise*.
If *verbose* is true, will print the class definition.
diff --git a/Lib/collections.py b/Lib/collections.py
index fbc00d1..0feda0a 100644
--- a/Lib/collections.py
+++ b/Lib/collections.py
@@ -2,6 +2,7 @@ __all__ = ['deque', 'defaultdict', 'named_tuple']
from _collections import deque, defaultdict
from operator import itemgetter as _itemgetter
+from keyword import iskeyword as _iskeyword
import sys as _sys
def named_tuple(typename, field_names, verbose=False):
@@ -35,6 +36,8 @@ def named_tuple(typename, field_names, verbose=False):
for name in (typename,) + field_names:
if not name.replace('_', '').isalnum():
raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name)
+ if _iskeyword(name):
+ raise ValueError('Type names and field names cannot be a keyword: %r' % name)
if name[0].isdigit():
raise ValueError('Type names and field names cannot start with a number: %r' % name)
seen_names = set()
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index 1af20ca..b1f3add 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -11,11 +11,17 @@ class TestNamedTuple(unittest.TestCase):
self.assertEqual(Point.__slots__, ())
self.assertEqual(Point.__module__, __name__)
self.assertEqual(Point.__getitem__, tuple.__getitem__)
- self.assertRaises(ValueError, named_tuple, 'abc%', 'def ghi')
- self.assertRaises(ValueError, named_tuple, 'abc', 'def g%hi')
- self.assertRaises(ValueError, named_tuple, 'abc', '__def__ ghi')
- self.assertRaises(ValueError, named_tuple, 'abc', 'def def ghi')
- self.assertRaises(ValueError, named_tuple, 'abc', '8def 9ghi')
+
+ self.assertRaises(ValueError, named_tuple, 'abc%', 'efg ghi') # type has non-alpha char
+ self.assertRaises(ValueError, named_tuple, 'class', 'efg ghi') # type has keyword
+ self.assertRaises(ValueError, named_tuple, '9abc', 'efg ghi') # type starts with digit
+
+ self.assertRaises(ValueError, named_tuple, 'abc', 'efg g%hi') # field with non-alpha char
+ self.assertRaises(ValueError, named_tuple, 'abc', 'abc class') # field has keyword
+ self.assertRaises(ValueError, named_tuple, 'abc', '8efg 9ghi') # field starts with digit
+ self.assertRaises(ValueError, named_tuple, 'abc', '__efg__ ghi') # field with double underscores
+ self.assertRaises(ValueError, named_tuple, 'abc', 'efg efg ghi') # duplicate field
+
named_tuple('Point0', 'x1 y2') # Verify that numbers are allowed in names
def test_instance(self):
@@ -66,7 +72,6 @@ class TestNamedTuple(unittest.TestCase):
self.assertEqual(p.y, y)
self.assertRaises(AttributeError, eval, 'p.z', locals())
-
def test_odd_sizes(self):
Zero = named_tuple('Zero', '')
self.assertEqual(Zero(), ())