Skip to content

Commit

Permalink
Move byte-compilation after installing wheel files
Browse files Browse the repository at this point in the history
There are a few changes here:

1. The byte-compilation now occurs after we copy the root-scheme files
   and files from any wheel data dirs
1. Instead of iterating over the files in the unpacked wheel directory,
   we iterate over the installed files as they exist in the installation
   path
2. In addition to asserting that pyc files were created, we also add
   them to the list of installed files, so they will be included in RECORD

By compiling after installation, we no longer depend on a separate
temporary directory - this brings us closer to installing directly from
wheel files.

By compiling with source files as they exist in the installation output
directory, we no longer generate pyc files with an embedded randomized
temp directory - this means that wheel installs can be deterministic.
  • Loading branch information
chrahunt committed Jul 4, 2020
1 parent 0e9ac94 commit e1e941d
Showing 1 changed file with 25 additions and 26 deletions.
51 changes: 25 additions & 26 deletions src/pip/_internal/operations/install/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,19 +452,6 @@ def install_unpacked_wheel(
changed = set() # type: Set[RecordPath]
generated = [] # type: List[str]

def pyc_source_file_paths():
# type: () -> Iterator[str]
for dir_path, subdir_paths, files in os.walk(source):
subdir_paths[:] = [
p for p in subdir_paths if p != '__pycache__'
]
for path in files:
if not os.path.isfile(path):
continue
if not path.endswith('.py'):
continue
yield os.path.join(dir_path, path)

def pyc_output_path(path):
# type: (str) -> str
"""Return the path the pyc file would have been written to.
Expand All @@ -477,19 +464,6 @@ def pyc_output_path(path):
else:
return importlib.util.cache_from_source(path)

# Compile all of the pyc files that we're going to be installing
if pycompile:
with captured_stdout() as stdout:
with warnings.catch_warnings():
warnings.filterwarnings('ignore')
for path in pyc_source_file_paths():
success = compileall.compile_file(
path, force=True, quiet=True
)
if success:
assert os.path.exists(pyc_output_path(path))
logger.debug(stdout.getvalue())

def record_installed(srcfile, destfile, modified=False):
# type: (text_type, text_type, bool) -> None
"""Map archive RECORD paths to installation RECORD paths."""
Expand Down Expand Up @@ -614,6 +588,31 @@ def is_entrypoint_wrapper(name):
filter=filter,
)

def pyc_source_file_paths():
# type: () -> Iterator[str]
for installed_path in sorted(set(installed.values())):
full_installed_path = os.path.join(lib_dir, installed_path)
if not os.path.isfile(full_installed_path):
continue
if not full_installed_path.endswith('.py'):
continue
yield full_installed_path

# Compile all of the pyc files for the installed files
if pycompile:
with captured_stdout() as stdout:
with warnings.catch_warnings():
warnings.filterwarnings('ignore')
for path in pyc_source_file_paths():
success = compileall.compile_file(
path, force=True, quiet=True
)
if success:
pyc_path = pyc_output_path(path)
assert os.path.exists(pyc_path)
record_installed(pyc_path, pyc_path)
logger.debug(stdout.getvalue())

maker = PipScriptMaker(None, scheme.scripts)

# Ensure old scripts are overwritten.
Expand Down

0 comments on commit e1e941d

Please sign in to comment.