Repository: dcs4cop/xcube
Issue: Determine correct filename extension

If you use the directory store to write a dataset (store.write_data(dataset)), it will be saved with a '.levels'-extension. This is because the filename extension is incorrectly determined.

Changed files:
test/core/store/stores/test_directory.py, xcube/core/store/stores/directory.py

diff --git a/test/core/store/stores/test_directory.py b/test/core/store/stores/test_directory.py
index 90213e41..ea2fe49d 100644
--- a/test/core/store/stores/test_directory.py
+++ b/test/core/store/stores/test_directory.py
@@ -60,18 +60,6 @@ class DirectoryDataStoreTest(unittest.TestCase):
         self.assertEqual({}, schema.properties)
         self.assertEqual(False, schema.additional_properties)
 
-    def test_search_data(self):
-        result = list(self.store.search_data(type_specifier=TYPE_SPECIFIER_CUBE))
-        self.assertTrue(len(result) > 0)
-
-        result = list(self.store.search_data(type_specifier=TYPE_SPECIFIER_DATASET))
-        self.assertTrue(len(result) > 0)
-
-        with self.assertRaises(DataStoreError) as cm:
-            list(self.store.search_data(type_specifier=TYPE_SPECIFIER_DATASET,
-                                        time_range=['2020-03-01', '2020-03-04'], bbox=[52, 11, 54, 12]))
-        self.assertEqual('Unsupported search parameters: time_range, bbox', f'{cm.exception}')
-
     def test_get_write_data_params_schema(self):
         schema = self.store.get_write_data_params_schema()
         self.assertEqual(
@@ -224,10 +212,10 @@ class DirectoryDataStoreTest(unittest.TestCase):
         with self.assertRaises(DataStoreError) as cm:
             set(self.store.describe_data('cube-1-250-250.zarr', type_specifier='geodataframe'))
         self.assertEqual(
-            'Type specifier "geodataframe" cannot be satisfied by type specifier "dataset" of data resource "cube-1-250-250.zarr"',
-            f'{cm.exception}')
+            'Type specifier "geodataframe" cannot be satisfied by type specifier "dataset" '
+            'of data resource "cube-1-250-250.zarr"', f'{cm.exception}')
 
-    def test_search_data(self):
+    def test_search_data_search(self):
         result = list(self.store.search_data())
         self.assertEqual(3, len(result))
         self.assertEqual(result[0].data_id, 'cube-1-250-250.zarr')
@@ -257,3 +245,23 @@ class DirectoryDataStoreTest(unittest.TestCase):
 
         result = list(self.store.search_data(type_specifier='geodataframe'))
         self.assertEqual(0, len(result))
+
+        with self.assertRaises(DataStoreError) as cm:
+            list(self.store.search_data(type_specifier=TYPE_SPECIFIER_DATASET,
+                                        time_range=['2020-03-01', '2020-03-04'], bbox=[52, 11, 54, 12]))
+        self.assertEqual('Unsupported search parameters: time_range, bbox', f'{cm.exception}')
+
+    def test_get_filename_ext(self):
+        import xarray as xr
+        import geopandas as gpd
+        from xcube.core.mldataset import BaseMultiLevelDataset
+
+        dataset = xr.Dataset()
+        self.assertEqual('.zarr', self.store._get_filename_ext(dataset))
+        frame = gpd.GeoDataFrame()
+        self.assertEqual('.geojson', self.store._get_filename_ext(frame))
+        mldataset = BaseMultiLevelDataset(base_dataset=dataset)
+        self.assertEqual('.levels', self.store._get_filename_ext(mldataset))
+
+        self.assertIsNone(self.store._get_filename_ext(None))
+        self.assertIsNone(self.store._get_filename_ext(DataStoreError('A nonsense object')))
diff --git a/xcube/core/store/stores/directory.py b/xcube/core/store/stores/directory.py
index 972e55cb..c7f96e61 100644
--- a/xcube/core/store/stores/directory.py
+++ b/xcube/core/store/stores/directory.py
@@ -321,8 +321,10 @@ class DirectoryDataStore(DefaultSearchMixin, MutableDataStore):
     @classmethod
     def _get_filename_ext(cls, data: Any) -> Optional[str]:
         type_specifier = get_type_specifier(data)
-        if TYPE_SPECIFIER_MULTILEVEL_DATASET.satisfies(type_specifier):
+        if type_specifier is None:
+            return None
+        if TYPE_SPECIFIER_MULTILEVEL_DATASET.is_satisfied_by(type_specifier):
             return '.levels'
-        if TYPE_SPECIFIER_GEODATAFRAME.satisfies(type_specifier):
+        if TYPE_SPECIFIER_GEODATAFRAME.is_satisfied_by(type_specifier):
             return '.geojson'
         return '.zarr'