Skip to content

Commit 73b0a1b

Browse files
committed
more review comments
1 parent 0b63a09 commit 73b0a1b

14 files changed

+512
-464
lines changed

python/example_code/neptune/analytics/create_neptune_graph_example.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@ def main():
3030
def execute_create_graph(client, graph_name):
3131
try:
3232
print("Creating Neptune graph...")
33-
response = client.create_graph(graph_name=graph_name)
34-
35-
graph = response.get("graph", {})
36-
created_graph_name = graph.get("name")
37-
graph_arn = graph.get("arn")
38-
graph_endpoint = graph.get("endpoint")
33+
response = client.create_graph(
34+
graphName=graph_name,
35+
provisionedMemory = 16
36+
)
37+
38+
created_graph_name = response.get("name")
39+
graph_arn = response.get("arn")
40+
graph_endpoint = response.get("endpoint")
3941

4042
print("Graph created successfully!")
4143
print(f"Graph Name: {created_graph_name}")

python/example_code/neptune/analytics/neptune_analytics_query_example.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,6 @@ def run_open_cypher_query(client, graph_id):
5353

5454
except client.exceptions.InternalServerException as e:
5555
print(f"InternalServerException: {e.response['Error']['Message']}")
56-
except client.exceptions.BadRequestException as e:
57-
print(f"BadRequestException: {e.response['Error']['Message']}")
58-
except client.exceptions.LimitExceededException as e:
59-
print(f"LimitExceededException: {e.response['Error']['Message']}")
6056
except ClientError as e:
6157
print(f"ClientError: {e.response['Error']['Message']}")
6258
except Exception as e: # <--- ADD THIS BLOCK
@@ -78,10 +74,6 @@ def run_open_cypher_query_with_params(client, graph_id):
7874

7975
except client.exceptions.InternalServerException as e:
8076
print(f"InternalServerException: {e.response['Error']['Message']}")
81-
except client.exceptions.BadRequestException as e:
82-
print(f"BadRequestException: {e.response['Error']['Message']}")
83-
except client.exceptions.LimitExceededException as e:
84-
print(f"LimitExceededException: {e.response['Error']['Message']}")
8577
except ClientError as e:
8678
print(f"ClientError: {e.response['Error']['Message']}")
8779
except Exception as e: # <--- ADD THIS BLOCK
@@ -96,7 +88,7 @@ def run_open_cypher_explain_query(client, graph_id):
9688
graphIdentifier=graph_id,
9789
queryString="MATCH (n {code: 'ANC'}) RETURN n",
9890
language='OPEN_CYPHER',
99-
explainMode="debug"
91+
explainMode='DETAILS'
10092
)
10193
print(resp['payload'].read().decode('UTF-8'))
10294

python/example_code/neptune/database/neptune_execute_gremlin_profile_query.py

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ def main():
3737
)
3838

3939
try:
40-
run_explain_query(neptune_client)
4140
run_profile_query(neptune_client)
4241
except ClientError as e:
4342
print(f"Neptune error: {e.response['Error']['Message']}")
@@ -46,23 +45,6 @@ def main():
4645
except Exception as e:
4746
print(f"Unexpected error: {str(e)}")
4847

