Exemple #1
0
 def from_python_std(cls, literal_type, t_value, upstream_nodes=None):
     """
     :param flytekit.models.types.LiteralType literal_type:
     :param T t_value:
     :param list[flytekit.common.nodes.SdkNode] upstream_nodes: [Optional] Keeps track of the nodes upstream,
         if applicable.
     :rtype: BindingData
     """
     scalar = None
     collection = None
     promise = None
     map = None
     downstream_sdk_type = _type_helpers.get_sdk_type_from_literal_type(
         literal_type)
     if isinstance(t_value, _promise.Input):
         if not downstream_sdk_type.is_castable_from(t_value.sdk_type):
             _user_exceptions.FlyteTypeException(
                 t_value.sdk_type,
                 downstream_sdk_type,
                 additional_msg="When binding workflow input: {}".format(
                     t_value))
         promise = t_value.promise
     elif isinstance(t_value, _promise.NodeOutput):
         if not downstream_sdk_type.is_castable_from(t_value.sdk_type):
             _user_exceptions.FlyteTypeException(
                 t_value.sdk_type,
                 downstream_sdk_type,
                 additional_msg="When binding node output: {}".format(
                     t_value))
         promise = t_value
         if upstream_nodes is not None:
             upstream_nodes.append(t_value.sdk_node)
     elif isinstance(t_value, list):
         if not issubclass(downstream_sdk_type, _containers.ListImpl):
             raise _user_exceptions.FlyteTypeException(
                 type(t_value),
                 downstream_sdk_type,
                 received_value=t_value,
                 additional_msg="Cannot bind a list to a non-list type.")
         collection = _literal_models.BindingDataCollection([
             BindingData.from_python_std(
                 downstream_sdk_type.sub_type.to_flyte_literal_type(),
                 v,
                 upstream_nodes=upstream_nodes) for v in t_value
         ])
     elif isinstance(t_value, dict) and \
             (not issubclass(downstream_sdk_type, _primitives.Generic) or BindingData._has_sub_bindings(t_value)):
         # TODO: This behavior should be embedded in the type engine.  Someone should be able to alter behavior of
         # TODO: binding logic by injecting their own type engine.  The same goes for the list check above.
         raise NotImplementedError(
             "TODO: Cannot use map bindings at the moment")
     else:
         sdk_value = downstream_sdk_type.from_python_std(t_value)
         scalar = sdk_value.scalar
         collection = sdk_value.collection
         map = sdk_value.map
     return cls(scalar=scalar,
                collection=collection,
                map=map,
                promise=promise)
Exemple #2
0
def binding_data_from_python_std(
    ctx: _flyte_context.FlyteContext,
    expected_literal_type: _type_models.LiteralType,
    t_value: typing.Any,
    t_value_type: type,
) -> _literals_models.BindingData:
    # This handles the case where the given value is the output of another task
    if isinstance(t_value, Promise):
        if not t_value.is_ready:
            return _literals_models.BindingData(promise=t_value.ref)

    elif isinstance(t_value, VoidPromise):
        raise AssertionError(
            f"Cannot pass output from task {t_value.task_name} that produces no outputs to a downstream task"
        )

    elif isinstance(t_value, list):
        if expected_literal_type.collection_type is None:
            raise AssertionError(
                f"this should be a list and it is not: {type(t_value)} vs {expected_literal_type}"
            )

        sub_type = ListTransformer.get_sub_type(t_value_type)
        collection = _literals_models.BindingDataCollection(bindings=[
            binding_data_from_python_std(
                ctx, expected_literal_type.collection_type, t, sub_type)
            for t in t_value
        ])

        return _literals_models.BindingData(collection=collection)

    elif isinstance(t_value, dict):
        if (expected_literal_type.map_value_type is None
                and expected_literal_type.simple !=
                _type_models.SimpleType.STRUCT):
            raise AssertionError(
                f"this should be a Dictionary type and it is not: {type(t_value)} vs {expected_literal_type}"
            )
        k_type, v_type = DictTransformer.get_dict_types(t_value_type)
        if expected_literal_type.simple == _type_models.SimpleType.STRUCT:
            lit = TypeEngine.to_literal(ctx, t_value, type(t_value),
                                        expected_literal_type)
            return _literals_models.BindingData(scalar=lit.scalar)
        else:
            m = _literals_models.BindingDataMap(
                bindings={
                    k: binding_data_from_python_std(
                        ctx, expected_literal_type.map_value_type, v, v_type)
                    for k, v in t_value.items()
                })
        return _literals_models.BindingData(map=m)

    # This is the scalar case - e.g. my_task(in1=5)
    scalar = TypeEngine.to_literal(ctx, t_value, t_value_type,
                                   expected_literal_type).scalar
    return _literals_models.BindingData(scalar=scalar)
