1
1
import collections
2
+ import operator
2
3
3
4
from .providers import AbstractResolver
4
- from .structs import DirectedGraph , build_iter_view
5
+ from .structs import DirectedGraph , IteratorMapping , build_iter_view
5
6
6
7
7
8
RequirementInformation = collections .namedtuple (
@@ -73,45 +74,12 @@ def __repr__(self):
73
74
)
74
75
return "Criterion({})" .format (requirements )
75
76
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
-
87
77
def iter_requirement (self ):
88
78
return (i .requirement for i in self .information )
89
79
90
80
def iter_parent (self ):
91
81
return (i .parent for i in self .information )
92
82
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
-
115
83
116
84
class ResolutionError (ResolverException ):
117
85
pass
@@ -168,13 +136,42 @@ def _push_new_state(self):
168
136
169
137
def _merge_into_criterion (self , requirement , parent ):
170
138
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 ))
175
164
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
178
175
179
176
def _get_criterion_item_preference (self , item ):
180
177
name , criterion = item
@@ -268,7 +265,7 @@ def _backtrack(self):
268
265
broken_state = self ._states .pop ()
269
266
name , candidate = broken_state .mapping .popitem ()
270
267
incompatibilities_from_broken = [
271
- (k , v .incompatibilities )
268
+ (k , list ( v .incompatibilities ) )
272
269
for k , v in broken_state .criteria .items ()
273
270
]
274
271
@@ -287,10 +284,27 @@ def _patch_criteria():
287
284
criterion = self .state .criteria [k ]
288
285
except KeyError :
289
286
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 :
292
301
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
+ )
294
308
return True
295
309
296
310
self ._push_new_state ()
0 commit comments