-
Notifications
You must be signed in to change notification settings - Fork 60
Expand file tree
/
Copy pathimporter.java
More file actions
337 lines (292 loc) · 11 KB
/
Copy pathimporter.java
File metadata and controls
337 lines (292 loc) · 11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
/* Copyright (c) Jython Developers */
package org.python.core.util;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.EnumSet;
import org.python.Version;
import org.python.core.BytecodeLoader;
import org.python.core.Py;
import org.python.core.PyCode;
import org.python.core.PyList;
import org.python.core.PyModule;
import org.python.core.PyObject;
import org.python.core.PyType;
import org.python.core.PyUnicode;
import org.python.core.imp;
/**
* A base class for PEP-302 path hooks. Handles looking through source, compiled, package and module
* items in the right order, and creating and filling in modules.
*/
public abstract class importer extends PyObject {
enum EntryType {
IS_SOURCE, IS_BYTECODE, IS_PACKAGE
}
/** SearchOrder defines how we search for a module. */
final SearchOrderEntry[] searchOrder;
public importer(PyType subType) {
super(subType);
searchOrder = makeSearchOrder();
}
public importer() {
searchOrder = makeSearchOrder();
}
/**
* Return the bytes for the data located at <code>path</code>.
*/
public abstract String get_data(String path);
/**
* Returns the value to fill in __path__ on a module with the given full module name created by
* this importer.
*/
protected abstract String makePackagePath(String fullname);
/**
* Given a full module name, return the potential file path in the archive (without extension).
*/
protected abstract String makeFilename(String fullname);
/**
* Given a full module name, return the potential file path including the archive (without
* extension).
*/
protected abstract String makeFilePath(String fullname);
/**
* Returns an entry for a filename from makeFilename with a potential suffix such that this
* importer can make a bundle with it, or null if fullFilename doesn't exist in this importer.
*/
protected abstract String makeEntry(String filenameAndSuffix);
/**
* Returns a Bundle for fullFilename and entry, the result from a makeEntry call for
* fullFilename.
*/
protected abstract Bundle makeBundle(String entry);
private SearchOrderEntry[] makeSearchOrder(){
return new SearchOrderEntry[] {
new SearchOrderEntry(EntryType.IS_PACKAGE, EntryType.IS_BYTECODE),
new SearchOrderEntry(EntryType.IS_PACKAGE, EntryType.IS_SOURCE),
new SearchOrderEntry(EntryType.IS_BYTECODE),
new SearchOrderEntry(EntryType.IS_SOURCE)};
}
protected final PyObject importer_find_module(String fullname, String path) {
ModuleInfo moduleInfo = getModuleInfo(fullname);
if (moduleInfo.notFound()) {
return Py.None;
}
return this;
}
protected final PyObject importer_find_spec(String fullname) {
PyObject moduleSpec = Py.getSystemState().importlib.__findattr__("ModuleSpec");
PyObject spec = moduleSpec.__call__(new PyUnicode(fullname), this);
ModuleInfo info = getModuleInfo(fullname);
if (info.notFound()) {
return null;
}
if (info.isPackage()) {
PyList pkgpath = new PyList();
pkgpath.add(makePackagePath(fullname));
spec.__setattr__("submodule_search_locations", pkgpath);
spec.__setattr__("is_package", Py.True);
}
spec.__setattr__("cached", new PyUnicode(info.getPath()));
spec.__setattr__("origin", new PyUnicode(info.getSourcePath()));
return spec;
}
protected final PyObject importer_load_module(String fullname) {
ModuleCodeData moduleCodeData = getModuleCode(fullname);
if (moduleCodeData == null) {
return Py.None;
}
// the module *must* be in sys.modules before the loader executes the module code; the
// module code may (directly or indirectly) import itself
PyModule mod = imp.addModule(fullname);
mod.__dict__.__setitem__("__loader__", this);
if (moduleCodeData.isPackage) {
// add __path__ to the module *before* the code gets executed
PyList pkgpath = new PyList();
pkgpath.add(makePackagePath(fullname));
mod.__dict__.__setitem__("__path__", pkgpath);
}
imp.createFromCode(fullname, moduleCodeData.code);
Py.writeDebug("import", "import " + fullname + " # loaded from " + moduleCodeData.path);
return mod;
}
/**
* @param fullname
* the fully qualified name of the module
* @return whether the module is a package
*/
protected final boolean importer_is_package(String fullname) {
ModuleInfo info = getModuleInfo(fullname);
if (info.notFound()) {
throw Py.ImportError(String.format("module %s not found", fullname));
}
return info.isPackage();
}
/**
* Bundle is an InputStream, bundled together with a method that can close the input stream and
* whatever resources are associated with it when the resource is imported.
*/
protected abstract static class Bundle implements AutoCloseable {
public InputStream inputStream;
public Bundle(InputStream inputStream) {
this.inputStream = inputStream;
}
/**
* Close the underlying resource if necessary. Raises an IOError if a problem occurs.
*/
@Override
public abstract void close();
}
/**
* Given a path to a compiled file in the archive, return the modification time of the
* matching .py file.
*
* @param path to the compiled file
* @return long mtime of the .py, or -1 if no source is available
*/
protected abstract long getSourceMtime(String path);
/**
* Return module information for the module with the fully qualified name.
*
* @param fullname
* the fully qualified name of the module
* @return the module's information
*/
protected final ModuleInfo getModuleInfo(String fullname) {
String path = makeFilename(fullname);
String filePath = makeFilePath(fullname);
for (SearchOrderEntry entry : searchOrder) {
String entryPath = filePath + entry.searchPath(path);
String importEntry = makeEntry(entryPath);
if (importEntry == null) {
continue;
}
return new ModuleInfo(fullname, entryPath, filePath + entry.sourcePath(path), entry);
}
return ModuleInfo.NOT_FOUND;
}
/**
* Return the code object and its associated data for the module with the fully qualified name.
*
* @param fullname
* the fully qualified name of the module
* @return the module's ModuleCodeData object
*/
protected final ModuleCodeData getModuleCode(String fullname) {
ModuleInfo moduleInfo = getModuleInfo(fullname);
if (moduleInfo.notFound()) {
throw Py.ImportError(String.format("can't find module '%s'", fullname), fullname);
}
String searchPath = moduleInfo.getPath();
long mtime = -1;
if (moduleInfo.isBytecode()) {
mtime = getSourceMtime(searchPath);
}
Bundle bundle = makeBundle(searchPath);
byte[] codeBytes;
try {
if (moduleInfo.isBytecode()) {
try {
codeBytes = imp.readCode(fullname, bundle.inputStream, true, mtime);
} catch (IOException ioe) {
throw Py.ImportError(ioe.getMessage() + "[path=" + searchPath + "]");
}
} else {
codeBytes = imp.compileSource(fullname, bundle.inputStream, searchPath);
}
} finally {
bundle.close();
}
PyCode code = BytecodeLoader.makeCode(fullname + Version.PY_CACHE_TAG, codeBytes, moduleInfo.getSourcePath());
return new ModuleCodeData(code, moduleInfo.isPackage(), searchPath);
}
/**
* Container for PyModule code - whether or not it's a package - and its path.
*/
protected class ModuleCodeData {
public PyCode code;
public boolean isPackage;
public String path;
public ModuleCodeData(PyCode code, boolean isPackage, String path) {
this.code = code;
this.isPackage = isPackage;
this.path = path;
}
}
/**
* A step in the module search order: the file suffix and its entry type.
*/
protected static class SearchOrderEntry {
public EnumSet<EntryType> types;
public SearchOrderEntry(EntryType type, EntryType... types) {
this.types = EnumSet.of(type, types);
}
public String sourcePath(String name) {
StringBuilder ret = new StringBuilder();
ret.append(name);
if (isPackage()) {
ret.append(File.separatorChar);
ret.append("__init__");
}
return ret.append(".py").toString();
}
public String searchPath(String name) {
if (isSource()) return sourcePath(name);
StringBuilder ret = new StringBuilder();
if (isPackage()) {
ret.append(name);
ret.append(File.separatorChar);
ret.append(imp.CACHEDIR);
ret.append(File.separatorChar);
ret.append("__init__");
} else {
ret.append(imp.CACHEDIR);
ret.append(File.separatorChar);
ret.append(name);
}
return ret.append(Version.PY_CACHE_TAG).append(".class").toString();
}
private boolean isPackage() {
return types.contains(EntryType.IS_PACKAGE);
}
private boolean isBytecode() {
return types.contains(EntryType.IS_BYTECODE);
}
private boolean isSource() {
return !isBytecode();
}
}
/**
* ModuleInfo is the blueprint for the importlib.machinery.ModuleSpec from PEP-451
*/
protected static class ModuleInfo {
private String name;
private String path;
private String sourcePath;
private SearchOrderEntry entry;
public static final ModuleInfo NOT_FOUND = new ModuleInfo();
private ModuleInfo() {
name = null;
}
public ModuleInfo(String name, String path, String sourcePath, SearchOrderEntry searchEntry) {
this.name = name;
this.path = path;
this.sourcePath = sourcePath;
this.entry = searchEntry;
}
public boolean isPackage() {
return entry.isPackage();
}
public boolean notFound() {
return name == null;
}
public boolean isBytecode() {
return entry.isBytecode();
}
public String getPath() {
return path;
}
public String getSourcePath() {
return sourcePath;
}
}
}