• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Core implementation of path-based import.
2
3This module is NOT meant to be directly imported! It has been designed such
4that it can be bootstrapped into Python as the implementation of import. As
5such it requires the injection of specific modules and attributes in order to
6work. One should use importlib as the public-facing version of this module.
7
8"""
9# IMPORTANT: Whenever making changes to this module, be sure to run a top-level
10# `make regen-importlib` followed by `make` in order to get the frozen version
11# of the module updated. Not doing so will result in the Makefile to fail for
12# all others who don't have a ./python around to freeze the module in the early
13# stages of compilation.
14#
15
16# See importlib._setup() for what is injected into the global namespace.
17
18# When editing this code be aware that code executed at import time CANNOT
19# reference any injected objects! This includes not only global code but also
20# anything specified at the class level.
21
22# Module injected manually by _set_bootstrap_module()
23_bootstrap = None
24
25# Import builtin modules
26import _imp
27import _io
28import sys
29import _warnings
30import marshal
31
32
33_MS_WINDOWS = (sys.platform == 'win32')
34if _MS_WINDOWS:
35    import nt as _os
36    import winreg
37else:
38    import posix as _os
39
40
41if _MS_WINDOWS:
42    path_separators = ['\\', '/']
43else:
44    path_separators = ['/']
45# Assumption made in _path_join()
46assert all(len(sep) == 1 for sep in path_separators)
47path_sep = path_separators[0]
48path_sep_tuple = tuple(path_separators)
49path_separators = ''.join(path_separators)
50_pathseps_with_colon = {f':{s}' for s in path_separators}
51
52
53# Bootstrap-related code ######################################################
54_CASE_INSENSITIVE_PLATFORMS_STR_KEY = 'win',
55_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin'
56_CASE_INSENSITIVE_PLATFORMS =  (_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY
57                                + _CASE_INSENSITIVE_PLATFORMS_STR_KEY)
58
59
60def _make_relax_case():
61    if sys.platform.startswith(_CASE_INSENSITIVE_PLATFORMS):
62        if sys.platform.startswith(_CASE_INSENSITIVE_PLATFORMS_STR_KEY):
63            key = 'PYTHONCASEOK'
64        else:
65            key = b'PYTHONCASEOK'
66
67        def _relax_case():
68            """True if filenames must be checked case-insensitively and ignore environment flags are not set."""
69            return not sys.flags.ignore_environment and key in _os.environ
70    else:
71        def _relax_case():
72            """True if filenames must be checked case-insensitively."""
73            return False
74    return _relax_case
75
76_relax_case = _make_relax_case()
77
78
79def _pack_uint32(x):
80    """Convert a 32-bit integer to little-endian."""
81    return (int(x) & 0xFFFFFFFF).to_bytes(4, 'little')
82
83
84def _unpack_uint32(data):
85    """Convert 4 bytes in little-endian to an integer."""
86    assert len(data) == 4
87    return int.from_bytes(data, 'little')
88
89def _unpack_uint16(data):
90    """Convert 2 bytes in little-endian to an integer."""
91    assert len(data) == 2
92    return int.from_bytes(data, 'little')
93
94
95if _MS_WINDOWS:
96    def _path_join(*path_parts):
97        """Replacement for os.path.join()."""
98        if not path_parts:
99            return ""
100        if len(path_parts) == 1:
101            return path_parts[0]
102        root = ""
103        path = []
104        for new_root, tail in map(_os._path_splitroot, path_parts):
105            if new_root.startswith(path_sep_tuple) or new_root.endswith(path_sep_tuple):
106                root = new_root.rstrip(path_separators) or root
107                path = [path_sep + tail]
108            elif new_root.endswith(':'):
109                if root.casefold() != new_root.casefold():
110                    # Drive relative paths have to be resolved by the OS, so we reset the
111                    # tail but do not add a path_sep prefix.
112                    root = new_root
113                    path = [tail]
114                else:
115                    path.append(tail)
116            else:
117                root = new_root or root
118                path.append(tail)
119        path = [p.rstrip(path_separators) for p in path if p]
120        if len(path) == 1 and not path[0]:
121            # Avoid losing the root's trailing separator when joining with nothing
122            return root + path_sep
123        return root + path_sep.join(path)
124
125else:
126    def _path_join(*path_parts):
127        """Replacement for os.path.join()."""
128        return path_sep.join([part.rstrip(path_separators)
129                              for part in path_parts if part])
130
131
132def _path_split(path):
133    """Replacement for os.path.split()."""
134    i = max(path.rfind(p) for p in path_separators)
135    if i < 0:
136        return '', path
137    return path[:i], path[i + 1:]
138
139
140def _path_stat(path):
141    """Stat the path.
142
143    Made a separate function to make it easier to override in experiments
144    (e.g. cache stat results).
145
146    """
147    return _os.stat(path)
148
149
150def _path_is_mode_type(path, mode):
151    """Test whether the path is the specified mode type."""
152    try:
153        stat_info = _path_stat(path)
154    except OSError:
155        return False
156    return (stat_info.st_mode & 0o170000) == mode
157
158
159def _path_isfile(path):
160    """Replacement for os.path.isfile."""
161    return _path_is_mode_type(path, 0o100000)
162
163
164def _path_isdir(path):
165    """Replacement for os.path.isdir."""
166    if not path:
167        path = _os.getcwd()
168    return _path_is_mode_type(path, 0o040000)
169
170
171if _MS_WINDOWS:
172    def _path_isabs(path):
173        """Replacement for os.path.isabs."""
174        if not path:
175            return False
176        root = _os._path_splitroot(path)[0].replace('/', '\\')
177        return len(root) > 1 and (root.startswith('\\\\') or root.endswith('\\'))
178
179else:
180    def _path_isabs(path):
181        """Replacement for os.path.isabs."""
182        return path.startswith(path_separators)
183
184
185def _write_atomic(path, data, mode=0o666):
186    """Best-effort function to write data to a path atomically.
187    Be prepared to handle a FileExistsError if concurrent writing of the
188    temporary file is attempted."""
189    # id() is used to generate a pseudo-random filename.
190    path_tmp = '{}.{}'.format(path, id(path))
191    fd = _os.open(path_tmp,
192                  _os.O_EXCL | _os.O_CREAT | _os.O_WRONLY, mode & 0o666)
193    try:
194        # We first write data to a temporary file, and then use os.replace() to
195        # perform an atomic rename.
196        with _io.FileIO(fd, 'wb') as file:
197            file.write(data)
198        _os.replace(path_tmp, path)
199    except OSError:
200        try:
201            _os.unlink(path_tmp)
202        except OSError:
203            pass
204        raise
205
206
207_code_type = type(_write_atomic.__code__)
208
209
210# Finder/loader utility code ###############################################
211
212# Magic word to reject .pyc files generated by other Python versions.
213# It should change for each incompatible change to the bytecode.
214#
215# The value of CR and LF is incorporated so if you ever read or write
216# a .pyc file in text mode the magic number will be wrong; also, the
217# Apple MPW compiler swaps their values, botching string constants.
218#
219# There were a variety of old schemes for setting the magic number.
220# The current working scheme is to increment the previous value by
221# 10.
222#
223# Starting with the adoption of PEP 3147 in Python 3.2, every bump in magic
224# number also includes a new "magic tag", i.e. a human readable string used
225# to represent the magic number in __pycache__ directories.  When you change
226# the magic number, you must also set a new unique magic tag.  Generally this
227# can be named after the Python major version of the magic number bump, but
228# it can really be anything, as long as it's different than anything else
229# that's come before.  The tags are included in the following table, starting
230# with Python 3.2a0.
231#
232# Known values:
233#  Python 1.5:   20121
234#  Python 1.5.1: 20121
235#     Python 1.5.2: 20121
236#     Python 1.6:   50428
237#     Python 2.0:   50823
238#     Python 2.0.1: 50823
239#     Python 2.1:   60202
240#     Python 2.1.1: 60202
241#     Python 2.1.2: 60202
242#     Python 2.2:   60717
243#     Python 2.3a0: 62011
244#     Python 2.3a0: 62021
245#     Python 2.3a0: 62011 (!)
246#     Python 2.4a0: 62041
247#     Python 2.4a3: 62051
248#     Python 2.4b1: 62061
249#     Python 2.5a0: 62071
250#     Python 2.5a0: 62081 (ast-branch)
251#     Python 2.5a0: 62091 (with)
252#     Python 2.5a0: 62092 (changed WITH_CLEANUP opcode)
253#     Python 2.5b3: 62101 (fix wrong code: for x, in ...)
254#     Python 2.5b3: 62111 (fix wrong code: x += yield)
255#     Python 2.5c1: 62121 (fix wrong lnotab with for loops and
256#                          storing constants that should have been removed)
257#     Python 2.5c2: 62131 (fix wrong code: for x, in ... in listcomp/genexp)
258#     Python 2.6a0: 62151 (peephole optimizations and STORE_MAP opcode)
259#     Python 2.6a1: 62161 (WITH_CLEANUP optimization)
260#     Python 2.7a0: 62171 (optimize list comprehensions/change LIST_APPEND)
261#     Python 2.7a0: 62181 (optimize conditional branches:
262#                          introduce POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE)
263#     Python 2.7a0  62191 (introduce SETUP_WITH)
264#     Python 2.7a0  62201 (introduce BUILD_SET)
265#     Python 2.7a0  62211 (introduce MAP_ADD and SET_ADD)
266#     Python 3000:   3000
267#                    3010 (removed UNARY_CONVERT)
268#                    3020 (added BUILD_SET)
269#                    3030 (added keyword-only parameters)
270#                    3040 (added signature annotations)
271#                    3050 (print becomes a function)
272#                    3060 (PEP 3115 metaclass syntax)
273#                    3061 (string literals become unicode)
274#                    3071 (PEP 3109 raise changes)
275#                    3081 (PEP 3137 make __file__ and __name__ unicode)
276#                    3091 (kill str8 interning)
277#                    3101 (merge from 2.6a0, see 62151)
278#                    3103 (__file__ points to source file)
279#     Python 3.0a4: 3111 (WITH_CLEANUP optimization).
280#     Python 3.0b1: 3131 (lexical exception stacking, including POP_EXCEPT
281                          #3021)
282#     Python 3.1a1: 3141 (optimize list, set and dict comprehensions:
283#                         change LIST_APPEND and SET_ADD, add MAP_ADD #2183)
284#     Python 3.1a1: 3151 (optimize conditional branches:
285#                         introduce POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE
286                          #4715)
287#     Python 3.2a1: 3160 (add SETUP_WITH #6101)
288#                   tag: cpython-32
289#     Python 3.2a2: 3170 (add DUP_TOP_TWO, remove DUP_TOPX and ROT_FOUR #9225)
290#                   tag: cpython-32
291#     Python 3.2a3  3180 (add DELETE_DEREF #4617)
292#     Python 3.3a1  3190 (__class__ super closure changed)
293#     Python 3.3a1  3200 (PEP 3155 __qualname__ added #13448)
294#     Python 3.3a1  3210 (added size modulo 2**32 to the pyc header #13645)
295#     Python 3.3a2  3220 (changed PEP 380 implementation #14230)
296#     Python 3.3a4  3230 (revert changes to implicit __class__ closure #14857)
297#     Python 3.4a1  3250 (evaluate positional default arguments before
298#                        keyword-only defaults #16967)
299#     Python 3.4a1  3260 (add LOAD_CLASSDEREF; allow locals of class to override
300#                        free vars #17853)
301#     Python 3.4a1  3270 (various tweaks to the __class__ closure #12370)
302#     Python 3.4a1  3280 (remove implicit class argument)
303#     Python 3.4a4  3290 (changes to __qualname__ computation #19301)
304#     Python 3.4a4  3300 (more changes to __qualname__ computation #19301)
305#     Python 3.4rc2 3310 (alter __qualname__ computation #20625)
306#     Python 3.5a1  3320 (PEP 465: Matrix multiplication operator #21176)
307#     Python 3.5b1  3330 (PEP 448: Additional Unpacking Generalizations #2292)
308#     Python 3.5b2  3340 (fix dictionary display evaluation order #11205)
309#     Python 3.5b3  3350 (add GET_YIELD_FROM_ITER opcode #24400)
310#     Python 3.5.2  3351 (fix BUILD_MAP_UNPACK_WITH_CALL opcode #27286)
311#     Python 3.6a0  3360 (add FORMAT_VALUE opcode #25483)
312#     Python 3.6a1  3361 (lineno delta of code.co_lnotab becomes signed #26107)
313#     Python 3.6a2  3370 (16 bit wordcode #26647)
314#     Python 3.6a2  3371 (add BUILD_CONST_KEY_MAP opcode #27140)
315#     Python 3.6a2  3372 (MAKE_FUNCTION simplification, remove MAKE_CLOSURE
316#                         #27095)
317#     Python 3.6b1  3373 (add BUILD_STRING opcode #27078)
318#     Python 3.6b1  3375 (add SETUP_ANNOTATIONS and STORE_ANNOTATION opcodes
319#                         #27985)
320#     Python 3.6b1  3376 (simplify CALL_FUNCTIONs & BUILD_MAP_UNPACK_WITH_CALL
321                          #27213)
322#     Python 3.6b1  3377 (set __class__ cell from type.__new__ #23722)
323#     Python 3.6b2  3378 (add BUILD_TUPLE_UNPACK_WITH_CALL #28257)
324#     Python 3.6rc1 3379 (more thorough __class__ validation #23722)
325#     Python 3.7a1  3390 (add LOAD_METHOD and CALL_METHOD opcodes #26110)
326#     Python 3.7a2  3391 (update GET_AITER #31709)
327#     Python 3.7a4  3392 (PEP 552: Deterministic pycs #31650)
328#     Python 3.7b1  3393 (remove STORE_ANNOTATION opcode #32550)
329#     Python 3.7b5  3394 (restored docstring as the first stmt in the body;
330#                         this might affected the first line number #32911)
331#     Python 3.8a1  3400 (move frame block handling to compiler #17611)
332#     Python 3.8a1  3401 (add END_ASYNC_FOR #33041)
333#     Python 3.8a1  3410 (PEP570 Python Positional-Only Parameters #36540)
334#     Python 3.8b2  3411 (Reverse evaluation order of key: value in dict
335#                         comprehensions #35224)
336#     Python 3.8b2  3412 (Swap the position of positional args and positional
337#                         only args in ast.arguments #37593)
338#     Python 3.8b4  3413 (Fix "break" and "continue" in "finally" #37830)
339#     Python 3.9a0  3420 (add LOAD_ASSERTION_ERROR #34880)
340#     Python 3.9a0  3421 (simplified bytecode for with blocks #32949)
341#     Python 3.9a0  3422 (remove BEGIN_FINALLY, END_FINALLY, CALL_FINALLY, POP_FINALLY bytecodes #33387)
342#     Python 3.9a2  3423 (add IS_OP, CONTAINS_OP and JUMP_IF_NOT_EXC_MATCH bytecodes #39156)
343#     Python 3.9a2  3424 (simplify bytecodes for *value unpacking)
344#     Python 3.9a2  3425 (simplify bytecodes for **value unpacking)
345#     Python 3.10a1 3430 (Make 'annotations' future by default)
346#     Python 3.10a1 3431 (New line number table format -- PEP 626)
347#     Python 3.10a2 3432 (Function annotation for MAKE_FUNCTION is changed from dict to tuple bpo-42202)
348#     Python 3.10a2 3433 (RERAISE restores f_lasti if oparg != 0)
349#     Python 3.10a6 3434 (PEP 634: Structural Pattern Matching)
350#     Python 3.10a7 3435 Use instruction offsets (as opposed to byte offsets).
351#     Python 3.10b1 3436 (Add GEN_START bytecode #43683)
352#     Python 3.10b1 3437 (Undo making 'annotations' future by default - We like to dance among core devs!)
353#     Python 3.10b1 3438 Safer line number table handling.
354#     Python 3.10b1 3439 (Add ROT_N)
355
356#
357# MAGIC must change whenever the bytecode emitted by the compiler may no
358# longer be understood by older implementations of the eval loop (usually
359# due to the addition of new opcodes).
360#
361# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
362# in PC/launcher.c must also be updated.
363
364MAGIC_NUMBER = (3439).to_bytes(2, 'little') + b'\r\n'
365_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little')  # For import.c
366
367_PYCACHE = '__pycache__'
368_OPT = 'opt-'
369
370SOURCE_SUFFIXES = ['.py']
371if _MS_WINDOWS:
372    SOURCE_SUFFIXES.append('.pyw')
373
374EXTENSION_SUFFIXES = _imp.extension_suffixes()
375
376BYTECODE_SUFFIXES = ['.pyc']
377# Deprecated.
378DEBUG_BYTECODE_SUFFIXES = OPTIMIZED_BYTECODE_SUFFIXES = BYTECODE_SUFFIXES
379
380def cache_from_source(path, debug_override=None, *, optimization=None):
381    """Given the path to a .py file, return the path to its .pyc file.
382
383    The .py file does not need to exist; this simply returns the path to the
384    .pyc file calculated as if the .py file were imported.
385
386    The 'optimization' parameter controls the presumed optimization level of
387    the bytecode file. If 'optimization' is not None, the string representation
388    of the argument is taken and verified to be alphanumeric (else ValueError
389    is raised).
390
391    The debug_override parameter is deprecated. If debug_override is not None,
392    a True value is the same as setting 'optimization' to the empty string
393    while a False value is equivalent to setting 'optimization' to '1'.
394
395    If sys.implementation.cache_tag is None then NotImplementedError is raised.
396
397    """
398    if debug_override is not None:
399        _warnings.warn('the debug_override parameter is deprecated; use '
400                       "'optimization' instead", DeprecationWarning)
401        if optimization is not None:
402            message = 'debug_override or optimization must be set to None'
403            raise TypeError(message)
404        optimization = '' if debug_override else 1
405    path = _os.fspath(path)
406    head, tail = _path_split(path)
407    base, sep, rest = tail.rpartition('.')
408    tag = sys.implementation.cache_tag
409    if tag is None:
410        raise NotImplementedError('sys.implementation.cache_tag is None')
411    almost_filename = ''.join([(base if base else rest), sep, tag])
412    if optimization is None:
413        if sys.flags.optimize == 0:
414            optimization = ''
415        else:
416            optimization = sys.flags.optimize
417    optimization = str(optimization)
418    if optimization != '':
419        if not optimization.isalnum():
420            raise ValueError('{!r} is not alphanumeric'.format(optimization))
421        almost_filename = '{}.{}{}'.format(almost_filename, _OPT, optimization)
422    filename = almost_filename + BYTECODE_SUFFIXES[0]
423    if sys.pycache_prefix is not None:
424        # We need an absolute path to the py file to avoid the possibility of
425        # collisions within sys.pycache_prefix, if someone has two different
426        # `foo/bar.py` on their system and they import both of them using the
427        # same sys.pycache_prefix. Let's say sys.pycache_prefix is
428        # `C:\Bytecode`; the idea here is that if we get `Foo\Bar`, we first
429        # make it absolute (`C:\Somewhere\Foo\Bar`), then make it root-relative
430        # (`Somewhere\Foo\Bar`), so we end up placing the bytecode file in an
431        # unambiguous `C:\Bytecode\Somewhere\Foo\Bar\`.
432        if not _path_isabs(head):
433            head = _path_join(_os.getcwd(), head)
434
435        # Strip initial drive from a Windows path. We know we have an absolute
436        # path here, so the second part of the check rules out a POSIX path that
437        # happens to contain a colon at the second character.
438        if head[1] == ':' and head[0] not in path_separators:
439            head = head[2:]
440
441        # Strip initial path separator from `head` to complete the conversion
442        # back to a root-relative path before joining.
443        return _path_join(
444            sys.pycache_prefix,
445            head.lstrip(path_separators),
446            filename,
447        )
448    return _path_join(head, _PYCACHE, filename)
449
450
451def source_from_cache(path):
452    """Given the path to a .pyc. file, return the path to its .py file.
453
454    The .pyc file does not need to exist; this simply returns the path to
455    the .py file calculated to correspond to the .pyc file.  If path does
456    not conform to PEP 3147/488 format, ValueError will be raised. If
457    sys.implementation.cache_tag is None then NotImplementedError is raised.
458
459    """
460    if sys.implementation.cache_tag is None:
461        raise NotImplementedError('sys.implementation.cache_tag is None')
462    path = _os.fspath(path)
463    head, pycache_filename = _path_split(path)
464    found_in_pycache_prefix = False
465    if sys.pycache_prefix is not None:
466        stripped_path = sys.pycache_prefix.rstrip(path_separators)
467        if head.startswith(stripped_path + path_sep):
468            head = head[len(stripped_path):]
469            found_in_pycache_prefix = True
470    if not found_in_pycache_prefix:
471        head, pycache = _path_split(head)
472        if pycache != _PYCACHE:
473            raise ValueError(f'{_PYCACHE} not bottom-level directory in '
474                             f'{path!r}')
475    dot_count = pycache_filename.count('.')
476    if dot_count not in {2, 3}:
477        raise ValueError(f'expected only 2 or 3 dots in {pycache_filename!r}')
478    elif dot_count == 3:
479        optimization = pycache_filename.rsplit('.', 2)[-2]
480        if not optimization.startswith(_OPT):
481            raise ValueError("optimization portion of filename does not start "
482                             f"with {_OPT!r}")
483        opt_level = optimization[len(_OPT):]
484        if not opt_level.isalnum():
485            raise ValueError(f"optimization level {optimization!r} is not an "
486                             "alphanumeric value")
487    base_filename = pycache_filename.partition('.')[0]
488    return _path_join(head, base_filename + SOURCE_SUFFIXES[0])
489
490
491def _get_sourcefile(bytecode_path):
492    """Convert a bytecode file path to a source path (if possible).
493
494    This function exists purely for backwards-compatibility for
495    PyImport_ExecCodeModuleWithFilenames() in the C API.
496
497    """
498    if len(bytecode_path) == 0:
499        return None
500    rest, _, extension = bytecode_path.rpartition('.')
501    if not rest or extension.lower()[-3:-1] != 'py':
502        return bytecode_path
503    try:
504        source_path = source_from_cache(bytecode_path)
505    except (NotImplementedError, ValueError):
506        source_path = bytecode_path[:-1]
507    return source_path if _path_isfile(source_path) else bytecode_path
508
509
510def _get_cached(filename):
511    if filename.endswith(tuple(SOURCE_SUFFIXES)):
512        try:
513            return cache_from_source(filename)
514        except NotImplementedError:
515            pass
516    elif filename.endswith(tuple(BYTECODE_SUFFIXES)):
517        return filename
518    else:
519        return None
520
521
522def _calc_mode(path):
523    """Calculate the mode permissions for a bytecode file."""
524    try:
525        mode = _path_stat(path).st_mode
526    except OSError:
527        mode = 0o666
528    # We always ensure write access so we can update cached files
529    # later even when the source files are read-only on Windows (#6074)
530    mode |= 0o200
531    return mode
532
533
534def _check_name(method):
535    """Decorator to verify that the module being requested matches the one the
536    loader can handle.
537
538    The first argument (self) must define _name which the second argument is
539    compared against. If the comparison fails then ImportError is raised.
540
541    """
542    def _check_name_wrapper(self, name=None, *args, **kwargs):
543        if name is None:
544            name = self.name
545        elif self.name != name:
546            raise ImportError('loader for %s cannot handle %s' %
547                                (self.name, name), name=name)
548        return method(self, name, *args, **kwargs)
549
550    # FIXME: @_check_name is used to define class methods before the
551    # _bootstrap module is set by _set_bootstrap_module().
552    if _bootstrap is not None:
553        _wrap = _bootstrap._wrap
554    else:
555        def _wrap(new, old):
556            for replace in ['__module__', '__name__', '__qualname__', '__doc__']:
557                if hasattr(old, replace):
558                    setattr(new, replace, getattr(old, replace))
559            new.__dict__.update(old.__dict__)
560
561    _wrap(_check_name_wrapper, method)
562    return _check_name_wrapper
563
564
565def _find_module_shim(self, fullname):
566    """Try to find a loader for the specified module by delegating to
567    self.find_loader().
568
569    This method is deprecated in favor of finder.find_spec().
570
571    """
572    _warnings.warn("find_module() is deprecated and "
573                   "slated for removal in Python 3.12; use find_spec() instead",
574                   DeprecationWarning)
575    # Call find_loader(). If it returns a string (indicating this
576    # is a namespace package portion), generate a warning and
577    # return None.
578    loader, portions = self.find_loader(fullname)
579    if loader is None and len(portions):
580        msg = 'Not importing directory {}: missing __init__'
581        _warnings.warn(msg.format(portions[0]), ImportWarning)
582    return loader
583
584
585def _classify_pyc(data, name, exc_details):
586    """Perform basic validity checking of a pyc header and return the flags field,
587    which determines how the pyc should be further validated against the source.
588
589    *data* is the contents of the pyc file. (Only the first 16 bytes are
590    required, though.)
591
592    *name* is the name of the module being imported. It is used for logging.
593
594    *exc_details* is a dictionary passed to ImportError if it raised for
595    improved debugging.
596
597    ImportError is raised when the magic number is incorrect or when the flags
598    field is invalid. EOFError is raised when the data is found to be truncated.
599
600    """
601    magic = data[:4]
602    if magic != MAGIC_NUMBER:
603        message = f'bad magic number in {name!r}: {magic!r}'
604        _bootstrap._verbose_message('{}', message)
605        raise ImportError(message, **exc_details)
606    if len(data) < 16:
607        message = f'reached EOF while reading pyc header of {name!r}'
608        _bootstrap._verbose_message('{}', message)
609        raise EOFError(message)
610    flags = _unpack_uint32(data[4:8])
611    # Only the first two flags are defined.
612    if flags & ~0b11:
613        message = f'invalid flags {flags!r} in {name!r}'
614        raise ImportError(message, **exc_details)
615    return flags
616
617
618def _validate_timestamp_pyc(data, source_mtime, source_size, name,
619                            exc_details):
620    """Validate a pyc against the source last-modified time.
621
622    *data* is the contents of the pyc file. (Only the first 16 bytes are
623    required.)
624
625    *source_mtime* is the last modified timestamp of the source file.
626
627    *source_size* is None or the size of the source file in bytes.
628
629    *name* is the name of the module being imported. It is used for logging.
630
631    *exc_details* is a dictionary passed to ImportError if it raised for
632    improved debugging.
633
634    An ImportError is raised if the bytecode is stale.
635
636    """
637    if _unpack_uint32(data[8:12]) != (source_mtime & 0xFFFFFFFF):
638        message = f'bytecode is stale for {name!r}'
639        _bootstrap._verbose_message('{}', message)
640        raise ImportError(message, **exc_details)
641    if (source_size is not None and
642        _unpack_uint32(data[12:16]) != (source_size & 0xFFFFFFFF)):
643        raise ImportError(f'bytecode is stale for {name!r}', **exc_details)
644
645
646def _validate_hash_pyc(data, source_hash, name, exc_details):
647    """Validate a hash-based pyc by checking the real source hash against the one in
648    the pyc header.
649
650    *data* is the contents of the pyc file. (Only the first 16 bytes are
651    required.)
652
653    *source_hash* is the importlib.util.source_hash() of the source file.
654
655    *name* is the name of the module being imported. It is used for logging.
656
657    *exc_details* is a dictionary passed to ImportError if it raised for
658    improved debugging.
659
660    An ImportError is raised if the bytecode is stale.
661
662    """
663    if data[8:16] != source_hash:
664        raise ImportError(
665            f'hash in bytecode doesn\'t match hash of source {name!r}',
666            **exc_details,
667        )
668
669
670def _compile_bytecode(data, name=None, bytecode_path=None, source_path=None):
671    """Compile bytecode as found in a pyc."""
672    code = marshal.loads(data)
673    if isinstance(code, _code_type):
674        _bootstrap._verbose_message('code object from {!r}', bytecode_path)
675        if source_path is not None:
676            _imp._fix_co_filename(code, source_path)
677        return code
678    else:
679        raise ImportError('Non-code object in {!r}'.format(bytecode_path),
680                          name=name, path=bytecode_path)
681
682
683def _code_to_timestamp_pyc(code, mtime=0, source_size=0):
684    "Produce the data for a timestamp-based pyc."
685    data = bytearray(MAGIC_NUMBER)
686    data.extend(_pack_uint32(0))
687    data.extend(_pack_uint32(mtime))
688    data.extend(_pack_uint32(source_size))
689    data.extend(marshal.dumps(code))
690    return data
691
692
693def _code_to_hash_pyc(code, source_hash, checked=True):
694    "Produce the data for a hash-based pyc."
695    data = bytearray(MAGIC_NUMBER)
696    flags = 0b1 | checked << 1
697    data.extend(_pack_uint32(flags))
698    assert len(source_hash) == 8
699    data.extend(source_hash)
700    data.extend(marshal.dumps(code))
701    return data
702
703
704def decode_source(source_bytes):
705    """Decode bytes representing source code and return the string.
706
707    Universal newline support is used in the decoding.
708    """
709    import tokenize  # To avoid bootstrap issues.
710    source_bytes_readline = _io.BytesIO(source_bytes).readline
711    encoding = tokenize.detect_encoding(source_bytes_readline)
712    newline_decoder = _io.IncrementalNewlineDecoder(None, True)
713    return newline_decoder.decode(source_bytes.decode(encoding[0]))
714
715
716# Module specifications #######################################################
717
718_POPULATE = object()
719
720
721def spec_from_file_location(name, location=None, *, loader=None,
722                            submodule_search_locations=_POPULATE):
723    """Return a module spec based on a file location.
724
725    To indicate that the module is a package, set
726    submodule_search_locations to a list of directory paths.  An
727    empty list is sufficient, though its not otherwise useful to the
728    import system.
729
730    The loader must take a spec as its only __init__() arg.
731
732    """
733    if location is None:
734        # The caller may simply want a partially populated location-
735        # oriented spec.  So we set the location to a bogus value and
736        # fill in as much as we can.
737        location = '<unknown>'
738        if hasattr(loader, 'get_filename'):
739            # ExecutionLoader
740            try:
741                location = loader.get_filename(name)
742            except ImportError:
743                pass
744    else:
745        location = _os.fspath(location)
746        if not _path_isabs(location):
747            try:
748                location = _path_join(_os.getcwd(), location)
749            except OSError:
750                pass
751
752    # If the location is on the filesystem, but doesn't actually exist,
753    # we could return None here, indicating that the location is not
754    # valid.  However, we don't have a good way of testing since an
755    # indirect location (e.g. a zip file or URL) will look like a
756    # non-existent file relative to the filesystem.
757
758    spec = _bootstrap.ModuleSpec(name, loader, origin=location)
759    spec._set_fileattr = True
760
761    # Pick a loader if one wasn't provided.
762    if loader is None:
763        for loader_class, suffixes in _get_supported_file_loaders():
764            if location.endswith(tuple(suffixes)):
765                loader = loader_class(name, location)
766                spec.loader = loader
767                break
768        else:
769            return None
770
771    # Set submodule_search_paths appropriately.
772    if submodule_search_locations is _POPULATE:
773        # Check the loader.
774        if hasattr(loader, 'is_package'):
775            try:
776                is_package = loader.is_package(name)
777            except ImportError:
778                pass
779            else:
780                if is_package:
781                    spec.submodule_search_locations = []
782    else:
783        spec.submodule_search_locations = submodule_search_locations
784    if spec.submodule_search_locations == []:
785        if location:
786            dirname = _path_split(location)[0]
787            spec.submodule_search_locations.append(dirname)
788
789    return spec
790
791
792# Loaders #####################################################################
793
794class WindowsRegistryFinder:
795
796    """Meta path finder for modules declared in the Windows registry."""
797
798    REGISTRY_KEY = (
799        'Software\\Python\\PythonCore\\{sys_version}'
800        '\\Modules\\{fullname}')
801    REGISTRY_KEY_DEBUG = (
802        'Software\\Python\\PythonCore\\{sys_version}'
803        '\\Modules\\{fullname}\\Debug')
804    DEBUG_BUILD = (_MS_WINDOWS and '_d.pyd' in EXTENSION_SUFFIXES)
805
806    @staticmethod
807    def _open_registry(key):
808        try:
809            return winreg.OpenKey(winreg.HKEY_CURRENT_USER, key)
810        except OSError:
811            return winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key)
812
813    @classmethod
814    def _search_registry(cls, fullname):
815        if cls.DEBUG_BUILD:
816            registry_key = cls.REGISTRY_KEY_DEBUG
817        else:
818            registry_key = cls.REGISTRY_KEY
819        key = registry_key.format(fullname=fullname,
820                                  sys_version='%d.%d' % sys.version_info[:2])
821        try:
822            with cls._open_registry(key) as hkey:
823                filepath = winreg.QueryValue(hkey, '')
824        except OSError:
825            return None
826        return filepath
827
828    @classmethod
829    def find_spec(cls, fullname, path=None, target=None):
830        filepath = cls._search_registry(fullname)
831        if filepath is None:
832            return None
833        try:
834            _path_stat(filepath)
835        except OSError:
836            return None
837        for loader, suffixes in _get_supported_file_loaders():
838            if filepath.endswith(tuple(suffixes)):
839                spec = _bootstrap.spec_from_loader(fullname,
840                                                   loader(fullname, filepath),
841                                                   origin=filepath)
842                return spec
843
844    @classmethod
845    def find_module(cls, fullname, path=None):
846        """Find module named in the registry.
847
848        This method is deprecated.  Use find_spec() instead.
849
850        """
851        _warnings.warn("WindowsRegistryFinder.find_module() is deprecated and "
852                       "slated for removal in Python 3.12; use find_spec() instead",
853                       DeprecationWarning)
854        spec = cls.find_spec(fullname, path)
855        if spec is not None:
856            return spec.loader
857        else:
858            return None
859
860
861class _LoaderBasics:
862
863    """Base class of common code needed by both SourceLoader and
864    SourcelessFileLoader."""
865
866    def is_package(self, fullname):
867        """Concrete implementation of InspectLoader.is_package by checking if
868        the path returned by get_filename has a filename of '__init__.py'."""
869        filename = _path_split(self.get_filename(fullname))[1]
870        filename_base = filename.rsplit('.', 1)[0]
871        tail_name = fullname.rpartition('.')[2]
872        return filename_base == '__init__' and tail_name != '__init__'
873
874    def create_module(self, spec):
875        """Use default semantics for module creation."""
876
877    def exec_module(self, module):
878        """Execute the module."""
879        code = self.get_code(module.__name__)
880        if code is None:
881            raise ImportError('cannot load module {!r} when get_code() '
882                              'returns None'.format(module.__name__))
883        _bootstrap._call_with_frames_removed(exec, code, module.__dict__)
884
885    def load_module(self, fullname):
886        """This method is deprecated."""
887        # Warning implemented in _load_module_shim().
888        return _bootstrap._load_module_shim(self, fullname)
889
890
891class SourceLoader(_LoaderBasics):
892
893    def path_mtime(self, path):
894        """Optional method that returns the modification time (an int) for the
895        specified path (a str).
896
897        Raises OSError when the path cannot be handled.
898        """
899        raise OSError
900
901    def path_stats(self, path):
902        """Optional method returning a metadata dict for the specified
903        path (a str).
904
905        Possible keys:
906        - 'mtime' (mandatory) is the numeric timestamp of last source
907          code modification;
908        - 'size' (optional) is the size in bytes of the source code.
909
910        Implementing this method allows the loader to read bytecode files.
911        Raises OSError when the path cannot be handled.
912        """
913        return {'mtime': self.path_mtime(path)}
914
915    def _cache_bytecode(self, source_path, cache_path, data):
916        """Optional method which writes data (bytes) to a file path (a str).
917
918        Implementing this method allows for the writing of bytecode files.
919
920        The source path is needed in order to correctly transfer permissions
921        """
922        # For backwards compatibility, we delegate to set_data()
923        return self.set_data(cache_path, data)
924
925    def set_data(self, path, data):
926        """Optional method which writes data (bytes) to a file path (a str).
927
928        Implementing this method allows for the writing of bytecode files.
929        """
930
931
932    def get_source(self, fullname):
933        """Concrete implementation of InspectLoader.get_source."""
934        path = self.get_filename(fullname)
935        try:
936            source_bytes = self.get_data(path)
937        except OSError as exc:
938            raise ImportError('source not available through get_data()',
939                              name=fullname) from exc
940        return decode_source(source_bytes)
941
942    def source_to_code(self, data, path, *, _optimize=-1):
943        """Return the code object compiled from source.
944
945        The 'data' argument can be any object type that compile() supports.
946        """
947        return _bootstrap._call_with_frames_removed(compile, data, path, 'exec',
948                                        dont_inherit=True, optimize=_optimize)
949
950    def get_code(self, fullname):
951        """Concrete implementation of InspectLoader.get_code.
952
953        Reading of bytecode requires path_stats to be implemented. To write
954        bytecode, set_data must also be implemented.
955
956        """
957        source_path = self.get_filename(fullname)
958        source_mtime = None
959        source_bytes = None
960        source_hash = None
961        hash_based = False
962        check_source = True
963        try:
964            bytecode_path = cache_from_source(source_path)
965        except NotImplementedError:
966            bytecode_path = None
967        else:
968            try:
969                st = self.path_stats(source_path)
970            except OSError:
971                pass
972            else:
973                source_mtime = int(st['mtime'])
974                try:
975                    data = self.get_data(bytecode_path)
976                except OSError:
977                    pass
978                else:
979                    exc_details = {
980                        'name': fullname,
981                        'path': bytecode_path,
982                    }
983                    try:
984                        flags = _classify_pyc(data, fullname, exc_details)
985                        bytes_data = memoryview(data)[16:]
986                        hash_based = flags & 0b1 != 0
987                        if hash_based:
988                            check_source = flags & 0b10 != 0
989                            if (_imp.check_hash_based_pycs != 'never' and
990                                (check_source or
991                                 _imp.check_hash_based_pycs == 'always')):
992                                source_bytes = self.get_data(source_path)
993                                source_hash = _imp.source_hash(
994                                    _RAW_MAGIC_NUMBER,
995                                    source_bytes,
996                                )
997                                _validate_hash_pyc(data, source_hash, fullname,
998                                                   exc_details)
999                        else:
1000                            _validate_timestamp_pyc(
1001                                data,
1002                                source_mtime,
1003                                st['size'],
1004                                fullname,
1005                                exc_details,
1006                            )
1007                    except (ImportError, EOFError):
1008                        pass
1009                    else:
1010                        _bootstrap._verbose_message('{} matches {}', bytecode_path,
1011                                                    source_path)
1012                        return _compile_bytecode(bytes_data, name=fullname,
1013                                                 bytecode_path=bytecode_path,
1014                                                 source_path=source_path)
1015        if source_bytes is None:
1016            source_bytes = self.get_data(source_path)
1017        code_object = self.source_to_code(source_bytes, source_path)
1018        _bootstrap._verbose_message('code object from {}', source_path)
1019        if (not sys.dont_write_bytecode and bytecode_path is not None and
1020                source_mtime is not None):
1021            if hash_based:
1022                if source_hash is None:
1023                    source_hash = _imp.source_hash(source_bytes)
1024                data = _code_to_hash_pyc(code_object, source_hash, check_source)
1025            else:
1026                data = _code_to_timestamp_pyc(code_object, source_mtime,
1027                                              len(source_bytes))
1028            try:
1029                self._cache_bytecode(source_path, bytecode_path, data)
1030            except NotImplementedError:
1031                pass
1032        return code_object
1033
1034
1035class FileLoader:
1036
1037    """Base file loader class which implements the loader protocol methods that
1038    require file system usage."""
1039
1040    def __init__(self, fullname, path):
1041        """Cache the module name and the path to the file found by the
1042        finder."""
1043        self.name = fullname
1044        self.path = path
1045
1046    def __eq__(self, other):
1047        return (self.__class__ == other.__class__ and
1048                self.__dict__ == other.__dict__)
1049
1050    def __hash__(self):
1051        return hash(self.name) ^ hash(self.path)
1052
1053    @_check_name
1054    def load_module(self, fullname):
1055        """Load a module from a file.
1056
1057        This method is deprecated.  Use exec_module() instead.
1058
1059        """
1060        # The only reason for this method is for the name check.
1061        # Issue #14857: Avoid the zero-argument form of super so the implementation
1062        # of that form can be updated without breaking the frozen module.
1063        return super(FileLoader, self).load_module(fullname)
1064
1065    @_check_name
1066    def get_filename(self, fullname):
1067        """Return the path to the source file as found by the finder."""
1068        return self.path
1069
1070    def get_data(self, path):
1071        """Return the data from path as raw bytes."""
1072        if isinstance(self, (SourceLoader, ExtensionFileLoader)):
1073            with _io.open_code(str(path)) as file:
1074                return file.read()
1075        else:
1076            with _io.FileIO(path, 'r') as file:
1077                return file.read()
1078
1079    @_check_name
1080    def get_resource_reader(self, module):
1081        from importlib.readers import FileReader
1082        return FileReader(self)
1083
1084
1085class SourceFileLoader(FileLoader, SourceLoader):
1086
1087    """Concrete implementation of SourceLoader using the file system."""
1088
1089    def path_stats(self, path):
1090        """Return the metadata for the path."""
1091        st = _path_stat(path)
1092        return {'mtime': st.st_mtime, 'size': st.st_size}
1093
1094    def _cache_bytecode(self, source_path, bytecode_path, data):
1095        # Adapt between the two APIs
1096        mode = _calc_mode(source_path)
1097        return self.set_data(bytecode_path, data, _mode=mode)
1098
1099    def set_data(self, path, data, *, _mode=0o666):
1100        """Write bytes data to a file."""
1101        parent, filename = _path_split(path)
1102        path_parts = []
1103        # Figure out what directories are missing.
1104        while parent and not _path_isdir(parent):
1105            parent, part = _path_split(parent)
1106            path_parts.append(part)
1107        # Create needed directories.
1108        for part in reversed(path_parts):
1109            parent = _path_join(parent, part)
1110            try:
1111                _os.mkdir(parent)
1112            except FileExistsError:
1113                # Probably another Python process already created the dir.
1114                continue
1115            except OSError as exc:
1116                # Could be a permission error, read-only filesystem: just forget
1117                # about writing the data.
1118                _bootstrap._verbose_message('could not create {!r}: {!r}',
1119                                            parent, exc)
1120                return
1121        try:
1122            _write_atomic(path, data, _mode)
1123            _bootstrap._verbose_message('created {!r}', path)
1124        except OSError as exc:
1125            # Same as above: just don't write the bytecode.
1126            _bootstrap._verbose_message('could not create {!r}: {!r}', path,
1127                                        exc)
1128
1129
1130class SourcelessFileLoader(FileLoader, _LoaderBasics):
1131
1132    """Loader which handles sourceless file imports."""
1133
1134    def get_code(self, fullname):
1135        path = self.get_filename(fullname)
1136        data = self.get_data(path)
1137        # Call _classify_pyc to do basic validation of the pyc but ignore the
1138        # result. There's no source to check against.
1139        exc_details = {
1140            'name': fullname,
1141            'path': path,
1142        }
1143        _classify_pyc(data, fullname, exc_details)
1144        return _compile_bytecode(
1145            memoryview(data)[16:],
1146            name=fullname,
1147            bytecode_path=path,
1148        )
1149
1150    def get_source(self, fullname):
1151        """Return None as there is no source code."""
1152        return None
1153
1154
1155class ExtensionFileLoader(FileLoader, _LoaderBasics):
1156
1157    """Loader for extension modules.
1158
1159    The constructor is designed to work with FileFinder.
1160
1161    """
1162
1163    def __init__(self, name, path):
1164        self.name = name
1165        self.path = path
1166
1167    def __eq__(self, other):
1168        return (self.__class__ == other.__class__ and
1169                self.__dict__ == other.__dict__)
1170
1171    def __hash__(self):
1172        return hash(self.name) ^ hash(self.path)
1173
1174    def create_module(self, spec):
1175        """Create an unitialized extension module"""
1176        module = _bootstrap._call_with_frames_removed(
1177            _imp.create_dynamic, spec)
1178        _bootstrap._verbose_message('extension module {!r} loaded from {!r}',
1179                         spec.name, self.path)
1180        return module
1181
1182    def exec_module(self, module):
1183        """Initialize an extension module"""
1184        _bootstrap._call_with_frames_removed(_imp.exec_dynamic, module)
1185        _bootstrap._verbose_message('extension module {!r} executed from {!r}',
1186                         self.name, self.path)
1187
1188    def is_package(self, fullname):
1189        """Return True if the extension module is a package."""
1190        file_name = _path_split(self.path)[1]
1191        return any(file_name == '__init__' + suffix
1192                   for suffix in EXTENSION_SUFFIXES)
1193
1194    def get_code(self, fullname):
1195        """Return None as an extension module cannot create a code object."""
1196        return None
1197
1198    def get_source(self, fullname):
1199        """Return None as extension modules have no source code."""
1200        return None
1201
1202    @_check_name
1203    def get_filename(self, fullname):
1204        """Return the path to the source file as found by the finder."""
1205        return self.path
1206
1207
1208class _NamespacePath:
1209    """Represents a namespace package's path.  It uses the module name
1210    to find its parent module, and from there it looks up the parent's
1211    __path__.  When this changes, the module's own path is recomputed,
1212    using path_finder.  For top-level modules, the parent module's path
1213    is sys.path."""
1214
1215    # When invalidate_caches() is called, this epoch is incremented
1216    # https://bugs.python.org/issue45703
1217    _epoch = 0
1218
1219    def __init__(self, name, path, path_finder):
1220        self._name = name
1221        self._path = path
1222        self._last_parent_path = tuple(self._get_parent_path())
1223        self._last_epoch = self._epoch
1224        self._path_finder = path_finder
1225
1226    def _find_parent_path_names(self):
1227        """Returns a tuple of (parent-module-name, parent-path-attr-name)"""
1228        parent, dot, me = self._name.rpartition('.')
1229        if dot == '':
1230            # This is a top-level module. sys.path contains the parent path.
1231            return 'sys', 'path'
1232        # Not a top-level module. parent-module.__path__ contains the
1233        #  parent path.
1234        return parent, '__path__'
1235
1236    def _get_parent_path(self):
1237        parent_module_name, path_attr_name = self._find_parent_path_names()
1238        return getattr(sys.modules[parent_module_name], path_attr_name)
1239
1240    def _recalculate(self):
1241        # If the parent's path has changed, recalculate _path
1242        parent_path = tuple(self._get_parent_path()) # Make a copy
1243        if parent_path != self._last_parent_path or self._epoch != self._last_epoch:
1244            spec = self._path_finder(self._name, parent_path)
1245            # Note that no changes are made if a loader is returned, but we
1246            #  do remember the new parent path
1247            if spec is not None and spec.loader is None:
1248                if spec.submodule_search_locations:
1249                    self._path = spec.submodule_search_locations
1250            self._last_parent_path = parent_path     # Save the copy
1251            self._last_epoch = self._epoch
1252        return self._path
1253
1254    def __iter__(self):
1255        return iter(self._recalculate())
1256
1257    def __getitem__(self, index):
1258        return self._recalculate()[index]
1259
1260    def __setitem__(self, index, path):
1261        self._path[index] = path
1262
1263    def __len__(self):
1264        return len(self._recalculate())
1265
1266    def __repr__(self):
1267        return '_NamespacePath({!r})'.format(self._path)
1268
1269    def __contains__(self, item):
1270        return item in self._recalculate()
1271
1272    def append(self, item):
1273        self._path.append(item)
1274
1275
1276# We use this exclusively in module_from_spec() for backward-compatibility.
1277class _NamespaceLoader:
1278    def __init__(self, name, path, path_finder):
1279        self._path = _NamespacePath(name, path, path_finder)
1280
1281    @staticmethod
1282    def module_repr(module):
1283        """Return repr for the module.
1284
1285        The method is deprecated.  The import machinery does the job itself.
1286
1287        """
1288        _warnings.warn("_NamespaceLoader.module_repr() is deprecated and "
1289                       "slated for removal in Python 3.12", DeprecationWarning)
1290        return '<module {!r} (namespace)>'.format(module.__name__)
1291
1292    def is_package(self, fullname):
1293        return True
1294
1295    def get_source(self, fullname):
1296        return ''
1297
1298    def get_code(self, fullname):
1299        return compile('', '<string>', 'exec', dont_inherit=True)
1300
1301    def create_module(self, spec):
1302        """Use default semantics for module creation."""
1303
1304    def exec_module(self, module):
1305        pass
1306
1307    def load_module(self, fullname):
1308        """Load a namespace module.
1309
1310        This method is deprecated.  Use exec_module() instead.
1311
1312        """
1313        # The import system never calls this method.
1314        _bootstrap._verbose_message('namespace module loaded with path {!r}',
1315                                    self._path)
1316        # Warning implemented in _load_module_shim().
1317        return _bootstrap._load_module_shim(self, fullname)
1318
1319    def get_resource_reader(self, module):
1320        from importlib.readers import NamespaceReader
1321        return NamespaceReader(self._path)
1322
1323
1324# Finders #####################################################################
1325
1326class PathFinder:
1327
1328    """Meta path finder for sys.path and package __path__ attributes."""
1329
1330    @staticmethod
1331    def invalidate_caches():
1332        """Call the invalidate_caches() method on all path entry finders
1333        stored in sys.path_importer_caches (where implemented)."""
1334        for name, finder in list(sys.path_importer_cache.items()):
1335            if finder is None:
1336                del sys.path_importer_cache[name]
1337            elif hasattr(finder, 'invalidate_caches'):
1338                finder.invalidate_caches()
1339        # Also invalidate the caches of _NamespacePaths
1340        # https://bugs.python.org/issue45703
1341        _NamespacePath._epoch += 1
1342
1343    @staticmethod
1344    def _path_hooks(path):
1345        """Search sys.path_hooks for a finder for 'path'."""
1346        if sys.path_hooks is not None and not sys.path_hooks:
1347            _warnings.warn('sys.path_hooks is empty', ImportWarning)
1348        for hook in sys.path_hooks:
1349            try:
1350                return hook(path)
1351            except ImportError:
1352                continue
1353        else:
1354            return None
1355
1356    @classmethod
1357    def _path_importer_cache(cls, path):
1358        """Get the finder for the path entry from sys.path_importer_cache.
1359
1360        If the path entry is not in the cache, find the appropriate finder
1361        and cache it. If no finder is available, store None.
1362
1363        """
1364        if path == '':
1365            try:
1366                path = _os.getcwd()
1367            except FileNotFoundError:
1368                # Don't cache the failure as the cwd can easily change to
1369                # a valid directory later on.
1370                return None
1371        try:
1372            finder = sys.path_importer_cache[path]
1373        except KeyError:
1374            finder = cls._path_hooks(path)
1375            sys.path_importer_cache[path] = finder
1376        return finder
1377
1378    @classmethod
1379    def _legacy_get_spec(cls, fullname, finder):
1380        # This would be a good place for a DeprecationWarning if
1381        # we ended up going that route.
1382        if hasattr(finder, 'find_loader'):
1383            msg = (f"{_bootstrap._object_name(finder)}.find_spec() not found; "
1384                    "falling back to find_loader()")
1385            _warnings.warn(msg, ImportWarning)
1386            loader, portions = finder.find_loader(fullname)
1387        else:
1388            msg = (f"{_bootstrap._object_name(finder)}.find_spec() not found; "
1389                    "falling back to find_module()")
1390            _warnings.warn(msg, ImportWarning)
1391            loader = finder.find_module(fullname)
1392            portions = []
1393        if loader is not None:
1394            return _bootstrap.spec_from_loader(fullname, loader)
1395        spec = _bootstrap.ModuleSpec(fullname, None)
1396        spec.submodule_search_locations = portions
1397        return spec
1398
1399    @classmethod
1400    def _get_spec(cls, fullname, path, target=None):
1401        """Find the loader or namespace_path for this module/package name."""
1402        # If this ends up being a namespace package, namespace_path is
1403        #  the list of paths that will become its __path__
1404        namespace_path = []
1405        for entry in path:
1406            if not isinstance(entry, (str, bytes)):
1407                continue
1408            finder = cls._path_importer_cache(entry)
1409            if finder is not None:
1410                if hasattr(finder, 'find_spec'):
1411                    spec = finder.find_spec(fullname, target)
1412                else:
1413                    spec = cls._legacy_get_spec(fullname, finder)
1414                if spec is None:
1415                    continue
1416                if spec.loader is not None:
1417                    return spec
1418                portions = spec.submodule_search_locations
1419                if portions is None:
1420                    raise ImportError('spec missing loader')
1421                # This is possibly part of a namespace package.
1422                #  Remember these path entries (if any) for when we
1423                #  create a namespace package, and continue iterating
1424                #  on path.
1425                namespace_path.extend(portions)
1426        else:
1427            spec = _bootstrap.ModuleSpec(fullname, None)
1428            spec.submodule_search_locations = namespace_path
1429            return spec
1430
1431    @classmethod
1432    def find_spec(cls, fullname, path=None, target=None):
1433        """Try to find a spec for 'fullname' on sys.path or 'path'.
1434
1435        The search is based on sys.path_hooks and sys.path_importer_cache.
1436        """
1437        if path is None:
1438            path = sys.path
1439        spec = cls._get_spec(fullname, path, target)
1440        if spec is None:
1441            return None
1442        elif spec.loader is None:
1443            namespace_path = spec.submodule_search_locations
1444            if namespace_path:
1445                # We found at least one namespace path.  Return a spec which
1446                # can create the namespace package.
1447                spec.origin = None
1448                spec.submodule_search_locations = _NamespacePath(fullname, namespace_path, cls._get_spec)
1449                return spec
1450            else:
1451                return None
1452        else:
1453            return spec
1454
1455    @classmethod
1456    def find_module(cls, fullname, path=None):
1457        """find the module on sys.path or 'path' based on sys.path_hooks and
1458        sys.path_importer_cache.
1459
1460        This method is deprecated.  Use find_spec() instead.
1461
1462        """
1463        _warnings.warn("PathFinder.find_module() is deprecated and "
1464                       "slated for removal in Python 3.12; use find_spec() instead",
1465                       DeprecationWarning)
1466        spec = cls.find_spec(fullname, path)
1467        if spec is None:
1468            return None
1469        return spec.loader
1470
1471    @staticmethod
1472    def find_distributions(*args, **kwargs):
1473        """
1474        Find distributions.
1475
1476        Return an iterable of all Distribution instances capable of
1477        loading the metadata for packages matching ``context.name``
1478        (or all names if ``None`` indicated) along the paths in the list
1479        of directories ``context.path``.
1480        """
1481        from importlib.metadata import MetadataPathFinder
1482        return MetadataPathFinder.find_distributions(*args, **kwargs)
1483
1484
1485class FileFinder:
1486
1487    """File-based finder.
1488
1489    Interactions with the file system are cached for performance, being
1490    refreshed when the directory the finder is handling has been modified.
1491
1492    """
1493
1494    def __init__(self, path, *loader_details):
1495        """Initialize with the path to search on and a variable number of
1496        2-tuples containing the loader and the file suffixes the loader
1497        recognizes."""
1498        loaders = []
1499        for loader, suffixes in loader_details:
1500            loaders.extend((suffix, loader) for suffix in suffixes)
1501        self._loaders = loaders
1502        # Base (directory) path
1503        self.path = path or '.'
1504        if not _path_isabs(self.path):
1505            self.path = _path_join(_os.getcwd(), self.path)
1506        self._path_mtime = -1
1507        self._path_cache = set()
1508        self._relaxed_path_cache = set()
1509
1510    def invalidate_caches(self):
1511        """Invalidate the directory mtime."""
1512        self._path_mtime = -1
1513
1514    find_module = _find_module_shim
1515
1516    def find_loader(self, fullname):
1517        """Try to find a loader for the specified module, or the namespace
1518        package portions. Returns (loader, list-of-portions).
1519
1520        This method is deprecated.  Use find_spec() instead.
1521
1522        """
1523        _warnings.warn("FileFinder.find_loader() is deprecated and "
1524                       "slated for removal in Python 3.12; use find_spec() instead",
1525                       DeprecationWarning)
1526        spec = self.find_spec(fullname)
1527        if spec is None:
1528            return None, []
1529        return spec.loader, spec.submodule_search_locations or []
1530
1531    def _get_spec(self, loader_class, fullname, path, smsl, target):
1532        loader = loader_class(fullname, path)
1533        return spec_from_file_location(fullname, path, loader=loader,
1534                                       submodule_search_locations=smsl)
1535
1536    def find_spec(self, fullname, target=None):
1537        """Try to find a spec for the specified module.
1538
1539        Returns the matching spec, or None if not found.
1540        """
1541        is_namespace = False
1542        tail_module = fullname.rpartition('.')[2]
1543        try:
1544            mtime = _path_stat(self.path or _os.getcwd()).st_mtime
1545        except OSError:
1546            mtime = -1
1547        if mtime != self._path_mtime:
1548            self._fill_cache()
1549            self._path_mtime = mtime
1550        # tail_module keeps the original casing, for __file__ and friends
1551        if _relax_case():
1552            cache = self._relaxed_path_cache
1553            cache_module = tail_module.lower()
1554        else:
1555            cache = self._path_cache
1556            cache_module = tail_module
1557        # Check if the module is the name of a directory (and thus a package).
1558        if cache_module in cache:
1559            base_path = _path_join(self.path, tail_module)
1560            for suffix, loader_class in self._loaders:
1561                init_filename = '__init__' + suffix
1562                full_path = _path_join(base_path, init_filename)
1563                if _path_isfile(full_path):
1564                    return self._get_spec(loader_class, fullname, full_path, [base_path], target)
1565            else:
1566                # If a namespace package, return the path if we don't
1567                #  find a module in the next section.
1568                is_namespace = _path_isdir(base_path)
1569        # Check for a file w/ a proper suffix exists.
1570        for suffix, loader_class in self._loaders:
1571            try:
1572                full_path = _path_join(self.path, tail_module + suffix)
1573            except ValueError:
1574                return None
1575            _bootstrap._verbose_message('trying {}', full_path, verbosity=2)
1576            if cache_module + suffix in cache:
1577                if _path_isfile(full_path):
1578                    return self._get_spec(loader_class, fullname, full_path,
1579                                          None, target)
1580        if is_namespace:
1581            _bootstrap._verbose_message('possible namespace for {}', base_path)
1582            spec = _bootstrap.ModuleSpec(fullname, None)
1583            spec.submodule_search_locations = [base_path]
1584            return spec
1585        return None
1586
1587    def _fill_cache(self):
1588        """Fill the cache of potential modules and packages for this directory."""
1589        path = self.path
1590        try:
1591            contents = _os.listdir(path or _os.getcwd())
1592        except (FileNotFoundError, PermissionError, NotADirectoryError):
1593            # Directory has either been removed, turned into a file, or made
1594            # unreadable.
1595            contents = []
1596        # We store two cached versions, to handle runtime changes of the
1597        # PYTHONCASEOK environment variable.
1598        if not sys.platform.startswith('win'):
1599            self._path_cache = set(contents)
1600        else:
1601            # Windows users can import modules with case-insensitive file
1602            # suffixes (for legacy reasons). Make the suffix lowercase here
1603            # so it's done once instead of for every import. This is safe as
1604            # the specified suffixes to check against are always specified in a
1605            # case-sensitive manner.
1606            lower_suffix_contents = set()
1607            for item in contents:
1608                name, dot, suffix = item.partition('.')
1609                if dot:
1610                    new_name = '{}.{}'.format(name, suffix.lower())
1611                else:
1612                    new_name = name
1613                lower_suffix_contents.add(new_name)
1614            self._path_cache = lower_suffix_contents
1615        if sys.platform.startswith(_CASE_INSENSITIVE_PLATFORMS):
1616            self._relaxed_path_cache = {fn.lower() for fn in contents}
1617
1618    @classmethod
1619    def path_hook(cls, *loader_details):
1620        """A class method which returns a closure to use on sys.path_hook
1621        which will return an instance using the specified loaders and the path
1622        called on the closure.
1623
1624        If the path called on the closure is not a directory, ImportError is
1625        raised.
1626
1627        """
1628        def path_hook_for_FileFinder(path):
1629            """Path hook for importlib.machinery.FileFinder."""
1630            if not _path_isdir(path):
1631                raise ImportError('only directories are supported', path=path)
1632            return cls(path, *loader_details)
1633
1634        return path_hook_for_FileFinder
1635
1636    def __repr__(self):
1637        return 'FileFinder({!r})'.format(self.path)
1638
1639
1640# Import setup ###############################################################
1641
1642def _fix_up_module(ns, name, pathname, cpathname=None):
1643    # This function is used by PyImport_ExecCodeModuleObject().
1644    loader = ns.get('__loader__')
1645    spec = ns.get('__spec__')
1646    if not loader:
1647        if spec:
1648            loader = spec.loader
1649        elif pathname == cpathname:
1650            loader = SourcelessFileLoader(name, pathname)
1651        else:
1652            loader = SourceFileLoader(name, pathname)
1653    if not spec:
1654        spec = spec_from_file_location(name, pathname, loader=loader)
1655    try:
1656        ns['__spec__'] = spec
1657        ns['__loader__'] = loader
1658        ns['__file__'] = pathname
1659        ns['__cached__'] = cpathname
1660    except Exception:
1661        # Not important enough to report.
1662        pass
1663
1664
1665def _get_supported_file_loaders():
1666    """Returns a list of file-based module loaders.
1667
1668    Each item is a tuple (loader, suffixes).
1669    """
1670    extensions = ExtensionFileLoader, _imp.extension_suffixes()
1671    source = SourceFileLoader, SOURCE_SUFFIXES
1672    bytecode = SourcelessFileLoader, BYTECODE_SUFFIXES
1673    return [extensions, source, bytecode]
1674
1675
1676def _set_bootstrap_module(_bootstrap_module):
1677    global _bootstrap
1678    _bootstrap = _bootstrap_module
1679
1680
1681def _install(_bootstrap_module):
1682    """Install the path-based import components."""
1683    _set_bootstrap_module(_bootstrap_module)
1684    supported_loaders = _get_supported_file_loaders()
1685    sys.path_hooks.extend([FileFinder.path_hook(*supported_loaders)])
1686    sys.meta_path.append(PathFinder)
1687