Exemple #3
0
def test_binding_data_collection_nested():
    b1 = literals.BindingData(scalar=literals.Scalar(primitive=literals.Primitive(integer=5)))
    b2 = literals.BindingData(scalar=literals.Scalar(primitive=literals.Primitive(integer=57)))

    bc_inner = literals.BindingDataCollection(bindings=[b1, b2])

    bd = literals.BindingData(collection=bc_inner)
    bc_outer = literals.BindingDataCollection(bindings=[bd])
    obj = literals.BindingData(collection=bc_outer)
    assert obj.scalar is None
    assert obj.promise is None
    assert obj.collection is not None
    assert obj.map is None

    obj2 = literals.BindingData.from_flyte_idl(obj.to_flyte_idl())
    assert obj == obj2
    assert obj2.scalar is None
    assert obj2.promise is None
    assert obj2.collection is not None
    assert obj2.map is None
    assert obj2.value.bindings[0].value.bindings[0].value.value.value == 5
    assert obj2.value.bindings[0].value.bindings[1].value.value.value == 57
Exemple #4
0
def binding_data_from_python_std(
    ctx: _flyte_context.FlyteContext,
    expected_literal_type: _type_models.LiteralType,
    t_value: typing.Any,
    t_value_type: type,
) -> _literals_models.BindingData:
    # This handles the case where the given value is the output of another task
    if isinstance(t_value, Promise):
        if not t_value.is_ready:
            return _literals_models.BindingData(promise=t_value.ref)

    elif isinstance(t_value, VoidPromise):
        raise AssertionError(
            f"Cannot pass output from task {t_value.task_name} that produces no outputs to a downstream task"
        )

    elif isinstance(t_value, list):
        if expected_literal_type.collection_type is None:
            raise AssertionError(
                f"this should be a list and it is not: {type(t_value)} vs {expected_literal_type}"
            )

        sub_type = ListTransformer.get_sub_type(t_value_type)
        collection = _literals_models.BindingDataCollection(bindings=[
            binding_data_from_python_std(
                ctx, expected_literal_type.collection_type, t, sub_type)
            for t in t_value
        ])

        return _literals_models.BindingData(collection=collection)

    elif isinstance(t_value, dict):
        if (expected_literal_type.map_value_type is None
                and expected_literal_type.simple !=
                _type_models.SimpleType.STRUCT):
            raise AssertionError(
                f"this should be a Dictionary type and it is not: {type(t_value)} vs {expected_literal_type}"
            )
        k_type, v_type = DictTransformer.get_dict_types(t_value_type)
        if expected_literal_type.simple == _type_models.SimpleType.STRUCT:
            lit = TypeEngine.to_literal(ctx, t_value, type(t_value),
                                        expected_literal_type)
            return _literals_models.BindingData(scalar=lit.scalar)
        else:
            m = _literals_models.BindingDataMap(
                bindings={
                    k: binding_data_from_python_std(
                        ctx, expected_literal_type.map_value_type, v, v_type)
                    for k, v in t_value.items()
                })
        return _literals_models.BindingData(map=m)

    elif isinstance(t_value, tuple):
        raise AssertionError(
            "Tuples are not a supported type for individual values in Flyte - got a tuple -"
            f" {t_value}. If using named tuple in an inner task, please, de-reference the"
            "actual attribute that you want to use. For example, in NamedTuple('OP', x=int) then"
            "return v.x, instead of v, even if this has a single element")

    # This is the scalar case - e.g. my_task(in1=5)
    scalar = TypeEngine.to_literal(ctx, t_value, t_value_type,
                                   expected_literal_type).scalar
    return _literals_models.BindingData(scalar=scalar)