| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 1 |  | 
 | 2 | #include "Python.h" | 
 | 3 | #include "structmember.h" | 
 | 4 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 5 | /* _functools module written and maintained | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 6 |    by Hye-Shik Chang <perky@FreeBSD.org> | 
 | 7 |    with adaptations by Raymond Hettinger <python@rcn.com> | 
| Thomas Wouters | 4d70c3d | 2006-06-08 14:42:34 +0000 | [diff] [blame] | 8 |    Copyright (c) 2004, 2005, 2006 Python Software Foundation. | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 9 |    All rights reserved. | 
 | 10 | */ | 
 | 11 |  | 
 | 12 | /* partial object **********************************************************/ | 
 | 13 |  | 
 | 14 | typedef struct { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 15 |     PyObject_HEAD | 
 | 16 |     PyObject *fn; | 
 | 17 |     PyObject *args; | 
 | 18 |     PyObject *kw; | 
 | 19 |     PyObject *dict; | 
 | 20 |     PyObject *weakreflist; /* List of weak references */ | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 21 | } partialobject; | 
 | 22 |  | 
 | 23 | static PyTypeObject partial_type; | 
 | 24 |  | 
 | 25 | static PyObject * | 
 | 26 | partial_new(PyTypeObject *type, PyObject *args, PyObject *kw) | 
 | 27 | { | 
| Alexander Belopolsky | e49af34 | 2015-03-01 15:08:17 -0500 | [diff] [blame] | 28 |     PyObject *func, *pargs, *nargs, *pkw; | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 29 |     partialobject *pto; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 30 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 31 |     if (PyTuple_GET_SIZE(args) < 1) { | 
 | 32 |         PyErr_SetString(PyExc_TypeError, | 
 | 33 |                         "type 'partial' takes at least one argument"); | 
 | 34 |         return NULL; | 
 | 35 |     } | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 36 |  | 
| Alexander Belopolsky | e49af34 | 2015-03-01 15:08:17 -0500 | [diff] [blame] | 37 |     pargs = pkw = Py_None; | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 38 |     func = PyTuple_GET_ITEM(args, 0); | 
| Alexander Belopolsky | e49af34 | 2015-03-01 15:08:17 -0500 | [diff] [blame] | 39 |     if (Py_TYPE(func) == &partial_type && type == &partial_type) { | 
 | 40 |         partialobject *part = (partialobject *)func; | 
 | 41 |         if (part->dict == NULL) { | 
 | 42 |             pargs = part->args; | 
 | 43 |             pkw = part->kw; | 
 | 44 |             func = part->fn; | 
 | 45 |         } | 
 | 46 |     } | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 47 |     if (!PyCallable_Check(func)) { | 
 | 48 |         PyErr_SetString(PyExc_TypeError, | 
 | 49 |                         "the first argument must be callable"); | 
 | 50 |         return NULL; | 
 | 51 |     } | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 52 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 53 |     /* create partialobject structure */ | 
 | 54 |     pto = (partialobject *)type->tp_alloc(type, 0); | 
 | 55 |     if (pto == NULL) | 
 | 56 |         return NULL; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 57 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 58 |     pto->fn = func; | 
 | 59 |     Py_INCREF(func); | 
| Alexander Belopolsky | e49af34 | 2015-03-01 15:08:17 -0500 | [diff] [blame] | 60 |  | 
 | 61 |     nargs = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX); | 
 | 62 |     if (nargs == NULL) { | 
 | 63 |         pto->args = NULL; | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 64 |         pto->kw = NULL; | 
 | 65 |         Py_DECREF(pto); | 
 | 66 |         return NULL; | 
 | 67 |     } | 
