[Python-checkins] r79703 - in python/branches/py3k: Doc/library/struct.rst Lib/test/test_struct.py Misc/NEWS Modules/_struct.c

mark.dickinson python-checkins at python.org
Sat Apr 3 17:54:36 CEST 2010


Author: mark.dickinson
Date: Sat Apr  3 17:54:36 2010
New Revision: 79703

Log:
Merged revisions 79674 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r79674 | mark.dickinson | 2010-04-03 15:05:10 +0100 (Sat, 03 Apr 2010) | 3 lines
  
  Issue #8300:  Let struct.pack use __index__ to convert and pack non-integers.
  Based on a patch by Meador Inge.
........


Modified:
   python/branches/py3k/   (props changed)
   python/branches/py3k/Doc/library/struct.rst
   python/branches/py3k/Lib/test/test_struct.py
   python/branches/py3k/Misc/NEWS
   python/branches/py3k/Modules/_struct.c

Modified: python/branches/py3k/Doc/library/struct.rst
==============================================================================
--- python/branches/py3k/Doc/library/struct.rst	(original)
+++ python/branches/py3k/Doc/library/struct.rst	Sat Apr  3 17:54:36 2010
@@ -119,6 +119,15 @@
    the platform C compiler supports C :ctype:`long long`, or, on Windows,
    :ctype:`__int64`.  They are always available in standard modes.
 
+(4)
+   When attempting to pack a non-integer using any of the integer conversion
+   codes, if the non-integer has a :meth:`__index__` method then that method is
+   called to convert the argument to an integer before packing.
+
+   .. versionchanged:: 3.2
+      Use of the :meth:`__index__` method for non-integers is new in 3.2.
+
+
 A format character may be preceded by an integral repeat count.  For example,
 the format string ``'4h'`` means exactly the same as ``'hhhh'``.
 

Modified: python/branches/py3k/Lib/test/test_struct.py
==============================================================================
--- python/branches/py3k/Lib/test/test_struct.py	(original)
+++ python/branches/py3k/Lib/test/test_struct.py	Sat Apr  3 17:54:36 2010
@@ -282,6 +282,23 @@
                                   struct.pack, self.format,
                                   NotAnInt)
 
+                # Objects with an '__index__' method should be allowed
+                # to pack as integers.
+                class Indexable(object):
+                    def __init__(self, value):
+                        self._value = value
+
+                    def __index__(self):
+                        return self._value
+
+                for obj in (Indexable(0), Indexable(10), Indexable(17),
+                            Indexable(42), Indexable(100), Indexable(127)):
+                    try:
+                        struct.pack(format, obj)
+                    except:
+                        self.fail("integer code pack failed on object "
+                                  "with '__index__' method")
+
         for code in integer_codes:
             for byteorder in byteorders:
                 if (byteorder in ('', '@') and code in ('q', 'Q') and

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Sat Apr  3 17:54:36 2010
@@ -879,6 +879,11 @@
 Extension Modules
 -----------------
 
+- Issue #8300: When passing a non-integer argument to struct.pack with any
+  integer format code, struct.pack first attempts to convert the non-integer
+  using its __index__ method.  If that method is non-existent or raises
+  TypeError it goes on to try the __int__ method, as described below.
+
 - Issue #8142: Update libffi to the 3.0.9 release.
 
 - Issue #6949: Allow the _dbm extension to be built with db 4.8.x.

Modified: python/branches/py3k/Modules/_struct.c
==============================================================================
--- python/branches/py3k/Modules/_struct.c	(original)
+++ python/branches/py3k/Modules/_struct.c	Sat Apr  3 17:54:36 2010
@@ -97,12 +97,27 @@
 {
 	assert(v != NULL);
 	if (!PyLong_Check(v)) {
-		PyErr_SetString(StructError,
-				"required argument is not an integer");
-		return NULL;
+		/* Not an integer;  try to use __index__ to convert. */
+		if (PyIndex_Check(v)) {
+			v = PyNumber_Index(v);
+			if (v == NULL)
+				return NULL;
+			if (!PyLong_Check(v)) {
+				PyErr_SetString(PyExc_TypeError,
+						"__index__ method "
+						"returned non-integer");
+				return NULL;
+			}
+		}
+		else {
+			PyErr_SetString(StructError,
+					"required argument is not an integer");
+			return NULL;
+		}
 	}
+	else
+		Py_INCREF(v);
 
-	Py_INCREF(v);
 	return v;
 }
 


More information about the Python-checkins mailing list