diff --git a/src/neo4j/__init__.py b/src/neo4j/__init__.py index bc9784a3d..b238d87c2 100644 --- a/src/neo4j/__init__.py +++ b/src/neo4j/__init__.py @@ -186,7 +186,7 @@ _log = _getLogger("neo4j") -def __getattr__(name): +def __getattr__(name) -> _t.Any: # TODO: 6.0 - remove this if name in ( "log", "Config", "PoolConfig", "SessionConfig", "WorkspaceConfig" @@ -219,7 +219,7 @@ def __getattr__(name): raise AttributeError(f"module {__name__} has no attribute {name}") -def __dir__(): +def __dir__() -> _t.List[str]: return __all__ diff --git a/src/neo4j/_meta.py b/src/neo4j/_meta.py index 1eeae87a0..52e83ddfc 100644 --- a/src/neo4j/_meta.py +++ b/src/neo4j/_meta.py @@ -116,6 +116,7 @@ def decorator(f): return t.cast(property, decorator) +# TODO: 6.0 - remove this class, replace usage with PreviewWarning class ExperimentalWarning(Warning): """ Base class for warnings about experimental features. @@ -145,6 +146,8 @@ def foo(x): return _make_warning_decorator(message, experimental_warn) +# TODO: 6.0 - consider moving this to the `warnings` module +# and not to re-export it from the top-level package `neo4j` class PreviewWarning(Warning): """A driver feature in preview has been used. diff --git a/src/neo4j/addressing.py b/src/neo4j/addressing.py index f18ad1424..f075a0796 100644 --- a/src/neo4j/addressing.py +++ b/src/neo4j/addressing.py @@ -38,6 +38,16 @@ class _WithPeerName(te.Protocol): def getpeername(self) -> tuple: ... +__all__ = [ + "Address", + "IPv4Address", + "IPv6Address", + "ResolvedAddress", + "ResolvedIPv4Address", + "ResolvedIPv6Address", +] + + class _AddressMeta(type(tuple)): # type: ignore[misc] def __init__(cls, *args, **kwargs): @@ -311,7 +321,7 @@ def __str__(self) -> str: class IPv6Address(Address): - """An IPv6 address (family ``AF_INETl``). + """An IPv6 address (family ``AF_INET6``). This class should not be instantiated directly. Instead, use :class:`.Address` or one of its factory methods. @@ -323,6 +333,7 @@ def __str__(self) -> str: return "[{}]:{}".format(*self) +# TODO: 6.0 - make this class private class ResolvedAddress(Address): _unresolved_host_name: str @@ -342,9 +353,11 @@ def __new__(cls, iterable, *, host_name: str) -> ResolvedAddress: return new +# TODO: 6.0 - make this class private class ResolvedIPv4Address(IPv4Address, ResolvedAddress): pass +# TODO: 6.0 - make this class private class ResolvedIPv6Address(IPv6Address, ResolvedAddress): pass diff --git a/src/neo4j/api.py b/src/neo4j/api.py index 9af802cbb..5daae3f9d 100644 --- a/src/neo4j/api.py +++ b/src/neo4j/api.py @@ -40,12 +40,51 @@ _Protocol = object +__all__ = [ + "READ_ACCESS", + "WRITE_ACCESS", + "DRIVER_BOLT", + "DRIVER_NEO4J", + "SECURITY_TYPE_NOT_SECURE", + "SECURITY_TYPE_SELF_SIGNED_CERTIFICATE", + "SECURITY_TYPE_SECURE", + "URI_SCHEME_BOLT", + "URI_SCHEME_BOLT_SELF_SIGNED_CERTIFICATE", + "URI_SCHEME_BOLT_SECURE", + "URI_SCHEME_NEO4J", + "URI_SCHEME_NEO4J_SELF_SIGNED_CERTIFICATE", + "URI_SCHEME_NEO4J_SECURE", + "URI_SCHEME_BOLT_ROUTING", + "TRUST_SYSTEM_CA_SIGNED_CERTIFICATES", + "TRUST_ALL_CERTIFICATES", + "SYSTEM_DATABASE", + "DEFAULT_DATABASE", + "Auth", + "AuthToken", + "basic_auth", + "kerberos_auth", + "bearer_auth", + "custom_auth", + "Bookmark", + "Bookmarks", + "ServerInfo", + "Version", + "BookmarkManager", + "AsyncBookmarkManager", + "parse_neo4j_uri", + "check_access_mode", + "parse_routing_context", +] + + READ_ACCESS: te.Final[str] = "READ" WRITE_ACCESS: te.Final[str] = "WRITE" +# TODO: 6.0 - make these 2 constants private DRIVER_BOLT: te.Final[str] = "DRIVER_BOLT" DRIVER_NEO4J: te.Final[str] = "DRIVER_NEO4J" +# TODO: 6.0 - make these 3 constants private SECURITY_TYPE_NOT_SECURE: te.Final[str] = "SECURITY_TYPE_NOT_SECURE" SECURITY_TYPE_SELF_SIGNED_CERTIFICATE: te.Final[str] = \ "SECURITY_TYPE_SELF_SIGNED_CERTIFICATE" @@ -354,6 +393,9 @@ def update(self, metadata: dict) -> None: self._metadata.update(metadata) +# TODO: 6.0 - this class should not be public. +# As far the user is concerned, protocol versions should simply be a +# tuple[int, int]. class Version(tuple): def __new__(cls, *v): @@ -480,6 +522,7 @@ async def get_bookmarks(self) -> t.Collection[str]: get_bookmarks.__doc__ = BookmarkManager.get_bookmarks.__doc__ +# TODO: 6.0 - make this function private def parse_neo4j_uri(uri): parsed = urlparse(uri) @@ -525,6 +568,7 @@ def parse_neo4j_uri(uri): return driver_type, security_type, parsed +# TODO: 6.0 - make this function private def check_access_mode(access_mode): if access_mode is None: return WRITE_ACCESS @@ -535,6 +579,7 @@ def check_access_mode(access_mode): return access_mode +# TODO: 6.0 - make this function private def parse_routing_context(query): """ Parse the query portion of a URI to generate a routing context dictionary. """ diff --git a/src/neo4j/exceptions.py b/src/neo4j/exceptions.py index 4371e1b3f..61e1ef66e 100644 --- a/src/neo4j/exceptions.py +++ b/src/neo4j/exceptions.py @@ -101,6 +101,48 @@ _TSession = t.Union["AsyncSession", "Session"] +__all__ = [ + # TODO: 6.0 - make these constants private + "CLASSIFICATION_CLIENT", + "CLASSIFICATION_TRANSIENT", + "CLASSIFICATION_DATABASE", + "ERROR_REWRITE_MAP", + + "Neo4jError", + "ClientError", + "CypherSyntaxError", + "CypherTypeError", + "ConstraintError", + "AuthError", + "TokenExpired", + "Forbidden", + "DatabaseError", + "TransientError", + "DatabaseUnavailable", + "NotALeader", + "ForbiddenOnReadOnlyDatabase", + "DriverError", + "SessionError", + "TransactionError", + "TransactionNestingError", + "ResultError", + "ResultFailedError", + "ResultConsumedError", + "ResultNotSingleError", + "BrokenRecordError", + "SessionExpired", + "ServiceUnavailable", + "RoutingServiceUnavailable", + "WriteServiceUnavailable", + "ReadServiceUnavailable", + "IncompleteCommit", + "ConfigurationError", + "AuthConfigurationError", + "CertificateConfigurationError", + "UnsupportedServerProduct", +] + + CLASSIFICATION_CLIENT: te.Final[str] = "ClientError" CLASSIFICATION_TRANSIENT: te.Final[str] = "TransientError" CLASSIFICATION_DATABASE: te.Final[str] = "DatabaseError" diff --git a/src/neo4j/meta.py b/src/neo4j/meta.py index bb74ef3ab..0814cd6d6 100644 --- a/src/neo4j/meta.py +++ b/src/neo4j/meta.py @@ -40,7 +40,7 @@ deprecation_warn( "The module `neo4j.meta` was made internal and will " "no longer be available for import in future versions." - "`ExperimentalWarning` can be imported from `neo4j` directly and " - "`neo4j.meta.version` is exposed as `neo4j.__version__`.", + "`ExperimentalWarning` can be imported from `neo4j.warnings` and " + "`neo4j.meta.version` is exposed through `neo4j.__version__`.", stack_level=2 ) diff --git a/src/neo4j/warnings.py b/src/neo4j/warnings.py index 783787690..e33da0b18 100644 --- a/src/neo4j/warnings.py +++ b/src/neo4j/warnings.py @@ -22,12 +22,18 @@ from ._work.summary import SummaryNotification +__all__ = [ + "Neo4jWarning", + "Neo4jDeprecationWarning", +] + + class Neo4jWarning(Warning): """ Warning emitted for notifications sent by the server. Which notifications trigger a warning can be controlled by a - configuration: :ref:`driver-warn-notification-severity-ref` + configuration option: :ref:`driver-warn-notification-severity-ref` **This is experimental** (see :ref:`filter-warnings-ref`). It might be changed or removed any time even without prior notice. diff --git a/tests/unit/async_/test_driver.py b/tests/unit/async_/test_driver.py index a55df4ddd..22a0d1ec6 100644 --- a/tests/unit/async_/test_driver.py +++ b/tests/unit/async_/test_driver.py @@ -453,9 +453,9 @@ def forget(self, databases: t.Iterable[str]) -> None: @mark_async_test async def test_with_static_client_certificate() -> None: - with pytest.warns(neo4j.PreviewWarning, match="Mutual TLS"): + with pytest.warns(PreviewWarning, match="Mutual TLS"): cert = ClientCertificate("foo") - with pytest.warns(neo4j.PreviewWarning, match="Mutual TLS"): + with pytest.warns(PreviewWarning, match="Mutual TLS"): async with AsyncGraphDatabase.driver( "bolt://localhost", client_certificate=cert ) as driver: @@ -474,7 +474,7 @@ async def get_certificate(self) -> t.Optional[ClientCertificate]: return None provider = Provider() - with pytest.warns(neo4j.PreviewWarning, match="Mutual TLS"): + with pytest.warns(PreviewWarning, match="Mutual TLS"): async with AsyncGraphDatabase.driver( "bolt://localhost", client_certificate=provider ) as driver: @@ -490,7 +490,7 @@ async def get_certificate(self) -> t.Optional[ClientCertificate]: return None provider = Provider() - with pytest.warns(neo4j.PreviewWarning, match="Mutual TLS"): + with pytest.warns(PreviewWarning, match="Mutual TLS"): async with AsyncGraphDatabase.driver( "bolt://localhost", client_certificate=provider ) as driver: diff --git a/tests/unit/sync/test_driver.py b/tests/unit/sync/test_driver.py index 3930ee565..ef7d341d5 100644 --- a/tests/unit/sync/test_driver.py +++ b/tests/unit/sync/test_driver.py @@ -452,9 +452,9 @@ def forget(self, databases: t.Iterable[str]) -> None: @mark_sync_test def test_with_static_client_certificate() -> None: - with pytest.warns(neo4j.PreviewWarning, match="Mutual TLS"): + with pytest.warns(PreviewWarning, match="Mutual TLS"): cert = ClientCertificate("foo") - with pytest.warns(neo4j.PreviewWarning, match="Mutual TLS"): + with pytest.warns(PreviewWarning, match="Mutual TLS"): with GraphDatabase.driver( "bolt://localhost", client_certificate=cert ) as driver: @@ -473,7 +473,7 @@ def get_certificate(self) -> t.Optional[ClientCertificate]: return None provider = Provider() - with pytest.warns(neo4j.PreviewWarning, match="Mutual TLS"): + with pytest.warns(PreviewWarning, match="Mutual TLS"): with GraphDatabase.driver( "bolt://localhost", client_certificate=provider ) as driver: @@ -489,7 +489,7 @@ def get_certificate(self) -> t.Optional[ClientCertificate]: return None provider = Provider() - with pytest.warns(neo4j.PreviewWarning, match="Mutual TLS"): + with pytest.warns(PreviewWarning, match="Mutual TLS"): with GraphDatabase.driver( "bolt://localhost", client_certificate=provider ) as driver: