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
feat: convert backend chart errors to the new error type #9753
Conversation
8c32f79
to
6232b47
Compare
@@ -39,7 +39,7 @@ class Datasource(BaseSupersetView): | |||
def save(self) -> Response: | |||
data = request.form.get("data") | |||
if not isinstance(data, str): | |||
return json_error_response("Request missing data field.", status="500") | |||
return json_error_response("Request missing data field.", status=500) |
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.
cleaning up some typing
from typing import Any, Dict | ||
|
||
|
||
class SupersetErrorType(str, Enum): |
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.
inheriting from str
provides automatic json serialization
6232b47
to
ed1e2fe
Compare
FRONTEND_CSRF_ERROR: 'FRONTEND_CSRF_ERROR', | ||
FRONTEND_NETWORK_ERROR: 'FRONTEND_NETWORK_ERROR', | ||
FRONTEND_TIMEOUT_ERROR: 'FRONTEND_TIMEOUT_ERROR', | ||
|
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.
Nit. Nix empty lines?
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.
I put the empty lines here to try and organize these errors into categories, since i expect there to be many of them going forward
setup.cfg
Outdated
@@ -45,7 +45,7 @@ combine_as_imports = true | |||
include_trailing_comma = true | |||
line_length = 88 | |||
known_first_party = superset | |||
known_third_party =alembic,apispec,backoff,bleach,celery,click,colorama,contextlib2,croniter,cryptography,dataclasses,dateutil,flask,flask_appbuilder,flask_babel,flask_caching,flask_compress,flask_login,flask_migrate,flask_sqlalchemy,flask_talisman,flask_testing,flask_wtf,geohash,geopy,humanize,isodate,jinja2,markdown,markupsafe,marshmallow,msgpack,numpy,pandas,parsedatetime,pathlib2,polyline,prison,pyarrow,pyhive,pytz,retry,selenium,setuptools,simplejson,sphinx_rtd_theme,sqlalchemy,sqlalchemy_utils,sqlparse,werkzeug,wtforms,wtforms_json,yaml | |||
known_third_party =alembic,apispec,backoff,bleach,celery,click,colorama,contextlib2,croniter,cryptography,dateutil,flask,flask_appbuilder,flask_babel,flask_caching,flask_compress,flask_login,flask_migrate,flask_sqlalchemy,flask_talisman,flask_testing,flask_wtf,geohash,geopy,humanize,isodate,jinja2,markdown,markupsafe,marshmallow,msgpack,numpy,pandas,parsedatetime,pathlib2,polyline,prison,pyarrow,pyhive,pytz,retry,selenium,setuptools,simplejson,sphinx_rtd_theme,sqlalchemy,sqlalchemy_utils,sqlparse,werkzeug,wtforms,wtforms_json,yaml |
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.
dataclasses
should be included here as it's not part of the stdlib
in Python 3.6.
FRONTEND_CSRF_ERROR = "FRONTEND_CSRF_ERROR" | ||
FRONTEND_NETWORK_ERROR = "FRONTEND_NETWORK_ERROR" | ||
FRONTEND_TIMEOUT_ERROR = "FRONTEND_TIMEOUT_ERROR" | ||
|
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.
Nit. Nix empty lines?
superset/errors.py
Outdated
message: str | ||
error_type: SupersetErrorType | ||
level: ErrorLevel | ||
extra: Dict[str, Any] |
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.
Do you want to make this optional?
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.
I went back and forth on that... I guess optional is probably safer in the long run, and means people don't need to remember to initialize with an empty dict, although it pushes a bit of work to the front end to check that the object exists
superset/viz.py
Outdated
|
||
error = dataclasses.asdict( | ||
SupersetError( | ||
message="{}".format(ex), |
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.
Why not message=str(ex)
?
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.
this was copy pasted from before, i assume str(ex)
works the same way, so i'll change it
superset/viz.py
Outdated
message="{}".format(ex), | ||
level=ErrorLevel.ERROR, | ||
type=SupersetErrorType.VIZ_GET_DF_ERROR, | ||
extra={}, |
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.
See note regarding making this optional.
superset/viz.py
Outdated
extra={}, | ||
) | ||
) | ||
if not self.errors: |
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.
See previous comment which would simplify this to self.errors.append(error)
.
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.
not sure how your previous comment would affect this
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.
@etr2460 apologies if I'm misreading the logic but isn't self.errors
going to be a list by default and thus rather than:
if not self.errors:
self.errors = [error]
else:
self.errors.append(error)
this could be:
self.errors.append(error)
213096b
to
81a1153
Compare
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.
@john-bodley replied to/addressed your comments
FRONTEND_CSRF_ERROR: 'FRONTEND_CSRF_ERROR', | ||
FRONTEND_NETWORK_ERROR: 'FRONTEND_NETWORK_ERROR', | ||
FRONTEND_TIMEOUT_ERROR: 'FRONTEND_TIMEOUT_ERROR', | ||
|
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.
I put the empty lines here to try and organize these errors into categories, since i expect there to be many of them going forward
superset/errors.py
Outdated
message: str | ||
error_type: SupersetErrorType | ||
level: ErrorLevel | ||
extra: Dict[str, Any] |
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.
I went back and forth on that... I guess optional is probably safer in the long run, and means people don't need to remember to initialize with an empty dict, although it pushes a bit of work to the front end to check that the object exists
superset/viz.py
Outdated
|
||
error = dataclasses.asdict( | ||
SupersetError( | ||
message="{}".format(ex), |
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.
this was copy pasted from before, i assume str(ex)
works the same way, so i'll change it
superset/viz.py
Outdated
extra={}, | ||
) | ||
) | ||
if not self.errors: |
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.
not sure how your previous comment would affect this
81a1153
to
d00f6dd
Compare
Codecov Report
@@ Coverage Diff @@
## master #9753 +/- ##
==========================================
+ Coverage 70.79% 70.98% +0.19%
==========================================
Files 587 184 -403
Lines 30435 17854 -12581
Branches 3152 0 -3152
==========================================
- Hits 21545 12673 -8872
+ Misses 8776 5181 -3595
+ Partials 114 0 -114
Continue to review full report at Codecov.
|
superset/models/helpers.py
Outdated
): | ||
self.df: pd.DataFrame = df | ||
self.query: str = query | ||
self.duration: int = duration | ||
self.status: str = status | ||
self.error_message: Optional[str] = error_message | ||
self.errors: Optional[List[Dict[str, Any]]] = errors |
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.
@etr2460 sorry this could be:
self.errors: List[Dict[str, Any]] = errors or []
which simplifies the related content in viz.py
.
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.
I actually think it's better to keep this optional? Because at the end of the day we send errors
down to the client, and i think it being null is better than []
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.
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.
I moved to empty list to make the backend logic a bit neater
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.
389f774
to
dc776e9
Compare
bd9517b
to
7b87ad2
Compare
7b87ad2
to
fa15615
Compare
@@ -48,6 +50,12 @@ export default function getClientErrorObject( | |||
.json() | |||
.then(errorJson => { | |||
let error = { ...responseObject, ...errorJson }; | |||
|
|||
// Backwards compatibility for old error renderers with the new error object | |||
if (error.errors && error.errors.length > 0) { |
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.
I suspect this new line cause some error_details logged as empty.
this is how front-end use error field:
https://github.com/apache/incubator-superset/blob/38a6bd79da2be8c13a89a5f67f77faeb55c4e08b/superset-frontend/src/chart/chartAction.js#L403
Can you check what is in err.errors[0].message?
CATEGORY
Choose one
SUMMARY
Continuing to implement SIP-40, this time adding some of the backend logic. My plan is as follows:
error
field in api responses with theerrors
list of SupersetError Objectserrors
list into theerror
field againBEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
No ui changes
TEST PLAN
Test dashboards loading with and without errors in charts, see errors still render properly
Test SQL Lab with and without query errors
ADDITIONAL INFORMATION
REVIEWERS
to: @john-bodley @villebro @dpgaspar