diff --git a/python_modules/dagster/dagster/_check/__init__.py b/python_modules/dagster/dagster/_check/__init__.py index 54b6f6ce6ce85..9908af0f45224 100644 --- a/python_modules/dagster/dagster/_check/__init__.py +++ b/python_modules/dagster/dagster/_check/__init__.py @@ -1233,6 +1233,34 @@ def opt_nullable_iterable_param( return iterable_param(obj, param_name, of_type, additional_message) +def old_is_iterable( + obj: object, + of_type: Optional[TypeOrTupleOfTypes] = None, + additional_message: Optional[str] = None, +) -> Iterable: + if not isinstance(obj, Iterable): + raise _type_mismatch_error(obj, list, additional_message) + + if not of_type: + return obj + + return _check_iterable_items(obj, of_type, "list") + + +def is_iterable( + obj: object, + of_type: Optional[TTypeOrTupleOfTTypes[T]] = None, + additional_message: Optional[str] = None, +) -> Iterable[T]: + if not isinstance(obj, Iterable): + raise _type_mismatch_error(obj, list, additional_message) + + if not of_type: + return obj + + return _check_iterable_items(obj, of_type, "list") + + # ######################## # ##### SET # ######################## diff --git a/python_modules/dagster/dagster_tests/definitions_tests/decorators_tests/test_asset_check_decorator.py b/python_modules/dagster/dagster_tests/definitions_tests/decorators_tests/test_asset_check_decorator.py index 234817af59eb1..d78fa16ed40d6 100644 --- a/python_modules/dagster/dagster_tests/definitions_tests/decorators_tests/test_asset_check_decorator.py +++ b/python_modules/dagster/dagster_tests/definitions_tests/decorators_tests/test_asset_check_decorator.py @@ -848,9 +848,7 @@ def checks() -> Iterable[AssetCheckResult]: yield AssetCheckResult(passed=False, asset_key="asset1", check_name="check2") yield AssetCheckResult(passed=True, asset_key="asset2") - checks_ret_obj = checks() - assert isinstance(checks_ret_obj, Iterable) - results = check.is_list(list(checks_ret_obj), of_type=AssetCheckResult) + results = check.is_list(check.is_iterable(checks()), of_type=AssetCheckResult) assert len(results) == 3 assert all(isinstance(result, AssetCheckResult) for result in results) assert results[0].passed diff --git a/python_modules/dagster/dagster_tests/general_tests/check_tests/test_check.py b/python_modules/dagster/dagster_tests/general_tests/check_tests/test_check.py index 92954699245bc..1cc5a77aab9dc 100644 --- a/python_modules/dagster/dagster_tests/general_tests/check_tests/test_check.py +++ b/python_modules/dagster/dagster_tests/general_tests/check_tests/test_check.py @@ -3,7 +3,7 @@ import sys from collections import defaultdict from contextlib import contextmanager -from typing import Dict, Iterable, List, Mapping, Optional, Sequence, Set, Union +from typing import Any, Dict, Iterable, List, Mapping, Optional, Sequence, Set, Union import dagster._check as check import pytest @@ -1514,6 +1514,42 @@ def test_opt_iterable(): check.opt_iterable_param(["atr", None], "nonedoesntcount", of_type=str) +def test_is_iterable() -> None: + assert check.is_iterable([]) == [] + assert check.is_iterable((1, 2)) == tuple([1, 2]) + assert check.is_iterable("foo") == "foo" # str is iterable + assert check.is_iterable({"a": 1}) == {"a": 1} # dict is iterable + + assert check.is_iterable([1, "str"]) == [1, "str"] + + with pytest.raises(CheckError): + check.is_iterable([1, "str"], of_type=int) + + with pytest.raises(CheckError): + check.is_iterable([1, "str"], of_type=str) + + with pytest.raises(CheckError): + check.is_iterable(None) + + with pytest.raises(CheckError): + check.is_iterable(1) + + +def test_is_iterable_typing() -> None: + def returns_iterable_of_int_but_typed_any() -> Any: + return [1, 2] + + def returns_iterable_of_t() -> Iterable[int]: + any_typed = returns_iterable_of_int_but_typed_any() + retval = check.is_iterable(any_typed, of_type=str) + # That the type: ignore is necessary is proof that + # is_iterable flows type information correctly + return retval # type: ignore + + # meaningless assert. The test is show the typechecker working + assert returns_iterable_of_t + + # ################################################################################################### # ##### CHECK BUILDER # ###################################################################################################