1
1
from __future__ import annotations
2
2
3
3
import sys
4
+ from collections import defaultdict
4
5
from typing import TYPE_CHECKING , TypedDict
5
6
6
7
from packaging .requirements import InvalidRequirement , Requirement
@@ -26,28 +27,64 @@ def resolve(root: Path, groups: set[str]) -> set[Requirement]:
26
27
return set ()
27
28
with pyproject_file .open ("rb" ) as file_handler :
28
29
pyproject = tomllib .load (file_handler )
29
- dependency_groups = pyproject ["dependency-groups" ]
30
- if not isinstance (dependency_groups , dict ):
31
- msg = f"dependency-groups is { type (dependency_groups ).__name__ } instead of table"
30
+ dependency_groups_raw = pyproject ["dependency-groups" ]
31
+ if not isinstance (dependency_groups_raw , dict ):
32
+ msg = f"dependency-groups is { type (dependency_groups_raw ).__name__ } instead of table"
32
33
raise Fail (msg )
34
+ original_names_lookup , dependency_groups = _normalize_group_names (dependency_groups_raw )
33
35
result : set [Requirement ] = set ()
34
36
for group in groups :
35
- result = result .union (_resolve_dependency_group (dependency_groups , group ))
37
+ result = result .union (_resolve_dependency_group (dependency_groups , group , original_names_lookup ))
36
38
return result
37
39
38
40
41
+ def _normalize_group_names (
42
+ dependency_groups : dict [str , list [str ] | _IncludeGroup ],
43
+ ) -> tuple [dict [str , str ], dict [str , list [str ] | _IncludeGroup ]]:
44
+ original_names = defaultdict (list )
45
+ normalized_groups = {}
46
+
47
+ for group_name , value in dependency_groups .items ():
48
+ normed_group_name : str = canonicalize_name (group_name )
49
+ original_names [normed_group_name ].append (group_name )
50
+ normalized_groups [normed_group_name ] = value
51
+
52
+ errors = []
53
+ for normed_name , names in original_names .items ():
54
+ if len (names ) > 1 :
55
+ errors .append (f"{ normed_name } ({ ', ' .join (names )} )" )
56
+ if errors :
57
+ msg = f"Duplicate dependency group names: { ', ' .join (errors )} "
58
+ raise ValueError (msg )
59
+
60
+ original_names_lookup = {
61
+ normed_name : original_names [0 ]
62
+ for normed_name , original_names in original_names .items ()
63
+ if len (original_names ) == 1
64
+ }
65
+
66
+ return original_names_lookup , normalized_groups
67
+
68
+
39
69
def _resolve_dependency_group (
40
- dependency_groups : dict [str , list [str ] | _IncludeGroup ], group : str , past_groups : tuple [str , ...] = ()
70
+ dependency_groups : dict [str , list [str ] | _IncludeGroup ],
71
+ group : str ,
72
+ original_names_lookup : dict [str , str ],
73
+ past_groups : tuple [str , ...] = (),
41
74
) -> set [Requirement ]:
42
75
if group in past_groups :
43
- msg = f"Cyclic dependency group include: { group !r} -> { past_groups !r} "
76
+ original_group = original_names_lookup .get (group , group )
77
+ original_past_groups = tuple (original_names_lookup .get (g , g ) for g in past_groups )
78
+ msg = f"Cyclic dependency group include: { original_group !r} -> { original_past_groups !r} "
44
79
raise Fail (msg )
45
80
if group not in dependency_groups :
46
- msg = f"dependency group { group !r} not found"
81
+ original_group = original_names_lookup .get (group , group )
82
+ msg = f"dependency group { original_group !r} not found"
47
83
raise Fail (msg )
48
84
raw_group = dependency_groups [group ]
49
85
if not isinstance (raw_group , list ):
50
- msg = f"dependency group { group !r} is not a list"
86
+ original_group = original_names_lookup .get (group , group )
87
+ msg = f"dependency group { original_group !r} is not a list"
51
88
raise Fail (msg )
52
89
53
90
result = set ()
@@ -63,7 +100,11 @@ def _resolve_dependency_group(
63
100
raise Fail (msg ) from exc
64
101
elif isinstance (item , dict ) and tuple (item .keys ()) == ("include-group" ,):
65
102
include_group = canonicalize_name (next (iter (item .values ())))
66
- result = result .union (_resolve_dependency_group (dependency_groups , include_group , (* past_groups , group )))
103
+ result = result .union (
104
+ _resolve_dependency_group (
105
+ dependency_groups , include_group , original_names_lookup , (* past_groups , group )
106
+ )
107
+ )
67
108
else :
68
109
msg = f"invalid dependency group item: { item !r} "
69
110
raise Fail (msg )
0 commit comments