Panu Matilainen d4f7fd
From 13b0ebee7cdb1e4d200b3c40d0ec9440f198a1d4 Mon Sep 17 00:00:00 2001
Panu Matilainen d4f7fd
Message-Id: <13b0ebee7cdb1e4d200b3c40d0ec9440f198a1d4.1554886141.git.pmatilai@redhat.com>
Panu Matilainen d4f7fd
From: Panu Matilainen <pmatilai@redhat.com>
Panu Matilainen d4f7fd
Date: Wed, 10 Apr 2019 11:24:44 +0300
Panu Matilainen d4f7fd
Subject: [PATCH] Monkey-patch .decode() method to our strings as a temporary
Panu Matilainen d4f7fd
 compat crutch
Panu Matilainen d4f7fd
Panu Matilainen d4f7fd
As a temporary crutch to support faster deployment of the sane
Panu Matilainen d4f7fd
string behavior on python3, monkey-patch a decode method into all
Panu Matilainen d4f7fd
strings we return. This seems to be enough to fix practically all
Panu Matilainen d4f7fd
API users who have already adapted to the long-standing broken API
Panu Matilainen d4f7fd
on Python 3. API users compatible with both Python 2 and 3 never needed
Panu Matilainen d4f7fd
this anyway. Issue a warning with pointer to the relevant bug when the
Panu Matilainen d4f7fd
fake decode() method is used to alert users to the issue.
Panu Matilainen d4f7fd
Panu Matilainen d4f7fd
This is certainly an evil thing to do and will be removed as soon as
Panu Matilainen d4f7fd
the critical users have been fixed to work with the new, corrected
Panu Matilainen d4f7fd
behavior.
Panu Matilainen d4f7fd
---
Panu Matilainen d4f7fd
 python/rpm/__init__.py |  3 +++
Panu Matilainen d4f7fd
 python/rpmmodule.c     |  1 +
Panu Matilainen d4f7fd
 python/rpmsystem-py.h  | 22 ++++++++++++++++++++--
Panu Matilainen d4f7fd
 3 files changed, 24 insertions(+), 2 deletions(-)
Panu Matilainen d4f7fd
Panu Matilainen d4f7fd
diff --git a/python/rpm/__init__.py b/python/rpm/__init__.py
Panu Matilainen d4f7fd
index 54728bbd4..6d69eda7b 100644
Panu Matilainen d4f7fd
--- a/python/rpm/__init__.py
Panu Matilainen d4f7fd
+++ b/python/rpm/__init__.py
Panu Matilainen d4f7fd
@@ -61,6 +61,9 @@ except ImportError:
Panu Matilainen d4f7fd
 # backwards compatibility + give the same class both ways
Panu Matilainen d4f7fd
 ts = TransactionSet
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
+def _fakedecode(self, encoding='utf-8', errors='strict'):
Panu Matilainen d4f7fd
+    warnings.warn("decode() called on unicode string, see https://bugzilla.redhat.com/show_bug.cgi?id=1693751", UnicodeWarning, stacklevel=2)
Panu Matilainen d4f7fd
+    return self
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 def headerLoad(*args, **kwds):
Panu Matilainen d4f7fd
     """DEPRECATED! Use rpm.hdr() instead."""
Panu Matilainen d4f7fd
diff --git a/python/rpmmodule.c b/python/rpmmodule.c
Panu Matilainen d4f7fd
index 05032edc7..2a76cfbd0 100644
Panu Matilainen d4f7fd
--- a/python/rpmmodule.c
Panu Matilainen d4f7fd
+++ b/python/rpmmodule.c
Panu Matilainen d4f7fd
@@ -28,6 +28,7 @@
Panu Matilainen d4f7fd
  */
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 PyObject * pyrpmError;
Panu Matilainen d4f7fd
+PyObject * fakedecode = NULL;
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
 static PyObject * archScore(PyObject * self, PyObject * arg)
Panu Matilainen d4f7fd
 {
Panu Matilainen d4f7fd
diff --git a/python/rpmsystem-py.h b/python/rpmsystem-py.h
Panu Matilainen d4f7fd
index 25938464a..803da0fc1 100644
Panu Matilainen d4f7fd
--- a/python/rpmsystem-py.h
Panu Matilainen d4f7fd
+++ b/python/rpmsystem-py.h
Panu Matilainen c7bd80
@@ -19,12 +19,29 @@
Panu Matilainen d4f7fd
 #define PyInt_AsSsize_t PyLong_AsSsize_t
Panu Matilainen d4f7fd
 #endif
Panu Matilainen d4f7fd
 
Panu Matilainen d4f7fd
+PyObject * fakedecode;
Panu Matilainen d4f7fd
+
Panu Matilainen d4f7fd
 static inline PyObject * utf8FromString(const char *s)
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
-    if (s != NULL)
Panu Matilainen d4f7fd
-	return PyUnicode_DecodeUTF8(s, strlen(s), "surrogateescape");
Panu Matilainen d4f7fd
+    if (s != NULL) {
Panu Matilainen d4f7fd
+	PyObject *o = PyUnicode_DecodeUTF8(s, strlen(s), "surrogateescape");
Panu Matilainen d4f7fd
+	/* fish the fake decode function from python side if not done yet */
Panu Matilainen d4f7fd
+	if (fakedecode == NULL) {
Panu Matilainen d4f7fd
+	    PyObject *n = PyUnicode_FromString("rpm");
Panu Matilainen d4f7fd
+	    PyObject *m = PyImport_Import(n);
Panu Matilainen d4f7fd
+	    PyObject *md = PyModule_GetDict(m);
Panu Matilainen d4f7fd
+	    fakedecode = PyDict_GetItemString(md, "_fakedecode");
Panu Matilainen d4f7fd
+	    Py_DECREF(m);
Panu Matilainen d4f7fd
+	    Py_DECREF(n);
Panu Matilainen d4f7fd
+	}
Panu Matilainen d4f7fd
+	if (fakedecode && o) {
Panu Matilainen d4f7fd
+	    /* monkey-patch it into the string object as "decode" */
Panu Matilainen d4f7fd
+	    PyDict_SetItemString(Py_TYPE(o)->tp_dict, "decode", fakedecode);
Panu Matilainen d4f7fd
+	}
Panu Matilainen d4f7fd
+	return o;
Panu Matilainen d4f7fd
+    }
Panu Matilainen d4f7fd
 #else
Panu Matilainen d4f7fd
     if (s != NULL)
Panu Matilainen d4f7fd
 	return PyBytes_FromString(s);
Panu Matilainen d4f7fd
-- 
Panu Matilainen d4f7fd
2.20.1
Panu Matilainen d4f7fd