1import os
2import sys
3import platform
4
5from typing import Union
6
7
8__all__ = ['install', 'NullFinder']
9
10
11def install(cls):
12 """
13 Class decorator for installation on sys.meta_path.
14
15 Adds the backport DistributionFinder to sys.meta_path and
16 attempts to disable the finder functionality of the stdlib
17 DistributionFinder.
18 """
19 sys.meta_path.append(cls())
20 disable_stdlib_finder()
21 return cls
22
23
24def disable_stdlib_finder():
25 """
26 Give the backport primacy for discovering path-based distributions
27 by monkey-patching the stdlib O_O.
28
29 See #91 for more background for rationale on this sketchy
30 behavior.
31 """
32
33 def matches(finder):
34 return getattr(
35 finder, '__module__', None
36 ) == '_frozen_importlib_external' and hasattr(finder, 'find_distributions')
37
38 for finder in filter(matches, sys.meta_path): # pragma: nocover
39 del finder.find_distributions
40
41
42class NullFinder:
43 """
44 A "Finder" (aka "MetaClassFinder") that never finds any modules,
45 but may find distributions.
46 """
47
48 @staticmethod
49 def find_spec(*args, **kwargs):
50 return None
51
52
53def pypy_partial(val):
54 """
55 Adjust for variable stacklevel on partial under PyPy.
56
57 Workaround for #327.
58 """
59 is_pypy = platform.python_implementation() == 'PyPy'
60 return val + is_pypy
61
62
63if sys.version_info >= (3, 9):
64 StrPath = Union[str, os.PathLike[str]]
65else:
66 # PathLike is only subscriptable at runtime in 3.9+
67 StrPath = Union[str, "os.PathLike[str]"] # pragma: no cover