#7475: add (un)transform method to bytes/bytearray and str, add back codecs that can be used with them from Python 2.
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 89e3c8a..fd50882 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -7432,6 +7432,7 @@
     v = PyUnicode_AsEncodedString((PyObject *)self, encoding, errors);
     if (v == NULL)
         goto onError;
+    /* XXX this check is redundant */
     if (!PyBytes_Check(v)) {
         PyErr_Format(PyExc_TypeError,
                      "encoder did not return a bytes object "
@@ -7446,6 +7447,44 @@
     return NULL;
 }
 
+PyDoc_STRVAR(transform__doc__,
+             "S.transform(encoding, errors='strict') -> str\n\
+\n\
+Transform S using the codec registered for encoding. errors may be given\n\
+to set a different error handling scheme.");
+
+static PyObject *
+unicode_transform(PyUnicodeObject *self, PyObject *args, PyObject *kwargs)
+{
+    static char *kwlist[] = {"encoding", "errors", 0};
+    char *encoding = NULL;
+    char *errors = NULL;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|s:transform",
+                                     kwlist, &encoding, &errors))
+        return NULL;
+    return PyUnicode_AsEncodedUnicode((PyObject *)self, encoding, errors);
+}
+
+PyDoc_STRVAR(untransform__doc__,
+             "S.untransform(encoding, errors='strict') -> str\n\
+\n\
+Reverse-transform S using the codec registered for encoding. errors may be\n\
+given to set a different error handling scheme.");
+
+static PyObject *
+unicode_untransform(PyUnicodeObject *self, PyObject *args, PyObject *kwargs)
+{
+    static char *kwlist[] = {"encoding", "errors", 0};
+    char *encoding = NULL;
+    char *errors = NULL;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|s:untransform",
+                                     kwlist, &encoding, &errors))
+        return NULL;
+    return PyUnicode_AsDecodedUnicode((PyObject *)self, encoding, errors);
+}
+
 PyDoc_STRVAR(expandtabs__doc__,
              "S.expandtabs([tabsize]) -> str\n\
 \n\
@@ -9091,7 +9130,8 @@
     /* Order is according to common usage: often used methods should
        appear first, since lookup is done sequentially. */
 
-    {"encode", (PyCFunction) unicode_encode, METH_VARARGS | METH_KEYWORDS, encode__doc__},
+    {"encode", (PyCFunction) unicode_encode, METH_VARARGS | METH_KEYWORDS,
+     encode__doc__},
     {"replace", (PyCFunction) unicode_replace, METH_VARARGS, replace__doc__},
     {"split", (PyCFunction) unicode_split, METH_VARARGS, split__doc__},
     {"rsplit", (PyCFunction) unicode_rsplit, METH_VARARGS, rsplit__doc__},
@@ -9136,6 +9176,10 @@
     {"__format__", (PyCFunction) unicode__format__, METH_VARARGS, p_format__doc__},
     {"maketrans", (PyCFunction) unicode_maketrans,
      METH_VARARGS | METH_STATIC, maketrans__doc__},
+    {"transform", (PyCFunction) unicode_transform, METH_VARARGS | METH_KEYWORDS,
+     transform__doc__},
+    {"untransform", (PyCFunction) unicode_untransform, METH_VARARGS | METH_KEYWORDS,
+     untransform__doc__},
     {"__sizeof__", (PyCFunction) unicode__sizeof__, METH_NOARGS, sizeof__doc__},
 #if 0
     {"capwords", (PyCFunction) unicode_capwords, METH_NOARGS, capwords__doc__},