Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
24c9fee
bolt 5x7 error tests
MaxAake Sep 24, 2024
4af6b73
pre-commit runs
MaxAake Sep 24, 2024
678da42
upgrade flake8
MaxAake Sep 24, 2024
1206bf0
Bump pre-commit tool versions +++ now requiring Python 3.8+ +++ (#631)
MaxAake Sep 24, 2024
d1af132
Merge branch '5.0' into bolt-5x7-and-gql-errors
MaxAake Sep 24, 2024
cac1cc0
fix flake8 issues
MaxAake Sep 24, 2024
2fbbd7e
Merge branch 'bolt-5x7-and-gql-errors' of https://github.com/neo4j-dr…
MaxAake Sep 24, 2024
0b489fb
bump feature requirement on older error testing
MaxAake Sep 24, 2024
74e32ae
Update test_errors.py
MaxAake Sep 24, 2024
89076a9
WIP
robsdedude Sep 24, 2024
bfb2a04
Protocol: adjust error cause to be a pure GQLError
robsdedude Sep 24, 2024
c31bcd5
WiP: add more GQL error tests
robsdedude Sep 24, 2024
f14d6e8
WiP: add tests for nested errors
robsdedude Sep 24, 2024
0491438
Fix GQL error tests for Bolt 5.6
robsdedude Sep 25, 2024
f93167b
Add test for GQLError retryability
robsdedude Sep 25, 2024
a7e7716
Tidy code clean-up
robsdedude Sep 25, 2024
d0cc695
changing _status_parameters to a CypherMap
MaxAake Sep 25, 2024
89fd54d
Restore funky diag. record rubbish values
robsdedude Sep 25, 2024
02b0eaa
Create v5x7_return_1.script
MaxAake Sep 26, 2024
1b57dfd
Update expected fallback GQL error description
robsdedude Sep 27, 2024
67e7d80
Fix bolt version in v5.7 version test script
robsdedude Sep 27, 2024
73b1afa
Respect feature flag when checking for error retryability
robsdedude Oct 3, 2024
ddbdffc
Guard more assertions with types.Feature.API_RETRYABLE_EXCEPTION
robsdedude Oct 3, 2024
5cd7704
Merge branch '5.0' into bolt-5x7-and-gql-errors
robsdedude Oct 3, 2024
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
4 changes: 2 additions & 2 deletions boltstub/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ def signal_handler(sig, frame):
elif sigint_count == 2:
print("2nd SIGINT received. Closing all connections.")
service.close_all_connections_async()
if sigint_count > 3:
print("3nd SIGINT received. Hard exit.")
elif sigint_count >= 3:
print("3rd SIGINT received. Hard exit.")
return exit_(130)

if platform.system() == "Windows":
Expand Down
9 changes: 9 additions & 0 deletions boltstub/bolt_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -561,3 +561,12 @@ class Bolt5x6Protocol(Bolt5x5Protocol):
equivalent_versions = set()

server_agent = "Neo4j/5.23.0"


class Bolt5x7Protocol(Bolt5x6Protocol):
protocol_version = (5, 7)
version_aliases = set()
# allow the server to negotiate other bolt versions
equivalent_versions = set()

server_agent = "Neo4j/5.24.0"
14 changes: 14 additions & 0 deletions nutkit/protocol/cypher.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,4 +496,18 @@ def as_cypher_type(value):
return CypherString(value)
if isinstance(value, (bytes, bytearray)):
return CypherBytes(value)
if isinstance(
value,
(
CypherNode,
CypherRelationship,
CypherPath,
CypherPoint,
CypherDate,
CypherTime,
CypherDateTime,
CypherDuration,
)
):
return value
raise TypeError("Unsupported type: {}".format(type(value)))
2 changes: 2 additions & 0 deletions nutkit/protocol/feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ class Feature(Enum):
BOLT_5_5 = "Feature:Bolt:5.5"
# The driver supports Bolt protocol version 5.6
BOLT_5_6 = "Feature:Bolt:5.6"
# The driver supports Bolt protocol version 5.7
BOLT_5_7 = "Feature:Bolt:5.7"
# The driver supports patching DateTimes to use UTC for Bolt 4.3 and 4.4
BOLT_PATCH_UTC = "Feature:Bolt:Patch:UTC"
# The driver supports impersonation
Expand Down
65 changes: 63 additions & 2 deletions nutkit/protocol/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -761,20 +761,81 @@ class DriverError(BaseError):
"""

def __init__(self, id=None, errorType=None, msg="", code="",
retryable=None):
retryable=None, gqlStatus=None, statusDescription=None,
cause=None, diagnosticRecord=None, classification=None,
rawClassification=None):
self.id = id
self.errorType = errorType
self.msg = msg
self.code = code
self.retryable = retryable
assert isinstance(gqlStatus, (str, type(None)))
self.gql_status = gqlStatus
assert isinstance(statusDescription, (str, type(None)))
self.status_description = statusDescription
if cause is not None:
assert isinstance(cause, GqlError)
self.cause = cause
assert isinstance(diagnosticRecord, (dict, type(None)))
self.diagnostic_record = diagnosticRecord
assert isinstance(classification, (str, type(None)))
self.classification = classification
assert isinstance(rawClassification, (str, type(None)))
self.raw_classification = rawClassification

def __str__(self):
return f"DriverError(type={self.errorType}, msg={self.msg!r})"
return (
f"DriverError("
f"errorType={self.errorType!r}, "
f"msg={self.msg!r}, "
f"code={self.code!r}, "
f"retryable={self.retryable!r}, "
f"gqlStatus={self.gql_status!r}, "
f"statusDescription={self.status_description!r}, "
f"diagnosticRecord={self.diagnostic_record!r}, "
f"classification={self.classification!r}, "
f"rawClassification={self.raw_classification!r}, "
f"cause={self.cause!r})"
)

def __repr__(self):
return self.__str__()


class GqlError:
"""TODO."""

def __init__(self, msg="", gqlStatus=None, statusDescription=None,
cause=None, diagnosticRecord=None, classification=None,
rawClassification=None):
self.msg = msg
assert isinstance(gqlStatus, (str, type(None)))
self.gql_status = gqlStatus
assert isinstance(statusDescription, (str, type(None)))
self.status_description = statusDescription
if cause is not None:
assert isinstance(cause, GqlError)
self.cause = cause
assert isinstance(diagnosticRecord, (dict, type(None)))
self.diagnostic_record = diagnosticRecord
assert isinstance(classification, (str, type(None)))
self.classification = classification
assert isinstance(rawClassification, (str, type(None)))
self.raw_classification = rawClassification

def __str__(self):
return (
f"DriverErrorCause("
f"msg={self.msg!r}, "
f"gqlStatus={self.gql_status!r}, "
f"statusDescription={self.status_description!r}, "
f"diagnosticRecord={self.diagnostic_record!r}, "
f"classification={self.classification!r}, "
f"rawClassification={self.raw_classification!r}, "
f"cause={self.cause!r})"
)


class FrontendError(BaseError):
"""
Error originating from client code.
Expand Down
Empty file added tests/stub/errors/__init__.py
Empty file.
19 changes: 19 additions & 0 deletions tests/stub/errors/scripts/error.script
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
!: BOLT #BOLT_VERSION#

A: HELLO {"{}": "*"}
A: LOGON {"{}": "*"}
*: RESET
C: RUN {"U": "*"} {"{}": "*"} {"{}": "*"}
S: FAILURE #ERROR#
# Allow driver to pipeline a PULL or DISCARD after RUN
{?
{{
C: PULL {"[n]": {"Z": "*"}}
S: IGNORED
----
C: DISCARD {"[n]": {"Z": "*"}}
S: IGNORED
}}
?}
+: RESET
A: GOODBYE
Loading