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

Provide support for no_update in Dash for R #111

Merged
merged 12 commits into from
Aug 13, 2019
Merged

Conversation

rpkyle
Copy link
Contributor

@rpkyle rpkyle commented Aug 2, 2019

This PR proposes to introduce a function entitled dashNoUpdate() which functions analogously to dash.no_update in Python, although the implementation differs slightly.

As with its counterpart, the function permits developers to selectively prevent one or more outputs from updating the layout. Currently, dashNoUpdate() only supports single-output callbacks, but should be easily extended to the multiple outputs scenario when that feature is available in R.

Additionally, the response$body returned is an empty character string, with a response$status of 204:

dashR/R/dash.R

Lines 294 to 299 in b23c248

# inspect the output_value to determine whether any outputs have no_update
# objects within them; these should not be updated
if (class(output_value) == "no_update") {
response$body <- character(1) # return empty string
response$status <- 204L
}

Closes #25.

@Marc-Andre-Rivet

@rpkyle rpkyle requested a review from alexcjohnson August 2, 2019 16:47
@rpkyle rpkyle self-assigned this Aug 2, 2019
@rpkyle rpkyle added this to the Dash v1.1.0 milestone Aug 2, 2019
@alexcjohnson
Copy link
Collaborator

Looks great!

Now that we have a test framework, let's get in the habit of testing new features as they come in here. You should be able to essentially just port this one test, but simplify it - take out the Value stuff, and you only have one variant to test as opposed to that test covering both no_update and PreventUpdate:

https://github.com/plotly/dash/blob/master/tests/integration/test_integration.py#L120-L178

R/dependencies.R Outdated Show resolved Hide resolved
@rpkyle
Copy link
Contributor Author

rpkyle commented Aug 7, 2019

@alexcjohnson I identified a minor issue today while reviewing app PRs with the new code, the following warning appears periodically for some applications:

