From d453721e8b5b099110036258010b6491c1603b17 Mon Sep 17 00:00:00 2001 From: Tpt Date: Wed, 4 Jan 2023 17:25:37 +0100 Subject: [PATCH] Python: Uses typing.io for I/O types annotations --- python/generate_stubs.py | 1 + python/src/io.rs | 4 ++-- python/src/store.rs | 6 +++--- python/tests/test_io.py | 17 ++++++++++------- python/tests/test_model.py | 1 + python/tests/test_store.py | 18 +++++++----------- 6 files changed, 24 insertions(+), 23 deletions(-) diff --git a/python/generate_stubs.py b/python/generate_stubs.py index 9bb80ecf..7568e8e9 100644 --- a/python/generate_stubs.py +++ b/python/generate_stubs.py @@ -23,6 +23,7 @@ GENERICS = { "iterable": _path_to_type("typing", "Iterable"), "iterator": _path_to_type("typing", "Iterator"), "list": _path_to_type("typing", "List"), + "io": _path_to_type("typing", "IO"), } OBJECT_MEMBERS = dict(inspect.getmembers(object)) diff --git a/python/src/io.rs b/python/src/io.rs index 38667825..64b1b028 100644 --- a/python/src/io.rs +++ b/python/src/io.rs @@ -32,7 +32,7 @@ pub fn add_to_module(module: &PyModule) -> PyResult<()> { /// and ``application/xml`` for `RDF/XML `_. /// /// :param input: The binary I/O object or file path to read from. For example, it could be a file path as a string or a file reader opened in binary mode with ``open('my_file.ttl', 'rb')``. -/// :type input: io.RawIOBase or io.BufferedIOBase or io.TextIOBase or str +/// :type input: io(bytes) or io(str) or str /// :param mime_type: the MIME type of the RDF serialization. /// :type mime_type: str /// :param base_iri: the base IRI used to resolve the relative IRIs in the file or :py:const:`None` if relative IRI resolution should not be done. @@ -105,7 +105,7 @@ pub fn parse( /// :param input: the RDF triples and quads to serialize. /// :type input: iterable(Triple) or iterable(Quad) /// :param output: The binary I/O object or file path to write to. For example, it could be a file path as a string or a file writer opened in binary mode with ``open('my_file.ttl', 'wb')``. -/// :type output: io.RawIOBase or io.BufferedIOBase or str +/// :type output: io(bytes) or str /// :param mime_type: the MIME type of the RDF serialization. /// :type mime_type: str /// :rtype: None diff --git a/python/src/store.rs b/python/src/store.rs index b73972da..8ae81d43 100644 --- a/python/src/store.rs +++ b/python/src/store.rs @@ -266,7 +266,7 @@ impl PyStore { /// and ``application/xml`` for `RDF/XML `_. /// /// :param input: The binary I/O object or file path to read from. For example, it could be a file path as a string or a file reader opened in binary mode with ``open('my_file.ttl', 'rb')``. - /// :type input: io.RawIOBase or io.BufferedIOBase or io.TextIOBase or str + /// :type input: io(bytes) or io(str) or str /// :param mime_type: the MIME type of the RDF serialization. /// :type mime_type: str /// :param base_iri: the base IRI used to resolve the relative IRIs in the file or :py:const:`None` if relative IRI resolution should not be done. @@ -350,7 +350,7 @@ impl PyStore { /// and ``application/xml`` for `RDF/XML `_. /// /// :param input: The binary I/O object or file path to read from. For example, it could be a file path as a string or a file reader opened in binary mode with ``open('my_file.ttl', 'rb')``. - /// :type input: io.RawIOBase or io.BufferedIOBase or io.TextIOBase or str + /// :type input: io(bytes) or io(str) or str /// :param mime_type: the MIME type of the RDF serialization. /// :type mime_type: str /// :param base_iri: the base IRI used to resolve the relative IRIs in the file or :py:const:`None` if relative IRI resolution should not be done. @@ -431,7 +431,7 @@ impl PyStore { /// and ``application/xml`` for `RDF/XML `_. /// /// :param output: The binary I/O object or file path to write to. For example, it could be a file path as a string or a file writer opened in binary mode with ``open('my_file.ttl', 'wb')``. - /// :type output: io.RawIOBase or io.BufferedIOBase or str + /// :type output: io(bytes) or str /// :param mime_type: the MIME type of the RDF serialization. /// :type mime_type: str /// :param from_graph: if a triple based format is requested, the store graph from which dump the triples. By default, the default graph is used. diff --git a/python/tests/test_io.py b/python/tests/test_io.py index 93204942..004dd3e7 100644 --- a/python/tests/test_io.py +++ b/python/tests/test_io.py @@ -1,6 +1,6 @@ import unittest -from io import StringIO, BytesIO, RawIOBase -from tempfile import NamedTemporaryFile +from io import StringIO, BytesIO, UnsupportedOperation +from tempfile import NamedTemporaryFile, TemporaryFile from pyoxigraph import * @@ -49,11 +49,9 @@ class TestParse(unittest.TestCase): ) def test_parse_io_error(self) -> None: - class BadIO(RawIOBase): - pass - - with self.assertRaises(NotImplementedError) as _: - list(parse(BadIO(), mime_type="application/n-triples")) + with self.assertRaises(UnsupportedOperation) as _: + with TemporaryFile("wb") as fp: + list(parse(fp, mime_type="application/n-triples")) class TestSerialize(unittest.TestCase): @@ -71,3 +69,8 @@ class TestSerialize(unittest.TestCase): self.assertEqual( fp.read(), b' "1" .\n' ) + + def test_serialize_io_error(self) -> None: + with self.assertRaises(UnsupportedOperation) as _: + with TemporaryFile("rb") as fp: + serialize([EXAMPLE_TRIPLE], fp, "text/turtle") diff --git a/python/tests/test_model.py b/python/tests/test_model.py index e84322a4..b879cefb 100644 --- a/python/tests/test_model.py +++ b/python/tests/test_model.py @@ -1,4 +1,5 @@ import unittest + from pyoxigraph import * XSD_STRING = NamedNode("http://www.w3.org/2001/XMLSchema#string") diff --git a/python/tests/test_store.py b/python/tests/test_store.py index a8ac1e0b..aab3d648 100644 --- a/python/tests/test_store.py +++ b/python/tests/test_store.py @@ -1,10 +1,10 @@ import os import unittest -from io import BytesIO, RawIOBase +from io import BytesIO, UnsupportedOperation +from tempfile import NamedTemporaryFile, TemporaryFile from typing import Any from pyoxigraph import * -from tempfile import NamedTemporaryFile foo = NamedNode("http://foo") bar = NamedNode("http://bar") @@ -241,11 +241,9 @@ class TestStore(unittest.TestCase): self.assertEqual(set(store), {Quad(foo, bar, baz, graph)}) def test_load_with_io_error(self) -> None: - class BadIO(RawIOBase): - pass - - with self.assertRaises(NotImplementedError) as _: - Store().load(BadIO(), mime_type="application/n-triples") + with self.assertRaises(UnsupportedOperation) as _: + with TemporaryFile("wb") as fp: + Store().load(fp, mime_type="application/n-triples") def test_dump_ntriples(self) -> None: store = Store() @@ -281,11 +279,9 @@ class TestStore(unittest.TestCase): ) def test_dump_with_io_error(self) -> None: - class BadIO(RawIOBase): - pass - with self.assertRaises(OSError) as _: - Store().dump(BadIO(), mime_type="application/rdf+xml") + with TemporaryFile("rb") as fp: + Store().dump(fp, mime_type="application/rdf+xml") def test_write_in_read(self) -> None: store = Store()