Skip to content

Commit

Permalink
Make JSONConnector fail gracefully
Browse files Browse the repository at this point in the history
JSONConnector.file_iterator() now properly raises a ConnectorError
when it cannot read the input file.
  • Loading branch information
soininen committed Jan 10, 2025
1 parent 430b403 commit bf45766
Show file tree
Hide file tree
Showing 8 changed files with 32 additions and 36 deletions.
5 changes: 1 addition & 4 deletions spinedb_api/spine_io/importers/csv_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@
# this program. If not, see <http://www.gnu.org/licenses/>.
######################################################################################################################

"""
Contains CSVConnector class and a help function.
"""
""" Contains CSVConnector class and a help function. """


import csv
Expand Down
5 changes: 1 addition & 4 deletions spinedb_api/spine_io/importers/datapackage_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@
# this program. If not, see <http://www.gnu.org/licenses/>.
######################################################################################################################

"""
Contains DataPackageConnector class.
"""
""" Contains DataPackageConnector class. """
from itertools import chain
import threading
from datapackage import Package
Expand Down
5 changes: 1 addition & 4 deletions spinedb_api/spine_io/importers/excel_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@
# this program. If not, see <http://www.gnu.org/licenses/>.
######################################################################################################################

"""
Contains ExcelConnector class and a help function.
"""
""" Contains ExcelConnector class and a help function. """

import io
from itertools import chain, islice, takewhile
Expand Down
4 changes: 2 additions & 2 deletions spinedb_api/spine_io/importers/gdx_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
""" Contains GDXConnector class and a help function. """

from gdx2py import GAMSParameter, GAMSScalar, GAMSSet, GdxFile
from spinedb_api import SpineDBAPIError
from spinedb_api.exception import ConnectorError
from ..gdx_utils import find_gams_directory
from .reader import SourceConnection

Expand Down Expand Up @@ -100,7 +100,7 @@ def get_data_iterator(self, table, options, max_rows=-1):
return iter([]), []
symbol = self._gdx_file[table]
if symbol is None:
raise SpineDBAPIError(f"the type of '{table}' is not supported.")
raise ConnectorError(f"the type of '{table}' is not supported.")
if isinstance(symbol, GAMSScalar):
return iter([[float(symbol)]]), ["Value"]
domains = symbol.domain if symbol.domain is not None else symbol.dimension * [None]
Expand Down
22 changes: 12 additions & 10 deletions spinedb_api/spine_io/importers/json_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@
# this program. If not, see <http://www.gnu.org/licenses/>.
######################################################################################################################

"""
Contains JSONConnector class.
"""
""" Contains JSONConnector class. """

import os
import sys
import ijson
from ijson import IncompleteJSONError
from ...exception import ConnectorError
from .reader import SourceConnection


Expand Down Expand Up @@ -66,12 +65,15 @@ def file_iterator(self, table, options, max_rows=-1):
prefix = ".".join(table.split(".")[1:])
with open(self._filename, "rb") as f:
row = 0
for obj in ijson.items(f, prefix):
for x in _tabulize_json(obj):
if row > max_rows:
return
yield x[:max_depth]
row += 1
try:
for obj in ijson.items(f, prefix):
for x in _tabulize_json(obj):
if row > max_rows:
return
yield x[:max_depth]
row += 1
except IncompleteJSONError as error:
raise ConnectorError(f"failed to read JSON: {error}") from error

def get_data_iterator(self, table, options, max_rows=-1):
"""
Expand Down
5 changes: 1 addition & 4 deletions spinedb_api/spine_io/importers/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@
# this program. If not, see <http://www.gnu.org/licenses/>.
######################################################################################################################

"""
Contains a class template for a data source connector used in import ui.
"""
""" Contains a class template for a data source connector used in import ui. """

from itertools import islice
from spinedb_api import DateTime, Duration, ParameterValueFormatError
Expand Down
5 changes: 1 addition & 4 deletions tests/spine_io/importers/test_GdxConnector.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@
# this program. If not, see <http://www.gnu.org/licenses/>.
######################################################################################################################

"""
Unit tests for GDXConnector class.
"""
""" Unit tests for GDXConnector class. """

import os.path
import pickle
Expand Down
17 changes: 13 additions & 4 deletions tests/spine_io/importers/test_json_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@
# this program. If not, see <http://www.gnu.org/licenses/>.
######################################################################################################################

"""
Contains unit tests for JSONConnector.
"""
""" Contains unit tests for JSONConnector. """
import json
from pathlib import Path
import pickle
from tempfile import TemporaryDirectory
import unittest
from spinedb_api.exception import ConnectorError
from spinedb_api.spine_io.importers.json_reader import JSONConnector


Expand All @@ -40,6 +38,17 @@ def test_file_iterator_works_with_empty_options(self):
reader.disconnect()
self.assertEqual(rows, [["a", 1], ["b", "c", 2]])

def test_invalid_json_raises_connector_error(self):
reader = JSONConnector(None)
with TemporaryDirectory() as temp_dir:
file_path = Path(temp_dir) / "test file.json"
with open(file_path, "w") as out_file:
out_file.write("PK")
reader.connect_to_source(str(file_path))
with self.assertRaises(ConnectorError):
rows = list(reader.file_iterator("data", {}))
reader.disconnect()


if __name__ == "__main__":
unittest.main()

0 comments on commit bf45766

Please sign in to comment.