abc.py 10.5 KB
Newer Older
1
"""Abstract base classes related to import."""
2
from . import _bootstrap
3
from . import _bootstrap_external
4
from . import machinery
5 6
try:
    import _frozen_importlib
7
except ImportError as exc:
8 9 10
    if exc.name != '_frozen_importlib':
        raise
    _frozen_importlib = None
11 12 13 14
try:
    import _frozen_importlib_external
except ImportError as exc:
    _frozen_importlib_external = _bootstrap_external
15 16 17
import abc


18 19 20 21
def _register(abstract_cls, *classes):
    for cls in classes:
        abstract_cls.register(cls)
        if _frozen_importlib is not None:
22 23 24 25
            try:
                frozen_cls = getattr(_frozen_importlib, cls.__name__)
            except AttributeError:
                frozen_cls = getattr(_frozen_importlib_external, cls.__name__)
26 27 28
            abstract_cls.register(frozen_cls)


29
class Finder(metaclass=abc.ABCMeta):
30

31
    """Legacy abstract base class for import finders.
32

33 34 35 36
    It may be subclassed for compatibility with legacy third party
    reimplementations of the import system.  Otherwise, finder
    implementations should derive from the more specific MetaPathFinder
    or PathEntryFinder ABCs.
37 38
    """

39
    @abc.abstractmethod
40
    def find_module(self, fullname, path=None):
41
        """An abstract method that should find a module.
42
        The fullname is a str and the optional path is a str or None.
43
        Returns a Loader object or None.
44
        """
45

46 47 48 49 50

class MetaPathFinder(Finder):

    """Abstract base class for import finders on sys.meta_path."""

51 52 53
    # We don't define find_spec() here since that would break
    # hasattr checks we do to support backward compatibility.

54
    def find_module(self, fullname, path):
55 56 57 58 59
        """Return a loader for the module.

        If no module is found, return None.  The fullname is a str and
        the path is a list of strings or None.

60 61 62
        This method is deprecated in favor of finder.find_spec(). If find_spec()
        exists then backwards-compatible functionality is provided for this
        method.
63

64
        """
65 66 67 68
        if not hasattr(self, 'find_spec'):
            return None
        found = self.find_spec(fullname, path)
        return found.loader if found is not None else None
69

70 71 72 73 74
    def invalidate_caches(self):
        """An optional method for clearing the finder's cache, if any.
        This method is used by importlib.invalidate_caches().
        """

75
_register(MetaPathFinder, machinery.BuiltinImporter, machinery.FrozenImporter,
76
          machinery.PathFinder, machinery.WindowsRegistryFinder)
77 78


79 80 81
class PathEntryFinder(Finder):

    """Abstract base class for path entry finders used by PathFinder."""
82

83 84 85
    # We don't define find_spec() here since that would break
    # hasattr checks we do to support backward compatibility.

86
    def find_loader(self, fullname):
87 88 89 90 91 92 93 94 95 96
        """Return (loader, namespace portion) for the path entry.

        The fullname is a str.  The namespace portion is a sequence of
        path entries contributing to part of a namespace package. The
        sequence may be empty.  If loader is not None, the portion will
        be ignored.

        The portion will be discarded if another path entry finder
        locates the module as a normal module or package.

97 98
        This method is deprecated in favor of finder.find_spec(). If find_spec()
        is provided than backwards-compatible functionality is provided.
99

100
        """
101 102 103 104 105 106 107 108 109 110 111
        if not hasattr(self, 'find_spec'):
            return None, []
        found = self.find_spec(fullname)
        if found is not None:
            if not found.submodule_search_locations:
                portions = []
            else:
                portions = found.submodule_search_locations
            return found.loader, portions
        else:
            return None, []
112

113
    find_module = _bootstrap_external._find_module_shim
114 115 116 117 118 119

    def invalidate_caches(self):
        """An optional method for clearing the finder's cache, if any.
        This method is used by PathFinder.invalidate_caches().
        """

120 121 122 123 124
_register(PathEntryFinder, machinery.FileFinder)


class Loader(metaclass=abc.ABCMeta):

125
    """Abstract base class for import loaders."""
126

127 128
    def create_module(self, spec):
        """Return a module to initialize and into which to load.
129

130 131 132 133
        This method should raise ImportError if anything prevents it
        from creating a new module.  It may return None to indicate
        that the spec should create the new module.
        """
134
        # By default, defer to default semantics for the new module.
135 136 137 138 139
        return None

    # We don't define exec_module() here since that would break
    # hasattr checks we do to support backward compatibility.

140
    def load_module(self, fullname):
141 142 143 144
        """Return the loaded module.

        The module must be added to sys.modules and have import-related
        attributes set properly.  The fullname is a str.
145 146

        ImportError is raised on failure.
147

148 149 150
        This method is deprecated in favor of loader.exec_module(). If
        exec_module() exists then it is used to provide a backwards-compatible
        functionality for this method.
151

152
        """
153 154
        if not hasattr(self, 'exec_module'):
            raise ImportError
155
        return _bootstrap._load_module_shim(self, fullname)
156

157
    def module_repr(self, module):
158 159
        """Return a module's repr.

Brett Cannon's avatar
Brett Cannon committed
160 161
        Used by the module type when the method does not raise
        NotImplementedError.
162

163 164
        This method is deprecated.

165
        """
166
        # The exception will cause ModuleType.__repr__ to ignore this method.
167
        raise NotImplementedError
168 169 170 171


class ResourceLoader(Loader):

172 173
    """Abstract base class for loaders which can return data from their
    back-end storage.
174 175 176 177 178 179

    This ABC represents one of the optional protocols specified by PEP 302.

    """

    @abc.abstractmethod
180
    def get_data(self, path):
181
        """Abstract method which when implemented should return the bytes for
182
        the specified path.  The path must be a str."""
183
        raise IOError
184 185 186 187


class InspectLoader(Loader):

188 189
    """Abstract base class for loaders which support inspection about the
    modules they can load.
190 191 192 193 194

    This ABC represents one of the optional protocols specified by PEP 302.

    """

195
    def is_package(self, fullname):
196
        """Optional method which when implemented should return whether the
197 198
        module is a package.  The fullname is a str.  Returns a bool.

199
        Raises ImportError if the module cannot be found.
200 201
        """
        raise ImportError
202

203
    def get_code(self, fullname):
204
        """Method which returns the code object for the module.
205

206 207 208 209
        The fullname is a str.  Returns a types.CodeType if possible, else
        returns None if a code object does not make sense
        (e.g. built-in module). Raises ImportError if the module cannot be
        found.
210
        """
211 212 213 214
        source = self.get_source(fullname)
        if source is None:
            return None
        return self.source_to_code(source)
215 216

    @abc.abstractmethod
217
    def get_source(self, fullname):
218
        """Abstract method which should return the source code for the
219 220 221 222 223
        module.  The fullname is a str.  Returns a str.

        Raises ImportError if the module cannot be found.
        """
        raise ImportError
224

225 226
    @staticmethod
    def source_to_code(data, path='<string>'):
227 228 229 230 231 232
        """Compile 'data' into a code object.

        The 'data' argument can be anything that compile() can handle. The'path'
        argument should be where the data was retrieved (when applicable)."""
        return compile(data, path, 'exec', dont_inherit=True)

233 234
    exec_module = _bootstrap_external._LoaderBasics.exec_module
    load_module = _bootstrap_external._LoaderBasics.load_module
235

236
_register(InspectLoader, machinery.BuiltinImporter, machinery.FrozenImporter)
237

238

239 240 241 242 243 244 245 246 247 248
class ExecutionLoader(InspectLoader):

    """Abstract base class for loaders that wish to support the execution of
    modules as scripts.

    This ABC represents one of the optional protocols specified in PEP 302.

    """

    @abc.abstractmethod
249
    def get_filename(self, fullname):
250
        """Abstract method which should return the value that __file__ is to be
251 252 253 254 255
        set to.

        Raises ImportError if the module cannot be found.
        """
        raise ImportError
256

257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
    def get_code(self, fullname):
        """Method to return the code object for fullname.

        Should return None if not applicable (e.g. built-in module).
        Raise ImportError if the module cannot be found.
        """
        source = self.get_source(fullname)
        if source is None:
            return None
        try:
            path = self.get_filename(fullname)
        except ImportError:
            return self.source_to_code(source)
        else:
            return self.source_to_code(source, path)

273
_register(ExecutionLoader, machinery.ExtensionFileLoader)
274

275

276
class FileLoader(_bootstrap_external.FileLoader, ResourceLoader, ExecutionLoader):
277 278 279 280 281

    """Abstract base class partially implementing the ResourceLoader and
    ExecutionLoader ABCs."""

_register(FileLoader, machinery.SourceFileLoader,
282
            machinery.SourcelessFileLoader)
283 284


285
class SourceLoader(_bootstrap_external.SourceLoader, ResourceLoader, ExecutionLoader):
286

287 288
    """Abstract base class for loading source code (and optionally any
    corresponding bytecode).
289

290 291 292 293 294 295 296 297 298 299 300 301
    To support loading from source code, the abstractmethods inherited from
    ResourceLoader and ExecutionLoader need to be implemented. To also support
    loading from bytecode, the optional methods specified directly by this ABC
    is required.

    Inherited abstractmethods not implemented in this ABC:

        * ResourceLoader.get_data
        * ExecutionLoader.get_filename

    """

302
    def path_mtime(self, path):
303
        """Return the (int) modification time for the path (str)."""
304
        if self.path_stats.__func__ is SourceLoader.path_stats:
305
            raise IOError
306 307 308 309 310 311 312 313 314 315
        return int(self.path_stats(path)['mtime'])

    def path_stats(self, path):
        """Return a metadata dict for the source pointed to by the path (str).
        Possible keys:
        - 'mtime' (mandatory) is the numeric timestamp of last source
          code modification;
        - 'size' (optional) is the size in bytes of the source code.
        """
        if self.path_mtime.__func__ is SourceLoader.path_mtime:
316
            raise IOError
317
        return {'mtime': self.path_mtime(path)}
318

319
    def set_data(self, path, data):
320 321
        """Write the bytes to the path (if possible).

322 323
        Accepts a str path and data as bytes.

324 325 326 327 328
        Any needed intermediary directories are to be created. If for some
        reason the file cannot be written because of permissions, fail
        silently.
        """

329
_register(SourceLoader, machinery.SourceFileLoader)