Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/virtualenv/create/creator.py @ 2:6af9afd405e9 draft
"planemo upload commit 0a63dd5f4d38a1f6944587f52a8cd79874177fc1"
| author | shellac |
|---|---|
| date | Thu, 14 May 2020 14:56:58 -0400 |
| parents | 26e78fe6e8c4 |
| children |
comparison
equal
deleted
inserted
replaced
| 1:75ca89e9b81c | 2:6af9afd405e9 |
|---|---|
| 1 from __future__ import absolute_import, print_function, unicode_literals | |
| 2 | |
| 3 import json | |
| 4 import logging | |
| 5 import os | |
| 6 import sys | |
| 7 from abc import ABCMeta, abstractmethod | |
| 8 from argparse import ArgumentTypeError | |
| 9 from ast import literal_eval | |
| 10 from collections import OrderedDict | |
| 11 | |
| 12 from six import add_metaclass | |
| 13 | |
| 14 from virtualenv.discovery.cached_py_info import LogCmd | |
| 15 from virtualenv.info import WIN_CPYTHON_2 | |
| 16 from virtualenv.pyenv_cfg import PyEnvCfg | |
| 17 from virtualenv.util.path import Path, safe_delete | |
| 18 from virtualenv.util.six import ensure_str, ensure_text | |
| 19 from virtualenv.util.subprocess import run_cmd | |
| 20 from virtualenv.util.zipapp import ensure_file_on_disk | |
| 21 from virtualenv.version import __version__ | |
| 22 | |
| 23 HERE = Path(os.path.abspath(__file__)).parent | |
| 24 DEBUG_SCRIPT = HERE / "debug.py" | |
| 25 | |
| 26 | |
| 27 class CreatorMeta(object): | |
| 28 def __init__(self): | |
| 29 self.error = None | |
| 30 | |
| 31 | |
| 32 @add_metaclass(ABCMeta) | |
| 33 class Creator(object): | |
| 34 """A class that given a python Interpreter creates a virtual environment""" | |
| 35 | |
| 36 def __init__(self, options, interpreter): | |
| 37 """Construct a new virtual environment creator. | |
| 38 | |
| 39 :param options: the CLI option as parsed from :meth:`add_parser_arguments` | |
| 40 :param interpreter: the interpreter to create virtual environment from | |
| 41 """ | |
| 42 self.interpreter = interpreter | |
| 43 self._debug = None | |
| 44 self.dest = Path(options.dest) | |
| 45 self.clear = options.clear | |
| 46 self.pyenv_cfg = PyEnvCfg.from_folder(self.dest) | |
| 47 self.app_data = options.app_data.folder | |
| 48 | |
| 49 def __repr__(self): | |
| 50 return ensure_str(self.__unicode__()) | |
| 51 | |
| 52 def __unicode__(self): | |
| 53 return "{}({})".format(self.__class__.__name__, ", ".join("{}={}".format(k, v) for k, v in self._args())) | |
| 54 | |
| 55 def _args(self): | |
| 56 return [ | |
| 57 ("dest", ensure_text(str(self.dest))), | |
| 58 ("clear", self.clear), | |
| 59 ] | |
| 60 | |
| 61 @classmethod | |
| 62 def can_create(cls, interpreter): | |
| 63 """Determine if we can create a virtual environment. | |
| 64 | |
| 65 :param interpreter: the interpreter in question | |
| 66 :return: ``None`` if we can't create, any other object otherwise that will be forwarded to \ | |
| 67 :meth:`add_parser_arguments` | |
| 68 """ | |
| 69 return True | |
| 70 | |
| 71 @classmethod | |
| 72 def add_parser_arguments(cls, parser, interpreter, meta, app_data): | |
| 73 """Add CLI arguments for the creator. | |
| 74 | |
| 75 :param parser: the CLI parser | |
| 76 :param interpreter: the interpreter we're asked to create virtual environment for | |
| 77 :param meta: value as returned by :meth:`can_create` | |
| 78 """ | |
| 79 parser.add_argument( | |
| 80 "dest", help="directory to create virtualenv at", type=cls.validate_dest, | |
| 81 ) | |
| 82 parser.add_argument( | |
| 83 "--clear", | |
| 84 dest="clear", | |
| 85 action="store_true", | |
| 86 help="remove the destination directory if exist before starting (will overwrite files otherwise)", | |
| 87 default=False, | |
| 88 ) | |
| 89 | |
| 90 @abstractmethod | |
| 91 def create(self): | |
| 92 """Perform the virtual environment creation.""" | |
| 93 raise NotImplementedError | |
| 94 | |
| 95 @classmethod | |
| 96 def validate_dest(cls, raw_value): | |
| 97 """No path separator in the path, valid chars and must be write-able""" | |
| 98 | |
| 99 def non_write_able(dest, value): | |
| 100 common = Path(*os.path.commonprefix([value.parts, dest.parts])) | |
| 101 raise ArgumentTypeError( | |
| 102 "the destination {} is not write-able at {}".format(dest.relative_to(common), common) | |
| 103 ) | |
| 104 | |
| 105 # the file system must be able to encode | |
| 106 # note in newer CPython this is always utf-8 https://www.python.org/dev/peps/pep-0529/ | |
| 107 encoding = sys.getfilesystemencoding() | |
| 108 refused = OrderedDict() | |
| 109 kwargs = {"errors": "ignore"} if encoding != "mbcs" else {} | |
| 110 for char in ensure_text(raw_value): | |
| 111 try: | |
| 112 trip = char.encode(encoding, **kwargs).decode(encoding) | |
| 113 if trip == char: | |
| 114 continue | |
| 115 raise ValueError(trip) | |
| 116 except ValueError: | |
| 117 refused[char] = None | |
| 118 if refused: | |
| 119 raise ArgumentTypeError( | |
| 120 "the file system codec ({}) cannot handle characters {!r} within {!r}".format( | |
| 121 encoding, "".join(refused.keys()), raw_value | |
| 122 ) | |
| 123 ) | |
| 124 if os.pathsep in raw_value: | |
| 125 raise ArgumentTypeError( | |
| 126 "destination {!r} must not contain the path separator ({}) as this would break " | |
| 127 "the activation scripts".format(raw_value, os.pathsep) | |
| 128 ) | |
| 129 | |
| 130 value = Path(raw_value) | |
| 131 if value.exists() and value.is_file(): | |
| 132 raise ArgumentTypeError("the destination {} already exists and is a file".format(value)) | |
| 133 if (3, 3) <= sys.version_info <= (3, 6): | |
| 134 # pre 3.6 resolve is always strict, aka must exists, sidestep by using os.path operation | |
| 135 dest = Path(os.path.realpath(raw_value)) | |
| 136 else: | |
| 137 dest = Path(os.path.abspath(str(value))).resolve() # on Windows absolute does not imply resolve so use both | |
| 138 value = dest | |
| 139 while dest: | |
| 140 if dest.exists(): | |
| 141 if os.access(ensure_text(str(dest)), os.W_OK): | |
| 142 break | |
| 143 else: | |
| 144 non_write_able(dest, value) | |
| 145 base, _ = dest.parent, dest.name | |
| 146 if base == dest: | |
| 147 non_write_able(dest, value) # pragma: no cover | |
| 148 dest = base | |
| 149 return str(value) | |
| 150 | |
| 151 def run(self): | |
| 152 if self.dest.exists() and self.clear: | |
| 153 logging.debug("delete %s", self.dest) | |
| 154 safe_delete(self.dest) | |
| 155 self.create() | |
| 156 self.set_pyenv_cfg() | |
| 157 | |
| 158 def set_pyenv_cfg(self): | |
| 159 self.pyenv_cfg.content = OrderedDict() | |
| 160 self.pyenv_cfg["home"] = self.interpreter.system_exec_prefix | |
| 161 self.pyenv_cfg["implementation"] = self.interpreter.implementation | |
| 162 self.pyenv_cfg["version_info"] = ".".join(str(i) for i in self.interpreter.version_info) | |
| 163 self.pyenv_cfg["virtualenv"] = __version__ | |
| 164 | |
| 165 @property | |
| 166 def debug(self): | |
| 167 """ | |
| 168 :return: debug information about the virtual environment (only valid after :meth:`create` has run) | |
| 169 """ | |
| 170 if self._debug is None and self.exe is not None: | |
| 171 self._debug = get_env_debug_info(self.exe, self.debug_script(), self.app_data) | |
| 172 return self._debug | |
| 173 | |
| 174 # noinspection PyMethodMayBeStatic | |
| 175 def debug_script(self): | |
| 176 return DEBUG_SCRIPT | |
| 177 | |
| 178 | |
| 179 def get_env_debug_info(env_exe, debug_script, app_data): | |
| 180 env = os.environ.copy() | |
| 181 env.pop(str("PYTHONPATH"), None) | |
| 182 | |
| 183 with ensure_file_on_disk(debug_script, app_data) as debug_script: | |
| 184 cmd = [str(env_exe), str(debug_script)] | |
| 185 if WIN_CPYTHON_2: | |
| 186 cmd = [ensure_text(i) for i in cmd] | |
| 187 logging.debug(str("debug via %r"), LogCmd(cmd)) | |
| 188 code, out, err = run_cmd(cmd) | |
| 189 | |
| 190 # noinspection PyBroadException | |
| 191 try: | |
| 192 if code != 0: | |
| 193 result = literal_eval(out) | |
| 194 else: | |
| 195 result = json.loads(out) | |
| 196 if err: | |
| 197 result["err"] = err | |
| 198 except Exception as exception: | |
| 199 return {"out": out, "err": err, "returncode": code, "exception": repr(exception)} | |
| 200 if "sys" in result and "path" in result["sys"]: | |
| 201 del result["sys"]["path"][0] | |
| 202 return result |
