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

Skip to content

Commit c593577

Browse files
committed
Merged revisions 79674 via svnmerge from
svn+ssh://[email protected]/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. ........
1 parent 089b00c commit c593577

4 files changed

Lines changed: 50 additions & 4 deletions

File tree

Doc/library/struct.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,15 @@ Notes:
119119
the platform C compiler supports C :ctype:`long long`, or, on Windows,
120120
:ctype:`__int64`. They are always available in standard modes.
121121

122+
(4)
123+
When attempting to pack a non-integer using any of the integer conversion
124+
codes, if the non-integer has a :meth:`__index__` method then that method is
125+
called to convert the argument to an integer before packing.
126+
127+
.. versionchanged:: 3.2
128+
Use of the :meth:`__index__` method for non-integers is new in 3.2.
129+
130+
122131
A format character may be preceded by an integral repeat count. For example,
123132
the format string ``'4h'`` means exactly the same as ``'hhhh'``.
124133

Lib/test/test_struct.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,23 @@ def __int__(self):
282282
struct.pack, self.format,
283283
NotAnInt)
284284

285+
# Objects with an '__index__' method should be allowed
286+
# to pack as integers.
287+
class Indexable(object):
288+
def __init__(self, value):
289+
self._value = value
290+
291+
def __index__(self):
292+
return self._value
293+
294+
for obj in (Indexable(0), Indexable(10), Indexable(17),
295+
Indexable(42), Indexable(100), Indexable(127)):
296+
try:
297+
struct.pack(format, obj)
298+
except:
299+
self.fail("integer code pack failed on object "
300+
"with '__index__' method")
301+
285302
for code in integer_codes:
286303
for byteorder in byteorders:
287304
if (byteorder in ('', '@') and code in ('q', 'Q') and

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,11 @@ Library
879879
Extension Modules
880880
-----------------
881881

882+
- Issue #8300: When passing a non-integer argument to struct.pack with any
883+
integer format code, struct.pack first attempts to convert the non-integer
884+
using its __index__ method. If that method is non-existent or raises
885+
TypeError it goes on to try the __int__ method, as described below.
886+
882887
- Issue #8142: Update libffi to the 3.0.9 release.
883888

884889
- Issue #6949: Allow the _dbm extension to be built with db 4.8.x.

Modules/_struct.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,27 @@ get_pylong(PyObject *v)
9797
{
9898
assert(v != NULL);
9999
if (!PyLong_Check(v)) {
100-
PyErr_SetString(StructError,
101-
"required argument is not an integer");
102-
return NULL;
100+
/* Not an integer; try to use __index__ to convert. */
101+
if (PyIndex_Check(v)) {
102+
v = PyNumber_Index(v);
103+
if (v == NULL)
104+
return NULL;
105+
if (!PyLong_Check(v)) {
106+
PyErr_SetString(PyExc_TypeError,
107+
"__index__ method "
108+
"returned non-integer");
109+
return NULL;
110+
}
111+
}
112+
else {
113+
PyErr_SetString(StructError,
114+
"required argument is not an integer");
115+
return NULL;
116+
}
103117
}
118+
else
119+
Py_INCREF(v);
104120

105-
Py_INCREF(v);
106121
return v;
107122
}
108123

0 commit comments

Comments
 (0)