diff --git a/pyproject.toml b/pyproject.toml index 5cd5c1af..711d73ed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ name = "crate" dynamic = ["version"] description = "CrateDB Python Client" authors = [{ name = "Crate.io", email = "office@crate.io" }] -requires-python = ">=3.10" +requires-python = ">=3.6" readme = "README.rst" license = "Apache-2.0" classifiers = [ @@ -35,6 +35,10 @@ classifiers = [ "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", @@ -59,7 +63,7 @@ dependencies = [ dev = [ "backports.zoneinfo<1; python_version<'3.9'", "certifi", - "coverage", + "coverage<8", "mypy<1.20", "pytest<10", "pytz", diff --git a/src/crate/client/cursor.py b/src/crate/client/cursor.py index 587f1491..a223999f 100644 --- a/src/crate/client/cursor.py +++ b/src/crate/client/cursor.py @@ -221,6 +221,8 @@ def duration(self): def _convert_rows(self): """ Iterate rows, apply type converters, and generate converted rows. + + The converter is only supported on Python >= 3.10. """ if not ("col_types" in self._result and self._result["col_types"]): raise ValueError( @@ -238,7 +240,7 @@ def _convert_rows(self): for row in self._result["rows"]: yield [ convert(value) - for convert, value in zip(converters, row, strict=False) + for convert, value in zip(converters, row, strict=False) # type: ignore[call-overload] ] @property diff --git a/tests/client/test_cursor.py b/tests/client/test_cursor.py index 976491f9..b7dd9a65 100644 --- a/tests/client/test_cursor.py +++ b/tests/client/test_cursor.py @@ -20,6 +20,7 @@ # software solely pursuant to the terms of the relevant commercial agreement. import datetime +import sys from ipaddress import IPv4Address from unittest import mock @@ -58,6 +59,9 @@ def test_cursor_fetch(mocked_connection): ] +@pytest.mark.skipif( + sys.version_info < (3, 10), reason="Test needs Python >= 3.10" +) def test_cursor_description(mocked_connection): cursor = mocked_connection.cursor() response = { @@ -249,6 +253,9 @@ def test_execute_with_bulk_args(mocked_connection): mocked_connection.client.sql.assert_called_once_with(statement, None, [[1]]) +@pytest.mark.skipif( + sys.version_info < (3, 10), reason="Converter needs Python >= 3.10" +) def test_execute_custom_converter(mocked_connection): """ Verify that a custom converter is correctly applied when passed to a cursor. @@ -299,6 +306,9 @@ def test_execute_custom_converter(mocked_connection): ] +@pytest.mark.skipif( + sys.version_info < (3, 10), reason="Converter needs Python >= 3.10" +) def test_execute_with_converter_and_invalid_data_type(mocked_connection): converter = DefaultTypeConverter() @@ -323,6 +333,9 @@ def test_execute_with_converter_and_invalid_data_type(mocked_connection): assert e.exception.args == "999 is not a valid DataType" +@pytest.mark.skipif( + sys.version_info < (3, 10), reason="Converter needs Python >= 3.10" +) def test_execute_array_with_converter(mocked_connection): converter = DefaultTypeConverter() cursor = mocked_connection.cursor(converter=converter) @@ -345,6 +358,9 @@ def test_execute_array_with_converter(mocked_connection): ] +@pytest.mark.skipif( + sys.version_info < (3, 10), reason="Converter needs Python >= 3.10" +) def test_execute_array_with_converter_invalid(mocked_connection): converter = DefaultTypeConverter() cursor = mocked_connection.cursor(converter=converter) @@ -368,6 +384,9 @@ def test_execute_array_with_converter_invalid(mocked_connection): ) +@pytest.mark.skipif( + sys.version_info < (3, 10), reason="Converter needs Python >= 3.10" +) def test_execute_nested_array_with_converter(mocked_connection): converter = DefaultTypeConverter() cursor = mocked_connection.cursor(converter=converter) @@ -405,6 +424,9 @@ def test_execute_nested_array_with_converter(mocked_connection): ] +@pytest.mark.skipif( + sys.version_info < (3, 10), reason="Converter needs Python >= 3.10" +) def test_executemany_with_converter(mocked_connection): converter = DefaultTypeConverter() cursor = mocked_connection.cursor(converter=converter) @@ -426,6 +448,9 @@ def test_executemany_with_converter(mocked_connection): assert result == [] +@pytest.mark.skipif( + sys.version_info < (3, 10), reason="Converter needs Python >= 3.10" +) def test_execute_with_timezone(mocked_connection): # Create a `Cursor` object with `time_zone`. tz_mst = datetime.timezone(datetime.timedelta(hours=7), name="MST") diff --git a/tests/client/tests.py b/tests/client/tests.py index ae6a479f..65a007bd 100644 --- a/tests/client/tests.py +++ b/tests/client/tests.py @@ -1,4 +1,5 @@ import doctest +import sys import unittest from .layer import ( @@ -18,14 +19,17 @@ def test_suite(): suite.addTest(doctest.DocTestSuite("crate.client.connection")) suite.addTest(doctest.DocTestSuite("crate.client.http")) - s = doctest.DocFileSuite( - "docs/by-example/connection.rst", - "docs/by-example/cursor.rst", - module_relative=False, - optionflags=flags, - encoding="utf-8", - ) - suite.addTest(s) + if sys.version_info >= (3, 10): + # This suite includes converter tests, + # which are only available with Python 3.10 and newer. + s = doctest.DocFileSuite( + "docs/by-example/connection.rst", + "docs/by-example/cursor.rst", + module_relative=False, + optionflags=flags, + encoding="utf-8", + ) + suite.addTest(s) s = doctest.DocFileSuite( "docs/by-example/https.rst",