comparison env/lib/python3.9/site-packages/virtualenv/create/via_global_ref/_virtualenv.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 """Patches that are applied at runtime to the virtual environment"""
2 # -*- coding: utf-8 -*-
3
4 import os
5 import sys
6
7 VIRTUALENV_PATCH_FILE = os.path.join(__file__)
8
9
10 def patch_dist(dist):
11 """
12 Distutils allows user to configure some arguments via a configuration file:
13 https://docs.python.org/3/install/index.html#distutils-configuration-files
14
15 Some of this arguments though don't make sense in context of the virtual environment files, let's fix them up.
16 """
17 # we cannot allow some install config as that would get packages installed outside of the virtual environment
18 old_parse_config_files = dist.Distribution.parse_config_files
19
20 def parse_config_files(self, *args, **kwargs):
21 result = old_parse_config_files(self, *args, **kwargs)
22 install = self.get_option_dict("install")
23
24 if "prefix" in install: # the prefix governs where to install the libraries
25 install["prefix"] = VIRTUALENV_PATCH_FILE, os.path.abspath(sys.prefix)
26 for base in ("purelib", "platlib", "headers", "scripts", "data"):
27 key = "install_{}".format(base)
28 if key in install: # do not allow global configs to hijack venv paths
29 install.pop(key, None)
30 return result
31
32 dist.Distribution.parse_config_files = parse_config_files
33
34
35 # Import hook that patches some modules to ignore configuration values that break package installation in case
36 # of virtual environments.
37 _DISTUTILS_PATCH = "distutils.dist", "setuptools.dist"
38 if sys.version_info > (3, 4):
39 # https://docs.python.org/3/library/importlib.html#setting-up-an-importer
40 from functools import partial
41 from importlib.abc import MetaPathFinder
42 from importlib.util import find_spec
43
44 class _Finder(MetaPathFinder):
45 """A meta path finder that allows patching the imported distutils modules"""
46
47 fullname = None
48
49 # lock[0] is threading.Lock(), but initialized lazily to avoid importing threading very early at startup,
50 # because there are gevent-based applications that need to be first to import threading by themselves.
51 # See https://github.com/pypa/virtualenv/issues/1895 for details.
52 lock = []
53
54 def find_spec(self, fullname, path, target=None):
55 if fullname in _DISTUTILS_PATCH and self.fullname is None:
56 # initialize lock[0] lazily
57 if len(self.lock) == 0:
58 import threading
59
60 lock = threading.Lock()
61 # there is possibility that two threads T1 and T2 are simultaneously running into find_spec,
62 # observing .lock as empty, and further going into hereby initialization. However due to the GIL,
63 # list.append() operation is atomic and this way only one of the threads will "win" to put the lock
64 # - that every thread will use - into .lock[0].
65 # https://docs.python.org/3/faq/library.html#what-kinds-of-global-value-mutation-are-thread-safe
66 self.lock.append(lock)
67
68 with self.lock[0]:
69 self.fullname = fullname
70 try:
71 spec = find_spec(fullname, path)
72 if spec is not None:
73 # https://www.python.org/dev/peps/pep-0451/#how-loading-will-work
74 is_new_api = hasattr(spec.loader, "exec_module")
75 func_name = "exec_module" if is_new_api else "load_module"
76 old = getattr(spec.loader, func_name)
77 func = self.exec_module if is_new_api else self.load_module
78 if old is not func:
79 try:
80 setattr(spec.loader, func_name, partial(func, old))
81 except AttributeError:
82 pass # C-Extension loaders are r/o such as zipimporter with <python 3.7
83 return spec
84 finally:
85 self.fullname = None
86
87 @staticmethod
88 def exec_module(old, module):
89 old(module)
90 if module.__name__ in _DISTUTILS_PATCH:
91 patch_dist(module)
92
93 @staticmethod
94 def load_module(old, name):
95 module = old(name)
96 if module.__name__ in _DISTUTILS_PATCH:
97 patch_dist(module)
98 return module
99
100 sys.meta_path.insert(0, _Finder())
101 else:
102 # https://www.python.org/dev/peps/pep-0302/
103 from imp import find_module
104 from pkgutil import ImpImporter, ImpLoader
105
106 class _VirtualenvImporter(object, ImpImporter):
107 def __init__(self, path=None):
108 object.__init__(self)
109 ImpImporter.__init__(self, path)
110
111 def find_module(self, fullname, path=None):
112 if fullname in _DISTUTILS_PATCH:
113 try:
114 return _VirtualenvLoader(fullname, *find_module(fullname.split(".")[-1], path))
115 except ImportError:
116 pass
117 return None
118
119 class _VirtualenvLoader(object, ImpLoader):
120 def __init__(self, fullname, file, filename, etc):
121 object.__init__(self)
122 ImpLoader.__init__(self, fullname, file, filename, etc)
123
124 def load_module(self, fullname):
125 module = super(_VirtualenvLoader, self).load_module(fullname)
126 patch_dist(module)
127 module.__loader__ = None # distlib fallback
128 return module
129
130 sys.meta_path.append(_VirtualenvImporter())