alexk / rpms / rpm

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