Skip to content

Commit 1bd382f

Browse files
authored
Emit DeprecationWarning on using the driver after closing it (#962)
1 parent 3d2eb62 commit 1bd382f

File tree

4 files changed

+100
-0
lines changed

4 files changed

+100
-0
lines changed

src/neo4j/_async/driver.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,16 @@ def __del__(self):
489489
)
490490
self.close()
491491

492+
def _check_state(self):
493+
if self._closed:
494+
# TODO: 6.0 - raise the error
495+
# raise DriverError("Driver closed")
496+
deprecation_warn(
497+
"Using a driver after it has been closed is deprecated. "
498+
"Future versions of the driver will raise an error.",
499+
stack_level=3
500+
)
501+
492502
@property
493503
def encrypted(self) -> bool:
494504
"""Indicate whether the driver was configured to use encryption."""
@@ -535,6 +545,7 @@ def session(self, **config) -> AsyncSession:
535545
536546
:returns: new :class:`neo4j.AsyncSession` object
537547
"""
548+
self._check_state()
538549
session_config = self._read_session_config(config)
539550
return self._session(session_config)
540551

@@ -558,6 +569,7 @@ def _prepare_session_config(cls, preview_check, config_kwargs):
558569
async def close(self) -> None:
559570
""" Shut down, closing any open connections in the pool.
560571
"""
572+
self._check_state()
561573
try:
562574
await self._pool.close()
563575
except asyncio.CancelledError:
@@ -832,6 +844,7 @@ async def example(driver: neo4j.AsyncDriver) -> neo4j.Record::
832844
* Added the ``auth_`` parameter.
833845
* Stabilized from experimental.
834846
"""
847+
self._check_state()
835848
invalid_kwargs = [k for k in kwargs if
836849
k[-2:-1] != "_" and k[-1:] == "_"]
837850
if invalid_kwargs:
@@ -962,6 +975,7 @@ async def verify_connectivity(self, **config) -> None:
962975
If you need information about the remote server, use
963976
:meth:`get_server_info` instead.
964977
"""
978+
self._check_state()
965979
if config:
966980
experimental_warn(
967981
"All configuration key-word arguments to "
@@ -1034,6 +1048,7 @@ async def get_server_info(self, **config) -> ServerInfo:
10341048
10351049
.. versionadded:: 5.0
10361050
"""
1051+
self._check_state()
10371052
if config:
10381053
experimental_warn(
10391054
"All configuration key-word arguments to "
@@ -1057,6 +1072,7 @@ async def supports_multi_db(self) -> bool:
10571072
won't throw a :exc:`ConfigurationError` when trying to use this
10581073
driver feature.
10591074
"""
1075+
self._check_state()
10601076
session_config = self._read_session_config({}, preview_check=False)
10611077
async with self._session(session_config) as session:
10621078
await session._connect(READ_ACCESS)
@@ -1132,6 +1148,7 @@ async def verify_authentication(
11321148
11331149
.. versionadded:: 5.8
11341150
"""
1151+
self._check_state()
11351152
if config:
11361153
experimental_warn(
11371154
"All configuration key-word arguments but auth to "
@@ -1173,6 +1190,7 @@ async def supports_session_auth(self) -> bool:
11731190
11741191
.. versionadded:: 5.8
11751192
"""
1193+
self._check_state()
11761194
session_config = self._read_session_config({}, preview_check=False)
11771195
async with self._session(session_config) as session:
11781196
await session._connect(READ_ACCESS)

src/neo4j/_sync/driver.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,16 @@ def __del__(self):
488488
)
489489
self.close()
490490

491+
def _check_state(self):
492+
if self._closed:
493+
# TODO: 6.0 - raise the error
494+
# raise DriverError("Driver closed")
495+
deprecation_warn(
496+
"Using a driver after it has been closed is deprecated. "
497+
"Future versions of the driver will raise an error.",
498+
stack_level=3
499+
)
500+
491501
@property
492502
def encrypted(self) -> bool:
493503
"""Indicate whether the driver was configured to use encryption."""
@@ -534,6 +544,7 @@ def session(self, **config) -> Session:
534544
535545
:returns: new :class:`neo4j.Session` object
536546
"""
547+
self._check_state()
537548
session_config = self._read_session_config(config)
538549
return self._session(session_config)
539550

@@ -557,6 +568,7 @@ def _prepare_session_config(cls, preview_check, config_kwargs):
557568
def close(self) -> None:
558569
""" Shut down, closing any open connections in the pool.
559570
"""
571+
self._check_state()
560572
try:
561573
self._pool.close()
562574
except asyncio.CancelledError:
@@ -831,6 +843,7 @@ def example(driver: neo4j.Driver) -> neo4j.Record::
831843
* Added the ``auth_`` parameter.
832844
* Stabilized from experimental.
833845
"""
846+
self._check_state()
834847
invalid_kwargs = [k for k in kwargs if
835848
k[-2:-1] != "_" and k[-1:] == "_"]
836849
if invalid_kwargs:
@@ -961,6 +974,7 @@ def verify_connectivity(self, **config) -> None:
961974
If you need information about the remote server, use
962975
:meth:`get_server_info` instead.
963976
"""
977+
self._check_state()
964978
if config:
965979
experimental_warn(
966980
"All configuration key-word arguments to "
@@ -1033,6 +1047,7 @@ def get_server_info(self, **config) -> ServerInfo:
10331047
10341048
.. versionadded:: 5.0
10351049
"""
1050+
self._check_state()
10361051
if config:
10371052
experimental_warn(
10381053
"All configuration key-word arguments to "
@@ -1056,6 +1071,7 @@ def supports_multi_db(self) -> bool:
10561071
won't throw a :exc:`ConfigurationError` when trying to use this
10571072
driver feature.
10581073
"""
1074+
self._check_state()
10591075
session_config = self._read_session_config({}, preview_check=False)
10601076
with self._session(session_config) as session:
10611077
session._connect(READ_ACCESS)
@@ -1131,6 +1147,7 @@ def verify_authentication(
11311147
11321148
.. versionadded:: 5.8
11331149
"""
1150+
self._check_state()
11341151
if config:
11351152
experimental_warn(
11361153
"All configuration key-word arguments but auth to "
@@ -1172,6 +1189,7 @@ def supports_session_auth(self) -> bool:
11721189
11731190
.. versionadded:: 5.8
11741191
"""
1192+
self._check_state()
11751193
session_config = self._read_session_config({}, preview_check=False)
11761194
with self._session(session_config) as session:
11771195
session._connect(READ_ACCESS)

tests/unit/async_/test_driver.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from __future__ import annotations
2020

21+
import inspect
2122
import ssl
2223
import typing as t
2324

@@ -951,3 +952,34 @@ async def test_supports_session_auth(session_cls_mock) -> None:
951952
session_mock = session_cls_mock.return_value.__aenter__.return_value
952953
connection_mock = session_mock._connection
953954
assert res is connection_mock.supports_re_auth
955+
956+
957+
@pytest.mark.parametrize(
958+
("method_name", "args", "kwargs"),
959+
(
960+
("execute_query", ("",), {}),
961+
("session", (), {}),
962+
("verify_connectivity", (), {}),
963+
("get_server_info", (), {}),
964+
("supports_multi_db", (), {}),
965+
("supports_session_auth", (), {}),
966+
("close", (), {}),
967+
968+
)
969+
)
970+
@mark_async_test
971+
async def test_using_closed_driver_is_deprecated(
972+
method_name, args, kwargs, session_cls_mock
973+
) -> None:
974+
driver = AsyncGraphDatabase.driver("bolt://localhost")
975+
await driver.close()
976+
977+
method = getattr(driver, method_name)
978+
with pytest.warns(
979+
DeprecationWarning,
980+
match="Using a driver after it has been closed is deprecated."
981+
):
982+
if inspect.iscoroutinefunction(method):
983+
await method(*args, **kwargs)
984+
else:
985+
method(*args, **kwargs)

tests/unit/sync/test_driver.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from __future__ import annotations
2020

21+
import inspect
2122
import ssl
2223
import typing as t
2324

@@ -950,3 +951,34 @@ def test_supports_session_auth(session_cls_mock) -> None:
950951
session_mock = session_cls_mock.return_value.__enter__.return_value
951952
connection_mock = session_mock._connection
952953
assert res is connection_mock.supports_re_auth
954+
955+
956+
@pytest.mark.parametrize(
957+
("method_name", "args", "kwargs"),
958+
(
959+
("execute_query", ("",), {}),
960+
("session", (), {}),
961+
("verify_connectivity", (), {}),
962+
("get_server_info", (), {}),
963+
("supports_multi_db", (), {}),
964+
("supports_session_auth", (), {}),
965+
("close", (), {}),
966+
967+
)
968+
)
969+
@mark_sync_test
970+
def test_using_closed_driver_is_deprecated(
971+
method_name, args, kwargs, session_cls_mock
972+
) -> None:
973+
driver = GraphDatabase.driver("bolt://localhost")
974+
driver.close()
975+
976+
method = getattr(driver, method_name)
977+
with pytest.warns(
978+
DeprecationWarning,
979+
match="Using a driver after it has been closed is deprecated."
980+
):
981+
if inspect.iscoroutinefunction(method):
982+
method(*args, **kwargs)
983+
else:
984+
method(*args, **kwargs)

0 commit comments

Comments
 (0)