diff --git a/frictionless/schemes/multipart/__spec__/test_loader.py b/frictionless/schemes/multipart/__spec__/test_loader.py index e7aac1abfa..f6a6564342 100644 --- a/frictionless/schemes/multipart/__spec__/test_loader.py +++ b/frictionless/schemes/multipart/__spec__/test_loader.py @@ -175,3 +175,17 @@ def test_multipart_loader_with_compressed_parts_issue_1215(): {"id": 1, "name": "english"}, {"id": 2, "name": "中国人"}, ] + + +def test_multipart_loader_missing_trailing_newline(tmpdir): + tmpdir.join("chunk1.csv").write("id,name\n1,english") + tmpdir.join("chunk2.csv").write("id,name\n2,german\n") + with TableResource( + path=str(tmpdir.join("chunk1.csv")), + extrapaths=[str(tmpdir.join("chunk2.csv"))], + ) as resource: + assert resource.header == ["id", "name"] + assert resource.read_rows() == [ + {"id": 1, "name": "english"}, + {"id": 2, "name": "german"}, + ] diff --git a/frictionless/schemes/multipart/loader.py b/frictionless/schemes/multipart/loader.py index ee77ea363a..d9fcd87815 100644 --- a/frictionless/schemes/multipart/loader.py +++ b/frictionless/schemes/multipart/loader.py @@ -104,9 +104,14 @@ def read(self, size: int): return res def read_line_stream(self): + last_line_had_terminator = True for number, path in enumerate(self.__paths, start=1): + if number > 1 and not last_line_had_terminator: + yield b"\n" + last_line_had_terminator = True with FileResource(path=path) as resource: for line_number, line in enumerate(resource.byte_stream, start=1): if not self.__headless and number > 1 and line_number == 1: continue + last_line_had_terminator = line.endswith((b"\n", b"\r")) yield line