-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Missing inputs #1212
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
Merged
Merged
Missing inputs #1212
Changes from 3 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
6a3ef75
local setup for test components
alexcjohnson 9c7a241
fix #1200 - all inputs missing acts like PreventUpdate
alexcjohnson a2387c3
changelog for #1212 no-input callback regression fix
alexcjohnson 4cdb7b0
console.error when we're logging info related to an error we're about…
alexcjohnson b44bd54
don't use errors as control flow
alexcjohnson 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
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 |
---|---|---|
|
@@ -154,9 +154,6 @@ function unwrapIfNotMulti(paths, idProps, spec, anyVals, depType) { | |
']' | ||
); | ||
} | ||
// TODO: unwrapped list of wildcard ids? | ||
// eslint-disable-next-line no-console | ||
console.log(paths.objs); | ||
throw new ReferenceError( | ||
'A nonexistent object was used in an `' + | ||
depType + | ||
|
@@ -247,20 +244,47 @@ async function fireReadyCallbacks(dispatch, getState, callbacks) { | |
|
||
let payload; | ||
try { | ||
const outputs = allOutputs.map((out, i) => | ||
unwrapIfNotMulti( | ||
paths, | ||
map(pick(['id', 'property']), out), | ||
cb.callback.outputs[i], | ||
cb.anyVals, | ||
'Output' | ||
) | ||
); | ||
const inVals = fillVals(paths, layout, cb, inputs, 'Input', true); | ||
|
||
const preventCallback = () => { | ||
removeCallbackFromPending(); | ||
// no server call here; for performance purposes pretend this is | ||
// a clientside callback and defer fireNext for the end | ||
// of the currently-ready callbacks. | ||
hasClientSide = true; | ||
return null; | ||
}; | ||
|
||
if (inVals === null) { | ||
return preventCallback(); | ||
} | ||
|
||
let outputs; | ||
try { | ||
outputs = allOutputs.map((out, i) => | ||
unwrapIfNotMulti( | ||
paths, | ||
map(pick(['id', 'property']), out), | ||
cb.callback.outputs[i], | ||
cb.anyVals, | ||
'Output' | ||
) | ||
); | ||
} catch (e) { | ||
if (e instanceof ReferenceError && !flatten(inVals).length) { | ||
// This case is all-empty multivalued wildcard inputs, | ||
// which we would normally fire the callback for, except | ||
// some outputs are missing. So instead we treat it like | ||
// regular missing inputs and just silently prevent it. | ||
return preventCallback(); | ||
} | ||
throw e; | ||
} | ||
|
||
payload = { | ||
output, | ||
outputs: isMultiOutputProp(output) ? outputs : outputs[0], | ||
inputs: fillVals(paths, layout, cb, inputs, 'Input'), | ||
inputs: inVals, | ||
changedPropIds: keys(cb.changedPropIds), | ||
}; | ||
if (cb.callback.state.length) { | ||
|
@@ -360,14 +384,18 @@ async function fireReadyCallbacks(dispatch, getState, callbacks) { | |
updatePending(pendingCallbacks, without(updated, allPropIds)); | ||
} | ||
|
||
function handleError(err) { | ||
function removeCallbackFromPending() { | ||
const {pendingCallbacks} = getState(); | ||
if (requestIsActive(pendingCallbacks, resolvedId, requestId)) { | ||
// Skip all prop updates from this callback, and remove | ||
// it from the pending list so callbacks it was blocking | ||
// that have other changed inputs will still fire. | ||
updatePending(pendingCallbacks, allPropIds); | ||
} | ||
} | ||
|
||
function handleError(err) { | ||
removeCallbackFromPending(); | ||
const outputs = payload | ||
? map(combineIdAndProp, flatten([payload.outputs])).join(', ') | ||
: output; | ||
|
@@ -398,9 +426,12 @@ async function fireReadyCallbacks(dispatch, getState, callbacks) { | |
return hasClientSide ? fireNext().then(done) : done; | ||
} | ||
|
||
function fillVals(paths, layout, cb, specs, depType) { | ||
function fillVals(paths, layout, cb, specs, depType, allowAllMissing) { | ||
const getter = depType === 'Input' ? cb.getInputs : cb.getState; | ||
return getter(paths).map((inputList, i) => | ||
const errors = []; | ||
let emptyMultiValues = 0; | ||
|
||
const fillInputs = (inputList, i) => | ||
unwrapIfNotMulti( | ||
paths, | ||
inputList.map(({id, property, path: path_}) => ({ | ||
|
@@ -411,8 +442,45 @@ function fillVals(paths, layout, cb, specs, depType) { | |
specs[i], | ||
cb.anyVals, | ||
depType | ||
) | ||
); | ||
); | ||
|
||
const tryFill = (inputList, i) => { | ||
try { | ||
const inputs = fillInputs(inputList, i); | ||
if (isMultiValued(specs[i]) && !inputs.length) { | ||
emptyMultiValues++; | ||
} | ||
return inputs; | ||
} catch (e) { | ||
if (e instanceof ReferenceError) { | ||
errors.push(e); | ||
return null; | ||
} | ||
// any other error we still want to see! | ||
throw e; | ||
} | ||
}; | ||
|
||
const inputVals = getter(paths).map(allowAllMissing ? tryFill : fillInputs); | ||
|
||
if (errors.length) { | ||
if (errors.length + emptyMultiValues === inputVals.length) { | ||
// We have at least one non-multivalued input, but all simple and | ||
// multi-valued inputs are missing. | ||
// (if all inputs are multivalued and all missing we still return | ||
// them as normal, and fire the callback.) | ||
return null; | ||
} | ||
// If we get here we have some missing and some present inputs. | ||
// That's a real error, so rethrow the first missing error. | ||
// Wildcard reference errors mention a list of wildcard specs logged | ||
// TODO: unwrapped list of wildcard ids? | ||
// eslint-disable-next-line no-console | ||
console.log(paths.objs); | ||
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. Is this meant to be |
||
throw errors[0]; | ||
} | ||
|
||
return inputVals; | ||
} | ||
|
||
function handleServerside(config, payload, hooks) { | ||
|
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
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.
Wondering what would be required to be able to write this (and https://github.com/plotly/dash/pull/1212/files#diff-15692ba768eeab56e95aa409ab7c19b7R279) so that we don't use exceptions as flow control.
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.
yeah I suppose that's cleaner now that they aren't always errors -> b44bd54