def install_package_no_deps(self, package_or_url: str, pip_args: List[str]) -> str: with animate(f"determining package name from {package_or_url!r}", self.do_animation): old_package_set = self.list_installed_packages() cmd = ["install"] + ["--no-dependencies" ] + pip_args + [package_or_url] pip_process = self._run_pip(cmd) subprocess_post_check(pip_process, raise_error=False) if pip_process.returncode: raise PipxError(f""" Cannot determine package name from spec {package_or_url!r}. Check package spec for errors. """) installed_packages = self.list_installed_packages() - old_package_set if len(installed_packages) == 1: package_name = installed_packages.pop() logger.info(f"Determined package name: {package_name}") else: logger.info(f"old_package_set = {old_package_set}") logger.info(f"install_packages = {installed_packages}") raise PipxError(f""" Cannot determine package name from spec {package_or_url!r}. Check package spec for errors. """) return package_name
def upgrade_package( self, package_name: str, package_or_url: str, pip_args: List[str], include_dependencies: bool, include_apps: bool, is_main_package: bool, suffix: str = "", ) -> None: with animate( f"upgrading {full_package_description(package_name, package_or_url)}", self.do_animation, ): pip_process = self._run_pip(["install"] + pip_args + ["--upgrade", package_or_url]) subprocess_post_check(pip_process) self._update_package_metadata( package_name=package_name, package_or_url=package_or_url, pip_args=pip_args, include_dependencies=include_dependencies, include_apps=include_apps, is_main_package=is_main_package, suffix=suffix, )
def _upgrade_package_no_metadata(self, package: str, pip_args: List[str]) -> None: with animate(f"upgrading {full_package_description(package, package)}", self.do_animation): pip_process = self._run_pip(["install"] + pip_args + ["--upgrade", package]) subprocess_post_check(pip_process)
def create(self, verbose: bool = False) -> None: if not self.is_valid: with animate("creating shared libraries", not verbose): create_process = run_subprocess( [DEFAULT_PYTHON, "-m", "venv", "--clear", self.root]) subprocess_post_check(create_process) # ignore installed packages to ensure no unexpected patches from the OS vendor # are used self.upgrade(pip_args=["--force-reinstall"], verbose=verbose)
def install_package( self, package: str, package_or_url: str, pip_args: List[str], include_dependencies: bool, include_apps: bool, is_main_package: bool, suffix: str = "", ) -> None: if pip_args is None: pip_args = [] # package name in package specifier can mismatch URL due to user error package_or_url = fix_package_name(package_or_url, package) # check syntax and clean up spec and pip_args (package_or_url, pip_args) = parse_specifier_for_install( package_or_url, pip_args ) with animate( f"installing {full_package_description(package, package_or_url)}", self.do_animation, ): cmd = ["install"] + pip_args + [package_or_url] pip_process = self._run_pip(cmd) subprocess_post_check(pip_process, raise_error=False) if pip_process.returncode: raise PipxError( f"Error installing {full_package_description(package, package_or_url)}." ) self._update_package_metadata( package=package, package_or_url=package_or_url, pip_args=pip_args, include_dependencies=include_dependencies, include_apps=include_apps, is_main_package=is_main_package, suffix=suffix, ) # Verify package installed ok if self.package_metadata[package].package_version is None: raise PipxError( f"Unable to install " f"{full_package_description(package, package_or_url)}.\n" f"Check the name or spec for errors, and verify that it can " f"be installed with pip.", wrap_message=False, )
def upgrade(self, *, pip_args: Optional[List[str]] = None, verbose: bool = False) -> None: if not self.is_valid: self.create(verbose=verbose) return # Don't try to upgrade multiple times per run if self.has_been_updated_this_run: logger.info(f"Already upgraded libraries in {self.root}") return if pip_args is None: pip_args = [] logger.info(f"Upgrading shared libraries in {self.root}") ignored_args = ["--editable"] _pip_args = [arg for arg in pip_args if arg not in ignored_args] if not verbose: _pip_args.append("-q") try: with animate("upgrading shared libraries", not verbose): upgrade_process = run_subprocess([ self.python_path, "-m", "pip", "--disable-pip-version-check", "install", *_pip_args, "--upgrade", "pip", "setuptools", "wheel", ]) subprocess_post_check(upgrade_process) self.has_been_updated_this_run = True self.pip_path.touch() except Exception: logger.error("Failed to upgrade shared libraries", exc_info=True)
def create_venv(self, venv_args: List[str], pip_args: List[str]) -> None: with animate("creating virtual environment", self.do_animation): cmd = [self.python, "-m", "venv", "--without-pip"] venv_process = run_subprocess(cmd + venv_args + [str(self.root)]) subprocess_post_check(venv_process) shared_libs.create(self.verbose) pipx_pth = get_site_packages(self.python_path) / PIPX_SHARED_PTH # write path pointing to the shared libs site-packages directory # example pipx_pth location: # ~/.local/pipx/venvs/black/lib/python3.8/site-packages/pipx_shared.pth # example shared_libs.site_packages location: # ~/.local/pipx/shared/lib/python3.6/site-packages # # https://docs.python.org/3/library/site.html # A path configuration file is a file whose name has the form 'name.pth'. # its contents are additional items (one per line) to be added to sys.path pipx_pth.write_text(f"{shared_libs.site_packages}\n", encoding="utf-8") self.pipx_metadata.venv_args = venv_args self.pipx_metadata.python_version = self.get_python_version()