1 #include "rpmsystem-py.h"
3 #include <rpm/rpmlib.h> /* rpmReadPackageFile, headerCheck */
4 #include <rpm/rpmtag.h>
5 #include <rpm/rpmpgp.h>
7 #include <rpm/rpmbuild.h>
10 #include "rpmds-py.h" /* XXX for rpmdsNew */
12 #include "rpmfi-py.h" /* XXX for rpmfiNew */
24 * \brief A python rpm.ts object represents an RPM transaction set.
26 * The transaction set is the workhorse of RPM. It performs the
27 * installation and upgrade of packages. The rpm.ts object is
28 * instantiated by the TransactionSet function in the rpm module.
30 * The TransactionSet function takes two optional arguments. The first
31 * argument is the root path. The second is the verify signature disable flags,
32 * a set of the following bits:
34 * - rpm.RPMVSF_NOHDRCHK if set, don't check rpmdb headers
35 * - rpm.RPMVSF_NEEDPAYLOAD if not set, check header+payload (if possible)
36 * - rpm.RPMVSF_NOSHA1HEADER if set, don't check header SHA1 digest
37 * - rpm.RPMVSF_NODSAHEADER if set, don't check header DSA signature
38 * - rpm.RPMVSF_NOMD5 if set, don't check header+payload MD5 digest
39 * - rpm.RPMVSF_NODSA if set, don't check header+payload DSA signature
40 * - rpm.RPMVSF_NORSA if set, don't check header+payload RSA signature
42 * For convenience, there are the following masks:
43 * - rpm._RPMVSF_NODIGESTS if set, don't check digest(s).
44 * - rpm._RPMVSF_NOSIGNATURES if set, don't check signature(s).
46 * A rpm.ts object has the following methods:
48 * - addInstall(hdr,data,mode) Add an install element to a transaction set.
49 * @param hdr the header to be added
50 * @param data user data that will be passed to the transaction callback
51 * during transaction execution
52 * @param mode optional argument that specifies if this package should
53 * be installed ('i'), upgraded ('u').
55 * - addErase(name) Add an erase element to a transaction set.
56 * @param name the package name to be erased
58 * - check() Perform a dependency check on the transaction set. After
59 * headers have been added to a transaction set, a dependency
60 * check can be performed to make sure that all package
61 * dependencies are satisfied.
62 * @return None If there are no unresolved dependencies
63 * Otherwise a list of complex tuples is returned, one tuple per
64 * unresolved dependency, with
65 * The format of the dependency tuple is:
66 * ((packageName, packageVersion, packageRelease),
67 * (reqName, reqVersion),
71 * packageName, packageVersion, packageRelease are the name,
72 * version, and release of the package that has the unresolved
73 * dependency or conflict.
74 * The reqName and reqVersion are the name and version of the
75 * requirement or conflict.
76 * The needsFlags is a bitfield that describes the versioned
77 * nature of a requirement or conflict. The constants
78 * rpm.RPMSENSE_LESS, rpm.RPMSENSE_GREATER, and
79 * rpm.RPMSENSE_EQUAL can be logical ANDed with the needsFlags
80 * to get versioned dependency information.
81 * suggestedPackage is a tuple if the dependency check was aware
82 * of a package that solves this dependency problem when the
83 * dependency check was run. Packages that are added to the
84 * transaction set as "available" are examined during the
85 * dependency check as possible dependency solvers. The tuple
86 * contains two values, (header, suggestedName). These are set to
87 * the header of the suggested package and its name, respectively.
88 * If there is no known package to solve the dependency problem,
89 * suggestedPackage is None.
90 * The constants rpm.RPMDEP_SENSE_CONFLICTS and
91 * rpm.RPMDEP_SENSE_REQUIRES are set to show a dependency as a
92 * requirement or a conflict.
94 * - ts.order() Do a topological sort of added element relations.
97 * - ts.setFlags(transFlags) Set transaction set flags.
98 * @param transFlags - bit(s) to controll transaction operations. The
99 * following values can be logically OR'ed together:
100 * - rpm.RPMTRANS_FLAG_TEST - test mode, do not modify the RPM
101 * database, change any files, or run any package scripts
102 * - rpm.RPMTRANS_FLAG_BUILD_PROBS - only build a list of
103 * problems encountered when attempting to run this transaction
105 * - rpm.RPMTRANS_FLAG_NOSCRIPTS - do not execute package scripts
106 * - rpm.RPMTRANS_FLAG_JUSTDB - only make changes to the rpm
107 * database, do not modify files.
108 * - rpm.RPMTRANS_FLAG_NOTRIGGERS - do not run trigger scripts
109 * - rpm.RPMTRANS_FLAG_NODOCS - do not install files marked as %doc
110 * - rpm.RPMTRANS_FLAG_ALLFILES - create all files, even if a
111 * file is marked %config(missingok) and an upgrade is
113 * - rpm.RPMTRANS_FLAG_KEEPOBSOLETE - do not remove obsoleted
115 * @return previous transFlags
117 * - ts.setProbFilter(ignoreSet) Set transaction set problem filter.
118 * @param problemSetFilter - control bit(s) to ignore classes of problems,
119 * a logical or of one or more of the following bit(s):
120 * - rpm.RPMPROB_FILTER_IGNOREOS -
121 * - rpm.RPMPROB_FILTER_IGNOREARCH -
122 * - rpm.RPMPROB_FILTER_REPLACEPKG -
123 * - rpm.RPMPROB_FILTER_FORCERELOCATE -
124 * - rpm.RPMPROB_FILTER_REPLACENEWFILES -
125 * - rpm.RPMPROB_FILTER_REPLACEOLDFILES -
126 * - rpm.RPMPROB_FILTER_OLDPACKAGE -
127 * - rpm.RPMPROB_FILTER_DISKSPACE -
128 * @return previous ignoreSet
130 * - ts.run(callback,data) Attempt to execute a transaction set.
131 * After the transaction set has been populated with install/upgrade or
132 * erase actions, the transaction set can be executed by invoking
133 * the ts.run() method.
136 struct rpmtsObject_s {
138 PyObject *md_dict; /*!< to look like PyModuleObject */
144 struct rpmtsCallbackType_s {
148 PyThreadState *_save;
152 static void die(PyObject *cb)
157 if (PyErr_Occurred()) {
160 if ((r = PyObject_Repr(cb)) != NULL) {
161 pyfn = PyString_AsString(r);
163 fprintf(stderr, _("error: python callback %s failed, aborting!\n"),
164 pyfn ? pyfn : "???");
165 rpmdbCheckTerminate(1);
170 rpmts_AddInstall(rpmtsObject * s, PyObject * args)
177 if (!PyArg_ParseTuple(args, "O&Oi:AddInstall",
178 hdrFromPyObject, &h, &key, &how))
181 rc = rpmtsAddInstallElement(s->ts, h, key, how, NULL);
182 return PyBool_FromLong((rc == 0));
186 rpmts_AddErase(rpmtsObject * s, PyObject * args)
190 if (!PyArg_ParseTuple(args, "O&:AddErase", hdrFromPyObject, &h))
193 return PyBool_FromLong(rpmtsAddEraseElement(s->ts, h, -1) == 0);
197 rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data)
199 struct rpmtsCallbackType_s * cbInfo = (struct rpmtsCallbackType_s *) data;
200 PyObject * args, * result;
203 if (cbInfo->tso == NULL) return res;
204 if (cbInfo->cb == Py_None) return res;
206 PyEval_RestoreThread(cbInfo->_save);
208 args = Py_BuildValue("(Oissi)", cbInfo->tso,
209 rpmdsTagN(ds), rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds));
210 result = PyEval_CallObject(cbInfo->cb, args);
216 if (PyInt_Check(result))
217 res = PyInt_AsLong(result);
221 cbInfo->_save = PyEval_SaveThread();
227 rpmts_Check(rpmtsObject * s, PyObject * args, PyObject * kwds)
229 struct rpmtsCallbackType_s cbInfo;
231 char * kwlist[] = {"callback", NULL};
233 memset(&cbInfo, 0, sizeof(cbInfo));
234 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:Check", kwlist,
238 if (cbInfo.cb != NULL) {
239 if (!PyCallable_Check(cbInfo.cb)) {
240 PyErr_SetString(PyExc_TypeError, "expected a callable");
243 rc = rpmtsSetSolveCallback(s->ts, rpmts_SolveCallback, (void *)&cbInfo);
247 cbInfo._save = PyEval_SaveThread();
249 rc = rpmtsCheck(s->ts);
251 PyEval_RestoreThread(cbInfo._save);
253 return PyBool_FromLong((rc == 0));
257 rpmts_Order(rpmtsObject * s)
261 Py_BEGIN_ALLOW_THREADS
262 rc = rpmtsOrder(s->ts);
265 return Py_BuildValue("i", rc);
269 rpmts_Clean(rpmtsObject * s)
277 rpmts_OpenDB(rpmtsObject * s)
281 dbmode = rpmtsGetDBMode(s->ts);
285 return Py_BuildValue("i", rpmtsOpenDB(s->ts, dbmode));
289 rpmts_CloseDB(rpmtsObject * s)
293 rc = rpmtsCloseDB(s->ts);
294 rpmtsSetDBMode(s->ts, -1); /* XXX disable lazy opens */
296 return Py_BuildValue("i", rc);
300 rpmts_InitDB(rpmtsObject * s)
304 rc = rpmtsInitDB(s->ts, O_RDONLY);
306 rc = rpmtsCloseDB(s->ts);
308 return Py_BuildValue("i", rc);
312 rpmts_RebuildDB(rpmtsObject * s)
316 Py_BEGIN_ALLOW_THREADS
317 rc = rpmtsRebuildDB(s->ts);
320 return Py_BuildValue("i", rc);
324 rpmts_VerifyDB(rpmtsObject * s)
328 Py_BEGIN_ALLOW_THREADS
329 rc = rpmtsVerifyDB(s->ts);
332 return Py_BuildValue("i", rc);
336 rpmts_HdrFromFdno(rpmtsObject * s, PyObject * args, PyObject * kwds)
338 PyObject * result = NULL;
342 char * kwlist[] = {"fd", NULL};
344 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:HdrFromFdno", kwlist,
345 rpmFdFromPyObject, &fd))
348 rpmrc = rpmReadPackageFile(s->ts, fd, "rpmts_HdrFromFdno", &h);
354 result = Py_BuildValue("N", hdr_Wrap(&hdr_Type, h));
355 h = headerFree(h); /* XXX ref held by result */
359 PyErr_SetString(pyrpmError, "public key not available");
362 case RPMRC_NOTTRUSTED:
363 PyErr_SetString(pyrpmError, "public key not trusted");
369 PyErr_SetString(pyrpmError, "error reading package header");
377 rpmts_HdrCheck(rpmtsObject * s, PyObject * args, PyObject * kwds)
380 PyObject * result = NULL;
385 char * kwlist[] = {"headers", NULL};
387 if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:HdrCheck", kwlist, &blob))
390 uh = PyString_AsString(blob);
391 uc = PyString_Size(blob);
393 rpmrc = headerCheck(s->ts, uh, uc, &msg);
402 PyErr_SetString(pyrpmError, "public key not availaiable");
405 case RPMRC_NOTTRUSTED:
406 PyErr_SetString(pyrpmError, "public key not trusted");
411 PyErr_SetString(pyrpmError, msg);
420 rpmts_PgpPrtPkts(rpmtsObject * s, PyObject * args, PyObject * kwds)
426 char * kwlist[] = {"octets", NULL};
428 if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:PgpPrtPkts", kwlist, &blob))
431 pkt = (unsigned char *)PyString_AsString(blob);
432 pktlen = PyString_Size(blob);
434 rc = pgpPrtPkts(pkt, pktlen, NULL, 1);
436 return Py_BuildValue("i", rc);
440 rpmts_PgpImportPubkey(rpmtsObject * s, PyObject * args, PyObject * kwds)
446 char * kwlist[] = {"pubkey", NULL};
448 if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:PgpImportPubkey",
452 pkt = (unsigned char *)PyString_AsString(blob);
453 pktlen = PyString_Size(blob);
455 rc = rpmtsImportPubkey(s->ts, pkt, pktlen);
457 return Py_BuildValue("i", rc);
461 rpmtsCallback(const void * hd, const rpmCallbackType what,
462 const rpm_loff_t amount, const rpm_loff_t total,
463 const void * pkgKey, rpmCallbackData data)
465 Header h = (Header) hd;
466 struct rpmtsCallbackType_s * cbInfo = data;
467 PyObject * pkgObj = (PyObject *) pkgKey;
468 PyObject * args, * result;
471 if (cbInfo->cb == Py_None) return NULL;
473 /* Synthesize a python object for callback (if necessary). */
474 if (pkgObj == NULL) {
476 pkgObj = Py_BuildValue("s", headerGetString(h, RPMTAG_NAME));
484 PyEval_RestoreThread(cbInfo->_save);
486 args = Py_BuildValue("(iLLOO)", what, amount, total, pkgObj, cbInfo->data);
487 result = PyEval_CallObject(cbInfo->cb, args);
495 if (what == RPMCALLBACK_INST_OPEN_FILE) {
498 if (!PyArg_Parse(result, "i", &fdno)) {
502 cbInfo->_save = PyEval_SaveThread();
505 fcntl(Fileno(fd), F_SETFD, FD_CLOEXEC);
509 if (what == RPMCALLBACK_INST_CLOSE_FILE) {
514 cbInfo->_save = PyEval_SaveThread();
520 rpmts_Problems(rpmtsObject * s)
522 return rpmps_Wrap(&rpmps_Type, rpmtsProblems(s->ts));
526 rpmts_Run(rpmtsObject * s, PyObject * args, PyObject * kwds)
529 struct rpmtsCallbackType_s cbInfo;
530 rpmprobFilterFlags ignoreSet;
531 char * kwlist[] = {"callback", "data", "ignoreSet", NULL};
533 if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOi:Run", kwlist,
534 &cbInfo.cb, &cbInfo.data, &ignoreSet))
538 cbInfo._save = PyEval_SaveThread();
540 if (cbInfo.cb != NULL) {
541 if (!PyCallable_Check(cbInfo.cb)) {
542 PyErr_SetString(PyExc_TypeError, "expected a callable");
545 (void) rpmtsSetNotifyCallback(s->ts, rpmtsCallback, (void *) &cbInfo);
548 rc = rpmtsRun(s->ts, NULL, ignoreSet);
551 (void) rpmtsSetNotifyCallback(s->ts, NULL, NULL);
553 PyEval_RestoreThread(cbInfo._save);
555 return Py_BuildValue("i", rc);
559 rpmts_iternext(rpmtsObject * s)
561 PyObject * result = NULL;
564 /* Reset iterator on 1st entry. */
565 if (s->tsi == NULL) {
566 s->tsi = rpmtsiInit(s->ts);
571 te = rpmtsiNext(s->tsi, 0);
573 result = rpmte_Wrap(&rpmte_Type, te);
575 s->tsi = rpmtsiFree(s->tsi);
582 rpmts_Match(rpmtsObject * s, PyObject * args, PyObject * kwds)
584 PyObject *Key = NULL;
586 /* XXX lkey *must* be a 32 bit integer, int "works" on all known platforms. */
589 rpmTag tag = RPMDBI_PACKAGES;
590 char * kwlist[] = {"tagNumber", "key", NULL};
592 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O:Match", kwlist,
593 tagNumFromPyObject, &tag, &Key))
597 if (PyString_Check(Key)) {
598 key = PyString_AsString(Key);
599 len = PyString_Size(Key);
600 } else if (PyInt_Check(Key)) {
601 lkey = PyInt_AsLong(Key);
605 PyErr_SetString(PyExc_TypeError, "unknown key type");
608 /* One of the conversions above failed, exception is set already */
609 if (PyErr_Occurred()) {
614 /* XXX If not already opened, open the database O_RDONLY now. */
615 /* XXX FIXME: lazy default rdonly open also done by rpmtsInitIterator(). */
616 if (rpmtsGetRdb(s->ts) == NULL) {
617 int rc = rpmtsOpenDB(s->ts, O_RDONLY);
618 if (rc || rpmtsGetRdb(s->ts) == NULL) {
619 PyErr_SetString(PyExc_TypeError, "rpmdb open failed");
624 return rpmmi_Wrap(&rpmmi_Type, rpmtsInitIterator(s->ts, tag, key, len), (PyObject*)s);
627 static struct PyMethodDef rpmts_methods[] = {
628 {"addInstall", (PyCFunction) rpmts_AddInstall, METH_VARARGS,
630 {"addErase", (PyCFunction) rpmts_AddErase, METH_VARARGS|METH_KEYWORDS,
632 {"check", (PyCFunction) rpmts_Check, METH_VARARGS|METH_KEYWORDS,
634 {"order", (PyCFunction) rpmts_Order, METH_NOARGS,
636 {"problems", (PyCFunction) rpmts_Problems, METH_NOARGS,
637 "ts.problems() -> ps\n\
638 - Return current problem set.\n" },
639 {"run", (PyCFunction) rpmts_Run, METH_VARARGS|METH_KEYWORDS,
640 "ts.run(callback, data) -> (problems)\n\
641 - Run a transaction set, returning list of problems found.\n\
642 Note: The callback may not be None.\n" },
643 {"clean", (PyCFunction) rpmts_Clean, METH_NOARGS,
645 {"openDB", (PyCFunction) rpmts_OpenDB, METH_NOARGS,
646 "ts.openDB() -> None\n\
647 - Open the default transaction rpmdb.\n\
648 Note: The transaction rpmdb is lazily opened, so ts.openDB() is seldom needed.\n" },
649 {"closeDB", (PyCFunction) rpmts_CloseDB, METH_NOARGS,
650 "ts.closeDB() -> None\n\
651 - Close the default transaction rpmdb.\n\
652 Note: ts.closeDB() disables lazy opens, and should hardly ever be used.\n" },
653 {"initDB", (PyCFunction) rpmts_InitDB, METH_NOARGS,
654 "ts.initDB() -> None\n\
655 - Initialize the default transaction rpmdb.\n\
656 Note: ts.initDB() is seldom needed anymore.\n" },
657 {"rebuildDB", (PyCFunction) rpmts_RebuildDB, METH_NOARGS,
658 "ts.rebuildDB() -> None\n\
659 - Rebuild the default transaction rpmdb.\n" },
660 {"verifyDB", (PyCFunction) rpmts_VerifyDB, METH_NOARGS,
661 "ts.verifyDB() -> None\n\
662 - Verify the default transaction rpmdb.\n" },
663 {"hdrFromFdno",(PyCFunction) rpmts_HdrFromFdno,METH_VARARGS|METH_KEYWORDS,
664 "ts.hdrFromFdno(fdno) -> hdr\n\
665 - Read a package header from a file descriptor.\n" },
666 {"hdrCheck", (PyCFunction) rpmts_HdrCheck, METH_VARARGS|METH_KEYWORDS,
668 {"pgpPrtPkts", (PyCFunction) rpmts_PgpPrtPkts, METH_VARARGS|METH_KEYWORDS,
670 {"pgpImportPubkey", (PyCFunction) rpmts_PgpImportPubkey, METH_VARARGS|METH_KEYWORDS,
672 {"dbMatch", (PyCFunction) rpmts_Match, METH_VARARGS|METH_KEYWORDS,
673 "ts.dbMatch([TagN, [key, [len]]]) -> mi\n\
674 - Create a match iterator for the default transaction rpmdb.\n" },
675 {NULL, NULL} /* sentinel */
678 static void rpmts_dealloc(rpmtsObject * s)
681 s->ts = rpmtsFree(s->ts);
683 if (s->scriptFd) Fclose(s->scriptFd);
684 s->ob_type->tp_free((PyObject *)s);
687 static PyObject * rpmts_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds)
689 char * rootDir = "/";
690 rpmVSFlags vsflags = rpmExpandNumeric("%{?__vsflags}");
691 char * kwlist[] = {"rootdir", "vsflags", 0};
694 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si:rpmts_new", kwlist,
699 (void) rpmtsSetRootDir(ts, rootDir);
700 /* XXX: make this use common code with rpmts_SetVSFlags() to check the
702 (void) rpmtsSetVSFlags(ts, vsflags);
704 return rpmts_Wrap(subtype, ts);
707 static PyObject *rpmts_get_tid(rpmtsObject *s, void *closure)
709 return Py_BuildValue("i", rpmtsGetTid(s->ts));
712 static PyObject *rpmts_get_rootDir(rpmtsObject *s, void *closure)
714 return Py_BuildValue("s", rpmtsRootDir(s->ts));
717 static int rpmts_set_scriptFd(rpmtsObject *s, PyObject *value, void *closure)
720 if (PyArg_Parse(value, "O&", rpmFdFromPyObject, &s->scriptFd)) {
721 rpmtsSetScriptFd(s->ts, s->scriptFd);
722 } else if (value == Py_None) {
725 rpmtsSetScriptFd(s->ts, NULL);
732 static PyObject *rpmts_get_color(rpmtsObject *s, void *closure)
734 return Py_BuildValue("i", rpmtsColor(s->ts));
737 static PyObject *rpmts_get_prefcolor(rpmtsObject *s, void *closure)
739 return Py_BuildValue("i", rpmtsPrefColor(s->ts));
742 static int rpmts_set_color(rpmtsObject *s, PyObject *value, void *closure)
745 if (!PyArg_Parse(value, "i", &color)) return -1;
747 /* TODO: validate the bits */
748 rpmtsSetColor(s->ts, color);
752 static int rpmts_set_prefcolor(rpmtsObject *s, PyObject *value, void *closure)
755 if (!PyArg_Parse(value, "i", &color)) return -1;
757 /* TODO: validate the bits */
758 rpmtsSetPrefColor(s->ts, color);
762 static int rpmts_set_flags(rpmtsObject *s, PyObject *value, void *closure)
765 if (!PyArg_Parse(value, "i", &flags)) return -1;
767 /* TODO: validate the bits */
768 rpmtsSetFlags(s->ts, flags);
772 static int rpmts_set_vsflags(rpmtsObject *s, PyObject *value, void *closure)
775 if (!PyArg_Parse(value, "i", &flags)) return -1;
777 /* TODO: validate the bits */
778 rpmtsSetVSFlags(s->ts, flags);
782 static PyObject *rpmts_get_flags(rpmtsObject *s, void *closure)
784 return Py_BuildValue("i", rpmtsFlags(s->ts));
787 static PyObject *rpmts_get_vsflags(rpmtsObject *s, void *closure)
789 return Py_BuildValue("i", rpmtsVSFlags(s->ts));
792 static char rpmts_doc[] =
795 static PyGetSetDef rpmts_getseters[] = {
796 /* only provide a setter until we have rpmfd wrappings */
797 {"scriptFd", NULL, (setter)rpmts_set_scriptFd, NULL },
798 {"tid", (getter)rpmts_get_tid, NULL, NULL },
799 {"rootDir", (getter)rpmts_get_rootDir, NULL, NULL },
800 {"_color", (getter)rpmts_get_color, (setter)rpmts_set_color, NULL},
801 {"_prefcolor", (getter)rpmts_get_prefcolor, (setter)rpmts_set_prefcolor, NULL},
802 {"_flags", (getter)rpmts_get_flags, (setter)rpmts_set_flags, NULL},
803 {"_vsflags", (getter)rpmts_get_vsflags, (setter)rpmts_set_vsflags, NULL},
807 PyTypeObject rpmts_Type = {
808 PyObject_HEAD_INIT(&PyType_Type)
810 "rpm.ts", /* tp_name */
811 sizeof(rpmtsObject), /* tp_size */
813 (destructor) rpmts_dealloc, /* tp_dealloc */
815 (getattrfunc)0, /* tp_getattr */
816 (setattrfunc)0, /* tp_setattr */
819 0, /* tp_as_number */
820 0, /* tp_as_sequence */
821 0, /* tp_as_mapping */
825 PyObject_GenericGetAttr, /* tp_getattro */
826 PyObject_GenericSetAttr, /* tp_setattro */
827 0, /* tp_as_buffer */
828 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
829 rpmts_doc, /* tp_doc */
832 0, /* tp_richcompare */
833 0, /* tp_weaklistoffset */
834 PyObject_SelfIter, /* tp_iter */
835 (iternextfunc) rpmts_iternext, /* tp_iternext */
836 rpmts_methods, /* tp_methods */
838 rpmts_getseters, /* tp_getset */
841 0, /* tp_descr_get */
842 0, /* tp_descr_set */
843 0, /* tp_dictoffset */
846 (newfunc) rpmts_new, /* tp_new */
851 PyObject * rpmts_Wrap(PyTypeObject *subtype, rpmts ts)
853 rpmtsObject * s = (rpmtsObject *)subtype->tp_alloc(subtype, 0);
854 if (s == NULL) return PyErr_NoMemory();
859 return (PyObject *) s;