summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_operator.c277
1 files changed, 270 insertions, 7 deletions
diff --git a/Modules/_operator.c b/Modules/_operator.c
index 8f524a6..9e4db58 100644
--- a/Modules/_operator.c
+++ b/Modules/_operator.c
@@ -485,6 +485,41 @@ itemgetter_call(itemgetterobject *ig, PyObject *args, PyObject *kw)
return result;
}
+static PyObject *
+itemgetter_repr(itemgetterobject *ig)
+{
+ PyObject *repr;
+ const char *reprfmt;
+
+ int status = Py_ReprEnter((PyObject *)ig);
+ if (status != 0) {
+ if (status < 0)
+ return NULL;
+ return PyUnicode_FromFormat("%s(...)", Py_TYPE(ig)->tp_name);
+ }
+
+ reprfmt = ig->nitems == 1 ? "%s(%R)" : "%s%R";
+ repr = PyUnicode_FromFormat(reprfmt, Py_TYPE(ig)->tp_name, ig->item);
+ Py_ReprLeave((PyObject *)ig);
+ return repr;
+}
+
+static PyObject *
+itemgetter_reduce(itemgetterobject *ig)
+{
+ if (ig->nitems == 1)
+ return Py_BuildValue("O(O)", Py_TYPE(ig), ig->item);
+ return PyTuple_Pack(2, Py_TYPE(ig), ig->item);
+}
+
+PyDoc_STRVAR(reduce_doc, "Return state information for pickling");
+
+static PyMethodDef itemgetter_methods[] = {
+ {"__reduce__", (PyCFunction)itemgetter_reduce, METH_NOARGS,
+ reduce_doc},
+ {NULL}
+};
+
PyDoc_STRVAR(itemgetter_doc,
"itemgetter(item, ...) --> itemgetter object\n\
\n\
@@ -503,7 +538,7 @@ static PyTypeObject itemgetter_type = {
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
- 0, /* tp_repr */
+ (reprfunc)itemgetter_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
@@ -521,7 +556,7 @@ static PyTypeObject itemgetter_type = {
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
- 0, /* tp_methods */
+ itemgetter_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -737,6 +772,91 @@ attrgetter_call(attrgetterobject *ag, PyObject *args, PyObject *kw)
return result;
}
+static PyObject *
+dotjoinattr(PyObject *attr, PyObject **attrsep)
+{
+ if (PyTuple_CheckExact(attr)) {
+ if (*attrsep == NULL) {
+ *attrsep = PyUnicode_FromString(".");
+ if (*attrsep == NULL)
+ return NULL;
+ }
+ return PyUnicode_Join(*attrsep, attr);
+ } else {
+ Py_INCREF(attr);
+ return attr;
+ }
+}
+
+static PyObject *
+attrgetter_args(attrgetterobject *ag)
+{
+ Py_ssize_t i;
+ PyObject *attrsep = NULL;
+ PyObject *attrstrings = PyTuple_New(ag->nattrs);
+ if (attrstrings == NULL)
+ return NULL;
+
+ for (i = 0; i < ag->nattrs; ++i) {
+ PyObject *attr = PyTuple_GET_ITEM(ag->attr, i);
+ PyObject *attrstr = dotjoinattr(attr, &attrsep);
+ if (attrstr == NULL) {
+ Py_XDECREF(attrsep);
+ Py_DECREF(attrstrings);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(attrstrings, i, attrstr);
+ }
+ Py_XDECREF(attrsep);
+ return attrstrings;
+}
+
+static PyObject *
+attrgetter_repr(attrgetterobject *ag)
+{
+ PyObject *repr = NULL;
+ int status = Py_ReprEnter((PyObject *)ag);
+ if (status != 0) {
+ if (status < 0)
+ return NULL;
+ return PyUnicode_FromFormat("%s(...)", Py_TYPE(ag)->tp_name);
+ }
+
+ if (ag->nattrs == 1) {
+ PyObject *attrsep = NULL;
+ PyObject *attr = dotjoinattr(PyTuple_GET_ITEM(ag->attr, 0), &attrsep);
+ if (attr != NULL)
+ repr = PyUnicode_FromFormat("%s(%R)", Py_TYPE(ag)->tp_name, attr);
+ Py_XDECREF(attrsep);
+ }
+ else {
+ PyObject *attrstrings = attrgetter_args(ag);
+ if (attrstrings != NULL) {
+ repr = PyUnicode_FromFormat("%s%R",
+ Py_TYPE(ag)->tp_name, attrstrings);
+ Py_DECREF(attrstrings);
+ }
+ }
+ Py_ReprLeave((PyObject *)ag);
+ return repr;
+}
+
+static PyObject *
+attrgetter_reduce(attrgetterobject *ag)
+{
+ PyObject *attrstrings = attrgetter_args(ag);
+ if (attrstrings == NULL)
+ return NULL;
+
+ return Py_BuildValue("ON", Py_TYPE(ag), attrstrings);
+}
+
+static PyMethodDef attrgetter_methods[] = {
+ {"__reduce__", (PyCFunction)attrgetter_reduce, METH_NOARGS,
+ reduce_doc},
+ {NULL}
+};
+
PyDoc_STRVAR(attrgetter_doc,
"attrgetter(attr, ...) --> attrgetter object\n\
\n\
@@ -757,7 +877,7 @@ static PyTypeObject attrgetter_type = {
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
- 0, /* tp_repr */
+ (reprfunc)attrgetter_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
@@ -775,7 +895,7 @@ static PyTypeObject attrgetter_type = {
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
- 0, /* tp_methods */
+ attrgetter_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
@@ -813,6 +933,13 @@ methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
+ name = PyTuple_GET_ITEM(args, 0);
+ if (!PyUnicode_Check(name)) {
+ PyErr_SetString(PyExc_TypeError,
+ "method name must be a string");
+ return NULL;
+ }
+
/* create methodcallerobject structure */
mc = PyObject_GC_New(methodcallerobject, &methodcaller_type);
if (mc == NULL)
@@ -825,8 +952,8 @@ methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
mc->args = newargs;
- name = PyTuple_GET_ITEM(args, 0);
Py_INCREF(name);
+ PyUnicode_InternInPlace(&name);
mc->name = name;
Py_XINCREF(kwds);
@@ -869,6 +996,142 @@ methodcaller_call(methodcallerobject *mc, PyObject *args, PyObject *kw)
return result;
}
+static PyObject *
+methodcaller_repr(methodcallerobject *mc)
+{
+ PyObject *argreprs, *repr = NULL, *sep, *joinedargreprs;
+ Py_ssize_t numtotalargs, numposargs, numkwdargs, i;
+ int status = Py_ReprEnter((PyObject *)mc);
+ if (status != 0) {
+ if (status < 0)
+ return NULL;
+ return PyUnicode_FromFormat("%s(...)", Py_TYPE(mc)->tp_name);
+ }
+
+ if (mc->kwds != NULL) {
+ numkwdargs = PyDict_Size(mc->kwds);
+ if (numkwdargs < 0) {
+ Py_ReprLeave((PyObject *)mc);
+ return NULL;
+ }
+ } else {
+ numkwdargs = 0;
+ }
+
+ numposargs = PyTuple_GET_SIZE(mc->args);
+ numtotalargs = numposargs + numkwdargs;
+
+ if (numtotalargs == 0) {
+ repr = PyUnicode_FromFormat("%s(%R)", Py_TYPE(mc)->tp_name, mc->name);
+ Py_ReprLeave((PyObject *)mc);
+ return repr;
+ }
+
+ argreprs = PyTuple_New(numtotalargs);
+ if (argreprs == NULL) {
+ Py_ReprLeave((PyObject *)mc);
+ return NULL;
+ }
+
+ for (i = 0; i < numposargs; ++i) {
+ PyObject *onerepr = PyObject_Repr(PyTuple_GET_ITEM(mc->args, i));
+ if (onerepr == NULL)
+ goto done;
+ PyTuple_SET_ITEM(argreprs, i, onerepr);
+ }
+
+ if (numkwdargs != 0) {
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(mc->kwds, &pos, &key, &value)) {
+ PyObject *onerepr = PyUnicode_FromFormat("%U=%R", key, value);
+ if (onerepr == NULL)
+ goto done;
+ if (i >= numtotalargs) {
+ i = -1;
+ break;
+ }
+ PyTuple_SET_ITEM(argreprs, i, onerepr);
+ ++i;
+ }
+ if (i != numtotalargs) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "keywords dict changed size during iteration");
+ goto done;
+ }
+ }
+
+ sep = PyUnicode_FromString(", ");
+ if (sep == NULL)
+ goto done;
+
+ joinedargreprs = PyUnicode_Join(sep, argreprs);
+ Py_DECREF(sep);
+ if (joinedargreprs == NULL)
+ goto done;
+
+ repr = PyUnicode_FromFormat("%s(%R, %U)", Py_TYPE(mc)->tp_name,
+ mc->name, joinedargreprs);
+ Py_DECREF(joinedargreprs);
+
+done:
+ Py_DECREF(argreprs);
+ Py_ReprLeave((PyObject *)mc);
+ return repr;
+}
+
+static PyObject *
+methodcaller_reduce(methodcallerobject *mc)
+{
+ PyObject *newargs;
+ if (!mc->kwds || PyDict_Size(mc->kwds) == 0) {
+ Py_ssize_t i;
+ Py_ssize_t callargcount = PyTuple_GET_SIZE(mc->args);
+ newargs = PyTuple_New(1 + callargcount);
+ if (newargs == NULL)
+ return NULL;
+ Py_INCREF(mc->name);
+ PyTuple_SET_ITEM(newargs, 0, mc->name);
+ for (i = 0; i < callargcount; ++i) {
+ PyObject *arg = PyTuple_GET_ITEM(mc->args, i);
+ Py_INCREF(arg);
+ PyTuple_SET_ITEM(newargs, i + 1, arg);
+ }
+ return Py_BuildValue("ON", Py_TYPE(mc), newargs);
+ }
+ else {
+ PyObject *functools;
+ PyObject *partial;
+ PyObject *constructor;
+ _Py_IDENTIFIER(partial);
+ functools = PyImport_ImportModule("functools");
+ if (!functools)
+ return NULL;
+ partial = _PyObject_GetAttrId(functools, &PyId_partial);
+ Py_DECREF(functools);
+ if (!partial)
+ return NULL;
+ newargs = PyTuple_New(2);
+ if (newargs == NULL) {
+ Py_DECREF(partial);
+ return NULL;
+ }
+ Py_INCREF(Py_TYPE(mc));
+ PyTuple_SET_ITEM(newargs, 0, (PyObject *)Py_TYPE(mc));
+ Py_INCREF(mc->name);
+ PyTuple_SET_ITEM(newargs, 1, mc->name);
+ constructor = PyObject_Call(partial, newargs, mc->kwds);
+ Py_DECREF(newargs);
+ Py_DECREF(partial);
+ return Py_BuildValue("NO", constructor, mc->args);
+ }
+}
+
+static PyMethodDef methodcaller_methods[] = {
+ {"__reduce__", (PyCFunction)methodcaller_reduce, METH_NOARGS,
+ reduce_doc},
+ {NULL}
+};
PyDoc_STRVAR(methodcaller_doc,
"methodcaller(name, ...) --> methodcaller object\n\
\n\
@@ -888,7 +1151,7 @@ static PyTypeObject methodcaller_type = {
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
- 0, /* tp_repr */
+ (reprfunc)methodcaller_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
@@ -906,7 +1169,7 @@ static PyTypeObject methodcaller_type = {
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
- 0, /* tp_methods */
+ methodcaller_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */