diff --git a/rdflib/plugins/sparql/results/tsvresults.py b/rdflib/plugins/sparql/results/tsvresults.py index 2406cf4e3..066aba7fa 100644 --- a/rdflib/plugins/sparql/results/tsvresults.py +++ b/rdflib/plugins/sparql/results/tsvresults.py @@ -68,30 +68,24 @@ def parse(self, source, content_type=None): # if reading from source returns bytes do utf-8 decoding source = codecs.getreader("utf-8")(source) - try: - r = Result("SELECT") - - header = source.readline() - - r.vars = list(HEADER.parseString(header.strip(), parseAll=True)) - r.bindings = [] - while True: - line = source.readline() - if not line: - break - line = line.strip("\n") - if line == "": - continue - - row = ROW.parseString(line, parseAll=True) - r.bindings.append(dict(zip(r.vars, (self.convertTerm(x) for x in row)))) - - return r - - except ParseException as err: - print(err.line) - print(" " * (err.column - 1) + "^") - print(err) + r = Result("SELECT") + + header = source.readline() + + r.vars = list(HEADER.parseString(header.strip(), parseAll=True)) + r.bindings = [] + while True: + line = source.readline() + if not line: + break + line = line.strip("\n") + if line == "": + continue + + row = ROW.parseString(line, parseAll=True) + r.bindings.append(dict(zip(r.vars, (self.convertTerm(x) for x in row)))) + + return r def convertTerm(self, t): if t is NONE_VALUE: diff --git a/test/test_sparql/test_result.py b/test/test_sparql/test_result.py new file mode 100644 index 000000000..808ae58ec --- /dev/null +++ b/test/test_sparql/test_result.py @@ -0,0 +1,53 @@ +import inspect +import logging +from io import StringIO +from typing import Mapping, Sequence, Type, Union + +import pytest +from pyparsing import ParseException + +from rdflib.query import Result +from rdflib.term import Identifier, Literal, Variable + +BindingsType = Sequence[Mapping[Variable, Identifier]] +ParseOutcomeType = Union[BindingsType, Type[Exception]] + + +@pytest.mark.parametrize( + ("data", "format", "parse_outcome"), + [ + pytest.param( + "a\n1", + "csv", + [{Variable("a"): Literal("1")}], + id="csv-okay-1c1r", + ), + pytest.param( + '?a\n"1"', + "tsv", + [{Variable("a"): Literal("1")}], + id="tsv-okay-1c1r", + ), + pytest.param( + "1,2,3\nhttp://example.com", + "tsv", + ParseException, + id="tsv-invalid", + ), + ], +) +def test_select_result_parse( + data: str, format: str, parse_outcome: ParseOutcomeType +) -> None: + """ + Round tripping of a select query through the serializer and parser of a + specific format results in an equivalent result object. + """ + logging.debug("data = %s", data) + + if inspect.isclass(parse_outcome) and issubclass(parse_outcome, Exception): + with pytest.raises(parse_outcome): + parsed_result = Result.parse(StringIO(data), format=format) + else: + parsed_result = Result.parse(StringIO(data), format=format) + assert parse_outcome == parsed_result.bindings