11from __future__ import annotations
22
33import sys
4+ from collections import defaultdict
45from typing import TYPE_CHECKING , TypedDict
56
67from packaging .requirements import InvalidRequirement , Requirement
@@ -26,28 +27,64 @@ def resolve(root: Path, groups: set[str]) -> set[Requirement]:
2627 return set ()
2728 with pyproject_file .open ("rb" ) as file_handler :
2829 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"
3233 raise Fail (msg )
34+ original_names_lookup , dependency_groups = _normalize_group_names (dependency_groups_raw )
3335 result : set [Requirement ] = set ()
3436 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 ))
3638 return result
3739
3840
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+
3969def _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 , ...] = (),
4174) -> set [Requirement ]:
4275 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} "
4479 raise Fail (msg )
4580 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"
4783 raise Fail (msg )
4884 raw_group = dependency_groups [group ]
4985 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"
5188 raise Fail (msg )
5289
5390 result = set ()
@@ -63,7 +100,11 @@ def _resolve_dependency_group(
63100 raise Fail (msg ) from exc
64101 elif isinstance (item , dict ) and tuple (item .keys ()) == ("include-group" ,):
65102 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+ )
67108 else :
68109 msg = f"invalid dependency group item: { item !r} "
69110 raise Fail (msg )
0 commit comments