From 2b5e87cd3796b7d8ab575eacf3f817f7cea04d31 Mon Sep 17 00:00:00 2001 From: Pradyun Gedam Date: Sat, 2 Nov 2019 20:11:30 +0530 Subject: [PATCH 1/3] Move operations.{generate_metadata -> build.metadata} --- src/pip/_internal/operations/build/__init__.py | 0 .../operations/{generate_metadata.py => build/metadata.py} | 0 src/pip/_internal/req/req_install.py | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 src/pip/_internal/operations/build/__init__.py rename src/pip/_internal/operations/{generate_metadata.py => build/metadata.py} (100%) diff --git a/src/pip/_internal/operations/build/__init__.py b/src/pip/_internal/operations/build/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/pip/_internal/operations/generate_metadata.py b/src/pip/_internal/operations/build/metadata.py similarity index 100% rename from src/pip/_internal/operations/generate_metadata.py rename to src/pip/_internal/operations/build/metadata.py diff --git a/src/pip/_internal/req/req_install.py b/src/pip/_internal/req/req_install.py index f47bbbf0f..168204e07 100644 --- a/src/pip/_internal/req/req_install.py +++ b/src/pip/_internal/req/req_install.py @@ -24,7 +24,7 @@ from pip._internal.build_env import NoOpBuildEnvironment from pip._internal.exceptions import InstallationError from pip._internal.locations import distutils_scheme from pip._internal.models.link import Link -from pip._internal.operations.generate_metadata import get_metadata_generator +from pip._internal.operations.build.metadata import get_metadata_generator from pip._internal.pyproject import load_pyproject_toml, make_pyproject_path from pip._internal.req.req_uninstall import UninstallPathSet from pip._internal.utils.compat import native_str From 3f76f5702b1a0387eb1c14ab9663af3dc4a1997e Mon Sep 17 00:00:00 2001 From: Pradyun Gedam Date: Sat, 2 Nov 2019 20:19:44 +0530 Subject: [PATCH 2/3] Move logic and imports for legacy metadata generation --- .../_internal/operations/build/metadata.py | 111 +--------------- .../operations/build/metadata_legacy.py | 120 ++++++++++++++++++ 2 files changed, 124 insertions(+), 107 deletions(-) create mode 100644 src/pip/_internal/operations/build/metadata_legacy.py diff --git a/src/pip/_internal/operations/build/metadata.py b/src/pip/_internal/operations/build/metadata.py index 04e5ace12..6bb132f81 100644 --- a/src/pip/_internal/operations/build/metadata.py +++ b/src/pip/_internal/operations/build/metadata.py @@ -5,19 +5,15 @@ import atexit 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, - runner_with_spinner_message, +from pip._internal.operations.build.metadata_legacy import ( + _generate_metadata_legacy, ) +from pip._internal.utils.subprocess import runner_with_spinner_message 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 Callable, List, Optional + from typing import Callable from pip._internal.req.req_install import InstallRequirement @@ -38,105 +34,6 @@ def get_metadata_generator(install_req): return _generate_metadata -def _find_egg_info(source_directory, is_editable): - # type: (str, bool) -> str - """Find an .egg-info in `source_directory`, based on `is_editable`. - """ - - 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_editable_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 - if is_editable: - filenames = locate_editable_egg_info(base) - else: - base = os.path.join(base, 'pip-egg-info') - filenames = os.listdir(base) - - if not filenames: - raise InstallationError( - "Files/directories not found in {}".format(base) - ) - - # 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) - - return os.path.join(base, filenames[0]) - - -def _generate_metadata_legacy(install_req): - # type: (InstallRequirement) -> str - req_details_str = install_req.name or "from {}".format(install_req.link) - logger.debug( - 'Running setup.py (path:%s) egg_info for package %s', - install_req.setup_py_path, req_details_str, - ) - - 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 install_req.editable: - egg_info_dir = os.path.join( - install_req.unpacked_source_directory, 'pip-egg-info', - ) - - # setuptools complains if the target directory does not exist. - ensure_dir(egg_info_dir) - - args = make_setuptools_egg_info_args( - install_req.setup_py_path, - egg_info_dir=egg_info_dir, - no_user_config=install_req.isolated, - ) - - with install_req.build_env: - call_subprocess( - args, - cwd=install_req.unpacked_source_directory, - command_desc='python setup.py egg_info', - ) - - # Return the .egg-info directory. - return _find_egg_info( - install_req.unpacked_source_directory, - install_req.editable, - ) - - def _generate_metadata(install_req): # type: (InstallRequirement) -> str assert install_req.pep517_backend is not None diff --git a/src/pip/_internal/operations/build/metadata_legacy.py b/src/pip/_internal/operations/build/metadata_legacy.py new file mode 100644 index 000000000..4d8d1cf23 --- /dev/null +++ b/src/pip/_internal/operations/build/metadata_legacy.py @@ -0,0 +1,120 @@ +"""Metadata generation logic for legacy source distributions. +""" + +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.typing import MYPY_CHECK_RUNNING +from pip._internal.vcs import vcs + +if MYPY_CHECK_RUNNING: + from typing import List, Optional + + from pip._internal.req.req_install import InstallRequirement + +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 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_editable_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 + if is_editable: + filenames = locate_editable_egg_info(base) + else: + base = os.path.join(base, 'pip-egg-info') + filenames = os.listdir(base) + + if not filenames: + raise InstallationError( + "Files/directories not found in {}".format(base) + ) + + # 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) + + return os.path.join(base, filenames[0]) + + +def _generate_metadata_legacy(install_req): + # type: (InstallRequirement) -> str + assert install_req.unpacked_source_directory + + req_details_str = install_req.name or "from {}".format(install_req.link) + logger.debug( + 'Running setup.py (path:%s) egg_info for package %s', + install_req.setup_py_path, req_details_str, + ) + + 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 install_req.editable: + egg_info_dir = os.path.join( + install_req.unpacked_source_directory, 'pip-egg-info', + ) + + # setuptools complains if the target directory does not exist. + ensure_dir(egg_info_dir) + + args = make_setuptools_egg_info_args( + install_req.setup_py_path, + egg_info_dir=egg_info_dir, + no_user_config=install_req.isolated, + ) + + with install_req.build_env: + call_subprocess( + args, + cwd=install_req.unpacked_source_directory, + command_desc='python setup.py egg_info', + ) + + # Return the .egg-info directory. + return _find_egg_info( + install_req.unpacked_source_directory, + install_req.editable, + ) From bebd69173b2eec1ecc263a12e6fefefa45d76fa4 Mon Sep 17 00:00:00 2001 From: Pradyun Gedam Date: Sat, 2 Nov 2019 20:21:01 +0530 Subject: [PATCH 3/3] Rename _generate_metadata_legacy -> generate_metadata Why: To avoid importing an _name. --- src/pip/_internal/operations/build/metadata.py | 5 ++--- src/pip/_internal/operations/build/metadata_legacy.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pip/_internal/operations/build/metadata.py b/src/pip/_internal/operations/build/metadata.py index 6bb132f81..66b59eb51 100644 --- a/src/pip/_internal/operations/build/metadata.py +++ b/src/pip/_internal/operations/build/metadata.py @@ -5,9 +5,8 @@ import atexit import logging import os -from pip._internal.operations.build.metadata_legacy import ( - _generate_metadata_legacy, -) +from pip._internal.operations.build.metadata_legacy import \ + generate_metadata as _generate_metadata_legacy from pip._internal.utils.subprocess import runner_with_spinner_message from pip._internal.utils.temp_dir import TempDirectory from pip._internal.utils.typing import MYPY_CHECK_RUNNING diff --git a/src/pip/_internal/operations/build/metadata_legacy.py b/src/pip/_internal/operations/build/metadata_legacy.py index 4d8d1cf23..ba6265db7 100644 --- a/src/pip/_internal/operations/build/metadata_legacy.py +++ b/src/pip/_internal/operations/build/metadata_legacy.py @@ -78,7 +78,7 @@ def _find_egg_info(source_directory, is_editable): return os.path.join(base, filenames[0]) -def _generate_metadata_legacy(install_req): +def generate_metadata(install_req): # type: (InstallRequirement) -> str assert install_req.unpacked_source_directory