Repository: python-poetry/poetry

Issue:
Dependencies of Git Dependencies are not always installed
### Description

Adding `https://github.com/kubernetes-client/python` as a dependency via git does not install its dependencies. Using pip directly installs dependencies, as does installing the package from pypi.


### Workarounds

Manually copying dependencies to pyproject.toml


### Poetry Installation Method

pipx

### Operating System

Debian GNU/Linux 12 (bookworm)

### Poetry Version

Poetry (version 1.8.1)

### Poetry Configuration

```bash session
cache-dir = "/home/andrew/.cache/pypoetry"
experimental.system-git-client = false
installer.max-workers = null
installer.modern-installation = true
installer.no-binary = null
installer.parallel = true
keyring.enabled = true
solver.lazy-wheel = true
virtualenvs.create = true
virtualenvs.in-project = null
virtualenvs.options.always-copy = false
virtualenvs.options.no-pip = false
virtualenvs.options.no-setuptools = false
virtualenvs.options.system-site-packages = false
virtualenvs.path = "{cache-dir}/virtualenvs"  # /home/andrew/.cache/pypoetry/virtualenvs
virtualenvs.prefer-active-python = false
virtualenvs.prompt = "{project_name}-py{python_version}"
warnings.export = true
```


### Python Sysconfig

_No response_

### Example pyproject.toml

```TOML
[tool.poetry]
name = "git-deps-issue"
version = "0.1.0"
description = ""
authors = ["Someone <someone@example.com>"]

[tool.poetry.dependencies]
python = "^3.8"
kubernetes = {git = "https://github.com/kubernetes-client/python"}

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
```


### Poetry Runtime Logs

