Correct type of dependency_groups#40
Conversation
sirosen
left a comment
There was a problem hiding this comment.
Hi, thanks for catching this and filing #39!
We fixed this when we ported dependency-groups into packaging, but didn't backport the fix to here.
We should not use list, however, for public interfaces where a broader category of iterables are acceptable. Especially because list is invariant, so this change would make it a type-checking error to pass a list[str] to these interfaces (which is wrong).
Some of these could use Iterable, but in packaging we used Sequence, so I think we should do the same here.
Co-authored-by: Stephen Rosen <sirosen@globus.org>
raw_group = self.dependency_groups[group]
if not isinstance(raw_group, list):
raise TypeError(f"Dependency group '{group}' is not a list")
self.dependency_groups, self._normalized_to_original = _normalize_group_names(
dependency_groups
)def _normalize_group_names(
dependency_groups: Mapping[str, list[str | Mapping[str, str]]],
) -> tuple[Mapping[str, list[str | Mapping[str, str]]], Mapping[str, str]]:
"""
Normalize group names and return both normalized groups and reverse mapping.
Returns a tuple of (normalized_groups, normalized_to_original).
"""
original_names: dict[str, list[str]] = {}
normalized_groups = {}
normalized_to_original: dict[str, str] = {}
for group_name, value in dependency_groups.items():
normed_group_name = _normalize_name(group_name)
original_names.setdefault(normed_group_name, []).append(group_name)
normalized_groups[normed_group_name] = value
normalized_to_original[normed_group_name] = group_name
errors = []
for normed_name, names in original_names.items():
if len(names) > 1:
errors.append(f"{normed_name} ({', '.join(names)})")
if errors:
raise ValueError(f"Duplicate dependency group names: {', '.join(errors)}")
return normalized_groups, normalized_to_originalvalues of If you think it's necessary, I'll add this comment to this PR. My English is not very good, so maybe I didn't explain it very well. |
No worries! I don't think I'm having trouble understanding what you're saying.
Why would it be necessary for us to convert inputs to If you look at the implementation in We can't fully copy in the
def f(x: list[int | str]): ...
def g(x: Sequence[int | str]): ...
y: list[str] = []
f(y) # type checkers mark this as an error
g(y) # this is okay
|
|
In line 143, we check that we have a list, and the type of this value exactly matches what we received as input. Therefore, it is necessary to convert to a list, or weaken this check. |
Yes. Would expanding the check to allow any |
close #39
📚 Documentation preview 📚: https://dependency-groups--40.org.readthedocs.build/en/40/