Esempio n. 1
0
def test_context_hook_invocation(hook_decorator):
    entered = []

    @hook_decorator
    def my_hook(_):
        entered.append("yes")

    my_hook(None)
    assert entered == ["yes"]

    entered = []
    my_hook(build_hook_context())
    assert entered == ["yes"]

    entered = []
    my_hook(_=build_hook_context())
    assert entered == ["yes"]

    with pytest.raises(
            DagsterInvalidInvocationError,
            match=
            "Decorated function expects one parameter, _, but 0 were provided.",
    ):
        my_hook()  # pylint: disable=no-value-for-parameter

    with pytest.raises(DagsterInvalidInvocationError,
                       match="Could not find expected argument '_'."):
        my_hook(foo=None)  # pylint: disable=unexpected-keyword-arg,no-value-for-parameter
Esempio n. 2
0
def test_hook_context_op_solid_provided():
    @op
    def hook_op(_):
        pass

    with pytest.raises(check.CheckError):
        build_hook_context(op=hook_op, solid=hook_op)
Esempio n. 3
0
def test_hook_graph_job_op():
    called = {}
    op_output = "hook_op_output"

    @success_hook(required_resource_keys={"resource_a"})
    def hook_one(context):
        assert context.op.name
        called[context.hook_def.name] = called.get(context.hook_def.name, 0) + 1

    @success_hook()
    def hook_two(context):
        assert not context.op_config
        assert not context.op_exception
        assert context.op_output_values["result"] == op_output
        called[context.hook_def.name] = called.get(context.hook_def.name, 0) + 1

    @op
    def hook_op(_):
        return op_output

    ctx = build_hook_context(resources={"resource_a": resource_a}, op=hook_op)
    hook_one(ctx)
    assert called.get("hook_one") == 1

    @graph
    def run_success_hook():
        hook_op.with_hooks({hook_one, hook_two})()

    success_hook_job = run_success_hook.to_job(resource_defs={"resource_a": resource_a})
    assert success_hook_job.execute_in_process().success

    assert called.get("hook_one") == 2
    assert called.get("hook_two") == 1
Esempio n. 4
0
def test_hook_invocation_with_solid():
    @success_hook
    def basic_hook(context):
        assert context.solid.name == "foo"
        assert len(context.solid.graph_definition.solids) == 1

    @solid
    def foo():
        pass

    @solid
    def not_foo():
        pass

    basic_hook(build_hook_context(solid=foo))
    basic_hook(build_hook_context(solid=not_foo.alias("foo")))
Esempio n. 5
0
def test_success_hook_cm_resource(hook_decorator, is_event_list_hook):
    entered = []

    @resource
    def cm_resource(_):
        try:
            entered.append("try")
            yield "foo"
        finally:
            entered.append("finally")

    decorator = hook_decorator(required_resource_keys={"cm"})
    if is_event_list_hook:

        def my_hook_cm_resource(context, _):
            assert context.resources.cm == "foo"
            assert entered == ["try"]

        hook = decorator(my_hook_cm_resource)
    else:

        def my_hook_cm_resource(context):  # type: ignore[misc]
            assert context.resources.cm == "foo"
            assert entered == ["try"]

        hook = decorator(my_hook_cm_resource)

    with build_hook_context(resources={"cm": cm_resource}) as context:
        if is_event_list_hook:
            hook(context, None)
        else:
            hook(context)

    assert entered == ["try", "finally"]

    with pytest.raises(
        DagsterInvariantViolationError,
        match=re.escape(
            "At least one provided resource is a generator, but attempting to access resources "
            "outside of context manager scope. You can use the following syntax to open a context "
            "manager: `with build_hook_context(...) as context:`"
        ),
    ):
        if is_event_list_hook:
            hook(build_hook_context(resources={"cm": cm_resource}), None)
        else:
            hook(build_hook_context(resources={"cm": cm_resource}))
