[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