diff --git a/src/neo4j/_async/auth_management.py b/src/neo4j/_async/auth_management.py index f9b616b1..e497d400 100644 --- a/src/neo4j/_async/auth_management.py +++ b/src/neo4j/_async/auth_management.py @@ -22,7 +22,6 @@ import typing as t -import warnings from logging import getLogger from .._async_compat.concurrency import AsyncLock @@ -31,10 +30,7 @@ expiring_auth_has_expired, ExpiringAuth, ) -from .._meta import ( - preview, - PreviewWarning, -) +from .._meta import preview # work around for https://github.com/sphinx-doc/sphinx/pull/10880 # make sure TAuth is resolved in the docs, else they're pretty useless @@ -215,11 +211,9 @@ async def auth_provider(): handled_codes = frozenset(("Neo.ClientError.Security.Unauthorized",)) async def wrapped_provider() -> ExpiringAuth: - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", - message=r"^Auth managers\b.*", - category=PreviewWarning) - return ExpiringAuth(await provider()) + return ExpiringAuth._without_warning( # type: ignore + await provider() + ) return AsyncNeo4jAuthTokenManager(wrapped_provider, handled_codes) diff --git a/src/neo4j/_async/driver.py b/src/neo4j/_async/driver.py index 0d0af7ad..e05a3a3b 100644 --- a/src/neo4j/_async/driver.py +++ b/src/neo4j/_async/driver.py @@ -20,7 +20,6 @@ import asyncio import typing as t -import warnings if t.TYPE_CHECKING: @@ -47,7 +46,6 @@ experimental_warn, preview, preview_warn, - PreviewWarning, unclosed_resource_warn, ) from .._work import EagerResult @@ -196,12 +194,7 @@ def driver( driver_type, security_type, parsed = parse_neo4j_uri(uri) if not isinstance(auth, AsyncAuthManager): - with warnings.catch_warnings(): - warnings.filterwarnings( - "ignore", message=r".*\bAuth managers\b.*", - category=PreviewWarning - ) - auth = AsyncAuthManagers.static(auth) + auth = AsyncAuthManagers.static._without_warning(auth) else: preview_warn("Auth managers are a preview feature.", stack_level=2) @@ -501,13 +494,6 @@ def encrypted(self) -> bool: """Indicate whether the driver was configured to use encryption.""" return bool(self._pool.pool_config.encrypted) - def _prepare_session_config(self, **config): - if "auth" in config: - preview_warn("User switching is a preview feature.", - stack_level=3) - _normalize_notifications_config(config) - return config - if t.TYPE_CHECKING: def session( @@ -549,7 +535,25 @@ def session(self, **config) -> AsyncSession: :returns: new :class:`neo4j.AsyncSession` object """ - raise NotImplementedError + session_config = self._read_session_config(config) + return self._session(session_config) + + def _session(self, session_config) -> AsyncSession: + return AsyncSession(self._pool, session_config) + + def _read_session_config(self, config_kwargs, preview_check=True): + config = self._prepare_session_config(preview_check, config_kwargs) + session_config = SessionConfig(self._default_workspace_config, + config) + return session_config + + @classmethod + def _prepare_session_config(cls, preview_check, config_kwargs): + if preview_check and "auth" in config_kwargs: + preview_warn("User switching is a preview feature.", + stack_level=5) + _normalize_notifications_config(config_kwargs) + return config_kwargs async def close(self) -> None: """ Shut down, closing any open connections in the pool. @@ -844,14 +848,16 @@ async def example(driver: neo4j.AsyncDriver) -> neo4j.Record:: bookmark_manager_ = self._query_bookmark_manager assert bookmark_manager_ is not _default - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", - message=r"^User switching\b.*", - category=PreviewWarning) - session = self.session(database=database_, - impersonated_user=impersonated_user_, - bookmark_manager=bookmark_manager_, - auth=auth_) + session_config = self._read_session_config( + { + "database": database_, + "impersonated_user": impersonated_user_, + "bookmark_manager": bookmark_manager_, + "auth": auth_, + }, + preview_check=False + ) + session = self._session(session_config) async with session: if routing_ == RoutingControl.WRITE: executor = session.execute_write @@ -963,7 +969,8 @@ async def verify_connectivity(self, **config) -> None: "changed or removed in any future version without prior " "notice." ) - await self._get_server_info() + session_config = self._read_session_config(config) + await self._get_server_info(session_config) if t.TYPE_CHECKING: @@ -1034,7 +1041,8 @@ async def get_server_info(self, **config) -> ServerInfo: "changed or removed in any future version without prior " "notice." ) - return await self._get_server_info() + session_config = self._read_session_config(config) + return await self._get_server_info(session_config) async def supports_multi_db(self) -> bool: """ Check if the server or cluster supports multi-databases. @@ -1049,7 +1057,8 @@ async def supports_multi_db(self) -> bool: won't throw a :exc:`ConfigurationError` when trying to use this driver feature. """ - async with self.session() as session: + session_config = self._read_session_config({}, preview_check=False) + async with self._session(session_config) as session: await session._connect(READ_ACCESS) assert session._connection return session._connection.supports_multiple_databases @@ -1130,30 +1139,24 @@ async def verify_authentication( "changed or removed in any future version without prior " "notice." ) - config["auth"] = auth if "database" not in config: config["database"] = "system" - try: - with warnings.catch_warnings(): - warnings.filterwarnings( - "ignore", message=r"^User switching\b.*", - category=PreviewWarning - ) - session = self.session(**config) - async with session as session: + session_config = self._read_session_config(config) + session_config = SessionConfig(session_config, {"auth": auth}) + async with self._session(session_config) as session: + try: await session._verify_authentication() - except Neo4jError as exc: - if exc.code in ( - "Neo.ClientError.Security.CredentialsExpired", - "Neo.ClientError.Security.Forbidden", - "Neo.ClientError.Security.TokenExpired", - "Neo.ClientError.Security.Unauthorized", - ): - return False - raise + except Neo4jError as exc: + if exc.code in ( + "Neo.ClientError.Security.CredentialsExpired", + "Neo.ClientError.Security.Forbidden", + "Neo.ClientError.Security.TokenExpired", + "Neo.ClientError.Security.Unauthorized", + ): + return False + raise return True - async def supports_session_auth(self) -> bool: """Check if the remote supports connection re-authentication. @@ -1170,13 +1173,14 @@ async def supports_session_auth(self) -> bool: .. versionadded:: 5.8 """ - async with self.session() as session: + session_config = self._read_session_config({}, preview_check=False) + async with self._session(session_config) as session: await session._connect(READ_ACCESS) assert session._connection return session._connection.supports_re_auth - async def _get_server_info(self, **config) -> ServerInfo: - async with self.session(**config) as session: + async def _get_server_info(self, session_config) -> ServerInfo: + async with self._session(session_config) as session: return await session._get_server_info() @@ -1225,21 +1229,6 @@ def __init__(self, pool, default_workspace_config): AsyncDriver.__init__(self, pool, default_workspace_config) self._default_workspace_config = default_workspace_config - if not t.TYPE_CHECKING: - - def session(self, **config) -> AsyncSession: - """ - :param config: The values that can be specified are found in - :class: `neo4j.SessionConfig` - - :returns: - :rtype: :class: `neo4j.AsyncSession` - """ - config = self._prepare_session_config(**config) - session_config = SessionConfig(self._default_workspace_config, - config) - return AsyncSession(self._pool, session_config) - class AsyncNeo4jDriver(_Routing, AsyncDriver): """:class:`.AsyncNeo4jDriver` is instantiated for ``neo4j`` URIs. The @@ -1264,23 +1253,15 @@ def __init__(self, pool, default_workspace_config): _Routing.__init__(self, [pool.address]) AsyncDriver.__init__(self, pool, default_workspace_config) - if not t.TYPE_CHECKING: - - def session(self, **config) -> AsyncSession: - config = self._prepare_session_config(**config) - session_config = SessionConfig(self._default_workspace_config, - config) - return AsyncSession(self._pool, session_config) - -def _normalize_notifications_config(config): - if config.get("notifications_disabled_categories") is not None: - config["notifications_disabled_categories"] = [ +def _normalize_notifications_config(config_kwargs): + if config_kwargs.get("notifications_disabled_categories") is not None: + config_kwargs["notifications_disabled_categories"] = [ getattr(e, "value", e) - for e in config["notifications_disabled_categories"] + for e in config_kwargs["notifications_disabled_categories"] ] - if config.get("notifications_min_severity") is not None: - config["notifications_min_severity"] = getattr( - config["notifications_min_severity"], "value", - config["notifications_min_severity"] + if config_kwargs.get("notifications_min_severity") is not None: + config_kwargs["notifications_min_severity"] = getattr( + config_kwargs["notifications_min_severity"], "value", + config_kwargs["notifications_min_severity"] ) diff --git a/src/neo4j/_async/work/session.py b/src/neo4j/_async/work/session.py index 0897bcfb..acab6f0f 100644 --- a/src/neo4j/_async/work/session.py +++ b/src/neo4j/_async/work/session.py @@ -20,7 +20,6 @@ import asyncio import typing as t -import warnings from logging import getLogger from random import random from time import perf_counter @@ -28,10 +27,7 @@ from ..._async_compat import async_sleep from ..._async_compat.util import AsyncUtil from ..._conf import SessionConfig -from ..._meta import ( - deprecated, - PreviewWarning, -) +from ..._meta import deprecated from ..._util import ContextBool from ..._work import Query from ...api import ( @@ -108,14 +104,9 @@ class AsyncSession(AsyncWorkspace): def __init__(self, pool, session_config): assert isinstance(session_config, SessionConfig) if session_config.auth is not None: - with warnings.catch_warnings(): - warnings.filterwarnings( - "ignore", message=r".*\bAuth managers\b.*", - category=PreviewWarning - ) - session_config.auth = AsyncAuthManagers.static( - session_config.auth - ) + session_config.auth = AsyncAuthManagers.static._without_warning( + session_config.auth + ) super().__init__(pool, session_config) self._config = session_config self._initialize_bookmarks(session_config.bookmarks) diff --git a/src/neo4j/_auth_management.py b/src/neo4j/_auth_management.py index 577fcf2d..da9f28c5 100644 --- a/src/neo4j/_auth_management.py +++ b/src/neo4j/_auth_management.py @@ -24,13 +24,9 @@ import abc import time import typing as t -import warnings from dataclasses import dataclass -from ._meta import ( - preview, - PreviewWarning, -) +from ._meta import preview from .api import _TAuth from .exceptions import Neo4jError @@ -89,11 +85,9 @@ def expires_in(self, seconds: float) -> "ExpiringAuth": .. versionadded:: 5.9 """ - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", - message=r"^Auth managers\b.*", - category=PreviewWarning) - return ExpiringAuth(self.auth, time.time() + seconds) + return ExpiringAuth._without_warning( # type: ignore + self.auth, time.time() + seconds + ) def expiring_auth_has_expired(auth: ExpiringAuth) -> bool: diff --git a/src/neo4j/_conf.py b/src/neo4j/_conf.py index b9b1d35f..9d743f57 100644 --- a/src/neo4j/_conf.py +++ b/src/neo4j/_conf.py @@ -18,14 +18,12 @@ from __future__ import annotations -import warnings from abc import ABCMeta from collections.abc import Mapping from ._meta import ( deprecation_warn, experimental_warn, - ExperimentalWarning, ) from .api import ( DEFAULT_DATABASE, @@ -271,15 +269,15 @@ def _consume(cls, data): config[key] = value return cls(config) - def __update(self, data): + def __update(self, data, warn=True): data_dict = dict(iter_items(data)) def set_attr(k, v): if k in self.keys(): - if k in self._deprecated_options(): + if warn and k in self._deprecated_options(): deprecation_warn("The '{}' config key is " "deprecated.".format(k)) - if k in self._experimental_options(): + if warn and k in self._experimental_options(): experimental_warn( "The '{}' config key is experimental. " "It might be changed or removed any time even without " @@ -293,10 +291,11 @@ def set_attr(k, v): "Cannot specify both '{}' and '{}' in config" .format(k0, k) ) - deprecation_warn( - "The '{}' config key is deprecated, please use '{}' " - "instead".format(k, k0) - ) + if warn: + deprecation_warn( + "The '{}' config key is deprecated, please use '{}' " + "instead".format(k, k0) + ) if k in self._deprecated_aliases(): set_attr(k0, v) else: # k in self._deprecated_alternatives: @@ -322,10 +321,7 @@ def set_attr(k, v): def __init__(self, *args, **kwargs): for arg in args: if isinstance(arg, Config): - with warnings.catch_warnings(): - for cat in (DeprecationWarning, ExperimentalWarning): - warnings.filterwarnings("ignore", category=cat) - self.__update(arg) + self.__update(arg, warn=False) else: self.__update(arg) self.__update(kwargs) diff --git a/src/neo4j/_meta.py b/src/neo4j/_meta.py index 10934763..099d94b2 100644 --- a/src/neo4j/_meta.py +++ b/src/neo4j/_meta.py @@ -28,7 +28,8 @@ from warnings import warn -_FuncT = t.TypeVar("_FuncT", bound=t.Callable) +if t.TYPE_CHECKING: + _FuncT = t.TypeVar("_FuncT", bound=t.Callable) # Can be automatically overridden in builds @@ -132,22 +133,6 @@ def foo(x): .. deprecated:: 5.8 we now use "preview" instead of "experimental". """ - def decorator(f): - if asyncio.iscoroutinefunction(f): - @wraps(f) - async def inner(*args, **kwargs): - experimental_warn(message, stack_level=2) - return await f(*args, **kwargs) - - return inner - else: - @wraps(f) - def inner(*args, **kwargs): - experimental_warn(message, stack_level=2) - return f(*args, **kwargs) - - return inner - return _make_warning_decorator(message, experimental_warn) @@ -173,7 +158,6 @@ def preview(message) -> t.Callable[[_FuncT], _FuncT]: def foo(x): pass """ - return _make_warning_decorator(message, preview_warn) @@ -196,16 +180,24 @@ async def inner(*args, **kwargs): warning_func(message, stack_level=2) return await f(*args, **kwargs) + inner._without_warning = f return inner if isclass(f): if hasattr(f, "__init__"): original_init = f.__init__ + @wraps(original_init) - def inner(*args, **kwargs): + def inner(self, *args, **kwargs): warning_func(message, stack_level=2) - return original_init(*args, **kwargs) + return original_init(self, *args, **kwargs) + + def _without_warning(cls, *args, **kwargs): + obj = cls.__new__(cls, *args, **kwargs) + original_init(obj, *args, **kwargs) + return obj f.__init__ = inner + f._without_warning = classmethod(_without_warning) return f raise TypeError( "Cannot decorate class without __init__" @@ -216,6 +208,7 @@ def inner(*args, **kwargs): warning_func(message, stack_level=2) return f(*args, **kwargs) + inner._without_warning = f return inner return decorator diff --git a/src/neo4j/_sync/auth_management.py b/src/neo4j/_sync/auth_management.py index 74cc40f5..c5f6f4e7 100644 --- a/src/neo4j/_sync/auth_management.py +++ b/src/neo4j/_sync/auth_management.py @@ -22,7 +22,6 @@ import typing as t -import warnings from logging import getLogger from .._async_compat.concurrency import Lock @@ -31,10 +30,7 @@ expiring_auth_has_expired, ExpiringAuth, ) -from .._meta import ( - preview, - PreviewWarning, -) +from .._meta import preview # work around for https://github.com/sphinx-doc/sphinx/pull/10880 # make sure TAuth is resolved in the docs, else they're pretty useless @@ -215,11 +211,9 @@ def auth_provider(): handled_codes = frozenset(("Neo.ClientError.Security.Unauthorized",)) def wrapped_provider() -> ExpiringAuth: - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", - message=r"^Auth managers\b.*", - category=PreviewWarning) - return ExpiringAuth(provider()) + return ExpiringAuth._without_warning( # type: ignore + provider() + ) return Neo4jAuthTokenManager(wrapped_provider, handled_codes) diff --git a/src/neo4j/_sync/driver.py b/src/neo4j/_sync/driver.py index 71a34554..2b9bb4b2 100644 --- a/src/neo4j/_sync/driver.py +++ b/src/neo4j/_sync/driver.py @@ -20,7 +20,6 @@ import asyncio import typing as t -import warnings if t.TYPE_CHECKING: @@ -47,7 +46,6 @@ experimental_warn, preview, preview_warn, - PreviewWarning, unclosed_resource_warn, ) from .._work import EagerResult @@ -195,12 +193,7 @@ def driver( driver_type, security_type, parsed = parse_neo4j_uri(uri) if not isinstance(auth, AuthManager): - with warnings.catch_warnings(): - warnings.filterwarnings( - "ignore", message=r".*\bAuth managers\b.*", - category=PreviewWarning - ) - auth = AuthManagers.static(auth) + auth = AuthManagers.static._without_warning(auth) else: preview_warn("Auth managers are a preview feature.", stack_level=2) @@ -500,13 +493,6 @@ def encrypted(self) -> bool: """Indicate whether the driver was configured to use encryption.""" return bool(self._pool.pool_config.encrypted) - def _prepare_session_config(self, **config): - if "auth" in config: - preview_warn("User switching is a preview feature.", - stack_level=3) - _normalize_notifications_config(config) - return config - if t.TYPE_CHECKING: def session( @@ -548,7 +534,25 @@ def session(self, **config) -> Session: :returns: new :class:`neo4j.Session` object """ - raise NotImplementedError + session_config = self._read_session_config(config) + return self._session(session_config) + + def _session(self, session_config) -> Session: + return Session(self._pool, session_config) + + def _read_session_config(self, config_kwargs, preview_check=True): + config = self._prepare_session_config(preview_check, config_kwargs) + session_config = SessionConfig(self._default_workspace_config, + config) + return session_config + + @classmethod + def _prepare_session_config(cls, preview_check, config_kwargs): + if preview_check and "auth" in config_kwargs: + preview_warn("User switching is a preview feature.", + stack_level=5) + _normalize_notifications_config(config_kwargs) + return config_kwargs def close(self) -> None: """ Shut down, closing any open connections in the pool. @@ -843,14 +847,16 @@ def example(driver: neo4j.Driver) -> neo4j.Record:: bookmark_manager_ = self._query_bookmark_manager assert bookmark_manager_ is not _default - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", - message=r"^User switching\b.*", - category=PreviewWarning) - session = self.session(database=database_, - impersonated_user=impersonated_user_, - bookmark_manager=bookmark_manager_, - auth=auth_) + session_config = self._read_session_config( + { + "database": database_, + "impersonated_user": impersonated_user_, + "bookmark_manager": bookmark_manager_, + "auth": auth_, + }, + preview_check=False + ) + session = self._session(session_config) with session: if routing_ == RoutingControl.WRITE: executor = session.execute_write @@ -962,7 +968,8 @@ def verify_connectivity(self, **config) -> None: "changed or removed in any future version without prior " "notice." ) - self._get_server_info() + session_config = self._read_session_config(config) + self._get_server_info(session_config) if t.TYPE_CHECKING: @@ -1033,7 +1040,8 @@ def get_server_info(self, **config) -> ServerInfo: "changed or removed in any future version without prior " "notice." ) - return self._get_server_info() + session_config = self._read_session_config(config) + return self._get_server_info(session_config) def supports_multi_db(self) -> bool: """ Check if the server or cluster supports multi-databases. @@ -1048,7 +1056,8 @@ def supports_multi_db(self) -> bool: won't throw a :exc:`ConfigurationError` when trying to use this driver feature. """ - with self.session() as session: + session_config = self._read_session_config({}, preview_check=False) + with self._session(session_config) as session: session._connect(READ_ACCESS) assert session._connection return session._connection.supports_multiple_databases @@ -1129,30 +1138,24 @@ def verify_authentication( "changed or removed in any future version without prior " "notice." ) - config["auth"] = auth if "database" not in config: config["database"] = "system" - try: - with warnings.catch_warnings(): - warnings.filterwarnings( - "ignore", message=r"^User switching\b.*", - category=PreviewWarning - ) - session = self.session(**config) - with session as session: + session_config = self._read_session_config(config) + session_config = SessionConfig(session_config, {"auth": auth}) + with self._session(session_config) as session: + try: session._verify_authentication() - except Neo4jError as exc: - if exc.code in ( - "Neo.ClientError.Security.CredentialsExpired", - "Neo.ClientError.Security.Forbidden", - "Neo.ClientError.Security.TokenExpired", - "Neo.ClientError.Security.Unauthorized", - ): - return False - raise + except Neo4jError as exc: + if exc.code in ( + "Neo.ClientError.Security.CredentialsExpired", + "Neo.ClientError.Security.Forbidden", + "Neo.ClientError.Security.TokenExpired", + "Neo.ClientError.Security.Unauthorized", + ): + return False + raise return True - def supports_session_auth(self) -> bool: """Check if the remote supports connection re-authentication. @@ -1169,13 +1172,14 @@ def supports_session_auth(self) -> bool: .. versionadded:: 5.8 """ - with self.session() as session: + session_config = self._read_session_config({}, preview_check=False) + with self._session(session_config) as session: session._connect(READ_ACCESS) assert session._connection return session._connection.supports_re_auth - def _get_server_info(self, **config) -> ServerInfo: - with self.session(**config) as session: + def _get_server_info(self, session_config) -> ServerInfo: + with self._session(session_config) as session: return session._get_server_info() @@ -1224,21 +1228,6 @@ def __init__(self, pool, default_workspace_config): Driver.__init__(self, pool, default_workspace_config) self._default_workspace_config = default_workspace_config - if not t.TYPE_CHECKING: - - def session(self, **config) -> Session: - """ - :param config: The values that can be specified are found in - :class: `neo4j.SessionConfig` - - :returns: - :rtype: :class: `neo4j.Session` - """ - config = self._prepare_session_config(**config) - session_config = SessionConfig(self._default_workspace_config, - config) - return Session(self._pool, session_config) - class Neo4jDriver(_Routing, Driver): """:class:`.Neo4jDriver` is instantiated for ``neo4j`` URIs. The @@ -1263,23 +1252,15 @@ def __init__(self, pool, default_workspace_config): _Routing.__init__(self, [pool.address]) Driver.__init__(self, pool, default_workspace_config) - if not t.TYPE_CHECKING: - - def session(self, **config) -> Session: - config = self._prepare_session_config(**config) - session_config = SessionConfig(self._default_workspace_config, - config) - return Session(self._pool, session_config) - -def _normalize_notifications_config(config): - if config.get("notifications_disabled_categories") is not None: - config["notifications_disabled_categories"] = [ +def _normalize_notifications_config(config_kwargs): + if config_kwargs.get("notifications_disabled_categories") is not None: + config_kwargs["notifications_disabled_categories"] = [ getattr(e, "value", e) - for e in config["notifications_disabled_categories"] + for e in config_kwargs["notifications_disabled_categories"] ] - if config.get("notifications_min_severity") is not None: - config["notifications_min_severity"] = getattr( - config["notifications_min_severity"], "value", - config["notifications_min_severity"] + if config_kwargs.get("notifications_min_severity") is not None: + config_kwargs["notifications_min_severity"] = getattr( + config_kwargs["notifications_min_severity"], "value", + config_kwargs["notifications_min_severity"] ) diff --git a/src/neo4j/_sync/work/session.py b/src/neo4j/_sync/work/session.py index b4b321f6..a40e7a0c 100644 --- a/src/neo4j/_sync/work/session.py +++ b/src/neo4j/_sync/work/session.py @@ -20,7 +20,6 @@ import asyncio import typing as t -import warnings from logging import getLogger from random import random from time import perf_counter @@ -28,10 +27,7 @@ from ..._async_compat import sleep from ..._async_compat.util import Util from ..._conf import SessionConfig -from ..._meta import ( - deprecated, - PreviewWarning, -) +from ..._meta import deprecated from ..._util import ContextBool from ..._work import Query from ...api import ( @@ -108,14 +104,9 @@ class Session(Workspace): def __init__(self, pool, session_config): assert isinstance(session_config, SessionConfig) if session_config.auth is not None: - with warnings.catch_warnings(): - warnings.filterwarnings( - "ignore", message=r".*\bAuth managers\b.*", - category=PreviewWarning - ) - session_config.auth = AuthManagers.static( - session_config.auth - ) + session_config.auth = AuthManagers.static._without_warning( + session_config.auth + ) super().__init__(pool, session_config) self._config = session_config self._initialize_bookmarks(session_config.bookmarks) diff --git a/src/neo4j/api.py b/src/neo4j/api.py index 457cadc5..9f7e80e0 100644 --- a/src/neo4j/api.py +++ b/src/neo4j/api.py @@ -189,6 +189,7 @@ def custom_auth( # TODO: 6.0 - remove this class +@deprecated("Use the `Bookmarks` class instead.") class Bookmark: """A Bookmark object contains an immutable list of bookmark string values. @@ -198,8 +199,6 @@ class Bookmark: `Bookmark` will be removed in version 6.0. Use :class:`Bookmarks` instead. """ - - @deprecated("Use the `Bookmarks`` class instead.") def __init__(self, *values: str) -> None: if values: bookmarks = []