Panu Matilainen d4f7fd
From 84920f898315d09a57a3f1067433eaeb7de5e830 Mon Sep 17 00:00:00 2001
Panu Matilainen d4f7fd
Message-Id: <84920f898315d09a57a3f1067433eaeb7de5e830.1554884444.git.pmatilai@redhat.com>
Panu Matilainen d4f7fd
From: Panu Matilainen <pmatilai@redhat.com>
Panu Matilainen d4f7fd
Date: Fri, 22 Feb 2019 19:44:16 +0200
Panu Matilainen d4f7fd
Subject: [PATCH] In Python 3, return all our string data as surrogate-escaped
Panu Matilainen d4f7fd
 utf-8 strings
Panu Matilainen d4f7fd
Panu Matilainen d4f7fd
In the almost ten years of rpm sort of supporting Python 3 bindings, quite
Panu Matilainen d4f7fd
obviously nobody has actually tried to use them. There's a major mismatch
Panu Matilainen d4f7fd
between what the header API outputs (bytes) and what all the other APIs
Panu Matilainen d4f7fd
accept (strings), resulting in hysterical TypeErrors all over the place,
Panu Matilainen d4f7fd
including but not limited to labelCompare() (RhBug:1631292). Also a huge
Panu Matilainen d4f7fd
number of other places have been returning strings and silently assuming
Panu Matilainen d4f7fd
utf-8 through use of Py_BuildValue("s", ...), which will just irrevocably
Panu Matilainen d4f7fd
fail when non-utf8 data is encountered.
Panu Matilainen d4f7fd
Panu Matilainen d4f7fd
The politically Python 3-correct solution would be declaring all our data
Panu Matilainen d4f7fd
as bytes with unspecified encoding - that's exactly what it historically is.
Panu Matilainen d4f7fd
However doing so would by definition break every single rpm script people
Panu Matilainen d4f7fd
have developed on Python 2. And when 99% of the rpm content in the world
Panu Matilainen d4f7fd
actually is utf-8 encoded even if it doesn't say so (and in recent times
Panu Matilainen d4f7fd
packages even advertise themselves as utf-8 encoded), the bytes-only route
Panu Matilainen d4f7fd
seems a wee bit too draconian, even to this grumpy old fella.
Panu Matilainen d4f7fd
Panu Matilainen d4f7fd
Instead, route all our string returns through a single helper macro
Panu Matilainen d4f7fd
which on Python 2 just does what we always did, but in Python 3 converts
Panu Matilainen d4f7fd
the data to surrogate-escaped utf-8 strings. This makes stuff "just work"
Panu Matilainen d4f7fd
out of the box pretty much everywhere even with Python 3 (including
Panu Matilainen d4f7fd
our own test-suite!), while still allowing to handle the non-utf8 case.
Panu Matilainen d4f7fd
Handling the non-utf8 case is a bit more uglier but still possible,
Panu Matilainen d4f7fd
which is exactly how you want corner-cases to be. There might be some
Panu Matilainen d4f7fd
uses for retrieving raw byte data from the header, but worrying about
Panu Matilainen d4f7fd
such an API is a case for some other rainy day, for now we mostly only
Panu Matilainen d4f7fd
care that stuff works again.
Panu Matilainen d4f7fd
Panu Matilainen d4f7fd
Also add test-cases for mixed data source labelCompare() and
Panu Matilainen d4f7fd
non-utf8 insert to + retrieve from header.
Panu Matilainen d4f7fd
---
Panu Matilainen d4f7fd
 python/header-py.c     |  2 +-
Panu Matilainen d4f7fd
 python/rpmds-py.c      |  8 ++++----
Panu Matilainen d4f7fd
 python/rpmfd-py.c      |  6 +++---
Panu Matilainen d4f7fd
 python/rpmfi-py.c      | 24 ++++++++++++------------
Panu Matilainen d4f7fd
 python/rpmfiles-py.c   | 26 +++++++++++++-------------
Panu Matilainen d4f7fd
 python/rpmkeyring-py.c |  2 +-
Panu Matilainen d4f7fd
 python/rpmmacro-py.c   |  2 +-
Panu Matilainen d4f7fd
 python/rpmmodule.c     |  2 +-
Panu Matilainen d4f7fd
 python/rpmps-py.c      |  8 ++++----
Panu Matilainen d4f7fd
 python/rpmstrpool-py.c |  2 +-
Panu Matilainen d4f7fd
 python/rpmsystem-py.h  |  7 +++++++
Panu Matilainen d4f7fd
 python/rpmtd-py.c      |  2 +-