| Alexander Belopolsky | e49af34 | 2015-03-01 15:08:17 -0500 | [diff] [blame] | 68 |     if (pargs == Py_None || PyTuple_GET_SIZE(pargs) == 0) { | 
 | 69 |         pto->args = nargs; | 
 | 70 |         Py_INCREF(nargs); | 
 | 71 |     } | 
 | 72 |     else if (PyTuple_GET_SIZE(nargs) == 0) { | 
 | 73 |         pto->args = pargs; | 
 | 74 |         Py_INCREF(pargs); | 
 | 75 |     } | 
 | 76 |     else { | 
 | 77 |         pto->args = PySequence_Concat(pargs, nargs); | 
 | 78 |         if (pto->args == NULL) { | 
 | 79 |             pto->kw = NULL; | 
 | 80 |             Py_DECREF(pto); | 
 | 81 |             return NULL; | 
 | 82 |         } | 
 | 83 |     } | 
 | 84 |     Py_DECREF(nargs); | 
 | 85 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 86 |     if (kw != NULL) { | 
| Alexander Belopolsky | e49af34 | 2015-03-01 15:08:17 -0500 | [diff] [blame] | 87 |         if (pkw == Py_None) { | 
 | 88 |             pto->kw = PyDict_Copy(kw); | 
 | 89 |         } | 
 | 90 |         else { | 
 | 91 |             pto->kw = PyDict_Copy(pkw); | 
 | 92 |             if (pto->kw != NULL) { | 
 | 93 |                 if (PyDict_Merge(pto->kw, kw, 1) != 0) { | 
 | 94 |                     Py_DECREF(pto); | 
 | 95 |                     return NULL; | 
 | 96 |                 } | 
 | 97 |             } | 
 | 98 |         } | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 99 |         if (pto->kw == NULL) { | 
 | 100 |             Py_DECREF(pto); | 
 | 101 |             return NULL; | 
 | 102 |         } | 
| Alexander Belopolsky | e49af34 | 2015-03-01 15:08:17 -0500 | [diff] [blame] | 103 |     } | 
 | 104 |     else { | 
| Benjamin Peterson | dae2ef1 | 2015-05-09 00:29:08 -0400 | [diff] [blame^] | 105 |         if (pkw == Py_None) { | 
 | 106 |             pto->kw = PyDict_New(); | 
 | 107 |             if (pto->kw == NULL) { | 
 | 108 |                 Py_DECREF(pto); | 
 | 109 |                 return NULL; | 
 | 110 |             } | 
 | 111 |         } | 
 | 112 |         else { | 
 | 113 |             pto->kw = pkw; | 
 | 114 |             Py_INCREF(pkw); | 
 | 115 |         } | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 116 |     } | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 117 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 118 |     pto->weakreflist = NULL; | 
 | 119 |     pto->dict = NULL; | 
| Raymond Hettinger | c8b6d1b | 2005-03-08 06:14:50 +0000 | [diff] [blame] | 120 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 121 |     return (PyObject *)pto; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 122 | } | 
 | 123 |  | 
 | 124 | static void | 
 | 125 | partial_dealloc(partialobject *pto) | 
 | 126 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 127 |     PyObject_GC_UnTrack(pto); | 
 | 128 |     if (pto->weakreflist != NULL) | 
 | 129 |         PyObject_ClearWeakRefs((PyObject *) pto); | 
 | 130 |     Py_XDECREF(pto->fn); | 
 | 131 |     Py_XDECREF(pto->args); | 
 | 132 |     Py_XDECREF(pto->kw); | 
 | 133 |     Py_XDECREF(pto->dict); | 
 | 134 |     Py_TYPE(pto)->tp_free(pto); | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 135 | } | 
 | 136 |  | 
 | 137 | static PyObject * | 
 | 138 | partial_call(partialobject *pto, PyObject *args, PyObject *kw) | 
 | 139 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 140 |     PyObject *ret; | 
 | 141 |     PyObject *argappl = NULL, *kwappl = NULL; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 142 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 143 |     assert (PyCallable_Check(pto->fn)); | 
 | 144 |     assert (PyTuple_Check(pto->args)); | 
 | 145 |     assert (pto->kw == Py_None  ||  PyDict_Check(pto->kw)); | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 146 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 147 |     if (PyTuple_GET_SIZE(pto->args) == 0) { | 
 | 148 |         argappl = args; | 
 | 149 |         Py_INCREF(args); | 
 | 150 |     } else if (PyTuple_GET_SIZE(args) == 0) { | 
 | 151 |         argappl = pto->args; | 
 | 152 |         Py_INCREF(pto->args); | 
 | 153 |     } else { | 
 | 154 |         argappl = PySequence_Concat(pto->args, args); | 
 | 155 |         if (argappl == NULL) | 
 | 156 |             return NULL; | 
 | 157 |     } | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 158 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 159 |     if (pto->kw == Py_None) { | 
 | 160 |         kwappl = kw; | 
 | 161 |         Py_XINCREF(kw); | 
 | 162 |     } else { | 
 | 163 |         kwappl = PyDict_Copy(pto->kw); | 
 | 164 |         if (kwappl == NULL) { | 
 | 165 |             Py_DECREF(argappl); | 
 | 166 |             return NULL; | 
 | 167 |         } | 
 | 168 |         if (kw != NULL) { | 
 | 169 |             if (PyDict_Merge(kwappl, kw, 1) != 0) { | 
 | 170 |                 Py_DECREF(argappl); | 
 | 171 |                 Py_DECREF(kwappl); | 
 | 172 |                 return NULL; | 
 | 173 |             } | 
 | 174 |         } | 
 | 175 |     } | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 176 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 177 |     ret = PyObject_Call(pto->fn, argappl, kwappl); | 
 | 178 |     Py_DECREF(argappl); | 
 | 179 |     Py_XDECREF(kwappl); | 
 | 180 |     return ret; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 181 | } | 
 | 182 |  | 
 | 183 | static int | 
 | 184 | partial_traverse(partialobject *pto, visitproc visit, void *arg) | 
 | 185 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 186 |     Py_VISIT(pto->fn); | 
 | 187 |     Py_VISIT(pto->args); | 
 | 188 |     Py_VISIT(pto->kw); | 
 | 189 |     Py_VISIT(pto->dict); | 
 | 190 |     return 0; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 191 | } | 
 | 192 |  | 
 | 193 | PyDoc_STRVAR(partial_doc, | 
 | 194 | "partial(func, *args, **keywords) - new function with partial application\n\ | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 195 |     of the given arguments and keywords.\n"); | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 196 |  | 
 | 197 | #define OFF(x) offsetof(partialobject, x) | 
 | 198 | static PyMemberDef partial_memberlist[] = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 199 |     {"func",            T_OBJECT,       OFF(fn),        READONLY, | 
 | 200 |      "function object to use in future partial calls"}, | 
 | 201 |     {"args",            T_OBJECT,       OFF(args),      READONLY, | 
 | 202 |      "tuple of arguments to future partial calls"}, | 
 | 203 |     {"keywords",        T_OBJECT,       OFF(kw),        READONLY, | 
 | 204 |      "dictionary of keyword arguments to future partial calls"}, | 
 | 205 |     {NULL}  /* Sentinel */ | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 206 | }; | 
 | 207 |  | 
