Two changes to from...import:

1) "from M import X" now works even if M is not a real module; it's
   basically a getattr() operation with AttributeError exceptions
   changed into ImportError.

2) "from M import *" now looks for M.__all__ to decide which names to
   import; if M.__all__ doesn't exist, it uses M.__dict__.keys() but
   filters out names starting with '_' as before.  Whether or not
   __all__ exists, there's no restriction on the type of M.
diff --git a/Python/ceval.c b/Python/ceval.c
index 347a541..ed201b3 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -3089,48 +3089,72 @@
 static PyObject *
 import_from(PyObject *v, PyObject *name)
 {
-	PyObject *w, *x;
-	if (!PyModule_Check(v)) {
-		PyErr_SetString(PyExc_TypeError,
-				"import-from requires a module object");
-		return NULL;
-	}
-	w = PyModule_GetDict(v); /* TDB: can this not fail ? */
-	x = PyDict_GetItem(w, name);
-	if (x == NULL) {
+	PyObject *x;
+
+	x = PyObject_GetAttr(v, name);
+	if (x == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
 		PyErr_Format(PyExc_ImportError,
 			     "cannot import name %.230s",
 			     PyString_AsString(name));
-	} else
-		Py_INCREF(x);
+	}
 	return x;
 }
-
+ 
 static int
 import_all_from(PyObject *locals, PyObject *v)
 {
-	int pos = 0, err;
-	PyObject *name, *value;
-	PyObject *w;
+	PyObject *all = PyObject_GetAttrString(v, "__all__");
+	PyObject *dict, *name, *value;
+	int skip_leading_underscores = 0;
+	int pos, err;
 
-	if (!PyModule_Check(v)) {
-		PyErr_SetString(PyExc_TypeError,
-				"import-from requires a module object");
-		return -1;
-	}
-	w = PyModule_GetDict(v); /* TBD: can this not fail ? */
-
-	while (PyDict_Next(w, &pos, &name, &value)) {
-		if (!PyString_Check(name) ||
-			PyString_AsString(name)[0] == '_')
-				continue;
-		Py_INCREF(value);
-		err = PyDict_SetItem(locals, name, value);
-		Py_DECREF(value);
-		if (err != 0)
+	if (all == NULL) {
+		if (!PyErr_ExceptionMatches(PyExc_AttributeError))
+			return -1; /* Unexpected error */
+		PyErr_Clear();
+		dict = PyObject_GetAttrString(v, "__dict__");
+		if (dict == NULL) {
+			if (!PyErr_ExceptionMatches(PyExc_AttributeError))
+				return -1;
+			PyErr_SetString(PyExc_ImportError,
+			"from-import-* object has no __dict__ and no __all__");
 			return -1;
+		}
+		all = PyMapping_Keys(dict);
+		Py_DECREF(dict);
+		if (all == NULL)
+			return -1;
+		skip_leading_underscores = 1;
 	}
-	return 0;
+
+	for (pos = 0, err = 0; ; pos++) {
+		name = PySequence_GetItem(all, pos);
+		if (name == NULL) {
+			if (!PyErr_ExceptionMatches(PyExc_IndexError))
+				err = -1;
+			else
+				PyErr_Clear();
+			break;
+		}
+		if (skip_leading_underscores &&
+		    PyString_Check(name) &&
+		    PyString_AS_STRING(name)[0] == '_')
+		{
+			Py_DECREF(name);
+			continue;
+		}
+		value = PyObject_GetAttr(v, name);
+		if (value == NULL)
+			err = -1;
+		else
+			err = PyDict_SetItem(locals, name, value);
+		Py_DECREF(name);
+		Py_XDECREF(value);
+		if (err != 0)
+			break;
+	}
+	Py_DECREF(all);
+	return err;
 }
 
 static PyObject *