|
3 | 3 | import operator |
4 | 4 | import os |
5 | 5 | from collections import defaultdict |
| 6 | +from functools import reduce |
6 | 7 |
|
7 | 8 | import packaging.markers |
8 | 9 | import packaging.requirements |
| 10 | +import packaging.specifiers |
9 | 11 | import packaging.utils |
10 | 12 | import packaging.version |
11 | 13 | import pytest |
@@ -92,12 +94,23 @@ def _iter_matches(self, identifier, requirements, incompatibilities): |
92 | 94 | name, _, _ = identifier.partition("[") |
93 | 95 | bad_versions = {c.version for c in incompatibilities[identifier]} |
94 | 96 | extras = {e for r in requirements[identifier] for e in r.extras} |
95 | | - for key in self.index[name]: |
96 | | - v = packaging.version.parse(key) |
97 | | - if any(v not in r.specifier for r in requirements[identifier]): |
98 | | - continue |
99 | | - if v in bad_versions: |
100 | | - continue |
| 97 | + |
| 98 | + # Get all versions from the index, excluding bad versions |
| 99 | + available_versions = ( |
| 100 | + v |
| 101 | + for key in self.index[name] |
| 102 | + if (v := packaging.version.parse(key)) not in bad_versions |
| 103 | + ) |
| 104 | + |
| 105 | + # Combine all requirement specifiers using & operator |
| 106 | + combined_specifier = reduce( |
| 107 | + operator.and_, |
| 108 | + map(operator.attrgetter("specifier"), requirements[identifier]), |
| 109 | + packaging.specifiers.SpecifierSet(), |
| 110 | + ) |
| 111 | + |
| 112 | + # Filter versions using the combined specifier |
| 113 | + for v in combined_specifier.filter(available_versions): |
101 | 114 | yield Candidate(name=name, version=v, extras=extras) |
102 | 115 |
|
103 | 116 | def find_matches(self, identifier, requirements, incompatibilities): |
|
0 commit comments