warning: the condition has length > 1 and only the first element will be used from if (class(output_value) == "no_update") {

I'll resolve this and comment in this PR when the commit is made, in addition to adding in the test we discussed.

@rpkyle
Copy link
Contributor Author

rpkyle commented Aug 9, 2019

Looks great!

Now that we have a test framework, let's get in the habit of testing new features as they come in here. You should be able to essentially just port this one test, but simplify it - take out the Value stuff, and you only have one variant to test as opposed to that test covering both no_update and PreventUpdate:

https://github.com/plotly/dash/blob/master/tests/integration/test_integration.py#L120-L178

fixed in d1f384f

@byronz

@byronz
Copy link
Contributor

byronz commented Aug 9, 2019

fixed in d1f384f

@rpkyle I would like a change in the test with the new proposed API in plotly/dash#859

R/dash.R Outdated Show resolved Hide resolved
@alexcjohnson
Copy link
Collaborator

The current test failure - where the value hasn't updated between the .click() call and the assert - is why I used .wait_for_text_to_equal in the dash-py test. In general there should be some sort of "wait for" after any callback, then additional tests can be bare assert statements.

In this case the dashNoUpdate() calls mean we'd be waiting for the text to be what it already was - so in fact if the test is fast enough we're not really testing anything. That's why the dash-py test uses the multiprocessing Value in until(lambda: callback1_count.value == 4,...). Since we can't do that here, I'd suggest just waiting a little while (time.sleep(1)?) before testing the text when it's intended not to change.

@byronz
Copy link
Contributor

byronz commented Aug 9, 2019

The current test failure - where the value hasn't updated between the .click() call and the assert - is why I used .wait_for_text_to_equal in the dash-py test. In general there should be some sort of "wait for" after any callback, then additional tests can be bare assert statements.

In this case the dashNoUpdate() calls mean we'd be waiting for the text to be what it already was - so in fact if the test is fast enough we're not really testing anything. That's why the dash-py test uses the multiprocessing Value in until(lambda: callback1_count.value == 4,...). Since we can't do that here, I'd suggest just waiting a little while (time.sleep(1)?) before testing the text when it's intended not to change.

this represents a common scenario where you would like to check something after an action and would like to wait a little bit so the assertion was not made too early to test nothing.

instead of the sleep then assert (our current way), I'm proposing to have sth similar to wait.until or wait.until_not: it does more assertions during that sleep period with a poll=0.1.

wait.check(lambda: out.text.endswith('#FF0000'), duration=0.5)

@alexcjohnson
Copy link
Collaborator

@byronz not sure I quite follow you re: wait.check but let's have this discussion in an issue over in the dash repo. As in my previous comment I'd like to get this merged using the existing dash.testing API, then we can come back and clean it up in a future PR.

@byronz
Copy link
Contributor

byronz commented Aug 9, 2019

@byronz not sure I quite follow you re: wait.check but let's have this discussion in an issue over in the dash repo. As in my previous comment I'd like to get this merged using the existing dash.testing API, then we can come back and clean it up in a future PR.

@alexcjohnson I'm not talking about change this right now in this PR, but something we might need as test API like wait.check, what it does is consistently check the condition for a specified amount of time.

@rpkyle
Copy link
Contributor Author

rpkyle commented Aug 9, 2019

@alexcjohnson I identified a minor issue today while reviewing app PRs with the new code, the following warning appears periodically for some applications:

warning: the condition has length > 1 and only the first element will be used from if (class(output_value) == "no_update") {

I'll resolve this and comment in this PR when the commit is made, in addition to adding in the test we discussed.

fixed in ae7b1b0

R/dash.R Show resolved Hide resolved
@rpkyle
Copy link
Contributor Author

rpkyle commented Aug 12, 2019

The current test failure - where the value hasn't updated between the .click() call and the assert - is why I used .wait_for_text_to_equal in the dash-py test. In general there should be some sort of "wait for" after any callback, then additional tests can be bare assert statements.

In this case the dashNoUpdate() calls mean we'd be waiting for the text to be what it already was - so in fact if the test is fast enough we're not really testing anything. That's why the dash-py test uses the multiprocessing Value in until(lambda: callback1_count.value == 4,...). Since we can't do that here, I'd suggest just waiting a little while (time.sleep(1)?) before testing the text when it's intended not to change.

fixed in 8f6dafd

@rpkyle rpkyle requested review from byronz and alexcjohnson August 12, 2019 04:44
dashr.find_element("#color-selector").click()
dashr.find_elements("div.VirtualizedSelectOption")[0].click()
time.sleep(1)
assert dashr.find_element("#message-box").text == "The hexadecimal representation of your last chosen color is #FF0000"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not to beat a dead horse, but since this is one of the first tests I'd like to make sure we get the best pattern for all the other tests to build on.

time.sleep should be a last resort. In this test you only need it when the text is expected to be the same after the action as it was before - ie just the checks after ...[3].click(). But in all the other cases you can do

dashr.wait_for_text_to_equal(
    "#message-box",
    "The hexadecimal representation of your last chosen color is #FF0000"
)

Which will return as soon as the correct value is found on the page, saving us most of that 1 sec delay each time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in be9d387

Copy link
Collaborator

@alexcjohnson alexcjohnson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💃 Alright, one more feature toward parity!

@rpkyle rpkyle merged commit a44050a into master Aug 13, 2019
@rpkyle rpkyle deleted the issue25-no-update branch August 13, 2019 03:20
@rpkyle rpkyle added the parity Modifications to improve parity across Dash implementations label Aug 13, 2019
rpkyle added a commit that referenced this pull request Aug 23, 2019
* rename pruned_errors to prune_errors

* rename pruned to prune

* provide support for no_update in Dash for R (#111)
@rpkyle rpkyle mentioned this pull request Jan 3, 2020
rpkyle added a commit that referenced this pull request Jan 4, 2020
* Provide support for no_update in Dash for R (#111)

* Use dev_tools_prune_errors instead of pruned_errors (#113)

* Better handling for user-defined error conditions in debug mode (#116)

* Provide support for multiple outputs (#119)

* Provide support for hot reloading in Dash for R (#127)

* Implement support for clientside callbacks in Dash for R (#130)

* Add line number context to stack traces when srcrefs are available (#133)

* Update dash-renderer to 1.2.2 and fix dev tools UI display of stack traces (#137)

* Support for meta tags in Dash for R (#142)

* Fixes for hot reloading interval handling and refreshing apps within viewer pane (#148)

* Support for asynchronous loading/compression in Dash for R (#157)

* Support returning asset URLs via public method within Dash class (#160)

* Minor fix for get_asset_url + docs, add url_base_pathname (#161)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement parity Modifications to improve parity across Dash implementations size: 1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement exceptions.PreventUpdate
4 participants