Skip to content

Commit ea5a1ee

Browse files
committedJun 25, 2024
PERF: faster pip install. algorithmic bug at the end of pip install in the code to display installed packages. O(n^2) to enumerate installed packages due to accidental loop in loop.
get_distribution(package_name) does a loop over all installed packages. that is quite surprising and unexpected. do not use it inside a loop. on a pip install run that takes 11 seconds: the loop takes 0.735 seconds on main branch. the loop takes 0.064 seconds with this fix.
1 parent 00c75c4 commit ea5a1ee

File tree

3 files changed

+14
-9
lines changed

3 files changed

+14
-9
lines changed
 

‎news/12791.bugfix.rst

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improve performance of pip install. Fix code to display installed packages at the end of pip install,
2+
was O(n^2) to enumerate packages due to accidental loop in loop.

‎src/pip/_internal/commands/install.py

+10-8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from optparse import SUPPRESS_HELP, Values
88
from typing import List, Optional
99

10+
from pip._vendor.packaging.utils import canonicalize_name
1011
from pip._vendor.rich import print_json
1112

1213
from pip._internal.cache import WheelCache
@@ -472,16 +473,17 @@ def run(self, options: Values, args: List[str]) -> int:
472473
)
473474
env = get_environment(lib_locations)
474475

476+
# Display a summary of installed packages, with extra care to
477+
# display a package name as it was requested by the user.
475478
installed.sort(key=operator.attrgetter("name"))
476479
items = []
477-
for result in installed:
478-
item = result.name
479-
try:
480-
installed_dist = env.get_distribution(item)
481-
if installed_dist is not None:
482-
item = f"{item}-{installed_dist.version}"
483-
except Exception:
484-
pass
480+
installed_versions = {}
481+
for distribution in env.iter_all_distributions():
482+
installed_versions[distribution.canonical_name] = distribution.version
483+
for package in installed:
484+
display_name = package.name
485+
version = installed_versions.get(canonicalize_name(display_name), None)
486+
item = f"{display_name}-{version}"
485487
items.append(item)
486488

487489
if conflicts is not None:

‎src/pip/_internal/metadata/importlib/_envs.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,10 @@ def _iter_distributions(self) -> Iterator[BaseDistribution]:
181181
yield from finder.find_linked(location)
182182

183183
def get_distribution(self, name: str) -> Optional[BaseDistribution]:
184+
canonical_name = canonicalize_name(name)
184185
matches = (
185186
distribution
186187
for distribution in self.iter_all_distributions()
187-
if distribution.canonical_name == canonicalize_name(name)
188+
if distribution.canonical_name == canonical_name
188189
)
189190
return next(matches, None)

0 commit comments

Comments
 (0)