Issue #3080: Add PyImport_AddModuleObject() and PyImport_ExecCodeModuleObject()
diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst
index cf48363..bcf5def 100644
--- a/Doc/c-api/import.rst
+++ b/Doc/c-api/import.rst
@@ -86,7 +86,7 @@
    an exception set on failure (the module still exists in this case).
 
 
-.. c:function:: PyObject* PyImport_AddModule(const char *name)
+.. c:function:: PyObject* PyImport_AddModuleObject(PyObject *name)
 
    Return the module object corresponding to a module name.  The *name* argument
    may be of the form ``package.module``. First check the modules dictionary if
@@ -100,6 +100,14 @@
       or one of its variants to import a module.  Package structures implied by a
       dotted name for *name* are not created if not already present.
 
+   .. versionadded:: 3.3
+
+
+.. c:function:: PyObject* PyImport_AddModule(const char *name)
+
+   Similar to :c:func:`PyImport_AddModuleObject`, but the name is an UTF-8
+   encoded string instead of a Unicode object.
+
 
 .. c:function:: PyObject* PyImport_ExecCodeModule(char *name, PyObject *co)
 
@@ -136,14 +144,23 @@
    See also :c:func:`PyImport_ExecCodeModuleWithPathnames`.
 
 
-.. c:function:: PyObject* PyImport_ExecCodeModuleWithPathnames(char *name, PyObject *co, char *pathname, char *cpathname)
+.. c:function:: PyObject* PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname, PyObject *cpathname)
 
    Like :c:func:`PyImport_ExecCodeModuleEx`, but the :attr:`__cached__`
    attribute of the module object is set to *cpathname* if it is
    non-``NULL``.  Of the three functions, this is the preferred one to use.
 
+   .. versionadded:: 3.3
+
+
+.. c:function:: PyObject* PyImport_ExecCodeModuleWithPathnames(char *name, PyObject *co, char *pathname, char *cpathname)
+
+   Like :c:func:`PyImport_ExecCodeModuleObject`, but *name*, *pathname* and
+   *cpathname* are UTF-8 encoded strings.
+
    .. versionadded:: 3.2
 
+
 .. c:function:: long PyImport_GetMagicNumber()
 
    Return the magic number for Python bytecode files (a.k.a. :file:`.pyc` and
diff --git a/Include/import.h b/Include/import.h
index 26e1f0f..f2d79b8 100644
--- a/Include/import.h
+++ b/Include/import.h
@@ -24,7 +24,16 @@
     char *pathname,             /* decoded from the filesystem encoding */
     char *cpathname             /* decoded from the filesystem encoding */
     );
+PyAPI_FUNC(PyObject *) PyImport_ExecCodeModuleObject(
+    PyObject *name,
+    PyObject *co,
+    PyObject *pathname,
+    PyObject *cpathname
+    );
 PyAPI_FUNC(PyObject *) PyImport_GetModuleDict(void);
+PyAPI_FUNC(PyObject *) PyImport_AddModuleObject(
+    PyObject *name
+    );
 PyAPI_FUNC(PyObject *) PyImport_AddModule(
     const char *name            /* UTF-8 encoded string */
     );
diff --git a/Python/import.c b/Python/import.c
index 39cd93f..22a7c87 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -698,18 +698,18 @@
    'NEW' REFERENCE! */
 
 PyObject *