Esempio n. 6
0
def test_my_success_hook():
    my_conn = mock.MagicMock()
    # construct HookContext with mocked ``my_conn`` resource.
    context = build_hook_context(resources={"my_conn": my_conn})

    my_success_hook(context)

    assert my_conn.send.call_count == 1
Esempio n. 7
0
def test_properties_on_hook_context():
    @success_hook
    def basic_hook(context):
        assert isinstance(context.job_name, str)
        assert isinstance(context.run_id, str)
        assert isinstance(context.op_exception, BaseException)

    error = DagsterInvariantViolationError("blah")
    basic_hook(build_hook_context(run_id="blah", job_name="blah", op_exception=error))
Esempio n. 8
0
def test_success_hook_with_resources(hook_decorator, is_event_list_hook):

    decorator = hook_decorator(required_resource_keys={"foo", "bar"})
    if is_event_list_hook:

        def my_hook_reqs_resources(context, _):
            assert context.resources.foo == "foo"
            assert context.resources.bar == "bar"

        hook = decorator(my_hook_reqs_resources)
    else:

        def my_hook_reqs_resources(context):  # type: ignore[misc]
            assert context.resources.foo == "foo"
            assert context.resources.bar == "bar"

        hook = decorator(my_hook_reqs_resources)

    @resource
    def bar_resource(_):
        return "bar"

    if is_event_list_hook:
        hook(build_hook_context(resources={
            "foo": "foo",
            "bar": bar_resource
        }), None)
    else:
        hook(build_hook_context(resources={"foo": "foo", "bar": bar_resource}))

    with pytest.raises(
            DagsterInvariantViolationError,
            match=r"The hook 'my_hook_reqs_resources' requires resource '\w+', "
            r"which was not provided by the context.",
    ):
        if is_event_list_hook:
            hook(None, None)
        else:
            hook(None)
Esempio n. 9
0
def test_event_list_hook_invocation():
    entered = []

    @event_list_hook
    def basic_event_list_hook(context, event_list):
        assert isinstance(context, HookContext)
        for event in event_list:
            if event.is_step_success:
                entered.append("yes")

    basic_event_list_hook(build_hook_context(),
                          [mock.MagicMock(is_step_success=True)])
    assert entered == ["yes"]
    entered = []

    basic_event_list_hook(build_hook_context(),
                          event_list=[mock.MagicMock(is_step_success=True)])
    assert entered == ["yes"]

    entered = []

    basic_event_list_hook(context=build_hook_context(),
                          event_list=[mock.MagicMock(is_step_success=True)])
    assert entered == ["yes"]

    with pytest.raises(
            DagsterInvalidInvocationError,
            match=
            "Decorated function expects two parameters, context and event_list, but 0 were provided.",
    ):
        basic_event_list_hook()  # pylint: disable=no-value-for-parameter

    with pytest.raises(
            DagsterInvalidInvocationError,
            match=
            "Decorated function expects two parameters, context and event_list, but 1 were provided.",
    ):
        basic_event_list_hook(event_list=[])  # pylint: disable=no-value-for-parameter

    with pytest.raises(
            DagsterInvalidInvocationError,
            match=
            "Decorated function expects two parameters, context and event_list, but 1 were provided.",
    ):
        basic_event_list_hook(context=None)  # pylint: disable=no-value-for-parameter

    with pytest.raises(
            DagsterInvalidInvocationError,
            match=
            "Decorated function expects two parameters, context and event_list, but 1 were provided.",
    ):
        basic_event_list_hook(None)  # pylint: disable=no-value-for-parameter

    with pytest.raises(DagsterInvalidInvocationError,
                       match="Could not find expected argument 'context'."):
        basic_event_list_hook(  # pylint: disable=unexpected-keyword-arg,no-value-for-parameter
            foo=None,
            event_list=[])

    with pytest.raises(DagsterInvalidInvocationError,
                       match="Could not find expected argument 'event_list'."):
        basic_event_list_hook(  # pylint: disable=unexpected-keyword-arg,no-value-for-parameter
            context=None,
            bar=[])