Panu Matilainen d4f7fd
 python/rpmte-py.c      | 16 ++++++++--------
Panu Matilainen d4f7fd
 python/rpmts-py.c      | 11 ++++++-----
Panu Matilainen d4f7fd
 python/spec-py.c       |  8 ++++----
Panu Matilainen d4f7fd
 tests/local.at         |  1 +
Panu Matilainen d4f7fd
 tests/rpmpython.at     | 34 ++++++++++++++++++++++++++++++++++
Panu Matilainen d4f7fd
 17 files changed, 102 insertions(+), 59 deletions(-)
Panu Matilainen d4f7fd
Panu Matilainen d4f7fd
diff --git a/python/header-py.c b/python/header-py.c
Panu Matilainen d4f7fd
index c9d54e869..93c241cb7 100644
Panu Matilainen d4f7fd
--- a/python/header-py.c
Panu Matilainen d4f7fd
+++ b/python/header-py.c
Panu Matilainen d4f7fd
@@ -231,7 +231,7 @@ static PyObject * hdrFormat(hdrObject * s, PyObject * args, PyObject * kwds)
Panu Matilainen d4f7fd
 	return NULL;
Panu Matilainen d4f7fd
     }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
-    result = Py_BuildValue("s", r);
Panu Matilainen d4f7fd
+    result = utf8FromString(r);
Panu Matilainen d4f7fd
     free(r);
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
     return result;
Panu Matilainen d4f7fd
diff --git a/python/rpmds-py.c b/python/rpmds-py.c
Panu Matilainen d4f7fd
index 39b26628e..ecc9af9d5 100644
Panu Matilainen d4f7fd
--- a/python/rpmds-py.c
Panu Matilainen d4f7fd
+++ b/python/rpmds-py.c
Panu Matilainen d4f7fd
@@ -31,19 +31,19 @@ rpmds_Ix(rpmdsObject * s)
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmds_DNEVR(rpmdsObject * s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmdsDNEVR(s->ds));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmdsDNEVR(s->ds));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmds_N(rpmdsObject * s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmdsN(s->ds));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmdsN(s->ds));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmds_EVR(rpmdsObject * s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmdsEVR(s->ds));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmdsEVR(s->ds));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
@@ -261,7 +261,7 @@ rpmds_subscript(rpmdsObject * s, PyObject * key)
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
     ix = (int) PyInt_AsLong(key);
