From 8a03493aedac836a06f3cfad422cd9ccb2b94ffe Mon Sep 17 00:00:00 2001 From: uwezkhan06 Date: Mon, 18 May 2026 21:02:29 +0530 Subject: [PATCH 1/2] Add input type validation to deep_mapping validator to prevent crashes on non-mapping inputs --- src/attr/validators.py | 10 ++++++++++ tests/test_validators.py | 14 ++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/attr/validators.py b/src/attr/validators.py index 0b1a29443..459971422 100644 --- a/src/attr/validators.py +++ b/src/attr/validators.py @@ -10,6 +10,7 @@ from contextlib import contextmanager from re import Pattern +from ._compat import Mapping from ._config import get_run_validators, set_run_validators from ._make import _AndValidator, and_, attrib, attrs from .converters import default_if_none @@ -397,6 +398,15 @@ def __call__(self, inst, attr, value): if self.mapping_validator is not None: self.mapping_validator(inst, attr, value) + if not isinstance(value, Mapping): + msg = f"'{attr.name}' must be a mapping (got {value!r} that is a {value.__class__!r})." + raise TypeError( + msg, + attr, + Mapping, + value, + ) + for key in value: if self.key_validator is not None: self.key_validator(inst, attr, key) diff --git a/tests/test_validators.py b/tests/test_validators.py index 8caa64272..9c9aee78b 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -807,6 +807,20 @@ def test_validators_iterables(self, conv): assert and_(*value_validator) == v.value_validator assert and_(*mapping_validator) == v.mapping_validator + def test_fail_non_mapping(self): + """ + Raise TypeError if value is not a mapping. + """ + key_validator = instance_of(str) + value_validator = instance_of(int) + v = deep_mapping(key_validator, value_validator) + a = simple_attr("test") + with pytest.raises(TypeError) as e: + v(None, a, [1, 2, 3]) + + msg = f"'{a.name}' must be a mapping (got [1, 2, 3] that is a {list!r})." + assert msg in str(e.value) + class TestIsCallable: """ From effcbe7f4bdbff9182b077dc44cbf4d58d325ca5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 18 May 2026 15:33:41 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_validators.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_validators.py b/tests/test_validators.py index 9c9aee78b..e4b4b9eff 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -818,7 +818,9 @@ def test_fail_non_mapping(self): with pytest.raises(TypeError) as e: v(None, a, [1, 2, 3]) - msg = f"'{a.name}' must be a mapping (got [1, 2, 3] that is a {list!r})." + msg = ( + f"'{a.name}' must be a mapping (got [1, 2, 3] that is a {list!r})." + ) assert msg in str(e.value)