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    def __init__(self, name, path, path_finder):
1216        self._name = name
1217        self._path = path
1218        self._last_parent_path = tuple(self._get_parent_path())
1219        self._path_finder = path_finder
1220
1221    def _find_parent_path_names(self):
1222        """Returns a tuple of (parent-module-name, parent-path-attr-name)"""
1223        parent, dot, me = self._name.rpartition('.')
1224        if dot == '':
1225            # This is a top-level module. sys.path contains the parent path.
1226            return 'sys', 'path'
1227        # Not a top-level module. parent-module.__path__ contains the
1228        #  parent path.
1229        return parent, '__path__'
1230
1231    def _get_parent_path(self):
1232        parent_module_name, path_attr_name = self._find_parent_path_names()
1233        return getattr(sys.modules[parent_module_name], path_attr_name)
1234
1235    def _recalculate(self):
1236        # If the parent's path has changed, recalculate _path
1237        parent_path = tuple(self._get_parent_path()) # Make a copy
1238        if parent_path != self._last_parent_path:
1239            spec = self._path_finder(self._name, parent_path)
1240            # Note that no changes are made if a loader is returned, but we
1241            #  do remember the new parent path
1242            if spec is not None and spec.loader is None:
1243                if spec.submodule_search_locations:
1244                    self._path = spec.submodule_search_locations
1245            self._last_parent_path = parent_path     # Save the copy
1246        return self._path
1247
1248    def __iter__(self):
1249        return iter(self._recalculate())
1250
1251    def __getitem__(self, index):
1252        return self._recalculate()[index]
1253
1254    def __setitem__(self, index, path):
1255        self._path[index] = path
1256
1257    def __len__(self):
1258        return len(self._recalculate())
1259
1260    def __repr__(self):
1261        return '_NamespacePath({!r})'.format(self._path)
1262
1263    def __contains__(self, item):
1264        return item in self._recalculate()
1265
1266    def append(self, item):
1267        self._path.append(item)
1268
1269
1270# We use this exclusively in module_from_spec() for backward-compatibility.
1271class _NamespaceLoader:
1272    def __init__(self, name, path, path_finder):
1273        self._path = _NamespacePath(name, path, path_finder)
1274
1275    @staticmethod
1276    def module_repr(module):
1277        """Return repr for the module.
1278
1279        The method is deprecated.  The import machinery does the job itself.
1280
1281        """
1282        _warnings.warn("_NamespaceLoader.module_repr() is deprecated and "
1283                       "slated for removal in Python 3.12", DeprecationWarning)
1284        return '<module {!r} (namespace)>'.format(module.__name__)
1285
1286    def is_package(self, fullname):
1287        return True
1288
1289    def get_source(self, fullname):
1290        return ''
1291
1292    def get_code(self, fullname):
1293        return compile('', '<string>', 'exec', dont_inherit=True)
1294
1295    def create_module(self, spec):
1296        """Use default semantics for module creation."""
1297
1298    def exec_module(self, module):
1299        pass
1300
1301    def load_module(self, fullname):
1302        """Load a namespace module.
1303
1304        This method is deprecated.  Use exec_module() instead.
1305
1306        """
1307        # The import system never calls this method.
1308        _bootstrap._verbose_message('namespace module loaded with path {!r}',
1309                                    self._path)
1310        # Warning implemented in _load_module_shim().
1311        return _bootstrap._load_module_shim(self, fullname)
1312
1313    def get_resource_reader(self, module):
1314        from importlib.readers import NamespaceReader
1315        return NamespaceReader(self._path)
1316
1317
1318# Finders #####################################################################
1319
1320class PathFinder:
1321
1322    """Meta path finder for sys.path and package __path__ attributes."""
1323
1324    @staticmethod
1325    def invalidate_caches():
1326        """Call the invalidate_caches() method on all path entry finders
1327        stored in sys.path_importer_caches (where implemented)."""
1328        for name, finder in list(sys.path_importer_cache.items()):
1329            if finder is None:
1330                del sys.path_importer_cache[name]
1331            elif hasattr(finder, 'invalidate_caches'):
1332                finder.invalidate_caches()
1333
1334    @staticmethod
1335    def _path_hooks(path):
1336        """Search sys.path_hooks for a finder for 'path'."""
1337        if sys.path_hooks is not None and not sys.path_hooks:
1338            _warnings.warn('sys.path_hooks is empty', ImportWarning)
1339        for hook in sys.path_hooks:
1340            try:
1341                return hook(path)
1342            except ImportError:
1343                continue
1344        else:
1345            return None
1346
1347    @classmethod
1348    def _path_importer_cache(cls, path):
1349        """Get the finder for the path entry from sys.path_importer_cache.
1350
1351        If the path entry is not in the cache, find the appropriate finder
1352        and cache it. If no finder is available, store None.
1353
1354        """
1355        if path == '':
1356            try:
1357                path = _os.getcwd()
1358            except FileNotFoundError:
1359                # Don't cache the failure as the cwd can easily change to
1360                # a valid directory later on.
1361                return None
1362        try:
1363            finder = sys.path_importer_cache[path]
1364        except KeyError:
1365            finder = cls._path_hooks(path)
1366            sys.path_importer_cache[path] = finder
1367        return finder
1368
1369    @classmethod
1370    def _legacy_get_spec(cls, fullname, finder):
1371        # This would be a good place for a DeprecationWarning if
1372        # we ended up going that route.
1373        if hasattr(finder, 'find_loader'):
1374            msg = (f"{_bootstrap._object_name(finder)}.find_spec() not found; "
1375                    "falling back to find_loader()")
1376            _warnings.warn(msg, ImportWarning)
1377            loader, portions = finder.find_loader(fullname)
1378        else:
1379            msg = (f"{_bootstrap._object_name(finder)}.find_spec() not found; "
1380                    "falling back to find_module()")
1381            _warnings.warn(msg, ImportWarning)
1382            loader = finder.find_module(fullname)
1383            portions = []
1384        if loader is not None:
1385            return _bootstrap.spec_from_loader(fullname, loader)
1386        spec = _bootstrap.ModuleSpec(fullname, None)
1387        spec.submodule_search_locations = portions
1388        return spec
1389
1390    @classmethod
1391    def _get_spec(cls, fullname, path, target=None):
1392        """Find the loader or namespace_path for this module/package name."""
1393        # If this ends up being a namespace package, namespace_path is
1394        #  the list of paths that will become its __path__
1395        namespace_path = []
1396        for entry in path:
1397            if not isinstance(entry, (str, bytes)):
1398                continue
1399            finder = cls._path_importer_cache(entry)
1400            if finder is not None:
1401                if hasattr(finder, 'find_spec'):
1402                    spec = finder.find_spec(fullname, target)
1403                else:
1404                    spec = cls._legacy_get_spec(fullname, finder)
1405                if spec is None:
1406                    continue
1407                if spec.loader is not None:
1408                    return spec
1409                portions = spec.submodule_search_locations
1410                if portions is None:
1411                    raise ImportError('spec missing loader')
1412                # This is possibly part of a namespace package.
1413                #  Remember these path entries (if any) for when we
1414                #  create a namespace package, and continue iterating
1415                #  on path.
1416                namespace_path.extend(portions)
1417        else:
1418            spec = _bootstrap.ModuleSpec(fullname, None)
1419            spec.submodule_search_locations = namespace_path
1420            return spec
1421
1422    @classmethod
1423    def find_spec(cls, fullname, path=None, target=None):
1424        """Try to find a spec for 'fullname' on sys.path or 'path'.
1425
1426        The search is based on sys.path_hooks and sys.path_importer_cache.
1427        """
1428        if path is None:
1429            path = sys.path
1430        spec = cls._get_spec(fullname, path, target)
1431        if spec is None:
1432            return None
1433        elif spec.loader is None:
1434            namespace_path = spec.submodule_search_locations
1435            if namespace_path:
1436                # We found at least one namespace path.  Return a spec which
1437                # can create the namespace package.
1438                spec.origin = None
1439                spec.submodule_search_locations = _NamespacePath(fullname, namespace_path, cls._get_spec)
1440                return spec
1441            else:
1442                return None
1443        else:
1444            return spec
1445
1446    @classmethod
1447    def find_module(cls, fullname, path=None):
1448        """find the module on sys.path or 'path' based on sys.path_hooks and
1449        sys.path_importer_cache.
1450
1451        This method is deprecated.  Use find_spec() instead.
1452
1453        """
1454        _warnings.warn("PathFinder.find_module() is deprecated and "
1455                       "slated for removal in Python 3.12; use find_spec() instead",
1456                       DeprecationWarning)
1457        spec = cls.find_spec(fullname, path)
1458        if spec is None:
1459            return None
1460        return spec.loader
1461
1462    @staticmethod
1463    def find_distributions(*args, **kwargs):
1464        """
1465        Find distributions.
1466
1467        Return an iterable of all Distribution instances capable of
1468        loading the metadata for packages matching ``context.name``
1469        (or all names if ``None`` indicated) along the paths in the list
1470        of directories ``context.path``.
1471        """
1472        from importlib.metadata import MetadataPathFinder
1473        return MetadataPathFinder.find_distributions(*args, **kwargs)
1474
1475
1476class FileFinder:
1477
1478    """File-based finder.
1479
1480    Interactions with the file system are cached for performance, being
1481    refreshed when the directory the finder is handling has been modified.
1482
1483    """
1484
1485    def __init__(self, path, *loader_details):
1486        """Initialize with the path to search on and a variable number of
1487        2-tuples containing the loader and the file suffixes the loader
1488        recognizes."""
1489        loaders = []
1490        for loader, suffixes in loader_details:
1491            loaders.extend((suffix, loader) for suffix in suffixes)
1492        self._loaders = loaders
1493        # Base (directory) path
1494        self.path = path or '.'
1495        if not _path_isabs(self.path):
1496            self.path = _path_join(_os.getcwd(), self.path)
1497        self._path_mtime = -1
1498        self._path_cache = set()
1499        self._relaxed_path_cache = set()
1500
1501    def invalidate_caches(self):
1502        """Invalidate the directory mtime."""
1503        self._path_mtime = -1
1504
1505    find_module = _find_module_shim
1506
1507    def find_loader(self, fullname):
1508        """Try to find a loader for the specified module, or the namespace
1509        package portions. Returns (loader, list-of-portions).
1510
1511        This method is deprecated.  Use find_spec() instead.
1512
1513        """
1514        _warnings.warn("FileFinder.find_loader() is deprecated and "
1515                       "slated for removal in Python 3.12; use find_spec() instead",
1516                       DeprecationWarning)
1517        spec = self.find_spec(fullname)
1518        if spec is None:
1519            return None, []
1520        return spec.loader, spec.submodule_search_locations or []
1521
1522    def _get_spec(self, loader_class, fullname, path, smsl, target):
1523        loader = loader_class(fullname, path)
1524        return spec_from_file_location(fullname, path, loader=loader,
1525                                       submodule_search_locations=smsl)
1526
1527    def find_spec(self, fullname, target=None):
1528        """Try to find a spec for the specified module.
1529
1530        Returns the matching spec, or None if not found.
1531        """
1532        is_namespace = False
1533        tail_module = fullname.rpartition('.')[2]
1534        try:
1535            mtime = _path_stat(self.path or _os.getcwd()).st_mtime
1536        except OSError:
1537            mtime = -1
1538        if mtime != self._path_mtime:
1539            self._fill_cache()
1540            self._path_mtime = mtime
1541        # tail_module keeps the original casing, for __file__ and friends
1542        if _relax_case():
1543            cache = self._relaxed_path_cache
1544            cache_module = tail_module.lower()
1545        else:
1546            cache = self._path_cache
1547            cache_module = tail_module
1548        # Check if the module is the name of a directory (and thus a package).
1549        if cache_module in cache:
1550            base_path = _path_join(self.path, tail_module)
1551            for suffix, loader_class in self._loaders:
1552                init_filename = '__init__' + suffix
1553                full_path = _path_join(base_path, init_filename)
1554                if _path_isfile(full_path):
1555                    return self._get_spec(loader_class, fullname, full_path, [base_path], target)
1556            else:
1557                # If a namespace package, return the path if we don't
1558                #  find a module in the next section.
1559                is_namespace = _path_isdir(base_path)
1560        # Check for a file w/ a proper suffix exists.
1561        for suffix, loader_class in self._loaders:
1562            try:
1563                full_path = _path_join(self.path, tail_module + suffix)
1564            except ValueError:
1565                return None
1566            _bootstrap._verbose_message('trying {}', full_path, verbosity=2)
1567            if cache_module + suffix in cache:
1568                if _path_isfile(full_path):
1569                    return self._get_spec(loader_class, fullname, full_path,
1570                                          None, target)
1571        if is_namespace:
1572            _bootstrap._verbose_message('possible namespace for {}', base_path)
1573            spec = _bootstrap.ModuleSpec(fullname, None)
1574            spec.submodule_search_locations = [base_path]
1575            return spec
1576        return None
1577
1578    def _fill_cache(self):
1579        """Fill the cache of potential modules and packages for this directory."""
1580        path = self.path
1581        try:
1582            contents = _os.listdir(path or _os.getcwd())
1583        except (FileNotFoundError, PermissionError, NotADirectoryError):
1584            # Directory has either been removed, turned into a file, or made
1585            # unreadable.
1586            contents = []
1587        # We store two cached versions, to handle runtime changes of the
1588        # PYTHONCASEOK environment variable.
1589        if not sys.platform.startswith('win'):
1590            self._path_cache = set(contents)
1591        else:
1592            # Windows users can import modules with case-insensitive file
1593            # suffixes (for legacy reasons). Make the suffix lowercase here
1594            # so it's done once instead of for every import. This is safe as
1595            # the specified suffixes to check against are always specified in a
1596            # case-sensitive manner.
1597            lower_suffix_contents = set()
1598            for item in contents:
1599                name, dot, suffix = item.partition('.')
1600                if dot:
1601                    new_name = '{}.{}'.format(name, suffix.lower())
1602                else:
1603                    new_name = name
1604                lower_suffix_contents.add(new_name)
1605            self._path_cache = lower_suffix_contents
1606        if sys.platform.startswith(_CASE_INSENSITIVE_PLATFORMS):
1607            self._relaxed_path_cache = {fn.lower() for fn in contents}
1608
1609    @classmethod
1610    def path_hook(cls, *loader_details):
1611        """A class method which returns a closure to use on sys.path_hook
1612        which will return an instance using the specified loaders and the path
1613        called on the closure.
1614
1615        If the path called on the closure is not a directory, ImportError is
1616        raised.
1617
1618        """
1619        def path_hook_for_FileFinder(path):
1620            """Path hook for importlib.machinery.FileFinder."""
1621            if not _path_isdir(path):
1622                raise ImportError('only directories are supported', path=path)
1623            return cls(path, *loader_details)
1624
1625        return path_hook_for_FileFinder
1626
1627    def __repr__(self):
1628        return 'FileFinder({!r})'.format(self.path)
1629
1630
1631# Import setup ###############################################################
1632
1633def _fix_up_module(ns, name, pathname, cpathname=None):
1634    # This function is used by PyImport_ExecCodeModuleObject().
1635    loader = ns.get('__loader__')
1636    spec = ns.get('__spec__')
1637    if not loader:
1638        if spec:
1639            loader = spec.loader
1640        elif pathname == cpathname:
1641            loader = SourcelessFileLoader(name, pathname)
1642        else:
1643            loader = SourceFileLoader(name, pathname)
1644    if not spec:
1645        spec = spec_from_file_location(name, pathname, loader=loader)
1646    try:
1647        ns['__spec__'] = spec
1648        ns['__loader__'] = loader
1649        ns['__file__'] = pathname
1650        ns['__cached__'] = cpathname
1651    except Exception:
1652        # Not important enough to report.
1653        pass
1654
1655
1656def _get_supported_file_loaders():
1657    """Returns a list of file-based module loaders.
1658
1659    Each item is a tuple (loader, suffixes).
1660    """
1661    extensions = ExtensionFileLoader, _imp.extension_suffixes()
1662    source = SourceFileLoader, SOURCE_SUFFIXES
1663    bytecode = SourcelessFileLoader, BYTECODE_SUFFIXES
1664    return [extensions, source, bytecode]
1665
1666
1667def _set_bootstrap_module(_bootstrap_module):
1668    global _bootstrap
1669    _bootstrap = _bootstrap_module
1670
1671
1672def _install(_bootstrap_module):
1673    """Install the path-based import components."""
1674    _set_bootstrap_module(_bootstrap_module)
1675    supported_loaders = _get_supported_file_loaders()
1676    sys.path_hooks.extend([FileFinder.path_hook(*supported_loaders)])
1677    sys.meta_path.append(PathFinder)
1678