|
40 | 40 | from poetry.repositories import RepositoryPool |
41 | 41 | from poetry.utils.env import Env |
42 | 42 |
|
43 | | - MarkerOriginDict = defaultdict[Package, defaultdict[Package, BaseMarker]] |
| 43 | + # markers[child_package][parent_package][groups] -> BaseMarker |
| 44 | + MarkerOriginDict = defaultdict[ |
| 45 | + Package, |
| 46 | + defaultdict[Package, defaultdict[frozenset[NormalizedName], BaseMarker]], |
| 47 | + ] |
44 | 48 |
|
45 | 49 |
|
46 | 50 | class Solver: |
@@ -238,7 +242,9 @@ def depth_first_search( |
238 | 242 | source: PackageNode, |
239 | 243 | ) -> tuple[list[list[PackageNode]], MarkerOriginDict]: |
240 | 244 | back_edges: dict[DFSNodeID, list[PackageNode]] = defaultdict(list) |
241 | | - markers: MarkerOriginDict = defaultdict(lambda: defaultdict(EmptyMarker)) |
| 245 | + markers: MarkerOriginDict = defaultdict( |
| 246 | + lambda: defaultdict(lambda: defaultdict(EmptyMarker)) |
| 247 | + ) |
242 | 248 | visited: set[DFSNodeID] = set() |
243 | 249 | topo_sorted_nodes: list[PackageNode] = [] |
244 | 250 |
|
@@ -272,12 +278,16 @@ def dfs_visit( |
272 | 278 |
|
273 | 279 | for out_neighbor in node.reachable(): |
274 | 280 | back_edges[out_neighbor.id].append(node) |
275 | | - marker = markers[out_neighbor.package][node.package] |
276 | | - markers[out_neighbor.package][node.package] = marker.union( |
| 281 | + groups = out_neighbor.groups |
| 282 | + prev_marker = markers[out_neighbor.package][node.package][groups] |
| 283 | + new_marker = ( |
277 | 284 | out_neighbor.marker |
278 | 285 | if node.package.is_root() |
279 | 286 | else out_neighbor.marker.without_extras() |
280 | 287 | ) |
| 288 | + markers[out_neighbor.package][node.package][groups] = prev_marker.union( |
| 289 | + new_marker |
| 290 | + ) |
281 | 291 | dfs_visit(out_neighbor, back_edges, visited, sorted_nodes, markers) |
282 | 292 | sorted_nodes.insert(0, node) |
283 | 293 |
|
@@ -398,20 +408,36 @@ def calculate_markers( |
398 | 408 | transitive_marker: dict[NormalizedName, BaseMarker] = { |
399 | 409 | group: EmptyMarker() for group in transitive_info.groups |
400 | 410 | } |
401 | | - for parent, m in markers[package].items(): |
| 411 | + for parent, group_markers in markers[package].items(): |
402 | 412 | parent_info = packages[parent] |
403 | 413 | if parent_info.groups: |
| 414 | + # If parent has groups, we need to intersect its per-group |
| 415 | + # markers with each edge marker and union into child's groups. |
404 | 416 | if parent_info.groups != set(parent_info.markers): |
405 | 417 | # there is a cycle -> we need one more iteration |
406 | 418 | has_incomplete_markers = True |
407 | 419 | continue |
408 | 420 | for group in parent_info.groups: |
409 | | - transitive_marker[group] = transitive_marker[group].union( |
410 | | - parent_info.markers[group].intersect(m) |
411 | | - ) |
| 421 | + for edge_marker in group_markers.values(): |
| 422 | + transitive_marker[group] = transitive_marker[ |
| 423 | + group |
| 424 | + ].union( |
| 425 | + parent_info.markers[group].intersect(edge_marker) |
| 426 | + ) |
412 | 427 | else: |
413 | | - for group in transitive_info.groups: |
414 | | - transitive_marker[group] = transitive_marker[group].union(m) |
| 428 | + # Parent is the root (no groups). Edge markers specify which |
| 429 | + # dependency groups the edge belongs to. We should only add |
| 430 | + # the edge marker to the corresponding child groups. |
| 431 | + for groups, edge_marker in group_markers.items(): |
| 432 | + assert groups, ( |
| 433 | + f"Package {package.name} at depth {depth} has no groups." |
| 434 | + f" All dependencies except for the root package at depth -1 must have groups" |
| 435 | + ) |
| 436 | + for group in transitive_info.groups: |
| 437 | + if group in groups: |
| 438 | + transitive_marker[group] = transitive_marker[ |
| 439 | + group |
| 440 | + ].union(edge_marker) |
415 | 441 | transitive_info.markers = transitive_marker |
416 | 442 |
|
417 | 443 |
|
|
0 commit comments