|  | 
|  | 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