Skip to content

Commit

Permalink
MAINT: propogate errors on file upload (#13)
Browse files Browse the repository at this point in the history
* MAINT: show errors on file upload

* TST: test errors propogated
  • Loading branch information
stsievert authored Apr 13, 2020
1 parent d5a1e96 commit a988a8b
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 18 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ login:
docker run -i -t salmon_frontend /bin/bash

watch:
# for debugging on ec2, `sudo make watch`
docker-compose logs -f

63 changes: 47 additions & 16 deletions frontend/frontend/private.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from io import StringIO
import pprint
from functools import lru_cache
import traceback

import numpy as np

Expand All @@ -24,6 +25,8 @@
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from starlette.responses import HTMLResponse, JSONResponse, RedirectResponse
from starlette.status import HTTP_401_UNAUTHORIZED
from fastapi.responses import PlainTextResponse
from starlette.exceptions import HTTPException as StarletteHTTPException

from .public import _ensure_initialized, app, templates
from .utils import ServerException, get_logger, _extract_zipfile, _format_target
Expand Down Expand Up @@ -94,6 +97,45 @@ def upload_form():
return HTMLResponse(content=body)


async def _get_config(exp: bytes, targets_file: bytes) -> Dict[str, Any]:
config = yaml.load(exp, Loader=yaml.SafeLoader)
logger.info(config)
exp_config: Dict = {
"instructions": "Default instructions (can include <i>arbitrary</i> HTML)",
"max_queries": None,
"debrief": "Thanks!",
}
exp_config.update(config)

if targets_file:
fnames = _extract_zipfile(targets_file)
targets = [_format_target(f) for f in fnames]
exp_config["targets"] = targets

exp_config["n"] = len(exp_config["targets"])
logger.info(exp_config)
return exp_config


def exception_to_string(excp):
stack = traceback.extract_stack()[:-3] + traceback.extract_tb(
excp.__traceback__
) # add limit=??
pretty = traceback.format_list(stack)
return "Error!\n\n\nSummary:\n\n{} {}\n\nFull traceback:\n\n".format(
excp.__class__, excp
) + "".join(pretty)


class ExpParsingError(StarletteHTTPException):
pass


@app.exception_handler(ExpParsingError)
async def http_exception_handler(request, exc):
return PlainTextResponse(exc.detail, status_code=exc.status_code)


@app.post("/init_exp", tags=["private"])
async def process_form(
request: Request,
Expand Down Expand Up @@ -122,22 +164,11 @@ async def process_form(
- instructions: "Foobar!"
- max_queries: 25
"""

config = yaml.load(exp, Loader=yaml.SafeLoader)
print(config)
exp_config: Dict = {
"instructions": "Default instructions (can include <i>arbitrary</i> HTML)",
"max_queries": None,
"debrief": "Thanks!",
}
exp_config.update(config)

if targets_file:
fnames = _extract_zipfile(targets_file)
targets = [_format_target(f) for f in fnames]
exp_config["targets"] = targets

exp_config["n"] = len(exp_config["targets"])
try:
exp_config = await _get_config(exp, targets_file)
except Exception as e:
msg = exception_to_string(e)
raise ExpParsingError(status_code=500, detail=msg)

rj.jsonset("exp_config", root, exp_config)
rj.jsonset("responses", root, [])
Expand Down
3 changes: 3 additions & 0 deletions tests/data/bad_exp.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
targets:
- foo
- bar
19 changes: 17 additions & 2 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ def _get(endpoint, URL=URL, status_code=200, **kwargs):
return r


def _post(endpoint, data=None, URL=URL, status_code=200, **kwargs):
def _post(endpoint, data=None, URL=URL, status_code=200, error=False, **kwargs):
# data = data or {}
if isinstance(data, dict) and "exp" not in data:
data = json.dumps(data)
r = requests.post(URL + endpoint, data=data, **kwargs)
assert r.status_code == status_code
if not error:
assert r.status_code == status_code
return r


Expand Down Expand Up @@ -114,3 +115,17 @@ def test_basic():
assert 10e-3 < df.response_time.min()
assert expected_cols == set(df.columns)
assert df.puid.nunique() == 1

def test_bad_file_upload():
username, password = _get_auth()
print(username, password)
_get("/init_exp")
exp = Path(__file__).parent / "data" / "bad_exp.yaml"
r = _post(
"/init_exp", data={"exp": exp.read_bytes()}, auth=(username, password),
error=True,
)
assert r.status_code == 500
assert "Error!" in r.text
assert "yaml" in r.text
assert "-\tfoo" in r.text

0 comments on commit a988a8b

Please sign in to comment.