Add caching back in (#312)

* Add caching back in

Works now against filter instead of dataframe view

* Layout cache and move post->put

* Fix tests
This commit is contained in:
Charlotte Weaver
2018-10-11 16:29:46 -07:00
parent b90292ce4c
commit 3229babd14
4 changed files with 47 additions and 27 deletions
+1 -1
View File
@@ -461,7 +461,7 @@ Get the _default_ layout for all observations or (_future_) all variables. Retur
} }
``` ```
### POST /layout/obs, (_future_) POST /layout/var ### PUT /layout/obs, (_future_) PUT /layout/var
Generate layout for the caller-specified subset of data, as indicated by the filter. This operation implicitly requests a re-layout operation to be performed on the specified data. Generate layout for the caller-specified subset of data, as indicated by the filter. This operation implicitly requests a re-layout operation to be performed on the specified data.
+5 -10
View File
@@ -670,17 +670,12 @@ class LayoutObsAPI(Resource):
}, },
} }
}) })
def post(self): def put(self):
try: try:
return make_response( filter = request.get_json()["filter"]
jsonify({ interactive_limit = current_app.data.features["layout"]["obs"]["interactiveLimit"]
"layout": current_app.data.layout( layout = current_app.data.layout(filter, interactive_limit=interactive_limit)
request.get_json()["filter"], return make_response(jsonify({"layout": layout}), HTTPStatus.OK)
interactive_limit=current_app.data.features["layout"]["obs"]["interactiveLimit"]
)
}),
HTTPStatus.OK
)
except FilterError as e: except FilterError as e:
return make_response(e.message, HTTPStatus.BAD_REQUEST) return make_response(e.message, HTTPStatus.BAD_REQUEST)
except InteractiveError: except InteractiveError:
+4 -6
View File
@@ -6,8 +6,7 @@ from pandas import DataFrame, Series
import scanpy.api as sc import scanpy.api as sc
from scipy import stats from scipy import stats
# TODO fix memoization so that it correctly identifies the same request from server.app.app import cache
# from server.app.app import cache
from server.app.driver.driver import CXGDriver from server.app.driver.driver import CXGDriver
from server.app.util.constants import Axis, DEFAULT_TOP_N, DiffExpMode from server.app.util.constants import Axis, DEFAULT_TOP_N, DiffExpMode
from server.app.util.utils import FilterError, InteractiveError from server.app.util.utils import FilterError, InteractiveError
@@ -201,7 +200,7 @@ class ScanpyEngine(CXGDriver):
index = np.logical_and(index, key_idx) index = np.logical_and(index, key_idx)
return index return index
# @cache.memoize() @cache.memoize()
def annotation(self, filter, axis, fields=None): def annotation(self, filter, axis, fields=None):
""" """
Gets annotation value for each observation Gets annotation value for each observation
@@ -224,7 +223,7 @@ class ScanpyEngine(CXGDriver):
"data": annotations.reset_index().values.tolist() "data": annotations.reset_index().values.tolist()
} }
# @cache.memoize() @cache.memoize()
def data_frame(self, filter, axis): def data_frame(self, filter, axis):
""" """
Retrieves data for each variable for observations in data frame Retrieves data for each variable for observations in data frame
@@ -261,7 +260,6 @@ class ScanpyEngine(CXGDriver):
} }
return result return result
# @cache.memoize()
def diffexp(self, filter1, filter2, top_n=None, interactive_limit=None): def diffexp(self, filter1, filter2, top_n=None, interactive_limit=None):
""" """
Computes the top differentially expressed variables between two observation sets. If dataframes Computes the top differentially expressed variables between two observation sets. If dataframes
@@ -321,7 +319,7 @@ class ScanpyEngine(CXGDriver):
# Results need to be returned in var index order # Results need to be returned in var index order
return sorted(result, key=lambda gene: gene[0]) return sorted(result, key=lambda gene: gene[0])
# @cache.memoize() @cache.memoize()
def layout(self, filter, interactive_limit=None): def layout(self, filter, interactive_limit=None):
""" """
Computes a n-d layout for cells through dimensionality reduction. Computes a n-d layout for cells through dimensionality reduction.
+37 -10
View File
@@ -84,22 +84,16 @@ class EndPoints(unittest.TestCase):
} }
} }
} }
result = self.session.post(url, json=obs_filter) result = self.session.put(url, json=obs_filter)
self.assertEqual(result.status_code, HTTPStatus.OK) self.assertEqual(result.status_code, HTTPStatus.OK)
result_data = result.json() result_data = result.json()
self.assertEqual(len(result_data["layout"]["coordinates"]), 15) self.assertEqual(len(result_data["layout"]["coordinates"]), 15)
def test_bad_filter(self): def test_bad_filter(self):
endpoints = { endpoints = ["layout/obs", "annotations/obs", "annotations/var", "data/obs", "data/var"]
"layout/obs": "post", for endpoint in endpoints:
"annotations/obs": "put",
"annotations/var": "put",
"data/obs": "put",
"data/var": "put"
}
for endpoint, method in endpoints.items():
url = f"{URL_BASE}{endpoint}" url = f"{URL_BASE}{endpoint}"
result = getattr(self.session, method)(url, json=BAD_FILTER) result = self.session.put(url, json=BAD_FILTER)
self.assertEqual(result.status_code, HTTPStatus.BAD_REQUEST) self.assertEqual(result.status_code, HTTPStatus.BAD_REQUEST)
def test_get_annotations_obs(self): def test_get_annotations_obs(self):
@@ -373,6 +367,39 @@ class EndPoints(unittest.TestCase):
self.assertEqual(len(result_data["obs"]), 2638) self.assertEqual(len(result_data["obs"]), 2638)
self.assertEqual(len(result_data["var"][0]), 2639) self.assertEqual(len(result_data["var"][0]), 2639)
def test_cache(self):
endpoint = "annotations/var"
url = f"{URL_BASE}{endpoint}"
f1 = {"filter": {"var": {"annotation_value": [{"name": "name",
"values": ["HLA-DRB1", "HLA-DQA1", "HLA-DQB1", "HLA-DPA1",
"HLA-DPB1", "MS4A1", "IL32", "CCL5", "CD79B",
"CD79A"]}]}}}
result = self.session.put(url, json=f1)
self.assertEqual(result.status_code, HTTPStatus.OK)
result_data1 = result.json()
f2 = {"filter": {"var": {"annotation_value": [{"name": "name",
"values": ["FGFBP2", "GZMA", "LTB", "PRF1", "CTSW", "GZMH",
"CCL5", "CCL4", "CST7", "NKG7"]}]}}}
result = self.session.put(url, json=f2)
self.assertEqual(result.status_code, HTTPStatus.OK)
result_data2 = result.json()
self.assertNotEqual(result_data1, result_data2)
def test_cache_nofilter(self):
endpoint = "annotations/var"
url = f"{URL_BASE}{endpoint}"
f1 = {"filter": {}}
result = self.session.put(url, json=f1)
self.assertEqual(result.status_code, HTTPStatus.OK)
result_data1 = result.json()
f2 = {"filter": {"var": {"annotation_value": [{"name": "name",
"values": ["FGFBP2", "GZMA", "LTB", "PRF1", "CTSW", "GZMH",
"CCL5", "CCL4", "CST7", "NKG7"]}]}}}
result = self.session.put(url, json=f2)
self.assertEqual(result.status_code, HTTPStatus.OK)
result_data2 = result.json()
self.assertNotEqual(result_data1, result_data2)
def test_static(self): def test_static(self):
endpoint = "static" endpoint = "static"
file = "js/service-worker.js" file = "js/service-worker.js"