def install_requirements(self, finder, requirements, message): args = [ sys.executable, '-m', 'pip', 'install', '--ignore-installed', '--no-user', '--prefix', self.path, '--no-warn-script-location', ] if logger.getEffectiveLevel() <= logging.DEBUG: args.append('-v') for format_control in ('no_binary', 'only_binary'): formats = getattr(finder.format_control, format_control) args.extend(('--' + format_control.replace('_', '-'), ','.join(sorted(formats or {':none:'})))) if finder.index_urls: args.extend(['-i', finder.index_urls[0]]) for extra_index in finder.index_urls[1:]: args.extend(['--extra-index-url', extra_index]) else: args.append('--no-index') for link in finder.find_links: args.extend(['--find-links', link]) for _, host, _ in finder.secure_origins: args.extend(['--trusted-host', host]) if finder.allow_all_prereleases: args.append('--pre') if finder.process_dependency_links: args.append('--process-dependency-links') args.append('--') args.extend(requirements) with open_spinner(message) as spinner: call_subprocess(args, show_stdout=False, spinner=spinner)
def test_spinner_finish( self, exit_status, show_stdout, extra_ok_returncodes, log_level, caplog, expected, ): """ Test that the spinner finishes correctly. """ expected_exc_type = expected[0] expected_final_status = expected[1] expected_spin_count = expected[2] command = ( 'print("Hello"); print("world"); exit({})'.format(exit_status) ) args, spinner = self.prepare_call(caplog, log_level, command=command) try: call_subprocess( args, show_stdout=show_stdout, extra_ok_returncodes=extra_ok_returncodes, spinner=spinner, ) except Exception as exc: exc_type = type(exc) else: exc_type = None assert exc_type == expected_exc_type assert spinner.final_status == expected_final_status assert spinner.spin_count == expected_spin_count
def run_egg_info(self): # type: () -> None if self.name: logger.debug( 'Running setup.py (path:%s) egg_info for package %s', self.setup_py, self.name, ) else: logger.debug( 'Running setup.py (path:%s) egg_info for package from %s', self.setup_py, self.link, ) script = SETUPTOOLS_SHIM % self.setup_py base_cmd = [sys.executable, '-c', script] if self.isolated: base_cmd += ["--no-user-cfg"] egg_info_cmd = base_cmd + ['egg_info'] # We can't put the .egg-info files at the root, because then the # source code will be mistaken for an installed egg, causing # problems if self.editable: egg_base_option = [] # type: List[str] else: egg_info_dir = os.path.join(self.setup_py_dir, 'pip-egg-info') ensure_dir(egg_info_dir) egg_base_option = ['--egg-base', 'pip-egg-info'] with self.build_env: call_subprocess( egg_info_cmd + egg_base_option, cwd=self.setup_py_dir, command_desc='python setup.py egg_info')
def _copy_dist_from_dir(link_path, location): """Copy distribution files in `link_path` to `location`. Invoked when user requests to install a local directory. E.g.: pip install . pip install ~/dev/git-repos/python-prompt-toolkit """ # Note: This is currently VERY SLOW if you have a lot of data in the # directory, because it copies everything with `shutil.copytree`. # What it should really do is build an sdist and install that. # See https://github.com/pypa/pip/issues/2195 if os.path.isdir(location): rmtree(location) # build an sdist setup_py = 'setup.py' sdist_args = [sys.executable] sdist_args.append('-c') sdist_args.append(SETUPTOOLS_SHIM % setup_py) sdist_args.append('sdist') sdist_args += ['--dist-dir', location] logger.info('Running setup.py sdist for %s', link_path) with indent_log(): call_subprocess(sdist_args, cwd=link_path, show_stdout=False) # unpack sdist into `location` sdist = os.path.join(location, os.listdir(location)[0]) logger.info('Unpacking sdist %s into %s', sdist, location) unpack_file(sdist, location, content_type=None, link=None)
def install_editable( self, install_options, # type: List[str] global_options=(), # type: Sequence[str] prefix=None # type: Optional[str] ): # type: (...) -> None logger.info('Running setup.py develop for %s', self.name) if self.isolated: global_options = list(global_options) + ["--no-user-cfg"] if prefix: prefix_param = ['--prefix={}'.format(prefix)] install_options = list(install_options) + prefix_param with indent_log(): # FIXME: should we do --install-headers here too? with self.build_env: call_subprocess( [ sys.executable, '-c', SETUPTOOLS_SHIM % self.setup_py ] + list(global_options) + ['develop', '--no-deps'] + list(install_options), cwd=self.setup_py_dir, ) self.install_succeeded = True
def __build_one(self, req, tempd, python_tag=None, isolate=False): base_args = self._base_setup_args(req, isolate=isolate) spin_message = 'Running setup.py bdist_wheel for %s' % (req.name,) with open_spinner(spin_message) as spinner: logger.debug('Destination directory: %s', tempd) wheel_args = base_args + ['bdist_wheel', '-d', tempd] \ + self.build_options if python_tag is not None: wheel_args += ["--python-tag", python_tag] env = {} if isolate: env['PYTHONNOUSERSITE'] = '1' try: call_subprocess(wheel_args, cwd=req.setup_py_dir, extra_environ=env, show_stdout=False, spinner=spinner) return True except: spinner.finish("error") logger.error('Failed building wheel for %s', req.name) return False
def _build_one_legacy(self, req, tempd, python_tag=None): """Build one InstallRequirement using the "legacy" build process. Returns path to wheel if successfully built. Otherwise, returns None. """ base_args = self._base_setup_args(req) spin_message = 'Building wheel for %s (setup.py)' % (req.name,) with open_spinner(spin_message) as spinner: logger.debug('Destination directory: %s', tempd) wheel_args = base_args + ['bdist_wheel', '-d', tempd] \ + self.build_options if python_tag is not None: wheel_args += ["--python-tag", python_tag] try: call_subprocess(wheel_args, cwd=req.setup_py_dir, show_stdout=False, spinner=spinner) except Exception: spinner.finish("error") logger.error('Failed building wheel for %s', req.name) return None # listdir's return value is sorted to be deterministic return os.path.join(tempd, sorted(os.listdir(tempd))[0])
def install_editable(self, install_options, global_options=(), prefix=None): logger.info('Running setup.py develop for %s', self.name) if self.isolated: global_options = list(global_options) + ["--no-user-cfg"] if prefix: prefix_param = ['--prefix={0}'.format(prefix)] install_options = list(install_options) + prefix_param with indent_log(): # FIXME: should we do --install-headers here too? call_subprocess( [ sys.executable, '-c', SETUPTOOLS_SHIM % self.setup_py ] + list(global_options) + ['develop', '--no-deps'] + list(install_options), cwd=self.setup_py_dir, show_stdout=False) self.install_succeeded = True
def run_egg_info(self): assert self.source_dir if self.name: logger.debug( 'Running setup.py (path:%s) egg_info for package %s', self.setup_py, self.name, ) else: logger.debug( 'Running setup.py (path:%s) egg_info for package from %s', self.setup_py, self.link, ) with indent_log(): script = SETUPTOOLS_SHIM % self.setup_py base_cmd = [sys.executable, '-c', script] if self.isolated: base_cmd += ["--no-user-cfg"] egg_info_cmd = base_cmd + ['egg_info'] # We can't put the .egg-info files at the root, because then the # source code will be mistaken for an installed egg, causing # problems if self.editable: egg_base_option = [] else: egg_info_dir = os.path.join(self.setup_py_dir, 'pip-egg-info') ensure_dir(egg_info_dir) egg_base_option = ['--egg-base', 'pip-egg-info'] with self.build_env: call_subprocess( egg_info_cmd + egg_base_option, cwd=self.setup_py_dir, show_stdout=False, command_desc='python setup.py egg_info') if not self.req: if isinstance(parse_version(self.pkg_info()["Version"]), Version): op = "==" else: op = "===" self.req = Requirement( "".join([ self.pkg_info()["Name"], op, self.pkg_info()["Version"], ]) ) self._correct_build_location() else: metadata_name = canonicalize_name(self.pkg_info()["Name"]) if canonicalize_name(self.req.name) != metadata_name: logger.warning( 'Running setup.py (path:%s) egg_info for package %s ' 'produced metadata for project name %s. Fix your ' '#egg=%s fragments.', self.setup_py, self.name, metadata_name, self.name ) self.req = Requirement(metadata_name)
def runner(cmd, cwd=None, extra_environ=None): with open_spinner(self.spin_message) as spinner: call_subprocess( cmd, cwd=cwd, extra_environ=extra_environ, spinner=spinner ) self.spin_message = ""
def _clean_one(self, req): base_args = self._base_setup_args(req) logger.info('Running setup.py clean for %s', req.name) clean_args = base_args + ['clean', '--all'] try: call_subprocess(clean_args, cwd=req.source_dir, show_stdout=False) return True except: logger.error('Failed cleaning build dir for %s', req.name) return False
def runner( cmd, # type: List[str] cwd=None, # type: Optional[str] extra_environ=None # type: Optional[Mapping[str, Any]] ): # type: (...) -> None with open_spinner(self.spin_message) as spinner: call_subprocess( cmd, cwd=cwd, extra_environ=extra_environ, spinner=spinner ) self.spin_message = ""
def _build_one_legacy(self, req, tempd, python_tag=None): """Build one InstallRequirement using the "legacy" build process. Returns path to wheel if successfully built. Otherwise, returns None. """ base_args = self._base_setup_args(req) spin_message = 'Building wheel for %s (setup.py)' % (req.name,) with open_spinner(spin_message) as spinner: logger.debug('Destination directory: %s', tempd) wheel_args = base_args + ['bdist_wheel', '-d', tempd] \ + self.build_options if python_tag is not None: wheel_args += ["--python-tag", python_tag] try: output = call_subprocess(wheel_args, cwd=req.setup_py_dir, show_stdout=False, spinner=spinner) except Exception: spinner.finish("error") logger.error('Failed building wheel for %s', req.name) return None names = os.listdir(tempd) wheel_path = get_legacy_build_wheel_path( names=names, temp_dir=tempd, req=req, command_args=wheel_args, command_output=output, ) return wheel_path
def _install_build_reqs(self, reqs, prefix): # Local import to avoid circular import (wheel <-> req_install) from pip._internal.req.req_install import InstallRequirement from pip._internal.index import FormatControl # Ignore the --no-binary option when installing the build system, so # we don't recurse trying to build a self-hosting build system. finder = copy.copy(self.finder) finder.format_control = FormatControl(set(), set()) urls = [finder.find_requirement(InstallRequirement.from_line(r), upgrade=False).url for r in reqs] args = [sys.executable, '-m', 'pip', 'install', '--ignore-installed', '--prefix', prefix] + list(urls) with open_spinner("Installing build dependencies") as spinner: call_subprocess(args, show_stdout=False, spinner=spinner)
def setup_py(self): assert self.source_dir, "No source dir for %s" % self cmd = [sys.executable, '-c', 'import setuptools'] output = call_subprocess( cmd, show_stdout=False, command_desc='python -c "import setuptools"', on_returncode='ignore', ) if output: if get_installed_version('setuptools') is None: add_msg = "Please install setuptools." else: add_msg = output # Setuptools is not available raise InstallationError( "Could not import setuptools which is required to " "install from a source distribution.\n%s" % add_msg ) setup_py = os.path.join(self.setup_py_dir, 'setup.py') # Python2 __file__ should not be unicode if six.PY2 and isinstance(setup_py, six.text_type): setup_py = setup_py.encode(sys.getfilesystemencoding()) return setup_py
def run_command(self, cmd, show_stdout=True, cwd=None, on_returncode='raise', command_desc=None, extra_environ=None, spinner=None): """ Run a VCS subcommand This is simply a wrapper around call_subprocess that adds the VCS command name, and checks that the VCS is available """ cmd = [self.name] + cmd try: return call_subprocess(cmd, show_stdout, cwd, on_returncode, command_desc, extra_environ, unset_environ=self.unset_environ, spinner=spinner) except OSError as e: # errno.ENOENT = no such file or directory # In other words, the VCS executable isn't available if e.errno == errno.ENOENT: raise BadCommand( 'Cannot find command %r - do you have ' '%r installed and in your ' 'PATH?' % (self.name, self.name)) else: raise # re-raise exception if a different error occurred
def _install_build_reqs(finder, prefix, build_requirements): # NOTE: What follows is not a very good thing. # Eventually, this should move into the BuildEnvironment class and # that should handle all the isolation and sub-process invocation. finder = copy(finder) finder.format_control = FormatControl(set(), set([":all:"])) urls = [ finder.find_requirement( InstallRequirement.from_line(r), upgrade=False).url for r in build_requirements ] args = [ sys.executable, '-m', 'pip', 'install', '--ignore-installed', '--no-user', '--prefix', prefix, ] + list(urls) with open_spinner("Installing build dependencies") as spinner: call_subprocess(args, show_stdout=False, spinner=spinner)
def install_requirements( self, finder, # type: PackageFinder requirements, # type: Iterable[str] prefix_as_string, # type: str message # type: Optional[str] ): # type: (...) -> None prefix = self._prefixes[prefix_as_string] assert not prefix.setup prefix.setup = True if not requirements: return args = [ sys.executable, os.path.dirname(pip_location), 'install', '--ignore-installed', '--no-user', '--prefix', prefix.path, '--no-warn-script-location', ] # type: List[str] if logger.getEffectiveLevel() <= logging.DEBUG: args.append('-v') for format_control in ('no_binary', 'only_binary'): formats = getattr(finder.format_control, format_control) args.extend(('--' + format_control.replace('_', '-'), ','.join(sorted(formats or {':none:'})))) if finder.index_urls: args.extend(['-i', finder.index_urls[0]]) for extra_index in finder.index_urls[1:]: args.extend(['--extra-index-url', extra_index]) else: args.append('--no-index') for link in finder.find_links: args.extend(['--find-links', link]) for _, host, _ in finder.secure_origins: args.extend(['--trusted-host', host]) if finder.allow_all_prereleases: args.append('--pre') if finder.process_dependency_links: args.append('--process-dependency-links') args.append('--') args.extend(requirements) with open_spinner(message) as spinner: call_subprocess(args, show_stdout=False, spinner=spinner)
def _build_one_legacy(self, req, tempd, python_tag=None): base_args = self._base_setup_args(req) spin_message = 'Building wheel for %s (setup.py)' % (req.name,) with open_spinner(spin_message) as spinner: logger.debug('Destination directory: %s', tempd) wheel_args = base_args + ['bdist_wheel', '-d', tempd] \ + self.build_options if python_tag is not None: wheel_args += ["--python-tag", python_tag] try: call_subprocess(wheel_args, cwd=req.setup_py_dir, show_stdout=False, spinner=spinner) return True except Exception: spinner.finish("error") logger.error('Failed building wheel for %s', req.name) return False
def test_info_logging__subprocess_error(self, capfd, caplog): """ Test INFO logging of a subprocess with an error (and without passing show_stdout=True). """ log_level = INFO command = 'print("Hello"); print("world"); exit("fail")' args, spinner = self.prepare_call(caplog, log_level, command=command) with pytest.raises(InstallationError): call_subprocess(args, spinner=spinner) result = None expected = (None, [ ('pip.subprocessor', ERROR, 'Complete output from command '), # The "failed" portion is later on in this "Hello" string. ('pip.subprocessor', ERROR, 'Hello'), ]) # The spinner should spin three times in this case since the # subprocess output isn't being written to the console. self.check_result( capfd, caplog, log_level, spinner, result, expected, expected_spinner=(3, 'error'), ) # Do some further checking on the captured log records to confirm # that the subprocess output was logged. last_record = caplog.record_tuples[-1] last_message = last_record[2] lines = last_message.splitlines() # We have to sort before comparing the lines because we can't # guarantee the order in which stdout and stderr will appear. # For example, we observed the stderr lines coming before stdout # in CI for PyPy 2.7 even though stdout happens first chronologically. assert sorted(lines) == [ '----------------------------------------', 'Hello', 'fail', 'world', ], 'lines: {}'.format(lines) # Show the full output on failure.
def test_info_logging_with_show_stdout_true(self, capfd, caplog): """ Test INFO logging with show_stdout=True. """ log_level = logging.INFO args, spinner = self.prepare_call(caplog, log_level) result = call_subprocess(args, spinner=spinner, show_stdout=True) expected = (None, ['Hello', 'world'], []) # The spinner shouldn't spin in this case since the subprocess # output is already being written to the console. self.check_result( capfd, caplog, log_level, spinner, result, expected, expected_spinner=(0, None), )
def test_info_logging(self, capfd, caplog): """ Test INFO logging (and without passing show_stdout=True). """ log_level = INFO args, spinner = self.prepare_call(caplog, log_level) result = call_subprocess(args, spinner=spinner) expected = (['Hello', 'world'], []) # The spinner should spin twice in this case since the subprocess # output isn't being written to the console. self.check_result( capfd, caplog, log_level, spinner, result, expected, expected_spinner=(2, 'done'), )
def test_debug_logging(self, capfd, caplog): """ Test DEBUG logging (and without passing show_stdout=True). """ log_level = DEBUG args, spinner = self.prepare_call(caplog, log_level) result = call_subprocess(args, spinner=spinner) expected = (['Hello', 'world'], [ ('pip.subprocessor', DEBUG, 'Running command '), ('pip.subprocessor', DEBUG, 'Hello'), ('pip.subprocessor', DEBUG, 'world'), ]) # The spinner shouldn't spin in this case since the subprocess # output is already being logged to the console. self.check_result( capfd, caplog, log_level, spinner, result, expected, expected_spinner=(0, None), )
def run_command( self, cmd, # type: List[str] show_stdout=True, # type: bool cwd=None, # type: Optional[str] on_returncode='raise', # type: str extra_ok_returncodes=None, # type: Optional[Iterable[int]] command_desc=None, # type: Optional[str] extra_environ=None, # type: Optional[Mapping[str, Any]] spinner=None # type: Optional[SpinnerInterface] ): # type: (...) -> Optional[Text] """ Run a VCS subcommand This is simply a wrapper around call_subprocess that adds the VCS command name, and checks that the VCS is available """ cmd = [self.name] + cmd try: return call_subprocess(cmd, show_stdout, cwd, on_returncode=on_returncode, extra_ok_returncodes=extra_ok_returncodes, command_desc=command_desc, extra_environ=extra_environ, unset_environ=self.unset_environ, spinner=spinner) except OSError as e: # errno.ENOENT = no such file or directory # In other words, the VCS executable isn't available if e.errno == errno.ENOENT: raise BadCommand( 'Cannot find command %r - do you have ' '%r installed and in your ' 'PATH?' % (self.name, self.name)) else: raise # re-raise exception if a different error occurred
def test_closes_stdin(self): with pytest.raises(InstallationError): call_subprocess( [sys.executable, '-c', 'input()'], show_stdout=True, )
def install(self, install_options, global_options=None, root=None, home=None, prefix=None, warn_script_location=True, use_user_site=False, pycompile=True): global_options = global_options if global_options is not None else [] if self.editable: self.install_editable( install_options, global_options, prefix=prefix, ) return if self.is_wheel: version = wheel.wheel_version(self.source_dir) wheel.check_compatibility(version, self.name) self.move_wheel_files( self.source_dir, root=root, prefix=prefix, home=home, warn_script_location=warn_script_location, use_user_site=use_user_site, pycompile=pycompile, ) self.install_succeeded = True return # Extend the list of global and install options passed on to # the setup.py call with the ones from the requirements file. # Options specified in requirements file override those # specified on the command line, since the last option given # to setup.py is the one that is used. global_options = list(global_options) + \ self.options.get('global_options', []) install_options = list(install_options) + \ self.options.get('install_options', []) if self.isolated: global_options = global_options + ["--no-user-cfg"] with TempDirectory(kind="record") as temp_dir: record_filename = os.path.join(temp_dir.path, 'install-record.txt') install_args = self.get_install_args( global_options, record_filename, root, prefix, pycompile, ) msg = 'Running setup.py install for %s' % (self.name, ) with open_spinner(msg) as spinner: with indent_log(): call_subprocess( install_args + install_options, cwd=self.setup_py_dir, show_stdout=False, spinner=spinner, ) if not os.path.exists(record_filename): logger.debug('Record file %s not found', record_filename) return self.install_succeeded = True def prepend_root(path): if root is None or not os.path.isabs(path): return path else: return change_root(root, path) with open(record_filename) as f: for line in f: directory = os.path.dirname(line) if directory.endswith('.egg-info'): egg_info_dir = prepend_root(directory) break else: logger.warning( 'Could not find .egg-info directory in install record' ' for %s', self, ) # FIXME: put the record somewhere # FIXME: should this be an error? return new_lines = [] with open(record_filename) as f: for line in f: filename = line.strip() if os.path.isdir(filename): filename += os.path.sep new_lines.append( os.path.relpath(prepend_root(filename), egg_info_dir)) new_lines.sort() ensure_dir(egg_info_dir) inst_files_path = os.path.join(egg_info_dir, 'installed-files.txt') with open(inst_files_path, 'w') as f: f.write('\n'.join(new_lines) + '\n')
def install( self, install_options, # type: List[str] global_options=None, # type: Optional[Sequence[str]] root=None, # type: Optional[str] home=None, # type: Optional[str] prefix=None, # type: Optional[str] warn_script_location=True, # type: bool use_user_site=False, # type: bool pycompile=True, # type: bool ): # type: (...) -> None global_options = global_options if global_options is not None else [] if self.editable: self.install_editable( install_options, global_options, prefix=prefix, ) return if self.is_wheel: version = wheel.wheel_version(self.source_dir) wheel.check_compatibility(version, self.name) self.move_wheel_files( self.source_dir, root=root, prefix=prefix, home=home, warn_script_location=warn_script_location, use_user_site=use_user_site, pycompile=pycompile, ) self.install_succeeded = True return # Extend the list of global and install options passed on to # the setup.py call with the ones from the requirements file. # Options specified in requirements file override those # specified on the command line, since the last option given # to setup.py is the one that is used. global_options = list(global_options) + self.options.get( "global_options", []) install_options = list(install_options) + self.options.get( "install_options", []) if self.isolated: # https://github.com/python/mypy/issues/1174 global_options = global_options + ["--no-user-cfg"] # type: ignore with TempDirectory(kind="record") as temp_dir: record_filename = os.path.join(temp_dir.path, "install-record.txt") install_args = self.get_install_args( global_options, record_filename, root, prefix, pycompile, ) msg = "Running setup.py install for %s" % (self.name, ) with open_spinner(msg) as spinner: with indent_log(): with self.build_env: call_subprocess( install_args + install_options, cwd=self.setup_py_dir, spinner=spinner, ) if not os.path.exists(record_filename): logger.debug("Record file %s not found", record_filename) return self.install_succeeded = True def prepend_root(path): # type: (str) -> str if root is None or not os.path.isabs(path): return path else: return change_root(root, path) with open(record_filename) as f: for line in f: directory = os.path.dirname(line) if directory.endswith(".egg-info"): egg_info_dir = prepend_root(directory) break else: logger.warning( "Could not find .egg-info directory in install record" " for %s", self, ) # FIXME: put the record somewhere # FIXME: should this be an error? return new_lines = [] with open(record_filename) as f: for line in f: filename = line.strip() if os.path.isdir(filename): filename += os.path.sep new_lines.append( os.path.relpath(prepend_root(filename), egg_info_dir)) new_lines.sort() ensure_dir(egg_info_dir) inst_files_path = os.path.join(egg_info_dir, "installed-files.txt") with open(inst_files_path, "w") as f: f.write("\n".join(new_lines) + "\n")
def install( self, install_options, # type: List[str] global_options=None, # type: Optional[Sequence[str]] root=None, # type: Optional[str] home=None, # type: Optional[str] prefix=None, # type: Optional[str] warn_script_location=True, # type: bool use_user_site=False, # type: bool pycompile=True # type: bool ): # type: (...) -> None global_options = global_options if global_options is not None else [] if self.editable: self.install_editable( install_options, global_options, prefix=prefix, ) return if self.is_wheel: version = wheel.wheel_version(self.source_dir) wheel.check_compatibility(version, self.name) self.move_wheel_files( self.source_dir, root=root, prefix=prefix, home=home, warn_script_location=warn_script_location, use_user_site=use_user_site, pycompile=pycompile, ) self.install_succeeded = True return # Extend the list of global and install options passed on to # the setup.py call with the ones from the requirements file. # Options specified in requirements file override those # specified on the command line, since the last option given # to setup.py is the one that is used. global_options = list(global_options) + \ self.options.get('global_options', []) install_options = list(install_options) + \ self.options.get('install_options', []) if self.isolated: # https://github.com/python/mypy/issues/1174 global_options = global_options + ["--no-user-cfg"] # type: ignore with TempDirectory(kind="record") as temp_dir: record_filename = os.path.join(temp_dir.path, 'install-record.txt') install_args = self.get_install_args( global_options, record_filename, root, prefix, pycompile, ) msg = 'Running setup.py install for %s' % (self.name,) with open_spinner(msg) as spinner: with indent_log(): with self.build_env: call_subprocess( install_args + install_options, cwd=self.setup_py_dir, spinner=spinner, ) if not os.path.exists(record_filename): logger.debug('Record file %s not found', record_filename) return self.install_succeeded = True def prepend_root(path): if root is None or not os.path.isabs(path): return path else: return change_root(root, path) with open(record_filename) as f: for line in f: directory = os.path.dirname(line) if directory.endswith('.egg-info'): egg_info_dir = prepend_root(directory) break else: logger.warning( 'Could not find .egg-info directory in install record' ' for %s', self, ) # FIXME: put the record somewhere # FIXME: should this be an error? return new_lines = [] with open(record_filename) as f: for line in f: filename = line.strip() if os.path.isdir(filename): filename += os.path.sep new_lines.append( os.path.relpath(prepend_root(filename), egg_info_dir) ) new_lines.sort() ensure_dir(egg_info_dir) inst_files_path = os.path.join(egg_info_dir, 'installed-files.txt') with open(inst_files_path, 'w') as f: f.write('\n'.join(new_lines) + '\n')
def test_call_subprocess_works_okay_when_just_given_nothing(): try: call_subprocess([sys.executable, '-c', 'print("Hello")']) except Exception: assert False, "Expected subprocess call to succeed"
def test_closes_stdin(self): with pytest.raises(InstallationError): call_subprocess( [sys.executable, '-c', 'input()'], show_stdout=True, )
def test_call_subprocess_closes_stdin(): with pytest.raises(InstallationError): call_subprocess([sys.executable, '-c', 'input()'])
def test_call_subprocess_closes_stdin(): with pytest.raises(InstallationError): call_subprocess([sys.executable, '-c', 'input()'])
def run_egg_info(self): assert self.source_dir if self.name: logger.debug( "Running setup.py (path:%s) egg_info for package %s", self.setup_py, self.name, ) else: logger.debug( "Running setup.py (path:%s) egg_info for package from %s", self.setup_py, self.link, ) with indent_log(): script = SETUPTOOLS_SHIM % self.setup_py base_cmd = [sys.executable, "-c", script] if self.isolated: base_cmd += ["--no-user-cfg"] egg_info_cmd = base_cmd + ["egg_info"] # We can't put the .egg-info files at the root, because then the # source code will be mistaken for an installed egg, causing # problems if self.editable: egg_base_option = [] else: egg_info_dir = os.path.join(self.setup_py_dir, "pip-egg-info") ensure_dir(egg_info_dir) egg_base_option = ["--egg-base", "pip-egg-info"] with self.build_env: call_subprocess( egg_info_cmd + egg_base_option, cwd=self.setup_py_dir, show_stdout=False, command_desc="python setup.py egg_info", ) if not self.req: if isinstance(parse_version(self.pkg_info()["Version"]), Version): op = "==" else: op = "===" self.req = Requirement("".join([ self.pkg_info()["Name"], op, self.pkg_info()["Version"], ])) self._correct_build_location() else: metadata_name = canonicalize_name(self.pkg_info()["Name"]) if canonicalize_name(self.req.name) != metadata_name: logger.warning( "Running setup.py (path:%s) egg_info for package %s " "produced metadata for project name %s. Fix your " "#egg=%s fragments.", self.setup_py, self.name, metadata_name, self.name, ) self.req = Requirement(metadata_name)
def test_call_subprocess_works_okay_when_just_given_nothing(): try: call_subprocess([sys.executable, '-c', 'print("Hello")']) except Exception: assert False, "Expected subprocess call to succeed"