Repository: pdm-project/pdm
Pull request #3202 (2024-10-11 02:00:59)

fix: allow prereleases when the requirement is pinned even if disabled by project
Signed-off-by: Frost Ming <me@frostming.com>

## Pull Request Checklist

- [ ] A news fragment is added in `news/` describing what is new.
- [ ] Test cases added for changed code.

## Describe what you have changed in this PR.


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/pdm-project/pdm/pull/3202?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 85.10%. Comparing base [(`5ee042a`)](https://app.codecov.io/gh/pdm-project/pdm/commit/5ee042a6201468a4ee787441d870afebf8d63e7c?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project) to head [(`96e99fa`)](https://app.codecov.io/gh/pdm-project/pdm/commit/96e99fa412aa939c2de461e09601e7347b4be11c?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project).

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #3202      +/-   ##
==========================================
- Coverage   85.59%   85.10%   -0.50%     
==========================================
  Files         112      112              
  Lines       11222    11224       +2     
  Branches     2434     2435       +1     
==========================================
- Hits         9606     9552      -54     
- Misses       1101     1148      +47     
- Partials      515      524       +9     
```

| [Flag](https://app.codecov.io/gh/pdm-project/pdm/pull/3202/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project) | Coverage Δ | |
|---|---|---|
| [unittests](https://app.codecov.io/gh/pdm-project/pdm/pull/3202/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project) | `84.98% <100.00%> (-0.42%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/pdm-project/pdm/pull/3202?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project).


Patch:
diff --git a/news/3202.bugfix.md b/news/3202.bugfix.md
new file mode 100644
index 00000000..823d5013
--- /dev/null
+++ b/news/3202.bugfix.md
@@ -0,0 +1,1 @@
+Allow prereleases when the requirement is pinned even if disabled by project
diff --git a/src/pdm/resolver/providers.py b/src/pdm/resolver/providers.py
index 77f77116..af824393 100644
--- a/src/pdm/resolver/providers.py
+++ b/src/pdm/resolver/providers.py
@@ -184,6 +184,8 @@ class BaseProvider(AbstractProvider):
             return [can]
         else:
             prerelease = requirement.prerelease
+            if prerelease is None and requirement.is_pinned and requirement.specifier.prereleases:
+                prerelease = True
             if prerelease is None and (key := requirement.identify()) in self.locked_candidates:
                 # keep the prerelease if it is locked
                 candidates = self.locked_candidates[key]
@@ -265,8 +267,10 @@ class BaseProvider(AbstractProvider):
             # This should be a URL candidate or self package, consider it to be matching
             return True
         # Allow prereleases if: 1) it is not specified in the tool settings or
-        # 2) the candidate doesn't come from PyPI index.
-        allow_prereleases = self.allow_prereleases in (True, None) or not candidate.req.is_named
+        # 2) the candidate doesn't come from PyPI index or 3) the requirement is pinned
+        allow_prereleases = (
+            self.allow_prereleases in (True, None) or not candidate.req.is_named or requirement.is_pinned
+        )
         return requirement.specifier.contains(version, allow_prereleases)
 
     def get_dependencies(self, candidate: Candidate) -> list[Requirement]:


Test patch:
diff --git a/tests/resolver/test_resolve.py b/tests/resolver/test_resolve.py
index 4a555823..c7a62ef9 100644
--- a/tests/resolver/test_resolve.py
+++ b/tests/resolver/test_resolve.py
@@ -120,6 +120,11 @@ def test_resolve_allow_prereleases(resolve, repository):
         resolve(["bar"], allow_prereleases=False)
 
 
+def test_resolve_prereleases_if_disabled_by_project(resolve):
+    result = resolve(["urllib3==1.23b0"], allow_prereleases=False)
+    assert result["urllib3"].version == "1.23b0"
+
+
 def test_resolve_with_extras(resolve):
     result = resolve(["requests[socks]"])
     assert result["pysocks"].version == "1.5.6"