mirror of
https://github.com/python/cpython
synced 2026-09-29 11:35:29 +03:00
Apply SF patch #101029: call __getitem__ with a proper slice object if there
is no __getslice__ available. Also does the same for C extension types. Includes rudimentary documentation (it could use a cross reference to the section on slice objects, I couldn't figure out how to do that) and a test suite for all Python __hooks__ I could think of, including the new behaviour.
This commit is contained in:
parent
68add2e938
commit
1d75a79c00
5 changed files with 435 additions and 18 deletions
|
|
@ -876,10 +876,29 @@ PySequence_GetItem(PyObject *s, int i)
|
|||
return type_error("unindexable object");
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
sliceobj_from_intint(int i, int j)
|
||||
{
|
||||
PyObject *start, *end, *slice;
|
||||
start = PyInt_FromLong((long)i);
|
||||
if (!start)
|
||||
return NULL;
|
||||
end = PyInt_FromLong((long)j);
|
||||
if (!end) {
|
||||
Py_DECREF(start);
|
||||
return NULL;
|
||||
}
|
||||
slice = PySlice_New(start, end, NULL);
|
||||
Py_DECREF(start);
|
||||
Py_DECREF(end);
|
||||
return slice;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PySequence_GetSlice(PyObject *s, int i1, int i2)
|
||||
{
|
||||
PySequenceMethods *m;
|
||||
PyMappingMethods *mp;
|
||||
|
||||
if (!s) return null_error();
|
||||
|
||||
|
|
@ -897,6 +916,14 @@ PySequence_GetSlice(PyObject *s, int i1, int i2)
|
|||
}
|
||||
}
|
||||
return m->sq_slice(s, i1, i2);
|
||||
} else if ((mp = s->ob_type->tp_as_mapping) && mp->mp_subscript) {
|
||||
PyObject *res;
|
||||
PyObject *slice = sliceobj_from_intint(i1, i2);
|
||||
if (!slice)
|
||||
return NULL;
|
||||
res = mp->mp_subscript(s, slice);
|
||||
Py_DECREF(slice);
|
||||
return res;
|
||||
}
|
||||
|
||||
return type_error("unsliceable object");
|
||||
|
|
@ -960,6 +987,7 @@ int
|
|||
PySequence_SetSlice(PyObject *s, int i1, int i2, PyObject *o)
|
||||
{
|
||||
PySequenceMethods *m;
|
||||
PyMappingMethods *mp;
|
||||
|
||||
if (s == NULL) {
|
||||
null_error();
|
||||
|
|
@ -980,7 +1008,16 @@ PySequence_SetSlice(PyObject *s, int i1, int i2, PyObject *o)
|
|||
}
|
||||
}
|
||||
return m->sq_ass_slice(s, i1, i2, o);
|
||||
} else if ((mp = s->ob_type->tp_as_mapping) && mp->mp_ass_subscript) {
|
||||
int res;
|
||||
PyObject *slice = sliceobj_from_intint(i1, i2);
|
||||
if (!slice)
|
||||
return -1;
|
||||
res = mp->mp_ass_subscript(s, slice, o);
|
||||
Py_DECREF(slice);
|
||||
return res;
|
||||
}
|
||||
|
||||
type_error("object doesn't support slice assignment");
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -971,6 +971,27 @@ instance_item(PyInstanceObject *inst, int i)
|
|||
return res;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
sliceobj_from_intint(int i, int j)
|
||||
{
|
||||
PyObject *start, *end, *res;
|
||||
|
||||
start = PyInt_FromLong((long)i);
|
||||
if (!start)
|
||||
return NULL;
|
||||
|
||||
end = PyInt_FromLong((long)j);
|
||||
if (!end) {
|
||||
Py_DECREF(start);
|
||||
return NULL;
|
||||
}
|
||||
res = PySlice_New(start, end, NULL);
|
||||
Py_DECREF(start);
|
||||
Py_DECREF(end);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
instance_slice(PyInstanceObject *inst, int i, int j)
|
||||
{
|
||||
|
|
@ -980,9 +1001,19 @@ instance_slice(PyInstanceObject *inst, int i, int j)
|
|||
if (getslicestr == NULL)
|
||||
getslicestr = PyString_InternFromString("__getslice__");
|
||||
func = instance_getattr(inst, getslicestr);
|
||||
if (func == NULL)
|
||||
return NULL;
|
||||
arg = Py_BuildValue("(ii)", i, j);
|
||||
|
||||
if (func == NULL) {
|
||||
PyErr_Clear();
|
||||
|
||||
if (getitemstr == NULL)
|
||||
getitemstr = PyString_InternFromString("__getitem__");
|
||||
func = instance_getattr(inst, getitemstr);
|
||||
if (func == NULL)
|
||||
return NULL;
|
||||
arg = Py_BuildValue("(N)", sliceobj_from_intint(i, j));
|
||||
} else
|
||||
arg = Py_BuildValue("(ii)", i, j);
|
||||
|
||||
if (arg == NULL) {
|
||||
Py_DECREF(func);
|
||||
return NULL;
|
||||
|
|
@ -1038,19 +1069,39 @@ instance_ass_slice(PyInstanceObject *inst, int i, int j, PyObject *value)
|
|||
delslicestr =
|
||||
PyString_InternFromString("__delslice__");
|
||||
func = instance_getattr(inst, delslicestr);
|
||||
if (func == NULL) {
|
||||
PyErr_Clear();
|
||||
if (delitemstr == NULL)
|
||||
delitemstr =
|
||||
PyString_InternFromString("__delitem__");
|
||||
func = instance_getattr(inst, delitemstr);
|
||||
if (func == NULL)
|
||||
return -1;
|
||||
|
||||
arg = Py_BuildValue("(N)",
|
||||
sliceobj_from_intint(i, j));
|
||||
} else
|
||||
arg = Py_BuildValue("(ii)", i, j);
|
||||
}
|
||||
else {
|
||||
if (setslicestr == NULL)
|
||||
setslicestr =
|
||||
PyString_InternFromString("__setslice__");
|
||||
func = instance_getattr(inst, setslicestr);
|
||||
if (func == NULL) {
|
||||
PyErr_Clear();
|
||||
if (setitemstr == NULL)
|
||||
setitemstr =
|
||||
PyString_InternFromString("__setitem__");
|
||||
func = instance_getattr(inst, setitemstr);
|
||||
if (func == NULL)
|
||||
return -1;
|
||||
|
||||
arg = Py_BuildValue("(NO)",
|
||||
sliceobj_from_intint(i, j), value);
|
||||
} else
|
||||
arg = Py_BuildValue("(iiO)", i, j, value);
|
||||
}
|
||||
if (func == NULL)
|
||||
return -1;
|
||||
if (value == NULL)
|
||||
arg = Py_BuildValue("(ii)", i, j);
|
||||
else
|
||||
arg = Py_BuildValue("(iiO)", i, j, value);
|
||||
if (arg == NULL) {
|
||||
Py_DECREF(func);
|
||||
return -1;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue