-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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 inference error messages in WIT notebook mode #2414
Conversation
@tolga-b please review |
@stephanwlee please review, thanks |
handleError_: function(errorStr) { | ||
this.showToast_(errorStr); | ||
this.exampleStatusStr = errorStr; | ||
this.$.spinner.hidden = true; |
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.
Can you please use the Polymer data binding instead?
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.
done
this.exampleStatusStr = 'Request failed'; | ||
this.showToast_('Request failed: ' + reason); | ||
this.$.spinner.hidden = true; | ||
this.handleError_('Request failed: ' + reason); |
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.
Strings like 'Request failed' often don't mean anything to the user (especially if it is a toast; which request? TensorBoard's request?). Please be a little bit more descriptive.
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.
good point. Adding new string param for what the request does, so that if it fails the error states what request failed (such as 'Datapoint load', or 'Model inference').
output.eval_js("""inferenceCallback('{inferences}')""".format( | ||
inferences=json.dumps(inferences))) | ||
except Exception as e: | ||
error_str = str(e) |
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.
How is this used?
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.
thx, removed
@@ -90,6 +90,9 @@ def infer_mutants(wit_id, details): | |||
|
|||
// Javascript callbacks called by python code to communicate with WIT | |||
// Polymer element. | |||
window.backendError = errorStr => {{ | |||
wit.handleError_(errorStr); |
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.
make handleError_
a public method
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.
done
inferences=json.dumps(inferences))) | ||
try: | ||
inferences = base.WitWidgetBase.infer_impl(self) | ||
output.eval_js("""inferenceCallback('{inferences}')""".format( |
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.
Pardon the drive-by, but this is an injection vector when any of the
keys or values (recursively) of inferences
contains a single quote:
>>> import json
>>> inferences = {"label_vocab": "',alert('hmm'),null[0],'"}
>>> js = """inferenceCallback('{inferences}')""".format(
... inferences=json.dumps(inferences))
>>> print(js)
inferenceCallback('{"label_vocab": "',alert('hmm'),null[0],'"}')
I’d expect to see simply inferenceCallback({inferences})
, without the
quotes, such that the JS gets an object literal rather than a string
literal. If it really needs to be a string for some reason, you can
create the string literal safely by JSON-encoding again (in either
Python or JS).
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.
replaced with object and not string.
inferences=json.dumps(inferences))) | ||
except Exception as e: | ||
error_str = str(e) | ||
output.eval_js("""backendError('{error}')""".format( |
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.
Likewise an injection vector, and this one may be plausibly hit even in
a non-malicious case, because Python exception texts frequently contain
single quotes:
>>> import json
>>> try: None.wat
... except Exception as e:
... js = """backendError('{error}')""".format(error=json.dumps(str(e)))
... print(js)
...
backendError('"'NoneType' object has no attribute 'wat'"')
>>> # ^ JS syntax error
(More occurrences below.)
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.
replaced with object and not string.
addressed @stephanwlee and @wchargin comments |
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.
All comments are nits.
makeAsyncRequest_: function( | ||
url, thenDoFn, postData, errorFn = () => {}) { | ||
url, thenDoFn, postData, requestStr, errorFn = () => {}) { |
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.
super nit: requestStr
-> humanReadableRequestName
?
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.
done
this.exampleStatusStr = 'Request failed'; | ||
this.showToast_('Request failed: ' + reason); | ||
this.$.spinner.hidden = true; | ||
this.handleError(requestStr + ' failed: ' + reason); |
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.
`Request for ${humanReadableRequestName} failed: ${reason}`
I thought it would be confusing to show a toast that says something like Model inference failed: foobarbaz
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.
done
try: | ||
inferences = base.WitWidgetBase.infer_impl(self) | ||
output.eval_js("""inferenceCallback({inferences})""".format( | ||
inferences=json.dumps(inferences))) |
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.
as per http://google.github.io/styleguide/pyguide.html#3192-line-breaking, you might want +2 more whitespace here and below.
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.
done
@stephanwlee addressed your comments, thanks |
If a model fails to run inference in WitWidget, no error is currently displayed so the user has no idea why WIT isn't working correctly. This change adds in proper error handling.
Updated jupyter and colab witwidget code so that if inference throws any python error, it is properly caught and sent to the frontend.
The frontend now displays that inference error in a toast and in the status message.
Also fixed a small bug where when comparing 2 regression models, the initial Facets Dive view doesn't compare the two models.
Ran colab and jupyter notebooks with and without inference errors to see that the error message in both cases gets to the user.
Ran a two-model regression notebook to see proper default Dive display.