-
Notifications
You must be signed in to change notification settings - Fork 227
Expand file tree
/
Copy pathimporter.java
More file actions
274 lines (236 loc) · 9.2 KB
/
importer.java
File metadata and controls
274 lines (236 loc) · 9.2 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
/* Copyright (c) Jython Developers */
package org.python.core.util;
import java.io.IOException;
import java.io.InputStream;
import java.util.EnumSet;
import java.util.logging.Logger;
import java.util.logging.Level;
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.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<T> extends PyObject {
protected static Logger logger = Logger.getLogger("org.python.import");
static enum EntryType {
IS_SOURCE, IS_BYTECODE, IS_PACKAGE
};
/** SearchOrder defines how we search for a module. */
final SearchOrderEntry[] searchOrder;
/** Module information */
protected static enum ModuleInfo {
ERROR, NOT_FOUND, MODULE, PACKAGE
};
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 separator between directories and files used by this type of importer.
*/
protected abstract String getSeparator();
/**
* 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 T makeEntry(String filenameAndSuffix);
/**
* Returns a Bundle for fullFilename and entry, the result from a makeEntry call for
* fullFilename.
*/
protected abstract Bundle makeBundle(String filenameAndSuffix, T entry);
private SearchOrderEntry[] makeSearchOrder(){
String initName = "__init__.py";
return new SearchOrderEntry[] {
new SearchOrderEntry(getSeparator() + imp.makeCompiledFilename(initName),
EnumSet.of(EntryType.IS_PACKAGE, EntryType.IS_BYTECODE)),
new SearchOrderEntry(getSeparator() + initName,
EnumSet.of(EntryType.IS_PACKAGE, EntryType.IS_SOURCE)),
new SearchOrderEntry("$py.class", EnumSet.of(EntryType.IS_BYTECODE)),
new SearchOrderEntry(".py", EnumSet.of(EntryType.IS_SOURCE)),};
}
protected final PyObject importer_find_module(String fullname, String path) {
ModuleInfo moduleInfo = getModuleInfo(fullname);
if (moduleInfo == ModuleInfo.ERROR || moduleInfo == ModuleInfo.NOT_FOUND) {
return Py.None;
}
return this;
}
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, moduleCodeData.path);
logger.log(Level.FINE, "import {0} # loaded from {1}",
new Object[] {fullname, 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);
return info == ModuleInfo.PACKAGE;
}
/**
* 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);
for (SearchOrderEntry entry : searchOrder) {
T importEntry = makeEntry(path + entry.suffix);
if (importEntry == null) {
continue;
}
if (entry.type.contains(EntryType.IS_PACKAGE)) {
return ModuleInfo.PACKAGE;
}
return ModuleInfo.MODULE;
}
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) {
String path = makeFilename(fullname);
String fullPath = makeFilePath(fullname);
if (path.length() == 0) {
return null;
}
for (SearchOrderEntry entry : searchOrder) {
String suffix = entry.suffix;
String searchPath = path + suffix;
String fullSearchPath = fullPath + suffix;
logger.log(Level.FINE, "# trying {0}", searchPath);
T tocEntry = makeEntry(searchPath);
if (tocEntry == null) {
continue;
}
boolean isPackage = entry.type.contains(EntryType.IS_PACKAGE);
boolean isBytecode = entry.type.contains(EntryType.IS_BYTECODE);
long mtime = -1;
if (isBytecode) {
mtime = getSourceMtime(searchPath);
}
Bundle bundle = makeBundle(searchPath, tocEntry);
byte[] codeBytes;
try {
if (isBytecode) {
try {
codeBytes = imp.readCode(fullname, bundle.inputStream, true, mtime);
} catch (IOException ioe) {
throw Py.ImportError(ioe.getMessage() + "[path=" + fullSearchPath + "]");
}
if (codeBytes == null) {
// bad magic number or non-matching mtime in byte code, try next
continue;
}
} else {
codeBytes = imp.compileSource(fullname, bundle.inputStream, fullSearchPath);
}
} finally {
bundle.close();
}
PyCode code = BytecodeLoader.makeCode(fullname + "$py", codeBytes, fullSearchPath);
return new ModuleCodeData(code, isPackage, fullSearchPath);
}
return null;
}
/**
* 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 String suffix;
public EnumSet<EntryType> type;
public SearchOrderEntry(String suffix, EnumSet<EntryType> type) {
this.suffix = suffix;
this.type = type;
}
}
}