11import collections
2+ import operator
23
34from .providers import AbstractResolver
4- from .structs import DirectedGraph , build_iter_view
5+ from .structs import DirectedGraph , IteratorMapping , build_iter_view
56
67
78RequirementInformation = collections .namedtuple (
@@ -73,45 +74,12 @@ def __repr__(self):
7374 )
7475 return "Criterion({})" .format (requirements )
7576
76- @classmethod
77- def from_requirement (cls , provider , requirement , parent ):
78- """Build an instance from a requirement."""
79- matches = provider .find_matches (requirements = [requirement ])
80- cands = build_iter_view (matches )
81- infos = [RequirementInformation (requirement , parent )]
82- criterion = cls (cands , infos , incompatibilities = [])
83- if not cands :
84- raise RequirementsConflicted (criterion )
85- return criterion
86-
8777 def iter_requirement (self ):
8878 return (i .requirement for i in self .information )
8979
9080 def iter_parent (self ):
9181 return (i .parent for i in self .information )
9282
93- def merged_with (self , provider , requirement , parent ):
94- """Build a new instance from this and a new requirement."""
95- infos = list (self .information )
96- infos .append (RequirementInformation (requirement , parent ))
97- matches = provider .find_matches ([r for r , _ in infos ])
98- cands = build_iter_view (matches )
99- criterion = type (self )(cands , infos , list (self .incompatibilities ))
100- if not cands :
101- raise RequirementsConflicted (criterion )
102- return criterion
103-
104- def excluded_of (self , candidates ):
105- """Build a new instance from this, but excluding specified candidates.
106-
107- Returns the new instance, or None if we still have no valid candidates.
108- """
109- cands = self .candidates .excluding (candidates )
110- if not cands :
111- return None
112- incompats = self .incompatibilities + candidates
113- return type (self )(cands , list (self .information ), incompats )
114-
11583
11684class ResolutionError (ResolverException ):
11785 pass
@@ -168,13 +136,42 @@ def _push_new_state(self):
168136
169137 def _merge_into_criterion (self , requirement , parent ):
170138 self ._r .adding_requirement (requirement = requirement , parent = parent )
171- name = self ._p .identify (requirement_or_candidate = requirement )
172- if name in self .state .criteria :
173- crit = self .state .criteria [name ]
174- crit = crit .merged_with (self ._p , requirement , parent )
139+
140+ identifier = self ._p .identify (requirement_or_candidate = requirement )
141+ criterion = self .state .criteria .get (identifier )
142+ if criterion :
143+ incompatibilities = list (criterion .incompatibilities )
144+ else :
145+ incompatibilities = []
146+
147+ matches = self ._p .find_matches (
148+ identifier = identifier ,
149+ requirements = IteratorMapping (
150+ self .state .criteria ,
151+ operator .methodcaller ("iter_requirement" ),
152+ {identifier : [requirement ]},
153+ ),
154+ incompatibilities = IteratorMapping (
155+ self .state .criteria ,
156+ operator .attrgetter ("incompatibilities" ),
157+ {identifier : incompatibilities },
158+ ),
159+ )
160+
161+ if criterion :
162+ information = list (criterion .information )
163+ information .append (RequirementInformation (requirement , parent ))
175164 else :
176- crit = Criterion .from_requirement (self ._p , requirement , parent )
177- return name , crit
165+ information = [RequirementInformation (requirement , parent )]
166+
167+ criterion = Criterion (
168+ candidates = build_iter_view (matches ),
169+ information = information ,
170+ incompatibilities = incompatibilities ,
171+ )
172+ if not criterion .candidates :
173+ raise RequirementsConflicted (criterion )
174+ return identifier , criterion
178175
179176 def _get_criterion_item_preference (self , item ):
180177 name , criterion = item
@@ -268,7 +265,7 @@ def _backtrack(self):
268265 broken_state = self ._states .pop ()
269266 name , candidate = broken_state .mapping .popitem ()
270267 incompatibilities_from_broken = [
271- (k , v .incompatibilities )
268+ (k , list ( v .incompatibilities ) )
272269 for k , v in broken_state .criteria .items ()
273270 ]
274271
@@ -287,10 +284,27 @@ def _patch_criteria():
287284 criterion = self .state .criteria [k ]
288285 except KeyError :
289286 continue
290- criterion = criterion .excluded_of (incompatibilities )
291- if criterion is None :
287+ matches = self ._p .find_matches (
288+ identifier = k ,
289+ requirements = IteratorMapping (
290+ self .state .criteria ,
291+ operator .methodcaller ("iter_requirement" ),
292+ ),
293+ incompatibilities = IteratorMapping (
294+ self .state .criteria ,
295+ operator .attrgetter ("incompatibilities" ),
296+ {k : incompatibilities },
297+ ),
298+ )
299+ candidates = build_iter_view (matches )
300+ if not candidates :
292301 return False
293- self .state .criteria [k ] = criterion
302+ incompatibilities .extend (criterion .incompatibilities )
303+ self .state .criteria [k ] = Criterion (
304+ candidates = candidates ,
305+ information = list (criterion .information ),
306+ incompatibilities = incompatibilities ,
307+ )
294308 return True
295309
296310 self ._push_new_state ()
0 commit comments