Commit c593577a authored by Mark Dickinson's avatar Mark Dickinson

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.
........
parent 089b00cb
...@@ -119,6 +119,15 @@ Notes: ...@@ -119,6 +119,15 @@ Notes:
the platform C compiler supports C :ctype:`long long`, or, on Windows, the platform C compiler supports C :ctype:`long long`, or, on Windows,
:ctype:`__int64`. They are always available in standard modes. :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, A format character may be preceded by an integral repeat count. For example,
the format string ``'4h'`` means exactly the same as ``'hhhh'``. the format string ``'4h'`` means exactly the same as ``'hhhh'``.
......
...@@ -282,6 +282,23 @@ class StructTest(unittest.TestCase): ...@@ -282,6 +282,23 @@ class StructTest(unittest.TestCase):
struct.pack, self.format, struct.pack, self.format,
NotAnInt) 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 code in integer_codes:
for byteorder in byteorders: for byteorder in byteorders:
if (byteorder in ('', '@') and code in ('q', 'Q') and if (byteorder in ('', '@') and code in ('q', 'Q') and
......
...@@ -879,6 +879,11 @@ Library ...@@ -879,6 +879,11 @@ Library
Extension Modules 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 #8142: Update libffi to the 3.0.9 release.
- Issue #6949: Allow the _dbm extension to be built with db 4.8.x. - Issue #6949: Allow the _dbm extension to be built with db 4.8.x.
......
...@@ -97,12 +97,27 @@ get_pylong(PyObject *v) ...@@ -97,12 +97,27 @@ get_pylong(PyObject *v)
{ {
assert(v != NULL); assert(v != NULL);
if (!PyLong_Check(v)) { if (!PyLong_Check(v)) {
PyErr_SetString(StructError, /* Not an integer; try to use __index__ to convert. */
"required argument is not an integer"); if (PyIndex_Check(v)) {
return NULL; 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; return v;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment