diff --git a/client/src/actions/index.js b/client/src/actions/index.js index d9a77420..a829b45b 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -58,7 +58,7 @@ const doInitialDataLoad = () => dispatch({ type: "initial data load start" }); try { - const [, schema] = await Promise.all([ + const [config, schema] = await Promise.all([ configFetch(dispatch), schemaFetch(dispatch), userColorsFetchAndLoad(dispatch), @@ -75,6 +75,15 @@ const doInitialDataLoad = () => obsCrossfilter, }); dispatch({ type: "initial data load complete" }); + + const defaultEmbedding = config?.parameters?.["default_embedding"]; + const layoutSchema = schema?.schema?.layout?.obs ?? []; + if ( + defaultEmbedding && + layoutSchema.some((s) => s.name === defaultEmbedding) + ) { + dispatch(embActions.layoutChoiceAction(defaultEmbedding)); + } } catch (error) { dispatch({ type: "initial data load error", error }); } diff --git a/server/common/app_config.py b/server/common/app_config.py index da2f6463..ebca5f7f 100644 --- a/server/common/app_config.py +++ b/server/common/app_config.py @@ -242,11 +242,17 @@ class AppConfig(object): "about_legal_privacy": dataset_config.app__about_legal_privacy, } - # dataset_props + # corpora dataset_props # TODO/Note: putting info from the dataset into the /config is not ideal. # However, it is definitely not part of /schema, and we do not have a top-level # route for data properties. Consider creating one at some point. corpora_props = data_adaptor.get_corpora_props() + if corpora_props and "default_embedding" in corpora_props: + default_embedding = corpora_props["default_embedding"] + if isinstance(default_embedding, str) and default_embedding.startswith("X_"): + default_embedding = default_embedding[2:] # drop X_ prefix + if default_embedding in data_adaptor.get_embedding_names(): + parameters["default_embedding"] = default_embedding data_adaptor.update_parameters(parameters) if annotation: diff --git a/server/test/test_corpora.py b/server/test/test_corpora.py index b0637706..f502244c 100644 --- a/server/test/test_corpora.py +++ b/server/test/test_corpora.py @@ -1,13 +1,19 @@ import unittest import anndata import json +import tempfile +import shutil +from http import HTTPStatus +import requests from server.common.corpora import ( corpora_get_versions_from_anndata, corpora_is_version_supported, corpora_get_props_from_anndata, ) -from server.test import PROJECT_ROOT +from server.test import PROJECT_ROOT, start_test_server, stop_test_server + +VERSION = "v0.2" class CorporaAPITest(unittest.TestCase): @@ -71,3 +77,70 @@ class CorporaAPITest(unittest.TestCase): def _get_h5ad(self): return anndata.read_h5ad(f"{PROJECT_ROOT}/example-dataset/pbmc3k.h5ad") + + +class CorporaRESTAPITest(unittest.TestCase): + """ Confirm endpoints reflect Corpora-specific features """ + + @classmethod + def setCorporaFields(cls, path): + adata = anndata.read_h5ad(path) + corpora_props = { + "version": { + "corpora_schema_version": "1.0.0", + "corpora_encoding_version": "0.1.0" + }, + "title": "PBMC3K", + "contributors": json.dumps([ + {"name": "name"} + ]), + "layer_descriptions": { + "X": "raw counts" + }, + "organism": "human", + "organism_ontology_term_id": "unknown", + "project_name": "test project", + "project_description": "test description", + "project_links": json.dumps([ + {"link_name": "test link", "link_type": "SUMMARY", "link_url": "https://a.u.r.l/"} + ]), + "default_embedding": "X_tsne" + } + adata.uns.update(corpora_props) + adata.write(path) + + @classmethod + def setUpClass(cls): + cls.tmp_dir = tempfile.TemporaryDirectory() + src = f"{PROJECT_ROOT}/example-dataset/pbmc3k.h5ad" + dst = f"{cls.tmp_dir.name}/pbmc3k.h5ad" + shutil.copyfile(src, dst) + cls.setCorporaFields(dst) + cls.ps, cls.server = start_test_server([dst]) + + @classmethod + def tearDownClass(cls): + stop_test_server(cls.ps) + cls.tmp_dir.cleanup() + + def setUp(self): + self.session = requests.Session() + self.url_base = f"{self.server}/api/{VERSION}/" + + def test_config(self): + endpoint = "config" + url = f"{self.url_base}{endpoint}" + result = self.session.get(url) + self.assertEqual(result.status_code, HTTPStatus.OK) + self.assertEqual(result.headers["Content-Type"], "application/json") + + result_data = result.json() + self.assertIsInstance(result_data["config"]["corpora_props"], dict) + self.assertIsInstance(result_data["config"]["parameters"], dict) + + corpora_props = result_data["config"]["corpora_props"] + parameters = result_data["config"]["parameters"] + + self.assertEqual(corpora_props["version"]["corpora_schema_version"], "1.0.0") + self.assertEqual(corpora_props["organism"], "human") + self.assertEqual(parameters["default_embedding"], "tsne")