blob: 0d376298c257e43820eac04d1f987cfb427a1fa8 [file] [log] [blame]
Brett Cannon2a922ed2009-03-09 03:35:50 +00001"""Abstract base classes related to import."""
2from . import _bootstrap
3from . import machinery
Brett Cannonf23e3742010-06-27 23:57:46 +00004from . import util
Brett Cannon2a922ed2009-03-09 03:35:50 +00005import abc
Brett Cannonf23e3742010-06-27 23:57:46 +00006import imp
7import io
8import marshal
9import os.path
10import sys
11import tokenize
Brett Cannon2a922ed2009-03-09 03:35:50 +000012import types
Brett Cannonf23e3742010-06-27 23:57:46 +000013import warnings
Brett Cannon2a922ed2009-03-09 03:35:50 +000014
15
16class Loader(metaclass=abc.ABCMeta):
17
Brett Cannon7aa21f72009-03-15 00:53:05 +000018 """Abstract base class for import loaders."""
Brett Cannon2a922ed2009-03-09 03:35:50 +000019
Brett Cannon7aa21f72009-03-15 00:53:05 +000020 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +000021 def load_module(self, fullname):
Raymond Hettingerd958ea72011-01-13 19:08:04 +000022 """Abstract method which when implemented should load a module.
23 The fullname is a str."""
Brett Cannon2a922ed2009-03-09 03:35:50 +000024 raise NotImplementedError
25
Brett Cannon2a922ed2009-03-09 03:35:50 +000026
27class Finder(metaclass=abc.ABCMeta):
28
Brett Cannon7aa21f72009-03-15 00:53:05 +000029 """Abstract base class for import finders."""
Brett Cannon2a922ed2009-03-09 03:35:50 +000030
31 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +000032 def find_module(self, fullname, path=None):
Raymond Hettingerd958ea72011-01-13 19:08:04 +000033 """Abstract method which when implemented should find a module.
34 The fullname is a str and the optional path is a str or None.
35 Returns a Loader object.
36 """
Brett Cannon2a922ed2009-03-09 03:35:50 +000037 raise NotImplementedError
38
39Finder.register(machinery.BuiltinImporter)
40Finder.register(machinery.FrozenImporter)
41Finder.register(machinery.PathFinder)
42
43
Brett Cannon2a922ed2009-03-09 03:35:50 +000044class ResourceLoader(Loader):
45
Brett Cannon7aa21f72009-03-15 00:53:05 +000046 """Abstract base class for loaders which can return data from their
47 back-end storage.
Brett Cannon2a922ed2009-03-09 03:35:50 +000048
49 This ABC represents one of the optional protocols specified by PEP 302.
50
51 """
52
53 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +000054 def get_data(self, path):
Brett Cannon7aa21f72009-03-15 00:53:05 +000055 """Abstract method which when implemented should return the bytes for
Raymond Hettingerd958ea72011-01-13 19:08:04 +000056 the specified path. The path must be a str."""
Brett Cannon2a922ed2009-03-09 03:35:50 +000057 raise NotImplementedError
58
59
60class InspectLoader(Loader):
61
Brett Cannon7aa21f72009-03-15 00:53:05 +000062 """Abstract base class for loaders which support inspection about the
63 modules they can load.
Brett Cannon2a922ed2009-03-09 03:35:50 +000064
65 This ABC represents one of the optional protocols specified by PEP 302.
66
67 """
68
69 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +000070 def is_package(self, fullname):
Brett Cannon7aa21f72009-03-15 00:53:05 +000071 """Abstract method which when implemented should return whether the
Raymond Hettingerd958ea72011-01-13 19:08:04 +000072 module is a package. The fullname is a str. Returns a bool."""
Brett Cannonf23e3742010-06-27 23:57:46 +000073 raise NotImplementedError
Brett Cannon2a922ed2009-03-09 03:35:50 +000074
75 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +000076 def get_code(self, fullname):
Brett Cannon7aa21f72009-03-15 00:53:05 +000077 """Abstract method which when implemented should return the code object
Raymond Hettingerd958ea72011-01-13 19:08:04 +000078 for the module. The fullname is a str. Returns a types.CodeType."""
Brett Cannonf23e3742010-06-27 23:57:46 +000079 raise NotImplementedError
Brett Cannon2a922ed2009-03-09 03:35:50 +000080
81 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +000082 def get_source(self, fullname):
Brett Cannon7aa21f72009-03-15 00:53:05 +000083 """Abstract method which should return the source code for the
Raymond Hettingerd958ea72011-01-13 19:08:04 +000084 module. The fullname is a str. Returns a str."""
Brett Cannonf23e3742010-06-27 23:57:46 +000085 raise NotImplementedError
Brett Cannon2a922ed2009-03-09 03:35:50 +000086
Brett Cannona113ac52009-03-15 01:41:33 +000087InspectLoader.register(machinery.BuiltinImporter)
Brett Cannon8d110132009-03-15 02:20:16 +000088InspectLoader.register(machinery.FrozenImporter)
Brett Cannona113ac52009-03-15 01:41:33 +000089
Brett Cannon2a922ed2009-03-09 03:35:50 +000090
Brett Cannon69194272009-07-20 04:23:48 +000091class ExecutionLoader(InspectLoader):
92
93 """Abstract base class for loaders that wish to support the execution of
94 modules as scripts.
95
96 This ABC represents one of the optional protocols specified in PEP 302.
97
98 """
99
100 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +0000101 def get_filename(self, fullname):
Brett Cannon69194272009-07-20 04:23:48 +0000102 """Abstract method which should return the value that __file__ is to be
103 set to."""
104 raise NotImplementedError
105
106
Brett Cannon0cf9e6a2010-06-28 04:57:24 +0000107class SourceLoader(_bootstrap.SourceLoader, ResourceLoader, ExecutionLoader):
Brett Cannon2a922ed2009-03-09 03:35:50 +0000108
Brett Cannonf23e3742010-06-27 23:57:46 +0000109 """Abstract base class for loading source code (and optionally any
110 corresponding bytecode).
Brett Cannon2a922ed2009-03-09 03:35:50 +0000111
Brett Cannonf23e3742010-06-27 23:57:46 +0000112 To support loading from source code, the abstractmethods inherited from
113 ResourceLoader and ExecutionLoader need to be implemented. To also support
114 loading from bytecode, the optional methods specified directly by this ABC
115 is required.
116
117 Inherited abstractmethods not implemented in this ABC:
118
119 * ResourceLoader.get_data
120 * ExecutionLoader.get_filename
121
122 """
123
Raymond Hettingercd92f372011-01-13 02:31:25 +0000124 def path_mtime(self, path):
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000125 """Return the (int) modification time for the path (str)."""
Antoine Pitrou5136ac02012-01-13 18:52:16 +0100126 if self.path_stats.__func__ is SourceLoader.path_stats:
127 raise NotImplementedError
128 return int(self.path_stats(path)['mtime'])
129
130 def path_stats(self, path):
131 """Return a metadata dict for the source pointed to by the path (str).
132 Possible keys:
133 - 'mtime' (mandatory) is the numeric timestamp of last source
134 code modification;
135 - 'size' (optional) is the size in bytes of the source code.
136 """
137 if self.path_mtime.__func__ is SourceLoader.path_mtime:
138 raise NotImplementedError
139 return {'mtime': self.path_mtime(path)}
Brett Cannon8d189072010-08-22 20:38:47 +0000140
Raymond Hettingercd92f372011-01-13 02:31:25 +0000141 def set_data(self, path, data):
Brett Cannon8d189072010-08-22 20:38:47 +0000142 """Write the bytes to the path (if possible).
143
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000144 Accepts a str path and data as bytes.
145
Brett Cannon8d189072010-08-22 20:38:47 +0000146 Any needed intermediary directories are to be created. If for some
147 reason the file cannot be written because of permissions, fail
148 silently.
149
150 """
151 raise NotImplementedError
152
Brett Cannonf23e3742010-06-27 23:57:46 +0000153
154class PyLoader(SourceLoader):
155
156 """Implement the deprecated PyLoader ABC in terms of SourceLoader.
157
158 This class has been deprecated! It is slated for removal in Python 3.4.
159 If compatibility with Python 3.1 is not needed then implement the
160 SourceLoader ABC instead of this class. If Python 3.1 compatibility is
161 needed, then use the following idiom to have a single class that is
162 compatible with Python 3.1 onwards::
163
164 try:
165 from importlib.abc import SourceLoader
166 except ImportError:
167 from importlib.abc import PyLoader as SourceLoader
168
169
170 class CustomLoader(SourceLoader):
171 def get_filename(self, fullname):
172 # Implement ...
173
174 def source_path(self, fullname):
175 '''Implement source_path in terms of get_filename.'''
176 try:
177 return self.get_filename(fullname)
178 except ImportError:
179 return None
180
181 def is_package(self, fullname):
182 filename = os.path.basename(self.get_filename(fullname))
183 return os.path.splitext(filename)[0] == '__init__'
Brett Cannon7aa21f72009-03-15 00:53:05 +0000184
185 """
Brett Cannon2a922ed2009-03-09 03:35:50 +0000186
187 @abc.abstractmethod
Brett Cannonf23e3742010-06-27 23:57:46 +0000188 def is_package(self, fullname):
Brett Cannon2a922ed2009-03-09 03:35:50 +0000189 raise NotImplementedError
190
Brett Cannonf23e3742010-06-27 23:57:46 +0000191 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +0000192 def source_path(self, fullname):
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000193 """Abstract method. Accepts a str module name and returns the path to
194 the source code for the module."""
Brett Cannonf23e3742010-06-27 23:57:46 +0000195 raise NotImplementedError
Brett Cannon2a922ed2009-03-09 03:35:50 +0000196
Brett Cannonf23e3742010-06-27 23:57:46 +0000197 def get_filename(self, fullname):
198 """Implement get_filename in terms of source_path.
199
200 As get_filename should only return a source file path there is no
201 chance of the path not existing but loading still being possible, so
202 ImportError should propagate instead of being turned into returning
203 None.
204
205 """
206 warnings.warn("importlib.abc.PyLoader is deprecated and is "
207 "slated for removal in Python 3.4; "
208 "use SourceLoader instead. "
209 "See the importlib documentation on how to be "
210 "compatible with Python 3.1 onwards.",
Florent Xicluna67317752011-12-10 11:07:42 +0100211 DeprecationWarning)
Brett Cannonf23e3742010-06-27 23:57:46 +0000212 path = self.source_path(fullname)
213 if path is None:
214 raise ImportError
215 else:
216 return path
217
Brett Cannonf23e3742010-06-27 23:57:46 +0000218
219class PyPycLoader(PyLoader):
Brett Cannon2a922ed2009-03-09 03:35:50 +0000220
Brett Cannon7aa21f72009-03-15 00:53:05 +0000221 """Abstract base class to assist in loading source and bytecode by
222 requiring only back-end storage methods to be implemented.
Brett Cannon2a922ed2009-03-09 03:35:50 +0000223
Brett Cannonf23e3742010-06-27 23:57:46 +0000224 This class has been deprecated! Removal is slated for Python 3.4. Implement
225 the SourceLoader ABC instead. If Python 3.1 compatibility is needed, see
226 PyLoader.
227
Brett Cannon7aa21f72009-03-15 00:53:05 +0000228 The methods get_code, get_source, and load_module are implemented for the
229 user.
230
231 """
Brett Cannon2a922ed2009-03-09 03:35:50 +0000232
Brett Cannonf23e3742010-06-27 23:57:46 +0000233 def get_filename(self, fullname):
234 """Return the source or bytecode file path."""
235 path = self.source_path(fullname)
236 if path is not None:
237 return path
238 path = self.bytecode_path(fullname)
239 if path is not None:
240 return path
241 raise ImportError("no source or bytecode path available for "
242 "{0!r}".format(fullname))
243
244 def get_code(self, fullname):
245 """Get a code object from source or bytecode."""
246 warnings.warn("importlib.abc.PyPycLoader is deprecated and slated for "
247 "removal in Python 3.4; use SourceLoader instead. "
248 "If Python 3.1 compatibility is required, see the "
249 "latest documentation for PyLoader.",
Florent Xicluna67317752011-12-10 11:07:42 +0100250 DeprecationWarning)
Brett Cannonf23e3742010-06-27 23:57:46 +0000251 source_timestamp = self.source_mtime(fullname)
252 # Try to use bytecode if it is available.
253 bytecode_path = self.bytecode_path(fullname)
254 if bytecode_path:
255 data = self.get_data(bytecode_path)
256 try:
257 magic = data[:4]
258 if len(magic) < 4:
259 raise ImportError("bad magic number in {}".format(fullname))
260 raw_timestamp = data[4:8]
261 if len(raw_timestamp) < 4:
262 raise EOFError("bad timestamp in {}".format(fullname))
263 pyc_timestamp = marshal._r_long(raw_timestamp)
264 bytecode = data[8:]
265 # Verify that the magic number is valid.
266 if imp.get_magic() != magic:
267 raise ImportError("bad magic number in {}".format(fullname))
268 # Verify that the bytecode is not stale (only matters when
269 # there is source to fall back on.
270 if source_timestamp:
271 if pyc_timestamp < source_timestamp:
272 raise ImportError("bytecode is stale")
273 except (ImportError, EOFError):
274 # If source is available give it a shot.
275 if source_timestamp is not None:
276 pass
277 else:
278 raise
279 else:
280 # Bytecode seems fine, so try to use it.
281 return marshal.loads(bytecode)
282 elif source_timestamp is None:
283 raise ImportError("no source or bytecode available to create code "
284 "object for {0!r}".format(fullname))
285 # Use the source.
286 source_path = self.source_path(fullname)
287 if source_path is None:
288 message = "a source path must exist to load {0}".format(fullname)
289 raise ImportError(message)
290 source = self.get_data(source_path)
291 code_object = compile(source, source_path, 'exec', dont_inherit=True)
292 # Generate bytecode and write it out.
293 if not sys.dont_write_bytecode:
294 data = bytearray(imp.get_magic())
295 data.extend(marshal._w_long(source_timestamp))
296 data.extend(marshal.dumps(code_object))
297 self.write_bytecode(fullname, data)
298 return code_object
299
Brett Cannon2a922ed2009-03-09 03:35:50 +0000300 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +0000301 def source_mtime(self, fullname):
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000302 """Abstract method. Accepts a str filename and returns an int
Brett Cannon7aa21f72009-03-15 00:53:05 +0000303 modification time for the source of the module."""
Brett Cannon2a922ed2009-03-09 03:35:50 +0000304 raise NotImplementedError
305
306 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +0000307 def bytecode_path(self, fullname):
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000308 """Abstract method. Accepts a str filename and returns the str pathname
309 to the bytecode for the module."""
Brett Cannon2a922ed2009-03-09 03:35:50 +0000310 raise NotImplementedError
311
312 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +0000313 def write_bytecode(self, fullname, bytecode):
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000314 """Abstract method. Accepts a str filename and bytes object
315 representing the bytecode for the module. Returns a boolean
316 representing whether the bytecode was written or not."""
Brett Cannon2a922ed2009-03-09 03:35:50 +0000317 raise NotImplementedError