Esempio n. 1
0
def test_double_dagster_type():

    AlwaysSucceedsFoo = DagsterType(name='Foo',
                                    type_check_fn=lambda _, _val: True)
    AlwaysFailsFoo = DagsterType(name='Foo',
                                 type_check_fn=lambda _, _val: False)

    @lambda_solid
    def return_a_thing():
        return 1

    @lambda_solid(
        input_defs=[InputDefinition('succeeds', AlwaysSucceedsFoo)],
        output_def=OutputDefinition(AlwaysFailsFoo),
    )
    def yup(succeeds):
        return succeeds

    with pytest.raises(DagsterInvalidDefinitionError) as exc_info:

        @pipeline
        def _should_fail():
            yup(return_a_thing())

    assert str(exc_info.value) == (
        'You have created two dagster types with the same name "Foo". '
        'Dagster types have must have unique names.')
Esempio n. 2
0
def test_contextual_type_check():
    def fancy_type_check(context, value):
        return TypeCheck(success=context.resources.foo.check(value))

    custom = DagsterType(
        key="custom", name="custom", type_check_fn=fancy_type_check, required_resource_keys={"foo"}
    )

    @resource
    def foo(_context):
        class _Foo:
            def check(self, _value):
                return True

        return _Foo()

    @lambda_solid
    def return_one():
        return 1

    @solid(input_defs=[InputDefinition("inp", custom)])
    def bar(_context, inp):
        return inp

    @pipeline(mode_defs=[ModeDefinition(resource_defs={"foo": foo})])
    def fancy_pipeline():
        bar(return_one())

    assert execute_pipeline(fancy_pipeline).success
Esempio n. 3
0
def test_raise_on_error_true_type_check_raises_exception():
    def raise_exception_inner(_context, _):
        raise Failure("I am dissapoint")

    ThrowExceptionType = DagsterType(name="ThrowExceptionType", type_check_fn=raise_exception_inner)

    @solid(output_defs=[OutputDefinition(ThrowExceptionType)])
    def foo_solid(_):
        return 1

    @pipeline
    def foo_pipeline():
        foo_solid()

    with pytest.raises(Failure, match=re.escape("I am dissapoint")):
        execute_pipeline(foo_pipeline)

    pipeline_result = execute_pipeline(foo_pipeline, raise_on_error=False)
    assert not pipeline_result.success
    assert [event.event_type_value for event in pipeline_result.step_event_list] == [
        DagsterEventType.STEP_START.value,
        DagsterEventType.STEP_FAILURE.value,
    ]
    for event in pipeline_result.step_event_list:
        if event.event_type_value == DagsterEventType.STEP_FAILURE.value:
            assert event.event_specific_data.error.cls_name == "Failure"
Esempio n. 4
0
def define_custom_dict(name, permitted_key_names):
    def type_check_method(_, value):
        if not isinstance(value, dict):
            return TypeCheck(
                False,
                description="Value {value} should be of type {type_name}.".format(
                    value=value, type_name=name
                ),
            )
        for key in value:
            if not key in permitted_key_names:
                return TypeCheck(
                    False,
                    description=(
                        "Key {name} is not a permitted value, values can only be of: " "{name_list}"
                    ).format(name=value.name, name_list=permitted_key_names),
                )
        return TypeCheck(
            True,
            metadata_entries=[
                EventMetadataEntry.text(label="row_count", text=str(len(value))),
                EventMetadataEntry.text(label="series_names", text=", ".join(value.keys())),
            ],
        )

    return DagsterType(key=name, name=name, type_check_fn=type_check_method)
Esempio n. 5
0
def test_raise_on_error_true_type_check_returns_unsuccessful_type_check():
    FalsyType = DagsterType(
        name="FalsyType",
        type_check_fn=lambda _, _val: TypeCheck(
            success=False, metadata_entries=[EventMetadataEntry.text("foo", "bar", "baz")]
        ),
    )

    @solid(output_defs=[OutputDefinition(FalsyType)])
    def foo_solid(_):
        return 1

    @pipeline
    def foo_pipeline():
        foo_solid()

    with pytest.raises(DagsterTypeCheckDidNotPass) as e:
        execute_pipeline(foo_pipeline)
    assert e.value.metadata_entries[0].label == "bar"
    assert e.value.metadata_entries[0].entry_data.text == "foo"
    assert e.value.metadata_entries[0].description == "baz"
    assert isinstance(e.value.dagster_type, DagsterType)

    pipeline_result = execute_pipeline(foo_pipeline, raise_on_error=False)
    assert not pipeline_result.success
    assert [event.event_type_value for event in pipeline_result.step_event_list] == [
        DagsterEventType.STEP_START.value,
        DagsterEventType.STEP_OUTPUT.value,
        DagsterEventType.STEP_FAILURE.value,
    ]
    for event in pipeline_result.step_event_list:
        if event.event_type_value == DagsterEventType.STEP_FAILURE.value:
            assert event.event_specific_data.error.cls_name == "DagsterTypeCheckDidNotPass"
Esempio n. 6
0
def test_raise_on_error_type_check_returns_false():
    FalsyType = DagsterType(name='FalsyType',
                            type_check_fn=lambda _, _val: False)

    @solid(output_defs=[OutputDefinition(FalsyType)])
    def foo_solid(_):
        return 1

    @pipeline
    def foo_pipeline():
        foo_solid()

    with pytest.raises(DagsterTypeCheckDidNotPass):
        execute_pipeline(foo_pipeline)

    pipeline_result = execute_pipeline(foo_pipeline, raise_on_error=False)
    assert not pipeline_result.success
    assert [
        event.event_type_value for event in pipeline_result.step_event_list
    ] == [
        DagsterEventType.STEP_START.value,
        DagsterEventType.STEP_OUTPUT.value,
        DagsterEventType.STEP_FAILURE.value,
    ]
    for event in pipeline_result.step_event_list:
        if event.event_type_value == DagsterEventType.STEP_FAILURE.value:
            assert event.event_specific_data.error.cls_name == 'DagsterTypeCheckDidNotPass'
Esempio n. 7
0
def test_python_object_type_with_custom_type_check():
    def eq_3(_, value):
        return isinstance(value, int) and value == 3

    Int3 = DagsterType(name="Int3", type_check_fn=eq_3)

    assert Int3.unique_name == "Int3"
    assert check_dagster_type(Int3, 3).success
    assert not check_dagster_type(Int3, 5).success
Esempio n. 8
0
def test_python_object_type_with_custom_type_check():
    def eq_3(value):
        return isinstance(value, int) and value == 3

    Int3 = DagsterType(name='Int3', type_check_fn=eq_3)

    assert Int3.name == 'Int3'
    assert_success(Int3, 3)
    assert_failure(Int3, 5)
Esempio n. 9
0
def do_type_check(context: TypeCheckContext, dagster_type: DagsterType, value: Any) -> TypeCheck:
    type_check = dagster_type.type_check(context, value)
    if not isinstance(type_check, TypeCheck):
        return TypeCheck(
            success=False,
            description=(
                "Type checks must return TypeCheck. Type check for type {type_name} returned "
                "value of type {return_type} when checking runtime value of type {dagster_type}."
            ).format(
                type_name=dagster_type.display_name,
                return_type=type(type_check),
                dagster_type=type(value),
            ),
        )
    return type_check
Esempio n. 10
0
def test_metadata_entries():

    metadata_entry = MetadataEntry("foo", None, MetadataValue.text("bar"))

    # We use `Output` as a stand-in for all events here, they all follow the same pattern of calling
    # `normalize_metadata`.
    with pytest.warns(DeprecationWarning,
                      match=re.escape('"metadata_entries" is deprecated')):
        Output("foo", "bar", metadata_entries=[metadata_entry])

    with pytest.warns(DeprecationWarning,
                      match=re.escape('"metadata_entries" is deprecated')):
        DagsterType(lambda _, __: True,
                    "foo",
                    metadata_entries=[metadata_entry])
Esempio n. 11
0
def test_raise_on_error_true_type_check_returns_successful_type_check():
    TruthyExceptionType = DagsterType(
        name="TruthyExceptionType",
        type_check_fn=lambda _, _val: TypeCheck(
            success=True, metadata_entries=[EventMetadataEntry.text("foo", "bar", "baz")]
        ),
    )

    @solid(output_defs=[OutputDefinition(TruthyExceptionType)])
    def foo_solid(_):
        return 1

    @pipeline
    def foo_pipeline():
        foo_solid()

    pipeline_result = execute_pipeline(foo_pipeline)
    assert pipeline_result.success
    for event in pipeline_result.step_event_list:
        if event.event_type_value == DagsterEventType.STEP_OUTPUT.value:
            assert event.event_specific_data.type_check_data
            assert event.event_specific_data.type_check_data.metadata_entries[0].label == "bar"
            assert (
                event.event_specific_data.type_check_data.metadata_entries[0].entry_data.text
                == "foo"
            )
            assert (
                event.event_specific_data.type_check_data.metadata_entries[0].description == "baz"
            )

    pipeline_result = execute_pipeline(foo_pipeline, raise_on_error=False)
    assert pipeline_result.success
    assert set(
        [
            DagsterEventType.STEP_START.value,
            DagsterEventType.STEP_OUTPUT.value,
            DagsterEventType.STEP_SUCCESS.value,
        ]
    ).issubset([event.event_type_value for event in pipeline_result.step_event_list])
