From bf8e6bc7853f1f014e20def4f7e994ba926d8e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Sat, 4 Apr 2020 11:32:58 +0200 Subject: [PATCH 1/4] Generate legacy metadata in temporary directory Before it was generated in a pip-egg-info subdirectory of the source dir. This will avoid polluting source dir when we build in place. --- .../operations/build/metadata_legacy.py | 27 +++++++++---------- src/pip/_internal/req/req_install.py | 2 -- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/pip/_internal/operations/build/metadata_legacy.py b/src/pip/_internal/operations/build/metadata_legacy.py index b6813f89b..5e23ccf8e 100644 --- a/src/pip/_internal/operations/build/metadata_legacy.py +++ b/src/pip/_internal/operations/build/metadata_legacy.py @@ -5,9 +5,9 @@ import logging import os from pip._internal.exceptions import InstallationError -from pip._internal.utils.misc import ensure_dir from pip._internal.utils.setuptools_build import make_setuptools_egg_info_args from pip._internal.utils.subprocess import call_subprocess +from pip._internal.utils.temp_dir import TempDirectory from pip._internal.utils.typing import MYPY_CHECK_RUNNING from pip._internal.vcs import vcs @@ -19,9 +19,9 @@ if MYPY_CHECK_RUNNING: logger = logging.getLogger(__name__) -def _find_egg_info(source_directory, is_editable): - # type: (str, bool) -> str - """Find an .egg-info in `source_directory`, based on `is_editable`. +def _find_egg_info(source_directory): + # type: (str) -> str + """Find an .egg-info in `source_directory`. """ def looks_like_virtual_env(path): @@ -31,7 +31,7 @@ def _find_egg_info(source_directory, is_editable): os.path.exists(os.path.join(path, 'Scripts', 'Python.exe')) ) - def locate_editable_egg_info(base): + def locate_egg_info(base): # type: (str) -> List[str] candidates = [] # type: List[str] for root, dirs, files in os.walk(base): @@ -58,11 +58,7 @@ def _find_egg_info(source_directory, is_editable): ) base = source_directory - if is_editable: - filenames = locate_editable_egg_info(base) - else: - base = os.path.join(base, 'pip-egg-info') - filenames = os.listdir(base) + filenames = locate_egg_info(base) if not filenames: raise InstallationError( @@ -101,9 +97,9 @@ def generate_metadata( # to avoid confusion due to the source code being considered an installed # egg. if not editable: - egg_info_dir = os.path.join(source_dir, 'pip-egg-info') - # setuptools complains if the target directory does not exist. - ensure_dir(egg_info_dir) + egg_info_dir = TempDirectory( + kind="pip-egg-info", globally_managed=True + ).path args = make_setuptools_egg_info_args( setup_py_path, @@ -119,4 +115,7 @@ def generate_metadata( ) # Return the .egg-info directory. - return _find_egg_info(source_dir, editable) + if not editable: + assert egg_info_dir + return _find_egg_info(egg_info_dir) + return _find_egg_info(source_dir) diff --git a/src/pip/_internal/req/req_install.py b/src/pip/_internal/req/req_install.py index 44c29d1b5..985c31fd6 100644 --- a/src/pip/_internal/req/req_install.py +++ b/src/pip/_internal/req/req_install.py @@ -729,8 +729,6 @@ class InstallRequirement(object): os.path.abspath(self.unpacked_source_directory) ) for dirpath, dirnames, filenames in os.walk(dir): - if 'pip-egg-info' in dirnames: - dirnames.remove('pip-egg-info') for dirname in dirnames: dir_arcname = self._get_archive_name( dirname, parentdir=dirpath, rootdir=dir, From da2ab6b829969bfbac37cc9098e594b4f32f98cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Sun, 5 Apr 2020 11:21:38 +0200 Subject: [PATCH 2/4] Simplify legacy metadata generation Always generate legacy metadata in a temporary directory, even in the editable case. Generating it in the source directory did not add value, because setup.py develop always regenerates the .egg-info directory. --- .../operations/build/metadata_legacy.py | 75 ++++--------------- 1 file changed, 16 insertions(+), 59 deletions(-) diff --git a/src/pip/_internal/operations/build/metadata_legacy.py b/src/pip/_internal/operations/build/metadata_legacy.py index 5e23ccf8e..6edc66b36 100644 --- a/src/pip/_internal/operations/build/metadata_legacy.py +++ b/src/pip/_internal/operations/build/metadata_legacy.py @@ -9,69 +9,34 @@ from pip._internal.utils.setuptools_build import make_setuptools_egg_info_args from pip._internal.utils.subprocess import call_subprocess from pip._internal.utils.temp_dir import TempDirectory from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.vcs import vcs if MYPY_CHECK_RUNNING: - from typing import List, Optional - from pip._internal.build_env import BuildEnvironment logger = logging.getLogger(__name__) -def _find_egg_info(source_directory): +def _find_egg_info(directory): # type: (str) -> str - """Find an .egg-info in `source_directory`. + """Find an .egg-info subdirectory in `directory`. """ - - def looks_like_virtual_env(path): - # type: (str) -> bool - return ( - os.path.lexists(os.path.join(path, 'bin', 'python')) or - os.path.exists(os.path.join(path, 'Scripts', 'Python.exe')) - ) - - def locate_egg_info(base): - # type: (str) -> List[str] - candidates = [] # type: List[str] - for root, dirs, files in os.walk(base): - for dir_ in vcs.dirnames: - if dir_ in dirs: - dirs.remove(dir_) - # Iterate over a copy of ``dirs``, since mutating - # a list while iterating over it can cause trouble. - # (See https://github.com/pypa/pip/pull/462.) - for dir_ in list(dirs): - if looks_like_virtual_env(os.path.join(root, dir_)): - dirs.remove(dir_) - # Also don't search through tests - elif dir_ == 'test' or dir_ == 'tests': - dirs.remove(dir_) - candidates.extend(os.path.join(root, dir_) for dir_ in dirs) - return [f for f in candidates if f.endswith('.egg-info')] - - def depth_of_directory(dir_): - # type: (str) -> int - return ( - dir_.count(os.path.sep) + - (os.path.altsep and dir_.count(os.path.altsep) or 0) - ) - - base = source_directory - filenames = locate_egg_info(base) + filenames = [ + f for f in os.listdir(directory) if f.endswith(".egg-info") + ] if not filenames: raise InstallationError( - "Files/directories not found in {}".format(base) + "No .egg-info directory found in {}".format(directory) ) - # If we have more than one match, we pick the toplevel one. This - # can easily be the case if there is a dist folder which contains - # an extracted tarball for testing purposes. if len(filenames) > 1: - filenames.sort(key=depth_of_directory) + raise InstallationError( + "More than one .egg-info directory found in {}".format( + directory + ) + ) - return os.path.join(base, filenames[0]) + return os.path.join(directory, filenames[0]) def generate_metadata( @@ -92,14 +57,9 @@ def generate_metadata( setup_py_path, details, ) - egg_info_dir = None # type: Optional[str] - # For non-editable installs, don't put the .egg-info files at the root, - # to avoid confusion due to the source code being considered an installed - # egg. - if not editable: - egg_info_dir = TempDirectory( - kind="pip-egg-info", globally_managed=True - ).path + egg_info_dir = TempDirectory( + kind="pip-egg-info", globally_managed=True + ).path args = make_setuptools_egg_info_args( setup_py_path, @@ -115,7 +75,4 @@ def generate_metadata( ) # Return the .egg-info directory. - if not editable: - assert egg_info_dir - return _find_egg_info(egg_info_dir) - return _find_egg_info(source_dir) + return _find_egg_info(egg_info_dir) From 34adf0a258f2e51db9b82c37fee067d86e6b96cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Sun, 5 Apr 2020 11:22:24 +0200 Subject: [PATCH 3/4] Simplify make_setuptools_egg_info_args --- src/pip/_internal/utils/setuptools_build.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pip/_internal/utils/setuptools_build.py b/src/pip/_internal/utils/setuptools_build.py index 4147a650d..2a664b007 100644 --- a/src/pip/_internal/utils/setuptools_build.py +++ b/src/pip/_internal/utils/setuptools_build.py @@ -121,9 +121,9 @@ def make_setuptools_egg_info_args( no_user_config, # type: bool ): # type: (...) -> List[str] - args = make_setuptools_shim_args(setup_py_path) - if no_user_config: - args += ["--no-user-cfg"] + args = make_setuptools_shim_args( + setup_py_path, no_user_config=no_user_config + ) args += ["egg_info"] From 030578ef04bf6ea35a0ccd2acc0ca61a2fe5c050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Tue, 7 Apr 2020 17:00:11 +0200 Subject: [PATCH 4/4] Remove unused argument from generate_metadata --- src/pip/_internal/operations/build/metadata_legacy.py | 1 - src/pip/_internal/req/req_install.py | 1 - 2 files changed, 2 deletions(-) diff --git a/src/pip/_internal/operations/build/metadata_legacy.py b/src/pip/_internal/operations/build/metadata_legacy.py index 6edc66b36..14762aef3 100644 --- a/src/pip/_internal/operations/build/metadata_legacy.py +++ b/src/pip/_internal/operations/build/metadata_legacy.py @@ -43,7 +43,6 @@ def generate_metadata( build_env, # type: BuildEnvironment setup_py_path, # type: str source_dir, # type: str - editable, # type: bool isolated, # type: bool details, # type: str ): diff --git a/src/pip/_internal/req/req_install.py b/src/pip/_internal/req/req_install.py index 985c31fd6..906058f7d 100644 --- a/src/pip/_internal/req/req_install.py +++ b/src/pip/_internal/req/req_install.py @@ -516,7 +516,6 @@ class InstallRequirement(object): build_env=self.build_env, setup_py_path=self.setup_py_path, source_dir=self.unpacked_source_directory, - editable=self.editable, isolated=self.isolated, details=self.name or "from {}".format(self.link) )