| Georg Brandl | c2fb6c7 | 2006-02-21 17:49:57 +0000 | [diff] [blame] | 208 | static PyGetSetDef partial_getsetlist[] = { | 
| Benjamin Peterson | 23d7f12 | 2012-02-19 20:02:57 -0500 | [diff] [blame] | 209 |     {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 210 |     {NULL} /* Sentinel */ | 
| Raymond Hettinger | c8b6d1b | 2005-03-08 06:14:50 +0000 | [diff] [blame] | 211 | }; | 
 | 212 |  | 
| Alexander Belopolsky | 41e422a | 2010-12-01 20:05:49 +0000 | [diff] [blame] | 213 | static PyObject * | 
 | 214 | partial_repr(partialobject *pto) | 
 | 215 | { | 
 | 216 |     PyObject *result; | 
 | 217 |     PyObject *arglist; | 
 | 218 |     PyObject *tmp; | 
 | 219 |     Py_ssize_t i, n; | 
 | 220 |  | 
 | 221 |     arglist = PyUnicode_FromString(""); | 
 | 222 |     if (arglist == NULL) { | 
 | 223 |         return NULL; | 
 | 224 |     } | 
 | 225 |     /* Pack positional arguments */ | 
 | 226 |     assert (PyTuple_Check(pto->args)); | 
 | 227 |     n = PyTuple_GET_SIZE(pto->args); | 
 | 228 |     for (i = 0; i < n; i++) { | 
 | 229 |         tmp = PyUnicode_FromFormat("%U, %R", arglist, | 
 | 230 |                                    PyTuple_GET_ITEM(pto->args, i)); | 
 | 231 |         Py_DECREF(arglist); | 
 | 232 |         if (tmp == NULL) | 
 | 233 |             return NULL; | 
 | 234 |         arglist = tmp; | 
 | 235 |     } | 
 | 236 |     /* Pack keyword arguments */ | 
 | 237 |     assert (pto->kw == Py_None  ||  PyDict_Check(pto->kw)); | 
 | 238 |     if (pto->kw != Py_None) { | 
 | 239 |         PyObject *key, *value; | 
 | 240 |         for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) { | 
 | 241 |             tmp = PyUnicode_FromFormat("%U, %U=%R", arglist, | 
 | 242 |                                        key, value); | 
 | 243 |             Py_DECREF(arglist); | 
 | 244 |             if (tmp == NULL) | 
 | 245 |                 return NULL; | 
 | 246 |             arglist = tmp; | 
 | 247 |         } | 
 | 248 |     } | 
 | 249 |     result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name, | 
 | 250 |                                   pto->fn, arglist); | 
 | 251 |     Py_DECREF(arglist); | 
 | 252 |     return result; | 
 | 253 | } | 
 | 254 |  | 
