__init__.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. from __future__ import annotations
  2. import collections
  3. import logging
  4. from collections.abc import Generator
  5. from dataclasses import dataclass
  6. from pip._internal.cli.progress_bars import BarType, get_install_progress_renderer
  7. from pip._internal.utils.logging import indent_log
  8. from .req_file import parse_requirements
  9. from .req_install import InstallRequirement
  10. from .req_set import RequirementSet
  11. __all__ = [
  12. "RequirementSet",
  13. "InstallRequirement",
  14. "parse_requirements",
  15. "install_given_reqs",
  16. ]
  17. logger = logging.getLogger(__name__)
  18. @dataclass(frozen=True)
  19. class InstallationResult:
  20. name: str
  21. def _validate_requirements(
  22. requirements: list[InstallRequirement],
  23. ) -> Generator[tuple[str, InstallRequirement], None, None]:
  24. for req in requirements:
  25. assert req.name, f"invalid to-be-installed requirement: {req}"
  26. yield req.name, req
  27. def install_given_reqs(
  28. requirements: list[InstallRequirement],
  29. root: str | None,
  30. home: str | None,
  31. prefix: str | None,
  32. warn_script_location: bool,
  33. use_user_site: bool,
  34. pycompile: bool,
  35. progress_bar: BarType,
  36. ) -> list[InstallationResult]:
  37. """
  38. Install everything in the given list.
  39. (to be called after having downloaded and unpacked the packages)
  40. """
  41. to_install = collections.OrderedDict(_validate_requirements(requirements))
  42. if to_install:
  43. logger.info(
  44. "Installing collected packages: %s",
  45. ", ".join(to_install.keys()),
  46. )
  47. installed = []
  48. show_progress = logger.isEnabledFor(logging.INFO) and len(to_install) > 1
  49. items = iter(to_install.values())
  50. if show_progress:
  51. renderer = get_install_progress_renderer(
  52. bar_type=progress_bar, total=len(to_install)
  53. )
  54. items = renderer(items)
  55. with indent_log():
  56. for requirement in items:
  57. req_name = requirement.name
  58. assert req_name is not None
  59. if requirement.should_reinstall:
  60. logger.info("Attempting uninstall: %s", req_name)
  61. with indent_log():
  62. uninstalled_pathset = requirement.uninstall(auto_confirm=True)
  63. else:
  64. uninstalled_pathset = None
  65. try:
  66. requirement.install(
  67. root=root,
  68. home=home,
  69. prefix=prefix,
  70. warn_script_location=warn_script_location,
  71. use_user_site=use_user_site,
  72. pycompile=pycompile,
  73. )
  74. except Exception:
  75. # if install did not succeed, rollback previous uninstall
  76. if uninstalled_pathset and not requirement.install_succeeded:
  77. uninstalled_pathset.rollback()
  78. raise
  79. else:
  80. if uninstalled_pathset and requirement.install_succeeded:
  81. uninstalled_pathset.commit()
  82. installed.append(InstallationResult(req_name))
  83. return installed