示例#1
0
def detect_link(field: ModelField) -> Optional[LinkInfo]:
    """
    It detects link and returns LinkInfo if any found.

    :param field: ModelField
    :return: Optional[LinkInfo]
    """
    if field.type_ == Link:
        if field.allow_none is True:
            return LinkInfo(
                field=field.name,
                model_class=field.sub_fields[0].type_,  # type: ignore
                link_type=LinkTypes.OPTIONAL_DIRECT,
            )
        return LinkInfo(
            field=field.name,
            model_class=field.sub_fields[0].type_,  # type: ignore
            link_type=LinkTypes.DIRECT,
        )
    if (inspect.isclass(get_origin(field.outer_type_))
            and issubclass(get_origin(field.outer_type_), list)  # type: ignore
            and len(field.sub_fields) == 1  # type: ignore
        ):
        internal_field = field.sub_fields[0]  # type: ignore
        if internal_field.type_ == Link:
            if internal_field.allow_none is True:
                return None
            return LinkInfo(
                field=field.name,
                model_class=internal_field.sub_fields[0].type_,  # type: ignore
                link_type=LinkTypes.LIST,
            )
    return None
示例#2
0
def is_list_type(t: Any, test_type: Optional[type] = None) -> bool:
    """Check if `t` is list type.

    And optionally check if the list items are of `test_type`

    >>> is_list_type(List[int])
    True
    >>> is_list_type(Optional[List[int]])
    True
    >>> is_list_type(Optional[List[int]], int)
    True
    >>> is_list_type(Optional[List[int]], str)
    False
    >>> is_list_type(Optional[int])
    False
    >>> is_list_type(List[Tuple[int, int]])
    True
    >>> is_list_type(List[Tuple[int, int]], int)
    False
    >>> is_list_type(List[Tuple[int, int]], Tuple[int, int])
    True
    >>> is_list_type(List[strEnum], Enum)
    True
    >>> is_list_type(int)
    False
    >>> is_list_type(Literal[1,2,3])
    False
    >>> is_list_type(List[Union[str, int]])
    True
    >>> is_list_type(List[Union[str, int]], Union[str, int])
    False
    >>> is_list_type(List[Union[str, int]], str)
    True
    >>> is_list_type(List[Union[str, int]], int)
    False
    >>> is_list_type(List[Union[str, int]], Union[int, int])
    False
    """
    if get_origin(t):
        if is_optional_type(t) or is_union_type(t):
            for arg in get_args(t):
                if is_list_type(arg, test_type):
                    return True
        elif get_origin(t) == Literal:  # type:ignore
            return False  # Literal cannot contain lists see pep 586
        elif issubclass(get_origin(t), list):  # type: ignore
            if test_type and get_args(t):
                first_arg = get_args(t)[0]
                # To support a list with union of multiple product blocks.
                if is_union_type(first_arg) and get_args(first_arg) and not is_union_type(test_type):
                    first_arg = get_args(first_arg)[0]
                return is_of_type(first_arg, test_type)
            else:
                return True

    return False
示例#3
0
def is_union_type(t: Any, test_type: Optional[type] = None) -> bool:
    """Check if `t` is union type (Union[Type, AnotherType]).

    Optionally check if T is of `test_type` We cannot check for literal Nones.

    >>> is_union_type(Union[int, str])
    True
    >>> is_union_type(Union[int, str], str)
    True
    >>> is_union_type(Union[int, str], Union[int, str])
    True
    >>> is_union_type(Union[int, None])
    True
    >>> is_union_type(int)
    False
    """
    if get_origin(t) not in union_types:
        return False
    if not test_type:
        return True

    if is_of_type(t, test_type):
        return True
    for arg in get_args(t):
        result = is_of_type(arg, test_type)
        if result:
            return result
    return False
示例#4
0
def is_optional_type(t: Any, test_type: Optional[type] = None) -> bool:
    """Check if `t` is optional type (Union[None, ...]).

    And optionally check if T is of `test_type`

    >>> is_optional_type(Optional[int])
    True
    >>> is_optional_type(Union[None, int])
    True
    >>> is_optional_type(Union[int, str, None])
    True
    >>> is_optional_type(Optional[int], int)
    True
    >>> is_optional_type(Optional[int], str)
    False
    >>> is_optional_type(Optional[State], int)
    False
    >>> is_optional_type(Optional[State], State)
    True
    """
    if get_origin(t) in union_types and None.__class__ in get_args(t):
        for arg in get_args(t):
            if arg is None.__class__:
                continue

            return not test_type or is_of_type(arg, test_type)
    return False
