From e904a208022b042a2e5f4f5e1f788c34bd306714 Mon Sep 17 00:00:00 2001 From: Robsdedude Date: Mon, 15 May 2023 13:16:32 +0200 Subject: [PATCH] Fixing documentation and type hints * When renaming some of the re-auth APIs before stabilizing them in 3.8, some references in the docs were missed. * The docs for `ExpiringAuth` was completely missing becuase the `@preview` decorator broke sphinx. * Fix typing change in `datetime.replace` breaking us (arguments were changed from type `int` to `SupportsIndex`). As a virtual subclass, our custom temporal types should follow this change. * Fix broken layout of `execute_query` parameter docs. --- docs/source/api.rst | 14 +++--- docs/source/async_api.rst | 14 +++--- src/neo4j/_async/driver.py | 7 ++- src/neo4j/_auth_management.py | 7 +-- src/neo4j/_meta.py | 84 +++++++++++++++++++++-------------- src/neo4j/_sync/driver.py | 7 ++- src/neo4j/time/__init__.py | 74 +++++++++++++++--------------- 7 files changed, 110 insertions(+), 97 deletions(-) diff --git a/docs/source/api.rst b/docs/source/api.rst index 46b828b0f..970d08d28 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -160,11 +160,11 @@ Closing a driver will immediately shut down all connections in the pool. query, use :meth:`neo4j.Driver.verify_connectivity`. .. autoclass:: neo4j.Driver() - :members: session, query_bookmark_manager, encrypted, close, + :members: session, execute_query_bookmark_manager, encrypted, close, verify_connectivity, get_server_info, verify_authentication, supports_session_auth, supports_multi_db - .. method:: execute_query(query, parameters_=None,routing_=neo4j.RoutingControl.WRITE, database_=None, impersonated_user_=None, bookmark_manager_=self.query_bookmark_manager, result_transformer_=Result.to_eager_result, **kwargs) + .. method:: execute_query(query, parameters_=None,routing_=neo4j.RoutingControl.WRITE, database_=None, impersonated_user_=None, bookmark_manager_=self.execute_query_bookmark_manager, result_transformer_=Result.to_eager_result, **kwargs) Execute a query in a transaction function and return all results. @@ -283,9 +283,8 @@ Closing a driver will immediately shut down all connections in the pool. https://github.com/neo4j/neo4j-python-driver/wiki/preview-features See also the Session config :ref:`session-auth-ref`. - :type auth_: typing.Union[ - typing.Tuple[typing.Any, typing.Any], neo4j.Auth, None - ] + :type auth_: + typing.Union[typing.Tuple[typing.Any, typing.Any], neo4j.Auth, None] :param result_transformer_: A function that gets passed the :class:`neo4j.Result` object resulting from the query and converts it to a different type. The @@ -354,12 +353,11 @@ Closing a driver will immediately shut down all connections in the pool. If present, the bookmark manager is used to keep the query causally consistent with all work executed using the same bookmark manager. - Defaults to the driver's :attr:`.query_bookmark_manager`. + Defaults to the driver's :attr:`.execute_query_bookmark_manager`. Pass :data:`None` to disable causal consistency. :type bookmark_manager_: - typing.Union[neo4j.BookmarkManager, neo4j.BookmarkManager, - None] + typing.Union[BookmarkManager, BookmarkManager, None] :param kwargs: additional keyword parameters. None of these can end with a single underscore. This is to avoid collisions with the keyword configuration parameters of this method. If you need to diff --git a/docs/source/async_api.rst b/docs/source/async_api.rst index c3593c34b..2dd29172f 100644 --- a/docs/source/async_api.rst +++ b/docs/source/async_api.rst @@ -149,11 +149,11 @@ Closing a driver will immediately shut down all connections in the pool. query, use :meth:`neo4j.AsyncDriver.verify_connectivity`. .. autoclass:: neo4j.AsyncDriver() - :members: session, query_bookmark_manager, encrypted, close, + :members: session, execute_query_bookmark_manager, encrypted, close, verify_connectivity, get_server_info, verify_authentication, supports_session_auth, supports_multi_db - .. method:: execute_query(query, parameters_=None, routing_=neo4j.RoutingControl.WRITE, database_=None, impersonated_user_=None, bookmark_manager_=self.query_bookmark_manager, result_transformer_=AsyncResult.to_eager_result, **kwargs) + .. method:: execute_query(query, parameters_=None, routing_=neo4j.RoutingControl.WRITE, database_=None, impersonated_user_=None, bookmark_manager_=self.execute_query_bookmark_manager, result_transformer_=AsyncResult.to_eager_result, **kwargs) :async: Execute a query in a transaction function and return all results. @@ -273,9 +273,8 @@ Closing a driver will immediately shut down all connections in the pool. https://github.com/neo4j/neo4j-python-driver/wiki/preview-features See also the Session config :ref:`session-auth-ref`. - :type auth_: typing.Union[ - typing.Tuple[typing.Any, typing.Any], neo4j.Auth, None - ] + :type auth_: + typing.Union[typing.Tuple[typing.Any, typing.Any], neo4j.Auth, None] :param result_transformer_: A function that gets passed the :class:`neo4j.AsyncResult` object resulting from the query and converts it to a different type. The @@ -344,12 +343,11 @@ Closing a driver will immediately shut down all connections in the pool. If present, the bookmark manager is used to keep the query causally consistent with all work executed using the same bookmark manager. - Defaults to the driver's :attr:`.query_bookmark_manager`. + Defaults to the driver's :attr:`.execute_query_bookmark_manager`. Pass :data:`None` to disable causal consistency. :type bookmark_manager_: - typing.Union[neo4j.AsyncBookmarkManager, neo4j.BookmarkManager, - None] + typing.Union[AsyncBookmarkManager, BookmarkManager, None] :param kwargs: additional keyword parameters. None of these can end with a single underscore. This is to avoid collisions with the keyword configuration parameters of this method. If you need to diff --git a/src/neo4j/_async/driver.py b/src/neo4j/_async/driver.py index 4f4bfde50..ff7a95b55 100644 --- a/src/neo4j/_async/driver.py +++ b/src/neo4j/_async/driver.py @@ -805,12 +805,11 @@ async def example(driver: neo4j.AsyncDriver) -> neo4j.Record:: If present, the bookmark manager is used to keep the query causally consistent with all work executed using the same bookmark manager. - Defaults to the driver's :attr:`.query_bookmark_manager`. + Defaults to the driver's :attr:`.execute_query_bookmark_manager`. Pass :data:`None` to disable causal consistency. :type bookmark_manager_: - typing.Union[neo4j.AsyncBookmarkManager, neo4j.BookmarkManager, - None] + typing.Union[AsyncBookmarkManager, BookmarkManager, None] :param kwargs: additional keyword parameters. None of these can end with a single underscore. This is to avoid collisions with the keyword configuration parameters of this method. If you need to @@ -875,7 +874,7 @@ def execute_query_bookmark_manager(self) -> AsyncBookmarkManager: async def example(driver: neo4j.AsyncDriver) -> None: await driver.execute_query("") async with driver.session( - bookmark_manager=driver.query_bookmark_manager + bookmark_manager=driver.execute_query_bookmark_manager ) as session: # every query inside this session will be causally chained # (i.e., can read what was written by ) diff --git a/src/neo4j/_auth_management.py b/src/neo4j/_auth_management.py index 69bfcec8c..14ff89db0 100644 --- a/src/neo4j/_auth_management.py +++ b/src/neo4j/_auth_management.py @@ -34,8 +34,8 @@ class ExpiringAuth: """Represents potentially expiring authentication information. - This class is used with :meth:`.AuthManagers.temporal` and - :meth:`.AsyncAuthManagers.temporal`. + This class is used with :meth:`.AuthManagers.expiration_based` and + :meth:`.AsyncAuthManagers.expiration_based`. :param auth: The authentication information. :param expires_in: The number of seconds until the authentication @@ -47,7 +47,8 @@ class ExpiringAuth: See also https://github.com/neo4j/neo4j-python-driver/wiki/preview-features .. seealso:: - :meth:`.AuthManagers.temporal`, :meth:`.AsyncAuthManagers.temporal` + :meth:`.AuthManagers.expiration_based`, + :meth:`.AsyncAuthManagers.expiration_based` .. versionadded:: 5.8 """ diff --git a/src/neo4j/_meta.py b/src/neo4j/_meta.py index d01c500d1..48b751a36 100644 --- a/src/neo4j/_meta.py +++ b/src/neo4j/_meta.py @@ -16,10 +16,13 @@ # limitations under the License. +from __future__ import annotations + import asyncio import tracemalloc import typing as t from functools import wraps +from inspect import isclass from warnings import warn @@ -67,23 +70,7 @@ def foo(x): pass """ - def decorator(f): - if asyncio.iscoroutinefunction(f): - @wraps(f) - async def inner(*args, **kwargs): - deprecation_warn(message, stack_level=2) - return await f(*args, **kwargs) - - return inner - else: - @wraps(f) - def inner(*args, **kwargs): - deprecation_warn(message, stack_level=2) - return f(*args, **kwargs) - - return inner - - return decorator + return _make_warning_decorator(message, deprecation_warn) def deprecated_property(message: str): @@ -104,20 +91,6 @@ def experimental_warn(message, stack_level=1): warn(message, category=ExperimentalWarning, stacklevel=stack_level + 1) -class PreviewWarning(Warning): - """ Base class for warnings about experimental features. - """ - - -def preview_warn(message, stack_level=1): - message += ( - " It might be changed without following the deprecation policy. " - "See also " - "https://github.com/neo4j/neo4j-python-driver/wiki/preview-features." - ) - warn(message, category=PreviewWarning, stacklevel=stack_level + 1) - - def experimental(message) -> t.Callable[[_FuncT], _FuncT]: """ Decorator for tagging experimental functions and methods. @@ -147,7 +120,21 @@ def inner(*args, **kwargs): return inner - return decorator + return _make_warning_decorator(message, experimental_warn) + + +class PreviewWarning(Warning): + """ Base class for warnings about experimental features. + """ + + +def preview_warn(message, stack_level=1): + message += ( + " It might be changed without following the deprecation policy. " + "See also " + "https://github.com/neo4j/neo4j-python-driver/wiki/preview-features." + ) + warn(message, category=PreviewWarning, stacklevel=stack_level + 1) def preview(message) -> t.Callable[[_FuncT], _FuncT]: @@ -158,18 +145,47 @@ def preview(message) -> t.Callable[[_FuncT], _FuncT]: def foo(x): pass """ + + return _make_warning_decorator(message, preview_warn) + + +if t.TYPE_CHECKING: + class _WarningFunc(t.Protocol): + def __call__(self, message: str, stack_level: int = 1) -> None: + ... +else: + _WarningFunc = object + + +def _make_warning_decorator( + message: str, + warning_func: _WarningFunc, +) -> t.Callable[[_FuncT], _FuncT]: def decorator(f): if asyncio.iscoroutinefunction(f): @wraps(f) async def inner(*args, **kwargs): - preview_warn(message, stack_level=2) + warning_func(message, stack_level=2) return await f(*args, **kwargs) return inner + if isclass(f): + if hasattr(f, "__init__"): + original_init = f.__init__ + @wraps(original_init) + def inner(*args, **kwargs): + warning_func(message, stack_level=2) + return original_init(*args, **kwargs) + + f.__init__ = inner + return f + raise TypeError( + "Cannot decorate class without __init__" + ) else: @wraps(f) def inner(*args, **kwargs): - preview_warn(message, stack_level=2) + warning_func(message, stack_level=2) return f(*args, **kwargs) return inner diff --git a/src/neo4j/_sync/driver.py b/src/neo4j/_sync/driver.py index ee8053fdc..c97fa0c94 100644 --- a/src/neo4j/_sync/driver.py +++ b/src/neo4j/_sync/driver.py @@ -804,12 +804,11 @@ def example(driver: neo4j.Driver) -> neo4j.Record:: If present, the bookmark manager is used to keep the query causally consistent with all work executed using the same bookmark manager. - Defaults to the driver's :attr:`.query_bookmark_manager`. + Defaults to the driver's :attr:`.execute_query_bookmark_manager`. Pass :data:`None` to disable causal consistency. :type bookmark_manager_: - typing.Union[neo4j.BookmarkManager, neo4j.BookmarkManager, - None] + typing.Union[BookmarkManager, BookmarkManager, None] :param kwargs: additional keyword parameters. None of these can end with a single underscore. This is to avoid collisions with the keyword configuration parameters of this method. If you need to @@ -874,7 +873,7 @@ def execute_query_bookmark_manager(self) -> BookmarkManager: def example(driver: neo4j.Driver) -> None: driver.execute_query("") with driver.session( - bookmark_manager=driver.query_bookmark_manager + bookmark_manager=driver.execute_query_bookmark_manager ) as session: # every query inside this session will be causally chained # (i.e., can read what was written by ) diff --git a/src/neo4j/time/__init__.py b/src/neo4j/time/__init__.py index 04bba43e6..e6cb583d2 100644 --- a/src/neo4j/time/__init__.py +++ b/src/neo4j/time/__init__.py @@ -25,6 +25,7 @@ from __future__ import annotations import re +import typing import typing as t from datetime import ( date, @@ -1232,9 +1233,9 @@ def __deepcopy__(self, *args, **kwargs) -> Date: def replace( self, - year: int = ..., - month: int = ..., - day: int = ..., + year: te.SupportsIndex = ..., + month: te.SupportsIndex = ..., + day: te.SupportsIndex = ..., **kwargs: object ) -> Date: ... @@ -1245,16 +1246,16 @@ def replace(self, **kwargs) -> Date: """Return a :class:`.Date` with one or more components replaced. :Keyword Arguments: - * **year** (`int`): overwrite the year - - default: `self.year` - * **month** (`int`): overwrite the month - - default: `self.month` - * **day** (`int`): overwrite the day - - default: `self.day` + * **year** (:class:`typing.SupportsIndex`): + overwrite the year - default: `self.year` + * **month** (:class:`typing.SupportsIndex`): + overwrite the month - default: `self.month` + * **day** (:class:`typing.SupportsIndex`): + overwrite the day - default: `self.day` """ - return Date(kwargs.get("year", self.__year), - kwargs.get("month", self.__month), - kwargs.get("day", self.__day)) + return Date(int(kwargs.get("year", self.__year)), + int(kwargs.get("month", self.__month)), + int(kwargs.get("day", self.__day))) def time_tuple(self) -> struct_time: """Convert the date to :class:`time.struct_time`.""" @@ -1766,10 +1767,10 @@ def __deepcopy__(self, *args, **kwargs) -> Time: def replace( # type: ignore[override] self, - hour: int = ..., - minute: int = ..., - second: int = ..., - nanosecond: int = ..., + hour: te.SupportsIndex = ..., + minute: te.SupportsIndex = ..., + second: te.SupportsIndex = ..., + nanosecond: te.SupportsIndex = ..., tzinfo: t.Optional[_tzinfo] = ..., **kwargs: object ) -> Time: @@ -1781,21 +1782,22 @@ def replace(self, **kwargs) -> Time: """Return a :class:`.Time` with one or more components replaced. :Keyword Arguments: - * **hour** (`int`): overwrite the hour - - default: `self.hour` - * **minute** (`int`): overwrite the minute - - default: `self.minute` - * **second** (`int`): overwrite the second - - default: `int(self.second)` - * **nanosecond** (`int`): overwrite the nanosecond - - default: `self.nanosecond` - * **tzinfo** (`datetime.tzinfo` or `None`): + * **hour** (:class:`typing.SupportsIndex`): + overwrite the hour - default: `self.hour` + * **minute** (:class:`typing.SupportsIndex`): + overwrite the minute - default: `self.minute` + * **second** (:class:`typing.SupportsIndex`): + overwrite the second - default: `int(self.second)` + * **nanosecond** (:class:`typing.SupportsIndex`): + overwrite the nanosecond - default: `self.nanosecond` + * **tzinfo** (:class:`datetime.tzinfo` or `None`): overwrite the timezone - default: `self.tzinfo` """ - return Time(hour=kwargs.get("hour", self.__hour), - minute=kwargs.get("minute", self.__minute), - second=kwargs.get("second", self.__second), - nanosecond=kwargs.get("nanosecond", self.__nanosecond), + return Time(hour=int(kwargs.get("hour", self.__hour)), + minute=int(kwargs.get("minute", self.__minute)), + second=int(kwargs.get("second", self.__second)), + nanosecond=int(kwargs.get("nanosecond", + self.__nanosecond)), tzinfo=kwargs.get("tzinfo", self.__tzinfo)) def _utc_offset(self, dt=None): @@ -2516,13 +2518,13 @@ def timetz(self) -> Time: def replace( # type: ignore[override] self, - year: int = ..., - month: int = ..., - day: int = ..., - hour: int = ..., - minute: int = ..., - second: int = ..., - nanosecond: int = ..., + year: te.SupportsIndex = ..., + month: te.SupportsIndex = ..., + day: te.SupportsIndex = ..., + hour: te.SupportsIndex = ..., + minute: te.SupportsIndex = ..., + second: te.SupportsIndex = ..., + nanosecond: te.SupportsIndex = ..., tzinfo: t.Optional[_tzinfo] = ..., **kwargs: object ) -> DateTime: