Commit e6103a1b authored by Kevin Modzelewski's avatar Kevin Modzelewski

from module import *

parent 07af2757
......@@ -1453,6 +1453,14 @@ private:
const std::string& name = alias->name;
const std::string& asname = alias->asname.size() ? alias->asname : alias->name;
if (name == "*") {
RELEASE_ASSERT(irstate->getSourceInfo()->ast->type == AST_TYPE::Module,
"import * not supported in functions");
emitter.createCall2(exc_info, g.funcs.importStar, imported_v,
embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_module_type_ptr));
continue;
}
// TODO add patchpoints to this?
llvm::Value* r = emitter.createCall2(exc_info, g.funcs.importFrom, module->getValue(),
embedConstantPtr(&name, g.llvm_str_type_ptr)).getInstruction();
......
......@@ -183,6 +183,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(unaryop);
GET(import);
GET(importFrom);
GET(importStar);
GET(repr);
GET(isinstance);
......
......@@ -34,7 +34,7 @@ struct GlobalFuncs {
*boxInstanceMethod, *boxBool, *unboxBool, *createTuple, *createDict, *createList, *createSlice,
*createUserClass, *createClosure;
llvm::Value* getattr, *setattr, *print, *nonzero, *binop, *compare, *augbinop, *unboxedLen, *getitem, *getclsattr,
*getGlobal, *setitem, *delitem, *unaryop, *import, *importFrom, *repr, *isinstance;
*getGlobal, *setitem, *delitem, *unaryop, *import, *importFrom, *importStar, *repr, *isinstance;
llvm::Value* checkUnpackingLength, *raiseAttributeError, *raiseAttributeErrorStr, *raiseNotIterableError,
*assertNameDefined, *assertFail;
......
......@@ -75,6 +75,7 @@ void force() {
FORCE(unaryop);
FORCE(import);
FORCE(importFrom);
FORCE(importStar);
FORCE(repr);
FORCE(isinstance);
......
......@@ -2971,4 +2971,52 @@ extern "C" Box* importFrom(Box* _m, const std::string* name) {
raiseExcHelper(ImportError, "cannot import name %s", name->c_str());
}
extern "C" void importStar(Box* _from_module, BoxedModule* to_module) {
assert(_from_module->cls == module_cls);
BoxedModule* from_module = static_cast<BoxedModule*>(_from_module);
static std::string all_str("__all__");
static std::string getitem_str("__getitem__");
Box* all = from_module->getattr(all_str);
if (all) {
Box* all_getitem = typeLookup(all->cls, getitem_str, NULL, NULL);
if (!all_getitem)
raiseExcHelper(TypeError, "'%s' object does not support indexing", getTypeName(all)->c_str());
int idx = 0;
while (true) {
Box* attr_name;
try {
attr_name = runtimeCallInternal2(all_getitem, NULL, ArgPassSpec(2), all, boxInt(idx));
} catch (Box* b) {
if (b->cls == IndexError)
break;
throw;
}
idx++;
if (attr_name->cls != str_cls)
raiseExcHelper(TypeError, "attribute name must be string, not '%s'", getTypeName(attr_name)->c_str());
BoxedString* casted_attr_name = static_cast<BoxedString*>(attr_name);
Box* attr_value = from_module->getattr(casted_attr_name->s);
if (!attr_value)
raiseExcHelper(AttributeError, "'module' object has no attribute '%s'", casted_attr_name->s.c_str());
to_module->setattr(casted_attr_name->s, attr_value, NULL);
}
return;
}
HCAttrs* module_attrs = from_module->getAttrsPtr();
for (auto& p : module_attrs->hcls->attr_offsets) {
if (p.first[0] == '_')
continue;
to_module->setattr(p.first, module_attrs->attr_list->attrs[p.second], NULL);
}
}
}
......@@ -41,7 +41,6 @@ extern "C" const std::string* getNameOfClass(BoxedClass* cls);
// TODO sort this
extern "C" void my_assert(bool b);
extern "C" Box* importFrom(Box* obj, const std::string* attr);
extern "C" Box* getattr(Box* obj, const char* attr);
extern "C" void setattr(Box* obj, const char* attr, Box* attr_val);
extern "C" bool nonzero(Box* obj);
......@@ -71,6 +70,8 @@ extern "C" void delitem(Box* target, Box* slice);
extern "C" Box* getclsattr(Box* obj, const char* attr);
extern "C" Box* unaryop(Box* operand, int op_type);
extern "C" Box* import(const std::string* name);
extern "C" Box* importFrom(Box* obj, const std::string* attr);
extern "C" void importStar(Box* from_module, BoxedModule* to_module);
extern "C" void checkUnpackingLength(i64 expected, i64 given);
extern "C" void assertNameDefined(bool b, const char* name);
extern "C" void assertFail(BoxedModule* inModule, Box* msg);
......
print "importing nested", __name__
_y = 2
y = 2
def bar():
......
# import_target defines __all__ to be ['x']
from import_target import *
print x
try:
print foo
assert 0
except NameError:
pass
try:
print _x
assert 0
except NameError:
pass
# import_nested_target doesn't define __all__
from import_nested_target import *
print y
try:
print _y
assert 0
except NameError:
pass
# import_target_bad_all defines an __all__ with a nonexistent name
try:
from import_target_bad_all import *
assert 0
except AttributeError:
pass
from import_target_custom_all import *
print z
......@@ -14,3 +14,5 @@ def foo():
class C(object):
pass
_x = 1
__all__ = ['x']
# No 'x' defined in this file, importing * will fail with an AttributeError
__all__ = ['x']
# The __all__ variable must support iteration, through the old-style (__getitem__) protocol
z = 123
class C(object):
def __getitem__(self, idx):
print "__getitem__", idx
if idx == 0:
return 'z'
raise IndexError
__all__ = C()
......@@ -185,13 +185,15 @@ def run_test(fn, check_stats, run_memcheck):
r += " \033[31mFAILED\033[0m (bad output)"
failed.append(fn)
return r
exp_fd, exp_fn = tempfile.mkstemp()
out_fd, out_fn = tempfile.mkstemp()
exp_fd, exp_fn = tempfile.mkstemp(prefix="expected_")
out_fd, out_fn = tempfile.mkstemp(prefix="received_")
os.fdopen(exp_fd, 'w').write(expected_out)
os.fdopen(out_fd, 'w').write(out)
p = subprocess.Popen(["diff", "-C2", "-a", exp_fn, out_fn], stdout=subprocess.PIPE, preexec_fn=set_ulimits)
diff = p.stdout.read()
assert p.wait() in (0, 1)
os.unlink(exp_fn)
os.unlink(out_fn)
raise Exception("Failed on %s:\n%s" % (fn, diff))
elif not TEST_PYPY and canonicalize_stderr(stderr) != canonicalize_stderr(expected_err):
if KEEP_GOING:
......
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