Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,20 @@ See also https://github.com/neo4j/neo4j-python-driver/wiki for a full changelog.
- Remove `ExperimentalWarning` and turn the few left instances of it into `PreviewWarning`.
- Deprecate importing `PreviewWarning` from `neo4j`.
Import it from `neo4j.warnings` instead.
- Make undocumented internal constants private:
- `neo4j.api`
- `DRIVER_BOLT`
- `DRIVER_NEO4J`
- `SECURITY_TYPE_NOT_SECURE`
- `SECURITY_TYPE_SECURE`
- `SECURITY_TYPE_SELF_SIGNED_CERTIFICATE`
- `neo4j.exceptions`
- `CLASSIFICATION_CLIENT`
- `CLASSIFICATION_DATABASE`
- `CLASSIFICATION_TRANSIENT`
- `ERROR_REWRITE_MAP`
- `client_errors`
- `transient_errors`


## Version 5.28
Expand Down
15 changes: 15 additions & 0 deletions src/neo4j/_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@


__all__ = [
"DRIVER_BOLT",
"DRIVER_NEO4J",
"SECURITY_TYPE_NOT_SECURE",
"SECURITY_TYPE_SECURE",
"SECURITY_TYPE_SELF_SIGNED_CERTIFICATE",
"NotificationCategory",
"NotificationClassification",
"NotificationDisabledCategory",
Expand All @@ -36,6 +41,16 @@
]


DRIVER_BOLT: te.Final[str] = "DRIVER_BOLT"
DRIVER_NEO4J: te.Final[str] = "DRIVER_NEO4J"

SECURITY_TYPE_NOT_SECURE: te.Final[str] = "SECURITY_TYPE_NOT_SECURE"
SECURITY_TYPE_SELF_SIGNED_CERTIFICATE: te.Final[str] = (
"SECURITY_TYPE_SELF_SIGNED_CERTIFICATE"
)
SECURITY_TYPE_SECURE: te.Final[str] = "SECURITY_TYPE_SECURE"


