Skip to content

Commit

Permalink
Merge pull request #725 from neuroscout/report_warnings
Browse files Browse the repository at this point in the history
Generate warnings in report
  • Loading branch information
adelavega committed Jan 28, 2020
2 parents ff5dc13 + e15de1e commit f062f0c
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 71 deletions.
82 changes: 62 additions & 20 deletions neuroscout/frontend/src/analysis_builder/Report.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { Button, Tabs, Collapse, Card, Tooltip, Icon, Select, Spin, Popconfirm } from 'antd';
import { Alert, Button, Tabs, Collapse, Card, Tooltip, Icon, Select, Spin, Popconfirm } from 'antd';
import vegaEmbed from 'vega-embed';

import { OptionProps } from 'antd/lib/select';
Expand Down Expand Up @@ -33,6 +33,28 @@ class VegaPlot extends React.Component<{spec: string}, {}> {
}
}

class Warnings extends React.Component<{warnings: string[]}> {
render() {
let alerts: any[] = [];
this.props.warnings.map((x, i) => {
alerts.push(
<Alert
message="Warning"
description={x}
type="warning"
showIcon={true}
/>
);
});
return(
<div>
<br/>
{alerts}
</div>
);
}
}

class Plots extends React.Component<{matrices: string[], plots: any[], corr_plots: any[], runTitles: string[]}, {}> {
plotContainer;
constructor(props) {
Expand Down Expand Up @@ -68,12 +90,28 @@ class Plots extends React.Component<{matrices: string[], plots: any[], corr_plot
}
}

class Tracebacks extends React.Component<{reportTraceback: string, compileTraceback: string}, {}> {
export class Tracebacks extends React.Component<{traceback: string, message: string}, {}> {
render() {
let display: any[] = [];
if (this.props.traceback) {
display.push(
<Alert
message={this.props.message}
description={
<div><p>{this.props.traceback}</p>
If you don't know what this error means, feel free to ask
on <a href="https://neurostars.org/">NeuroStars</a>.<br/>
If you believe this is a bug, please open an issue on open an
<a href="https://github.com/neuroscout/neuroscout/issues"> issue on GitHub</a>.
</div>}
type="error"
showIcon={true}
/>
);
}
return(
<div>
<p>{this.props.reportTraceback}</p>
<p>{this.props.compileTraceback}</p>
{display}
</div>
);
}
Expand All @@ -91,9 +129,9 @@ interface ReportState {
matrices: string[];
plots: string[];
corr_plots: string[];
warnings: string[];
reportTimestamp: string;
reportTraceback: string;
compileTraceback: string;
reportsLoaded: boolean;
reportsPosted: boolean;
compileLoaded: boolean;
Expand All @@ -111,12 +149,12 @@ export class Report extends React.Component<ReportProps, ReportState> {
matrices: [],
plots: [],
corr_plots: [],
warnings: [],
reportTimestamp: '',
reportsLoaded: false,
reportsPosted: false,
compileLoaded: false,
reportTraceback: '',
compileTraceback: '',
selectedRunIds: ['' + this.props.runs[0].id],
runTitles: [this.formatRun(this.props.runs[0])],
warnVisible: false
Expand Down Expand Up @@ -164,6 +202,11 @@ export class Report extends React.Component<ReportProps, ReportState> {
let state = {...this.state};
jwtFetch(`${domainRoot}/api/analyses/${id}/report?run_id=${this.state.selectedRunIds}`)
.then((res) => {
if (res.warnings) {
state.warnings = res.warnings;
} else {
state.warnings = [];
}
if (res.status === 'OK') {
if (res.result === undefined) {
return;
Expand All @@ -187,7 +230,6 @@ export class Report extends React.Component<ReportProps, ReportState> {
} else {
return;
}

state.reportsLoaded = true;
this.setState({...state});
});
Expand All @@ -211,9 +253,6 @@ export class Report extends React.Component<ReportProps, ReportState> {
.then((res) => {
state.status = res.status;
state.compileLoaded = true;
if (res.traceback) {
state.compileTraceback = res.traceback;
}
this.setState({...state});
});
}
Expand Down Expand Up @@ -254,13 +293,13 @@ export class Report extends React.Component<ReportProps, ReportState> {
}

filterRuns = (inputValue: string, option: React.ReactElement<OptionProps>): boolean => {

if (option.props.children) {
return ('' + option.props.children).includes(inputValue);
}
return false;
}

formatRun = (run: Run) => {
let ret = '';
if (!!run.subject) {
Expand Down Expand Up @@ -362,17 +401,20 @@ export class Report extends React.Component<ReportProps, ReportState> {
corr_plots={this.state.corr_plots}
runTitles={this.state.runTitles}
/>

{(this.state.warnings.length > 0) && <Warnings warnings={this.state.warnings} />}

{(this.state.reportTraceback) &&
<div>
<br/>
<Tracebacks
message="Report failed to generate"
traceback={this.state.reportTraceback}
/>
<br/></div>}
</Spin>
</Card>
<br/>
{(this.state.reportTraceback || this.state.compileTraceback) &&
<div>
<Card title="Errors" key="errors">
<Tracebacks
reportTraceback={this.state.reportTraceback}
compileTraceback={this.state.compileTraceback}
/>
</Card><br/></div>}
</div>
);
}
Expand Down
30 changes: 13 additions & 17 deletions neuroscout/frontend/src/analysis_builder/Status.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { jwtFetch } from '../utils';
import { Analysis } from '../coretypes';
import { StatusTag } from '../HelperComponents';
import { api } from '../api';

import { Tracebacks } from './Report';
const domainRoot = config.server_url;

export class DLLink extends React.Component<{status?: string, analysisId?: string}, {}> {
Expand Down Expand Up @@ -163,8 +163,8 @@ export class StatusTab extends React.Component<submitProps, statusTabState> {
}
jwtFetch(`${domainRoot}/api/analyses/${id}/compile`)
.then((res) => {
if (res.compile_traceback) {
this.setState({compileTraceback: res.compile_traceback});
if (res.traceback) {
this.setState({compileTraceback: res.traceback});
}
});
}
Expand Down Expand Up @@ -273,20 +273,6 @@ export class StatusTab extends React.Component<submitProps, statusTabState> {
<br/>
</div>
}
{(this.props.status === 'FAILED') &&
<div>
<h3>Analysis Failed to Compile</h3>
<p>
Oh no! It looks like your analysis failed to compile.
Once you make changes to fix the analysis you can re-run it below.
If the issue remains, please file a
<a href="https://github.com/neuroscout/neuroscout/issues"> bugreport</a>.
</p>
<Card title="Errors" key="errors">
<pre>{this.state.compileTraceback}</pre>
</Card>
</div>
}
{(this.props.status === 'DRAFT' || this.props.status === 'FAILED') &&
<Submit
status={this.props.status}
Expand All @@ -295,6 +281,16 @@ export class StatusTab extends React.Component<submitProps, statusTabState> {
private={this.props.private}
/>
}
{(this.props.status === 'FAILED') &&
<div>
<br/>
<Tracebacks
message="Analysis failed to compile"
traceback={this.state.compileTraceback}
/>
<br/>
</div>
}
{(this.props.status === 'PENDING' || this.props.status === 'SUBMITTING') &&
<div>
<h3>Analysis Pending Generation</h3>
Expand Down
1 change: 1 addition & 0 deletions neuroscout/models/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ class Report(db.Model):
generated_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
task_id = db.Column(db.Text) # Celery task id
result = db.Column(JSONB) # JSON result from Celery (once finished)
warnings = db.Column(JSONB, default=[])
traceback = db.Column(db.Text)

status = db.Column(db.Text, default='PENDING')
Expand Down
8 changes: 4 additions & 4 deletions neuroscout/populate/modify.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def delete_task(dataset, task):
db.session.commit()


def extend_extracted_objects(dataset_name, **selectors):
def extend_extracted_objects(dataset_name, task_name, **selectors):
""" Links RunStimuli for newly ingest runs in a Dataset,
for all ExtractedFeatures. Also links derived Stimuli with new Runs.
Args:
Expand All @@ -42,8 +42,8 @@ def extend_extracted_objects(dataset_name, **selectors):
run_ids = Run.query
for key, value in selectors.items():
run_ids = run_ids.filter(getattr(Run, key).in_(value))
runs = run_ids.join(Dataset).filter_by(
name=dataset_name)
runs = run_ids.join(Task).filter_by(name=task_name).join(
Dataset).filter_by(name=dataset_name)

# Create RunStimulus associations with derived stimuli
new_rs = []
Expand All @@ -69,7 +69,7 @@ def extend_extracted_objects(dataset_name, **selectors):
ExtractedEvent).join(Stimulus).join(
RunStimulus).filter(RunStimulus.run_id.in_(run_ids)).all()

create_predictors(efs, dataset_name, run_ids)
create_predictors(efs, dataset_name, task_name, run_ids)


def update_annotations(mode='predictors', **kwargs):
Expand Down
2 changes: 2 additions & 0 deletions neuroscout/schemas/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ class ReportSchema(Schema):
generated_at = fields.Time(description='Time report was generated')
result = fields.Dict(description='Links to report resources')
status = fields.Str(description='Report status')
warnings = fields.List(
fields.Str(), description='Report warnings')
traceback = fields.Str(
description='Traceback of generation error.')

Expand Down
37 changes: 18 additions & 19 deletions neuroscout/tasks/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
from .utils.build import build_analysis, impute_confounds
from .utils.viz import plot_design_matrix, plot_corr_matrix, sort_dm
from .utils.io import (
dump_analysis, update_record, PathBuilder, write_jsons, write_tarball)
update_record, PathBuilder, write_jsons, write_tarball, analysis_to_json)
from .utils.warnings import pre_warnings

MIN_CLI_VERSION = '0.3.3'

Expand All @@ -20,31 +21,27 @@ def compile(flask_app, hash_id, run_ids=None, build=False):
build (bool): Validate in pybids?
"""
FILE_DATA = Path(flask_app.config['FILE_DIR'])
analysis_object = Analysis.query.filter_by(hash_id=hash_id).one()

try:
analysis_object = Analysis.query.filter_by(hash_id=hash_id).one()
except Exception as e:
return {
'traceback': f'Error loading {hash_id} from db /n {str(e)}'
}
try:
a_id, analysis, resources, pes, bids_dir = dump_analysis(
hash_id)
a_id, analysis, resources, pes, bids_dir = analysis_to_json(
hash_id, run_ids)
except Exception as e:
update_record(
analysis_object,
exception=e,
traceback='Error deserializing analysis'
)
raise

try:
tmp_dir, bundle_paths, _ = build_analysis(
analysis, pes, bids_dir, run_ids, build=build)
except Exception as e:
update_record(
analysis_object,
exception=e,
traceback='Error validating analysis'
traceback='Error building analysis'
)
raise

Expand Down Expand Up @@ -94,30 +91,32 @@ def generate_report(flask_app, hash_id, report_id,
"""
FILE_DATA = Path(flask_app.config['FILE_DIR'])
domain = flask_app.config['SERVER_NAME']
report_object = Report.query.filter_by(id=report_id).one()

try:
report_object = Report.query.filter_by(id=report_id).one()
_, analysis, resources, pes, bids_dir = analysis_to_json(
hash_id, run_ids)
except Exception as e:
return {
'traceback': f'Error loading {report_id} from db /n {str(e)}'
}
update_record(
report_object,
exception=e,
traceback='Error deserializing analysis'
)
raise

try:
a_id, analysis, resources, pes, bids_dir = dump_analysis(
hash_id)
pre_warnings(analysis, pes, report_object)
except Exception as e:
update_record(
report_object,
exception=e,
traceback='Error deserializing analysis'
traceback='Error generating warnings'
)
raise

try:
_, _, bids_analysis = build_analysis(
analysis, pes, bids_dir, run_ids)
except Exception as e:
# Todo: In future, could add more messages here
update_record(
report_object,
exception=e,
Expand Down

0 comments on commit f062f0c

Please sign in to comment.