From 1983ef0edc61fb71960d6b2caf2d0a6baa83ae0e Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Tue, 4 May 2021 16:50:52 +0800 Subject: [PATCH 1/2] Better diagnose when setup.py/cfg cannot be found This adds a check before invoking 'egg_info' to make sure either setup.py or setup.cfg actually exists, and emit a clearer error message when neither can be found and the egg_info command can never succeed. --- news/9944.bugfix.rst | 2 ++ src/pip/_internal/req/req_install.py | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 news/9944.bugfix.rst diff --git a/news/9944.bugfix.rst b/news/9944.bugfix.rst new file mode 100644 index 00000000000..58bb70b78f3 --- /dev/null +++ b/news/9944.bugfix.rst @@ -0,0 +1,2 @@ +Emit clearer error message when a project root does not contain either +``pyproject.toml``, ``setup.py`` or ``setup.cfg``. diff --git a/src/pip/_internal/req/req_install.py b/src/pip/_internal/req/req_install.py index 55c17ac8b45..c2eea37123e 100644 --- a/src/pip/_internal/req/req_install.py +++ b/src/pip/_internal/req/req_install.py @@ -509,6 +509,19 @@ def load_pyproject_toml(self): self.unpacked_source_directory, backend, backend_path=backend_path, ) + def _check_setup_py_or_cfg_exists(self) -> bool: + """Check if the requirement actually has a setuptools build file. + + If setup.py does not exist, we also check setup.cfg in the same + directory and allow the directory if that exists. + """ + if os.path.exists(self.setup_py_path): + return True + stem, ext = os.path.splitext(self.setup_py_path) + if ext == ".py" and os.path.exists(f"{stem}.cfg"): + return True + return False + def _generate_metadata(self): # type: () -> str """Invokes metadata generator functions, with the required arguments. @@ -516,6 +529,12 @@ def _generate_metadata(self): if not self.use_pep517: assert self.unpacked_source_directory + if not self._check_setup_py_or_cfg_exists(): + raise InstallationError( + f'File "setup.py" or "setup.cfg" not found for legacy ' + f'project {self}.' + ) + return generate_metadata_legacy( build_env=self.build_env, setup_py_path=self.setup_py_path, From 1904e4d66da3cdc0f853dc9c9c99efffe3ca243b Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Tue, 11 May 2021 21:48:22 +0800 Subject: [PATCH 2/2] Relax installable dir check to allow cfg-only --- src/pip/_internal/utils/misc.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/pip/_internal/utils/misc.py b/src/pip/_internal/utils/misc.py index 26037dbdcbb..a4ad35be61c 100644 --- a/src/pip/_internal/utils/misc.py +++ b/src/pip/_internal/utils/misc.py @@ -269,18 +269,14 @@ def tabulate(rows): return table, sizes -def is_installable_dir(path): - # type: (str) -> bool - """Is path is a directory containing setup.py or pyproject.toml?""" +def is_installable_dir(path: str) -> bool: + """Is path is a directory containing pyproject.toml, setup.cfg or setup.py?""" if not os.path.isdir(path): return False - setup_py = os.path.join(path, "setup.py") - if os.path.isfile(setup_py): - return True - pyproject_toml = os.path.join(path, "pyproject.toml") - if os.path.isfile(pyproject_toml): - return True - return False + return any( + os.path.isfile(os.path.join(path, signifier)) + for signifier in ("pyproject.toml", "setup.cfg", "setup.py") + ) def read_chunks(file, size=io.DEFAULT_BUFFER_SIZE):