Fix bug that occurs when all categories are removed. (#1974)

Previously if the user remove all annotations, the code would still generate a tiledb uri
in the write_labels call, and add that to the database.  A tiledb array would not be written in this case.
When the read_labels was then called, it would find the entry in the database, attempt to open
the tiledb array, then fail.

The patch here will set the tiledb_uri to the empty string if all categories are removed.
When read_labels is called, it will see the empty uri and return None.
Furthermore, if the database does have a tiledb_uri that does not exist, or cannot be read,
then the code will now log a warning, and return None (instead of throwing an exception,
which results in a server error).

 #1932
This commit is contained in:
bmccandless
2020-11-06 18:04:14 -08:00
committed by GitHub
parent e892e64685
commit 23714bc9f8
2 changed files with 45 additions and 21 deletions
@@ -2,7 +2,7 @@ import json
import shutil
import unittest
from os import path, listdir
from unittest.mock import MagicMock, patch
from unittest.mock import MagicMock
import numpy as np
import pandas as pd
@@ -129,20 +129,34 @@ class WritableTileDBStoredAnnotationTest(unittest.TestCase):
with self.assertRaises(KeyError):
self.annotation_put_fbs(fbs_bad)
@patch("server.common.annotations.hosted_tiledb.AnnotationsHostedTileDB.get_user_id")
@patch("server.common.annotations.hosted_tiledb.AnnotationsHostedTileDB.get_user_name")
def test_write_labels_stores_df_as_tiledb_array(self, mock_user_name, mock_user_id):
mock_user_id.return_value = "1234"
mock_user_name.return_value = "user1234"
self.annotations.write_labels(self.df, self.data)
# get uri
dataset_id = self.db.query([CellxGeneDataset], [CellxGeneDataset.name == self.data.get_location()])[0].id
annotation = self.db.query_for_most_recent(
Annotation, [Annotation.user_id == "1234", Annotation.dataset_id == str(dataset_id)]
)
def test_write_labels_stores_df_as_tiledb_array(self):
with self.app.test_request_context():
self.annotations.write_labels(self.df, self.data)
# get uri
dataset_id = self.db.query([CellxGeneDataset], [CellxGeneDataset.name == self.data.get_location()])[0].id
annotation = self.db.query_for_most_recent(
Annotation, [Annotation.user_id == "1234", Annotation.dataset_id == str(dataset_id)]
)
df = tiledb.open(annotation.tiledb_uri)
self.assertEqual(type(df), tiledb.array.SparseArray)
df = tiledb.open(annotation.tiledb_uri)
self.assertEqual(type(df), tiledb.array.SparseArray)
def test_remove_categories(self):
with self.app.test_request_context():
# update empty category data, which is how annotations are removed
empty = make_fbs({})
self.annotation_put_fbs(empty)
# verify that the tiledb uri is an empty string.
dataset_id = self.db.query([CellxGeneDataset], [CellxGeneDataset.name == self.data.get_location()])[0].id
annotation = self.db.query_for_most_recent(
Annotation, [Annotation.user_id == self.user_id, Annotation.dataset_id == str(dataset_id)]
)
self.assertEqual(annotation.tiledb_uri, "")
# verify that read_labels returns None
df = self.annotations.read_labels(self.data)
self.assertIsNone(df)
class WritableAnnotationTest(unittest.TestCase):