Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions news/12782.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Improve pip install performance by only creating required parent
directories once, instead of before extracting every file in the wheel.
16 changes: 9 additions & 7 deletions src/pip/_internal/operations/install/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,12 +358,6 @@ def _getinfo(self) -> ZipInfo:
return self._zip_file.getinfo(self.src_record_path)

def save(self) -> None:
# directory creation is lazy and after file filtering
# to ensure we don't install empty dirs; empty dirs can't be
# uninstalled.
parent_dir = os.path.dirname(self.dest_path)
ensure_dir(parent_dir)

# When we open the output file below, any existing file is truncated
# before we start writing the new contents. This is fine in most
# cases, but can cause a segfault if pip has loaded a shared
Expand Down Expand Up @@ -421,7 +415,7 @@ def make(
return super().make(specification, options)


def _install_wheel(
def _install_wheel( # noqa: C901, PLR0915 function is too long
name: str,
wheel_zip: ZipFile,
wheel_path: str,
Expand Down Expand Up @@ -580,7 +574,15 @@ def is_entrypoint_wrapper(file: "File") -> bool:
script_scheme_files = map(ScriptFile, script_scheme_files)
files = chain(files, script_scheme_files)

existing_parents = set()
for file in files:
# directory creation is lazy and after file filtering
# to ensure we don't install empty dirs; empty dirs can't be
# uninstalled.
parent_dir = os.path.dirname(file.dest_path)
if parent_dir not in existing_parents:
ensure_dir(parent_dir)
existing_parents.add(parent_dir)
file.save()
record_installed(file.src_record_path, file.dest_path, file.changed)

Expand Down