20 from __future__
import print_function
30 from distutils.spawn
import find_executable
32 from .
import run_command, relocate
33 from .collect_requirements
import collect_requirements
35 _BYTECODE_REGEX = re.compile(
r".*\.py[co]")
36 _COMMENT_REGEX = re.compile(
r"(^|\s+)#.*$", flags=re.MULTILINE)
38 logger = logging.getLogger(__name__)
43 """ Manage a virtualenv at the specified path. """ 46 def initialize(self, python, use_system_packages, extra_pip_args, clean=True):
47 """ Initialize a new virtualenv using the specified python version and extra arguments. """ 50 shutil.rmtree(self.
path)
54 system_python = find_executable(python)
57 error_msg =
"Unable to find a system-installed {}.".format(python)
58 if python
and python[0].isdigit():
59 error_msg +=
" Perhaps you meant python{}".format(python)
60 raise RuntimeError(error_msg)
69 virtualenv = [system_python,
"-m",
"venv"]
71 virtualenv = [
"virtualenv",
"--no-setuptools",
"--verbose",
"--python", python]
74 preinstall += [
"setuptools>=44,<45"]
76 if use_system_packages:
77 virtualenv.append(
"--system-site-packages")
79 virtualenv.append(self.
path)
82 run_command([self.
_venv_bin(
"python"),
"-m",
"pip",
"install"] + extra_pip_args + preinstall, check=
True)
84 def install(self, requirements, extra_pip_args):
85 """ Sync a virtualenv with the specified requirements. """ 86 command = [self.
_venv_bin(
"python"),
"-m",
"pip",
"install"] + extra_pip_args
87 for req
in requirements:
90 def check(self, requirements, extra_pip_args):
91 """ Check if a set of requirements is completely locked. """ 92 with open(requirements,
"r") as f: 93 existing_requirements = f.read() 96 command = [self.
_venv_bin(
"pip-compile"),
"--no-header", requirements,
"-o",
"-"]
98 command += [
"--pip-args",
" ".join(extra_pip_args)]
100 generated_requirements =
run_command(command, check=
True, capture_output=
True).stdout.decode()
102 def _format(content):
104 content = _COMMENT_REGEX.sub(
"", content)
106 content = content.lower()
108 content = content.splitlines()
112 diff = list(difflib.unified_diff(_format(existing_requirements), _format(generated_requirements)))
116 def lock(self, package_name, input_requirements, no_overwrite, extra_pip_args):
117 """ Create a frozen requirement set from a set of input specifications. """ 121 logger.info(
"Package doesn't export any requirements, step can be skipped")
124 if no_overwrite
and os.path.exists(output_requirements):
125 logger.info(
"Lock file already exists, not overwriting")
128 pip_compile = self.
_venv_bin(
"pip-compile")
129 command = [pip_compile,
"--no-header", input_requirements]
131 if os.path.normpath(input_requirements) == os.path.normpath(output_requirements):
133 "Trying to write locked requirements {} into a path specified as input: {}".format(
134 output_requirements, input_requirements
139 command += [
"--pip-args",
" ".join(extra_pip_args)]
141 command += [
"-o", output_requirements]
145 logger.info(
"Wrote new lock file to {}".format(output_requirements))
148 """ Relocate a virtualenv to another directory. """ 150 relocate.fix_shebangs(self.
path, target_dir)
151 relocate.fix_activate_path(self.
path, target_dir)
155 local_dir = os.path.join(self.
path,
"local")
156 if os.path.exists(local_dir):
157 shutil.rmtree(local_dir)
160 return os.path.abspath(os.path.join(self.
path,
"bin", binary_name))
164 with open(os.devnull,
"w")
as devnull:
166 run_command([python_executable,
"-cimport {}".format(module)], stderr=devnull, check=
True)
168 except subprocess.CalledProcessError:
172 """ Remove all .py[co] files since they embed absolute paths. """ 173 for root, _, files
in os.walk(self.
path):
175 if _BYTECODE_REGEX.match(f):
176 os.remove(os.path.join(root, f))
def collect_requirements(package_name, no_deps=False)
def check(self, requirements, extra_pip_args)
def initialize(self, python, use_system_packages, extra_pip_args, clean=True)
def lock(self, package_name, input_requirements, no_overwrite, extra_pip_args)
def install(self, requirements, extra_pip_args)
def _check_module(self, python_executable, module)
def relocate(self, target_dir)
def _venv_bin(self, binary_name)
def _delete_bytecode(self)
def run_command(cmd, args, kwargs)