this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include <sys/stat.h>
3#include <sys/types.h>
4
5#include "gtest/gtest.h"
6
7#include "module-builtins.h"
8#include "objects.h"
9#include "runtime.h"
10#include "test-utils.h"
11
12namespace py {
13namespace testing {
14
15using ImportlibTest = RuntimeFixture;
16
17TEST_F(ImportlibTest, SimpleImport) {
18 TemporaryDirectory tempdir;
19 writeFile(tempdir.path + "foo.py", "x = 42");
20 writeFile(tempdir.path + "bar.py", "x = 67");
21
22 HandleScope scope(thread_);
23 List sys_path(&scope, moduleAtByCStr(runtime_, "sys", "path"));
24 sys_path.setNumItems(0);
25 Str temp_dir_str(&scope, runtime_->newStrFromCStr(tempdir.path.c_str()));
26 runtime_->listAdd(thread_, sys_path, temp_dir_str);
27 ASSERT_FALSE(runFromCStr(runtime_, R"(
28import foo
29import bar
30)")
31 .isError());
32 Object foo_obj(&scope, mainModuleAt(runtime_, "foo"));
33 ASSERT_TRUE(foo_obj.isModule());
34 Module foo(&scope, *foo_obj);
35 EXPECT_TRUE(isStrEqualsCStr(foo.name(), "foo"));
36
37 Object name(&scope, moduleAtById(thread_, foo, ID(__name__)));
38 EXPECT_TRUE(isStrEqualsCStr(*name, "foo"));
39 Object package(&scope, moduleAtById(thread_, foo, ID(__package__)));
40 EXPECT_TRUE(isStrEqualsCStr(*package, ""));
41 Object doc(&scope, moduleAtById(thread_, foo, ID(__doc__)));
42 EXPECT_TRUE(doc.isNoneType());
43 Str str_x(&scope, runtime_->newStrFromCStr("x"));
44 Object x(&scope, moduleAt(foo, str_x));
45 EXPECT_TRUE(isIntEqualsWord(*x, 42));
46}
47
48TEST_F(ImportlibTest, ImportsEmptyModule) {
49 TemporaryDirectory tempdir;
50 std::string module_dir = tempdir.path + "somedir";
51 ASSERT_EQ(mkdir(module_dir.c_str(), S_IRWXU), 0);
52
53 HandleScope scope(thread_);
54 List sys_path(&scope, moduleAtByCStr(runtime_, "sys", "path"));
55 sys_path.setNumItems(0);
56 Str temp_dir_str(&scope, runtime_->newStrFromCStr(tempdir.path.c_str()));
57 runtime_->listAdd(thread_, sys_path, temp_dir_str);
58 ASSERT_FALSE(runFromCStr(runtime_, R"(
59import somedir
60)")
61 .isError());
62 Object somedir(&scope, mainModuleAt(runtime_, "somedir"));
63 ASSERT_TRUE(somedir.isModule());
64}
65
66TEST_F(ImportlibTest, ImportsModuleWithInitPy) {
67 TemporaryDirectory tempdir;
68 std::string module_dir = tempdir.path + "bar";
69 ASSERT_EQ(mkdir(module_dir.c_str(), S_IRWXU), 0);
70 writeFile(module_dir + "/__init__.py", "y = 13");
71
72 HandleScope scope(thread_);
73 List sys_path(&scope, moduleAtByCStr(runtime_, "sys", "path"));
74 sys_path.setNumItems(0);
75 Str temp_dir_str(&scope, runtime_->newStrFromCStr(tempdir.path.c_str()));
76 runtime_->listAdd(thread_, sys_path, temp_dir_str);
77 ASSERT_FALSE(runFromCStr(runtime_, R"(
78import bar
79)")
80 .isError());
81 Object bar_obj(&scope, mainModuleAt(runtime_, "bar"));
82 ASSERT_TRUE(bar_obj.isModule());
83 Module bar(&scope, *bar_obj);
84 Str str_y(&scope, runtime_->newStrFromCStr("y"));
85 Object y(&scope, moduleAt(bar, str_y));
86 EXPECT_TRUE(isIntEqualsWord(*y, 13));
87}
88
89TEST_F(ImportlibTest, SubModuleImport) {
90 TemporaryDirectory tempdir;
91 std::string module_dir = tempdir.path + "baz";
92 ASSERT_EQ(mkdir(module_dir.c_str(), S_IRWXU), 0);
93 writeFile(module_dir + "/blam.py", "z = 7");
94
95 HandleScope scope(thread_);
96 List sys_path(&scope, moduleAtByCStr(runtime_, "sys", "path"));
97 sys_path.setNumItems(0);
98 Str temp_dir_str(&scope, runtime_->newStrFromCStr(tempdir.path.c_str()));
99 runtime_->listAdd(thread_, sys_path, temp_dir_str);
100 ASSERT_FALSE(runFromCStr(runtime_, R"(
101import baz.blam
102)")
103 .isError());
104 Object baz_obj(&scope, mainModuleAt(runtime_, "baz"));
105 ASSERT_TRUE(baz_obj.isModule());
106 Module baz(&scope, *baz_obj);
107 Str blam_str(&scope, runtime_->newStrFromCStr("blam"));
108 Object blam_obj(&scope, moduleAt(baz, blam_str));
109 ASSERT_TRUE(blam_obj.isModule());
110 Module blam(&scope, *blam_obj);
111
112 Str str_z(&scope, runtime_->newStrFromCStr("z"));
113 Object z(&scope, moduleAt(blam, str_z));
114 EXPECT_TRUE(isIntEqualsWord(*z, 7));
115}
116
117TEST_F(ImportlibTest, FromImportsWithRelativeName) {
118 TemporaryDirectory tempdir;
119 writeFile(tempdir.path + "a.py", "val = 'top val'");
120 std::string submodule = tempdir.path + "submodule";
121 ASSERT_EQ(mkdir(submodule.c_str(), S_IRWXU), 0);
122 writeFile(submodule + "/__init__.py", "from .a import val");
123 writeFile(submodule + "/a.py", "val = 'submodule val'");
124
125 HandleScope scope(thread_);
126 List sys_path(&scope, moduleAtByCStr(runtime_, "sys", "path"));
127 sys_path.setNumItems(0);
128 Str temp_dir_str(&scope, runtime_->newStrFromCStr(tempdir.path.c_str()));
129 runtime_->listAdd(thread_, sys_path, temp_dir_str);
130 ASSERT_FALSE(runFromCStr(runtime_, R"(
131import a
132import submodule
133from submodule.a import val
134)")
135 .isError());
136
137 Object top_val(&scope, moduleAtByCStr(runtime_, "a", "val"));
138 EXPECT_TRUE(isStrEqualsCStr(*top_val, "top val"));
139 Object subdir_val(&scope, moduleAtByCStr(runtime_, "submodule", "val"));
140 EXPECT_TRUE(isStrEqualsCStr(*subdir_val, "submodule val"));
141 Object main_val_from_submodule(&scope, mainModuleAt(runtime_, "val"));
142 EXPECT_TRUE(isStrEqualsCStr(*main_val_from_submodule, "submodule val"));
143}
144
145TEST_F(ImportlibTest, BuiltinsDunderImportWithSubmoduleReturnsToplevelModule) {
146 TemporaryDirectory tempdir;
147 std::string topmodule_dir = tempdir.path + "top";
148 ASSERT_EQ(mkdir(topmodule_dir.c_str(), S_IRWXU), 0);
149 std::string submodule_dir = tempdir.path + "top/sub";
150 ASSERT_EQ(mkdir(submodule_dir.c_str(), S_IRWXU), 0);
151 writeFile(submodule_dir + "/__init__.py", "initialized = True");
152
153 HandleScope scope(thread_);
154 List sys_path(&scope, moduleAtByCStr(runtime_, "sys", "path"));
155 sys_path.setNumItems(0);
156 Str temp_dir_str(&scope, runtime_->newStrFromCStr(tempdir.path.c_str()));
157 runtime_->listAdd(thread_, sys_path, temp_dir_str);
158
159 Object subname(&scope, runtime_->newStrFromCStr("top.sub"));
160 Object globals(&scope, NoneType::object());
161 Object locals(&scope, NoneType::object());
162 Object fromlist(&scope, runtime_->emptyTuple());
163 Object level(&scope, runtime_->newInt(0));
164 Object m0(&scope,
165 thread_->invokeFunction5(ID(builtins), ID(__import__), subname,
166 globals, locals, fromlist, level));
167 ASSERT_TRUE(m0.isModule());
168 EXPECT_TRUE(isStrEqualsCStr(Module::cast(*m0).name(), "top"));
169
170 Object initialized(&scope,
171 moduleAtByCStr(runtime_, "top.sub", "initialized"));
172 EXPECT_EQ(initialized, Bool::trueObj());
173
174 Object topname(&scope, runtime_->newStrFromCStr("top"));
175 Object m1(&scope,
176 thread_->invokeFunction5(ID(builtins), ID(__import__), topname,
177 globals, locals, fromlist, level));
178 EXPECT_EQ(m0, m1);
179
180 // Import a 2nd time so we hit the cache.
181 Object m2(&scope,
182 thread_->invokeFunction5(ID(builtins), ID(__import__), subname,
183 globals, locals, fromlist, level));
184 EXPECT_EQ(m0, m2);
185 Object m3(&scope,
186 thread_->invokeFunction5(ID(builtins), ID(__import__), topname,
187 globals, locals, fromlist, level));
188 EXPECT_EQ(m0, m3);
189}
190
191TEST_F(ImportlibTest, ImportFindsDefaultModules) {
192 EXPECT_FALSE(runFromCStr(runtime_, "import stat").isError());
193}
194
195TEST_F(ImportlibTest, SysMetaPathIsList) {
196 HandleScope scope(thread_);
197 ASSERT_FALSE(runFromCStr(runtime_, R"(
198import sys
199
200meta_path = sys.meta_path
201)")
202 .isError());
203 Object meta_path(&scope, mainModuleAt(runtime_, "meta_path"));
204 ASSERT_TRUE(meta_path.isList());
205}
206
207} // namespace testing
208} // namespace py