| Jack Diederich | e0cbd69 | 2009-04-01 04:27:09 +0000 | [diff] [blame] | 255 | /* Pickle strategy: | 
 | 256 |    __reduce__ by itself doesn't support getting kwargs in the unpickle | 
 | 257 |    operation so we define a __setstate__ that replaces all the information | 
 | 258 |    about the partial.  If we only replaced part of it someone would use | 
| Ezio Melotti | 1392500 | 2011-03-16 11:05:33 +0200 | [diff] [blame] | 259 |    it as a hook to do strange things. | 
| Jack Diederich | e0cbd69 | 2009-04-01 04:27:09 +0000 | [diff] [blame] | 260 |  */ | 
 | 261 |  | 
| Antoine Pitrou | 69f7114 | 2009-05-24 21:25:49 +0000 | [diff] [blame] | 262 | static PyObject * | 
| Jack Diederich | e0cbd69 | 2009-04-01 04:27:09 +0000 | [diff] [blame] | 263 | partial_reduce(partialobject *pto, PyObject *unused) | 
 | 264 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 265 |     return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn, | 
 | 266 |                          pto->args, pto->kw, | 
 | 267 |                          pto->dict ? pto->dict : Py_None); | 
| Jack Diederich | e0cbd69 | 2009-04-01 04:27:09 +0000 | [diff] [blame] | 268 | } | 
 | 269 |  | 
| Antoine Pitrou | 69f7114 | 2009-05-24 21:25:49 +0000 | [diff] [blame] | 270 | static PyObject * | 
| Serhiy Storchaka | 19c4e0d | 2013-02-04 12:47:24 +0200 | [diff] [blame] | 271 | partial_setstate(partialobject *pto, PyObject *state) | 
| Jack Diederich | e0cbd69 | 2009-04-01 04:27:09 +0000 | [diff] [blame] | 272 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 273 |     PyObject *fn, *fnargs, *kw, *dict; | 
| Serhiy Storchaka | 19c4e0d | 2013-02-04 12:47:24 +0200 | [diff] [blame] | 274 |     if (!PyArg_ParseTuple(state, "OOOO", | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 275 |                           &fn, &fnargs, &kw, &dict)) | 
 | 276 |         return NULL; | 
 | 277 |     Py_XDECREF(pto->fn); | 
 | 278 |     Py_XDECREF(pto->args); | 
 | 279 |     Py_XDECREF(pto->kw); | 
 | 280 |     Py_XDECREF(pto->dict); | 
 | 281 |     pto->fn = fn; | 
 | 282 |     pto->args = fnargs; | 
 | 283 |     pto->kw = kw; | 
 | 284 |     if (dict != Py_None) { | 
 | 285 |       pto->dict = dict; | 
 | 286 |       Py_INCREF(dict); | 
 | 287 |     } else { | 
 | 288 |       pto->dict = NULL; | 
 | 289 |     } | 
 | 290 |     Py_INCREF(fn); | 
 | 291 |     Py_INCREF(fnargs); | 
 | 292 |     Py_INCREF(kw); | 
 | 293 |     Py_RETURN_NONE; | 
| Jack Diederich | e0cbd69 | 2009-04-01 04:27:09 +0000 | [diff] [blame] | 294 | } | 
 | 295 |  | 
 | 296 | static PyMethodDef partial_methods[] = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 297 |     {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS}, | 
| Serhiy Storchaka | 19c4e0d | 2013-02-04 12:47:24 +0200 | [diff] [blame] | 298 |     {"__setstate__", (PyCFunction)partial_setstate, METH_O}, | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 299 |     {NULL,              NULL}           /* sentinel */ | 
| Jack Diederich | e0cbd69 | 2009-04-01 04:27:09 +0000 | [diff] [blame] | 300 | }; | 
 | 301 |  | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 302 | static PyTypeObject partial_type = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 303 |     PyVarObject_HEAD_INIT(NULL, 0) | 
 | 304 |     "functools.partial",                /* tp_name */ | 
 | 305 |     sizeof(partialobject),              /* tp_basicsize */ | 
 | 306 |     0,                                  /* tp_itemsize */ | 
 | 307 |     /* methods */ | 
 | 308 |     (destructor)partial_dealloc,        /* tp_dealloc */ | 
 | 309 |     0,                                  /* tp_print */ | 
 | 310 |     0,                                  /* tp_getattr */ | 
 | 311 |     0,                                  /* tp_setattr */ | 
 | 312 |     0,                                  /* tp_reserved */ | 
| Alexander Belopolsky | 41e422a | 2010-12-01 20:05:49 +0000 | [diff] [blame] | 313 |     (reprfunc)partial_repr,             /* tp_repr */ | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 314 |     0,                                  /* tp_as_number */ | 
 | 315 |     0,                                  /* tp_as_sequence */ | 
 | 316 |     0,                                  /* tp_as_mapping */ | 
 | 317 |     0,                                  /* tp_hash */ | 
 | 318 |     (ternaryfunc)partial_call,          /* tp_call */ | 
 | 319 |     0,                                  /* tp_str */ | 
 | 320 |     PyObject_GenericGetAttr,            /* tp_getattro */ | 
 | 321 |     PyObject_GenericSetAttr,            /* tp_setattro */ | 
 | 322 |     0,                                  /* tp_as_buffer */ | 
 | 323 |     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | | 
 | 324 |         Py_TPFLAGS_BASETYPE,            /* tp_flags */ | 
 | 325 |     partial_doc,                        /* tp_doc */ | 
 | 326 |     (traverseproc)partial_traverse,     /* tp_traverse */ | 
 | 327 |     0,                                  /* tp_clear */ | 
 | 328 |     0,                                  /* tp_richcompare */ | 
 | 329 |     offsetof(partialobject, weakreflist),       /* tp_weaklistoffset */ | 
 | 330 |     0,                                  /* tp_iter */ | 
 | 331 |     0,                                  /* tp_iternext */ | 
 | 332 |     partial_methods,                    /* tp_methods */ | 
 | 333 |     partial_memberlist,                 /* tp_members */ | 
 | 334 |     partial_getsetlist,                 /* tp_getset */ | 
 | 335 |     0,                                  /* tp_base */ | 
 | 336 |     0,                                  /* tp_dict */ | 
 | 337 |     0,                                  /* tp_descr_get */ | 
 | 338 |     0,                                  /* tp_descr_set */ | 
 | 339 |     offsetof(partialobject, dict),      /* tp_dictoffset */ | 
 | 340 |     0,                                  /* tp_init */ | 
 | 341 |     0,                                  /* tp_alloc */ | 
 | 342 |     partial_new,                        /* tp_new */ | 
 | 343 |     PyObject_GC_Del,                    /* tp_free */ | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 344 | }; | 
 | 345 |  | 
 | 346 |  | 
| Raymond Hettinger | 7ab9e22 | 2011-04-05 02:33:54 -0700 | [diff] [blame] | 347 | /* cmp_to_key ***************************************************************/ | 
 | 348 |  | 
 | 349 | typedef struct { | 
| Victor Stinner | 446c8d5 | 2011-04-05 12:21:35 +0200 | [diff] [blame] | 350 |     PyObject_HEAD | 
| Raymond Hettinger | 7ab9e22 | 2011-04-05 02:33:54 -0700 | [diff] [blame] | 351 |     PyObject *cmp; | 
 | 352 |     PyObject *object; | 
 | 353 | } keyobject; | 
 | 354 |  | 
 | 355 | static void | 
 | 356 | keyobject_dealloc(keyobject *ko) | 
 | 357 | { | 
 | 358 |     Py_DECREF(ko->cmp); | 
 | 359 |     Py_XDECREF(ko->object); | 
 | 360 |     PyObject_FREE(ko); | 
 | 361 | } | 
 | 362 |  | 
 | 363 | static int | 
 | 364 | keyobject_traverse(keyobject *ko, visitproc visit, void *arg) | 
 | 365 | { | 
 | 366 |     Py_VISIT(ko->cmp); | 
 | 367 |     if (ko->object) | 
 | 368 |         Py_VISIT(ko->object); | 
 | 369 |     return 0; | 
 | 370 | } | 
 | 371 |  | 
| Benjamin Peterson | 3bd9729 | 2011-04-05 17:25:14 -0500 | [diff] [blame] | 372 | static int | 
 | 373 | keyobject_clear(keyobject *ko) | 
 | 374 | { | 
 | 375 |     Py_CLEAR(ko->cmp); | 
 | 376 |     if (ko->object) | 
 | 377 |         Py_CLEAR(ko->object); | 
 | 378 |     return 0; | 
 | 379 | } | 
 | 380 |  | 
| Raymond Hettinger | 7ab9e22 | 2011-04-05 02:33:54 -0700 | [diff] [blame] | 381 | static PyMemberDef keyobject_members[] = { | 
 | 382 |     {"obj", T_OBJECT, | 
 | 383 |      offsetof(keyobject, object), 0, | 
 | 384 |      PyDoc_STR("Value wrapped by a key function.")}, | 
 | 385 |     {NULL} | 
 | 386 | }; | 
 | 387 |  | 
 | 388 | static PyObject * | 
| Raymond Hettinger | a563286 | 2011-04-09 12:57:00 -0700 | [diff] [blame] | 389 | keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds); | 
| Raymond Hettinger | 7ab9e22 | 2011-04-05 02:33:54 -0700 | [diff] [blame] | 390 |  | 
 | 391 | static PyObject * | 
 | 392 | keyobject_richcompare(PyObject *ko, PyObject *other, int op); | 
 | 393 |  | 
 | 394 | static PyTypeObject keyobject_type = { | 
 | 395 |     PyVarObject_HEAD_INIT(&PyType_Type, 0) | 
 | 396 |     "functools.KeyWrapper",             /* tp_name */ | 
 | 397 |     sizeof(keyobject),                  /* tp_basicsize */ | 
 | 398 |     0,                                  /* tp_itemsize */ | 
 | 399 |     /* methods */ | 
 | 400 |     (destructor)keyobject_dealloc,      /* tp_dealloc */ | 
 | 401 |     0,                                  /* tp_print */ | 
 | 402 |     0,                                  /* tp_getattr */ | 
 | 403 |     0,                                  /* tp_setattr */ | 
 | 404 |     0,                                  /* tp_reserved */ | 
 | 405 |     0,                                  /* tp_repr */ | 
 | 406 |     0,                                  /* tp_as_number */ | 
 | 407 |     0,                                  /* tp_as_sequence */ | 
 | 408 |     0,                                  /* tp_as_mapping */ | 
 | 409 |     0,                                  /* tp_hash */ | 
 | 410 |     (ternaryfunc)keyobject_call,        /* tp_call */ | 
 | 411 |     0,                                  /* tp_str */ | 
 | 412 |     PyObject_GenericGetAttr,            /* tp_getattro */ | 
 | 413 |     0,                                  /* tp_setattro */ | 
 | 414 |     0,                                  /* tp_as_buffer */ | 
 | 415 |     Py_TPFLAGS_DEFAULT,                 /* tp_flags */ | 
 | 416 |     0,                                  /* tp_doc */ | 
 | 417 |     (traverseproc)keyobject_traverse,   /* tp_traverse */ | 
| Benjamin Peterson | 3bd9729 | 2011-04-05 17:25:14 -0500 | [diff] [blame] | 418 |     (inquiry)keyobject_clear,           /* tp_clear */ | 
| Raymond Hettinger | 7ab9e22 | 2011-04-05 02:33:54 -0700 | [diff] [blame] | 419 |     keyobject_richcompare,              /* tp_richcompare */ | 
 | 420 |     0,                                  /* tp_weaklistoffset */ | 
 | 421 |     0,                                  /* tp_iter */ | 
 | 422 |     0,                                  /* tp_iternext */ | 
 | 423 |     0,                                  /* tp_methods */ | 
 | 424 |     keyobject_members,                  /* tp_members */ | 
 | 425 |     0,                                  /* tp_getset */ | 
 | 426 | }; | 
 | 427 |  | 
 | 428 | static PyObject * | 
 | 429 | keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds) | 
 | 430 | { | 
 | 431 |     PyObject *object; | 
 | 432 |     keyobject *result; | 
 | 433 |     static char *kwargs[] = {"obj", NULL}; | 
 | 434 |  | 
 | 435 |     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object)) | 
 | 436 |         return NULL; | 
 | 437 |     result = PyObject_New(keyobject, &keyobject_type); | 
 | 438 |     if (!result) | 
 | 439 |         return NULL; | 
 | 440 |     Py_INCREF(ko->cmp); | 
 | 441 |     result->cmp = ko->cmp; | 
 | 442 |     Py_INCREF(object); | 
 | 443 |     result->object = object; | 
 | 444 |     return (PyObject *)result; | 
 | 445 | } | 
 | 446 |  | 
 | 447 | static PyObject * | 
 | 448 | keyobject_richcompare(PyObject *ko, PyObject *other, int op) | 
 | 449 | { | 
 | 450 |     PyObject *res; | 
 | 451 |     PyObject *args; | 
 | 452 |     PyObject *x; | 
 | 453 |     PyObject *y; | 
 | 454 |     PyObject *compare; | 
 | 455 |     PyObject *answer; | 
 | 456 |     static PyObject *zero; | 
 | 457 |  | 
 | 458 |     if (zero == NULL) { | 
 | 459 |         zero = PyLong_FromLong(0); | 
 | 460 |         if (!zero) | 
 | 461 |             return NULL; | 
 | 462 |     } | 
 | 463 |  | 
 | 464 |     if (Py_TYPE(other) != &keyobject_type){ | 
 | 465 |         PyErr_Format(PyExc_TypeError, "other argument must be K instance"); | 
 | 466 |         return NULL; | 
 | 467 |     } | 
 | 468 |     compare = ((keyobject *) ko)->cmp; | 
 | 469 |     assert(compare != NULL); | 
 | 470 |     x = ((keyobject *) ko)->object; | 
 | 471 |     y = ((keyobject *) other)->object; | 
 | 472 |     if (!x || !y){ | 
 | 473 |         PyErr_Format(PyExc_AttributeError, "object"); | 
 | 474 |         return NULL; | 
 | 475 |     } | 
 | 476 |  | 
 | 477 |     /* Call the user's comparison function and translate the 3-way | 
 | 478 |      * result into true or false (or error). | 
 | 479 |      */ | 
 | 480 |     args = PyTuple_New(2); | 
 | 481 |     if (args == NULL) | 
 | 482 |         return NULL; | 
 | 483 |     Py_INCREF(x); | 
 | 484 |     Py_INCREF(y); | 
 | 485 |     PyTuple_SET_ITEM(args, 0, x); | 
 | 486 |     PyTuple_SET_ITEM(args, 1, y); | 
 | 487 |     res = PyObject_Call(compare, args, NULL); | 
 | 488 |     Py_DECREF(args); | 
 | 489 |     if (res == NULL) | 
 | 490 |         return NULL; | 
 | 491 |     answer = PyObject_RichCompare(res, zero, op); | 
 | 492 |     Py_DECREF(res); | 
 | 493 |     return answer; | 
 | 494 | } | 
 | 495 |  | 
 | 496 | static PyObject * | 
| Victor Stinner | 446c8d5 | 2011-04-05 12:21:35 +0200 | [diff] [blame] | 497 | functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds) | 
 | 498 | { | 
 | 499 |     PyObject *cmp; | 
| Raymond Hettinger | 7ab9e22 | 2011-04-05 02:33:54 -0700 | [diff] [blame] | 500 |     static char *kwargs[] = {"mycmp", NULL}; | 
| Victor Stinner | 446c8d5 | 2011-04-05 12:21:35 +0200 | [diff] [blame] | 501 |     keyobject *object; | 
| Raymond Hettinger | 7ab9e22 | 2011-04-05 02:33:54 -0700 | [diff] [blame] | 502 |  | 
 | 503 |     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp)) | 
 | 504 |         return NULL; | 
| Victor Stinner | 446c8d5 | 2011-04-05 12:21:35 +0200 | [diff] [blame] | 505 |     object = PyObject_New(keyobject, &keyobject_type); | 
| Raymond Hettinger | 7ab9e22 | 2011-04-05 02:33:54 -0700 | [diff] [blame] | 506 |     if (!object) | 
 | 507 |         return NULL; | 
 | 508 |     Py_INCREF(cmp); | 
 | 509 |     object->cmp = cmp; | 
 | 510 |     object->object = NULL; | 
 | 511 |     return (PyObject *)object; | 
 | 512 | } | 
 | 513 |  | 
 | 514 | PyDoc_STRVAR(functools_cmp_to_key_doc, | 
 | 515 | "Convert a cmp= function into a key= function."); | 
 | 516 |  | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 517 | /* reduce (used to be a builtin) ********************************************/ | 
 | 518 |  | 
 | 519 | static PyObject * | 
 | 520 | functools_reduce(PyObject *self, PyObject *args) | 
 | 521 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 522 |     PyObject *seq, *func, *result = NULL, *it; | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 523 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 524 |     if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result)) | 
 | 525 |         return NULL; | 
 | 526 |     if (result != NULL) | 
 | 527 |         Py_INCREF(result); | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 528 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 529 |     it = PyObject_GetIter(seq); | 
 | 530 |     if (it == NULL) { | 
| Alexander Belopolsky | e29e6bf | 2010-08-16 18:55:46 +0000 | [diff] [blame] | 531 |         if (PyErr_ExceptionMatches(PyExc_TypeError)) | 
 | 532 |             PyErr_SetString(PyExc_TypeError, | 
 | 533 |                             "reduce() arg 2 must support iteration"); | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 534 |         Py_XDECREF(result); | 
 | 535 |         return NULL; | 
 | 536 |     } | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 537 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 538 |     if ((args = PyTuple_New(2)) == NULL) | 
 | 539 |         goto Fail; | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 540 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 541 |     for (;;) { | 
 | 542 |         PyObject *op2; | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 543 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 544 |         if (args->ob_refcnt > 1) { | 
 | 545 |             Py_DECREF(args); | 
 | 546 |             if ((args = PyTuple_New(2)) == NULL) | 
 | 547 |                 goto Fail; | 
 | 548 |         } | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 549 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 550 |         op2 = PyIter_Next(it); | 
 | 551 |         if (op2 == NULL) { | 
 | 552 |             if (PyErr_Occurred()) | 
 | 553 |                 goto Fail; | 
 | 554 |             break; | 
 | 555 |         } | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 556 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 557 |         if (result == NULL) | 
 | 558 |             result = op2; | 
 | 559 |         else { | 
 | 560 |             PyTuple_SetItem(args, 0, result); | 
 | 561 |             PyTuple_SetItem(args, 1, op2); | 
 | 562 |             if ((result = PyEval_CallObject(func, args)) == NULL) | 
 | 563 |                 goto Fail; | 
 | 564 |         } | 
 | 565 |     } | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 566 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 567 |     Py_DECREF(args); | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 568 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 569 |     if (result == NULL) | 
 | 570 |         PyErr_SetString(PyExc_TypeError, | 
 | 571 |                    "reduce() of empty sequence with no initial value"); | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 572 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 573 |     Py_DECREF(it); | 
 | 574 |     return result; | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 575 |  | 
 | 576 | Fail: | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 577 |     Py_XDECREF(args); | 
 | 578 |     Py_XDECREF(result); | 
 | 579 |     Py_DECREF(it); | 
 | 580 |     return NULL; | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 581 | } | 
 | 582 |  | 
 | 583 | PyDoc_STRVAR(functools_reduce_doc, | 
 | 584 | "reduce(function, sequence[, initial]) -> value\n\ | 
 | 585 | \n\ | 
 | 586 | Apply a function of two arguments cumulatively to the items of a sequence,\n\ | 
 | 587 | from left to right, so as to reduce the sequence to a single value.\n\ | 
 | 588 | For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\ | 
 | 589 | ((((1+2)+3)+4)+5).  If initial is present, it is placed before the items\n\ | 
 | 590 | of the sequence in the calculation, and serves as a default when the\n\ | 
 | 591 | sequence is empty."); | 
 | 592 |  | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 593 | /* module level code ********************************************************/ | 
 | 594 |  | 
 | 595 | PyDoc_STRVAR(module_doc, | 
| Thomas Wouters | 4d70c3d | 2006-06-08 14:42:34 +0000 | [diff] [blame] | 596 | "Tools that operate on functions."); | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 597 |  | 
 | 598 | static PyMethodDef module_methods[] = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 599 |     {"reduce",          functools_reduce,     METH_VARARGS, functools_reduce_doc}, | 
| Victor Stinner | 446c8d5 | 2011-04-05 12:21:35 +0200 | [diff] [blame] | 600 |     {"cmp_to_key",      (PyCFunction)functools_cmp_to_key, | 
 | 601 |      METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc}, | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 602 |     {NULL,              NULL}           /* sentinel */ | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 603 | }; | 
 | 604 |  | 
| Martin v. Löwis | 1a21451 | 2008-06-11 05:26:20 +0000 | [diff] [blame] | 605 |  | 
 | 606 | static struct PyModuleDef _functoolsmodule = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 607 |     PyModuleDef_HEAD_INIT, | 
 | 608 |     "_functools", | 
 | 609 |     module_doc, | 
 | 610 |     -1, | 
 | 611 |     module_methods, | 
 | 612 |     NULL, | 
 | 613 |     NULL, | 
 | 614 |     NULL, | 
 | 615 |     NULL | 
| Martin v. Löwis | 1a21451 | 2008-06-11 05:26:20 +0000 | [diff] [blame] | 616 | }; | 
 | 617 |  | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 618 | PyMODINIT_FUNC | 
| Martin v. Löwis | 1a21451 | 2008-06-11 05:26:20 +0000 | [diff] [blame] | 619 | PyInit__functools(void) | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 620 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 621 |     int i; | 
 | 622 |     PyObject *m; | 
 | 623 |     char *name; | 
 | 624 |     PyTypeObject *typelist[] = { | 
 | 625 |         &partial_type, | 
 | 626 |         NULL | 
 | 627 |     }; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 628 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 629 |     m = PyModule_Create(&_functoolsmodule); | 
 | 630 |     if (m == NULL) | 
 | 631 |         return NULL; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 632 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 633 |     for (i=0 ; typelist[i] != NULL ; i++) { | 
 | 634 |         if (PyType_Ready(typelist[i]) < 0) { | 
 | 635 |             Py_DECREF(m); | 
 | 636 |             return NULL; | 
 | 637 |         } | 
 | 638 |         name = strchr(typelist[i]->tp_name, '.'); | 
 | 639 |         assert (name != NULL); | 
 | 640 |         Py_INCREF(typelist[i]); | 
 | 641 |         PyModule_AddObject(m, name+1, (PyObject *)typelist[i]); | 
 | 642 |     } | 
 | 643 |     return m; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 644 | } |