summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnderson Bravalheri <andersonbravalheri@gmail.com>2022-06-21 11:09:22 +0100
committerAnderson Bravalheri <andersonbravalheri@gmail.com>2022-06-21 11:37:13 +0100
commitfd5fcbb1ec200ba2b0c657628a591ce2255998e3 (patch)
treee4c20ee26e15647978b9f0102d8d27d11197840a
parentfd891afb3020eceab6d8528dfbc0d844865361d4 (diff)
downloadpython-setuptools-git-fd5fcbb1ec200ba2b0c657628a591ce2255998e3.tar.gz
build_meta: Allow dist-info and egg-info to coexist
PEP 517 does not care if other directories/files are left behind in the `metadata_directory`, as long as a `.dist_info` directory is produced at the root. We can leave the `.egg-info` directory behind, so this way we don't have to run it again when listing files from `build_py`.
-rw-r--r--setuptools/_path.py22
-rw-r--r--setuptools/build_meta.py47
-rw-r--r--setuptools/config/expand.py21
3 files changed, 45 insertions, 45 deletions
diff --git a/setuptools/_path.py b/setuptools/_path.py
index ede9cb00..3767523b 100644
--- a/setuptools/_path.py
+++ b/setuptools/_path.py
@@ -1,7 +1,29 @@
import os
+from typing import Union
+
+_Path = Union[str, os.PathLike]
def ensure_directory(path):
"""Ensure that the parent directory of `path` exists"""
dirname = os.path.dirname(path)
os.makedirs(dirname, exist_ok=True)
+
+
+def same_path(p1: _Path, p2: _Path) -> bool:
+ """Differs from os.path.samefile because it does not require paths to exist.
+ Purely string based (no comparison between i-nodes).
+ >>> same_path("a/b", "./a/b")
+ True
+ >>> same_path("a/b", "a/./b")
+ True
+ >>> same_path("a/b", "././a/b")
+ True
+ >>> same_path("a/b", "./a/b/c/..")
+ True
+ >>> same_path("a/b", "../a/b/c")
+ False
+ >>> same_path("a", "a/b")
+ False
+ """
+ return os.path.normpath(p1) == os.path.normpath(p2)
diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py
index f39a5a62..8e2af261 100644
--- a/setuptools/build_meta.py
+++ b/setuptools/build_meta.py
@@ -40,6 +40,7 @@ from typing import Dict, Iterator, List, Optional, Union
import setuptools
import distutils
+from ._path import same_path
from ._reqs import parse_strings
from ._deprecation_warning import SetuptoolsDeprecationWarning
from distutils.util import strtobool
@@ -341,6 +342,23 @@ class _BuildMetaBackend(_ConfigSettingsTranslator):
def get_requires_for_build_sdist(self, config_settings=None):
return self._get_build_requires(config_settings, requirements=[])
+ def _bubble_up_info_directory(self, metadata_directory: str, suffix: str) -> str:
+ """
+ PEP 517 requires that the .dist-info directory be placed in the
+ metadata_directory. To comply, we MUST copy the directory to the root.
+
+ Returns the basename of the info directory, e.g. `proj-0.0.0.dist-info`.
+ """
+ candidates = list(Path(metadata_directory).glob(f"**/*{suffix}/"))
+ assert len(candidates) == 1, f"Exactly one {suffix} should have been produced"
+ info_dir = candidates[0]
+
+ if not same_path(info_dir.parent, metadata_directory):
+ shutil.move(str(info_dir), metadata_directory)
+ # PEP 517 allow other files and dirs to exist in metadata_directory
+
+ return info_dir.name
+
def prepare_metadata_for_build_wheel(self, metadata_directory,
config_settings=None):
sys.argv = [
@@ -348,36 +366,13 @@ class _BuildMetaBackend(_ConfigSettingsTranslator):
*self._global_args(config_settings),
"dist_info",
"--output-dir", metadata_directory,
+ "--keep-egg-info",
]
with no_install_setup_requires():
self.run_setup()
- dist_info_directory = metadata_directory
- while True:
- dist_infos = [f for f in os.listdir(dist_info_directory)
- if f.endswith('.dist-info')]
-
- if (
- len(dist_infos) == 0 and
- len(_get_immediate_subdirectories(dist_info_directory)) == 1
- ):
-
- dist_info_directory = os.path.join(
- dist_info_directory, os.listdir(dist_info_directory)[0])
- continue
-
- assert len(dist_infos) == 1
- break
-
- # PEP 517 requires that the .dist-info directory be placed in the
- # metadata_directory. To comply, we MUST copy the directory to the root
- if dist_info_directory != metadata_directory:
- shutil.move(
- os.path.join(dist_info_directory, dist_infos[0]),
- metadata_directory)
- shutil.rmtree(dist_info_directory, ignore_errors=True)
-
- return dist_infos[0]
+ self._bubble_up_info_directory(metadata_directory, ".egg-info")
+ return self._bubble_up_info_directory(metadata_directory, ".dist-info")
def _build_with_temp_dir(self, setup_command, result_extension,
result_directory, config_settings):
diff --git a/setuptools/config/expand.py b/setuptools/config/expand.py
index da55d4ee..6ea54969 100644
--- a/setuptools/config/expand.py
+++ b/setuptools/config/expand.py
@@ -43,6 +43,8 @@ from types import ModuleType
from distutils.errors import DistutilsOptionError
+from .._path import same_path as _same_path
+
if TYPE_CHECKING:
from setuptools.dist import Distribution # noqa
from setuptools.discovery import ConfigDiscovery # noqa
@@ -330,25 +332,6 @@ def find_packages(
return packages
-def _same_path(p1: _Path, p2: _Path) -> bool:
- """Differs from os.path.samefile because it does not require paths to exist.
- Purely string based (no comparison between i-nodes).
- >>> _same_path("a/b", "./a/b")
- True
- >>> _same_path("a/b", "a/./b")
- True
- >>> _same_path("a/b", "././a/b")
- True
- >>> _same_path("a/b", "./a/b/c/..")
- True
- >>> _same_path("a/b", "../a/b/c")
- False
- >>> _same_path("a", "a/b")
- False
- """
- return os.path.normpath(p1) == os.path.normpath(p2)
-
-
def _nest_path(parent: _Path, path: _Path) -> str:
path = parent if path in {".", ""} else os.path.join(parent, path)
return os.path.normpath(path)