Panu Matilainen d4f7fd
     rpmdsSetIx(s->ds, ix);
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmdsDNEVR(s->ds));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmdsDNEVR(s->ds));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyMappingMethods rpmds_as_mapping = {
Panu Matilainen d4f7fd
diff --git a/python/rpmfd-py.c b/python/rpmfd-py.c
Panu Matilainen d4f7fd
index 85fb0cd24..4b05cce5f 100644
Panu Matilainen d4f7fd
--- a/python/rpmfd-py.c
Panu Matilainen d4f7fd
+++ b/python/rpmfd-py.c
Panu Matilainen d4f7fd
@@ -327,17 +327,17 @@ static PyObject *rpmfd_get_closed(rpmfdObject *s)
Panu Matilainen d4f7fd
 static PyObject *rpmfd_get_name(rpmfdObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
     /* XXX: rpm returns non-paths with [mumble], python files use <mumble> */
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", Fdescr(s->fd));
Panu Matilainen d4f7fd
+    return utf8FromString(Fdescr(s->fd));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmfd_get_mode(rpmfdObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", s->mode);
Panu Matilainen d4f7fd
+    return utf8FromString(s->mode);
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmfd_get_flags(rpmfdObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", s->flags);
Panu Matilainen d4f7fd
+    return utf8FromString(s->flags);
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyGetSetDef rpmfd_getseters[] = {
Panu Matilainen d4f7fd
diff --git a/python/rpmfi-py.c b/python/rpmfi-py.c
Panu Matilainen d4f7fd
index 8d2f926d0..db405c231 100644
Panu Matilainen d4f7fd
--- a/python/rpmfi-py.c
Panu Matilainen d4f7fd
+++ b/python/rpmfi-py.c
Panu Matilainen d4f7fd
@@ -41,19 +41,19 @@ rpmfi_DX(rpmfiObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmfi_BN(rpmfiObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfiBN(s->fi));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfiBN(s->fi));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmfi_DN(rpmfiObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfiDN(s->fi));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfiDN(s->fi));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmfi_FN(rpmfiObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfiFN(s->fi));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfiFN(s->fi));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
@@ -98,7 +98,7 @@ rpmfi_Digest(rpmfiObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
     char *digest = rpmfiFDigestHex(s->fi, NULL);
Panu Matilainen d4f7fd
     if (digest) {
Panu Matilainen d4f7fd
-	PyObject *dig = Py_BuildValue("s", digest);
Panu Matilainen d4f7fd
+	PyObject *dig = utf8FromString(digest);
Panu Matilainen d4f7fd
 	free(digest);
Panu Matilainen d4f7fd
 	return dig;
Panu Matilainen d4f7fd
     } else {
Panu Matilainen d4f7fd
@@ -109,7 +109,7 @@ rpmfi_Digest(rpmfiObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmfi_FLink(rpmfiObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfiFLink(s->fi));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfiFLink(s->fi));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
@@ -133,13 +133,13 @@ rpmfi_FMtime(rpmfiObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmfi_FUser(rpmfiObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfiFUser(s->fi));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfiFUser(s->fi));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmfi_FGroup(rpmfiObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfiFGroup(s->fi));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfiFGroup(s->fi));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
@@ -155,7 +155,7 @@ rpmfi_FClass(rpmfiObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
     if ((FClass = rpmfiFClass(s->fi)) == NULL)
Panu Matilainen d4f7fd
 	FClass = "";
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", FClass);
Panu Matilainen d4f7fd
+    return utf8FromString(FClass);
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
@@ -208,7 +208,7 @@ rpmfi_iternext(rpmfiObject * s)
Panu Matilainen d4f7fd
 	    Py_INCREF(Py_None);
Panu Matilainen d4f7fd
 	    PyTuple_SET_ITEM(result, 0, Py_None);
Panu Matilainen d4f7fd
 	} else
Panu Matilainen d4f7fd
-	    PyTuple_SET_ITEM(result,  0, Py_BuildValue("s", FN));
Panu Matilainen d4f7fd
+	    PyTuple_SET_ITEM(result,  0, utf8FromString(FN));
Panu Matilainen d4f7fd
 	PyTuple_SET_ITEM(result,  1, PyLong_FromLongLong(FSize));
Panu Matilainen d4f7fd
 	PyTuple_SET_ITEM(result,  2, PyInt_FromLong(FMode));
Panu Matilainen d4f7fd
 	PyTuple_SET_ITEM(result,  3, PyInt_FromLong(FMtime));
Panu Matilainen d4f7fd
@@ -222,12 +222,12 @@ rpmfi_iternext(rpmfiObject * s)
Panu Matilainen d4f7fd
 	    Py_INCREF(Py_None);
Panu Matilainen d4f7fd
 	    PyTuple_SET_ITEM(result, 10, Py_None);
Panu Matilainen d4f7fd
 	} else
Panu Matilainen d4f7fd
-	    PyTuple_SET_ITEM(result, 10, Py_BuildValue("s", FUser));
Panu Matilainen d4f7fd
+	    PyTuple_SET_ITEM(result, 10, utf8FromString(FUser));
Panu Matilainen d4f7fd
 	if (FGroup == NULL) {
Panu Matilainen d4f7fd
 	    Py_INCREF(Py_None);
Panu Matilainen d4f7fd
 	    PyTuple_SET_ITEM(result, 11, Py_None);
Panu Matilainen d4f7fd
 	} else
Panu Matilainen d4f7fd
-	    PyTuple_SET_ITEM(result, 11, Py_BuildValue("s", FGroup));
Panu Matilainen d4f7fd
+	    PyTuple_SET_ITEM(result, 11, utf8FromString(FGroup));
Panu Matilainen d4f7fd
 	PyTuple_SET_ITEM(result, 12, rpmfi_Digest(s, NULL));
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
     } else
Panu Matilainen d4f7fd
@@ -313,7 +313,7 @@ rpmfi_subscript(rpmfiObject * s, PyObject * key)
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
     ix = (int) PyInt_AsLong(key);
Panu Matilainen d4f7fd
     rpmfiSetFX(s->fi, ix);
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfiFN(s->fi));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfiFN(s->fi));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyMappingMethods rpmfi_as_mapping = {
Panu Matilainen d4f7fd
diff --git a/python/rpmfiles-py.c b/python/rpmfiles-py.c
Panu Matilainen d4f7fd
index bc07dbeaf..557246cae 100644
Panu Matilainen d4f7fd
--- a/python/rpmfiles-py.c
Panu Matilainen d4f7fd
+++ b/python/rpmfiles-py.c
Panu Matilainen d4f7fd
@@ -41,37 +41,37 @@ static PyObject *rpmfile_dx(rpmfileObject *s)
Panu Matilainen d4f7fd
 static PyObject *rpmfile_name(rpmfileObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
     char * fn = rpmfilesFN(s->files, s->ix);
Panu Matilainen d4f7fd
-    PyObject *o = Py_BuildValue("s", fn);
Panu Matilainen d4f7fd
+    PyObject *o = utf8FromString(fn);
Panu Matilainen d4f7fd
     free(fn);
Panu Matilainen d4f7fd
     return o;
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmfile_basename(rpmfileObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfilesBN(s->files, s->ix));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfilesBN(s->files, s->ix));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmfile_dirname(rpmfileObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfilesDN(s->files, rpmfilesDI(s->files, s->ix)));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfilesDN(s->files, rpmfilesDI(s->files, s->ix)));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmfile_orig_name(rpmfileObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
     char * fn = rpmfilesOFN(s->files, s->ix);
Panu Matilainen d4f7fd
-    PyObject *o = Py_BuildValue("s", fn);
Panu Matilainen d4f7fd
+    PyObject *o = utf8FromString(fn);
Panu Matilainen d4f7fd
     free(fn);
Panu Matilainen d4f7fd
     return o;
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmfile_orig_basename(rpmfileObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfilesOBN(s->files, s->ix));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfilesOBN(s->files, s->ix));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmfile_orig_dirname(rpmfileObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfilesODN(s->files, rpmfilesODI(s->files, s->ix)));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfilesODN(s->files, rpmfilesODI(s->files, s->ix)));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 static PyObject *rpmfile_mode(rpmfileObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
@@ -105,17 +105,17 @@ static PyObject *rpmfile_nlink(rpmfileObject *s)
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmfile_linkto(rpmfileObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfilesFLink(s->files, s->ix));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfilesFLink(s->files, s->ix));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmfile_user(rpmfileObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfilesFUser(s->files, s->ix));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfilesFUser(s->files, s->ix));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmfile_group(rpmfileObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfilesFGroup(s->files, s->ix));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfilesFGroup(s->files, s->ix));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmfile_fflags(rpmfileObject *s)
Panu Matilainen d4f7fd
@@ -145,7 +145,7 @@ static PyObject *rpmfile_digest(rpmfileObject *s)
Panu Matilainen d4f7fd
 						  NULL, &diglen);
