Make resolvelib's provider capable of handling empty iterators
This is _technically_ possible with the API, and accounting for that
enables the resolver to evolve with this information.
@@ -124,14 +124,29 @@ class PipProvider(_ProviderBase):
* If equal, prefer if any requirement is "pinned", i.e. contains
operator ``===`` or ``==``.
* If equal, calculate an approximate "depth" and resolve requirements
- closer to the user-specified requirements first.
+ closer to the user-specified requirements first. If the depth cannot
+ by determined (eg: due to no matching parents), it is considered
+ infinite.
* Order user-specified requirements by the order they are specified.
* If equal, prefers "non-free" requirements, i.e. contains at least one
operator, such as ``>=`` or ``<``.
* If equal, order alphabetically for consistency (helps debuggability).
"""
+ try:
+ next(iter(information[identifier]))
+ except StopIteration:
+ # There is no information for this identifier, so there's no known
+ # candidates.
+ has_information = False
+ else:
+ has_information = True
+
+ if has_information:
lookups = (r.get_candidate_lookup() for r, _ in information[identifier])
candidate, ireqs = zip(*lookups)
+ else:
+ candidate, ireqs = None, ()
+
operators = [
specifier.operator
for specifier_set in (ireq.specifier for ireq in ireqs if ireq)
@@ -146,11 +161,14 @@ class PipProvider(_ProviderBase):
requested_order: Union[int, float] = self._user_requested[identifier]
except KeyError:
requested_order = math.inf
+ if has_information:
parent_depths = (
self._known_depths[parent.name] if parent is not None else 0.0
for _, parent in information[identifier]
)
inferred_depth = min(d for d in parent_depths) + 1.0
+ else:
+ inferred_depth = math.inf
else:
inferred_depth = 1.0
self._known_depths[identifier] = inferred_depth