示例#5
0
def is_of_type(t: Any, test_type: Any) -> bool:
    """Check if annotation type is valid for type.

    >>> is_of_type(list, list)
    True
    >>> is_of_type(List[int], List[int])
    True
    >>> is_of_type(strEnum, str)
    True
    >>> is_of_type(strEnum, Enum)
    True
    >>> is_of_type(int, str)
    False
    """

    if is_union_type(test_type):
        return any(get_origin(t) is get_origin(arg) for arg in get_args(test_type))

    if (
        get_origin(t)
        and get_origin(test_type)
        and get_origin(t) is get_origin(test_type)
        and get_args(t) == get_args(test_type)
    ):
        return True

    if test_type is t:
        # Test type is a typing type instance and matches
        return True

    # Workaround for the fact that you can't call issubclass on typing types
    try:
        return issubclass(t, test_type)
    except TypeError:
        return False
示例#6
0
def wrap_validate_singleton(
    self: ModelField,
    v: Any,
    values: Dict[str, Any],
    loc: "LocStr",
    cls: Optional["ModelOrDc"],
) -> "ValidateReturn":
    if self.sub_fields:
        if get_origin(self.type_) is Union:
            for field in self.sub_fields:
                if v.__class__ is field.outer_type_:
                    return v, None
            for field in self.sub_fields:
                try:
                    if isinstance(v, field.outer_type_):
                        return v, None
                except TypeError:
                    pass

    return upstream_validate_singleton(self, v, values, loc, cls)
示例#7
0
def test_get_origin(input_value, output_value):
    if input_value is None:
        pytest.skip('Skipping undefined hint for this python version')
    assert get_origin(input_value) is output_value
示例#8
0
    def _analyze_arg_type(self, arg_type: Optional[type]):
        if arg_type is None:
            return

        origin = get_origin(arg_type)
        if origin:
            shape = None
            dtype = None

            if origin is Union:
                allow_types = []

                for arg in get_args(arg_type):
                    if arg is not None:
                        allow_types.append(arg)

                self.shape = ArgTypeShape.UNION
                self.outer_type = [self._get_arg_type(t) for t in allow_types]
                return

            if inspect.isclass(origin):
                if issubclass(origin, List):
                    shape = ArgTypeShape.LIST
                    args = get_args(arg_type)
                    if args and len(args) == 1:
                        vt = args[0]
                        if not inspect.isclass(vt):
                            vt = None
                        dtype = self._get_arg_type(vt)
                elif issubclass(origin, Mapping):
                    shape = ArgTypeShape.DICT
                    args = get_args(arg_type)
                    if args and len(args) == 2:
                        kt = args[0]
                        vt = args[1]
                        dtype = (self._get_arg_type(kt),
                                 self._get_arg_type(vt))
                    else:
                        dtype = (None, None)
                elif issubclass(origin, Set):
                    shape = ArgTypeShape.SET
                    args = get_args(arg_type)
                    if args and len(args) == 1:
                        vt = args[0]
                        if not inspect.isclass(vt):
                            vt = None
                        dtype = self._get_arg_type(vt)
            if shape is None:
                raise AssertionError(
                    f'Unsupported generic argument type: {arg_type}')
            self.shape = shape
            self.outer_type = dtype
            return

        if isinstance(arg_type, str):
            if hasattr(builtins, arg_type):
                arg_type = getattr(builtins, arg_type)
                self.outer_type = arg_type

        if not inspect.isclass(arg_type):
            raise AssertionError(
                f'Non-generic argument type must be a class, but got: {arg_type}'
            )
        if issubclass(arg_type, List):
            self.shape = ArgTypeShape.LIST
            self.outer_type = None
        elif issubclass(arg_type, Mapping):
            self.shape = ArgTypeShape.DICT
            self.outer_type = (None, None)
        elif issubclass(arg_type, Set):
            self.shape = ArgTypeShape.SET
            self.outer_type = None