From 56819ae0795a94464fd35b3af148e80ac4796fce Mon Sep 17 00:00:00 2001 From: Erik-Cristian S Date: Wed, 1 Apr 2020 19:14:50 +0100 Subject: [PATCH] Fix handlying of typing.Any (#29) * Black format Signed-off-by: Erik-Cristian Seulean * Fix handling of typing.Any So far Any was not taken in consideration and it was failing to handle it correctly. If the base_type is Any, stop the recursive check and return as if everything is fine. Signed-off-by: Erik-Cristian Seulean --- attrs_strict/_error.py | 4 +--- attrs_strict/_type_validation.py | 12 +++++++++--- tests/test_dict.py | 14 +++++++++++++- tests/test_list.py | 4 +++- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/attrs_strict/_error.py b/attrs_strict/_error.py index de8e013..0b2ad62 100644 --- a/attrs_strict/_error.py +++ b/attrs_strict/_error.py @@ -45,9 +45,7 @@ def __init__(self, container, attribute): def __str__(self): error = "{} can not be empty and must be {} (got {})".format( - self.attribute.name, - self.attribute.type, - self.container, + self.attribute.name, self.attribute.type, self.container, ) return self._render(error) diff --git a/attrs_strict/_type_validation.py b/attrs_strict/_type_validation.py index 735822f..1d4a44d 100644 --- a/attrs_strict/_type_validation.py +++ b/attrs_strict/_type_validation.py @@ -1,7 +1,13 @@ import collections import typing -from ._error import AttributeTypeError, BadTypeError, EmptyError, TupleError, UnionError +from ._error import ( + AttributeTypeError, + BadTypeError, + EmptyError, + TupleError, + UnionError, +) def type_validator(empty_ok=True): @@ -31,7 +37,7 @@ def _validate_elements(attribute, value, expected_type): else expected_type ) - if base_type is None: + if base_type is None or base_type == typing.Any: return if base_type != typing.Union and not isinstance(value, base_type): @@ -54,7 +60,7 @@ def _validate_elements(attribute, value, expected_type): def _handle_set_or_list(attribute, container, expected_type): - element_type, = expected_type.__args__ + (element_type,) = expected_type.__args__ for element in container: try: diff --git a/tests/test_dict.py b/tests/test_dict.py index 55c68ed..c2c0556 100644 --- a/tests/test_dict.py +++ b/tests/test_dict.py @@ -1,5 +1,5 @@ import collections -from typing import DefaultDict, List +from typing import Any, Dict, DefaultDict, List import pytest @@ -43,3 +43,15 @@ def test_defaultdict_with_correct_type_no_raise(): attr.type = DefaultDict[int, List[int]] validator(None, attr, elem) + + +def test_dict_with_any_does_not_raise(): + elem = {"foo": 123, "b": "abc"} + + validator = type_validator() + + attr = MagicMock() + attr.name = "zoo" + attr.type = Dict[str, Any] + + validator(None, attr, elem) diff --git a/tests/test_list.py b/tests/test_list.py index ea4cae6..44ab628 100644 --- a/tests/test_list.py +++ b/tests/test_list.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Set, Tuple +from typing import Any, Dict, List, Set, Tuple import pytest @@ -80,6 +80,8 @@ def test_list_of_values_raise_value_error(values, type_, error_message): ([[1], [2], [3]], List[List[int]]), ({1, 2, 3}, Set[int]), ([{1: [1, 2, 3], 2: [3, 4, 5]}], List[Dict[int, List[int]]]), + ([1, 2, 3, 4], List[Any]), + ([1, 2, {"foo": "bar"}], List[Any]), ], ) def test_list_of_valid_values_no_raise(values, type_):