Panu Matilainen d4f7fd
     if (digest) {
Panu Matilainen d4f7fd
 	char * hex = pgpHexStr(digest, diglen);
Panu Matilainen d4f7fd
-	PyObject *o = Py_BuildValue("s", hex);
Panu Matilainen d4f7fd
+	PyObject *o = utf8FromString(hex);
Panu Matilainen d4f7fd
 	free(hex);
Panu Matilainen d4f7fd
 	return o;
Panu Matilainen d4f7fd
     }
Panu Matilainen d4f7fd
@@ -154,17 +154,17 @@ static PyObject *rpmfile_digest(rpmfileObject *s)
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmfile_class(rpmfileObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfilesFClass(s->files, s->ix));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfilesFClass(s->files, s->ix));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmfile_caps(rpmfileObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfilesFCaps(s->files, s->ix));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfilesFCaps(s->files, s->ix));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmfile_langs(rpmfileObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmfilesFLangs(s->files, s->ix));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmfilesFLangs(s->files, s->ix));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmfile_links(rpmfileObject *s)
Panu Matilainen d4f7fd
diff --git a/python/rpmkeyring-py.c b/python/rpmkeyring-py.c
Panu Matilainen d4f7fd
index d5f131e42..8968e0513 100644
Panu Matilainen d4f7fd
--- a/python/rpmkeyring-py.c
Panu Matilainen d4f7fd
+++ b/python/rpmkeyring-py.c
Panu Matilainen d4f7fd
@@ -38,7 +38,7 @@ static PyObject *rpmPubkey_new(PyTypeObject *subtype,
Panu Matilainen d4f7fd
 static PyObject * rpmPubkey_Base64(rpmPubkeyObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
     char *b64 = rpmPubkeyBase64(s->pubkey);
Panu Matilainen d4f7fd
-    PyObject *res = Py_BuildValue("s", b64);
Panu Matilainen d4f7fd
+    PyObject *res = utf8FromString(b64);
Panu Matilainen d4f7fd
     free(b64);
Panu Matilainen d4f7fd
     return res;
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
diff --git a/python/rpmmacro-py.c b/python/rpmmacro-py.c
Panu Matilainen d4f7fd
index 3cb1a51f5..d8a365547 100644
Panu Matilainen d4f7fd
--- a/python/rpmmacro-py.c
Panu Matilainen d4f7fd
+++ b/python/rpmmacro-py.c
Panu Matilainen d4f7fd
@@ -52,7 +52,7 @@ rpmmacro_ExpandMacro(PyObject * self, PyObject * args, PyObject * kwds)
Panu Matilainen d4f7fd
 	if (rpmExpandMacros(NULL, macro, &str, 0) < 0)
Panu Matilainen d4f7fd
 	    PyErr_SetString(pyrpmError, "error expanding macro");
Panu Matilainen d4f7fd
 	else
Panu Matilainen d4f7fd
-	    res = Py_BuildValue("s", str);
Panu Matilainen d4f7fd
+	    res = utf8FromString(str);
Panu Matilainen d4f7fd
 	free(str);
Panu Matilainen d4f7fd
     }
Panu Matilainen d4f7fd
     return res;
Panu Matilainen d4f7fd
diff --git a/python/rpmmodule.c b/python/rpmmodule.c
Panu Matilainen d4f7fd
index 3faad23c7..05032edc7 100644
Panu Matilainen d4f7fd
--- a/python/rpmmodule.c
Panu Matilainen d4f7fd
+++ b/python/rpmmodule.c
Panu Matilainen d4f7fd
@@ -237,7 +237,7 @@ static void addRpmTags(PyObject *module)
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 	PyModule_AddIntConstant(module, tagname, tagval);
Panu Matilainen d4f7fd
 	pyval = PyInt_FromLong(tagval);
Panu Matilainen d4f7fd
-	pyname = Py_BuildValue("s", shortname);
Panu Matilainen d4f7fd
+	pyname = utf8FromString(shortname);
Panu Matilainen d4f7fd
 	PyDict_SetItem(dict, pyval, pyname);
Panu Matilainen d4f7fd
 	Py_DECREF(pyval);
Panu Matilainen d4f7fd
 	Py_DECREF(pyname);
Panu Matilainen d4f7fd
diff --git a/python/rpmps-py.c b/python/rpmps-py.c
Panu Matilainen d4f7fd
index bdc899a60..902b2ae63 100644
Panu Matilainen d4f7fd
--- a/python/rpmps-py.c
Panu Matilainen d4f7fd
+++ b/python/rpmps-py.c
Panu Matilainen d4f7fd
@@ -18,12 +18,12 @@ static PyObject *rpmprob_get_type(rpmProblemObject *s, void *closure)
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmprob_get_pkgnevr(rpmProblemObject *s, void *closure)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmProblemGetPkgNEVR(s->prob));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmProblemGetPkgNEVR(s->prob));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmprob_get_altnevr(rpmProblemObject *s, void *closure)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmProblemGetAltNEVR(s->prob));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmProblemGetAltNEVR(s->prob));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmprob_get_key(rpmProblemObject *s, void *closure)
Panu Matilainen d4f7fd
@@ -38,7 +38,7 @@ static PyObject *rpmprob_get_key(rpmProblemObject *s, void *closure)
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmprob_get_str(rpmProblemObject *s, void *closure)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmProblemGetStr(s->prob));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmProblemGetStr(s->prob));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmprob_get_num(rpmProblemObject *s, void *closure)
Panu Matilainen d4f7fd
@@ -59,7 +59,7 @@ static PyGetSetDef rpmprob_getseters[] = {
Panu Matilainen d4f7fd
 static PyObject *rpmprob_str(rpmProblemObject *s)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
     char *str = rpmProblemString(s->prob);
Panu Matilainen d4f7fd
-    PyObject *res = Py_BuildValue("s", str);
Panu Matilainen d4f7fd
+    PyObject *res = utf8FromString(str);
Panu Matilainen d4f7fd
     free(str);
Panu Matilainen d4f7fd
     return res;
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
diff --git a/python/rpmstrpool-py.c b/python/rpmstrpool-py.c
Panu Matilainen d4f7fd
index 356bd1de5..a56e2b540 100644
Panu Matilainen d4f7fd
--- a/python/rpmstrpool-py.c
Panu Matilainen d4f7fd
+++ b/python/rpmstrpool-py.c
Panu Matilainen d4f7fd
@@ -44,7 +44,7 @@ static PyObject *strpool_id2str(rpmstrPoolObject *s, PyObject *item)
Panu Matilainen d4f7fd
 	const char *str = rpmstrPoolStr(s->pool, id);
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 	if (str)
Panu Matilainen d4f7fd
-	    ret = PyBytes_FromString(str);
Panu Matilainen d4f7fd
+	    ret = utf8FromString(str);
Panu Matilainen d4f7fd
 	else 
Panu Matilainen d4f7fd
 	    PyErr_SetObject(PyExc_KeyError, item);
Panu Matilainen d4f7fd
     }
