issue 14660: Implement PEP 420, namespace packages.
diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c
index 7655f15..d50b2b2 100644
--- a/Objects/moduleobject.c
+++ b/Objects/moduleobject.c
@@ -366,8 +366,28 @@
 static PyObject *
 module_repr(PyModuleObject *m)
 {
-    PyObject *name, *filename, *repr;
+    PyObject *name, *filename, *repr, *loader = NULL;
 
+    /* See if the module has an __loader__.  If it does, give the loader the
+     * first shot at producing a repr for the module.
+     */
+    if (m->md_dict != NULL) {
+        loader = PyDict_GetItemString(m->md_dict, "__loader__");
+    }
+    if (loader != NULL) {
+        repr = PyObject_CallMethod(loader, "module_repr", "(O)",
+                                   (PyObject *)m, NULL);
+        if (repr == NULL) {
+            PyErr_Clear();
+        }
+        else {
+            return repr;
+        }
+    }
+    /* __loader__.module_repr(m) did not provide us with a repr.  Next, see if
+     * the module has an __file__.  If it doesn't then use repr(__loader__) if
+     * it exists, otherwise, just use module.__name__.
+     */
     name = PyModule_GetNameObject((PyObject *)m);
     if (name == NULL) {
         PyErr_Clear();
@@ -378,8 +398,17 @@
     filename = PyModule_GetFilenameObject((PyObject *)m);
     if (filename == NULL) {
         PyErr_Clear();
-        repr = PyUnicode_FromFormat("<module %R (built-in)>", name);
+        /* There's no m.__file__, so if there was an __loader__, use that in
+         * the repr, otherwise, the only thing you can use is m.__name__
+         */
+        if (loader == NULL) {
+            repr = PyUnicode_FromFormat("<module %R>", name);
+        }
+        else {
+            repr = PyUnicode_FromFormat("<module %R (%R)>", name, loader);
+        }
     }
+    /* Finally, use m.__file__ */
     else {
         repr = PyUnicode_FromFormat("<module %R from %R>", name, filename);
         Py_DECREF(filename);