diff --git a/docs/source/api.rst b/docs/source/api.rst index 35041a855..c9f45e45d 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -653,16 +653,13 @@ Specify a client certificate or certificate provider for mutual TLS (mTLS) authe This setting does not have any effect if ``encrypted`` is set to ``False`` (and the URI scheme is ``bolt://`` or ``neo4j://``) or a custom ``ssl_context`` is configured. -**This is a preview** (see :ref:`filter-warnings-ref`). -It might be changed without following the deprecation policy. -See also -https://github.com/neo4j/neo4j-python-driver/wiki/preview-features - :Type: :class:`.ClientCertificate`, :class:`.ClientCertificateProvider` or :data:`None`. :Default: :data:`None` .. versionadded:: 5.19 +.. versionchanged:: 5.27 Stabilized from preview. + .. autoclass:: neo4j.auth_management.ClientCertificate :members: diff --git a/docs/source/async_api.rst b/docs/source/async_api.rst index 483b70e74..74ce23a52 100644 --- a/docs/source/async_api.rst +++ b/docs/source/async_api.rst @@ -446,16 +446,13 @@ Specify a client certificate or certificate provider for mutual TLS (mTLS) authe This setting does not have any effect if ``encrypted`` is set to ``False`` (and the URI scheme is ``bolt://`` or ``neo4j://``) or a custom ``ssl_context`` is configured. -**This is a preview** (see :ref:`filter-warnings-ref`). -It might be changed without following the deprecation policy. -See also -https://github.com/neo4j/neo4j-python-driver/wiki/preview-features - :Type: :class:`.ClientCertificate`, :class:`.AsyncClientCertificateProvider` or :data:`None`. :Default: :data:`None` .. versionadded:: 5.19 +.. versionchanged:: 5.27 Stabilized from preview. + .. autoclass:: neo4j.auth_management.AsyncClientCertificateProvider :members: diff --git a/src/neo4j/_async/auth_management.py b/src/neo4j/_async/auth_management.py index bf527e1d3..268d4306a 100644 --- a/src/neo4j/_async/auth_management.py +++ b/src/neo4j/_async/auth_management.py @@ -31,7 +31,6 @@ expiring_auth_has_expired, ExpiringAuth, ) -from .._meta import preview if t.TYPE_CHECKING: @@ -331,12 +330,6 @@ class AsyncRotatingClientCertificateProvider(AsyncClientCertificateProvider): From that point on, the new certificate will be used for all new connections until :meth:`update_certificate` is called again and so on. - **This is a preview** (see :ref:`filter-warnings-ref`). - It might be changed without following the deprecation policy. - - See also - https://github.com/neo4j/neo4j-python-driver/wiki/preview-features - Example:: from neo4j import AsyncGraphDatabase @@ -386,6 +379,8 @@ class AsyncRotatingClientCertificateProvider(AsyncClientCertificateProvider): implementation internal. This entails removing the possibility to directly instantiate this class. Please use the factory method :meth:`.AsyncClientCertificateProviders.rotating` instead. + + .. versionchanged:: 5.27 Stabilized from preview. """ @abc.abstractmethod @@ -414,17 +409,12 @@ class AsyncClientCertificateProviders: """ A collection of :class:`.AsyncClientCertificateProvider` factories. - **This is a preview** (see :ref:`filter-warnings-ref`). - It might be changed without following the deprecation policy. - - See also - https://github.com/neo4j/neo4j-python-driver/wiki/preview-features - .. versionadded:: 5.19 + + .. versionchanged:: 5.27 Stabilized from preview. """ @staticmethod - @preview("Mutual TLS is a preview feature.") def static(cert: ClientCertificate) -> AsyncClientCertificateProvider: """ Create a static client certificate provider. @@ -435,7 +425,6 @@ def static(cert: ClientCertificate) -> AsyncClientCertificateProvider: return _AsyncStaticClientCertificateProvider(cert) @staticmethod - @preview("Mutual TLS is a preview feature.") def rotating( initial_cert: ClientCertificate, ) -> AsyncRotatingClientCertificateProvider: diff --git a/src/neo4j/_async/driver.py b/src/neo4j/_async/driver.py index 627fa14d7..c33f9894d 100644 --- a/src/neo4j/_async/driver.py +++ b/src/neo4j/_async/driver.py @@ -213,8 +213,6 @@ def driver( config["client_certificate"] = ( _AsyncStaticClientCertificateProvider(client_certificate) ) - if client_certificate is not None: - preview_warn("Mutual TLS is a preview feature.", stack_level=2) # TODO: 6.0 - remove "trust" config option if "trust" in config and config["trust"] not in { diff --git a/src/neo4j/_auth_management.py b/src/neo4j/_auth_management.py index 409d9ba94..79eea256c 100644 --- a/src/neo4j/_auth_management.py +++ b/src/neo4j/_auth_management.py @@ -21,8 +21,6 @@ import typing as t from dataclasses import dataclass -from ._meta import preview - if t.TYPE_CHECKING: from os import PathLike @@ -215,7 +213,6 @@ async def handle_security_exception( ... -@preview("Mutual TLS is a preview feature.") @dataclass class ClientCertificate: """ @@ -224,13 +221,9 @@ class ClientCertificate: The attributes are the same as the arguments to :meth:`ssl.SSLContext.load_cert_chain()`. - **This is a preview** (see :ref:`filter-warnings-ref`). - It might be changed without following the deprecation policy. - - See also - https://github.com/neo4j/neo4j-python-driver/wiki/preview-features - .. versionadded:: 5.19 + + .. versionchanged:: 5.27 Stabilized from preview. """ certfile: str | bytes | PathLike[str] | PathLike[bytes] @@ -267,13 +260,9 @@ class ClientCertificateProvider(_Protocol, metaclass=abc.ABCMeta): The provider **must not** interact with the driver in any way as this can cause deadlocks and undefined behaviour. - **This is a preview** (see :ref:`filter-warnings-ref`). - It might be changed without following the deprecation policy. - - See also - https://github.com/neo4j/neo4j-python-driver/wiki/preview-features - .. versionadded:: 5.19 + + .. versionchanged:: 5.27 Stabilized from preview. """ @abc.abstractmethod @@ -300,17 +289,13 @@ class AsyncClientCertificateProvider(_Protocol, metaclass=abc.ABCMeta): The package provides some default implementations of this class in :class:`.AsyncClientCertificateProviders` for convenience. - **This is a preview** (see :ref:`filter-warnings-ref`). - It might be changed without following the deprecation policy. - - See also - https://github.com/neo4j/neo4j-python-driver/wiki/preview-features - .. seealso:: :class:`.ClientCertificateProvider`, :class:`.AsyncClientCertificateProviders` .. versionadded:: 5.19 + + .. versionchanged:: 5.27 Stabilized from preview. """ @abc.abstractmethod diff --git a/src/neo4j/_sync/auth_management.py b/src/neo4j/_sync/auth_management.py index 493f91c65..87e65cd98 100644 --- a/src/neo4j/_sync/auth_management.py +++ b/src/neo4j/_sync/auth_management.py @@ -31,7 +31,6 @@ expiring_auth_has_expired, ExpiringAuth, ) -from .._meta import preview if t.TYPE_CHECKING: @@ -331,12 +330,6 @@ class RotatingClientCertificateProvider(ClientCertificateProvider): From that point on, the new certificate will be used for all new connections until :meth:`update_certificate` is called again and so on. - **This is a preview** (see :ref:`filter-warnings-ref`). - It might be changed without following the deprecation policy. - - See also - https://github.com/neo4j/neo4j-python-driver/wiki/preview-features - Example:: from neo4j import GraphDatabase @@ -386,6 +379,8 @@ class RotatingClientCertificateProvider(ClientCertificateProvider): implementation internal. This entails removing the possibility to directly instantiate this class. Please use the factory method :meth:`.ClientCertificateProviders.rotating` instead. + + .. versionchanged:: 5.27 Stabilized from preview. """ @abc.abstractmethod @@ -414,17 +409,12 @@ class ClientCertificateProviders: """ A collection of :class:`.ClientCertificateProvider` factories. - **This is a preview** (see :ref:`filter-warnings-ref`). - It might be changed without following the deprecation policy. - - See also - https://github.com/neo4j/neo4j-python-driver/wiki/preview-features - .. versionadded:: 5.19 + + .. versionchanged:: 5.27 Stabilized from preview. """ @staticmethod - @preview("Mutual TLS is a preview feature.") def static(cert: ClientCertificate) -> ClientCertificateProvider: """ Create a static client certificate provider. @@ -435,7 +425,6 @@ def static(cert: ClientCertificate) -> ClientCertificateProvider: return _StaticClientCertificateProvider(cert) @staticmethod - @preview("Mutual TLS is a preview feature.") def rotating( initial_cert: ClientCertificate, ) -> RotatingClientCertificateProvider: diff --git a/src/neo4j/_sync/driver.py b/src/neo4j/_sync/driver.py index 3b205a342..f1e63dc90 100644 --- a/src/neo4j/_sync/driver.py +++ b/src/neo4j/_sync/driver.py @@ -212,8 +212,6 @@ def driver( config["client_certificate"] = ( _StaticClientCertificateProvider(client_certificate) ) - if client_certificate is not None: - preview_warn("Mutual TLS is a preview feature.", stack_level=2) # TODO: 6.0 - remove "trust" config option if "trust" in config and config["trust"] not in { diff --git a/testkitbackend/_async/requests.py b/testkitbackend/_async/requests.py index 83e2475bb..3e26e3896 100644 --- a/testkitbackend/_async/requests.py +++ b/testkitbackend/_async/requests.py @@ -174,16 +174,10 @@ async def new_driver(backend, data): client_cert_provider_id ] data.mark_item_as_read_if_equals("clientCertificate", None) - expected_warnings.append( - (neo4j.PreviewWarning, r"Mutual TLS is a preview feature\.") - ) else: client_cert = fromtestkit.to_client_cert(data, "clientCertificate") if client_cert is not None: kwargs["client_certificate"] = client_cert - expected_warnings.append( - (neo4j.PreviewWarning, r"Mutual TLS is a preview feature\.") - ) if data["resolverRegistered"] or data["domainNameResolverRegistered"]: kwargs["resolver"] = resolution_func( backend, diff --git a/testkitbackend/_sync/requests.py b/testkitbackend/_sync/requests.py index 99693dacc..44a9233be 100644 --- a/testkitbackend/_sync/requests.py +++ b/testkitbackend/_sync/requests.py @@ -174,16 +174,10 @@ def new_driver(backend, data): client_cert_provider_id ] data.mark_item_as_read_if_equals("clientCertificate", None) - expected_warnings.append( - (neo4j.PreviewWarning, r"Mutual TLS is a preview feature\.") - ) else: client_cert = fromtestkit.to_client_cert(data, "clientCertificate") if client_cert is not None: kwargs["client_certificate"] = client_cert - expected_warnings.append( - (neo4j.PreviewWarning, r"Mutual TLS is a preview feature\.") - ) if data["resolverRegistered"] or data["domainNameResolverRegistered"]: kwargs["resolver"] = resolution_func( backend, diff --git a/testkitbackend/fromtestkit.py b/testkitbackend/fromtestkit.py index 3cd423e53..bee98b62e 100644 --- a/testkitbackend/fromtestkit.py +++ b/testkitbackend/fromtestkit.py @@ -39,7 +39,6 @@ ) from ._preview_imports import NotificationDisabledClassification -from ._warning_check import warnings_check def to_cypher_and_params(data): @@ -222,12 +221,9 @@ def to_client_cert(data, key) -> ClientCertificate | None: return None data[key].mark_item_as_read_if_equals("name", "ClientCertificate") cert_data = data[key]["data"] - with warnings_check( - ((neo4j.PreviewWarning, r"Mutual TLS is a preview feature\."),) - ): - return ClientCertificate( - cert_data["certfile"], cert_data["keyfile"], cert_data["password"] - ) + return ClientCertificate( + cert_data["certfile"], cert_data["keyfile"], cert_data["password"] + ) def set_notifications_config(config, data): diff --git a/tests/unit/async_/test_auth_management.py b/tests/unit/async_/test_auth_management.py index 57420d3a2..da0116bcd 100644 --- a/tests/unit/async_/test_auth_management.py +++ b/tests/unit/async_/test_auth_management.py @@ -24,7 +24,6 @@ from neo4j import ( Auth, basic_auth, - PreviewWarning, ) from neo4j._meta import copy_signature from neo4j.auth_management import ( @@ -261,22 +260,14 @@ def client_cert_factory() -> t.Callable[[], ClientCertificate]: i = 0 def factory() -> ClientCertificate: - with pytest.warns(PreviewWarning, match="Mutual TLS"): - return ClientCertificate(f"cert{i}") + return ClientCertificate(f"cert{i}") return factory -@copy_signature(AsyncClientCertificateProviders.static) -def static_cert_provider(*args, **kwargs): - with pytest.warns(PreviewWarning, match="Mutual TLS"): - return AsyncClientCertificateProviders.static(*args, **kwargs) +static_cert_provider = AsyncClientCertificateProviders.static - -@copy_signature(AsyncClientCertificateProviders.rotating) -def rotating_cert_provider(*args, **kwargs): - with pytest.warns(PreviewWarning, match="Mutual TLS"): - return AsyncClientCertificateProviders.rotating(*args, **kwargs) +rotating_cert_provider = AsyncClientCertificateProviders.rotating @mark_async_test diff --git a/tests/unit/async_/test_conf.py b/tests/unit/async_/test_conf.py index fcc5b9a2f..1902a5d65 100644 --- a/tests/unit/async_/test_conf.py +++ b/tests/unit/async_/test_conf.py @@ -19,7 +19,6 @@ import pytest from neo4j import ( - PreviewWarning, TrustAll, TrustCustomCAs, TrustSystemCAs, @@ -426,10 +425,8 @@ async def test_custom_ssl_context(encrypted, trusted_certificates): async def test_client_certificate(trusted_certificates, mocker) -> None: ssl_context_mock = mocker.patch("ssl.SSLContext", autospec=True) - with pytest.warns(PreviewWarning, match="Mutual TLS"): - cert = ClientCertificate("certfile", "keyfile", "password") - with pytest.warns(PreviewWarning, match="Mutual TLS"): - provider = AsyncClientCertificateProviders.rotating(cert) + cert = ClientCertificate("certfile", "keyfile", "password") + provider = AsyncClientCertificateProviders.rotating(cert) pool_config = AsyncPoolConfig.consume( { "client_certificate": provider, @@ -455,8 +452,7 @@ async def test_client_certificate(trusted_certificates, mocker) -> None: ssl_context_mock.assert_not_called() # test cache invalidation - with pytest.warns(PreviewWarning, match="Mutual TLS"): - cert2 = ClientCertificate("certfile2", "keyfile2", "password2") + cert2 = ClientCertificate("certfile2", "keyfile2", "password2") await provider.update_certificate(cert2) ssl_context = await pool_config.get_ssl_context() diff --git a/tests/unit/async_/test_driver.py b/tests/unit/async_/test_driver.py index 583894b4d..53d287102 100644 --- a/tests/unit/async_/test_driver.py +++ b/tests/unit/async_/test_driver.py @@ -484,17 +484,15 @@ def forget(self, databases: t.Iterable[str]) -> None: ... @mark_async_test async def test_with_static_client_certificate() -> None: - with pytest.warns(PreviewWarning, match="Mutual TLS"): - cert = ClientCertificate("foo") - with pytest.warns(PreviewWarning, match="Mutual TLS"): - async with AsyncGraphDatabase.driver( - "bolt://localhost", client_certificate=cert - ) as driver: - passed_provider = driver._pool.pool_config.client_certificate - assert isinstance( - passed_provider, _AsyncStaticClientCertificateProvider - ) - assert passed_provider._cert is cert + cert = ClientCertificate("foo") + async with AsyncGraphDatabase.driver( + "bolt://localhost", client_certificate=cert + ) as driver: + passed_provider = driver._pool.pool_config.client_certificate + assert isinstance( + passed_provider, _AsyncStaticClientCertificateProvider + ) + assert passed_provider._cert is cert @mark_async_test @@ -506,11 +504,10 @@ async def get_certificate(self) -> ClientCertificate | None: return None provider = Provider() - with pytest.warns(PreviewWarning, match="Mutual TLS"): - async with AsyncGraphDatabase.driver( - "bolt://localhost", client_certificate=provider - ) as driver: - assert driver._pool.pool_config.client_certificate is provider + async with AsyncGraphDatabase.driver( + "bolt://localhost", client_certificate=provider + ) as driver: + assert driver._pool.pool_config.client_certificate is provider @mark_async_test @@ -522,11 +519,10 @@ async def get_certificate(self) -> ClientCertificate | None: return None provider = Provider() - with pytest.warns(PreviewWarning, match="Mutual TLS"): - async with AsyncGraphDatabase.driver( - "bolt://localhost", client_certificate=provider - ) as driver: - assert driver._pool.pool_config.client_certificate is provider + async with AsyncGraphDatabase.driver( + "bolt://localhost", client_certificate=provider + ) as driver: + assert driver._pool.pool_config.client_certificate is provider if t.TYPE_CHECKING: diff --git a/tests/unit/sync/test_auth_management.py b/tests/unit/sync/test_auth_management.py index 34eb4d727..84e6d2514 100644 --- a/tests/unit/sync/test_auth_management.py +++ b/tests/unit/sync/test_auth_management.py @@ -24,7 +24,6 @@ from neo4j import ( Auth, basic_auth, - PreviewWarning, ) from neo4j._meta import copy_signature from neo4j.auth_management import ( @@ -261,22 +260,14 @@ def client_cert_factory() -> t.Callable[[], ClientCertificate]: i = 0 def factory() -> ClientCertificate: - with pytest.warns(PreviewWarning, match="Mutual TLS"): - return ClientCertificate(f"cert{i}") + return ClientCertificate(f"cert{i}") return factory -@copy_signature(ClientCertificateProviders.static) -def static_cert_provider(*args, **kwargs): - with pytest.warns(PreviewWarning, match="Mutual TLS"): - return ClientCertificateProviders.static(*args, **kwargs) +static_cert_provider = ClientCertificateProviders.static - -@copy_signature(ClientCertificateProviders.rotating) -def rotating_cert_provider(*args, **kwargs): - with pytest.warns(PreviewWarning, match="Mutual TLS"): - return ClientCertificateProviders.rotating(*args, **kwargs) +rotating_cert_provider = ClientCertificateProviders.rotating @mark_sync_test diff --git a/tests/unit/sync/test_conf.py b/tests/unit/sync/test_conf.py index cf2032e07..65481811b 100644 --- a/tests/unit/sync/test_conf.py +++ b/tests/unit/sync/test_conf.py @@ -19,7 +19,6 @@ import pytest from neo4j import ( - PreviewWarning, TrustAll, TrustCustomCAs, TrustSystemCAs, @@ -426,10 +425,8 @@ def test_custom_ssl_context(encrypted, trusted_certificates): def test_client_certificate(trusted_certificates, mocker) -> None: ssl_context_mock = mocker.patch("ssl.SSLContext", autospec=True) - with pytest.warns(PreviewWarning, match="Mutual TLS"): - cert = ClientCertificate("certfile", "keyfile", "password") - with pytest.warns(PreviewWarning, match="Mutual TLS"): - provider = ClientCertificateProviders.rotating(cert) + cert = ClientCertificate("certfile", "keyfile", "password") + provider = ClientCertificateProviders.rotating(cert) pool_config = PoolConfig.consume( { "client_certificate": provider, @@ -455,8 +452,7 @@ def test_client_certificate(trusted_certificates, mocker) -> None: ssl_context_mock.assert_not_called() # test cache invalidation - with pytest.warns(PreviewWarning, match="Mutual TLS"): - cert2 = ClientCertificate("certfile2", "keyfile2", "password2") + cert2 = ClientCertificate("certfile2", "keyfile2", "password2") provider.update_certificate(cert2) ssl_context = pool_config.get_ssl_context() diff --git a/tests/unit/sync/test_driver.py b/tests/unit/sync/test_driver.py index 9f2ebca18..a508c108e 100644 --- a/tests/unit/sync/test_driver.py +++ b/tests/unit/sync/test_driver.py @@ -483,17 +483,15 @@ def forget(self, databases: t.Iterable[str]) -> None: ... @mark_sync_test def test_with_static_client_certificate() -> None: - with pytest.warns(PreviewWarning, match="Mutual TLS"): - cert = ClientCertificate("foo") - with pytest.warns(PreviewWarning, match="Mutual TLS"): - with GraphDatabase.driver( - "bolt://localhost", client_certificate=cert - ) as driver: - passed_provider = driver._pool.pool_config.client_certificate - assert isinstance( - passed_provider, _StaticClientCertificateProvider - ) - assert passed_provider._cert is cert + cert = ClientCertificate("foo") + with GraphDatabase.driver( + "bolt://localhost", client_certificate=cert + ) as driver: + passed_provider = driver._pool.pool_config.client_certificate + assert isinstance( + passed_provider, _StaticClientCertificateProvider + ) + assert passed_provider._cert is cert @mark_sync_test @@ -505,11 +503,10 @@ def get_certificate(self) -> ClientCertificate | None: return None provider = Provider() - with pytest.warns(PreviewWarning, match="Mutual TLS"): - with GraphDatabase.driver( - "bolt://localhost", client_certificate=provider - ) as driver: - assert driver._pool.pool_config.client_certificate is provider + with GraphDatabase.driver( + "bolt://localhost", client_certificate=provider + ) as driver: + assert driver._pool.pool_config.client_certificate is provider @mark_sync_test @@ -521,11 +518,10 @@ def get_certificate(self) -> ClientCertificate | None: return None provider = Provider() - with pytest.warns(PreviewWarning, match="Mutual TLS"): - with GraphDatabase.driver( - "bolt://localhost", client_certificate=provider - ) as driver: - assert driver._pool.pool_config.client_certificate is provider + with GraphDatabase.driver( + "bolt://localhost", client_certificate=provider + ) as driver: + assert driver._pool.pool_config.client_certificate is provider if t.TYPE_CHECKING: