[Rpm-maint] [PATCH 15/15] Hack up various dark corners so that they compile with Python 3
Panu Matilainen
pmatilai at redhat.com
Thu Oct 29 12:24:26 UTC 2009
On Thu, 15 Oct 2009, David Malcolm wrote:
> diff --git a/python/rpmds-py.c b/python/rpmds-py.c
> index f45c908..1b091f9 100644
> --- a/python/rpmds-py.c
> +++ b/python/rpmds-py.c
> @@ -473,7 +473,10 @@ PyTypeObject rpmds_Type = {
> PyObject_GenericSetAttr, /* tp_setattro */
> 0, /* tp_as_buffer */
> Py_TPFLAGS_DEFAULT | /* tp_flags */
> +#if PY_MAJOR_VERSION < 3
> + /* FIXME: doublecheck this flag */
> Py_TPFLAGS_HAVE_RICHCOMPARE |
> +#endif
Py_TPFLAGS_HAVE_RICHCOMPARE is included in Py_TPFLAGS_DEFAULT for any
remotely recent Python 2.x versions, so it's simply unnecessary.
Removed...
> diff --git a/python/rpmfd-py.c b/python/rpmfd-py.c
> index 97cd100..837cea5 100644
> --- a/python/rpmfd-py.c
> +++ b/python/rpmfd-py.c
> @@ -9,12 +9,15 @@ int rpmFdFromPyObject(PyObject *obj, FD_t *fdp)
>
> if (PyInt_Check(obj)) {
> fd = fdDup(PyInt_AsLong(obj));
> +/* FIXME: still need to port this block to Py3k */
> +#if PY_MAJOR_VERSION < 3
> } else if (PyFile_Check(obj)) {
> FILE *fp = PyFile_AsFile(obj);
> fd = fdDup(fileno(fp));
> } else {
> PyErr_SetString(PyExc_TypeError, "integer or file object expected");
> return 0;
> +#endif
Turns out Python has a nice way to deal with this:
PyObject_AsFileDescriptor(). Using it not only avoids the 2.x vs 3.x
incompatibility but it also makes it work with any file-like object
implementing .fileno() method (including rpm.fd itself), and it even
reduces code :) Fixed in HEAD.
> }
> if (Ferror(fd)) {
> PyErr_SetString(PyExc_IOError, Fstrerror(fd));
> @@ -51,12 +54,28 @@ static PyObject *rpmfd_new(PyTypeObject *subtype,
> &fo, &mode, &flags))
> return NULL;
>
> - if (PyString_Check(fo)) {
> +#if PY_MAJOR_VERSION >= 3
> + /* Handle py3k unicode objects by decoding using default FS encoding */
> + if (PyUnicode_Check(fo)) {
> + PyObject *fs_encoded_bytes = NULL;
> + if (PyUnicode_FSConverter(fo, &fs_encoded_bytes)) {
> char *m = rstrscat(NULL, mode, ".", flags, NULL);
> Py_BEGIN_ALLOW_THREADS
> - fd = Fopen(PyString_AsString(fo), m);
> + fd = Fopen(PyBytes_AsString(fo), m);
> Py_END_ALLOW_THREADS
> free(m);
> + Py_DECREF(fs_encoded_bytes);
> + } else {
> + return NULL;
> + }
> +#else
> + if (PyBytes_Check(fo)) {
> + char *m = rstrscat(NULL, mode, ".", flags, NULL);
> + Py_BEGIN_ALLOW_THREADS
> + fd = Fopen(PyBytes_AsString(fo), m);
> + Py_END_ALLOW_THREADS
> + free(m);
> +#endif
> } else if (!rpmFdFromPyObject(fo, &fd)) {
> return NULL;
> }
Oh grumble... damn encodings. But ok I guess there's no way around it.
Just makes me wonder what to do with file names from headers, since we
have no clue of their encoding.
> diff --git a/python/rpmmodule.c b/python/rpmmodule.c
> index e0aeddc..c281db1 100644
> --- a/python/rpmmodule.c
> +++ b/python/rpmmodule.c
> @@ -64,6 +64,8 @@ static PyObject * setLogFile (PyObject * self, PyObject * args, PyObject *kwds)
> if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:logSetFile", kwlist, &fop))
> return NULL;
>
> +/* FIXME: still need to port this block to Py3k */
> +#if PY_MAJOR_VERSION < 3
> if (fop) {
> if (!PyFile_Check(fop)) {
> PyErr_SetString(PyExc_TypeError, "requires file object");
> @@ -71,6 +73,7 @@ static PyObject * setLogFile (PyObject * self, PyObject * args, PyObject *kwds)
> }
> fp = PyFile_AsFile(fop);
> }
> +#endif
I changed this to use PyObject_AsFileDescriptor() so it at least compiles,
although it gets a bit murky, need to check that it still works...
>
> (void) rpmlogSetFile(fp);
>
> diff --git a/python/rpmts-py.c b/python/rpmts-py.c
> index cc0ed00..3633d61 100644
> --- a/python/rpmts-py.c
> +++ b/python/rpmts-py.c
> @@ -159,7 +159,14 @@ static void die(PyObject *cb)
> PyErr_Print();
> }
> if ((r = PyObject_Repr(cb)) != NULL) {
> +#if PY_MAJOR_VERSION >= 3
> + /* FIXME: this is making assumptions about the encoding of stderr.*/
> + PyObject *utf8_bytes = PyUnicode_AsUTF8String(r);
> + pyfn = PyBytes_AsString(utf8_bytes);
> + Py_XDECREF(utf8_bytes);
> +#else
> pyfn = PyString_AsString(r);
> +#endif
> }
> fprintf(stderr, _("error: python callback %s failed, aborting!\n"),
> pyfn ? pyfn : "???");
Hmm. Dunno if it's worth the trouble dealing with Repr encoding and all,
this is afterall the last S.O.S. before sinking, plain "Fatal error in
transaction callback, by the time you read this I am already dead" would
be just as well.
- Panu -
More information about the Rpm-maint
mailing list