diff --git a/server/dive_server/crud.py b/server/dive_server/crud.py index c9beef6fe..6c69a22e5 100644 --- a/server/dive_server/crud.py +++ b/server/dive_server/crud.py @@ -139,12 +139,11 @@ def get_data_by_type( raise RestException('No array-type json objects are supported') if kwcoco.is_coco_json(data_dict): as_type = FileType.COCO_JSON + elif models.MetadataMutable.is_dive_configuration(data_dict): + data_dict = models.MetadataMutable(**data_dict).dict(exclude_none=True) + as_type = FileType.DIVE_CONF else: - try: - data_dict = models.MetadataMutable(**data_dict).dict(exclude_none=True) - as_type = FileType.DIVE_CONF - except pydantic.ValidationError: - as_type = FileType.DIVE_JSON + as_type = FileType.DIVE_JSON else: raise RestException('Got file of unknown and unusable type') diff --git a/server/dive_utils/models.py b/server/dive_utils/models.py index 0fd636fd5..32b189987 100644 --- a/server/dive_utils/models.py +++ b/server/dive_utils/models.py @@ -95,6 +95,19 @@ class MetadataMutable(BaseModel): confidenceFilters: Optional[Dict[str, float]] attributes: Optional[Dict[str, Attribute]] + @staticmethod + def is_dive_configuration(value: dict): + """ + Check if value is a configuration file if at lease one of the config options is populated + """ + keys = list(MetadataMutable.schema()['properties'].keys()) + + # Remove version: its appearance is not enough to indicate that + # the value is actually a configuration object. + keys.remove("version") + + return any([value.get(key, False) for key in keys]) + class GirderMetadataStatic(MetadataMutable): # Required diff --git a/server/tests/integration/test_dataset_download.py b/server/tests/integration/test_dataset_download.py index 6758642b1..545e5e81c 100644 --- a/server/tests/integration/test_dataset_download.py +++ b/server/tests/integration/test_dataset_download.py @@ -36,3 +36,25 @@ def test_download_csv(user: dict): if not row.startswith('#'): track_set.add(row.split(',')[0]) assert len(track_set) == expected[0]['trackCount'] + + +@pytest.mark.integration +@pytest.mark.parametrize("user", users.values()) +@pytest.mark.run(order=7) +def test_upload_json_detections(user: dict): + """ + Upload new annotations, and verify that the existing annotations change. + This test cleans up after itself, and does not change the state of the system + for future tests + """ + client = getClient(user['login']) + privateFolder = getTestFolder(client) + for dataset in client.listFolder(privateFolder['_id']): + old_tracks = client.get(f'dive_annotation?folderId={dataset["_id"]}') + newfile = client.uploadFileToFolder(dataset['_id'], '../testutils/tracks.json') + client.post(f'dive_rpc/postprocess/{dataset["_id"]}', data={"skipJobs": True}) + new_tracks = client.get(f'dive_annotation?folderId={dataset["_id"]}') + assert '999999' not in old_tracks, "Tracks should have updated" + assert '999999' in new_tracks, "Should have one track, 999999" + assert len(new_tracks.keys()) == 1, "Should have a single track" + client.delete(f'item/{newfile["itemId"]}') # Remove the uploaded detections diff --git a/testutils/tracks.json b/testutils/tracks.json new file mode 100644 index 000000000..eb1de7e4c --- /dev/null +++ b/testutils/tracks.json @@ -0,0 +1 @@ +{"999999": {"begin": 0, "end": 0, "trackId": 0, "features": [{"frame": 0, "bounds": [670, 183, 968, 433], "interpolate": false, "keyframe": true}], "confidencePairs": [["motion_signature", 0.996269]], "attributes": {}}}