Esempio n. 12
0
def test_raise_on_error_true_type_check_returns_true():
    TruthyExceptionType = DagsterType(name="TruthyExceptionType",
                                      type_check_fn=lambda _, _val: True)

    @solid(output_defs=[OutputDefinition(TruthyExceptionType)])
    def foo_solid(_):
        return 1

    @pipeline
    def foo_pipeline():
        foo_solid()

    assert execute_pipeline(foo_pipeline).success

    pipeline_result = execute_pipeline(foo_pipeline, raise_on_error=False)
    assert pipeline_result.success
    assert set([
        DagsterEventType.STEP_START.value,
        DagsterEventType.STEP_OUTPUT.value,
        DagsterEventType.STEP_SUCCESS.value,
    ]).issubset(
        [event.event_type_value for event in pipeline_result.step_event_list])
Esempio n. 13
0
    assert step_failure_event.event_specific_data.error.cls_name == "DagsterTypeCheckDidNotPass"


# TODO add more step output use cases


class AlwaysFailsException(Exception):
    # Made to make exception explicit so that we aren't accidentally masking other Exceptions
    pass


def _always_fails(_, _value):
    raise AlwaysFailsException("kdjfkjd")


ThrowsExceptionType = DagsterType(name="ThrowsExceptionType", type_check_fn=_always_fails,)


def _return_bad_value(_, _value):
    return "foo"


BadType = DagsterType(name="BadType", type_check_fn=_return_bad_value)


def test_input_type_returns_wrong_thing():
    @lambda_solid
    def return_one():
        return 1

    @lambda_solid(input_defs=[InputDefinition("value", BadType)])
Esempio n. 14
0
    assert not type_check_data.success
    assert type_check_data.description == 'Value "1" of python type "int" must be a string.'

    step_failure_event = solid_result.compute_step_failure_event
    assert step_failure_event.event_specific_data.error.cls_name == 'Failure'


# TODO add more step output use cases


def _always_fails(_value):
    raise Exception('kdjfkjd')


ThrowsExceptionType = DagsterType(
    name='ThrowsExceptionType',
    type_check_fn=_always_fails,
)


def _return_bad_value(_value):
    return 'kdjfkjd'


BadType = DagsterType(name='BadType', type_check_fn=_return_bad_value)


def test_input_type_returns_wrong_thing():
    @lambda_solid
    def return_one():
        return 1
Esempio n. 15
0
__all__ = ["fetch_json_data", "generate_dataframe", "save_dataframe_to_csv"]

import requests
import pandas as pd

import dagster
from dagster import solid
from dagster.core.types.dagster_type import Nothing, DagsterType
from dagster.core.definitions import InputDefinition

# Creating a DictOrList type for runtime type checking
DictOrList = DagsterType(
    type_check_fn=lambda _, value: type(value) in [dict, list],
    name="DictOrList")


@solid(config_schema={"api_endpoint": str, "api_path": str})
def fetch_json_data(context: dagster.SolidExecutionContext):
    """ Fetches data from a JSON API

        Configuration schema:
        - api_endpoint (str): the API base endpoint (e.g. https://api.github.com/)
        - api_path (str): the path of the API from which you want to fetch (e.g. /users/gabriel-milan)
    """

    # Joins URL parts into a single URL, stripping unnecessary slashes
    url_parts: list = [
        context.solid_config["api_endpoint"], context.solid_config["api_path"]
    ]
    url: str = "/".join(s.strip("/") for s in url_parts)
Esempio n. 16
0
        self.count = 0

    def serialize(self, value, write_file_obj):
        if self.count % 2 == 0:  # ensure two steps' serdes interleave
            time.sleep(1)
        write_file_obj.write(bytes(value.encode("utf-8")))

    def deserialize(self, read_file_obj):
        if self.count % 2 == 1:  # ensure two steps' serdes interleave
            time.sleep(1)
        return read_file_obj.read().decode("utf-8")


ADagsterType = DagsterType(
    name="ADagsterType",
    type_check_fn=lambda _, value: True,
    serialization_strategy=ASerializationStrategy(),
)

yield_something = test_nb_solid(
    name="yield_something",
    input_defs=[InputDefinition("obj", str)],
    output_defs=[OutputDefinition(ADagsterType)],
)


@solid(input_defs=[
    InputDefinition("a", ADagsterType),
    InputDefinition("b", ADagsterType)
])
def fan_in(a, b):