blob: 6a7e3647bfb141fc346cb60e949e2c37be27c01b [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
Brett Cannon2a922ed2009-03-09 03:35:50 +000021 def load_module(self, fullname:str) -> types.ModuleType:
Brett Cannon7aa21f72009-03-15 00:53:05 +000022 """Abstract method which when implemented should load a module."""
Brett Cannon2a922ed2009-03-09 03:35:50 +000023 raise NotImplementedError
24
Brett Cannon2a922ed2009-03-09 03:35:50 +000025
26class Finder(metaclass=abc.ABCMeta):
27
Brett Cannon7aa21f72009-03-15 00:53:05 +000028 """Abstract base class for import finders."""
Brett Cannon2a922ed2009-03-09 03:35:50 +000029
30 @abc.abstractmethod
31 def find_module(self, fullname:str, path:[str]=None) -> Loader:
Brett Cannon7aa21f72009-03-15 00:53:05 +000032 """Abstract method which when implemented should find a module."""
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
50 def get_data(self, path:str) -> bytes:
Brett Cannon7aa21f72009-03-15 00:53:05 +000051 """Abstract method which when implemented should return the bytes for
52 the specified path."""
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
66 def is_package(self, fullname:str) -> bool:
Brett Cannon7aa21f72009-03-15 00:53:05 +000067 """Abstract method which when implemented should return whether the
68 module is a package."""
Brett Cannonf23e3742010-06-27 23:57:46 +000069 raise NotImplementedError
Brett Cannon2a922ed2009-03-09 03:35:50 +000070
71 @abc.abstractmethod
72 def get_code(self, fullname:str) -> types.CodeType:
Brett Cannon7aa21f72009-03-15 00:53:05 +000073 """Abstract method which when implemented should return the code object
74 for the module"""
Brett Cannonf23e3742010-06-27 23:57:46 +000075 raise NotImplementedError
Brett Cannon2a922ed2009-03-09 03:35:50 +000076
77 @abc.abstractmethod
78 def get_source(self, fullname:str) -> str:
Brett Cannon7aa21f72009-03-15 00:53:05 +000079 """Abstract method which should return the source code for the
80 module."""
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
97 def get_filename(self, fullname:str) -> str:
98 """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
Brett Cannonf23e3742010-06-27 23:57:46 +0000120
121class PyLoader(SourceLoader):
122
123 """Implement the deprecated PyLoader ABC in terms of SourceLoader.
124
125 This class has been deprecated! It is slated for removal in Python 3.4.
126 If compatibility with Python 3.1 is not needed then implement the
127 SourceLoader ABC instead of this class. If Python 3.1 compatibility is
128 needed, then use the following idiom to have a single class that is
129 compatible with Python 3.1 onwards::
130
131 try:
132 from importlib.abc import SourceLoader
133 except ImportError:
134 from importlib.abc import PyLoader as SourceLoader
135
136
137 class CustomLoader(SourceLoader):
138 def get_filename(self, fullname):
139 # Implement ...
140
141 def source_path(self, fullname):
142 '''Implement source_path in terms of get_filename.'''
143 try:
144 return self.get_filename(fullname)
145 except ImportError:
146 return None
147
148 def is_package(self, fullname):
149 filename = os.path.basename(self.get_filename(fullname))
150 return os.path.splitext(filename)[0] == '__init__'
Brett Cannon7aa21f72009-03-15 00:53:05 +0000151
152 """
Brett Cannon2a922ed2009-03-09 03:35:50 +0000153
154 @abc.abstractmethod
Brett Cannonf23e3742010-06-27 23:57:46 +0000155 def is_package(self, fullname):
Brett Cannon2a922ed2009-03-09 03:35:50 +0000156 raise NotImplementedError
157
Brett Cannonf23e3742010-06-27 23:57:46 +0000158 @abc.abstractmethod
159 def source_path(self, fullname:str) -> object:
160 """Abstract method which when implemented should return the path to the
161 source code for the module."""
162 raise NotImplementedError
Brett Cannon2a922ed2009-03-09 03:35:50 +0000163
Brett Cannonf23e3742010-06-27 23:57:46 +0000164 def get_filename(self, fullname):
165 """Implement get_filename in terms of source_path.
166
167 As get_filename should only return a source file path there is no
168 chance of the path not existing but loading still being possible, so
169 ImportError should propagate instead of being turned into returning
170 None.
171
172 """
173 warnings.warn("importlib.abc.PyLoader is deprecated and is "
174 "slated for removal in Python 3.4; "
175 "use SourceLoader instead. "
176 "See the importlib documentation on how to be "
177 "compatible with Python 3.1 onwards.",
178 PendingDeprecationWarning)
179 path = self.source_path(fullname)
180 if path is None:
181 raise ImportError
182 else:
183 return path
184
Brett Cannonf23e3742010-06-27 23:57:46 +0000185
186class PyPycLoader(PyLoader):
Brett Cannon2a922ed2009-03-09 03:35:50 +0000187
Brett Cannon7aa21f72009-03-15 00:53:05 +0000188 """Abstract base class to assist in loading source and bytecode by
189 requiring only back-end storage methods to be implemented.
Brett Cannon2a922ed2009-03-09 03:35:50 +0000190
Brett Cannonf23e3742010-06-27 23:57:46 +0000191 This class has been deprecated! Removal is slated for Python 3.4. Implement
192 the SourceLoader ABC instead. If Python 3.1 compatibility is needed, see
193 PyLoader.
194
Brett Cannon7aa21f72009-03-15 00:53:05 +0000195 The methods get_code, get_source, and load_module are implemented for the
196 user.
197
198 """
Brett Cannon2a922ed2009-03-09 03:35:50 +0000199
Brett Cannonf23e3742010-06-27 23:57:46 +0000200 def get_filename(self, fullname):
201 """Return the source or bytecode file path."""
202 path = self.source_path(fullname)
203 if path is not None:
204 return path
205 path = self.bytecode_path(fullname)
206 if path is not None:
207 return path
208 raise ImportError("no source or bytecode path available for "
209 "{0!r}".format(fullname))
210
211 def get_code(self, fullname):
212 """Get a code object from source or bytecode."""
213 warnings.warn("importlib.abc.PyPycLoader is deprecated and slated for "
214 "removal in Python 3.4; use SourceLoader instead. "
215 "If Python 3.1 compatibility is required, see the "
216 "latest documentation for PyLoader.",
217 PendingDeprecationWarning)
218 source_timestamp = self.source_mtime(fullname)
219 # Try to use bytecode if it is available.
220 bytecode_path = self.bytecode_path(fullname)
221 if bytecode_path:
222 data = self.get_data(bytecode_path)
223 try:
224 magic = data[:4]
225 if len(magic) < 4:
226 raise ImportError("bad magic number in {}".format(fullname))
227 raw_timestamp = data[4:8]
228 if len(raw_timestamp) < 4:
229 raise EOFError("bad timestamp in {}".format(fullname))
230 pyc_timestamp = marshal._r_long(raw_timestamp)
231 bytecode = data[8:]
232 # Verify that the magic number is valid.
233 if imp.get_magic() != magic:
234 raise ImportError("bad magic number in {}".format(fullname))
235 # Verify that the bytecode is not stale (only matters when
236 # there is source to fall back on.
237 if source_timestamp:
238 if pyc_timestamp < source_timestamp:
239 raise ImportError("bytecode is stale")
240 except (ImportError, EOFError):
241 # If source is available give it a shot.
242 if source_timestamp is not None:
243 pass
244 else:
245 raise
246 else:
247 # Bytecode seems fine, so try to use it.
248 return marshal.loads(bytecode)
249 elif source_timestamp is None:
250 raise ImportError("no source or bytecode available to create code "
251 "object for {0!r}".format(fullname))
252 # Use the source.
253 source_path = self.source_path(fullname)
254 if source_path is None:
255 message = "a source path must exist to load {0}".format(fullname)
256 raise ImportError(message)
257 source = self.get_data(source_path)
258 code_object = compile(source, source_path, 'exec', dont_inherit=True)
259 # Generate bytecode and write it out.
260 if not sys.dont_write_bytecode:
261 data = bytearray(imp.get_magic())
262 data.extend(marshal._w_long(source_timestamp))
263 data.extend(marshal.dumps(code_object))
264 self.write_bytecode(fullname, data)
265 return code_object
266
Brett Cannon2a922ed2009-03-09 03:35:50 +0000267 @abc.abstractmethod
268 def source_mtime(self, fullname:str) -> int:
Brett Cannon7aa21f72009-03-15 00:53:05 +0000269 """Abstract method which when implemented should return the
270 modification time for the source of the module."""
Brett Cannon2a922ed2009-03-09 03:35:50 +0000271 raise NotImplementedError
272
273 @abc.abstractmethod
274 def bytecode_path(self, fullname:str) -> object:
Brett Cannon7aa21f72009-03-15 00:53:05 +0000275 """Abstract method which when implemented should return the path to the
276 bytecode for the module."""
Brett Cannon2a922ed2009-03-09 03:35:50 +0000277 raise NotImplementedError
278
279 @abc.abstractmethod
Brett Cannonb89ee8e2009-12-12 22:35:59 +0000280 def write_bytecode(self, fullname:str, bytecode:bytes) -> bool:
Brett Cannon7aa21f72009-03-15 00:53:05 +0000281 """Abstract method which when implemented should attempt to write the
Brett Cannonb89ee8e2009-12-12 22:35:59 +0000282 bytecode for the module, returning a boolean representing whether the
283 bytecode was written or not."""
Brett Cannon2a922ed2009-03-09 03:35:50 +0000284 raise NotImplementedError