From 57ba65e60687acb58f3d10c4da5e7152b0021de1 Mon Sep 17 00:00:00 2001 From: gwen Date: Sat, 1 Jul 2023 15:48:00 +0200 Subject: [PATCH] debut de traitement par lots --- actes-princiers/conf/base/catalog.yml | 5 + actes-princiers/conf/base/config.yml | 1 - actes-princiers/conf/base/houses.yml | 3 +- .../notebooks/LoadDataCatalog.ipynb | 154 +++++++++++++++++- .../src/actes_princiers/customcontext.py | 11 +- actes-princiers/src/actesdataset.py | 115 +++++++++++-- 6 files changed, 265 insertions(+), 24 deletions(-) delete mode 100644 actes-princiers/conf/base/config.yml diff --git a/actes-princiers/conf/base/catalog.yml b/actes-princiers/conf/base/catalog.yml index 9f4cd33..8006348 100644 --- a/actes-princiers/conf/base/catalog.yml +++ b/actes-princiers/conf/base/catalog.yml @@ -1,3 +1,8 @@ +xmlreflector: + type: actesdataset.XMLHousesReflector + housename: bourbon + folderpath: data/01_raw/houses/bourbon + actors: type: pandas.CSVDataSet filepath: data/01_raw/csv/actors.csv diff --git a/actes-princiers/conf/base/config.yml b/actes-princiers/conf/base/config.yml deleted file mode 100644 index 2ef5566..0000000 --- a/actes-princiers/conf/base/config.yml +++ /dev/null @@ -1 +0,0 @@ -houses_datapath: data/01_raw/houses diff --git a/actes-princiers/conf/base/houses.yml b/actes-princiers/conf/base/houses.yml index 3671e88..ff362aa 100644 --- a/actes-princiers/conf/base/houses.yml +++ b/actes-princiers/conf/base/houses.yml @@ -1,10 +1,11 @@ +raw_datapath: data/01_raw houses: bourbon: name: Bourbon path: houses/bourbon berry: name: Berry - path: houses/Berry + path: houses/berry anjou: name: Anjou path: houses/anjou diff --git a/actes-princiers/notebooks/LoadDataCatalog.ipynb b/actes-princiers/notebooks/LoadDataCatalog.ipynb index ea08035..eb5998a 100644 --- a/actes-princiers/notebooks/LoadDataCatalog.ipynb +++ b/actes-princiers/notebooks/LoadDataCatalog.ipynb @@ -12,25 +12,169 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 1, "id": "ae9bc24c", "metadata": {}, "outputs": [ { "data": { + "text/html": [ + "
<kedro.io.data_catalog.DataCatalog object at 0x7f2d5be6e740>\n",
+       "
\n" + ], "text/plain": [ - "" + "\u001b[1m<\u001b[0m\u001b[1;95mkedro.io.data_catalog.DataCatalog\u001b[0m\u001b[39m object at \u001b[0m\u001b[1;36m0x7f2d5be6e740\u001b[0m\u001b[1m>\u001b[0m\n" ] }, - "execution_count": 4, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" } ], "source": [ "catalog" ] }, + { + "cell_type": "code", + "execution_count": 1, + "id": "40417f25", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
[06/30/23 17:50:49] INFO     Loading data from 'xmlreflector' (XMLHousesReflector)...           data_catalog.py:345\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[2;36m[06/30/23 17:50:49]\u001b[0m\u001b[2;36m \u001b[0m\u001b[34mINFO \u001b[0m Loading data from \u001b[32m'xmlreflector'\u001b[0m \u001b[1m(\u001b[0mXMLHousesReflector\u001b[1m)\u001b[0m\u001b[33m...\u001b[0m \u001b]8;id=287074;file:///home/gwen/.local/lib/python3.10/site-packages/kedro/io/data_catalog.py\u001b\\\u001b[2mdata_catalog.py\u001b[0m\u001b]8;;\u001b\\\u001b[2m:\u001b[0m\u001b]8;id=134334;file:///home/gwen/.local/lib/python3.10/site-packages/kedro/io/data_catalog.py#345\u001b\\\u001b[2m345\u001b[0m\u001b]8;;\u001b\\\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮\n",
+       " /home/gwen/.local/lib/python3.10/site-packages/kedro/io/core.py:187 in load                      \n",
+       "                                                                                                  \n",
+       "   184 │   │   self._logger.debug(\"Loading %s\", str(self))                                        \n",
+       "   185 │   │                                                                                      \n",
+       "   186 │   │   try:                                                                               \n",
+       " 187 │   │   │   return self._load()                                                            \n",
+       "   188 │   │   except DataSetError:                                                               \n",
+       "   189 │   │   │   raise                                                                          \n",
+       "   190 │   │   except Exception as exc:                                                           \n",
+       "                                                                                                  \n",
+       " /media/gwen/maxtor/gwen/entrepot/cnrs/nicolas/depot/datascience/actes-princiers/src/actesdataset \n",
+       " .py:62 in _load                                                                                  \n",
+       "                                                                                                  \n",
+       "    59 │   │   self.filepath = filepath                                                           \n",
+       "    60 │                                                                                          \n",
+       "    61 │   def _load(self):                                                                       \n",
+       "  62 │   │   raise \"C'est chargé!\"                                                              \n",
+       "    63 │                                                                                          \n",
+       "    64 │   def _save(self):                                                                       \n",
+       "    65 │   │   raise NotImplementedError(\"Attention : dataset en lecture seule !\")                \n",
+       "╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
+       "TypeError: exceptions must derive from BaseException\n",
+       "\n",
+       "The above exception was the direct cause of the following exception:\n",
+       "\n",
+       "╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮\n",
+       " /tmp/ipykernel_28884/4226322454.py:1 in <module>                                                 \n",
+       "                                                                                                  \n",
+       " [Errno 2] No such file or directory: '/tmp/ipykernel_28884/4226322454.py'                        \n",
+       "                                                                                                  \n",
+       " /home/gwen/.local/lib/python3.10/site-packages/kedro/io/data_catalog.py:349 in load              \n",
+       "                                                                                                  \n",
+       "   346 │   │   │   \"Loading data from '%s' (%s)...\", name, type(dataset).__name__                 \n",
+       "   347 │   │   )                                                                                  \n",
+       "   348 │   │                                                                                      \n",
+       " 349 │   │   result = dataset.load()                                                            \n",
+       "   350 │   │                                                                                      \n",
+       "   351 │   │   return result                                                                      \n",
+       "   352                                                                                            \n",
+       "                                                                                                  \n",
+       " /home/gwen/.local/lib/python3.10/site-packages/kedro/io/core.py:196 in load                      \n",
+       "                                                                                                  \n",
+       "   193 │   │   │   message = (                                                                    \n",
+       "   194 │   │   │   │   f\"Failed while loading data from data set {str(self)}.\\n{str(exc)}\"        \n",
+       "   195 │   │   │   )                                                                              \n",
+       " 196 │   │   │   raise DataSetError(message) from exc                                           \n",
+       "   197 │                                                                                          \n",
+       "   198 │   def save(self, data: _DI) -> None:                                                     \n",
+       "   199 │   │   \"\"\"Saves data by delegation to the provided save method.                           \n",
+       "╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
+       "DataSetError: Failed while loading data from data set XMLHousesReflector(name=my own dataset).\n",
+       "exceptions must derive from BaseException\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[31m╭─\u001b[0m\u001b[31m────────────────────────────── \u001b[0m\u001b[1;31mTraceback \u001b[0m\u001b[1;2;31m(most recent call last)\u001b[0m\u001b[31m ───────────────────────────────\u001b[0m\u001b[31m─╮\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2;33m/home/gwen/.local/lib/python3.10/site-packages/kedro/io/\u001b[0m\u001b[1;33mcore.py\u001b[0m:\u001b[94m187\u001b[0m in \u001b[92mload\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m184 \u001b[0m\u001b[2m│ │ \u001b[0m\u001b[96mself\u001b[0m._logger.debug(\u001b[33m\"\u001b[0m\u001b[33mLoading \u001b[0m\u001b[33m%s\u001b[0m\u001b[33m\"\u001b[0m, \u001b[96mstr\u001b[0m(\u001b[96mself\u001b[0m)) \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m185 \u001b[0m\u001b[2m│ │ \u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m186 \u001b[0m\u001b[2m│ │ \u001b[0m\u001b[94mtry\u001b[0m: \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m187 \u001b[2m│ │ │ \u001b[0m\u001b[94mreturn\u001b[0m \u001b[96mself\u001b[0m._load() \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m188 \u001b[0m\u001b[2m│ │ \u001b[0m\u001b[94mexcept\u001b[0m DataSetError: \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m189 \u001b[0m\u001b[2m│ │ │ \u001b[0m\u001b[94mraise\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m190 \u001b[0m\u001b[2m│ │ \u001b[0m\u001b[94mexcept\u001b[0m \u001b[96mException\u001b[0m \u001b[94mas\u001b[0m exc: \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2;33m/media/gwen/maxtor/gwen/entrepot/cnrs/nicolas/depot/datascience/actes-princiers/src/\u001b[0m\u001b[1;33mactesdataset\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[1;33m.py\u001b[0m:\u001b[94m62\u001b[0m in \u001b[92m_load\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m 59 \u001b[0m\u001b[2m│ │ \u001b[0m\u001b[96mself\u001b[0m.filepath = filepath \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m 60 \u001b[0m\u001b[2m│ \u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m 61 \u001b[0m\u001b[2m│ \u001b[0m\u001b[94mdef\u001b[0m \u001b[92m_load\u001b[0m(\u001b[96mself\u001b[0m): \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m 62 \u001b[2m│ │ \u001b[0m\u001b[94mraise\u001b[0m \u001b[33m\"\u001b[0m\u001b[33mC\u001b[0m\u001b[33m'\u001b[0m\u001b[33mest chargé!\u001b[0m\u001b[33m\"\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m 63 \u001b[0m\u001b[2m│ \u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m 64 \u001b[0m\u001b[2m│ \u001b[0m\u001b[94mdef\u001b[0m \u001b[92m_save\u001b[0m(\u001b[96mself\u001b[0m): \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m 65 \u001b[0m\u001b[2m│ │ \u001b[0m\u001b[94mraise\u001b[0m \u001b[96mNotImplementedError\u001b[0m(\u001b[33m\"\u001b[0m\u001b[33mAttention : dataset en lecture seule !\u001b[0m\u001b[33m\"\u001b[0m) \u001b[31m│\u001b[0m\n", + "\u001b[31m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n", + "\u001b[1;91mTypeError: \u001b[0mexceptions must derive from BaseException\n", + "\n", + "\u001b[3mThe above exception was the direct cause of the following exception:\u001b[0m\n", + "\n", + "\u001b[31m╭─\u001b[0m\u001b[31m────────────────────────────── \u001b[0m\u001b[1;31mTraceback \u001b[0m\u001b[1;2;31m(most recent call last)\u001b[0m\u001b[31m ───────────────────────────────\u001b[0m\u001b[31m─╮\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2;33m/tmp/ipykernel_28884/\u001b[0m\u001b[1;33m4226322454.py\u001b[0m:\u001b[94m1\u001b[0m in \u001b[92m\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[3;31m[Errno 2] No such file or directory: '/tmp/ipykernel_28884/4226322454.py'\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2;33m/home/gwen/.local/lib/python3.10/site-packages/kedro/io/\u001b[0m\u001b[1;33mdata_catalog.py\u001b[0m:\u001b[94m349\u001b[0m in \u001b[92mload\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m346 \u001b[0m\u001b[2m│ │ │ \u001b[0m\u001b[33m\"\u001b[0m\u001b[33mLoading data from \u001b[0m\u001b[33m'\u001b[0m\u001b[33m%s\u001b[0m\u001b[33m'\u001b[0m\u001b[33m (\u001b[0m\u001b[33m%s\u001b[0m\u001b[33m)...\u001b[0m\u001b[33m\"\u001b[0m, name, \u001b[96mtype\u001b[0m(dataset).\u001b[91m__name__\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m347 \u001b[0m\u001b[2m│ │ \u001b[0m) \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m348 \u001b[0m\u001b[2m│ │ \u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m349 \u001b[2m│ │ \u001b[0mresult = dataset.load() \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m350 \u001b[0m\u001b[2m│ │ \u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m351 \u001b[0m\u001b[2m│ │ \u001b[0m\u001b[94mreturn\u001b[0m result \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m352 \u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2;33m/home/gwen/.local/lib/python3.10/site-packages/kedro/io/\u001b[0m\u001b[1;33mcore.py\u001b[0m:\u001b[94m196\u001b[0m in \u001b[92mload\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m193 \u001b[0m\u001b[2m│ │ │ \u001b[0mmessage = ( \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m194 \u001b[0m\u001b[2m│ │ │ │ \u001b[0m\u001b[33mf\u001b[0m\u001b[33m\"\u001b[0m\u001b[33mFailed while loading data from data set \u001b[0m\u001b[33m{\u001b[0m\u001b[96mstr\u001b[0m(\u001b[96mself\u001b[0m)\u001b[33m}\u001b[0m\u001b[33m.\u001b[0m\u001b[33m\\n\u001b[0m\u001b[33m{\u001b[0m\u001b[96mstr\u001b[0m(exc)\u001b[33m}\u001b[0m\u001b[33m\"\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m195 \u001b[0m\u001b[2m│ │ │ \u001b[0m) \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m196 \u001b[2m│ │ │ \u001b[0m\u001b[94mraise\u001b[0m DataSetError(message) \u001b[94mfrom\u001b[0m \u001b[4;96mexc\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m197 \u001b[0m\u001b[2m│ \u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m198 \u001b[0m\u001b[2m│ \u001b[0m\u001b[94mdef\u001b[0m \u001b[92msave\u001b[0m(\u001b[96mself\u001b[0m, data: _DI) -> \u001b[94mNone\u001b[0m: \u001b[31m│\u001b[0m\n", + "\u001b[31m│\u001b[0m \u001b[2m199 \u001b[0m\u001b[2m│ │ \u001b[0m\u001b[33m\"\"\"Saves data by delegation to the provided save method.\u001b[0m \u001b[31m│\u001b[0m\n", + "\u001b[31m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n", + "\u001b[1;91mDataSetError: \u001b[0mFailed while loading data from data set \u001b[1;35mXMLHousesReflector\u001b[0m\u001b[1m(\u001b[0m\u001b[33mname\u001b[0m=\u001b[35mmy\u001b[0m own dataset\u001b[1m)\u001b[0m.\n", + "exceptions must derive from BaseException\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "catalog.load(\"xmlreflector\")" + ] + }, { "cell_type": "code", "execution_count": 38, @@ -453,7 +597,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.2" + "version": "3.10.6" } }, "nbformat": 4, diff --git a/actes-princiers/src/actes_princiers/customcontext.py b/actes-princiers/src/actes_princiers/customcontext.py index 852435d..c75b341 100644 --- a/actes-princiers/src/actes_princiers/customcontext.py +++ b/actes-princiers/src/actes_princiers/customcontext.py @@ -6,6 +6,8 @@ from kedro.framework.context import KedroContext from kedro.pipeline import Pipeline, node, pipeline from actesdataset import XMLDataSet + +# FIXME : move in an utils.py module def tree(directory, relative_to=None): "helper that returns a directory tree structure" trees = dict() @@ -22,14 +24,13 @@ class ProjectContext(KedroContext): def get_houses(self): """loading from generic configuration file (that is, the global houses `houses.yaml`)""" - houses_file = self.config_loader.get("houses*") - return houses_file['houses'] + houses = self.config_loader.get("houses*") + return houses['houses'] def get_houses_datapath(self): """loading from generic configuration file""" - config = self.config_loader.get("config*") - return config['houses_datapath'] - + houses = self.config_loader.get("houses*") + return houses['raw_datapath'] def _get_catalog(self, *args, **kwargs): "catalog loader entry point" diff --git a/actes-princiers/src/actesdataset.py b/actes-princiers/src/actesdataset.py index 6b0eb16..9448287 100644 --- a/actes-princiers/src/actesdataset.py +++ b/actes-princiers/src/actesdataset.py @@ -5,6 +5,8 @@ from lxml import etree from kedro.io import AbstractDataSet, DataSetError + +# FIXME: supprimer l'héritage class XMLDataSet(AbstractDataSet): "lxml.etree._ElementTree loader" # FIXME set the typing signature !!!! @@ -23,24 +25,113 @@ class XMLDataSet(AbstractDataSet): return source_doc def _save(self, data:str) -> None: -# raise NotImplementedError("pas encore implemente !!!!") with open(self._filepath, 'w') as fhandle: fhandle.write(data) def _describe(self) -> Dict[str, Any]: return dict(filepath=self._filepath) -class JSONDataSet(AbstractDataSet): - def __init__(self, filepath: str): - self._filepath = filepath +class XMLHousesReflector(AbstractDataSet): + """``XMLHousesReflector`` stores instances of ``XMLDataSet`` + implementations to provide ``load`` and ``save`` capabilities. + anywhere in the program. To use a ``DataCatalog``, you need to + instantiate it with a file system folder path, it "reflects" + this file system of XML files. + It loads a dictionary of XML data sets. + + Args: + data_sets: A dictionary of data set names and data set instances. - def _load(self) -> Dict: - with open(self._filepath, 'r') as f: - return json.load(f) + Example:: - def _save(self, data: Dict) -> None: - with open(self._filepath, 'w') as f: - json.dump(data, f) + >>> from .actesdatasets import XMLDataSet, XMLCatalogReflector + >>> + >>> cars = XMLDataSet(filepath="cars.xml") + >>> io = XMLCatalogReflector(housename='bourbon', folderpath='/tmp/mydir', data_sets={'cars': cars}) +# filepath, load_args=None, save_args=None): + """ + def __init__(self, + housename: str, + folderpath: str, + data_sets: dict[str, XMLDataSet] = None): + self._housename = housename + self._folderpath = folderpath + self._datasets = data_sets +# self.filepath = filepath - def _describe(self) -> Dict[str, Any]: - return dict(filepath=self._filepath) + def _load(self): + return "C'est chargé!" + + def _save(self): + raise NotImplementedError("Attention : dataset en lecture seule !") + + def _exists(self) -> bool: + return True + + def _describe(self): + return dict(name="my own dataset") + +# def load(self, name: str) -> Any: +# """Loads a registered data set. + +# Args: +# name: A data set to be loaded. +# version: Optional argument for concrete data version to be loaded. +# Works only with versioned datasets. + +# Returns: +# The loaded data as configured. +# """ +# return result +# +## def save(self, name: str, data: Any) -> None: +## """Save data to a registered data set. + +## Args: +## name: A data set to be saved to. +## data: A data object to be saved as configured in the registered +## data set. + +## Raises: +## DatasetNotFoundError: When a data set with the given name +## has not yet been registered. + +## Example: +## :: + +## >>> import pandas as pd +## >>> +## >>> from kedro.extras.datasets.pandas import CSVDataSet +## >>> +## >>> cars = CSVDataSet(filepath="cars.csv", +## >>> load_args=None, +## >>> save_args={"index": False}) +## >>> io = DataCatalog(data_sets={'cars': cars}) +## >>> +## >>> df = pd.DataFrame({'col1': [1, 2], +## >>> 'col2': [4, 5], +## >>> 'col3': [5, 6]}) +## >>> io.save("cars", df) +## """ +## dataset = self._get_dataset(name) +### self._logger.info("Saving data to '%s' (%s)...", name, type(dataset).__name__) +## dataset.save(data) + +# def _describe(self) -> Dict[str, Any]: +# return dict(filepath=self._housename) + + +#class JSONDataSet(AbstractDataSet): +# def __init__(self, filepath: str): +# self._filepath = filepath + +# def _load(self) -> Dict: +# with open(self._filepath, 'r') as fp: +# return json.load(fp) + +# def _save(self, data: Dict) -> None: +# with open(self._filepath, 'w') as fp: +# json.dump(data, fp, sort_keys=True, indent=4) + +# def _describe(self) -> Dict[str, Any]: +# return dict(filepath=self._filepath)