The cast(type, obj)
is useful but lack of runtime type checking. Therefore, considering the following code:
from types import GenericAlias, UnionType
from typing import Any, cast
from annotated_types import T
from typeguard import check_type
def ensure_type(value, expected_type): # noqa: ANN401 This function should hold Any value
"""Check the type and return value only if the types are matched.
Otherwise, raise TypeError.
"""
if check_type(value, expected_type):
return cast("T", value)
msg = f"Type check failed: type({value}) is {type(value)}, expected {expected_type}"
raise TypeError(msg)
It would be clearer to use obj = ensure_type(..., type)
than if check_type(obj, type)
:
# Using `ensure_type`
data = ensure_type(request_some_data(), dict[str])
key = ensure_type(data.get("key"), PromisedKey)
print(key)
# Using `check_type`
data = request_some_data()
if check_type(data, dict[str]):
key = data.get("key")
if check_type(key, PromisedKey):
print(key)
However, I found it difficult to write type hints and make mypy
understand. I guess it might be something like
def ensure_type(value: Any, expected_type: type[T] | GenericAlias | UnionType) -> <the_same_type_of_expected_type>:
Looking at the source for the typeguard
package, the check_type
function has the signature:
@overload def check_type( value: object, expected_type: type[T], *, forward_ref_policy: ForwardRefPolicy = ..., typecheck_fail_callback: TypeCheckFailCallback | None = ..., collection_check_strategy: CollectionCheckStrategy = ..., ) -> T: ... @overload def check_type( value: object, expected_type: Any, *, forward_ref_policy: ForwardRefPolicy = ..., typecheck_fail_callback: TypeCheckFailCallback | None = ..., collection_check_strategy: CollectionCheckStrategy = ..., ) -> Any: ...
You can use something similar:
@overload
def ensure_type(value: object, expected_type: type[T]) -> T: ...
@overload
def ensure_type(value: object, expected_type: GenericAlias) -> GenericAlias: ...
@overload
def ensure_type(value: object, expected_type: UnionType) -> UnionType: ...
def ensure_type(value, expected_type):
"""Check the type and return value only if the types are matched.
Otherwise, raise TypeError.
"""
try:
return check_type(value, expected_type)
except TypeError:
# Override the check_type error message with your custom message.
msg = f"Type check failed: type({value}) is {type(value)}, expected {expected_type}"
raise TypeError(msg)