-
-
Notifications
You must be signed in to change notification settings - Fork 31
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
189 - Add Pattern Matching Callbacks for Dash R #228
Merged
Merged
Changes from all commits
Commits
Show all changes
65 commits
Select commit
Hold shift + click to select a range
508f8f5
Dash for R v0.7.1 (#221)
rpkyle 9be5ef9
Testing initial implementation
HammadTheOne 7cb20ef
More testing
HammadTheOne 8c39812
Callback Context Updates
HammadTheOne 0f47a6c
Updating callback context logic
HammadTheOne c4b6896
Fixing callback returns
HammadTheOne e860e0d
Adding callback args conditional
HammadTheOne 26372a3
Cleanup and additional changes to callback value conditionals
HammadTheOne aa8a9fc
Comment cleanup
HammadTheOne a4a196a
Added PMC callback validation, removed unnecessary code
HammadTheOne d19ed4e
Update R/dependencies.R
HammadTheOne fd09358
Update R/dependencies.R
HammadTheOne 4219296
Update R/dependencies.R
HammadTheOne 6f2539b
Update R/dependencies.R
HammadTheOne be2e509
Added build to gitignore
HammadTheOne 7ea4f56
Updated dependencies.R
HammadTheOne 18192cd
Update boilerplate docs and add wildcard symbols
HammadTheOne 504233a
Drying up validation code and applying symbol logic
HammadTheOne 1944f6f
Merge branch 'master' into 189-wildcards
HammadTheOne ba8f58c
Update test to use symbols
HammadTheOne fc58486
Cleaned up code and added allsmaller test example
HammadTheOne c94455f
Cleaning up redundant code
HammadTheOne f7723e0
Merge branch '189-wildcards' of https://github.com/plotly/dashr into …
HammadTheOne 939dc24
Update FUNDING.yml
nicolaskruchten 3c30a78
Updated callback_args logic and example
HammadTheOne bcec380
Adding basic unittests, updated validation
HammadTheOne 28e0bf4
Fixed response for MATCH callbacks
HammadTheOne 4af91cb
Added integration test and updated examples for docs
HammadTheOne 85e3052
Added additional integration test
HammadTheOne 77981ce
Formatting and cleanup
HammadTheOne 2d84a88
Merge branch 'master' into 189-wildcards
HammadTheOne e8831dd
update docs
bf63f8a
Update to-do app
HammadTheOne fb34b11
Merge branch '189-wildcards' of https://github.com/plotly/dashr into …
HammadTheOne 84f7cdf
Add comments to examples
HammadTheOne 297c0e8
Change empy vector to character type.
HammadTheOne 1ace13d
Update boilerplate text.
HammadTheOne 67166fb
Update tests/integration/callbacks/test_pattern_matching.py
HammadTheOne aa89f81
Update tests/integration/callbacks/test_pattern_matching.py
HammadTheOne 5d8c12a
Update tests/integration/callbacks/test_pattern_matching.py
HammadTheOne b2d9f30
Update tests/integration/callbacks/test_pattern_matching.py
HammadTheOne 6c01c78
Update tests/integration/callbacks/test_pattern_matching.py
HammadTheOne 7118828
Update tests/testthat/test-wildcards.R
HammadTheOne ab327c4
Update wildcards_test.R
HammadTheOne dc5e2e3
Update wildcards_test.R
HammadTheOne e06dd57
Update wildcards_test.R
HammadTheOne d43a59b
Update wildcards_test.R
HammadTheOne 1bc1cfc
Update wildcards_test.R
HammadTheOne e8a4fb1
Update wildcards_test.R
HammadTheOne c7fc099
Update wildcards_test.R
HammadTheOne 28560cd
Update wildcards_test.R
HammadTheOne 56f491a
Removed triple colon syntax
HammadTheOne 577deb4
Use seq_along and remove unnecessary unittest
HammadTheOne 617e873
Merge branch 'dev' into 189-wildcards
rpkyle 0250dbc
Update CHANGELOG.md
rpkyle e745e2f
Update CHANGELOG.md
rpkyle b9218b7
Add support for arbitrary and sorted keys
HammadTheOne 06b37d8
Whitespace deleted
HammadTheOne fc45ee7
Added integration tests
HammadTheOne 0b6d543
Fixing test output
HammadTheOne 1bec3c5
Fixing flakiness
HammadTheOne d777ae1
Update test_pattern_matching.py
HammadTheOne 330eb9d
Update test_pattern_matching.py
HammadTheOne 5969add
Updating boilerplate text and test with generalized keys
HammadTheOne 210d3c1
Minor test fixes
HammadTheOne File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
github: plotly | ||
custom: https://plotly.com/products/consulting-and-oem/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ node_modules/ | |
python/ | ||
todo.txt | ||
r-finance* | ||
build/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -290,6 +290,22 @@ assert_no_names <- function (x) | |
paste(nms, collapse = "', '")), call. = FALSE) | ||
} | ||
|
||
assertValidWildcards <- function(dependency) { | ||
if (is.symbol(dependency$id)) { | ||
result <- (jsonlite::validate(as.character(dependency$id)) && grepl("{", dependency$id)) | ||
} else { | ||
result <- TRUE | ||
} | ||
if (!result) { | ||
dependencyType <- class(dependency) | ||
stop(sprintf("A callback %s ID contains restricted pattern matching callback selectors ALL, MATCH or ALLSMALLER. Please verify that it is formatted as a pattern matching callback list ID, or choose a different component ID.", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we still need this check now that we're using symbols for these keywords? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, I can remove those now, and replace them with a different validation. |
||
dependencyType[dependencyType %in% c("input", "output", "state")]), | ||
call. = FALSE) | ||
} else { | ||
return(result) | ||
} | ||
} | ||
|
||
# the following function attempts to prune remote CSS | ||
# or local CSS/JS dependencies that either should not | ||
# be resolved to local R package paths, or which have | ||
|
@@ -403,6 +419,27 @@ assert_valid_callbacks <- function(output, params, func) { | |
stop(sprintf("The callback method requires that one or more properly formatted inputs are passed."), call. = FALSE) | ||
} | ||
|
||
# Verify that 'input', 'state' and 'output' parameters only contain 'Wildcard' keywords if they are JSON formatted ids for pattern matching callbacks | ||
valid_wildcard_inputs <- sapply(inputs, function(x) { | ||
rpkyle marked this conversation as resolved.
Show resolved
Hide resolved
|
||
assertValidWildcards(x) | ||
}) | ||
|
||
|
||
valid_wildcard_state <- sapply(state, function(x) { | ||
assertValidWildcards(x) | ||
}) | ||
|
||
if(any(sapply(output, is.list))) { | ||
valid_wildcard_output <- sapply(output, function(x) { | ||
assertValidWildcards(x) | ||
}) | ||
} else { | ||
valid_wildcard_output <- sapply(list(output), function(x) { | ||
assertValidWildcards(x) | ||
}) | ||
} | ||
|
||
|
||
# Check that outputs are not inputs | ||
# https://github.com/plotly/dash/issues/323 | ||
|
||
|
@@ -987,29 +1024,78 @@ removeHandlers <- function(fnList) { | |
} | ||
|
||
setCallbackContext <- function(callback_elements) { | ||
states <- lapply(callback_elements$states, function(x) { | ||
setNames(x$value, paste(x$id, x$property, sep=".")) | ||
}) | ||
# Set state elements for this callback | ||
|
||
if (length(callback_elements$state[[1]]) == 0) { | ||
states <- sapply(callback_elements$state, function(x) { | ||
setNames(list(x$value), paste(x$id, x$property, sep=".")) | ||
}) | ||
} else if (is.character(callback_elements$state[[1]][[1]])) { | ||
states <- sapply(callback_elements$state, function(x) { | ||
setNames(list(x$value), paste(x$id, x$property, sep=".")) | ||
}) | ||
} else { | ||
states <- sapply(callback_elements$state, function(x) { | ||
states_vector <- unlist(x) | ||
setNames(list(states_vector[grepl("value|value.", names(states_vector))]), | ||
paste(as.character(jsonlite::toJSON(x[[1]])), x$property, sep=".")) | ||
}) | ||
} | ||
|
||
splitIdProp <- function(x) unlist(strsplit(x, split = "[.]")) | ||
|
||
triggered <- lapply(callback_elements$changedPropIds, | ||
function(x) { | ||
input_id <- splitIdProp(x)[1] | ||
prop <- splitIdProp(x)[2] | ||
|
||
id_match <- vapply(callback_elements$inputs, function(x) x$id %in% input_id, logical(1)) | ||
prop_match <- vapply(callback_elements$inputs, function(x) x$property %in% prop, logical(1)) | ||
|
||
value <- sapply(callback_elements$inputs[id_match & prop_match], `[[`, "value") | ||
|
||
list(`prop_id` = x, `value` = value) | ||
|
||
# The following conditionals check whether the callback is a pattern-matching callback and if it has been triggered. | ||
if (startsWith(input_id, "{")){ | ||
id_match <- vapply(callback_elements$inputs, function(x) { | ||
x <- unlist(x) | ||
any(x[grepl("id.", names(x))] %in% jsonlite::fromJSON(input_id)[[1]]) | ||
}, logical(1))[[1]] | ||
} else { | ||
id_match <- vapply(callback_elements$inputs, function(x) x$id %in% input_id, logical(1)) | ||
} | ||
|
||
if (startsWith(input_id, "{")){ | ||
prop_match <- vapply(callback_elements$inputs, function(x) { | ||
x <- unlist(x) | ||
any(x[names(x) == "property"] %in% prop) | ||
}, logical(1))[[1]] | ||
} else { | ||
prop_match <- vapply(callback_elements$inputs, function(x) x$property %in% prop, logical(1)) | ||
} | ||
|
||
if (startsWith(input_id, "{")){ | ||
if (length(callback_elements$inputs) == 1 || !is.null(unlist(callback_elements$inputs, recursive = F)$value)) { | ||
value <- sapply(callback_elements$inputs[id_match & prop_match], `[[`, "value") | ||
} else { | ||
value <- sapply(callback_elements$inputs[id_match & prop_match][[1]], `[[`, "value") | ||
} | ||
} else { | ||
value <- sapply(callback_elements$inputs[id_match & prop_match], `[[`, "value") | ||
} | ||
|
||
return(list(`prop_id` = x, `value` = value)) | ||
} | ||
) | ||
|
||
inputs <- sapply(callback_elements$inputs, function(x) { | ||
setNames(list(x$value), paste(x$id, x$property, sep=".")) | ||
}) | ||
) | ||
if (length(callback_elements$inputs[[1]]) == 0 || is.character(callback_elements$inputs[[1]][[1]])) { | ||
inputs <- sapply(callback_elements$inputs, function(x) { | ||
setNames(list(x$value), paste(x$id, x$property, sep=".")) | ||
}) | ||
} else if (length(callback_elements$inputs[[1]]) > 1) { | ||
inputs <- sapply(callback_elements$inputs, function(x) { | ||
inputs_vector <- unlist(x) | ||
setNames(list(inputs_vector[grepl("value|value.", names(inputs_vector))]), paste(as.character(jsonlite::toJSON(x$id)), x$property, sep=".")) | ||
}) | ||
} else { | ||
inputs <- sapply(callback_elements$inputs, function(x) { | ||
inputs_vector <- unlist(x) | ||
setNames(list(inputs_vector[grepl("value|value.", names(inputs_vector))]), paste(as.character(jsonlite::toJSON(x[[1]]$id)), x[[1]]$property, sep=".")) | ||
}) | ||
} | ||
|
||
return(list(states=states, | ||
triggered=unlist(triggered, recursive=FALSE), | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here it looks like we're checking if
values
has a non-zero length. I'd guess that ifvalues = NULL
, then the length is zero. If this is correct, could we rewrite this as follows?