def package_name_from_spec(package_spec: str, python: str, *, pip_args: List[str], verbose: bool) -> str: start_time = time.time() # shortcut if valid PyPI name pypi_name = valid_pypi_name(package_spec) if pypi_name is not None: # NOTE: if pypi name and installed package name differ, this means pipx # will use the pypi name package_name = pypi_name logging.info(f"Determined package name: {package_name}") logging.info( f"Package name determined in {time.time()-start_time:.1f}s") return package_name # check syntax and clean up spec and pip_args (package_spec, pip_args) = parse_specifier_for_install(package_spec, pip_args) with tempfile.TemporaryDirectory() as temp_venv_dir: venv = Venv(Path(temp_venv_dir), python=python, verbose=verbose) venv.create_venv(venv_args=[], pip_args=[]) package_name = venv.install_package_no_deps( package_or_url=package_spec, pip_args=pip_args) logging.info(f"Package name determined in {time.time()-start_time:.1f}s") return package_name
def install_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: # package_name in package specifier can mismatch URL due to user error package_or_url = fix_package_name(package_or_url, package_name) # 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_name, package_or_url)}", self.do_animation, ): # do not use -q with `pip install` so subprocess_post_check_pip_errors # has more information to analyze in case of failure. cmd = ([str(self.python_path), "-m", "pip", "install"] + pip_args + [package_or_url]) # no logging because any errors will be specially logged by # subprocess_post_check_handle_pip_error() pip_process = run_subprocess(cmd, log_stdout=False, log_stderr=False) subprocess_post_check_handle_pip_error(pip_process) if pip_process.returncode: raise PipxError( f"Error installing {full_package_description(package_name, package_or_url)}." ) 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, ) # Verify package installed ok if self.package_metadata[package_name].package_version is None: raise PipxError( f"Unable to install " f"{full_package_description(package_name, 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 test_parse_specifier_for_install( caplog, package_spec_in, pip_args_in, package_spec_expected, pip_args_expected, warning_str, ): [package_or_url_out, pip_args_out] = parse_specifier_for_install(package_spec_in, pip_args_in) if warning_str is not None: assert warning_str in caplog.text
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 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 = [] # check syntax and clean up spec and pip_args (package_or_url, pip_args) = parse_specifier_for_install(package_or_url, pip_args) try: with animate( f"installing {full_package_description(package, package_or_url)}", self.do_animation, ): cmd = ["install"] + pip_args + [package_or_url] self._run_pip(cmd) except PipxError as e: logging.info(e) raise PipxError( f"Error installing " f"{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.")