diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c9805d97..4161af7d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,10 +19,13 @@ repos: - batch - id: trailing-whitespace args: [ --markdown-linebreak-ext=md ] - - repo: https://github.com/pycqa/isort - rev: 5.12.0 + - repo: local hooks: - id: isort + name: isort + entry: isort + types_or: [ python, pyi ] + language: system - repo: https://github.com/sphinx-contrib/sphinx-lint rev: e83a1a42a73284d301c05baaffc176042ffbcf82 hooks: @@ -45,7 +48,7 @@ repos: name: mypy static type check entry: mypy args: [ --show-error-codes, src, tests, testkitbackend, benchkit ] - 'types_or': [ python, pyi ] + types_or: [ python, pyi ] language: system pass_filenames: false require_serial: true diff --git a/benchkit/app.py b/benchkit/app.py index a2e9e756..b4e56853 100644 --- a/benchkit/app.py +++ b/benchkit/app.py @@ -16,6 +16,7 @@ from __future__ import annotations +import sys import typing as t from contextlib import contextmanager from multiprocessing import Semaphore @@ -43,7 +44,10 @@ from .workloads import Workload -T_App: te.TypeAlias = "Sanic[Config, BenchKitContext]" +if sys.version_info < (3, 8): + T_App: te.TypeAlias = "Sanic" +else: + T_App: te.TypeAlias = "Sanic[Config, BenchKitContext]" def create_app() -> T_App: diff --git a/benchkit/workloads.py b/benchkit/workloads.py index 8d86901f..21c2c650 100644 --- a/benchkit/workloads.py +++ b/benchkit/workloads.py @@ -543,7 +543,7 @@ def parse(cls, query: t.Any) -> te.Self: @dataclass class _WorkloadConfig: database: str | None - routing: t.Literal["r", "w"] + routing: te.Literal["r", "w"] @classmethod def parse(cls, data: t.Any) -> te.Self: @@ -553,7 +553,7 @@ def parse(cls, data: t.Any) -> te.Self: if not isinstance(database, str): raise TypeError("Workload database must be a string") - routing: t.Literal["r", "w"] = "w" + routing: te.Literal["r", "w"] = "w" if "routing" in data: raw_routing = data["routing"] if not isinstance(routing, str): diff --git a/requirements-dev.txt b/requirements-dev.txt index 5a22e864..ef164b16 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,32 +2,31 @@ -e .[pandas,numpy,pyarrow] # needed for packaging -build +build>=1.1.1 # TODO: 6.0 - bump when support for Python 3.7 is dropped # auto-generate sync driver from async code -unasync>=0.5.0 +unasync==0.5.0 # pre-commit hooks and tools -pre-commit>=2.15.0 -isort>=5.10.0 -mypy>=0.971 -typing-extensions>=4.3.0 -types-pytz>=2022.1.2 -ruff>=0.6.4 +pre-commit>=2.21.0 # TODO: 6.0 - bump when support for Python 3.7 is dropped +isort>=5.11.5 # TODO: 6.0 - bump when support for Python 3.7 is dropped +mypy>=1.4.1 # TODO: 6.0 - bump when support for Python 3.7 is dropped +typing-extensions>=4.7.1 +types-pytz>=2023.3.1.1 # TODO: 6.0 - bump when support for Python 3.7 is dropped +ruff>=0.8.2 # needed for running tests -coverage[toml]>=5.5 +coverage[toml]>=7.2.7 # TODO: 6.0 - bump when support for Python 3.7 is dropped freezegun>=1.5.1 -mock>=4.0.3 -pytest>=6.2.5 -pytest-asyncio>=0.16.0 -pytest-benchmark>=3.4.1 -pytest-cov>=3.0.0 -pytest-mock>=3.6.1 -tox>=4.0.0 -teamcity-messages>=1.32 +mock>=5.1.0 +pytest>=7.4.4 # TODO: 6.0 - bump when support for Python 3.7 is dropped +pytest-asyncio~=0.21.2 # TODO: 6.0 - bump when support for Python 3.7 is dropped +pytest-benchmark>=4.0.0 +pytest-cov>=4.1.0 # TODO: 6.0 - bump when support for Python 3.7 is dropped +pytest-mock>=3.11.1 # TODO: 6.0 - bump when support for Python 3.7 is dropped +tox>=4.8.0 # TODO: 6.0 - bump when support for Python 3.7 is dropped # needed for building docs -sphinx +Sphinx>=5.3.0 # TODO: 6.0 - bump when support for Python 3.7 is dropped # needed for BenchKit -sanic>=23.12.1 ; python_version >= '3.8.0' +sanic>=23.3.0 # TODO: 6.0 - bump when support for Python 3.7 is dropped diff --git a/src/neo4j/_async/work/result.py b/src/neo4j/_async/work/result.py index 696358de..ac62fa1f 100644 --- a/src/neo4j/_async/work/result.py +++ b/src/neo4j/_async/work/result.py @@ -105,7 +105,7 @@ class AsyncResult(AsyncNonConcurrentMethodChecker): """ _creation_stack: list[inspect.FrameInfo] | None - _creation_frame_cache: None | t.Literal[False] | inspect.FrameInfo + _creation_frame_cache: None | te.Literal[False] | inspect.FrameInfo def __init__( self, @@ -356,7 +356,7 @@ def _handle_warnings(self) -> None: ) @property - def _creation_frame(self) -> t.Literal[False] | inspect.FrameInfo: + def _creation_frame(self) -> te.Literal[False] | inspect.FrameInfo: if self._creation_frame_cache is not None: return self._creation_frame_cache diff --git a/src/neo4j/_spatial/__init__.py b/src/neo4j/_spatial/__init__.py index 20da1abd..bf6f19c4 100644 --- a/src/neo4j/_spatial/__init__.py +++ b/src/neo4j/_spatial/__init__.py @@ -58,7 +58,8 @@ def y(self) -> float: ... def z(self) -> float: ... def __new__(cls, iterable: t.Iterable[float]) -> Point: - return tuple.__new__(cls, map(float, iterable)) + # TODO: 6.0 - remove type ignore when support for Python 3.7 is dropped + return tuple.__new__(cls, map(float, iterable)) # type: ignore[type-var] def __repr__(self) -> str: return f"POINT({' '.join(map(str, self))})" diff --git a/src/neo4j/_sync/work/result.py b/src/neo4j/_sync/work/result.py index f343efa2..27164cf8 100644 --- a/src/neo4j/_sync/work/result.py +++ b/src/neo4j/_sync/work/result.py @@ -105,7 +105,7 @@ class Result(NonConcurrentMethodChecker): """ _creation_stack: list[inspect.FrameInfo] | None - _creation_frame_cache: None | t.Literal[False] | inspect.FrameInfo + _creation_frame_cache: None | te.Literal[False] | inspect.FrameInfo def __init__( self, @@ -356,7 +356,7 @@ def _handle_warnings(self) -> None: ) @property - def _creation_frame(self) -> t.Literal[False] | inspect.FrameInfo: + def _creation_frame(self) -> te.Literal[False] | inspect.FrameInfo: if self._creation_frame_cache is not None: return self._creation_frame_cache diff --git a/src/neo4j/api.py b/src/neo4j/api.py index 160f7c97..3fdc09fc 100644 --- a/src/neo4j/api.py +++ b/src/neo4j/api.py @@ -385,7 +385,8 @@ def protocol_version(self) -> tuple[int, int]: This is returned as a 2-tuple:class:`tuple` (subclass) of ``(major, minor)`` integers. """ - return self._protocol_version + # TODO: 6.0 - remove cast when support for Python 3.7 is dropped + return t.cast(t.Tuple[int, int], self._protocol_version) @property def agent(self) -> str: diff --git a/src/neo4j/time/__init__.py b/src/neo4j/time/__init__.py index 4f8ad101..cfee552d 100644 --- a/src/neo4j/time/__init__.py +++ b/src/neo4j/time/__init__.py @@ -470,7 +470,8 @@ def __new__( ) if not MIN_INT64 <= avg_total_seconds <= MAX_INT64: raise ValueError(f"Duration value out of range: {tuple_!r}") - return tuple.__new__(cls, tuple_) + # TODO: 6.0 - remove type ignore when support for Python 3.7 is dropped + return tuple.__new__(cls, tuple_) # type: ignore[type-var] def __bool__(self) -> bool: """Falsy if all primary instance attributes are.""" diff --git a/testkit/Dockerfile b/testkit/Dockerfile index 8b6b9d63..e61135da 100644 --- a/testkit/Dockerfile +++ b/testkit/Dockerfile @@ -57,18 +57,3 @@ RUN for version in $PYTHON_VERSIONS; do \ python$version -m pip install -U pip && \ python$version -m pip install -U coverage tox; \ done - -# Installing pyarrow lib until pre-built wheel for Python 3.13 exists -# https://github.com/apache/arrow/issues/43519 -RUN apt update && \ - apt install -y -V lsb-release cmake gcc && \ - distro_name=$(lsb_release --id --short | tr 'A-Z' 'a-z') && \ - code_name=$(lsb_release --codename --short) && \ - wget https://apache.jfrog.io/artifactory/arrow/${distro_name}/apache-arrow-apt-source-latest-${code_name}.deb && \ - apt install -y -V ./apache-arrow-apt-source-latest-${code_name}.deb && \ - apt update && \ - apt install -y -V libarrow-dev libarrow-dataset-dev libarrow-flight-dev libparquet-dev && \ - apt clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* -ENV PYARROW_WITH_CUDA=off -ENV PYARROW_WITH_GANDIVA=off -ENV PYARROW_PARALLEL=8 diff --git a/tests/unit/async_/test_driver.py b/tests/unit/async_/test_driver.py index 53d28710..71ba0e90 100644 --- a/tests/unit/async_/test_driver.py +++ b/tests/unit/async_/test_driver.py @@ -780,11 +780,10 @@ async def test_warn_notification_severity_driver_config( if min_sev_session is ...: session = driver.session() else: - session = driver.session( - # Works at runtime (will be ignored), but should be rejected by - # type checkers. - # type: ignore[call-arg] - warn_notification_severity=min_sev_session + # Works at runtime (will be ignored), but should be rejected by + # type checkers. + session = driver.session( # type: ignore[call-arg] + warn_notification_severity=min_sev_session, ) async with session: session_cls_mock.assert_called_once() diff --git a/tests/unit/common/test_record.py b/tests/unit/common/test_record.py index b3c38301..0f06fbe2 100644 --- a/tests/unit/common/test_record.py +++ b/tests/unit/common/test_record.py @@ -17,6 +17,7 @@ from __future__ import annotations import traceback +import typing as t import pytest import pytz @@ -166,39 +167,49 @@ def test_record_data_keys(keys, expected) -> None: ( *( (value, value) - for value in ( - None, - True, - False, - 0, - 1, - -1, - 2147483647, - -2147483648, - 3.141592653589, - "", - "Hello, world!", - "👋, 🌍!", - [], - [1, 2.0, "3", True, None], - {"foo": ["bar", 1]}, - b"", - b"foobar", - Date(2021, 1, 1), - Time(12, 34, 56, 123456789), - Time(1, 2, 3, 4, pytz.FixedOffset(60)), - DateTime(2021, 1, 1, 12, 34, 56, 123456789), - DateTime( - 2018, 10, 12, 11, 37, 41, 474716862, pytz.FixedOffset(60) - ), - pytz.timezone("Europe/Stockholm").localize( - DateTime(2018, 10, 12, 11, 37, 41, 474716862) + for value in t.cast( + t.Tuple[t.Any], + ( + None, + True, + False, + 0, + 1, + -1, + 2147483647, + -2147483648, + 3.141592653589, + "", + "Hello, world!", + "👋, 🌍!", + [], + [1, 2.0, "3", True, None], + {"foo": ["bar", 1]}, + b"", + b"foobar", + Date(2021, 1, 1), + Time(12, 34, 56, 123456789), + Time(1, 2, 3, 4, pytz.FixedOffset(60)), + DateTime(2021, 1, 1, 12, 34, 56, 123456789), + DateTime( + 2018, + 10, + 12, + 11, + 37, + 41, + 474716862, + pytz.FixedOffset(60), + ), + pytz.timezone("Europe/Stockholm").localize( + DateTime(2018, 10, 12, 11, 37, 41, 474716862) + ), + Duration(1, 2, 3, 4, 5, 6, 7), + CartesianPoint((1, 2.0)), + CartesianPoint((1, 2.0, 3)), + WGS84Point((1, 2.0)), + WGS84Point((1, 2.0, 3)), ), - Duration(1, 2, 3, 4, 5, 6, 7), - CartesianPoint((1, 2.0)), - CartesianPoint((1, 2.0, 3)), - WGS84Point((1, 2.0)), - WGS84Point((1, 2.0, 3)), ) ), *( diff --git a/tests/unit/sync/test_driver.py b/tests/unit/sync/test_driver.py index a508c108..b90ebd52 100644 --- a/tests/unit/sync/test_driver.py +++ b/tests/unit/sync/test_driver.py @@ -779,11 +779,10 @@ def test_warn_notification_severity_driver_config( if min_sev_session is ...: session = driver.session() else: - session = driver.session( - # Works at runtime (will be ignored), but should be rejected by - # type checkers. - # type: ignore[call-arg] - warn_notification_severity=min_sev_session + # Works at runtime (will be ignored), but should be rejected by + # type checkers. + session = driver.session( # type: ignore[call-arg] + warn_notification_severity=min_sev_session, ) with session: session_cls_mock.assert_called_once()