Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a method to get intermediate return values from flow #868

Open
ftruzzi opened this issue Mar 15, 2021 · 3 comments
Open

Add a method to get intermediate return values from flow #868

ftruzzi opened this issue Mar 15, 2021 · 3 comments

Comments

@ftruzzi
Copy link
Contributor

ftruzzi commented Mar 15, 2021

Hi!

It would be nice for testing to have a way to retrieve the intermediate result of a flow, in a way similar to how assert_flow() works but with the return value.

Example:

def do_stuff():
    return flow(0, func_1, bind(func_2))

def test_func_1():
    v = get_function_value(func_1, do_stuff)
    assert v == expected_value

In principle this can be done with sys.setprofile (in the trace function and for return events, arg contains the return value).

Proof of concept example:

def trace_func(function_to_search, frame, event, arg):
    if event == 'return' and frame.f_code.co_name == function_to_search.__name__:
        # modified exception to hold the return value under "value" attr
        raise DesiredValueFound(arg)

def get_function_value(function_to_search, my_flow):
    old_tracer = sys.gettrace()
    sys.setprofile(partial(trace_func, function_to_search))

    try:
         my_flow()
    except DesiredValueFound as e:
        return e.value
    finally:
        sys.settrace(old_tracer)

What do you think?

Thanks :)

@sobolevn
Copy link
Member

Can you please tell more about your use-case? What exactly are you testing?

@ftruzzi
Copy link
Contributor Author

ftruzzi commented Mar 15, 2021

Thanks for asking! I'm building a library to upload files on a website. The core of it is robobrowser interacting with forms until the upload is finished and unfortunately there is some shared state and function arguments and return values are not simple.

My flow is something like this: validate_file -> upload_file -> fetch_new_metadata -> update_metadata -> finish_upload, exposed through a single method e.g. upload

Individually testing the *_metadata functions is quite hard unless I manually save the returned form from upload_file (which is a complex object) for each test case and provide it as an argument together with a manually initialized state. A solution like the one I proposed would allow for much easier testing without having to manage any other data except for vcrpy to save and replay network requests with the data.

@internetimagery
Copy link

Perhaps if bind didn't just assume the returned value was the correct monadic instance (returning it directly), and instead attempted a map, then join... a subclass of a monad could be used (and propagated) through the flow, which could be used for assertions etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants