Blame SOURCES/0001-Monkey-patch-.decode-method-to-our-strings-as-a-temp.patch

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