From 0026876b3b0e092609137ae6c5203895c0b0a4e4 Mon Sep 17 00:00:00 2001 From: Robsdedude Date: Thu, 6 Nov 2025 14:55:25 +0100 Subject: [PATCH 1/2] Python 3.14 --- docs/source/index.rst | 1 + pyproject.toml | 1 + src/neo4j/_async/io/_bolt.py | 3 ++- src/neo4j/_async/io/_common.py | 5 +++-- src/neo4j/_async_compat/util.py | 2 +- src/neo4j/_sync/io/_bolt.py | 3 ++- src/neo4j/_sync/io/_common.py | 5 +++-- src/neo4j/_warnings.py | 9 +++++---- testkit/Dockerfile | 2 +- tests/conftest.py | 3 ++- tox.ini | 2 +- 11 files changed, 22 insertions(+), 14 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index abffa3afb..ac13f3815 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -19,6 +19,7 @@ See https://neo4j.com/developer/kb/neo4j-supported-versions/ for a driver-server Python versions supported: +* Python 3.14 * Python 3.13 * Python 3.12 * Python 3.11 diff --git a/pyproject.toml b/pyproject.toml index d7e34bb51..9d3a13388 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,6 +37,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Topic :: Database", "Topic :: Software Development", "Typing :: Typed", diff --git a/src/neo4j/_async/io/_bolt.py b/src/neo4j/_async/io/_bolt.py index 3c2d9e73b..62d4d206b 100644 --- a/src/neo4j/_async/io/_bolt.py +++ b/src/neo4j/_async/io/_bolt.py @@ -18,6 +18,7 @@ import abc import asyncio +import inspect from collections import deque from logging import getLogger from time import monotonic @@ -198,7 +199,7 @@ def __init__( ) def __del__(self): - if not asyncio.iscoroutinefunction(self.close): + if not inspect.iscoroutinefunction(self.close): self.close() @abc.abstractmethod diff --git a/src/neo4j/_async/io/_common.py b/src/neo4j/_async/io/_common.py index bcd02c334..dbffb9f9f 100644 --- a/src/neo4j/_async/io/_common.py +++ b/src/neo4j/_async/io/_common.py @@ -15,6 +15,7 @@ import asyncio +import inspect import logging from contextlib import suppress from struct import pack as struct_pack @@ -191,7 +192,7 @@ def inner(*args, **kwargs): try: func(*args, **kwargs) except (Neo4jError, ServiceUnavailable, SessionExpired) as exc: - assert not asyncio.iscoroutinefunction(self.__on_error) + assert not inspect.iscoroutinefunction(self.__on_error) self.__on_error(exc) raise @@ -212,7 +213,7 @@ async def inner(*args, **kwargs): return inner - if asyncio.iscoroutinefunction(connection_attr): + if inspect.iscoroutinefunction(connection_attr): return outer_async(connection_attr) return outer(connection_attr) diff --git a/src/neo4j/_async_compat/util.py b/src/neo4j/_async_compat/util.py index e59ceda1f..c72250329 100644 --- a/src/neo4j/_async_compat/util.py +++ b/src/neo4j/_async_compat/util.py @@ -67,7 +67,7 @@ async def callback(cb, *args, **kwargs): @staticmethod def shielded(coro_function): - assert asyncio.iscoroutinefunction(coro_function) + assert inspect.iscoroutinefunction(coro_function) @wraps(coro_function) async def shielded_function(*args, **kwargs): diff --git a/src/neo4j/_sync/io/_bolt.py b/src/neo4j/_sync/io/_bolt.py index 134c09248..076216d3e 100644 --- a/src/neo4j/_sync/io/_bolt.py +++ b/src/neo4j/_sync/io/_bolt.py @@ -18,6 +18,7 @@ import abc import asyncio +import inspect from collections import deque from logging import getLogger from time import monotonic @@ -198,7 +199,7 @@ def __init__( ) def __del__(self): - if not asyncio.iscoroutinefunction(self.close): + if not inspect.iscoroutinefunction(self.close): self.close() @abc.abstractmethod diff --git a/src/neo4j/_sync/io/_common.py b/src/neo4j/_sync/io/_common.py index cdf49af02..245cc8509 100644 --- a/src/neo4j/_sync/io/_common.py +++ b/src/neo4j/_sync/io/_common.py @@ -15,6 +15,7 @@ import asyncio +import inspect import logging from contextlib import suppress from struct import pack as struct_pack @@ -191,7 +192,7 @@ def inner(*args, **kwargs): try: func(*args, **kwargs) except (Neo4jError, ServiceUnavailable, SessionExpired) as exc: - assert not asyncio.iscoroutinefunction(self.__on_error) + assert not inspect.iscoroutinefunction(self.__on_error) self.__on_error(exc) raise @@ -212,7 +213,7 @@ def inner(*args, **kwargs): return inner - if asyncio.iscoroutinefunction(connection_attr): + if inspect.iscoroutinefunction(connection_attr): return outer_async(connection_attr) return outer(connection_attr) diff --git a/src/neo4j/_warnings.py b/src/neo4j/_warnings.py index 4bebeb6ac..7affca020 100644 --- a/src/neo4j/_warnings.py +++ b/src/neo4j/_warnings.py @@ -16,9 +16,8 @@ from __future__ import annotations -import asyncio +import inspect from functools import wraps -from inspect import isclass from warnings import warn from . import _typing as t @@ -98,7 +97,7 @@ def _make_warning_decorator( warning_func: _WarningFunc, ) -> t.Callable[[_FuncT], _FuncT]: def decorator(f): - if asyncio.iscoroutinefunction(f): + if inspect.iscoroutinefunction(f): @wraps(f) async def inner(*args, **kwargs): @@ -107,7 +106,8 @@ async def inner(*args, **kwargs): inner._without_warning = f return inner - if isclass(f): + + if inspect.isclass(f): if hasattr(f, "__init__"): original_init = f.__init__ @@ -125,6 +125,7 @@ def _without_warning(cls, *args, **kwargs): f._without_warning = classmethod(_without_warning) return f raise TypeError("Cannot decorate class without __init__") + else: @wraps(f) diff --git a/testkit/Dockerfile b/testkit/Dockerfile index 9727c1beb..d38ccc4f6 100644 --- a/testkit/Dockerfile +++ b/testkit/Dockerfile @@ -56,7 +56,7 @@ ENV PIP_NO_CACHE_DIR=1 FROM base AS base-py-arg # Install all supported Python versions -ARG PYTHON_VERSIONS="3.13 3.12 3.11 3.10" +ARG PYTHON_VERSIONS="3.14 3.13 3.12 3.11 3.10" FROM base AS base-py-arg-single-python diff --git a/tests/conftest.py b/tests/conftest.py index b56aefaa4..16bf1ecb4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -17,6 +17,7 @@ from __future__ import annotations import asyncio +import inspect import sys from functools import wraps @@ -186,7 +187,7 @@ def neo4j_session(neo4j_driver): @pytest_asyncio.fixture def aio_benchmark(benchmark, event_loop): def _wrapper(func, *args, **kwargs): - if asyncio.iscoroutinefunction(func): + if inspect.iscoroutinefunction(func): @benchmark def _(): diff --git a/tox.ini b/tox.ini index f31fae524..606bec650 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py{310,311,312,313}-{unit,integration,performance} +envlist = py{310,311,312,313,314}-{unit,integration,performance} [testenv] passenv = TEST_* From c1d074bc16ca0ab35f3ead0559e088e8daa4f84d Mon Sep 17 00:00:00 2001 From: MaxAake <61233757+MaxAake@users.noreply.github.com> Date: Mon, 10 Nov 2025 13:48:32 +0100 Subject: [PATCH 2/2] Add 3.14 to more places Signed-off-by: Rouven Bauer --- .github/workflows/tests.yaml | 2 ++ CHANGELOG.md | 2 +- README.rst | 1 + TESTING.md | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 230bfdf2f..80f724f1b 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -23,6 +23,8 @@ jobs: tox-factor: 'py312' - semver: '3.13' tox-factor: 'py313' + - semver: '3.14' + tox-factor: 'py314' steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b5a40b2f..ed21ff5f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ See also https://github.com/neo4j/neo4j-python-driver/wiki for a full changelog. ## NEXT RELEASE -- No breaking or major changes. +- Python 3.14 support added. ## Version 6.0 diff --git a/README.rst b/README.rst index 8c44ae607..215439d31 100644 --- a/README.rst +++ b/README.rst @@ -9,6 +9,7 @@ Driver upgrades within a major version will never contain breaking API changes. For version compatibility with Neo4j server, please refer to: https://neo4j.com/developer/kb/neo4j-supported-versions/ ++ Python 3.14 supported. + Python 3.13 supported. + Python 3.12 supported. + Python 3.11 supported. diff --git a/TESTING.md b/TESTING.md index db07ead9d..bc4d51140 100644 --- a/TESTING.md +++ b/TESTING.md @@ -1,6 +1,6 @@ # Neo4j Driver Testing To run driver tests, [Tox](https://tox.readthedocs.io) is required as well as at least one version of Python. -The versions of Python supported by this driver are CPython 3.10 - 3.13 +The versions of Python supported by this driver are CPython 3.10 - 3.14 ## Testing with TestKit TestKit is the shared test suite used by all official (and some community contributed) Neo4j drivers to ensure consistent and correct behavior across all drivers.