1import platform
2import sys
3
4__all__ = ['NullFinder', 'install']
5
6
7def install(cls):
8 """
9 Install cls on sys.meta_path.
10
11 Adds the backport DistributionFinder to sys.meta_path and
12 attempts to disable the finder functionality of the stdlib
13 DistributionFinder.
14
15 Call this only once the calling module is fully initialized, from
16 its end. The installed finder resolves PathDistribution from that
17 module's globals, so installing it any earlier publishes a finder
18 that anything walking sys.meta_path would trip over (#525).
19
20 Returns nothing, so that use as a class decorator fails outright
21 rather than reopening that window.
22 """
23 sys.meta_path.append(cls())
24 disable_stdlib_finder()
25
26
27def disable_stdlib_finder():
28 """
29 Give the backport primacy for discovering path-based distributions
30 by monkey-patching the stdlib O_O.
31
32 See #91 for more background for rationale on this sketchy
33 behavior.
34 """
35
36 def matches(finder):
37 return getattr(
38 finder, '__module__', None
39 ) == '_frozen_importlib_external' and hasattr(finder, 'find_distributions')
40
41 for finder in filter(matches, sys.meta_path): # pragma: nocover
42 del finder.find_distributions
43
44
45class NullFinder:
46 """
47 A "Finder" (aka "MetaPathFinder") that never finds any modules,
48 but may find distributions.
49 """
50
51 @staticmethod
52 def find_spec(*args, **kwargs):
53 return None
54
55
56def pypy_partial(val):
57 """
58 Adjust for variable stacklevel on partial under PyPy.
59
60 Workaround for #327.
61 """
62 is_pypy = platform.python_implementation() == 'PyPy'
63 return val + is_pypy