```bash session
# poetry -vvv install
Loading configuration file /home/andrew/.config/pypoetry/config.toml
Creating virtualenv git-deps-issue-5ERwWHeK-py3.11 in /home/andrew/.cache/pypoetry/virtualenvs
[virtualenv] find interpreter for spec PythonSpec(path=/home/andrew/.local/pipx/venvs/poetry/bin/python)
[filelock:filelock] Attempting to acquire lock 139883611697616 on /home/andrew/.local/share/virtualenv/py_info/1/ca3ed784184f1b3bb7c3539bfb45e71710cd27667424f92c2d5bb4df9c107c23.lock
[filelock:filelock] Lock 139883611697616 acquired on /home/andrew/.local/share/virtualenv/py_info/1/ca3ed784184f1b3bb7c3539bfb45e71710cd27667424f92c2d5bb4df9c107c23.lock
[virtualenv] got python info of %s from (PosixPath('/usr/bin/python3.11'), PosixPath('/home/andrew/.local/share/virtualenv/py_info/1/ca3ed784184f1b3bb7c3539bfb45e71710cd27667424f92c2d5bb4df9c107c23.json'))
[filelock:filelock] Attempting to release lock 139883611697616 on /home/andrew/.local/share/virtualenv/py_info/1/ca3ed784184f1b3bb7c3539bfb45e71710cd27667424f92c2d5bb4df9c107c23.lock
[filelock:filelock] Lock 139883611697616 released on /home/andrew/.local/share/virtualenv/py_info/1/ca3ed784184f1b3bb7c3539bfb45e71710cd27667424f92c2d5bb4df9c107c23.lock
[virtualenv] proposed PythonInfo(spec=CPython3.11.2.final.0-64, system=/usr/bin/python3.11, exe=/home/andrew/.local/pipx/venvs/poetry/bin/python, platform=linux, version='3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0]', encoding_fs_io=utf-8-utf-8)
[virtualenv] accepted PythonInfo(spec=CPython3.11.2.final.0-64, system=/usr/bin/python3.11, exe=/home/andrew/.local/pipx/venvs/poetry/bin/python, platform=linux, version='3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0]', encoding_fs_io=utf-8-utf-8)
[virtualenv] filesystem is case-sensitive
[virtualenv] create virtual environment via CPython3Posix(dest=/home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11, clear=False, no_vcs_ignore=False, global=False)
[virtualenv] create folder /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/bin
[virtualenv] create folder /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/lib/python3.11/site-packages
[virtualenv] write /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/pyvenv.cfg
[virtualenv] 	home = /usr/bin
[virtualenv] 	implementation = CPython
[virtualenv] 	version_info = 3.11.2.final.0
[virtualenv] 	virtualenv = 20.25.1
[virtualenv] 	include-system-site-packages = false
[virtualenv] 	base-prefix = /usr
[virtualenv] 	base-exec-prefix = /usr
[virtualenv] 	base-executable = /usr/bin/python3.11
[virtualenv] symlink /usr/bin/python3.11 to /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/bin/python
[virtualenv] create virtualenv import hook file /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/lib/python3.11/site-packages/_virtualenv.pth
[virtualenv] create /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/lib/python3.11/site-packages/_virtualenv.py
[virtualenv] ============================== target debug ==============================
[virtualenv] debug via /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/bin/python /home/andrew/.local/pipx/venvs/poetry/lib/python3.11/site-packages/virtualenv/create/debug.py
[virtualenv] {
[virtualenv]   "sys": {
[virtualenv]     "executable": "/home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/bin/python",
[virtualenv]     "_base_executable": "/usr/bin/python3.11",
[virtualenv]     "prefix": "/home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11",
[virtualenv]     "base_prefix": "/usr",
[virtualenv]     "real_prefix": null,
[virtualenv]     "exec_prefix": "/home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11",
[virtualenv]     "base_exec_prefix": "/usr",
[virtualenv]     "path": [
[virtualenv]       "/usr/lib/python311.zip",
[virtualenv]       "/usr/lib/python3.11",
[virtualenv]       "/usr/lib/python3.11/lib-dynload",
[virtualenv]       "/home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/lib/python3.11/site-packages"
[virtualenv]     ],
[virtualenv]     "meta_path": [
[virtualenv]       "<class '_virtualenv._Finder'>",
[virtualenv]       "<class '_frozen_importlib.BuiltinImporter'>",
[virtualenv]       "<class '_frozen_importlib.FrozenImporter'>",
[virtualenv]       "<class '_frozen_importlib_external.PathFinder'>"
[virtualenv]     ],
[virtualenv]     "fs_encoding": "utf-8",
[virtualenv]     "io_encoding": "utf-8"
[virtualenv]   },
[virtualenv]   "version": "3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0]",
[virtualenv]   "makefile_filename": "/usr/lib/python3.11/config-3.11-x86_64-linux-gnu/Makefile",
[virtualenv]   "os": "<module 'os' (frozen)>",
[virtualenv]   "site": "<module 'site' (frozen)>",
[virtualenv]   "datetime": "<module 'datetime' from '/usr/lib/python3.11/datetime.py'>",
[virtualenv]   "math": "<module 'math' (built-in)>",
[virtualenv]   "json": "<module 'json' from '/usr/lib/python3.11/json/__init__.py'>"
[virtualenv] }
[virtualenv] add seed packages via FromAppData(download=False, pip=bundle, setuptools=bundle, via=copy, app_data_dir=/home/andrew/.local/share/virtualenv)
[virtualenv] install setuptools from wheel /home/andrew/.local/pipx/venvs/poetry/lib/python3.11/site-packages/virtualenv/seed/wheels/embed/setuptools-69.1.0-py3-none-any.whl via CopyPipInstall
[virtualenv] install pip from wheel /home/andrew/.local/pipx/venvs/poetry/lib/python3.11/site-packages/virtualenv/seed/wheels/embed/pip-24.0-py3-none-any.whl via CopyPipInstall
[filelock:filelock] Attempting to acquire lock 139883609168016 on /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/setuptools-69.1.0-py3-none-any.lock
[filelock:filelock] Attempting to acquire lock 139883609175184 on /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/pip-24.0-py3-none-any.lock
[filelock:filelock] Lock 139883609168016 acquired on /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/setuptools-69.1.0-py3-none-any.lock
[filelock:filelock] Lock 139883609175184 acquired on /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/pip-24.0-py3-none-any.lock
[filelock:filelock] Attempting to release lock 139883609168016 on /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/setuptools-69.1.0-py3-none-any.lock
[filelock:filelock] Lock 139883609168016 released on /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/setuptools-69.1.0-py3-none-any.lock
[filelock:filelock] Attempting to release lock 139883609175184 on /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/pip-24.0-py3-none-any.lock
[filelock:filelock] Lock 139883609175184 released on /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/pip-24.0-py3-none-any.lock
[virtualenv] copy directory /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/setuptools-69.1.0-py3-none-any/pkg_resources to /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/lib/python3.11/site-packages/pkg_resources
[virtualenv] copy directory /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/pip-24.0-py3-none-any/pip-24.0.dist-info to /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/lib/python3.11/site-packages/pip-24.0.dist-info
[virtualenv] copy directory /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/pip-24.0-py3-none-any/pip to /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/lib/python3.11/site-packages/pip
[virtualenv] copy directory /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/setuptools-69.1.0-py3-none-any/_distutils_hack to /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/lib/python3.11/site-packages/_distutils_hack
[virtualenv] copy directory /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/setuptools-69.1.0-py3-none-any/setuptools-69.1.0.dist-info to /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/lib/python3.11/site-packages/setuptools-69.1.0.dist-info
[virtualenv] copy /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/setuptools-69.1.0-py3-none-any/distutils-precedence.pth to /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/lib/python3.11/site-packages/distutils-precedence.pth
[virtualenv] copy /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/setuptools-69.1.0-py3-none-any/setuptools-69.1.0.virtualenv to /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/lib/python3.11/site-packages/setuptools-69.1.0.virtualenv
[virtualenv] copy directory /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/setuptools-69.1.0-py3-none-any/setuptools to /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/lib/python3.11/site-packages/setuptools
[virtualenv] generated console scripts 
[virtualenv] copy /home/andrew/.local/share/virtualenv/wheel/3.11/image/1/CopyPipInstall/pip-24.0-py3-none-any/pip-24.0.virtualenv to /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/lib/python3.11/site-packages/pip-24.0.virtualenv
[distlib:distlib.util] changing mode of /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/bin/pip-3.11 to 755
[distlib:distlib.util] changing mode of /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/bin/pip3.11 to 755
[distlib:distlib.util] changing mode of /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/bin/pip3 to 755
[distlib:distlib.util] changing mode of /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/bin/pip to 755
[virtualenv] generated console scripts pip3 pip3.11 pip-3.11 pip
[virtualenv] add activators for Bash, CShell, Fish, Nushell, PowerShell, Python
[virtualenv] write /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/pyvenv.cfg
[virtualenv] 	home = /usr/bin
[virtualenv] 	implementation = CPython
[virtualenv] 	version_info = 3.11.2.final.0
[virtualenv] 	virtualenv = 20.25.1
[virtualenv] 	include-system-site-packages = false
[virtualenv] 	base-prefix = /usr
[virtualenv] 	base-exec-prefix = /usr
[virtualenv] 	base-executable = /usr/bin/python3.11
[virtualenv] 	prompt = git-deps-issue-py3.11
Using virtualenv: /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11
Installing dependencies from lock file

Finding the necessary packages for the current system

Package operations: 1 install, 0 updates, 0 removals

  - Installing kubernetes (29.0.0+snapshot d36ec43): Pending...
  - Installing kubernetes (29.0.0+snapshot d36ec43): Installing...
  - Installing kubernetes (29.0.0+snapshot d36ec43)

Installing the current project: git-deps-issue (0.1.0)
  - Building package git-deps-issue in editable mode
  - Adding git_deps_issue.pth to /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/lib/python3.11/site-packages for /home/andrew/git/src/github.com/meln5674/poetry-test
  - Adding the git_deps_issue-0.1.0.dist-info directory to /home/andrew/.cache/pypoetry/virtualenvs/git-deps-issue-5ERwWHeK-py3.11/lib/python3.11/site-packages
```



Discussion:
https://github.com/kubernetes-client/python/blob/851dc2a0b10d1bc07826c6ade489d1bd2ef431c3/setup.py#L33-L45

I guess the setup reader spots `REQUIRES = []`, reckons it understands that, and decides that it is done.

In most cases where setup.py builds up requirements via a series of conditional tests, this mistake doesn't really matter: in the sense that poetry only supports projects where the metadata is the same for all distributions, so a setup that goes "if windows this, if linux that" is fundamentally not compatible with poetry.

In this case the code _is_ providing a static list, but doing it in a rather elaborate way.

if what you care about is getting this working with kubernetes-client then probably your best bet is to go and offer them a pull request to rearrange things so that poetry doesn't get fooled.

