Esempio n. 1
0
def set_property_from_data(
    component_or_field: Union[UnicornView, UnicornField, Model],
    name: str,
    value: Any,
) -> None:
    """
    Sets properties on the component based on passed-in data.
    """

    try:
        if not hasattr(component_or_field, name):
            return
    except ValueError:
        # Treat ValueError the same as a missing field because trying to access a many-to-many
        # field before the model's pk will throw this exception
        return

    field = getattr(component_or_field, name)
    component_field_is_model_or_unicorn_field = _is_component_field_model_or_unicorn_field(
        component_or_field, name)

    # UnicornField and Models are always a dictionary (can be nested)
    if component_field_is_model_or_unicorn_field:
        # Re-get the field since it might have been set in `_is_component_field_model_or_unicorn_field`
        field = getattr(component_or_field, name)

        type_hints = get_type_hints(component_or_field)

        if isinstance(value, dict):
            for key in value.keys():
                key_value = value[key]
                set_property_from_data(field, key, key_value)
    elif hasattr(field, "related_val"):
        # Use `related_val` to check for many-to-many
        field.set(value)
    else:
        type_hints = get_type_hints(component_or_field)
        type_hint = type_hints.get(name)

        if _is_queryset(field, type_hint, value):
            value = _create_queryset(field, type_hint, value)
        elif type_hint:
            if is_dataclass(type_hint):
                value = type_hint(**value)
            else:
                # Construct the specified type by passing the value in
                # Usually the value will be a string (because it is coming from JSON)
                # and basic types can be constructed by passing in a string,
                # i.e. int("1") or float("1.1")
                try:
                    value = type_hint(value)
                except TypeError:
                    # Ignore this exception because some type-hints can't be instantiated like this (e.g. `List[]`)
                    pass

        if hasattr(component_or_field, "_set_property"):
            # Can assume that `component_or_field` is a component
            component_or_field._set_property(name, value)
        else:
            setattr(component_or_field, name, value)
Esempio n. 2
0
def test_get_type_hints_missing_type_hints():
    def test_func(input_str):
        return input_str

    expected = {}
    actual = get_type_hints(test_func)
    assert actual == expected
Esempio n. 3
0
def test_get_type_hints():
    def test_func(input_str: str):
        return input_str

    expected = {"input_str": str}
    actual = get_type_hints(test_func)
    assert actual == expected
Esempio n. 4
0
def set_property_from_data(
    component_or_field: Union[UnicornView, UnicornField, Model], name: str, value: Any,
) -> None:
    """
    Sets properties on the component based on passed-in data.
    """

    if not hasattr(component_or_field, name):
        return
    if isinstance(component_or_field, Model):
        set_property_for_model(component_or_field, name,value = value)
        return

    field = getattr(component_or_field, name)
    component_field_is_model_or_unicorn_field = _is_component_field_model_or_unicorn_field(
        component_or_field, name
    )

    # UnicornField and Models are always a dictionary (can be nested)
    if component_field_is_model_or_unicorn_field:
        # Re-get the field since it might have been set in `_is_component_field_model_or_unicorn_field`
        field = getattr(component_or_field, name)

        if isinstance(value, dict):
            for key in value.keys():
                key_value = value[key]
                set_property_from_data(field, key, key_value)
        else:
            set_property_from_data(field, field.name, value)
    else:
        type_hints = get_type_hints(component_or_field)

        if name in type_hints:
            # Construct the specified type by passing the value in
            # Usually the value will be a string (because it is coming from JSON)
            # and basic types can be constructed by passing in a string,
            # i.e. int("1") or float("1.1")

            if is_dataclass(type_hints[name]):
                value = type_hints[name](**value)
            else:
                value = type_hints[name](value)
                

        if hasattr(component_or_field, "_set_property"):
            # Can assume that `component_or_field` is a component
            component_or_field._set_property(name, value)
        else:
            setattr(component_or_field, name, value)
Esempio n. 5
0
def _is_component_field_model_or_unicorn_field(
    component_or_field: Union[UnicornView, UnicornField, Model],
    name: str,
) -> bool:
    """
    Determines whether a component's field is a Django `Model` or `UnicornField` either
    by checking the field's instance or inspecting the type hints.

    One side-effect is that the field will be instantiated if it is currently `None` and
    the type hint is available.

    Args:
        component: `UnicornView` to check.
        name: Name of the field.

    Returns:
        Whether the field is a Django `Model` or `UnicornField`.
    """
    field = getattr(component_or_field, name)

    if isinstance(field, UnicornField) or isinstance(field, Model):
        return True

    is_subclass_of_model = False
    is_subclass_of_unicorn_field = False
    component_type_hints = {}

    try:
        component_type_hints = get_type_hints(component_or_field)

        if name in component_type_hints:
            is_subclass_of_model = issubclass(component_type_hints[name],
                                              Model)

            if not is_subclass_of_model:
                is_subclass_of_unicorn_field = issubclass(
                    component_type_hints[name], UnicornField)

            # Construct a new class if the field is None and there is a type hint available
            if field is None:
                if is_subclass_of_model or is_subclass_of_unicorn_field:
                    field = component_type_hints[name]()
                    setattr(component_or_field, name, field)
    except TypeError:
        pass

    return is_subclass_of_model or is_subclass_of_unicorn_field
def _call_method_name(component: UnicornView, method_name: str,
                      args: List[Any], kwargs: Dict[str, Any]) -> Any:
    """
    Calls the method name with parameters.

    Args:
        param component: Component to call method on.
        param method_name: Method name to call.
        param args: List of arguments for the method.
        param kwargs: Dictionary of kwargs for the method.
    """

    if method_name is not None and hasattr(component, method_name):
        func = getattr(component, method_name)

        if len(args) == 1 or len(kwargs.keys()) == 1:
            arguments = get_method_arguments(func)
            type_hints = get_type_hints(func)

            for argument in arguments:
                if argument in type_hints:
                    if issubclass(type_hints[argument], Model):
                        DbModel = type_hints[argument]
                        key = "pk"
                        value = None

                        if args:
                            value = args.pop()
                        elif kwargs:
                            (key, value) = list(kwargs.items())[0]
                            del kwargs[key]

                        model = DbModel.objects.get(**{key: value})

                        args.append(model)

        if args and kwargs:
            return func(*args, **kwargs)
        elif args:
            return func(*args, **kwargs)
        elif kwargs:
            return func(**kwargs)
        else:
            return func()