Skip to content

Commit bff9cd6

Browse files
authored
Testing 0.0.2 (#343)
* Add .gitignore to exclude temporary files and directories * Enhance upsert_graph_template function to include store_config and improve error handling - Added store_config to the GraphTemplate creation process, ensuring comprehensive data handling. - Improved error handling by refining the structure of the upsert_graph_template function, enhancing robustness and clarity. - Included debug print statements for graph_template to aid in troubleshooting during development. * Remove debug print statements from upsert_graph_template function to clean up code and improve readability. * Update verify_inputs function to skip processing for 'store' identifier - Added a condition to the verify_inputs function in verify_graph.py to continue the loop when the identifier is 'store', preventing unnecessary processing for this case. * Skip processing for 'store' identifier in validate_dependencies function - Added a condition in the validate_dependencies function to continue the loop when the dependent identifier is 'store', preventing unnecessary validation checks for this case. * Enhance trigger_graph function to validate and process dependent strings - Added logic to validate dependent strings in the trigger_graph function, ensuring that only valid identifiers are processed and that dependencies exist in the provided store. - Improved error handling to provide clearer feedback when inputs are invalid, enhancing robustness and user experience. * Refactor endpoint URLs in runtime and routes to use singular 'state' instead of plural 'states' - Updated the endpoint construction in the Runtime class to reflect the change from '/states/{state_id}/executed' to '/state/{state_id}/executed' and similarly for the errored endpoint. - Modified the route definitions in the state-manager to align with the new singular endpoint structure for executed, errored, and prune state routes. * Refactor PruneSignal to encapsulate data in a dictionary before sending HTTP request - Updated the PruneSignal class to wrap the data in a dictionary when making the POST request, improving the structure of the request payload. * Update .gitignore to exclude temporary files and ensure .gitkeep is tracked - Enhanced .gitignore to ignore all temporary files and directories while ensuring that the .gitkeep file in the temp directory is not ignored, maintaining the directory structure in the repository. - Improved clarity of the ignore rules for better maintainability. * Refactor endpoint URLs in tests to use singular 'state' for consistency - Updated test assertions in `test_runtime_comprehensive.py` and `test_signals_and_runtime_functions.py` to reflect the change from '/states/{state_id}/...' to '/state/{state_id}/...' for executed and errored endpoints. - Ensured that the data structure in the POST request for prune operations is correctly encapsulated in a dictionary. * Update test assertions in test_routes.py to reflect singular 'state' endpoint structure - Modified assertions in the TestRouteStructure class to replace deprecated plural 'states' routes with singular 'state' routes for executed, errored, prune, and re-enqueue-after endpoints. - Ensured consistency with recent refactoring of endpoint URLs across the codebase. * Update version to 0.0.2b4 and enhance unit tests for trigger_graph functionality - Incremented the version in _version.py to 0.0.2b4. - Added multiple unit tests for the trigger_graph function to cover various scenarios, including handling dependent strings, validation errors, and edge cases with empty or invalid inputs. - Improved assertions in existing tests to ensure comprehensive coverage and robustness of the trigger_graph functionality. * Enhance unit tests for create_next_states and verify_graph functions - Updated the test_create_next_states.py to improve the test for handling empty state_ids, ensuring that a ValueError is raised and the exception handler is verified. - Expanded test_verify_graph.py with new tests for validation errors, valid graphs, and various input scenarios, ensuring comprehensive coverage of the verify_graph functionality. - Improved assertions to validate the behavior of the graph template under different conditions, enhancing the robustness of the tests. * Refactor unit tests to improve clarity and maintainability - Removed unused imports in test_create_next_states.py to streamline the test file. - Updated the logger patch in test_verify_graph.py for improved readability and consistency in mocking.
1 parent 0d64939 commit bff9cd6

16 files changed

Lines changed: 853 additions & 36 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Ignore temp directory and temp files at repository root
2+
/temp*
3+
!/temp/.gitkeep
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
version = "0.0.2b3"
1+
version = "0.0.2b4"

python-sdk/exospherehost/runtime.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,13 @@ def _get_executed_endpoint(self, state_id: str):
141141
"""
142142
Construct the endpoint URL for notifying executed states.
143143
"""
144-
return f"{self._state_manager_uri}/{str(self._state_manager_version)}/namespace/{self._namespace}/states/{state_id}/executed"
144+
return f"{self._state_manager_uri}/{str(self._state_manager_version)}/namespace/{self._namespace}/state/{state_id}/executed"
145145

146146
def _get_errored_endpoint(self, state_id: str):
147147
"""
148148
Construct the endpoint URL for notifying errored states.
149149
"""
150-
return f"{self._state_manager_uri}/{str(self._state_manager_version)}/namespace/{self._namespace}/states/{state_id}/errored"
150+
return f"{self._state_manager_uri}/{str(self._state_manager_version)}/namespace/{self._namespace}/state/{state_id}/errored"
151151

152152
def _get_register_endpoint(self):
153153
"""

python-sdk/exospherehost/signals.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@ async def send(self, endpoint: str, key: str):
2727
Raises:
2828
Exception: If the HTTP request fails (status code != 200).
2929
"""
30+
body = {
31+
"data": self.data
32+
}
3033
async with ClientSession() as session:
31-
async with session.post(endpoint, json=self.data, headers={"x-api-key": key}) as response:
34+
async with session.post(endpoint, json=body, headers={"x-api-key": key}) as response:
3235
if response.status != 200:
3336
raise Exception(f"Failed to send prune signal to {endpoint}")
3437

python-sdk/tests/test_runtime_comprehensive.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,13 +192,13 @@ def test_get_enque_endpoint(self, runtime_config):
192192
def test_get_executed_endpoint(self, runtime_config):
193193
runtime = Runtime(**runtime_config)
194194
endpoint = runtime._get_executed_endpoint("state123")
195-
expected = "http://localhost:8080/v1/namespace/test_namespace/states/state123/executed"
195+
expected = "http://localhost:8080/v1/namespace/test_namespace/state/state123/executed"
196196
assert endpoint == expected
197197

198198
def test_get_errored_endpoint(self, runtime_config):
199199
runtime = Runtime(**runtime_config)
200200
endpoint = runtime._get_errored_endpoint("state123")
201-
expected = "http://localhost:8080/v1/namespace/test_namespace/states/state123/errored"
201+
expected = "http://localhost:8080/v1/namespace/test_namespace/state/state123/errored"
202202
assert endpoint == expected
203203

204204
def test_get_register_endpoint(self, runtime_config):

python-sdk/tests/test_signals_and_runtime_functions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ async def test_prune_signal_send_success(self):
9595
# Verify the request was made correctly
9696
mock_session.post.assert_called_once_with(
9797
"http://test-endpoint/prune",
98-
json=data,
98+
json={"data": data},
9999
headers={"x-api-key": "test-api-key"}
100100
)
101101

@@ -270,7 +270,7 @@ async def test_signal_handling_direct(self):
270270
# Verify prune endpoint was called correctly
271271
mock_session.post.assert_called_once_with(
272272
runtime._get_prune_endpoint("test-state"),
273-
json={"reason": "direct_test"},
273+
json={"data": {"reason": "direct_test"}},
274274
headers={"x-api-key": "test-key"}
275275
)
276276

state-manager/app/controller/trigger_graph.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from app.models.db.run import Run
99
from app.models.db.graph_template_model import GraphTemplate
1010
from app.models.node_template_model import NodeTemplate
11+
from app.models.dependent_string import DependentString
1112
import uuid
1213

1314
logger = LogsManager().get_logger()
@@ -41,6 +42,30 @@ async def trigger_graph(namespace_name: str, graph_name: str, body: TriggerGraph
4142

4243
if not graph_template.is_valid():
4344
raise HTTPException(status_code=400, detail="Graph template is not valid")
45+
46+
root = graph_template.get_root_node()
47+
inputs = construct_inputs(root, body.inputs)
48+
49+
try:
50+
for field, value in inputs.items():
51+
dependent_string = DependentString.create_dependent_string(value)
52+
53+
for dependent in dependent_string.dependents.values():
54+
if dependent.identifier != "store":
55+
raise HTTPException(status_code=400, detail=f"Root node can have only store identifier as dependent but got {dependent.identifier}")
56+
elif dependent.field not in body.store:
57+
if dependent.field in graph_template.store_config.default_values.keys():
58+
dependent_string.set_value(dependent.identifier, dependent.field, graph_template.store_config.default_values[dependent.field])
59+
else:
60+
raise HTTPException(status_code=400, detail=f"Dependent {dependent.field} not found in store for root node {root.identifier}")
61+
else:
62+
dependent_string.set_value(dependent.identifier, dependent.field, body.store[dependent.field])
63+
64+
inputs[field] = dependent_string.generate_string()
65+
66+
except Exception as e:
67+
raise HTTPException(status_code=400, detail=f"Invalid input: {e}")
68+
4469

4570
check_required_store_keys(graph_template, body.store)
4671

@@ -64,16 +89,14 @@ async def trigger_graph(namespace_name: str, graph_name: str, body: TriggerGraph
6489
if len(new_stores) > 0:
6590
await Store.insert_many(new_stores)
6691

67-
root = graph_template.get_root_node()
68-
6992
new_state = State(
7093
node_name=root.node_name,
7194
namespace_name=namespace_name,
7295
identifier=root.identifier,
7396
graph_name=graph_name,
7497
run_id=run_id,
7598
status=StateStatusEnum.CREATED,
76-
inputs=construct_inputs(root, body.inputs),
99+
inputs=inputs,
77100
outputs={},
78101
error=None
79102
)

state-manager/app/controller/upsert_graph_template.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ async def upsert_graph_template(namespace_name: str, graph_name: str, body: Upse
1515
GraphTemplate.name == graph_name,
1616
GraphTemplate.namespace == namespace_name
1717
)
18-
18+
1919
try:
2020
if graph_template:
2121
logger.info(
@@ -28,7 +28,8 @@ async def upsert_graph_template(namespace_name: str, graph_name: str, body: Upse
2828
GraphTemplate.nodes: body.nodes, # type: ignore
2929
GraphTemplate.validation_status: GraphTemplateValidationStatus.PENDING, # type: ignore
3030
GraphTemplate.validation_errors: [], # type: ignore
31-
GraphTemplate.retry_policy: body.retry_policy # type: ignore
31+
GraphTemplate.retry_policy: body.retry_policy, # type: ignore
32+
GraphTemplate.store_config: body.store_config # type: ignore
3233
})
3334
)
3435

@@ -46,7 +47,8 @@ async def upsert_graph_template(namespace_name: str, graph_name: str, body: Upse
4647
nodes=body.nodes,
4748
validation_status=GraphTemplateValidationStatus.PENDING,
4849
validation_errors=[],
49-
retry_policy=body.retry_policy
50+
retry_policy=body.retry_policy,
51+
store_config=body.store_config
5052
).set_secrets(body.secrets)
5153
)
5254
except ValueError as e:

state-manager/app/routes.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ async def trigger_graph_route(namespace_name: str, graph_name: str, body: Trigge
9292
return await trigger_graph(namespace_name, graph_name, body, x_exosphere_request_id)
9393

9494
@router.post(
95-
"/states/{state_id}/executed",
95+
"/state/{state_id}/executed",
9696
response_model=ExecutedResponseModel,
9797
status_code=status.HTTP_200_OK,
9898
response_description="State executed successfully",
@@ -112,7 +112,7 @@ async def executed_state_route(namespace_name: str, state_id: str, body: Execute
112112

113113

114114
@router.post(
115-
"/states/{state_id}/errored",
115+
"/state/{state_id}/errored",
116116
response_model=ErroredResponseModel,
117117
status_code=status.HTTP_200_OK,
118118
response_description="State errored successfully",
@@ -132,7 +132,7 @@ async def errored_state_route(namespace_name: str, state_id: str, body: ErroredR
132132

133133

134134
@router.post(
135-
"/states/{state_id}/prune",
135+
"/state/{state_id}/prune",
136136
response_model=SignalResponseModel,
137137
status_code=status.HTTP_200_OK,
138138
response_description="State pruned successfully",
@@ -151,7 +151,7 @@ async def prune_state_route(namespace_name: str, state_id: str, body: PruneReque
151151

152152

153153
@router.post(
154-
"/states/{state_id}/re-enqueue-after",
154+
"/state/{state_id}/re-enqueue-after",
155155
response_model=SignalResponseModel,
156156
status_code=status.HTTP_200_OK,
157157
response_description="State re-enqueued successfully",

state-manager/app/tasks/create_next_states.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ def validate_dependencies(next_state_node_template: NodeTemplate, next_state_inp
7070
dependency_string = DependentString.create_dependent_string(next_state_node_template.inputs[field_name])
7171

7272
for dependent in dependency_string.dependents.values():
73+
if dependent.identifier == "store":
74+
continue
7375
# 2) For each placeholder, verify the identifier is either current or present in parents
7476
if dependent.identifier != identifier and dependent.identifier not in parents:
7577
raise KeyError(f"Identifier '{dependent.identifier}' not found in parents for template '{next_state_node_template.identifier}'")

0 commit comments

Comments
 (0)