eg 
```python
with open('requirements.txt') as f:
    REQUIRES = [line.split(" #")[0] for line in f.readlines()]
```
seems like a simplification they might want anyway, and should be something that poetry recognises it cannot understand
While that might be the case (and I'm already working off a fork, so I can just do it there), I don't think its too unreasonable to expect poetry to behave "close enough" to "pip install", and not do something completely different, silently. I'll refer you to my comment on the previous issue regarding this same bug: Heuristics are great, right up until they are wrong. I stand by my position that poetry ought to have some mechanism to say "Your guess is wrong, please build it.". I'd be happy to contribute something like this if it would be accepted.
I'm not a fan of "make it work" flags: if this is going to be fixed, let it be fixed without a config option.

I guess it's possible to go in either direction:
- make the setup reader more sophisticated, so that it recognises that this is in fact a case that it doesn't know how to handle
- make the setup reader less sophisticated, handling a narrower range of cases about which it really can be sure
  - eg it would be easy to make it not find `REQUIRES` at all: once it realises that the `install_requires` argument is a variable it could just give up there
- or maybe go all the way and abandon the setup reader altogether.

I would give serious consideration to removing the setup reader, though I don't know how maintainers would feel about that

The python ecosystem is quite different than it was when this code was written, most popular projects now have wheels declaring static metadata.  So the trade between "time saved by not building a wheel" and "sometimes being wrong" is in a different place than it was.
Setup reader was always considered a fallback. I thought we have had pep 517 build before falling back to setup reader. Or I might have incorrectly believed that since an empty list was previously being treated as a bad read and we fell back to a 517 metadata build. 

I'm curious if we are just way too optimistic about setup reader's parsed list. 
setup reader happens before build and has done for a long time, probably since forever
If you don't like "make it work" options, and while this might be considered a breaking change, what about needing to opt into the setupreader for path and git dependencies? It seems like it'd be much safer to do the slow, but reliable build by default unless the user explicitly gives the go-ahead for the faster, but riskier option.
That is still a "make it work" flag.  IMO any config option here is a mistake
To be concrete: the intermediate "keep the setup reader but make it less ambitious" middle option probably looks something like this:
```patch
diff --git a/src/poetry/utils/setup_reader.py b/src/poetry/utils/setup_reader.py
index 3c233cd9..a348e3b3 100644
--- a/src/poetry/utils/setup_reader.py
+++ b/src/poetry/utils/setup_reader.py
@@ -222,9 +222,6 @@ class SetupReader:
         if value is None:
             return []

-        if isinstance(value, ast.Name):
-            value = self._find_variable_in_body(body, value.id)
-
         if isinstance(value, ast.Constant) and value.value is None:
             return []

@@ -261,9 +258,6 @@ class SetupReader:
         if value is None:
             return {}

-        if isinstance(value, ast.Name):
-            value = self._find_variable_in_body(body, value.id)
-
         if isinstance(value, ast.Constant) and value.value is None:
             return {}
```
(plus corresponding fixes to testcases)

If I cared to make this more reliable, and did not want to try and persuade maintainers that the setup reader should be abandoned altogether, that is the approach I would pursue

Resolving patch:
diff --git a/src/poetry/inspection/info.py b/src/poetry/inspection/info.py
--- a/src/poetry/inspection/info.py
+++ b/src/poetry/inspection/info.py
@@ -27,7 +27,6 @@
 
 from poetry.utils.helpers import extractall
 from poetry.utils.isolated_build import isolated_builder
-from poetry.utils.setup_reader import SetupReader
 
 
 if TYPE_CHECKING:
@@ -341,58 +340,6 @@ def _from_sdist_file(cls, path: Path) -> PackageInfo:
 
         return info.update(new_info)
 
-    @staticmethod
-    def has_setup_files(path: Path) -> bool:
-        return any((path / f).exists() for f in SetupReader.FILES)
-
-    @classmethod
-    def from_setup_files(cls, path: Path) -> PackageInfo:
-        """
-        Mechanism to parse package information from a `setup.[py|cfg]` file. This uses
-        the implementation at `poetry.utils.setup_reader.SetupReader` in order to parse
-        the file. This is not reliable for complex setup files and should only attempted
-        as a fallback.
-
-        :param path: Path to `setup.py` file
-        """
-        if not cls.has_setup_files(path):
-            raise PackageInfoError(
-                path, "No setup files (setup.py, setup.cfg) was found."
-            )
-
-        try:
-            result = SetupReader.read_from_directory(path)
-        except Exception as e:
-            raise PackageInfoError(path, e)
-
-        python_requires = result["python_requires"]
-        if python_requires is None:
-            python_requires = "*"
-
-        requires = "".join(dep + "\n" for dep in result["install_requires"])
-        if result["extras_require"]:
-            requires += "\n"
-
-        for extra_name, deps in result["extras_require"].items():
-            requires += f"[{extra_name}]\n"
-
-            for dep in deps:
-                requires += dep + "\n"
-
-            requires += "\n"
-
-        requirements = parse_requires(requires)
-
-        info = cls(
-            name=result.get("name"),
-            version=result.get("version"),
-            summary=result.get("description", ""),
-            requires_dist=requirements,
-            requires_python=python_requires,
-        )
-
-        return info
-
     @staticmethod
     def _find_dist_info(path: Path) -> Iterator[Path]:
         """
@@ -491,16 +438,13 @@ def _get_poetry_package(path: Path) -> ProjectPackage | None:
         return None
 
     @classmethod
-    def from_directory(cls, path: Path, disable_build: bool = False) -> PackageInfo:
+    def from_directory(cls, path: Path) -> PackageInfo:
         """
-        Generate package information from a package source directory. If `disable_build`
-        is not `True` and introspection of all available metadata fails, the package is
-        attempted to be built in an isolated environment so as to generate required
-        metadata.
+        Generate package information from a package source directory. If introspection
+        of all available metadata fails, the package is attempted to be built in an
+        isolated environment so as to generate required metadata.
 
         :param path: Path to generate package information from.
-        :param disable_build: If not `True` and setup reader fails, PEP 517 isolated
-            build is attempted in order to gather metadata.
         """
         project_package = cls._get_poetry_package(path)
         info: PackageInfo | None
@@ -511,10 +455,7 @@ def from_directory(cls, path: Path, disable_build: bool = False) -> PackageInfo:
 
             if not info or info.requires_dist is None:
                 try:
-                    if disable_build:
-                        info = cls.from_setup_files(path)
-                    else:
-                        info = get_pep517_metadata(path)
+                    info = get_pep517_metadata(path)
                 except PackageInfoError:
                     if not info:
                         raise
@@ -591,11 +532,6 @@ def get_pep517_metadata(path: Path) -> PackageInfo:
     """
     info = None
 
-    with contextlib.suppress(PackageInfoError):
-        info = PackageInfo.from_setup_files(path)
-        if all(x is not None for x in (info.version, info.name, info.requires_dist)):
-            return info
-
     with tempfile.TemporaryDirectory() as dist:
         try:
             dest = Path(dist)
diff --git a/src/poetry/utils/setup_reader.py b/src/poetry/utils/setup_reader.py
deleted file mode 100644
--- a/src/poetry/utils/setup_reader.py
+++ /dev/null
@@ -1,383 +0,0 @@
-from __future__ import annotations
-
-import ast
-
-from configparser import ConfigParser
-from typing import TYPE_CHECKING
-from typing import Any
-from typing import ClassVar
-
-from poetry.core.constraints.version import Version
-
-
-if TYPE_CHECKING:
-    from pathlib import Path
-
-
-class SetupReaderError(Exception):
-    pass
-
-
-class SetupReader:
-    """
-    Class that reads a setup.py file without executing it.
-    """
-
-    DEFAULT: ClassVar[dict[str, Any]] = {
-        "name": None,
-        "version": None,
-        "description": None,
-        "install_requires": [],
-        "extras_require": {},
-        "python_requires": None,
-    }
-
-    FILES: ClassVar[list[str]] = ["setup.py", "setup.cfg"]
-
-    @classmethod
-    def read_from_directory(cls, directory: Path) -> dict[str, Any]:
-        result = cls.DEFAULT.copy()
-        for filename in cls.FILES:
-            filepath = directory / filename
-            if not filepath.exists():
-                continue
-
-            read_file_func = getattr(cls(), "read_" + filename.replace(".", "_"))
-            new_result = read_file_func(filepath)
-
-            for key in result:
-                if new_result[key]:
-                    result[key] = new_result[key]
-
-        return result
-
-    def read_setup_py(self, filepath: Path) -> dict[str, Any]:
-        with filepath.open(encoding="utf-8") as f:
-            content = f.read()
-
-        result: dict[str, Any] = {}
-
-        body = ast.parse(content).body
-
-        setup_call = self._find_setup_call(body)
-        if setup_call is None:
-            return self.DEFAULT
-
-        # Inspecting keyword arguments
-        call, body = setup_call
-        result["name"] = self._find_single_string(call, body, "name")
-        result["version"] = self._find_single_string(call, body, "version")
-        result["description"] = self._find_single_string(call, body, "description")
-        result["install_requires"] = self._find_install_requires(call, body)
-        result["extras_require"] = self._find_extras_require(call, body)
-        result["python_requires"] = self._find_single_string(
-            call, body, "python_requires"
-        )
-
-        return result
-
-    def read_setup_cfg(self, filepath: Path) -> dict[str, Any]:
-        parser = ConfigParser()
-
-        parser.read(str(filepath))
-
-        name = None
-        version = None
-        description = None
-        if parser.has_option("metadata", "name"):
-            name = parser.get("metadata", "name")
-
-        if parser.has_option("metadata", "version"):
-            version = Version.parse(parser.get("metadata", "version")).text
-
-        if parser.has_option("metadata", "description"):
-            description = parser.get("metadata", "description")
-
-        install_requires = []
-        extras_require: dict[str, list[str]] = {}
-        python_requires = None
-        if parser.has_section("options"):
-            if parser.has_option("options", "install_requires"):
-                for dep in parser.get("options", "install_requires").split("\n"):
-                    dep = dep.strip()
-                    if not dep:
-                        continue
-
-                    install_requires.append(dep)
-
-            if parser.has_option("options", "python_requires"):
-                python_requires = parser.get("options", "python_requires")
-
-        if parser.has_section("options.extras_require"):
-            for group in parser.options("options.extras_require"):
-                extras_require[group] = []
-                deps = parser.get("options.extras_require", group)
-                for dep in deps.split("\n"):
-                    dep = dep.strip()
-                    if not dep:
-                        continue
-
-                    extras_require[group].append(dep)
-
-        return {
-            "name": name,
-            "version": version,
-            "description": description,
-            "install_requires": install_requires,
-            "extras_require": extras_require,
-            "python_requires": python_requires,
-        }
-
-    def _find_setup_call(
-        self, elements: list[ast.stmt]
-    ) -> tuple[ast.Call, list[ast.stmt]] | None:
-        funcdefs: list[ast.stmt] = []
-        for i, element in enumerate(elements):
-            if isinstance(element, ast.If) and i == len(elements) - 1:
-                # Checking if the last element is an if statement
-                # and if it is 'if __name__ == "__main__"' which
-                # could contain the call to setup()
-                test = element.test
-                if not isinstance(test, ast.Compare):
-                    continue
-
-                left = test.left
-                if not isinstance(left, ast.Name):
-                    continue
-
-                if left.id != "__name__":
-                    continue
-
-                setup_call = self._find_sub_setup_call([element])
-                if setup_call is None:
-                    continue
-
-                call, body = setup_call
-                return call, body + elements
-
-            if not isinstance(element, ast.Expr):
-                if isinstance(element, ast.FunctionDef):
-                    funcdefs.append(element)
-
-                continue
-
-            value = element.value
-            if not isinstance(value, ast.Call):
-                continue
-
-            func = value.func
-            if not (isinstance(func, ast.Name) and func.id == "setup") and not (
-                isinstance(func, ast.Attribute)
-                and getattr(func.value, "id", None) == "setuptools"
-                and func.attr == "setup"
-            ):
-                continue
-
-            return value, elements
-
-        # Nothing, we inspect the function definitions
-        return self._find_sub_setup_call(funcdefs)
-
-    def _find_sub_setup_call(
-        self, elements: list[ast.stmt]
-    ) -> tuple[ast.Call, list[ast.stmt]] | None:
-        for element in elements:
-            if not isinstance(element, (ast.FunctionDef, ast.If)):
-                continue
-
-            setup_call = self._find_setup_call(element.body)
-            if setup_call is not None:
-                sub_call, body = setup_call
-
-                body = elements + body
-
-                return sub_call, body
-
-        return None
-
-    def _find_install_requires(self, call: ast.Call, body: list[ast.stmt]) -> list[str]:
-        value = self._find_in_call(call, "install_requires")
-        if value is None:
-            # Trying to find in kwargs
-            kwargs = self._find_call_kwargs(call)
-
-            if kwargs is None or not isinstance(kwargs, ast.Name):
-                return []
-
-            variable = self._find_variable_in_body(body, kwargs.id)
-
-            if isinstance(variable, ast.Dict):
-                value = self._find_in_dict(variable, "install_requires")
-
-            elif (
-                isinstance(variable, ast.Call)
-                and isinstance(variable.func, ast.Name)
-                and variable.func.id == "dict"
-            ):
-                value = self._find_in_call(variable, "install_requires")
-
-            else:
-                raise SetupReaderError(f"Cannot handle variable {variable}")
-
-        if value is None:
-            return []
-
-        if isinstance(value, ast.Name):
-            value = self._find_variable_in_body(body, value.id)
-
-        if isinstance(value, ast.Constant) and value.value is None:
-            return []
-
-        if isinstance(value, ast.List):
-            return string_list_values(value)
-
-        raise SetupReaderError(f"Cannot handle value of type {type(value)}")
-
-    def _find_extras_require(
-        self, call: ast.Call, body: list[ast.stmt]
-    ) -> dict[str, list[str]]:
-        value = self._find_in_call(call, "extras_require")
-        if value is None:
-            # Trying to find in kwargs
-            kwargs = self._find_call_kwargs(call)
-
-            if kwargs is None or not isinstance(kwargs, ast.Name):
-                return {}
-
-            variable = self._find_variable_in_body(body, kwargs.id)
-            if isinstance(variable, ast.Dict):
-                value = self._find_in_dict(variable, "extras_require")
-
-            elif (
-                isinstance(variable, ast.Call)
-                and isinstance(variable.func, ast.Name)
-                and variable.func.id == "dict"
-            ):
-                value = self._find_in_call(variable, "extras_require")
-
-            else:
-                raise SetupReaderError(f"Cannot handle variable {variable}")
-
-        if value is None:
-            return {}
-
-        if isinstance(value, ast.Name):
-            value = self._find_variable_in_body(body, value.id)
-
-        if isinstance(value, ast.Constant) and value.value is None:
-            return {}
-
-        if isinstance(value, ast.Dict):
-            extras_require: dict[str, list[str]] = {}
-            val: ast.expr | None
-            for key, val in zip(value.keys, value.values):
-                if not isinstance(key, ast.Constant) or not isinstance(key.value, str):
-                    raise SetupReaderError(f"Cannot handle key {key}")
-
-                if isinstance(val, ast.Name):
-                    val = self._find_variable_in_body(body, val.id)
-
-                if not isinstance(val, ast.List):
-                    raise SetupReaderError(f"Cannot handle value of type {type(val)}")
-
-                extras_require[key.value] = string_list_values(val)
-
-            return extras_require
-
-        raise SetupReaderError(f"Cannot handle value of type {type(value)}")
-
-    def _find_single_string(
-        self, call: ast.Call, body: list[ast.stmt], name: str
-    ) -> str | None:
-        value = self._find_in_call(call, name)
-        if value is None:
-            # Trying to find in kwargs
-            kwargs = self._find_call_kwargs(call)
-
-            if kwargs is None or not isinstance(kwargs, ast.Name):
-                return None
-
-            variable = self._find_variable_in_body(body, kwargs.id)
-            if not isinstance(variable, (ast.Dict, ast.Call)):
-                return None
-
-            if isinstance(variable, ast.Call):
-                if not isinstance(variable.func, ast.Name):
-                    return None
-
-                if variable.func.id != "dict":
-                    return None
-
-                value = self._find_in_call(variable, name)
-            else:
-                value = self._find_in_dict(variable, name)
-
-        if value is None:
-            return None
-
-        if isinstance(value, ast.Constant) and isinstance(value.value, str):
-            return value.value
-        elif isinstance(value, ast.Name):
-            variable = self._find_variable_in_body(body, value.id)
-
-            if (
-                variable is not None
-                and isinstance(variable, ast.Constant)
-                and isinstance(variable.value, str)
-            ):
-                return variable.value
-
-        return None
-
-    def _find_in_call(self, call: ast.Call, name: str) -> Any | None:
-        for keyword in call.keywords:
-            if keyword.arg == name:
-                return keyword.value
-        return None
-
-    def _find_call_kwargs(self, call: ast.Call) -> Any | None:
-        kwargs = None
-        for keyword in call.keywords:
-            if keyword.arg is None:
-                kwargs = keyword.value
-
-        return kwargs
-
-    def _find_variable_in_body(
-        self, body: list[ast.stmt], name: str
-    ) -> ast.expr | None:
-        for elem in body:
-            if not isinstance(elem, ast.Assign):
-                continue
-
-            for target in elem.targets:
-                if not isinstance(target, ast.Name):
-                    continue
-
-                if target.id == name:
-                    return elem.value
-
-        return None
-
-    def _find_in_dict(self, dict_: ast.Dict, name: str) -> ast.expr | None:
-        for key, val in zip(dict_.keys, dict_.values):
-            if (
-                isinstance(key, ast.Constant)
-                and isinstance(key.value, str)
-                and key.value == name
-            ):
-                return val
-
-        return None
-
-
-def string_list_values(value: ast.List) -> list[str]:
-    strings = []
-    for element in value.elts:
-        if isinstance(element, ast.Constant) and isinstance(element.value, str):
-            strings.append(element.value)
-
-        else:
-            raise SetupReaderError("Found non-string element in list")
-
-    return strings


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -7,7 +7,6 @@
 import shutil
 import sys
 
-from contextlib import suppress
 from pathlib import Path
 from typing import TYPE_CHECKING
 from typing import Any
@@ -26,9 +25,8 @@
 from poetry.config.config import Config as BaseConfig
 from poetry.config.dict_config_source import DictConfigSource
 from poetry.factory import Factory
-from poetry.inspection.info import PackageInfo
-from poetry.inspection.info import PackageInfoError
 from poetry.layouts import layout
+from poetry.packages.direct_origin import _get_package_from_git
 from poetry.repositories import Repository
 from poetry.repositories import RepositoryPool
 from poetry.utils.cache import ArtifactCache
@@ -279,19 +277,6 @@ def mock_user_config_dir(mocker: MockerFixture, config_dir: Path) -> None:
     mocker.patch("poetry.config.config.CONFIG_DIR", new=config_dir)
 
 
-@pytest.fixture(autouse=True)
-def pep517_metadata_mock(mocker: MockerFixture) -> None:
-    def get_pep517_metadata(path: Path) -> PackageInfo:
-        with suppress(PackageInfoError):
-            return PackageInfo.from_setup_files(path)
-        return PackageInfo(name="demo", version="0.1.2")
-
-    mocker.patch(
-        "poetry.inspection.info.get_pep517_metadata",
-        get_pep517_metadata,
-    )
-
-
 @pytest.fixture
 def environ() -> Iterator[None]:
     with isolated_environment():
@@ -316,6 +301,8 @@ def git_mock(mocker: MockerFixture) -> None:
     p = mocker.patch("poetry.vcs.git.Git.get_revision")
     p.return_value = MOCK_DEFAULT_GIT_REVISION
 
+    _get_package_from_git.cache_clear()
+
 
 @pytest.fixture
 def http() -> Iterator[type[httpretty.httpretty]]:
diff --git a/tests/helpers.py b/tests/helpers.py
--- a/tests/helpers.py
+++ b/tests/helpers.py
@@ -76,10 +76,10 @@ def get_dependency(
 
 
 def copy_path(source: Path, dest: Path) -> None:
-    if dest.is_symlink() or dest.is_file():
-        dest.unlink()  # missing_ok is only available in Python >= 3.8
-    elif dest.is_dir():
+    if dest.is_dir():
         shutil.rmtree(dest)
+    else:
+        dest.unlink(missing_ok=True)
 
     if source.is_dir():
         shutil.copytree(source, dest)
@@ -108,12 +108,13 @@ def mock_clone(
 
     assert parsed.resource is not None
     folder = FIXTURE_PATH / "git" / parsed.resource / path
+    assert folder.is_dir()
 
     if not source_root:
         source_root = Path(Config.create().get("cache-dir")) / "src"
 
     dest = source_root / path
-    dest.parent.mkdir(parents=True, exist_ok=True)
+    dest.mkdir(parents=True, exist_ok=True)
 
     copy_path(folder, dest)
     return MockDulwichRepo(dest)
diff --git a/tests/inspection/test_info.py b/tests/inspection/test_info.py
--- a/tests/inspection/test_info.py
+++ b/tests/inspection/test_info.py
@@ -28,11 +28,6 @@
     from tests.types import SetProjectContext
 
 
-@pytest.fixture(autouse=True)
-def pep517_metadata_mock() -> None:
-    pass
-
-
 @pytest.fixture
 def demo_sdist(fixture_dir: FixtureDirGetter) -> Path:
     return fixture_dir("distributions") / "demo-0.1.0.tar.gz"
@@ -150,19 +145,29 @@ def demo_check_info(info: PackageInfo, requires_dist: set[str] | None = None) ->
     if requires_dist:
         assert set(info.requires_dist) == requires_dist
     else:
+        # Exact formatting various according to the exact mechanism used to extract the
+        # metadata.
         assert set(info.requires_dist) in (
-            # before https://github.com/python-poetry/poetry-core/pull/510
             {
                 'cleo; extra == "foo"',
                 "pendulum (>=1.4.4)",
                 'tomlkit; extra == "bar"',
             },
-            # after https://github.com/python-poetry/poetry-core/pull/510
             {
                 'cleo ; extra == "foo"',
                 "pendulum (>=1.4.4)",
                 'tomlkit ; extra == "bar"',
             },
+            {
+                'cleo ; extra == "foo"',
+                "pendulum>=1.4.4",
+                'tomlkit ; extra == "bar"',
+            },
+            {
+                "cleo ; extra == 'foo'",
+                "pendulum (>=1.4.4)",
+                "tomlkit ; extra == 'bar'",
+            },
         )
 
 
@@ -243,9 +248,7 @@ def test_info_from_bdist(demo_wheel: Path) -> None:
 
 
 def test_info_from_poetry_directory(fixture_dir: FixtureDirGetter) -> None:
-    info = PackageInfo.from_directory(
-        fixture_dir("inspection") / "demo", disable_build=True
-    )
+    info = PackageInfo.from_directory(fixture_dir("inspection") / "demo")
     demo_check_info(info)
 
 
@@ -275,16 +278,6 @@ def test_info_from_requires_txt(fixture_dir: FixtureDirGetter) -> None:
     demo_check_info(info)
 
 
-def test_info_from_setup_py(demo_setup: Path) -> None:
-    info = PackageInfo.from_setup_files(demo_setup)
-    demo_check_info(info, requires_dist={"package"})
-
-
-def test_info_from_setup_cfg(demo_setup_cfg: Path) -> None:
-    info = PackageInfo.from_setup_files(demo_setup_cfg)
-    demo_check_info(info, requires_dist={"package"})
-
-
 def test_info_no_setup_pkg_info_no_deps(fixture_dir: FixtureDirGetter) -> None:
     info = PackageInfo.from_metadata_directory(
         fixture_dir("inspection") / "demo_no_setup_pkg_info_no_deps"
@@ -318,14 +311,7 @@ def test_info_no_setup_pkg_info_no_deps_dynamic(fixture_dir: FixtureDirGetter) -
 def test_info_setup_simple(mocker: MockerFixture, demo_setup: Path) -> None:
     spy = mocker.spy(VirtualEnv, "run")
     info = PackageInfo.from_directory(demo_setup)
-    assert spy.call_count == 0
-    demo_check_info(info, requires_dist={"package"})
-
-
-def test_info_setup_cfg(mocker: MockerFixture, demo_setup_cfg: Path) -> None:
-    spy = mocker.spy(VirtualEnv, "run")
-    info = PackageInfo.from_directory(demo_setup_cfg)
-    assert spy.call_count == 0
+    assert spy.call_count == 5
     demo_check_info(info, requires_dist={"package"})
 
 
@@ -356,14 +342,6 @@ def test_info_setup_complex_pep517_legacy(
     demo_check_info(info, requires_dist={"package"})
 
 
-def test_info_setup_complex_disable_build(
-    mocker: MockerFixture, demo_setup_complex: Path
-) -> None:
-    # Cannot extract install_requires from list comprehension.
-    with pytest.raises(PackageInfoError):
-        PackageInfo.from_directory(demo_setup_complex, disable_build=True)
-
-
 @pytest.mark.network
 def test_info_setup_complex_calls_script(demo_setup_complex_calls_script: Path) -> None:
     """Building the project requires calling a script from its build_requires."""
@@ -391,24 +369,6 @@ def test_info_setup_missing_mandatory_should_trigger_pep517(
     assert spy.call_count == 1
 
 
-@pytest.mark.network
-def test_info_setup_missing_install_requires_is_fine(
-    mocker: MockerFixture, source_dir: Path
-) -> None:
-    setup = "from setuptools import setup; "
-    setup += "setup("
-    setup += 'name="demo", '
-    setup += 'version="0.1.0", '
-    setup += ")"
-
-    setup_py = source_dir / "setup.py"
-    setup_py.write_text(setup)
-
-    spy = mocker.spy(VirtualEnv, "run")
-    _ = PackageInfo.from_directory(source_dir)
-    assert spy.call_count == 0
-
-
 def test_info_prefer_poetry_config_over_egg_info(fixture_dir: FixtureDirGetter) -> None:
     info = PackageInfo.from_directory(
         fixture_dir("inspection") / "demo_with_obsolete_egg_info"
diff --git a/tests/repositories/test_pypi_repository.py b/tests/repositories/test_pypi_repository.py
--- a/tests/repositories/test_pypi_repository.py
+++ b/tests/repositories/test_pypi_repository.py
@@ -239,37 +239,11 @@ def test_fallback_pep_658_metadata(
         assert dep.python_versions == "~2.7"
 
 
-def test_fallback_can_read_setup_to_get_dependencies(
-    pypi_repository: PyPiRepository,
-) -> None:
-    repo = pypi_repository
-    repo._fallback = True
-
-    package = repo.package("sqlalchemy", Version.parse("1.2.12"))
-
-    assert package.name == "sqlalchemy"
-    assert len(package.requires) == 9
-    assert len([r for r in package.requires if r.is_optional()]) == 9
-
-    assert package.extras == {
-        "mssql-pymssql": [Dependency("pymssql", "*")],
-        "mssql-pyodbc": [Dependency("pyodbc", "*")],
-        "mysql": [Dependency("mysqlclient", "*")],
-        "oracle": [Dependency("cx_oracle", "*")],
-        "postgresql": [Dependency("psycopg2", "*")],
-        "postgresql-pg8000": [Dependency("pg8000", "*")],
-        "postgresql-psycopg2binary": [Dependency("psycopg2-binary", "*")],
-        "postgresql-psycopg2cffi": [Dependency("psycopg2cffi", "*")],
-        "pymysql": [Dependency("pymysql", "*")],
-    }
-
-
 def test_pypi_repository_supports_reading_bz2_files(
     pypi_repository: PyPiRepository,
 ) -> None:
     repo = pypi_repository
     repo._fallback = True
-
     package = repo.package("twisted", Version.parse("18.9.0"))
 
     assert package.name == "twisted"
diff --git a/tests/utils/test_dependency_specification.py b/tests/utils/test_dependency_specification.py
--- a/tests/utils/test_dependency_specification.py
+++ b/tests/utils/test_dependency_specification.py
@@ -7,6 +7,7 @@
 
 from deepdiff import DeepDiff
 
+from poetry.inspection.info import PackageInfo
 from poetry.utils.dependency_specification import RequirementsParser
 
 
@@ -167,6 +168,8 @@ def test_parse_dependency_specification(
 ) -> None:
     original = Path.exists
 
+    # Parsing file and path dependencies reads metadata from the file or path in
+    # question: for these tests we mock that out.
     def _mock(self: Path) -> bool:
         if "/" in requirement and self == Path.cwd().joinpath(requirement):
             return True
@@ -174,6 +177,11 @@ def _mock(self: Path) -> bool:
 
     mocker.patch("pathlib.Path.exists", _mock)
 
+    mocker.patch(
+        "poetry.inspection.info.get_pep517_metadata",
+        return_value=PackageInfo(name="demo", version="0.1.2"),
+    )
+
     assert any(
         not DeepDiff(
             RequirementsParser(artifact_cache=artifact_cache).parse(requirement),
diff --git a/tests/utils/test_isolated_build.py b/tests/utils/test_isolated_build.py
--- a/tests/utils/test_isolated_build.py
+++ b/tests/utils/test_isolated_build.py
@@ -1,5 +1,6 @@
 from __future__ import annotations
 
+import shutil
 import sys
 
 from pathlib import Path
@@ -85,7 +86,8 @@ def test_isolated_env_install_failure(
 def test_isolated_builder_outside_poetry_project_context(
     tmp_working_directory: Path, fixture_dir: FixtureDirGetter
 ) -> None:
-    source = fixture_dir("project_with_setup")
+    source = tmp_working_directory / "source"
+    shutil.copytree(fixture_dir("project_with_setup"), source)
     destination = tmp_working_directory / "dist"
 
     try:
diff --git a/tests/utils/test_setup_reader.py b/tests/utils/test_setup_reader.py
deleted file mode 100644
--- a/tests/utils/test_setup_reader.py
+++ /dev/null
@@ -1,245 +0,0 @@
-from __future__ import annotations
-
-from pathlib import Path
-from typing import TYPE_CHECKING
-
-import pytest
-
-from poetry.core.version.exceptions import InvalidVersion
-
-from poetry.utils.setup_reader import SetupReader
-
-
-if TYPE_CHECKING:
-    from collections.abc import Callable
-
-
-@pytest.fixture()
-def setup() -> Callable[[str], Path]:
-    def _setup(name: str) -> Path:
-        return Path(__file__).parent / "fixtures" / "setups" / name
-
-    return _setup
-
-
-def test_setup_reader_read_minimal_setup_py(setup: Callable[[str], Path]) -> None:
-    result = SetupReader.read_from_directory(setup("minimal"))
-
-    expected_name = None
-    expected_version = None
-    expected_description = None
-    expected_install_requires: list[str] = []
-    expected_extras_require: dict[str, list[str]] = {}
-    expected_python_requires = None
-
-    assert result["name"] == expected_name
-    assert result["version"] == expected_version
-    assert result["description"] == expected_description
-    assert result["install_requires"] == expected_install_requires
-    assert result["extras_require"] == expected_extras_require
-    assert result["python_requires"] == expected_python_requires
-
-
-def test_setup_reader_read_first_level_setup_call_with_direct_types(
-    setup: Callable[[str], Path],
-) -> None:
-    result = SetupReader.read_from_directory(setup("flask"))
-
-    expected_name = "Flask"
-    expected_version = None
-    expected_description = "A simple framework for building complex web applications."
-    expected_install_requires = [
-        "Werkzeug>=0.14",
-        "Jinja2>=2.10",
-        "itsdangerous>=0.24",
-        "click>=5.1",
-    ]
-    expected_extras_require = {
-        "dotenv": ["python-dotenv"],
-        "dev": [
-            "pytest>=3",
-            "coverage",
-            "tox",
-            "sphinx",
-            "pallets-sphinx-themes",
-            "sphinxcontrib-log-cabinet",
-        ],
-        "docs": ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet"],
-    }
-    expected_python_requires = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
-
-    assert result["name"] == expected_name
-    assert result["version"] == expected_version
-    assert result["description"] == expected_description
-    assert result["install_requires"] == expected_install_requires
-    assert result["extras_require"] == expected_extras_require
-    assert result["python_requires"] == expected_python_requires
-
-
-def test_setup_reader_read_first_level_setup_call_with_variables(
-    setup: Callable[[str], Path],
-) -> None:
-    result = SetupReader.read_from_directory(setup("requests"))
-
-    expected_name = None
-    expected_version = None
-    expected_description = None
-    expected_install_requires = [
-        "chardet>=3.0.2,<3.1.0",
-        "idna>=2.5,<2.8",
-        "urllib3>=1.21.1,<1.25",
-        "certifi>=2017.4.17",
-    ]
-    expected_extras_require = {
-        "security": ["pyOpenSSL >= 0.14", "cryptography>=1.3.4", "idna>=2.0.0"],
-        "socks": ["PySocks>=1.5.6, !=1.5.7"],
-        'socks:sys_platform == "win32" and python_version == "2.7"': ["win_inet_pton"],
-    }
-    expected_python_requires = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-
-    assert result["name"] == expected_name
-    assert result["version"] == expected_version
-    assert result["description"] == expected_description
-    assert result["install_requires"] == expected_install_requires
-    assert result["extras_require"] == expected_extras_require
-    assert result["python_requires"] == expected_python_requires
-
-
-def test_setup_reader_read_sub_level_setup_call_with_direct_types(
-    setup: Callable[[str], Path],
-) -> None:
-    result = SetupReader.read_from_directory(setup("sqlalchemy"))
-
-    expected_name = "SQLAlchemy"
-    expected_version = None
-    expected_description = "Database Abstraction Library"
-    expected_install_requires: list[str] = []
-    expected_extras_require = {
-        "mysql": ["mysqlclient"],
-        "pymysql": ["pymysql"],
-        "postgresql": ["psycopg2"],
-        "postgresql_pg8000": ["pg8000"],
-        "postgresql_psycopg2cffi": ["psycopg2cffi"],
-        "oracle": ["cx_oracle"],
-        "mssql_pyodbc": ["pyodbc"],
-        "mssql_pymssql": ["pymssql"],
-    }
-
-    assert result["name"] == expected_name
-    assert result["version"] == expected_version
-    assert result["description"] == expected_description
-    assert result["install_requires"] == expected_install_requires
-    assert result["extras_require"] == expected_extras_require
-    assert result["python_requires"] is None
-
-
-def test_setup_reader_read_setup_cfg(setup: Callable[[str], Path]) -> None:
-    result = SetupReader.read_from_directory(setup("with-setup-cfg"))
-
-    expected_name = "with-setup-cfg"
-    expected_version = "1.2.3"
-    expected_description = "Package with setup.cfg"
-    expected_install_requires = ["six", "tomlkit"]
-    expected_extras_require = {
-        "validation": ["cerberus"],
-        "tests": ["pytest", "pytest-xdist", "pytest-cov"],
-    }
-    expected_python_requires = ">=2.6,!=3.0,!=3.1,!=3.2,!=3.3"
-
-    assert result["name"] == expected_name
-    assert result["version"] == expected_version
-    assert result["description"] == expected_description
-    assert result["install_requires"] == expected_install_requires
-    assert result["extras_require"] == expected_extras_require
-    assert result["python_requires"] == expected_python_requires
-
-
-def test_setup_reader_read_minimal_setup_cfg(setup: Callable[[str], Path]) -> None:
-    result = SetupReader.read_from_directory(setup("with-setup-cfg-minimal"))
-
-    expected_name = None
-    expected_version = None
-    expected_description = None
-    expected_install_requires: list[str] = []
-    expected_extras_require: dict[str, list[str]] = {}
-    expected_python_requires = None
-
-    assert result["name"] == expected_name
-    assert result["version"] == expected_version
-    assert result["description"] == expected_description
-    assert result["install_requires"] == expected_install_requires
-    assert result["extras_require"] == expected_extras_require
-    assert result["python_requires"] == expected_python_requires
-
-
-def test_setup_reader_read_setup_cfg_with_attr(setup: Callable[[str], Path]) -> None:
-    with pytest.raises(InvalidVersion):
-        SetupReader.read_from_directory(setup("with-setup-cfg-attr"))
-
-
-def test_setup_reader_read_setup_kwargs(setup: Callable[[str], Path]) -> None:
-    result = SetupReader.read_from_directory(setup("pendulum"))
-
-    expected_name = "pendulum"
-    expected_version = "2.0.4"
-    expected_description = "Python datetimes made easy"
-    expected_install_requires = ["python-dateutil>=2.6,<3.0", "pytzdata>=2018.3"]
-    expected_extras_require = {':python_version < "3.5"': ["typing>=3.6,<4.0"]}
-    expected_python_requires = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-
-    assert result["name"] == expected_name
-    assert result["version"] == expected_version
-    assert result["description"] == expected_description
-    assert result["install_requires"] == expected_install_requires
-    assert result["extras_require"] == expected_extras_require
-    assert result["python_requires"] == expected_python_requires
-
-
-def test_setup_reader_read_setup_call_in_main(setup: Callable[[str], Path]) -> None:
-    result = SetupReader.read_from_directory(setup("pyyaml"))
-
-    expected_name = "PyYAML"
-    expected_version = "3.13"
-    expected_description = "YAML parser and emitter for Python"
-    expected_install_requires: list[str] = []
-    expected_extras_require: dict[str, list[str]] = {}
-    expected_python_requires = None
-
-    assert result["name"] == expected_name
-    assert result["version"] == expected_version
-    assert result["description"] == expected_description
-    assert result["install_requires"] == expected_install_requires
-    assert result["extras_require"] == expected_extras_require
-    assert result["python_requires"] == expected_python_requires
-
-
-def test_setup_reader_read_extras_require_with_variables(
-    setup: Callable[[str], Path],
-) -> None:
-    result = SetupReader.read_from_directory(setup("extras_require_with_vars"))
-
-    expected_name = "extras_require_with_vars"
-    expected_version = "0.0.1"
-    expected_description = "test setup_reader.py"
-    expected_install_requires: list[str] = []
-    expected_extras_require = {"test": ["pytest"]}
-    expected_python_requires = None
-
-    assert result["name"] == expected_name
-    assert result["version"] == expected_version
-    assert result["description"] == expected_description
-    assert result["install_requires"] == expected_install_requires
-    assert result["extras_require"] == expected_extras_require
-    assert result["python_requires"] == expected_python_requires
-
-
-def test_setup_reader_setuptools(setup: Callable[[str], Path]) -> None:
-    result = SetupReader.read_from_directory(setup("setuptools_setup"))
-
-    expected_name = "my_package"
-    expected_version = "0.1.2"
-    expected_description = "Just a description"
-
-    assert result["name"] == expected_name
-    assert result["version"] == expected_version
-    assert result["description"] == expected_description