| 
 | 1 | +# Copyright 2025 The HuggingFace Team. All rights reserved.  | 
 | 2 | +#  | 
 | 3 | +# Licensed under the Apache License, Version 2.0 (the "License");  | 
 | 4 | +# you may not use this file except in compliance with the License.  | 
 | 5 | +# You may obtain a copy of the License at  | 
 | 6 | +#  | 
 | 7 | +#     http://www.apache.org/licenses/LICENSE-2.0  | 
 | 8 | +#  | 
 | 9 | +# Unless required by applicable law or agreed to in writing, software  | 
 | 10 | +# distributed under the License is distributed on an "AS IS" BASIS,  | 
 | 11 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  | 
 | 12 | +# See the License for the specific language governing permissions and  | 
 | 13 | +# limitations under the License.  | 
 | 14 | +"""  | 
 | 15 | +Typing utilities: Utilities related to type checking and validation  | 
 | 16 | +"""  | 
 | 17 | + | 
 | 18 | +from typing import Any, Dict, List, Set, Tuple, Type, Union, get_args, get_origin  | 
 | 19 | + | 
 | 20 | + | 
 | 21 | +def _is_valid_type(obj: Any, class_or_tuple: Union[Type, Tuple[Type, ...]]) -> bool:  | 
 | 22 | +    """  | 
 | 23 | +    Checks if an object is an instance of any of the provided types. For collections, it checks if every element is of  | 
 | 24 | +    the correct type as well.  | 
 | 25 | +    """  | 
 | 26 | +    if not isinstance(class_or_tuple, tuple):  | 
 | 27 | +        class_or_tuple = (class_or_tuple,)  | 
 | 28 | + | 
 | 29 | +    # Unpack unions  | 
 | 30 | +    unpacked_class_or_tuple = []  | 
 | 31 | +    for t in class_or_tuple:  | 
 | 32 | +        if get_origin(t) is Union:  | 
 | 33 | +            unpacked_class_or_tuple.extend(get_args(t))  | 
 | 34 | +        else:  | 
 | 35 | +            unpacked_class_or_tuple.append(t)  | 
 | 36 | +    class_or_tuple = tuple(unpacked_class_or_tuple)  | 
 | 37 | + | 
 | 38 | +    if Any in class_or_tuple:  | 
 | 39 | +        return True  | 
 | 40 | + | 
 | 41 | +    obj_type = type(obj)  | 
 | 42 | +    # Classes with obj's type  | 
 | 43 | +    class_or_tuple = {t for t in class_or_tuple if isinstance(obj, get_origin(t) or t)}  | 
 | 44 | + | 
 | 45 | +    # Singular types (e.g. int, ControlNet, ...)  | 
 | 46 | +    # Untyped collections (e.g. List, but not List[int])  | 
 | 47 | +    elem_class_or_tuple = {get_args(t) for t in class_or_tuple}  | 
 | 48 | +    if () in elem_class_or_tuple:  | 
 | 49 | +        return True  | 
 | 50 | +    # Typed lists or sets  | 
 | 51 | +    elif obj_type in (list, set):  | 
 | 52 | +        return any(all(_is_valid_type(x, t) for x in obj) for t in elem_class_or_tuple)  | 
 | 53 | +    # Typed tuples  | 
 | 54 | +    elif obj_type is tuple:  | 
 | 55 | +        return any(  | 
 | 56 | +            # Tuples with any length and single type (e.g. Tuple[int, ...])  | 
 | 57 | +            (len(t) == 2 and t[-1] is Ellipsis and all(_is_valid_type(x, t[0]) for x in obj))  | 
 | 58 | +            or  | 
 | 59 | +            # Tuples with fixed length and any types (e.g. Tuple[int, str])  | 
 | 60 | +            (len(obj) == len(t) and all(_is_valid_type(x, tt) for x, tt in zip(obj, t)))  | 
 | 61 | +            for t in elem_class_or_tuple  | 
 | 62 | +        )  | 
 | 63 | +    # Typed dicts  | 
 | 64 | +    elif obj_type is dict:  | 
 | 65 | +        return any(  | 
 | 66 | +            all(_is_valid_type(k, kt) and _is_valid_type(v, vt) for k, v in obj.items())  | 
 | 67 | +            for kt, vt in elem_class_or_tuple  | 
 | 68 | +        )  | 
 | 69 | + | 
 | 70 | +    else:  | 
 | 71 | +        return False  | 
 | 72 | + | 
 | 73 | + | 
 | 74 | +def _get_detailed_type(obj: Any) -> Type:  | 
 | 75 | +    """  | 
 | 76 | +    Gets a detailed type for an object, including nested types for collections.  | 
 | 77 | +    """  | 
 | 78 | +    obj_type = type(obj)  | 
 | 79 | + | 
 | 80 | +    if obj_type in (list, set):  | 
 | 81 | +        obj_origin_type = List if obj_type is list else Set  | 
 | 82 | +        elems_type = Union[tuple({_get_detailed_type(x) for x in obj})]  | 
 | 83 | +        return obj_origin_type[elems_type]  | 
 | 84 | +    elif obj_type is tuple:  | 
 | 85 | +        return Tuple[tuple(_get_detailed_type(x) for x in obj)]  | 
 | 86 | +    elif obj_type is dict:  | 
 | 87 | +        keys_type = Union[tuple({_get_detailed_type(k) for k in obj.keys()})]  | 
 | 88 | +        values_type = Union[tuple({_get_detailed_type(k) for k in obj.values()})]  | 
 | 89 | +        return Dict[keys_type, values_type]  | 
 | 90 | +    else:  | 
 | 91 | +        return obj_type  | 
0 commit comments