Panu Matilainen d4f7fd
diff --git a/python/rpmsystem-py.h b/python/rpmsystem-py.h
Panu Matilainen d4f7fd
index 955d60cd3..87c750571 100644
Panu Matilainen d4f7fd
--- a/python/rpmsystem-py.h
Panu Matilainen d4f7fd
+++ b/python/rpmsystem-py.h
Panu Matilainen d4f7fd
@@ -19,4 +19,11 @@
Panu Matilainen d4f7fd
 #define PyInt_AsSsize_t PyLong_AsSsize_t
Panu Matilainen d4f7fd
 #endif
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
+/* In Python 3, we return all strings as surrogate-escaped utf-8 */
Panu Matilainen d4f7fd
+#if PY_MAJOR_VERSION >= 3
Panu Matilainen d4f7fd
+#define utf8FromString(_s) PyUnicode_DecodeUTF8(_s, strlen(_s), "surrogateescape")
Panu Matilainen d4f7fd
+#else
Panu Matilainen d4f7fd
+#define utf8FromString(_s) PyBytes_FromString(_s)
Panu Matilainen d4f7fd
+#endif
Panu Matilainen d4f7fd
+
Panu Matilainen d4f7fd
 #endif	/* H_SYSTEM_PYTHON */
Panu Matilainen d4f7fd
diff --git a/python/rpmtd-py.c b/python/rpmtd-py.c
Panu Matilainen d4f7fd
index 247c7502a..23ca10517 100644
Panu Matilainen d4f7fd
--- a/python/rpmtd-py.c
Panu Matilainen d4f7fd
+++ b/python/rpmtd-py.c
Panu Matilainen d4f7fd
@@ -17,7 +17,7 @@ PyObject * rpmtd_ItemAsPyobj(rpmtd td, rpmTagClass tclass)
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
     switch (tclass) {
Panu Matilainen d4f7fd
     case RPM_STRING_CLASS:
Panu Matilainen d4f7fd
-	res = PyBytes_FromString(rpmtdGetString(td));
Panu Matilainen d4f7fd
+	res = utf8FromString(rpmtdGetString(td));
Panu Matilainen d4f7fd
 	break;
Panu Matilainen d4f7fd
     case RPM_NUMERIC_CLASS:
Panu Matilainen d4f7fd
 	res = PyLong_FromLongLong(rpmtdGetNumber(td));
Panu Matilainen d4f7fd
diff --git a/python/rpmte-py.c b/python/rpmte-py.c
Panu Matilainen d4f7fd
index 99ff2f496..2b3745754 100644
Panu Matilainen d4f7fd
--- a/python/rpmte-py.c
Panu Matilainen d4f7fd
+++ b/python/rpmte-py.c
Panu Matilainen d4f7fd
@@ -54,49 +54,49 @@ rpmte_TEType(rpmteObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmte_N(rpmteObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmteN(s->te));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmteN(s->te));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmte_E(rpmteObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmteE(s->te));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmteE(s->te));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmte_V(rpmteObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmteV(s->te));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmteV(s->te));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmte_R(rpmteObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmteR(s->te));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmteR(s->te));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmte_A(rpmteObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmteA(s->te));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmteA(s->te));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmte_O(rpmteObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmteO(s->te));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmteO(s->te));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmte_NEVR(rpmteObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmteNEVR(s->te));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmteNEVR(s->te));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
 rpmte_NEVRA(rpmteObject * s, PyObject * unused)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmteNEVRA(s->te));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmteNEVRA(s->te));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
