summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_capi/test_structmembers.py44
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2024-02-05-12-40-26.gh-issue-115011.L1AKF5.rst3
-rw-r--r--Python/structmember.c82
3 files changed, 62 insertions, 67 deletions
diff --git a/Lib/test/test_capi/test_structmembers.py b/Lib/test/test_capi/test_structmembers.py
index a294c3b..08ca1f8 100644
--- a/Lib/test/test_capi/test_structmembers.py
+++ b/Lib/test/test_capi/test_structmembers.py
@@ -81,36 +81,22 @@ class ReadWriteTests:
self._test_warn(name, maxval+1, minval)
self._test_warn(name, hardmaxval)
- if indexlimit is None:
- indexlimit = hardlimit
- if not indexlimit:
+ if indexlimit is False:
self.assertRaises(TypeError, setattr, ts, name, Index(minval))
self.assertRaises(TypeError, setattr, ts, name, Index(maxval))
else:
- hardminindexval, hardmaxindexval = indexlimit
self._test_write(name, Index(minval), minval)
- if minval < hardminindexval:
- self._test_write(name, Index(hardminindexval), hardminindexval)
- if maxval < hardmaxindexval:
- self._test_write(name, Index(maxval), maxval)
- else:
- self._test_write(name, Index(hardmaxindexval), hardmaxindexval)
- self._test_overflow(name, Index(hardminindexval-1))
- if name in ('T_UINT', 'T_ULONG'):
- self.assertRaises(TypeError, setattr, self.ts, name,
- Index(hardmaxindexval+1))
- self.assertRaises(TypeError, setattr, self.ts, name,
- Index(2**1000))
- else:
- self._test_overflow(name, Index(hardmaxindexval+1))
- self._test_overflow(name, Index(2**1000))
+ self._test_write(name, Index(maxval), maxval)
+ self._test_overflow(name, Index(hardminval-1))
+ self._test_overflow(name, Index(hardmaxval+1))
+ self._test_overflow(name, Index(2**1000))
self._test_overflow(name, Index(-2**1000))
- if hardminindexval < minval and name != 'T_ULONGLONG':
- self._test_warn(name, Index(hardminindexval))
- self._test_warn(name, Index(minval-1))
- if maxval < hardmaxindexval:
- self._test_warn(name, Index(maxval+1))
- self._test_warn(name, Index(hardmaxindexval))
+ if hardminval < minval:
+ self._test_warn(name, Index(hardminval))
+ self._test_warn(name, Index(minval-1), maxval)
+ if maxval < hardmaxval:
+ self._test_warn(name, Index(maxval+1), minval)
+ self._test_warn(name, Index(hardmaxval))
def test_bool(self):
ts = self.ts
@@ -138,14 +124,12 @@ class ReadWriteTests:
self._test_int_range('T_INT', INT_MIN, INT_MAX,
hardlimit=(LONG_MIN, LONG_MAX))
self._test_int_range('T_UINT', 0, UINT_MAX,
- hardlimit=(LONG_MIN, ULONG_MAX),
- indexlimit=(LONG_MIN, LONG_MAX))
+ hardlimit=(LONG_MIN, ULONG_MAX))
def test_long(self):
self._test_int_range('T_LONG', LONG_MIN, LONG_MAX)
self._test_int_range('T_ULONG', 0, ULONG_MAX,
- hardlimit=(LONG_MIN, ULONG_MAX),
- indexlimit=(LONG_MIN, LONG_MAX))
+ hardlimit=(LONG_MIN, ULONG_MAX))
def test_py_ssize_t(self):
self._test_int_range('T_PYSSIZET', PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, indexlimit=False)
@@ -153,7 +137,7 @@ class ReadWriteTests:
def test_longlong(self):
self._test_int_range('T_LONGLONG', LLONG_MIN, LLONG_MAX)
self._test_int_range('T_ULONGLONG', 0, ULLONG_MAX,
- indexlimit=(LONG_MIN, LONG_MAX))
+ hardlimit=(LONG_MIN, ULLONG_MAX))
def test_bad_assignments(self):
ts = self.ts
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-02-05-12-40-26.gh-issue-115011.L1AKF5.rst b/Misc/NEWS.d/next/Core and Builtins/2024-02-05-12-40-26.gh-issue-115011.L1AKF5.rst
new file mode 100644
index 0000000..cf91a4f
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2024-02-05-12-40-26.gh-issue-115011.L1AKF5.rst
@@ -0,0 +1,3 @@
+Setters for members with an unsigned integer type now support the same range
+of valid values for objects that has a :meth:`~object.__index__` method as
+for :class:`int`.
diff --git a/Python/structmember.c b/Python/structmember.c
index ebebaa0..f4de0cb 100644
--- a/Python/structmember.c
+++ b/Python/structmember.c
@@ -3,6 +3,9 @@
#include "Python.h"
#include "structmember.h" // PyMemberDef
+#include "pycore_abstract.h" // _PyNumber_Index()
+#include "pycore_long.h" // _PyLong_IsNegative()
+
PyObject *
PyMember_GetOne(const char *obj_addr, PyMemberDef *l)
@@ -200,27 +203,22 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
case T_UINT: {
/* XXX: For compatibility, accept negative int values
as well. */
- int overflow;
- long long_val = PyLong_AsLongAndOverflow(v, &overflow);
- if (long_val == -1 && PyErr_Occurred()) {
- return -1;
- }
- if (overflow < 0) {
- PyErr_SetString(PyExc_OverflowError,
- "Python int too large to convert to C long");
+ v = _PyNumber_Index(v);
+ if (v == NULL) {
return -1;
}
- else if (!overflow) {
- *(unsigned int *)addr = (unsigned int)(unsigned long)long_val;
- if (long_val < 0) {
- WARN("Writing negative value into unsigned field");
- }
- else if ((unsigned long)long_val > UINT_MAX) {
- WARN("Truncation of value to unsigned short");
+ if (_PyLong_IsNegative((PyLongObject *)v)) {
+ long long_val = PyLong_AsLong(v);
+ Py_DECREF(v);
+ if (long_val == -1 && PyErr_Occurred()) {
+ return -1;
}
+ *(unsigned int *)addr = (unsigned int)(unsigned long)long_val;
+ WARN("Writing negative value into unsigned field");
}
else {
unsigned long ulong_val = PyLong_AsUnsignedLong(v);
+ Py_DECREF(v);
if (ulong_val == (unsigned long)-1 && PyErr_Occurred()) {
return -1;
}
@@ -240,24 +238,22 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
case T_ULONG: {
/* XXX: For compatibility, accept negative int values
as well. */
- int overflow;
- long long_val = PyLong_AsLongAndOverflow(v, &overflow);
- if (long_val == -1 && PyErr_Occurred()) {
- return -1;
- }
- if (overflow < 0) {
- PyErr_SetString(PyExc_OverflowError,
- "Python int too large to convert to C long");
+ v = _PyNumber_Index(v);
+ if (v == NULL) {
return -1;
}
- else if (!overflow) {
- *(unsigned long *)addr = (unsigned long)long_val;
- if (long_val < 0) {
- WARN("Writing negative value into unsigned field");
+ if (_PyLong_IsNegative((PyLongObject *)v)) {
+ long long_val = PyLong_AsLong(v);
+ Py_DECREF(v);
+ if (long_val == -1 && PyErr_Occurred()) {
+ return -1;
}
+ *(unsigned long *)addr = (unsigned long)long_val;
+ WARN("Writing negative value into unsigned field");
}
else {
unsigned long ulong_val = PyLong_AsUnsignedLong(v);
+ Py_DECREF(v);
if (ulong_val == (unsigned long)-1 && PyErr_Occurred()) {
return -1;
}
@@ -313,18 +309,30 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
return -1;
break;
}
- case T_ULONGLONG:{
- unsigned long long value;
- /* ??? PyLong_AsLongLong accepts an int, but PyLong_AsUnsignedLongLong
- doesn't ??? */
- if (PyLong_Check(v))
- *(unsigned long long*)addr = value = PyLong_AsUnsignedLongLong(v);
- else
- *(unsigned long long*)addr = value = PyLong_AsLong(v);
- if ((value == (unsigned long long)-1) && PyErr_Occurred())
+ case Py_T_ULONGLONG: {
+ v = _PyNumber_Index(v);
+ if (v == NULL) {
return -1;
- break;
}
+ if (_PyLong_IsNegative((PyLongObject *)v)) {
+ long long_val = PyLong_AsLong(v);
+ Py_DECREF(v);
+ if (long_val == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+ *(unsigned long long *)addr = (unsigned long long)(long long)long_val;
+ WARN("Writing negative value into unsigned field");
+ }
+ else {
+ unsigned long long ulonglong_val = PyLong_AsUnsignedLongLong(v);
+ Py_DECREF(v);
+ if (ulonglong_val == (unsigned long long)-1 && PyErr_Occurred()) {
+ return -1;
+ }
+ *(unsigned long long*)addr = ulonglong_val;
+ }
+ break;
+ }
default:
PyErr_Format(PyExc_SystemError,
"bad memberdescr type for %s", l->name);