class NotificationMinimumSeverity(str, Enum):
"""
Filter notifications returned by the server by minimum severity.
Expand Down
8 changes: 4 additions & 4 deletions src/neo4j/_async/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,12 @@

from .._addressing import Address
from .._api import (
DRIVER_BOLT,
DRIVER_NEO4J,
NotificationMinimumSeverity,
RoutingControl,
SECURITY_TYPE_SECURE,
SECURITY_TYPE_SELF_SIGNED_CERTIFICATE,
TelemetryAPI,
)
from .._async_compat.util import AsyncUtil
Expand Down Expand Up @@ -60,13 +64,9 @@
Auth,
BookmarkManager,
Bookmarks,
DRIVER_BOLT,
DRIVER_NEO4J,
parse_neo4j_uri,
parse_routing_context,
READ_ACCESS,
SECURITY_TYPE_SECURE,
SECURITY_TYPE_SELF_SIGNED_CERTIFICATE,
ServerInfo,
TRUST_ALL_CERTIFICATES,
TRUST_SYSTEM_CA_SIGNED_CERTIFICATES,
Expand Down
8 changes: 4 additions & 4 deletions src/neo4j/_sync/driver.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 19 additions & 35 deletions src/neo4j/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,27 @@
urlparse,
)


if t.TYPE_CHECKING:
from typing_extensions import deprecated
else:
from ._warnings import deprecated

from . import _api
from .exceptions import ConfigurationError


if t.TYPE_CHECKING:
import typing_extensions as te
from typing_extensions import Protocol as _Protocol
from typing_extensions import (
deprecated,
Protocol as _Protocol,
)

from ._addressing import Address
else:
from ._warnings import deprecated

_Protocol = object


__all__ = [
"DEFAULT_DATABASE",
"DRIVER_BOLT",
"DRIVER_NEO4J",
"READ_ACCESS",
"SECURITY_TYPE_NOT_SECURE",
"SECURITY_TYPE_SECURE",
"SECURITY_TYPE_SELF_SIGNED_CERTIFICATE",
"SYSTEM_DATABASE",
"TRUST_ALL_CERTIFICATES",
"TRUST_SYSTEM_CA_SIGNED_CERTIFICATES",
Expand Down Expand Up @@ -81,17 +76,6 @@
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"
)
SECURITY_TYPE_SECURE: te.Final[str] = "SECURITY_TYPE_SECURE"

URI_SCHEME_BOLT: te.Final[str] = "bolt"
URI_SCHEME_BOLT_SELF_SIGNED_CERTIFICATE: te.Final[str] = "bolt+ssc"
URI_SCHEME_BOLT_SECURE: te.Final[str] = "bolt+s"
Expand Down Expand Up @@ -477,23 +461,23 @@ def parse_neo4j_uri(uri):
f"Use {URI_SCHEME_NEO4J!r}"
)
elif parsed.scheme == URI_SCHEME_BOLT:
driver_type = DRIVER_BOLT
security_type = SECURITY_TYPE_NOT_SECURE
driver_type = _api.DRIVER_BOLT
security_type = _api.SECURITY_TYPE_NOT_SECURE
elif parsed.scheme == URI_SCHEME_BOLT_SELF_SIGNED_CERTIFICATE:
driver_type = DRIVER_BOLT
security_type = SECURITY_TYPE_SELF_SIGNED_CERTIFICATE
driver_type = _api.DRIVER_BOLT
security_type = _api.SECURITY_TYPE_SELF_SIGNED_CERTIFICATE
elif parsed.scheme == URI_SCHEME_BOLT_SECURE:
driver_type = DRIVER_BOLT
security_type = SECURITY_TYPE_SECURE
driver_type = _api.DRIVER_BOLT
security_type = _api.SECURITY_TYPE_SECURE
elif parsed.scheme == URI_SCHEME_NEO4J:
driver_type = DRIVER_NEO4J
security_type = SECURITY_TYPE_NOT_SECURE
driver_type = _api.DRIVER_NEO4J
security_type = _api.SECURITY_TYPE_NOT_SECURE
elif parsed.scheme == URI_SCHEME_NEO4J_SELF_SIGNED_CERTIFICATE:
driver_type = DRIVER_NEO4J
security_type = SECURITY_TYPE_SELF_SIGNED_CERTIFICATE
driver_type = _api.DRIVER_NEO4J
security_type = _api.SECURITY_TYPE_SELF_SIGNED_CERTIFICATE
elif parsed.scheme == URI_SCHEME_NEO4J_SECURE:
driver_type = DRIVER_NEO4J
security_type = SECURITY_TYPE_SECURE
driver_type = _api.DRIVER_NEO4J
security_type = _api.SECURITY_TYPE_SECURE
else:
supported_schemes = [
URI_SCHEME_BOLT,
Expand Down
82 changes: 20 additions & 62 deletions src/neo4j/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,46 +75,6 @@
from ._warnings import deprecated as _deprecated


__all__ = [
"AuthConfigurationError",
"AuthError",
"BrokenRecordError",
"CertificateConfigurationError",
"ClientError",
"ConfigurationError",
"ConnectionAcquisitionTimeoutError",
"ConnectionPoolError",
"ConstraintError",
"CypherSyntaxError",
"CypherTypeError",
"DatabaseError",
"DatabaseUnavailable",
"DriverError",
"Forbidden",
"ForbiddenOnReadOnlyDatabase",
"GqlError",
"GqlErrorClassification",
"IncompleteCommit",
"Neo4jError",
"NotALeader",
"ReadServiceUnavailable",
"ResultConsumedError",
"ResultError",
"ResultFailedError",
"ResultNotSingleError",
"RoutingServiceUnavailable",
"ServiceUnavailable",
"SessionError",
"SessionExpired",
"TokenExpired",
"TransactionError",
"TransactionNestingError",
"TransientError",
"UnsupportedServerProduct",
"WriteServiceUnavailable",
]


if t.TYPE_CHECKING:
from collections.abc import Mapping

Expand Down Expand Up @@ -145,16 +105,14 @@


__all__ = [
"CLASSIFICATION_CLIENT", # TODO: 6.0 - make constant private
"CLASSIFICATION_DATABASE", # TODO: 6.0 - make constant private
"CLASSIFICATION_TRANSIENT", # TODO: 6.0 - make constant private
"ERROR_REWRITE_MAP", # TODO: 6.0 - make constant private
"AuthConfigurationError",
"AuthError",
"BrokenRecordError",
"CertificateConfigurationError",
"ClientError",
"ConfigurationError",
"ConnectionAcquisitionTimeoutError",
"ConnectionPoolError",
"ConstraintError",
"CypherSyntaxError",
"CypherTypeError",
Expand All @@ -163,6 +121,8 @@
"DriverError",
"Forbidden",
"ForbiddenOnReadOnlyDatabase",
"GqlError",
"GqlErrorClassification",
"IncompleteCommit",
"Neo4jError",
"NotALeader",
Expand All @@ -184,30 +144,30 @@
]


CLASSIFICATION_CLIENT: te.Final[str] = "ClientError"
CLASSIFICATION_TRANSIENT: te.Final[str] = "TransientError"
CLASSIFICATION_DATABASE: te.Final[str] = "DatabaseError"
_CLASSIFICATION_CLIENT: te.Final[str] = "ClientError"
_CLASSIFICATION_TRANSIENT: te.Final[str] = "TransientError"
_CLASSIFICATION_DATABASE: te.Final[str] = "DatabaseError"


ERROR_REWRITE_MAP: dict[str, tuple[str, str | None]] = {
_ERROR_REWRITE_MAP: dict[str, tuple[str, str | None]] = {
# This error can be retried ed. The driver just needs to re-authenticate
# with the same credentials.
"Neo.ClientError.Security.AuthorizationExpired": (
CLASSIFICATION_TRANSIENT,
_CLASSIFICATION_TRANSIENT,
None,
),
# In 5.0, this error has been re-classified as ClientError.
# For backwards compatibility with Neo4j 4.4 and earlier, we re-map it in
# the driver, too.
"Neo.TransientError.Transaction.Terminated": (
CLASSIFICATION_CLIENT,
_CLASSIFICATION_CLIENT,
"Neo.ClientError.Transaction.Terminated",
),
# In 5.0, this error has been re-classified as ClientError.
# For backwards compatibility with Neo4j 4.4 and earlier, we re-map it in
# the driver, too.
"Neo.TransientError.Transaction.LockClientStopped": (
CLASSIFICATION_CLIENT,
_CLASSIFICATION_CLIENT,
"Neo.ClientError.Transaction.LockClientStopped",
),
}
Expand Down Expand Up @@ -638,11 +598,11 @@ def _basic_hydrate(cls, *, neo4j_code: str, message: str) -> Neo4jError:
try:
_, classification, category, title = neo4j_code.split(".")
except ValueError:
classification = CLASSIFICATION_DATABASE
classification = _CLASSIFICATION_DATABASE
category = "General"
title = "UnknownError"
else:
classification_override, code_override = ERROR_REWRITE_MAP.get(
classification_override, code_override = _ERROR_REWRITE_MAP.get(
neo4j_code, (None, None)
)
if classification_override is not None:
Expand All @@ -665,19 +625,19 @@ def _basic_hydrate(cls, *, neo4j_code: str, message: str) -> Neo4jError:

@classmethod
def _extract_error_class(cls, classification, code) -> type[Neo4jError]:
if classification == CLASSIFICATION_CLIENT:
if classification == _CLASSIFICATION_CLIENT:
try:
return client_errors[code]
return _client_errors[code]
except KeyError:
return ClientError

elif classification == CLASSIFICATION_TRANSIENT:
elif classification == _CLASSIFICATION_TRANSIENT:
try:
return transient_errors[code]
return _transient_errors[code]
except KeyError:
return TransientError

elif classification == CLASSIFICATION_DATABASE:
elif classification == _CLASSIFICATION_DATABASE:
return DatabaseError

else:
Expand Down Expand Up @@ -958,8 +918,7 @@ class ForbiddenOnReadOnlyDatabase(TransientError):
pass


# TODO: 6.0 - Make map private
client_errors: dict[str, type[Neo4jError]] = {
_client_errors: dict[str, type[Neo4jError]] = {
# ConstraintError
"Neo.ClientError.Schema.ConstraintValidationFailed": ConstraintError,
"Neo.ClientError.Schema.ConstraintViolation": ConstraintError,
Expand Down Expand Up @@ -988,8 +947,7 @@ class ForbiddenOnReadOnlyDatabase(TransientError):
"Neo.ClientError.Cluster.NotALeader": NotALeader,
}

# TODO: 6.0 - Make map private
transient_errors: dict[str, type[Neo4jError]] = {
_transient_errors: dict[str, type[Neo4jError]] = {
# DatabaseUnavailableError
"Neo.TransientError.General.DatabaseUnavailable": DatabaseUnavailable
}
Expand Down
Loading