-PyImport_AddModule(const char *name)
+PyImport_AddModuleObject(PyObject *name)
 {
     PyObject *modules = PyImport_GetModuleDict();
     PyObject *m;
 
-    if ((m = PyDict_GetItemString(modules, name)) != NULL &&
+    if ((m = PyDict_GetItem(modules, name)) != NULL &&
         PyModule_Check(m))
         return m;
-    m = PyModule_New(name);
+    m = PyModule_NewObject(name);
     if (m == NULL)
         return NULL;
-    if (PyDict_SetItemString(modules, name, m) != 0) {
+    if (PyDict_SetItem(modules, name, m) != 0) {
         Py_DECREF(m);
         return NULL;
     }
@@ -718,14 +718,27 @@
     return m;
 }
 
+PyObject *
+PyImport_AddModule(const char *name)
+{
+    PyObject *nameobj, *module;
+    nameobj = PyUnicode_FromString(name);
+    if (nameobj == NULL)
+        return NULL;
+    module = PyImport_AddModuleObject(nameobj);
+    Py_DECREF(nameobj);
+    return module;
+}
+
+
 /* Remove name from sys.modules, if it's there. */
 static void
-remove_module(const char *name)
+remove_module(PyObject *name)
 {
     PyObject *modules = PyImport_GetModuleDict();
-    if (PyDict_GetItemString(modules, name) == NULL)
+    if (PyDict_GetItem(modules, name) == NULL)
         return;
-    if (PyDict_DelItemString(modules, name) < 0)
+    if (PyDict_DelItem(modules, name) < 0)
         Py_FatalError("import:  deleting existing key in"
                       "sys.modules failed");
 }
@@ -763,10 +776,42 @@
 PyImport_ExecCodeModuleWithPathnames(char *name, PyObject *co, char *pathname,
                                      char *cpathname)
 {
+    PyObject *m = NULL;
+    PyObject *nameobj, *pathobj = NULL, *cpathobj = NULL;
+
+    nameobj = PyUnicode_FromString(name);
+    if (nameobj == NULL)
+        return NULL;
+
+    if (pathname != NULL) {
+        pathobj = PyUnicode_DecodeFSDefault(pathname);
+        if (pathobj == NULL)
+            goto error;
+    } else
+        pathobj = NULL;
+    if (cpathname != NULL) {
+        cpathobj = PyUnicode_DecodeFSDefault(cpathname);
+        if (cpathobj == NULL)
+            goto error;
+    } else
+        cpathobj = NULL;
+    m = PyImport_ExecCodeModuleObject(nameobj, co, pathobj, cpathobj);
+error:
+    Py_DECREF(nameobj);
+    Py_XDECREF(pathobj);
+    Py_XDECREF(cpathobj);
+    return m;
+}
+
+PyObject*
+PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname,
+                              PyObject *cpathname)
+{
     PyObject *modules = PyImport_GetModuleDict();
     PyObject *m, *d, *v;
+    PyObject *pathbytes;
 
-    m = PyImport_AddModule(name);
+    m = PyImport_AddModuleObject(name);
     if (m == NULL)
         return NULL;
     /* If the module is being reloaded, we get the old module back
@@ -778,12 +823,18 @@
             goto error;
     }
     /* Remember the filename as the __file__ attribute */
-    v = NULL;
     if (pathname != NULL) {
-        v = get_sourcefile(pathname);
+        pathbytes = PyUnicode_EncodeFSDefault(pathname);
+        if (pathbytes != NULL) {
+            v = get_sourcefile(PyBytes_AS_STRING(pathbytes));
+            Py_DECREF(pathbytes);
+        } else
+            v = NULL;
         if (v == NULL)
             PyErr_Clear();
     }
+    else
+        v = NULL;
     if (v == NULL) {
         v = ((PyCodeObject *)co)->co_filename;
         Py_INCREF(v);
@@ -793,27 +844,21 @@
     Py_DECREF(v);
 
     /* Remember the pyc path name as the __cached__ attribute. */
-    if (cpathname == NULL) {
+    if (cpathname != NULL)
+        v = cpathname;
+    else
         v = Py_None;
-        Py_INCREF(v);
-    }
-    else if ((v = PyUnicode_FromString(cpathname)) == NULL) {
-        PyErr_Clear(); /* Not important enough to report */
-        v = Py_None;
-        Py_INCREF(v);
-    }
     if (PyDict_SetItemString(d, "__cached__", v) != 0)
         PyErr_Clear(); /* Not important enough to report */
-    Py_DECREF(v);
 
     v = PyEval_EvalCode(co, d, d);
     if (v == NULL)
         goto error;
     Py_DECREF(v);
 
-    if ((m = PyDict_GetItemString(modules, name)) == NULL) {
+    if ((m = PyDict_GetItem(modules, name)) == NULL) {
         PyErr_Format(PyExc_ImportError,
-                     "Loaded module %.200s not found in sys.modules",
+                     "Loaded module %R not found in sys.modules",
                      name);
         return NULL;
     }