diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d725bf5..6676030 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,9 @@ Unreleased - Remove support for Python 3.8 - Correct the type of the ``dependency_groups`` parameter to ``resolve()``, ``resolve_all()``, and ``DependencyGroupsResolver()``. +- Raise a clear ``TypeError`` when an ``include-group`` value is not a string + (was a cryptic ``TypeError`` from name normalization), and accept any + ``Mapping`` for include items, not only ``dict``. 1.3.1 ----- diff --git a/src/dependency_groups/_implementation.py b/src/dependency_groups/_implementation.py index def4f8b..c7533ad 100644 --- a/src/dependency_groups/_implementation.py +++ b/src/dependency_groups/_implementation.py @@ -154,11 +154,15 @@ def _parse_group( # valid PEP 508 Dependency Specifier # raises InvalidRequirement on failure elements.append(Requirement(item)) - elif isinstance(item, dict): + elif isinstance(item, Mapping): if tuple(item.keys()) != ("include-group",): raise ValueError(f"Invalid dependency group item: {item}") include_group = next(iter(item.values())) + if not isinstance(include_group, str): + raise TypeError( + f"Invalid include-group value, must be a string: {item}" + ) elements.append(DependencyGroupInclude(include_group=include_group)) else: raise ValueError(f"Invalid dependency group item: {item}") diff --git a/tests/test_resolve_func.py b/tests/test_resolve_func.py index 2bd3408..43f2025 100644 --- a/tests/test_resolve_func.py +++ b/tests/test_resolve_func.py @@ -166,6 +166,27 @@ def test_unknown_object_shape(item): resolve(groups, "test") +def test_non_str_include_group_value(): + groups = {"test": [{"include-group": 5}]} + with pytest.raises( + TypeError, match="Invalid include-group value, must be a string:" + ): + resolve(groups, "test") + + +def test_mapping_include_group_item(): + import types + + groups = { + "test": [ + "pytest", + types.MappingProxyType({"include-group": "runtime"}), + ], + "runtime": ["sqlalchemy"], + } + assert set(resolve(groups, "test")) == {"pytest", "sqlalchemy"} + + def test_resolve_all_empty(): groups = {} assert resolve_all(groups) == {}