■ ■ ■ ■ ■ ■
vuln_analyzer/lib/python3.11/site-packages/_virtualenv.py
| 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 | + | |
| 41 | + | class _Finder: |
| 42 | + | """A meta path finder that allows patching the imported distutils modules""" |
| 43 | + | |
| 44 | + | fullname = None |
| 45 | + | |
| 46 | + | # lock[0] is threading.Lock(), but initialized lazily to avoid importing threading very early at startup, |
| 47 | + | # because there are gevent-based applications that need to be first to import threading by themselves. |
| 48 | + | # See https://github.com/pypa/virtualenv/issues/1895 for details. |
| 49 | + | lock = [] |
| 50 | + | |
| 51 | + | def find_spec(self, fullname, path, target=None): # noqa: U100 |
| 52 | + | if fullname in _DISTUTILS_PATCH and self.fullname is None: |
| 53 | + | # initialize lock[0] lazily |
| 54 | + | if len(self.lock) == 0: |
| 55 | + | import threading |
| 56 | + | |
| 57 | + | lock = threading.Lock() |
| 58 | + | # there is possibility that two threads T1 and T2 are simultaneously running into find_spec, |
| 59 | + | # observing .lock as empty, and further going into hereby initialization. However due to the GIL, |
| 60 | + | # list.append() operation is atomic and this way only one of the threads will "win" to put the lock |
| 61 | + | # - that every thread will use - into .lock[0]. |
| 62 | + | # https://docs.python.org/3/faq/library.html#what-kinds-of-global-value-mutation-are-thread-safe |
| 63 | + | self.lock.append(lock) |
| 64 | + | |
| 65 | + | from functools import partial |
| 66 | + | from importlib.util import find_spec |
| 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()) |
| 131 | + | |