blob: 43e4866ef665e4131eca54b212c6928c23e319c6 [file] [log] [blame]
Brett Cannon2a922ed2009-03-09 03:35:50 +00001"""Abstract base classes related to import."""
2from . import _bootstrap
3from . import machinery
4import abc
Brett Cannonf23e3742010-06-27 23:57:46 +00005import imp
Brett Cannonf23e3742010-06-27 23:57:46 +00006import marshal
Brett Cannonf23e3742010-06-27 23:57:46 +00007import sys
8import tokenize
Brett Cannonf23e3742010-06-27 23:57:46 +00009import warnings
Brett Cannon2a922ed2009-03-09 03:35:50 +000010
11
12class Loader(metaclass=abc.ABCMeta):
13
Brett Cannon7aa21f72009-03-15 00:53:05 +000014 """Abstract base class for import loaders."""
Brett Cannon2a922ed2009-03-09 03:35:50 +000015
Brett Cannon7aa21f72009-03-15 00:53:05 +000016 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +000017 def load_module(self, fullname):
Raymond Hettingerd958ea72011-01-13 19:08:04 +000018 """Abstract method which when implemented should load a module.
19 The fullname is a str."""
Brett Cannon2a922ed2009-03-09 03:35:50 +000020 raise NotImplementedError
21
Brett Cannon2a922ed2009-03-09 03:35:50 +000022
23class Finder(metaclass=abc.ABCMeta):
24
Brett Cannon7aa21f72009-03-15 00:53:05 +000025 """Abstract base class for import finders."""
Brett Cannon2a922ed2009-03-09 03:35:50 +000026
27 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +000028 def find_module(self, fullname, path=None):
Raymond Hettingerd958ea72011-01-13 19:08:04 +000029 """Abstract method which when implemented should find a module.
30 The fullname is a str and the optional path is a str or None.
31 Returns a Loader object.
32 """
Brett Cannon2a922ed2009-03-09 03:35:50 +000033 raise NotImplementedError
34
35Finder.register(machinery.BuiltinImporter)
36Finder.register(machinery.FrozenImporter)
37Finder.register(machinery.PathFinder)
38
39
Brett Cannon2a922ed2009-03-09 03:35:50 +000040class ResourceLoader(Loader):
41
Brett Cannon7aa21f72009-03-15 00:53:05 +000042 """Abstract base class for loaders which can return data from their
43 back-end storage.
Brett Cannon2a922ed2009-03-09 03:35:50 +000044
45 This ABC represents one of the optional protocols specified by PEP 302.
46
47 """
48
49 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +000050 def get_data(self, path):
Brett Cannon7aa21f72009-03-15 00:53:05 +000051 """Abstract method which when implemented should return the bytes for
Raymond Hettingerd958ea72011-01-13 19:08:04 +000052 the specified path. The path must be a str."""
Brett Cannon2a922ed2009-03-09 03:35:50 +000053 raise NotImplementedError
54
55
56class InspectLoader(Loader):
57
Brett Cannon7aa21f72009-03-15 00:53:05 +000058 """Abstract base class for loaders which support inspection about the
59 modules they can load.
Brett Cannon2a922ed2009-03-09 03:35:50 +000060
61 This ABC represents one of the optional protocols specified by PEP 302.
62
63 """
64
65 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +000066 def is_package(self, fullname):
Brett Cannon7aa21f72009-03-15 00:53:05 +000067 """Abstract method which when implemented should return whether the
Raymond Hettingerd958ea72011-01-13 19:08:04 +000068 module is a package. The fullname is a str. Returns a bool."""
Brett Cannonf23e3742010-06-27 23:57:46 +000069 raise NotImplementedError
Brett Cannon2a922ed2009-03-09 03:35:50 +000070
71 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +000072 def get_code(self, fullname):
Brett Cannon7aa21f72009-03-15 00:53:05 +000073 """Abstract method which when implemented should return the code object
Raymond Hettingerd958ea72011-01-13 19:08:04 +000074 for the module. The fullname is a str. Returns a types.CodeType."""
Brett Cannonf23e3742010-06-27 23:57:46 +000075 raise NotImplementedError
Brett Cannon2a922ed2009-03-09 03:35:50 +000076
77 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +000078 def get_source(self, fullname):
Brett Cannon7aa21f72009-03-15 00:53:05 +000079 """Abstract method which should return the source code for the
Raymond Hettingerd958ea72011-01-13 19:08:04 +000080 module. The fullname is a str. Returns a str."""
Brett Cannonf23e3742010-06-27 23:57:46 +000081 raise NotImplementedError
Brett Cannon2a922ed2009-03-09 03:35:50 +000082
Brett Cannona113ac52009-03-15 01:41:33 +000083InspectLoader.register(machinery.BuiltinImporter)
Brett Cannon8d110132009-03-15 02:20:16 +000084InspectLoader.register(machinery.FrozenImporter)
Brett Cannona113ac52009-03-15 01:41:33 +000085
Brett Cannon2a922ed2009-03-09 03:35:50 +000086
Brett Cannon69194272009-07-20 04:23:48 +000087class ExecutionLoader(InspectLoader):
88
89 """Abstract base class for loaders that wish to support the execution of
90 modules as scripts.
91
92 This ABC represents one of the optional protocols specified in PEP 302.
93
94 """
95
96 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +000097 def get_filename(self, fullname):
Brett Cannon69194272009-07-20 04:23:48 +000098 """Abstract method which should return the value that __file__ is to be
99 set to."""
100 raise NotImplementedError
101
102
Brett Cannon0cf9e6a2010-06-28 04:57:24 +0000103class SourceLoader(_bootstrap.SourceLoader, ResourceLoader, ExecutionLoader):
Brett Cannon2a922ed2009-03-09 03:35:50 +0000104
Brett Cannonf23e3742010-06-27 23:57:46 +0000105 """Abstract base class for loading source code (and optionally any
106 corresponding bytecode).
Brett Cannon2a922ed2009-03-09 03:35:50 +0000107
Brett Cannonf23e3742010-06-27 23:57:46 +0000108 To support loading from source code, the abstractmethods inherited from
109 ResourceLoader and ExecutionLoader need to be implemented. To also support
110 loading from bytecode, the optional methods specified directly by this ABC
111 is required.
112
113 Inherited abstractmethods not implemented in this ABC:
114
115 * ResourceLoader.get_data
116 * ExecutionLoader.get_filename
117
118 """
119
Raymond Hettingercd92f372011-01-13 02:31:25 +0000120 def path_mtime(self, path):
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000121 """Return the (int) modification time for the path (str)."""
Antoine Pitrou5136ac02012-01-13 18:52:16 +0100122 if self.path_stats.__func__ is SourceLoader.path_stats:
123 raise NotImplementedError
124 return int(self.path_stats(path)['mtime'])
125
126 def path_stats(self, path):
127 """Return a metadata dict for the source pointed to by the path (str).
128 Possible keys:
129 - 'mtime' (mandatory) is the numeric timestamp of last source
130 code modification;
131 - 'size' (optional) is the size in bytes of the source code.
132 """
133 if self.path_mtime.__func__ is SourceLoader.path_mtime:
134 raise NotImplementedError
135 return {'mtime': self.path_mtime(path)}
Brett Cannon8d189072010-08-22 20:38:47 +0000136
Raymond Hettingercd92f372011-01-13 02:31:25 +0000137 def set_data(self, path, data):
Brett Cannon8d189072010-08-22 20:38:47 +0000138 """Write the bytes to the path (if possible).
139
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000140 Accepts a str path and data as bytes.
141
Brett Cannon8d189072010-08-22 20:38:47 +0000142 Any needed intermediary directories are to be created. If for some
143 reason the file cannot be written because of permissions, fail
144 silently.
145
146 """
147 raise NotImplementedError
148
Brett Cannonf23e3742010-06-27 23:57:46 +0000149
150class PyLoader(SourceLoader):
151
152 """Implement the deprecated PyLoader ABC in terms of SourceLoader.
153
154 This class has been deprecated! It is slated for removal in Python 3.4.
155 If compatibility with Python 3.1 is not needed then implement the
156 SourceLoader ABC instead of this class. If Python 3.1 compatibility is
157 needed, then use the following idiom to have a single class that is
158 compatible with Python 3.1 onwards::
159
160 try:
161 from importlib.abc import SourceLoader
162 except ImportError:
163 from importlib.abc import PyLoader as SourceLoader
164
165
166 class CustomLoader(SourceLoader):
167 def get_filename(self, fullname):
168 # Implement ...
169
170 def source_path(self, fullname):
171 '''Implement source_path in terms of get_filename.'''
172 try:
173 return self.get_filename(fullname)
174 except ImportError:
175 return None
176
177 def is_package(self, fullname):
178 filename = os.path.basename(self.get_filename(fullname))
179 return os.path.splitext(filename)[0] == '__init__'
Brett Cannon7aa21f72009-03-15 00:53:05 +0000180
181 """
Brett Cannon2a922ed2009-03-09 03:35:50 +0000182
183 @abc.abstractmethod
Brett Cannonf23e3742010-06-27 23:57:46 +0000184 def is_package(self, fullname):
Brett Cannon2a922ed2009-03-09 03:35:50 +0000185 raise NotImplementedError
186
Brett Cannonf23e3742010-06-27 23:57:46 +0000187 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +0000188 def source_path(self, fullname):
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000189 """Abstract method. Accepts a str module name and returns the path to
190 the source code for the module."""
Brett Cannonf23e3742010-06-27 23:57:46 +0000191 raise NotImplementedError
Brett Cannon2a922ed2009-03-09 03:35:50 +0000192
Brett Cannonf23e3742010-06-27 23:57:46 +0000193 def get_filename(self, fullname):
194 """Implement get_filename in terms of source_path.
195
196 As get_filename should only return a source file path there is no
197 chance of the path not existing but loading still being possible, so
198 ImportError should propagate instead of being turned into returning
199 None.
200
201 """
202 warnings.warn("importlib.abc.PyLoader is deprecated and is "
203 "slated for removal in Python 3.4; "
204 "use SourceLoader instead. "
205 "See the importlib documentation on how to be "
206 "compatible with Python 3.1 onwards.",
Florent Xicluna67317752011-12-10 11:07:42 +0100207 DeprecationWarning)
Brett Cannonf23e3742010-06-27 23:57:46 +0000208 path = self.source_path(fullname)
209 if path is None:
Brett Cannonbbb66802012-04-12 21:09:01 -0400210 raise ImportError(name=fullname)
Brett Cannonf23e3742010-06-27 23:57:46 +0000211 else:
212 return path
213
Brett Cannonf23e3742010-06-27 23:57:46 +0000214
215class PyPycLoader(PyLoader):
Brett Cannon2a922ed2009-03-09 03:35:50 +0000216
Brett Cannon7aa21f72009-03-15 00:53:05 +0000217 """Abstract base class to assist in loading source and bytecode by
218 requiring only back-end storage methods to be implemented.
Brett Cannon2a922ed2009-03-09 03:35:50 +0000219
Brett Cannonf23e3742010-06-27 23:57:46 +0000220 This class has been deprecated! Removal is slated for Python 3.4. Implement
221 the SourceLoader ABC instead. If Python 3.1 compatibility is needed, see
222 PyLoader.
223
Brett Cannon7aa21f72009-03-15 00:53:05 +0000224 The methods get_code, get_source, and load_module are implemented for the
225 user.
226
227 """
Brett Cannon2a922ed2009-03-09 03:35:50 +0000228
Brett Cannonf23e3742010-06-27 23:57:46 +0000229 def get_filename(self, fullname):
230 """Return the source or bytecode file path."""
231 path = self.source_path(fullname)
232 if path is not None:
233 return path
234 path = self.bytecode_path(fullname)
235 if path is not None:
236 return path
237 raise ImportError("no source or bytecode path available for "
Brett Cannonbbb66802012-04-12 21:09:01 -0400238 "{0!r}".format(fullname), name=fullname)
Brett Cannonf23e3742010-06-27 23:57:46 +0000239
240 def get_code(self, fullname):
241 """Get a code object from source or bytecode."""
242 warnings.warn("importlib.abc.PyPycLoader is deprecated and slated for "
243 "removal in Python 3.4; use SourceLoader instead. "
244 "If Python 3.1 compatibility is required, see the "
245 "latest documentation for PyLoader.",
Florent Xicluna67317752011-12-10 11:07:42 +0100246 DeprecationWarning)
Brett Cannonf23e3742010-06-27 23:57:46 +0000247 source_timestamp = self.source_mtime(fullname)
248 # Try to use bytecode if it is available.
249 bytecode_path = self.bytecode_path(fullname)
250 if bytecode_path:
251 data = self.get_data(bytecode_path)
252 try:
253 magic = data[:4]
254 if len(magic) < 4:
Philip Jenvey4b42ff62012-02-24 21:48:17 -0800255 raise ImportError(
Brett Cannonbbb66802012-04-12 21:09:01 -0400256 "bad magic number in {}".format(fullname),
257 name=fullname, path=bytecode_path)
Brett Cannonf23e3742010-06-27 23:57:46 +0000258 raw_timestamp = data[4:8]
259 if len(raw_timestamp) < 4:
260 raise EOFError("bad timestamp in {}".format(fullname))
Brett Cannonc264e3e2012-01-25 18:58:03 -0500261 pyc_timestamp = _bootstrap._r_long(raw_timestamp)
Brett Cannonf23e3742010-06-27 23:57:46 +0000262 bytecode = data[8:]
263 # Verify that the magic number is valid.
264 if imp.get_magic() != magic:
Philip Jenvey4b42ff62012-02-24 21:48:17 -0800265 raise ImportError(
Brett Cannonbbb66802012-04-12 21:09:01 -0400266 "bad magic number in {}".format(fullname),
267 name=fullname, path=bytecode_path)
Brett Cannonf23e3742010-06-27 23:57:46 +0000268 # 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:
Brett Cannonbbb66802012-04-12 21:09:01 -0400272 raise ImportError("bytecode is stale", name=fullname,
273 path=bytecode_path)
Brett Cannonf23e3742010-06-27 23:57:46 +0000274 except (ImportError, EOFError):
275 # If source is available give it a shot.
276 if source_timestamp is not None:
277 pass
278 else:
279 raise
280 else:
281 # Bytecode seems fine, so try to use it.
282 return marshal.loads(bytecode)
283 elif source_timestamp is None:
284 raise ImportError("no source or bytecode available to create code "
Brett Cannonbbb66802012-04-12 21:09:01 -0400285 "object for {0!r}".format(fullname),
286 name=fullname)
Brett Cannonf23e3742010-06-27 23:57:46 +0000287 # Use the source.
288 source_path = self.source_path(fullname)
289 if source_path is None:
290 message = "a source path must exist to load {0}".format(fullname)
Brett Cannonbbb66802012-04-12 21:09:01 -0400291 raise ImportError(message, name=fullname)
Brett Cannonf23e3742010-06-27 23:57:46 +0000292 source = self.get_data(source_path)
293 code_object = compile(source, source_path, 'exec', dont_inherit=True)
294 # Generate bytecode and write it out.
295 if not sys.dont_write_bytecode:
296 data = bytearray(imp.get_magic())
Brett Cannonc264e3e2012-01-25 18:58:03 -0500297 data.extend(_bootstrap._w_long(source_timestamp))
Brett Cannonf23e3742010-06-27 23:57:46 +0000298 data.extend(marshal.dumps(code_object))
299 self.write_bytecode(fullname, data)
300 return code_object
301
Brett Cannon2a922ed2009-03-09 03:35:50 +0000302 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +0000303 def source_mtime(self, fullname):
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000304 """Abstract method. Accepts a str filename and returns an int
Brett Cannon7aa21f72009-03-15 00:53:05 +0000305 modification time for the source of the module."""
Brett Cannon2a922ed2009-03-09 03:35:50 +0000306 raise NotImplementedError
307
308 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +0000309 def bytecode_path(self, fullname):
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000310 """Abstract method. Accepts a str filename and returns the str pathname
311 to the bytecode for the module."""
Brett Cannon2a922ed2009-03-09 03:35:50 +0000312 raise NotImplementedError
313
314 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +0000315 def write_bytecode(self, fullname, bytecode):
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000316 """Abstract method. Accepts a str filename and bytes object
317 representing the bytecode for the module. Returns a boolean
318 representing whether the bytecode was written or not."""
Brett Cannon2a922ed2009-03-09 03:35:50 +0000319 raise NotImplementedError