diff --git a/changelog.d/533.change.rst b/changelog.d/533.change.rst new file mode 100644 index 000000000..4d4e08dbb --- /dev/null +++ b/changelog.d/533.change.rst @@ -0,0 +1,2 @@ +Fixed ``attr.validators.deep_iterable()`` +and ``attr.validators.deep_mapping()`` type stubs. diff --git a/src/attr/validators.pyi b/src/attr/validators.pyi index 01af06845..c0ef52527 100644 --- a/src/attr/validators.pyi +++ b/src/attr/validators.pyi @@ -1,7 +1,22 @@ -from typing import Container, List, Union, TypeVar, Type, Any, Optional, Tuple +from typing import ( + Container, + List, + Union, + TypeVar, + Type, + Any, + Optional, + Tuple, + Iterable, + Mapping, +) from . import _ValidatorType _T = TypeVar("_T") +_I = TypeVar("_I", bound=Iterable[_T]) +_K = TypeVar("_K") +_V = TypeVar("_V") +_M = TypeVar("_V", bound=Mapping[_K, _V]) def instance_of( type: Union[Tuple[Type[_T], ...], Type[_T]] @@ -14,11 +29,11 @@ def in_(options: Container[_T]) -> _ValidatorType[_T]: ... def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ... def deep_iterable( member_validator: _ValidatorType[_T], - iterable_validator: Optional[_ValidatorType[_T]], -) -> _ValidatorType[_T]: ... + iterable_validator: Optional[_ValidatorType[_I]] = ..., +) -> _ValidatorType[_I]: ... def deep_mapping( - key_validator: _ValidatorType[_T], - value_validator: _ValidatorType[_T], - mapping_validator: Optional[_ValidatorType[_T]], -) -> _ValidatorType[_T]: ... + key_validator: _ValidatorType[_K], + value_validator: _ValidatorType[_V], + mapping_validator: Optional[_ValidatorType[_M]] = ..., +) -> _ValidatorType[_M]: ... def is_callable() -> _ValidatorType[_T]: ... diff --git a/tests/typing_example.py b/tests/typing_example.py index b68ce6e9e..18e837e52 100644 --- a/tests/typing_example.py +++ b/tests/typing_example.py @@ -1,4 +1,4 @@ -from typing import Any, List +from typing import Any, Dict, List, Tuple import attr @@ -114,3 +114,40 @@ class Error(Exception): # ConvCDefaultIfNone(1) # ConvCDefaultIfNone(None) + + +# Validators +@attr.s +class Validated: + a = attr.ib( + type=List[C], + validator=attr.validators.deep_iterable( + attr.validators.instance_of(C), attr.validators.instance_of(list) + ), + ) + a = attr.ib( + type=Tuple[C], + validator=attr.validators.deep_iterable( + attr.validators.instance_of(C), attr.validators.instance_of(tuple) + ), + ) + b = attr.ib( + type=List[C], + validator=attr.validators.deep_iterable( + attr.validators.instance_of(C) + ), + ) + c = attr.ib( + type=Dict[C, D], + validator=attr.validators.deep_mapping( + attr.validators.instance_of(C), + attr.validators.instance_of(D), + attr.validators.instance_of(dict), + ), + ) + d = attr.ib( + type=Dict[C, D], + validator=attr.validators.deep_mapping( + attr.validators.instance_of(C), attr.validators.instance_of(D) + ), + )