diff --git a/python/rpmts-py.c b/python/rpmts-py.c
Panu Matilainen d4f7fd
index 1ddfc9a1e..96e3bb28e 100644
Panu Matilainen d4f7fd
--- a/python/rpmts-py.c
Panu Matilainen d4f7fd
+++ b/python/rpmts-py.c
Panu Matilainen d4f7fd
@@ -230,8 +230,9 @@ rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data)
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
     PyEval_RestoreThread(cbInfo->_save);
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
-    args = Py_BuildValue("(Oissi)", cbInfo->tso,
Panu Matilainen d4f7fd
-		rpmdsTagN(ds), rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds));
Panu Matilainen d4f7fd
+    args = Py_BuildValue("(OiNNi)", cbInfo->tso,
Panu Matilainen d4f7fd
+		rpmdsTagN(ds), utf8FromString(rpmdsN(ds)),
Panu Matilainen d4f7fd
+		utf8FromString(rpmdsEVR(ds)), rpmdsFlags(ds));
Panu Matilainen d4f7fd
     result = PyEval_CallObject(cbInfo->cb, args);
Panu Matilainen d4f7fd
     Py_DECREF(args);
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
@@ -409,7 +410,7 @@ rpmts_HdrCheck(rpmtsObject * s, PyObject *obj)
Panu Matilainen d4f7fd
     rpmrc = headerCheck(s->ts, uh, uc, &msg;;
Panu Matilainen d4f7fd
     Py_END_ALLOW_THREADS;
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
-    return Py_BuildValue("(is)", rpmrc, msg);
Panu Matilainen d4f7fd
+    return Py_BuildValue("(iN)", rpmrc, utf8FromString(msg));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *
Panu Matilainen d4f7fd
@@ -500,7 +501,7 @@ rpmtsCallback(const void * hd, const rpmCallbackType what,
Panu Matilainen d4f7fd
     /* Synthesize a python object for callback (if necessary). */
Panu Matilainen d4f7fd
     if (pkgObj == NULL) {
Panu Matilainen d4f7fd
 	if (h) {
Panu Matilainen d4f7fd
-	    pkgObj = Py_BuildValue("s", headerGetString(h, RPMTAG_NAME));
Panu Matilainen d4f7fd
+	    pkgObj = utf8FromString(headerGetString(h, RPMTAG_NAME));
Panu Matilainen d4f7fd
 	} else {
Panu Matilainen d4f7fd
 	    pkgObj = Py_None;
Panu Matilainen d4f7fd
 	    Py_INCREF(pkgObj);
Panu Matilainen d4f7fd
@@ -845,7 +846,7 @@ static PyObject *rpmts_get_tid(rpmtsObject *s, void *closure)
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject *rpmts_get_rootDir(rpmtsObject *s, void *closure)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
-    return Py_BuildValue("s", rpmtsRootDir(s->ts));
Panu Matilainen d4f7fd
+    return utf8FromString(rpmtsRootDir(s->ts));
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static int rpmts_set_scriptFd(rpmtsObject *s, PyObject *value, void *closure)
Panu Matilainen d4f7fd
diff --git a/python/spec-py.c b/python/spec-py.c
Panu Matilainen d4f7fd
index 4efdbf4bf..70b796531 100644
Panu Matilainen d4f7fd
--- a/python/spec-py.c
Panu Matilainen d4f7fd
+++ b/python/spec-py.c
Panu Matilainen d4f7fd
@@ -57,7 +57,7 @@ static PyObject *pkgGetSection(rpmSpecPkg pkg, int section)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
     char *sect = rpmSpecPkgGetSection(pkg, section);
Panu Matilainen d4f7fd
     if (sect != NULL) {
Panu Matilainen d4f7fd
-        PyObject *ps = PyBytes_FromString(sect);
Panu Matilainen d4f7fd
+        PyObject *ps = utf8FromString(sect);
Panu Matilainen d4f7fd
         free(sect);
Panu Matilainen d4f7fd
         if (ps != NULL)
Panu Matilainen d4f7fd
             return ps;
Panu Matilainen d4f7fd
@@ -158,7 +158,7 @@ static PyObject * getSection(rpmSpec spec, int section)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
     const char *sect = rpmSpecGetSection(spec, section);
Panu Matilainen d4f7fd
     if (sect) {
Panu Matilainen d4f7fd
-	return Py_BuildValue("s", sect);
Panu Matilainen d4f7fd
+	return utf8FromString(sect);
Panu Matilainen d4f7fd
     }
Panu Matilainen d4f7fd
     Py_RETURN_NONE;
Panu Matilainen d4f7fd
 }
Panu Matilainen d4f7fd
@@ -208,8 +208,8 @@ static PyObject * spec_get_sources(specObject *s, void *closure)
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
     rpmSpecSrcIter iter = rpmSpecSrcIterInit(s->spec);
Panu Matilainen d4f7fd
     while ((source = rpmSpecSrcIterNext(iter)) != NULL) {
Panu Matilainen d4f7fd
-	PyObject *srcUrl = Py_BuildValue("(sii)",
Panu Matilainen d4f7fd
-				rpmSpecSrcFilename(source, 1),
Panu Matilainen d4f7fd
+	PyObject *srcUrl = Py_BuildValue("(Nii)",
Panu Matilainen d4f7fd
+				utf8FromString(rpmSpecSrcFilename(source, 1)),
Panu Matilainen d4f7fd
 				rpmSpecSrcNum(source),
Panu Matilainen d4f7fd
 				rpmSpecSrcFlags(source)); 
Panu Matilainen d4f7fd
         if (!srcUrl) {
Panu Matilainen d4f7fd
diff --git a/tests/local.at b/tests/local.at
Panu Matilainen d4f7fd
index 02ead66c9..42eef1c75 100644
Panu Matilainen d4f7fd
--- a/tests/local.at
Panu Matilainen d4f7fd
+++ b/tests/local.at
Panu Matilainen d4f7fd
@@ -10,6 +10,7 @@ rm -rf "${abs_builddir}"/testing`rpm --eval '%_dbpath'`/*
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 m4_define([RPMPY_RUN],[[
Panu Matilainen d4f7fd
 cat << EOF > test.py
Panu Matilainen d4f7fd
+# coding=utf-8
Panu Matilainen d4f7fd
 import rpm, sys
Panu Matilainen d4f7fd
 dbpath=rpm.expandMacro('%_dbpath')
Panu Matilainen d4f7fd
 rpm.addMacro('_dbpath', '${abs_builddir}/testing%s' % dbpath)
Panu Matilainen d4f7fd
diff --git a/tests/rpmpython.at b/tests/rpmpython.at
Panu Matilainen d4f7fd
index ff77f868c..58f3e84a6 100644
Panu Matilainen d4f7fd
--- a/tests/rpmpython.at
Panu Matilainen d4f7fd
+++ b/tests/rpmpython.at
Panu Matilainen d4f7fd
@@ -106,6 +106,25 @@ None
Panu Matilainen d4f7fd
 'rpm.hdr' object has no attribute '__foo__']
Panu Matilainen d4f7fd
 )
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
+RPMPY_TEST([non-utf8 data in header],[
Panu Matilainen d4f7fd
+str = u'älämölö'
Panu Matilainen d4f7fd
+enc = 'iso-8859-1'
Panu Matilainen d4f7fd
+b = str.encode(enc)
Panu Matilainen d4f7fd
+h = rpm.hdr()
Panu Matilainen d4f7fd
+h['group'] = b
Panu Matilainen d4f7fd
+d = h['group']
Panu Matilainen d4f7fd
+try:
Panu Matilainen d4f7fd
+    # python 3
Panu Matilainen d4f7fd
+    t = bytes(d, 'utf-8', 'surrogateescape')
Panu Matilainen d4f7fd
+except TypeError:
Panu Matilainen d4f7fd
+    # python 2
Panu Matilainen d4f7fd
+    t = bytes(d)
Panu Matilainen d4f7fd
+res = t.decode(enc)
Panu Matilainen d4f7fd
+myprint(str == res)
Panu Matilainen d4f7fd
+],
Panu Matilainen d4f7fd
+[True]
Panu Matilainen d4f7fd
+)
Panu Matilainen d4f7fd
+
Panu Matilainen d4f7fd
 RPMPY_TEST([invalid header data],[
Panu Matilainen d4f7fd
 h1 = rpm.hdr()
Panu Matilainen d4f7fd
 h1['basenames'] = ['bing', 'bang', 'bong']
Panu Matilainen d4f7fd
@@ -125,6 +144,21 @@ for h in [h1, h2]:
Panu Matilainen d4f7fd
 /opt/bing,/opt/bang,/flopt/bong]
Panu Matilainen d4f7fd
 )
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
+RPMPY_TEST([labelCompare],[
Panu Matilainen d4f7fd
+v = '1.0'
Panu Matilainen d4f7fd
+r = '1'
Panu Matilainen d4f7fd
+e = 3
Panu Matilainen d4f7fd
+h = rpm.hdr()
Panu Matilainen d4f7fd
+h['name'] = 'testpkg'
Panu Matilainen d4f7fd
+h['version'] = v
Panu Matilainen d4f7fd
+h['release'] = r
Panu Matilainen d4f7fd
+h['epoch'] = e
Panu Matilainen d4f7fd
+myprint(rpm.labelCompare((str(h['epoch']), h['version'], h['release']),
Panu Matilainen d4f7fd
+			 (str(e), v, r)))
Panu Matilainen d4f7fd
+],
Panu Matilainen d4f7fd
+[0]
Panu Matilainen d4f7fd
+)
Panu Matilainen d4f7fd
+
Panu Matilainen d4f7fd
 RPMPY_TEST([vfyflags API],[
Panu Matilainen d4f7fd
 ts = rpm.ts()
Panu Matilainen d4f7fd
 dlv = ts.getVfyFlags()
Panu Matilainen d4f7fd
-- 
Panu Matilainen d4f7fd
2.20.1
Panu Matilainen d4f7fd