Repository: pypa/pip

Issue:
Installing from source with --pre fails under specific condition with pip 21.2.1 
### Description

There is an issue when a project has a build dependency for which a pre-release version is available and which is stated both in `pyproject.toml` and `setup_requires` in `setup.py`.

In this case, trying to install it from source with `pip` (either from the source directory or from a tarball) with the `--pre` option fails (see below for the output).

This issue arises with `cython` for which an alpha version is available.

This issue does not occur:
- When removing the failing dependency from either `pyproject.toml` or `setup_requires` (which is what I'll do).
- Without the `--pre` flag
- When also adding `--no-build-isolation`


### Expected behavior

I'm not sure what is the expected behavior, but this was working with `pip` v21.1.3 and previous and breaks with `pip` v21.2.x

### pip version

21.2.1 and 21.2

### Python version

3.7

### OS

macos

### How to Reproduce

Create a project in a `testpip` directory with:
- `pyproject.toml`:
  ```
  [build-system]
  requires = ["setuptools", "wheel", "Cython"]
  build-backend = "setuptools.build_meta"
  ```
- `setup.py`:
  ```
  setup(
      name="testpip",
      version="0.0.1",
      py_module=["testpip"],
      setup_requires=["Cython"],
  )
  ```
- `testpip.py`

Run `pip install . --pre` from `testpip/`

### Output

```sh-session
pip install . --pre
Processing /testpip

  DEPRECATION: A future pip version will change local packages to be built in-place without first copying to a temporary directory. We recommend you use --use-feature=in-tree-build to test your packages with this new behavior before it becomes the default.
   pip 21.3 will remove support for this functionality. You can find discussion regarding this at https://github.com/pypa/pip/issues/7555.
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
ERROR: Some build dependencies for file:///testpip conflict with the backend dependencies: Cython==3.0.0a9 is incompatible with Cython.
```
```


### Code of Conduct

- [X] I agree to follow the [PSF Code of Conduct](https://www.python.org/psf/conduct/).


Discussion:
https://github.com/pypa/pip/blob/main/src/pip/_internal/build_env.py#L182
This patch fixes this particular issue:
```patch
<                 if dist.version not in req.specifier:
---
>                 if not req.specifier.contains(dist.version, prereleases=True):
```
But I have no clue about the side effects.
Anyway, if this is on the right track, I can turn this into a PR.
I believe your change is actually correct. The code around there only ensures the build environment is set up correctly, and should allow prereleases. Would you mind creating a pull request containing this change, and add a test to ensure this won’t break in the future?
Yes, sure!

Resolving patch:
diff --git a/src/pip/_internal/build_env.py b/src/pip/_internal/build_env.py
--- a/src/pip/_internal/build_env.py
+++ b/src/pip/_internal/build_env.py
@@ -179,7 +179,7 @@ def check_requirements(
                     installed_req_str = f"{req.name}=={dist.version}"
                 else:
                     installed_req_str = f"{req.name}==={dist.version}"
-                if dist.version not in req.specifier:
+                if not req.specifier.contains(dist.version, prereleases=True):
                     conflicting.add((installed_req_str, req_str))
                 # FIXME: Consider direct URL?
         return conflicting, missing


Test patch:
diff --git a/tests/functional/test_install.py b/tests/functional/test_install.py
--- a/tests/functional/test_install.py
+++ b/tests/functional/test_install.py
@@ -788,6 +788,45 @@ def test_editable_install__local_dir_setup_requires_with_pyproject(
     script.pip("install", "--find-links", shared_data.find_links, "-e", local_dir)
 
 
+def test_install_pre__setup_requires_with_pyproject(
+    script: PipTestEnvironment, shared_data: TestData, common_wheels: Path
+) -> None:
+    """
+    Test installing with a pre-release build dependency declared in both
+    setup.py and pyproject.toml.
+
+    https://github.com/pypa/pip/issues/10573
+    """
+    depends_package = "prerelease_dependency"
+    depends_path = create_basic_wheel_for_package(script, depends_package, "1.0.0a1")
+
+    local_dir = script.scratch_path.joinpath("temp")
+    local_dir.mkdir()
+    pyproject_path = local_dir.joinpath("pyproject.toml")
+    pyproject_path.write_text(
+        "[build-system]\n"
+        f'requires = ["setuptools", "wheel", "{depends_package}"]\n'
+        'build-backend = "setuptools.build_meta"\n'
+    )
+    setup_py_path = local_dir.joinpath("setup.py")
+    setup_py_path.write_text(
+        "from setuptools import setup\n"
+        f"setup(name='dummy', setup_requires=['{depends_package}'])\n"
+    )
+
+    script.pip(
+        "install",
+        "--pre",
+        "--no-cache-dir",
+        "--no-index",
+        "--find-links",
+        common_wheels,
+        "--find-links",
+        depends_path.parent,
+        local_dir,
+    )
+
+
 @pytest.mark.network
 def test_upgrade_argparse_shadowed(script: PipTestEnvironment) -> None:
     # If argparse is installed - even if shadowed for imported - we support