blob: fa343f85a47610cc897f0f01cf478b0dafc28f7b [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)."""
Brett Cannon8d189072010-08-22 20:38:47 +0000126 raise NotImplementedError
127
Raymond Hettingercd92f372011-01-13 02:31:25 +0000128 def set_data(self, path, data):
Brett Cannon8d189072010-08-22 20:38:47 +0000129 """Write the bytes to the path (if possible).
130
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000131 Accepts a str path and data as bytes.
132
Brett Cannon8d189072010-08-22 20:38:47 +0000133 Any needed intermediary directories are to be created. If for some
134 reason the file cannot be written because of permissions, fail
135 silently.
136
137 """
138 raise NotImplementedError
139
Brett Cannonf23e3742010-06-27 23:57:46 +0000140
141class PyLoader(SourceLoader):
142
143 """Implement the deprecated PyLoader ABC in terms of SourceLoader.
144
145 This class has been deprecated! It is slated for removal in Python 3.4.
146 If compatibility with Python 3.1 is not needed then implement the
147 SourceLoader ABC instead of this class. If Python 3.1 compatibility is
148 needed, then use the following idiom to have a single class that is
149 compatible with Python 3.1 onwards::
150
151 try:
152 from importlib.abc import SourceLoader
153 except ImportError:
154 from importlib.abc import PyLoader as SourceLoader
155
156
157 class CustomLoader(SourceLoader):
158 def get_filename(self, fullname):
159 # Implement ...
160
161 def source_path(self, fullname):
162 '''Implement source_path in terms of get_filename.'''
163 try:
164 return self.get_filename(fullname)
165 except ImportError:
166 return None
167
168 def is_package(self, fullname):
169 filename = os.path.basename(self.get_filename(fullname))
170 return os.path.splitext(filename)[0] == '__init__'
Brett Cannon7aa21f72009-03-15 00:53:05 +0000171
172 """
Brett Cannon2a922ed2009-03-09 03:35:50 +0000173
174 @abc.abstractmethod
Brett Cannonf23e3742010-06-27 23:57:46 +0000175 def is_package(self, fullname):
Brett Cannon2a922ed2009-03-09 03:35:50 +0000176 raise NotImplementedError
177
Brett Cannonf23e3742010-06-27 23:57:46 +0000178 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +0000179 def source_path(self, fullname):
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000180 """Abstract method. Accepts a str module name and returns the path to
181 the source code for the module."""
Brett Cannonf23e3742010-06-27 23:57:46 +0000182 raise NotImplementedError
Brett Cannon2a922ed2009-03-09 03:35:50 +0000183
Brett Cannonf23e3742010-06-27 23:57:46 +0000184 def get_filename(self, fullname):
185 """Implement get_filename in terms of source_path.
186
187 As get_filename should only return a source file path there is no
188 chance of the path not existing but loading still being possible, so
189 ImportError should propagate instead of being turned into returning
190 None.
191
192 """
193 warnings.warn("importlib.abc.PyLoader is deprecated and is "
194 "slated for removal in Python 3.4; "
195 "use SourceLoader instead. "
196 "See the importlib documentation on how to be "
197 "compatible with Python 3.1 onwards.",
198 PendingDeprecationWarning)
199 path = self.source_path(fullname)
200 if path is None:
201 raise ImportError
202 else:
203 return path
204
Brett Cannonf23e3742010-06-27 23:57:46 +0000205
206class PyPycLoader(PyLoader):
Brett Cannon2a922ed2009-03-09 03:35:50 +0000207
Brett Cannon7aa21f72009-03-15 00:53:05 +0000208 """Abstract base class to assist in loading source and bytecode by
209 requiring only back-end storage methods to be implemented.
Brett Cannon2a922ed2009-03-09 03:35:50 +0000210
Brett Cannonf23e3742010-06-27 23:57:46 +0000211 This class has been deprecated! Removal is slated for Python 3.4. Implement
212 the SourceLoader ABC instead. If Python 3.1 compatibility is needed, see
213 PyLoader.
214
Brett Cannon7aa21f72009-03-15 00:53:05 +0000215 The methods get_code, get_source, and load_module are implemented for the
216 user.
217
218 """
Brett Cannon2a922ed2009-03-09 03:35:50 +0000219
Brett Cannonf23e3742010-06-27 23:57:46 +0000220 def get_filename(self, fullname):
221 """Return the source or bytecode file path."""
222 path = self.source_path(fullname)
223 if path is not None:
224 return path
225 path = self.bytecode_path(fullname)
226 if path is not None:
227 return path
228 raise ImportError("no source or bytecode path available for "
229 "{0!r}".format(fullname))
230
231 def get_code(self, fullname):
232 """Get a code object from source or bytecode."""
233 warnings.warn("importlib.abc.PyPycLoader is deprecated and slated for "
234 "removal in Python 3.4; use SourceLoader instead. "
235 "If Python 3.1 compatibility is required, see the "
236 "latest documentation for PyLoader.",
237 PendingDeprecationWarning)
238 source_timestamp = self.source_mtime(fullname)
239 # Try to use bytecode if it is available.
240 bytecode_path = self.bytecode_path(fullname)
241 if bytecode_path:
242 data = self.get_data(bytecode_path)
243 try:
244 magic = data[:4]
245 if len(magic) < 4:
246 raise ImportError("bad magic number in {}".format(fullname))
247 raw_timestamp = data[4:8]
248 if len(raw_timestamp) < 4:
249 raise EOFError("bad timestamp in {}".format(fullname))
250 pyc_timestamp = marshal._r_long(raw_timestamp)
251 bytecode = data[8:]
252 # Verify that the magic number is valid.
253 if imp.get_magic() != magic:
254 raise ImportError("bad magic number in {}".format(fullname))
255 # Verify that the bytecode is not stale (only matters when
256 # there is source to fall back on.
257 if source_timestamp:
258 if pyc_timestamp < source_timestamp:
259 raise ImportError("bytecode is stale")
260 except (ImportError, EOFError):
261 # If source is available give it a shot.
262 if source_timestamp is not None:
263 pass
264 else:
265 raise
266 else:
267 # Bytecode seems fine, so try to use it.
268 return marshal.loads(bytecode)
269 elif source_timestamp is None:
270 raise ImportError("no source or bytecode available to create code "
271 "object for {0!r}".format(fullname))
272 # Use the source.
273 source_path = self.source_path(fullname)
274 if source_path is None:
275 message = "a source path must exist to load {0}".format(fullname)
276 raise ImportError(message)
277 source = self.get_data(source_path)
278 code_object = compile(source, source_path, 'exec', dont_inherit=True)
279 # Generate bytecode and write it out.
280 if not sys.dont_write_bytecode:
281 data = bytearray(imp.get_magic())
282 data.extend(marshal._w_long(source_timestamp))
283 data.extend(marshal.dumps(code_object))
284 self.write_bytecode(fullname, data)
285 return code_object
286
Brett Cannon2a922ed2009-03-09 03:35:50 +0000287 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +0000288 def source_mtime(self, fullname):
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000289 """Abstract method. Accepts a str filename and returns an int
Brett Cannon7aa21f72009-03-15 00:53:05 +0000290 modification time for the source of the module."""
Brett Cannon2a922ed2009-03-09 03:35:50 +0000291 raise NotImplementedError
292
293 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +0000294 def bytecode_path(self, fullname):
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000295 """Abstract method. Accepts a str filename and returns the str pathname
296 to the bytecode for the module."""
Brett Cannon2a922ed2009-03-09 03:35:50 +0000297 raise NotImplementedError
298
299 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +0000300 def write_bytecode(self, fullname, bytecode):
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000301 """Abstract method. Accepts a str filename and bytes object
302 representing the bytecode for the module. Returns a boolean
303 representing whether the bytecode was written or not."""
Brett Cannon2a922ed2009-03-09 03:35:50 +0000304 raise NotImplementedError