49-
50-
def run_explain_query(neptune_client):
51-
"""
52-
Runs an EXPLAIN query on the Neptune graph database.
53-
"""
54-
print("Running Gremlin EXPLAIN query...")
55-
56-
try:
57-
response = neptune_client.execute_gremlin_explain_query(
58-
gremlinQuery="g.V().has('code', 'ANC')"
59-
)
60-
print("Explain Query Result:")
61-
print(response.get("output", "No explain output returned."))
62-
except Exception as e:
63-
print(f"Failed to execute EXPLAIN query: {str(e)}")
64-
65-
6648
def run_profile_query(neptune_client):
6749
"""
6850
Runs a PROFILE query on the Neptune graph database.
@@ -74,7 +56,11 @@ def run_profile_query(neptune_client):
7456
gremlinQuery="g.V().has('code', 'ANC')"
7557
)
7658
print("Profile Query Result:")
77-
print(response['output'].read().decode('UTF-8'))
59+
output = response.get("output")
60+
if output:
61+
print(output.read().decode('utf-8'))
62+
else:
63+
print("No explain output returned.")
7864
except Exception as e:
7965
print(f"Failed to execute PROFILE query: {str(e)}")
8066

python/example_code/neptune/database/neptune_execute_gremlin_query.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@
2323
# Customize this with your Neptune endpoint
2424
NEPTUNE_ENDPOINT = "https://<your-neptune-endpoint>:8182"
2525

26-
def execute_gremlin_profile_query(client):
26+
def execute_gremlin_query(client):
2727
"""
2828
Executes a Gremlin query using the provided Neptune Data client.
2929
"""
30-
print("Executing Gremlin PROFILE query...")
30+
print("Executing Gremlin query...")
3131

3232
try:
3333
response = client.execute_gremlin_query(
34-
gremlinQueyr="g.V().has('code', 'ANC')"
34+
gremlinQuery="g.V().has('code', 'ANC')"
3535
)
3636

3737
print("Response is:")
@@ -59,7 +59,7 @@ def main():
5959
config=config
6060
)
6161

62-
execute_gremlin_profile_query(neptune_client)
62+
execute_gremlin_query(neptune_client)
6363

6464

6565
if __name__ == "__main__":

python/example_code/neptune/database/neptune_execute_open_cypher_query.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def execute_open_cypher_explain_query(client):
8282
print("\nRunning OpenCypher EXPLAIN query (debug mode)...")
8383
resp = client.execute_open_cypher_explain_query(
8484
openCypherQuery="MATCH (n {code: 'ANC'}) RETURN n",
85-
explainMode="debug"
85+
explainMode="details"
8686
)
8787
results = resp.get('results')
8888
if results is None:
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import boto3
2+
import io
3+
from botocore.stub import Stubber
4+
from botocore.response import StreamingBody
5+
from botocore.config import Config
6+
7+
GRAPH_ID = "my-graph-id"
8+
GRAPH_NAME = "my-test-graph"
9+
10+
class NeptuneGraphStubber:
11+
def __init__(self):
12+
"""
13+
Create NeptuneGraph client and stubber with minimal retry config for testing.
14+
"""
15+
config = Config(retries={"total_max_attempts": 1, "mode": "standard"}, read_timeout=None)
16+
self.client = boto3.client("neptune-graph", config=config)
17+
self.stubber = Stubber(self.client)
18+
19+
def add_execute_query_stub(self, graph_id, query_string, language, explain_mode=None, parameters=None):
20+
"""
21+
Add stub response for execute_query call matching parameters including optional explainMode and parameters.
22+
"""
23+
expected_params = {
24+
"graphIdentifier": graph_id,
25+
"queryString": query_string,
26+
"language": language,
27+
}
28+
if explain_mode is not None:
29+
expected_params["explainMode"] = explain_mode
30+
if parameters is not None:
31+
expected_params["parameters"] = parameters
32+
33+
# Example JSON payload response the service expects
34+
payload_bytes = b'{"results": [{"n": {"code": "ANC"}}]}'
35+
response_body = StreamingBody(io.BytesIO(payload_bytes), len(payload_bytes))
36+
response = {"payload": response_body}
37+
38+
self.stubber.add_response("execute_query", response, expected_params)
39+
40+
def add_create_graph_stub(self, graph_name, memory=16):
41+
"""
42+
Add stub response for create_graph call matching graphName and provisionedMemory parameters.
43+
"""
44+
expected_params = {
45+
"graphName": graph_name,
46+
"provisionedMemory": memory
47+
}
48+
response = {
49+
"id": "test-graph-id", # Required field in response
50+
"name": graph_name,
51+
"arn": f"arn:aws:neptune-graph:us-east-1:123456789012:graph/{graph_name}",
52+
"endpoint": f"https://{graph_name}.cluster-neptune.amazonaws.com"
53+
}
54+
self.stubber.add_response("create_graph", response, expected_params)
55+
56+
def activate(self):
57+
"""
58+
Activate the stubber.
59+
"""
60+
self.stubber.activate()
61+
62+
def deactivate(self):
63+
"""
64+
Deactivate the stubber.
65+
"""
66+
self.stubber.deactivate()
67+
68+
def get_client(self):
69+
"""
70+
Return the stubbed NeptuneGraph client.
71+
"""
72+
return self.client
73+
74+
75+
Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,55 @@
1-
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2-
# SPDX-License-Identifier: Apache-2.0
3-
4-
from unittest.mock import MagicMock
1+
import pytest
52
from botocore.exceptions import ClientError, BotoCoreError
6-
from analytics.create_neptune_graph_example import execute_create_graph # Adjust import as needed
3+
from analytics.create_neptune_graph_example import execute_create_graph
4+
from neptune_graph_stubber import NeptuneGraphStubber
75

8-
def test_execute_create_graph(capfd):
9-
mock_client = MagicMock()
6+
class MockBotoCoreError(BotoCoreError):
7+
def __init__(self, message="BotoCore error occurred"):
8+
super().__init__()
9+
self.message = message
10+
11+
def __str__(self):
12+
return self.message
1013

14+
def test_execute_create_graph(capfd):
1115
# --- Success case ---
12-
mock_client.create_graph.return_value = {
13-
"GraphName": "test-graph",
14-
"GraphArn": "arn:aws:neptune:region:123456789012:graph/test-graph",
15-
"GraphEndpoint": "https://test-graph.endpoint"
16-
}
16+
stubber = NeptuneGraphStubber()
17+
client = stubber.get_client()
18+
stubber.activate()
1719

18-
execute_create_graph(mock_client, "test-graph")
20+
stubber.add_create_graph_stub("test-graph")
21+
execute_create_graph(client, "test-graph")
1922
out, _ = capfd.readouterr()
2023
assert "Creating Neptune graph..." in out
2124
assert "Graph created successfully!" in out
2225
assert "Graph Name: test-graph" in out
23-
assert "Graph ARN: arn:aws:neptune:region:123456789012:graph/test-graph" in out
24-
assert "Graph Endpoint: https://test-graph.endpoint" in out
26+
assert "Graph ARN: arn:aws:neptune-graph:us-east-1:123456789012:graph/test-graph" in out
27+
assert "Graph Endpoint: https://test-graph.cluster-neptune.amazonaws.com" in out
28+
29+
stubber.deactivate() # deactivate the stubber before mocking
2530

2631
# --- ClientError case ---
27-
mock_client.create_graph.side_effect = ClientError(
28-
{"Error": {"Message": "Client error occurred"}}, "CreateGraph"
29-
)
30-
execute_create_graph(mock_client, "test-graph")
32+
def raise_client_error(**kwargs):
33+
raise ClientError(
34+
{"Error": {"Message": "Client error occurred"}}, "CreateGraph"
35+
)
36+
client.create_graph = raise_client_error
37+
execute_create_graph(client, "test-graph")
3138
out, _ = capfd.readouterr()
3239
assert "Failed to create graph: Client error occurred" in out
3340

3441
# --- BotoCoreError case ---
35-
mock_client.create_graph.side_effect = BotoCoreError()
36-
execute_create_graph(mock_client, "test-graph")
42+
def raise_boto_core_error(**kwargs):
43+
raise MockBotoCoreError()
44+
client.create_graph = raise_boto_core_error
45+
execute_create_graph(client, "test-graph")
3746
out, _ = capfd.readouterr()
38-
assert "Failed to create graph:" in out # check prefix only
47+
assert "Failed to create graph: BotoCore error occurred" in out
3948

4049
# --- Generic Exception case ---
41-
mock_client.create_graph.side_effect = Exception("Generic failure")
42-
execute_create_graph(mock_client, "test-graph")
50+
def raise_generic_error(**kwargs):
51+
raise Exception("Generic failure")
52+
client.create_graph = raise_generic_error
53+
execute_create_graph(client, "test-graph")
4354
out, _ = capfd.readouterr()
4455
assert "Unexpected error: Generic failure" in out

0 commit comments

Comments
 (0)