Commit 2a035a20 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Fix some importing mechanics that particularly affect import hooks

There are some times that the importing logic has to look up attributes
on objects, and we were using Box::getattr() (equivalent to
obj.__dict__[attr] ) instead of getattr() (equivalent to getattr()).
This was working fine until we started trying to run the custom import hook
in six.py, since that creates a subclass of ModuleType which defines
some of the important attributes as class-level attributes.
parent f7ac934e
......@@ -150,7 +150,7 @@ static Box* importSub(const std::string& name, const std::string& full_name, Box
if (parent_module == NULL) {
path_list = NULL;
} else {
path_list = static_cast<BoxedList*>(parent_module->getattr("__path__", NULL));
path_list = static_cast<BoxedList*>(getattrInternal(parent_module, "__path__", NULL));
if (path_list == NULL || path_list->cls != list_cls) {
return NULL;
}
......@@ -261,7 +261,7 @@ extern "C" PyObject* PyImport_ImportModuleLevel(const char* name, PyObject* glob
// Named the same thing as the CPython method:
static void ensure_fromlist(Box* module, Box* fromlist, const std::string& module_name, bool recursive) {
if (module->getattr("__path__") == NULL) {
if (getattrInternal(module, "__path__", NULL) == NULL) {
// If it's not a package, then there's no sub-importing to do
return;
}
......@@ -275,14 +275,14 @@ static void ensure_fromlist(Box* module, Box* fromlist, const std::string& modul
if (recursive)
continue;
Box* all = module->getattr("__all__");
Box* all = getattrInternal(module, "__all__", NULL);
if (all) {
ensure_fromlist(module, all, module_name, true);
}
continue;
}
Box* attr = module->getattr(s->s);
Box* attr = getattrInternal(module, s->s, NULL);
if (attr != NULL)
continue;
......
......@@ -4097,11 +4097,11 @@ extern "C" Box* getGlobal(BoxedModule* m, const std::string* name) {
}
extern "C" Box* importFrom(Box* _m, const std::string* name) {
assert(_m->cls == module_cls);
assert(isSubclass(_m->cls, module_cls));
BoxedModule* m = static_cast<BoxedModule*>(_m);
Box* r = m->getattr(*name, NULL);
Box* r = getattrInternal(m, *name, NULL);
if (r)
return r;
......
# The six.py module exposed some issues with how we were handling imports;
# an imported name is not necessarily an attribute of the module object itself,
# it can be a class object too. It also goes through descriptor logic.
#
# This test is an attempt to extract some of the behavior of the six.py module
# for testing.
import sys
class ImportHook(object):
def find_module(self, name, path=None):
print "find_module('%s')" % name, path
if name.startswith("pseudo"):
return self
return None
def load_module(self, name):
return MyModule(name)
class MyDescr(object):
def __get__(self, *args):
print "descr.get", args
return self
def __repr__(self):
return "<MyDescr>"
import types
class MyModule(types.ModuleType):
# This __path__ is on the class type but should still get found:
__path__ = []
# Fetching this object will invoke a descriptor
descr = MyDescr()
def __init__(self, name):
super(MyModule, self).__init__(name)
self.inst_descr = MyDescr()
sys.meta_path.append(ImportHook())
import pseudo
print pseudo
import pseudo.a.b as b
print b
from pseudo.c import c
print c
from pseudo.e import descr, inst_descr
print descr, inst_descr
import pseudo.f.descr as d
print d
import pseudo.g.inst_descr as d
print d
# Other things to test: __all__, __file__, __name__, __package__
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment