From 9a9329baf2341a1cc6923bdd88486ce9e4597025 Mon Sep 17 00:00:00 2001 From: Rouven Bauer Date: Fri, 11 Mar 2022 12:40:55 +0100 Subject: [PATCH] Fix session/workspace lifecycle * don't emit deprecation warning of workspace.__del__ if it was closed already * don't import things while executing a destructor (in deprecation warning) * unasync _AsyncClassNames as well --- bin/make-unasync | 3 +++ neo4j/_async/work/session.py | 2 ++ neo4j/_async/work/workspace.py | 7 +++++-- neo4j/_sync/work/session.py | 2 ++ neo4j/_sync/work/transaction.py | 18 +++++++++--------- neo4j/_sync/work/workspace.py | 7 +++++-- neo4j/meta.py | 2 +- 7 files changed, 27 insertions(+), 14 deletions(-) diff --git a/bin/make-unasync b/bin/make-unasync index bde42d7e0..e8f8efda8 100755 --- a/bin/make-unasync +++ b/bin/make-unasync @@ -172,6 +172,9 @@ class CustomRule(unasync.Rule): # Convert class names from 'AsyncXyz' to 'Xyz' if len(name) > 5 and name.startswith("Async") and name[5].isupper(): return name[5:] + # Convert class names from '_AsyncXyz' to '_Xyz' + elif len(name) > 6 and name.startswith("_Async") and name[6].isupper(): + return "_" + name[6:] # Convert variable/method/function names from 'async_xyz' to 'xyz' elif len(name) > 6 and name.startswith("async_"): return name[6:] diff --git a/neo4j/_async/work/session.py b/neo4j/_async/work/session.py index fd84e7633..9cb54fed6 100644 --- a/neo4j/_async/work/session.py +++ b/neo4j/_async/work/session.py @@ -147,6 +147,8 @@ async def close(self): This will release any borrowed resources, such as connections, and will roll back any outstanding transactions. """ + if self._closed: + return if self._connection: if self._auto_result: if self._state_failed is False: diff --git a/neo4j/_async/work/workspace.py b/neo4j/_async/work/workspace.py index 2098269d8..a47e457e9 100644 --- a/neo4j/_async/work/workspace.py +++ b/neo4j/_async/work/workspace.py @@ -45,8 +45,9 @@ def __init__(self, pool, config): self._closed = False def __del__(self): - if not self._closed: - unclosed_resource_warn(self) + if self._closed: + return + unclosed_resource_warn(self) # TODO: 6.0 - remove this if asyncio.iscoroutinefunction(self.close): return @@ -120,5 +121,7 @@ async def _disconnect(self, sync=False): self._connection_access_mode = None async def close(self): + if self._closed: + return await self._disconnect(sync=True) self._closed = True diff --git a/neo4j/_sync/work/session.py b/neo4j/_sync/work/session.py index 780befdb6..fd2f99cc4 100644 --- a/neo4j/_sync/work/session.py +++ b/neo4j/_sync/work/session.py @@ -147,6 +147,8 @@ def close(self): This will release any borrowed resources, such as connections, and will roll back any outstanding transactions. """ + if self._closed: + return if self._connection: if self._auto_result: if self._state_failed is False: diff --git a/neo4j/_sync/work/transaction.py b/neo4j/_sync/work/transaction.py index 8a36a90d1..6336f9936 100644 --- a/neo4j/_sync/work/transaction.py +++ b/neo4j/_sync/work/transaction.py @@ -29,7 +29,7 @@ __all__ = ("Transaction", "ManagedTransaction") -class _AsyncTransactionBase: +class _TransactionBase: def __init__(self, connection, fetch_size, on_closed, on_error): self._connection = connection self._error_handling_connection = ConnectionErrorHandler( @@ -196,7 +196,7 @@ def _closed(self): return self._closed_flag -class Transaction(_AsyncTransactionBase): +class Transaction(_TransactionBase): """ Container for multiple Cypher queries to be executed within a single context. :class:`Transaction` objects can be used as a context managers (:py:const:`with` block) where the transaction is committed @@ -207,32 +207,32 @@ class Transaction(_AsyncTransactionBase): """ - @wraps(_AsyncTransactionBase._enter) + @wraps(_TransactionBase._enter) def __enter__(self): return self._enter() - @wraps(_AsyncTransactionBase._exit) + @wraps(_TransactionBase._exit) def __exit__(self, exception_type, exception_value, traceback): self._exit(exception_type, exception_value, traceback) - @wraps(_AsyncTransactionBase._commit) + @wraps(_TransactionBase._commit) def commit(self): return self._commit() - @wraps(_AsyncTransactionBase._rollback) + @wraps(_TransactionBase._rollback) def rollback(self): return self._rollback() - @wraps(_AsyncTransactionBase._close) + @wraps(_TransactionBase._close) def close(self): return self._close() - @wraps(_AsyncTransactionBase._closed) + @wraps(_TransactionBase._closed) def closed(self): return self._closed() -class ManagedTransaction(_AsyncTransactionBase): +class ManagedTransaction(_TransactionBase): """Transaction object provided to transaction functions. Inside a transaction function, the driver is responsible for managing diff --git a/neo4j/_sync/work/workspace.py b/neo4j/_sync/work/workspace.py index 38d312f41..96646ad12 100644 --- a/neo4j/_sync/work/workspace.py +++ b/neo4j/_sync/work/workspace.py @@ -45,8 +45,9 @@ def __init__(self, pool, config): self._closed = False def __del__(self): - if not self._closed: - unclosed_resource_warn(self) + if self._closed: + return + unclosed_resource_warn(self) # TODO: 6.0 - remove this if asyncio.iscoroutinefunction(self.close): return @@ -120,5 +121,7 @@ def _disconnect(self, sync=False): self._connection_access_mode = None def close(self): + if self._closed: + return self._disconnect(sync=True) self._closed = True diff --git a/neo4j/meta.py b/neo4j/meta.py index d662bf0d0..35fa789ff 100644 --- a/neo4j/meta.py +++ b/neo4j/meta.py @@ -18,6 +18,7 @@ import asyncio from functools import wraps +from warnings import warn # Can be automatically overridden in builds @@ -39,7 +40,6 @@ def get_user_agent(): def deprecation_warn(message, stack_level=2): - from warnings import warn warn(message, category=DeprecationWarning, stacklevel=stack_level)