From 003bb7f0e76b979ebc687090f487cd8d97aa9c6f Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Thu, 18 Apr 2024 13:58:25 -0700 Subject: [PATCH 01/20] initial commit --- azure/durable_functions/models/DurableOrchestrationContext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure/durable_functions/models/DurableOrchestrationContext.py b/azure/durable_functions/models/DurableOrchestrationContext.py index df101003..74398fc7 100644 --- a/azure/durable_functions/models/DurableOrchestrationContext.py +++ b/azure/durable_functions/models/DurableOrchestrationContext.py @@ -236,7 +236,7 @@ def call_http(self, method: str, uri: str, content: Optional[str] = None, The durable HTTP request to schedule. """ json_content: Optional[str] = None - if content and content is not isinstance(content, str): + if content is None: json_content = json.dumps(content) else: json_content = content From 6fe6471ac3326bd292ef3997475f7d7897fbcb14 Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Thu, 18 Apr 2024 14:03:20 -0700 Subject: [PATCH 02/20] remove unused pkg --- azure/durable_functions/models/OrchestratorState.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure/durable_functions/models/OrchestratorState.py b/azure/durable_functions/models/OrchestratorState.py index abf09a74..7b426292 100644 --- a/azure/durable_functions/models/OrchestratorState.py +++ b/azure/durable_functions/models/OrchestratorState.py @@ -1,5 +1,5 @@ import json -from typing import List, Any, Dict, Optional, Union +from typing import List, Any, Dict, Optional from azure.durable_functions.models.ReplaySchema import ReplaySchema From f56a3226e2eaa690f8a85a0a7a27ff3812b8237c Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Wed, 2 Oct 2024 09:43:49 -0700 Subject: [PATCH 03/20] improve call_http for clarity --- .../models/DurableOrchestrationContext.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/azure/durable_functions/models/DurableOrchestrationContext.py b/azure/durable_functions/models/DurableOrchestrationContext.py index 74398fc7..42ac4d80 100644 --- a/azure/durable_functions/models/DurableOrchestrationContext.py +++ b/azure/durable_functions/models/DurableOrchestrationContext.py @@ -236,10 +236,11 @@ def call_http(self, method: str, uri: str, content: Optional[str] = None, The durable HTTP request to schedule. """ json_content: Optional[str] = None - if content is None: - json_content = json.dumps(content) - else: - json_content = content + if content is not None: + if not isinstance(content, str): + json_content = json.dumps(content) + else: + json_content = content request = DurableHttpRequest(method, uri, json_content, headers, token_source) action = CallHttpAction(request) From 74f400f9ff340b1ee3f23595cd102d65ad6d069b Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Wed, 2 Oct 2024 13:07:46 -0700 Subject: [PATCH 04/20] add content handling test for call_http --- tests/orchestrator/test_call_http.py | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/orchestrator/test_call_http.py b/tests/orchestrator/test_call_http.py index be46d870..c95db756 100644 --- a/tests/orchestrator/test_call_http.py +++ b/tests/orchestrator/test_call_http.py @@ -174,3 +174,36 @@ def test_post_completed_state(): # assert_valid_schema(result) assert_orchestration_state_equals(expected, result) validate_result_http_request(result) + +@pytest.mark.parametrize("content, expected_content", [ + (None, None), + ("string data", "string data"), + ('{"key": "value"}', '{"key": "value"}'), + ('["list", "content"]', '["list", "content"]'), + ('[]', '[]'), + ('42', '42'), + ('true', 'true'), + # Cases that test actual behavior (not strictly adhering to Optional[str]) + ({"key": "value"}, '{"key": "value"}'), + (["list", "content"], '["list", "content"]'), + ([], '[]'), + (42, '42'), + (True, 'true'), +]) +def test_call_http_content_handling(content, expected_content): + context = DurableOrchestrationContext.from_json( + '{"history":[],"input":null,"instanceId":"test","isReplaying":false,"parentInstanceId":null}') + method = "GET" + uri = "https://localhost:7071/test" + + task = context.call_http(method, uri, content) + + assert isinstance(task, TaskBase) + assert len(context._actions) == 1 + action = context._actions[0][0] + assert isinstance(action, CallHttpAction) + + http_request = action.http_request + assert http_request.method == method + assert http_request.uri == uri + assert http_request.content == expected_content From 55c310c9feb3b6803fd1957c28bb815e9c7ade67 Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Wed, 2 Oct 2024 13:12:00 -0700 Subject: [PATCH 05/20] add import --- tests/orchestrator/test_call_http.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/orchestrator/test_call_http.py b/tests/orchestrator/test_call_http.py index c95db756..0a221aa5 100644 --- a/tests/orchestrator/test_call_http.py +++ b/tests/orchestrator/test_call_http.py @@ -1,5 +1,6 @@ from azure.durable_functions.models.ReplaySchema import ReplaySchema import json +import pytest from typing import Dict from azure.durable_functions.constants import HTTP_ACTION_NAME @@ -7,6 +8,7 @@ from .orchestrator_test_utils import assert_orchestration_state_equals, \ get_orchestration_state_result, assert_valid_schema, assert_dict_are_equal from tests.test_utils.ContextBuilder import ContextBuilder +from azure.durable_functions.models.DurableOrchestrationContext import DurableOrchestrationContext from azure.durable_functions.models.OrchestratorState import OrchestratorState from azure.durable_functions.models.actions.CallHttpAction import CallHttpAction from azure.durable_functions.models.TokenSource import ManagedIdentityTokenSource @@ -198,7 +200,6 @@ def test_call_http_content_handling(content, expected_content): task = context.call_http(method, uri, content) - assert isinstance(task, TaskBase) assert len(context._actions) == 1 action = context._actions[0][0] assert isinstance(action, CallHttpAction) From 82b4a633b11adbe6cc1a8bf831f4fd24c6a04a2a Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Wed, 2 Oct 2024 13:34:46 -0700 Subject: [PATCH 06/20] update test --- tests/orchestrator/test_call_http.py | 29 +++++++++++++--------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/tests/orchestrator/test_call_http.py b/tests/orchestrator/test_call_http.py index 0a221aa5..3fcbab94 100644 --- a/tests/orchestrator/test_call_http.py +++ b/tests/orchestrator/test_call_http.py @@ -63,8 +63,8 @@ def get_request() -> DurableHttpRequest: return DurableHttpRequest(method='GET', uri=TEST_URI) -def post_request() -> DurableHttpRequest: - return DurableHttpRequest(method="POST", uri=TEST_URI, content=json.dumps(CONTENT), +def post_request(content: Optional[str] = None) -> DurableHttpRequest: + return DurableHttpRequest(method="POST", uri=TEST_URI, content=json.dumps(content), headers=HEADERS, token_source=TOKEN_SOURCE) @@ -135,7 +135,7 @@ def test_initial_post_state(): context_builder, complete_generator_function) expected_state = base_expected_state() - request = post_request() + request = post_request(CONTENT) add_http_action(expected_state, request) expected = expected_state.to_json() @@ -168,7 +168,7 @@ def test_post_completed_state(): context_builder, complete_generator_function) expected_state = base_expected_state() - request = post_request() + request = post_request(CONTENT) add_http_action(expected_state, request) expected_state._is_done = True expected = expected_state.to_json() @@ -193,18 +193,15 @@ def test_post_completed_state(): (True, 'true'), ]) def test_call_http_content_handling(content, expected_content): - context = DurableOrchestrationContext.from_json( - '{"history":[],"input":null,"instanceId":"test","isReplaying":false,"parentInstanceId":null}') - method = "GET" - uri = "https://localhost:7071/test" + def orchestrator_function(context): + yield context.call_http("POST", TEST_URI, content) - task = context.call_http(method, uri, content) + context_builder = ContextBuilder('test_call_http_content_handling') + result = get_orchestration_state_result(context_builder, orchestrator_function) - assert len(context._actions) == 1 - action = context._actions[0][0] - assert isinstance(action, CallHttpAction) + assert len(result['actions']) == 1 + http_action = result['actions'][0][0]['httpRequest'] - http_request = action.http_request - assert http_request.method == method - assert http_request.uri == uri - assert http_request.content == expected_content + assert http_action['method'] == "POST" + assert http_action['uri'] == TEST_URI + assert http_action['content'] == expected_content From 6f3a01803d4e061cd6e22744fe09256d0ef78944 Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Wed, 2 Oct 2024 13:37:23 -0700 Subject: [PATCH 07/20] update test --- tests/orchestrator/test_call_http.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/orchestrator/test_call_http.py b/tests/orchestrator/test_call_http.py index 3fcbab94..8e33de9d 100644 --- a/tests/orchestrator/test_call_http.py +++ b/tests/orchestrator/test_call_http.py @@ -63,7 +63,7 @@ def get_request() -> DurableHttpRequest: return DurableHttpRequest(method='GET', uri=TEST_URI) -def post_request(content: Optional[str] = None) -> DurableHttpRequest: +def post_request() -> DurableHttpRequest: return DurableHttpRequest(method="POST", uri=TEST_URI, content=json.dumps(content), headers=HEADERS, token_source=TOKEN_SOURCE) @@ -135,7 +135,7 @@ def test_initial_post_state(): context_builder, complete_generator_function) expected_state = base_expected_state() - request = post_request(CONTENT) + request = post_request() add_http_action(expected_state, request) expected = expected_state.to_json() @@ -168,7 +168,7 @@ def test_post_completed_state(): context_builder, complete_generator_function) expected_state = base_expected_state() - request = post_request(CONTENT) + request = post_request() add_http_action(expected_state, request) expected_state._is_done = True expected = expected_state.to_json() From 81697131060b14248901d31fc0c5cd7e2298d097 Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Wed, 2 Oct 2024 13:39:16 -0700 Subject: [PATCH 08/20] update typo --- tests/orchestrator/test_call_http.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/orchestrator/test_call_http.py b/tests/orchestrator/test_call_http.py index 8e33de9d..c2e4369a 100644 --- a/tests/orchestrator/test_call_http.py +++ b/tests/orchestrator/test_call_http.py @@ -64,7 +64,7 @@ def get_request() -> DurableHttpRequest: def post_request() -> DurableHttpRequest: - return DurableHttpRequest(method="POST", uri=TEST_URI, content=json.dumps(content), + return DurableHttpRequest(method="POST", uri=TEST_URI, content=json.dumps(CONTENT), headers=HEADERS, token_source=TOKEN_SOURCE) From 87a38e903ee4a14004ec9ff7dbe9cbdf0401bfc4 Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Wed, 2 Oct 2024 13:44:18 -0700 Subject: [PATCH 09/20] remove unused using --- tests/orchestrator/test_call_http.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/orchestrator/test_call_http.py b/tests/orchestrator/test_call_http.py index c2e4369a..0543c43f 100644 --- a/tests/orchestrator/test_call_http.py +++ b/tests/orchestrator/test_call_http.py @@ -8,7 +8,6 @@ from .orchestrator_test_utils import assert_orchestration_state_equals, \ get_orchestration_state_result, assert_valid_schema, assert_dict_are_equal from tests.test_utils.ContextBuilder import ContextBuilder -from azure.durable_functions.models.DurableOrchestrationContext import DurableOrchestrationContext from azure.durable_functions.models.OrchestratorState import OrchestratorState from azure.durable_functions.models.actions.CallHttpAction import CallHttpAction from azure.durable_functions.models.TokenSource import ManagedIdentityTokenSource From 2a6bcedb3c40a9a41646fb1e178a673f5c4b6b82 Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Fri, 4 Oct 2024 11:41:07 -0700 Subject: [PATCH 10/20] update by comments --- .../models/DurableOrchestrationContext.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/azure/durable_functions/models/DurableOrchestrationContext.py b/azure/durable_functions/models/DurableOrchestrationContext.py index 42ac4d80..d7a30fb4 100644 --- a/azure/durable_functions/models/DurableOrchestrationContext.py +++ b/azure/durable_functions/models/DurableOrchestrationContext.py @@ -214,7 +214,8 @@ def call_activity_with_retry(self, def call_http(self, method: str, uri: str, content: Optional[str] = None, headers: Optional[Dict[str, str]] = None, - token_source: TokenSource = None) -> TaskBase: + token_source: TokenSource = None, + is_raw_str: bool = False) -> TaskBase: """Schedule a durable HTTP call to the specified endpoint. Parameters @@ -237,10 +238,11 @@ def call_http(self, method: str, uri: str, content: Optional[str] = None, """ json_content: Optional[str] = None if content is not None: - if not isinstance(content, str): - json_content = json.dumps(content) - else: + if isinstance(content, str) and is_raw_str: + # don't serialize the str value - use it as the raw HTTP request payload json_content = content + else: + json_content = json.dumps(content) request = DurableHttpRequest(method, uri, json_content, headers, token_source) action = CallHttpAction(request) From 79ec2810b4eff63e85025a4be3f0c1cf088a4a68 Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Fri, 4 Oct 2024 11:42:20 -0700 Subject: [PATCH 11/20] add space --- azure/durable_functions/models/DurableOrchestrationContext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure/durable_functions/models/DurableOrchestrationContext.py b/azure/durable_functions/models/DurableOrchestrationContext.py index d7a30fb4..100c018a 100644 --- a/azure/durable_functions/models/DurableOrchestrationContext.py +++ b/azure/durable_functions/models/DurableOrchestrationContext.py @@ -239,7 +239,7 @@ def call_http(self, method: str, uri: str, content: Optional[str] = None, json_content: Optional[str] = None if content is not None: if isinstance(content, str) and is_raw_str: - # don't serialize the str value - use it as the raw HTTP request payload + # don't serialize the str value - use it as the raw HTTP request payload json_content = content else: json_content = json.dumps(content) From 0dc14567e8af6da9ed59b1b26c3895c3104146c1 Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Fri, 4 Oct 2024 11:49:55 -0700 Subject: [PATCH 12/20] update unit tests as we update call_http logic --- tests/orchestrator/test_call_http.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/orchestrator/test_call_http.py b/tests/orchestrator/test_call_http.py index 0543c43f..4009bb69 100644 --- a/tests/orchestrator/test_call_http.py +++ b/tests/orchestrator/test_call_http.py @@ -178,12 +178,12 @@ def test_post_completed_state(): @pytest.mark.parametrize("content, expected_content", [ (None, None), - ("string data", "string data"), - ('{"key": "value"}', '{"key": "value"}'), - ('["list", "content"]', '["list", "content"]'), - ('[]', '[]'), - ('42', '42'), - ('true', 'true'), + ("string data", '"string data"'), + ('{"key": "value"}', '"{\\"key\\": \\"value\\"}"'), + ('["list", "content"]', '"[\\"list\\", \\"content\\"]"'), + ('[]', '"[]"'), + ('42', '"42"'), + ('true', '"true"'), # Cases that test actual behavior (not strictly adhering to Optional[str]) ({"key": "value"}, '{"key": "value"}'), (["list", "content"], '["list", "content"]'), From 138439dc4bc67e9307156b5a40beaf0c7939f7bc Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Sun, 6 Oct 2024 19:57:05 -0700 Subject: [PATCH 13/20] update by comment --- .../models/DurableOrchestrationContext.py | 3 ++ tests/orchestrator/test_call_http.py | 34 +++++++++++-------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/azure/durable_functions/models/DurableOrchestrationContext.py b/azure/durable_functions/models/DurableOrchestrationContext.py index 100c018a..2b59de12 100644 --- a/azure/durable_functions/models/DurableOrchestrationContext.py +++ b/azure/durable_functions/models/DurableOrchestrationContext.py @@ -230,6 +230,9 @@ def call_http(self, method: str, uri: str, content: Optional[str] = None, The HTTP request headers. token_source: TokenSource The source of OAuth token to add to the request. + is_raw_str: bool, optional + If True, the content will be treated as a raw string and will not be serialized to JSON. + If False (default), the content will be serialized to a JSON string before sending. Returns ------- diff --git a/tests/orchestrator/test_call_http.py b/tests/orchestrator/test_call_http.py index 4009bb69..8314f943 100644 --- a/tests/orchestrator/test_call_http.py +++ b/tests/orchestrator/test_call_http.py @@ -176,24 +176,28 @@ def test_post_completed_state(): assert_orchestration_state_equals(expected, result) validate_result_http_request(result) -@pytest.mark.parametrize("content, expected_content", [ - (None, None), - ("string data", '"string data"'), - ('{"key": "value"}', '"{\\"key\\": \\"value\\"}"'), - ('["list", "content"]', '"[\\"list\\", \\"content\\"]"'), - ('[]', '"[]"'), - ('42', '"42"'), - ('true', '"true"'), +@pytest.mark.parametrize("content, expected_content, is_raw_str", [ + (None, None, False), + ("string data", '"string data"', False), + ('{"key": "value"}', '"{\\"key\\": \\"value\\"}"', False), + ('["list", "content"]', '"[\\"list\\", \\"content\\"]"', False), + ('[]', '"[]"', False), + ('42', '"42"', False), + ('true', '"true"', False), # Cases that test actual behavior (not strictly adhering to Optional[str]) - ({"key": "value"}, '{"key": "value"}'), - (["list", "content"], '["list", "content"]'), - ([], '[]'), - (42, '42'), - (True, 'true'), + ({"key": "value"}, '{"key": "value"}', False), + (["list", "content"], '["list", "content"]', False), + ([], '[]', False), + (42, '42', False), + (True, 'true', False), + # Cases when is_raw_str is True + ("string data", "string data", True), + ('{"key": "value"}', '{"key": "value"}', True), + ('[]', '[]', True), ]) -def test_call_http_content_handling(content, expected_content): +def test_call_http_content_handling(content, expected_content, is_raw_str): def orchestrator_function(context): - yield context.call_http("POST", TEST_URI, content) + yield context.call_http("POST", TEST_URI, content, is_raw_str=is_raw_str) context_builder = ContextBuilder('test_call_http_content_handling') result = get_orchestration_state_result(context_builder, orchestrator_function) From 8ce42d9fb6744e2ed83bf48691b0d88f8b049182 Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Sun, 6 Oct 2024 20:02:24 -0700 Subject: [PATCH 14/20] update description --- azure/durable_functions/models/DurableOrchestrationContext.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure/durable_functions/models/DurableOrchestrationContext.py b/azure/durable_functions/models/DurableOrchestrationContext.py index 2b59de12..82070560 100644 --- a/azure/durable_functions/models/DurableOrchestrationContext.py +++ b/azure/durable_functions/models/DurableOrchestrationContext.py @@ -231,8 +231,8 @@ def call_http(self, method: str, uri: str, content: Optional[str] = None, token_source: TokenSource The source of OAuth token to add to the request. is_raw_str: bool, optional - If True, the content will be treated as a raw string and will not be serialized to JSON. - If False (default), the content will be serialized to a JSON string before sending. + If True, send content as-is. + If False (default), serialize content to JSON. Returns ------- From 46009aaad490198a1971f3fc79f820b9eea5f1d9 Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Tue, 8 Oct 2024 11:19:07 -0700 Subject: [PATCH 15/20] update by comment --- .../models/DurableOrchestrationContext.py | 8 +++++++- tests/orchestrator/test_call_http.py | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/azure/durable_functions/models/DurableOrchestrationContext.py b/azure/durable_functions/models/DurableOrchestrationContext.py index 82070560..c5ca98b5 100644 --- a/azure/durable_functions/models/DurableOrchestrationContext.py +++ b/azure/durable_functions/models/DurableOrchestrationContext.py @@ -231,7 +231,7 @@ def call_http(self, method: str, uri: str, content: Optional[str] = None, token_source: TokenSource The source of OAuth token to add to the request. is_raw_str: bool, optional - If True, send content as-is. + If True, send string content as-is. If False (default), serialize content to JSON. Returns @@ -240,6 +240,12 @@ def call_http(self, method: str, uri: str, content: Optional[str] = None, The durable HTTP request to schedule. """ json_content: Optional[str] = None + + # validate parameters + if (not isinstance(content, str)) and is_raw_str: + raise TypeError("Invalid use of 'is_raw_str' parameter: 'is_raw_str' is set to 'True' but 'content' is not an instance of type 'str'. " \ + "Either set 'is_raw_str' to 'False', or ensure your 'content' is of type 'str'.") + if content is not None: if isinstance(content, str) and is_raw_str: # don't serialize the str value - use it as the raw HTTP request payload diff --git a/tests/orchestrator/test_call_http.py b/tests/orchestrator/test_call_http.py index 8314f943..6b8450f8 100644 --- a/tests/orchestrator/test_call_http.py +++ b/tests/orchestrator/test_call_http.py @@ -194,6 +194,7 @@ def test_post_completed_state(): ("string data", "string data", True), ('{"key": "value"}', '{"key": "value"}', True), ('[]', '[]', True), + (None, None, True), ]) def test_call_http_content_handling(content, expected_content, is_raw_str): def orchestrator_function(context): @@ -208,3 +209,17 @@ def orchestrator_function(context): assert http_action['method'] == "POST" assert http_action['uri'] == TEST_URI assert http_action['content'] == expected_content + +# Test that call_http raises a TypeError when is_raw_str is True but content is not a string +def test_call_http_non_string_content_with_raw_str(): + def orchestrator_function(context): + yield context.call_http("POST", TEST_URI, {"key": "value"}, is_raw_str=True) + + context_builder = ContextBuilder('test_call_http_non_string_content_with_raw_str') + + with pytest.raises(TypeError) as e: + get_orchestration_state_result(context_builder, orchestrator_function) + + expected_error_message = "Invalid use of 'is_raw_str' parameter: 'is_raw_str' is set to 'True' but 'content' is not an instance of type 'str'. Either set 'is_raw_str' to 'False', or ensure your 'content' is of type 'str'." + assert e.type == TypeError + assert str(e.value) == expected_error_message \ No newline at end of file From e0fa5aa69b5d6d05d8c8ec0e45fa9eb5f7ab6629 Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Tue, 8 Oct 2024 11:21:50 -0700 Subject: [PATCH 16/20] re-arrange the error message as it's too long --- .../durable_functions/models/DurableOrchestrationContext.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/azure/durable_functions/models/DurableOrchestrationContext.py b/azure/durable_functions/models/DurableOrchestrationContext.py index c5ca98b5..b339ba28 100644 --- a/azure/durable_functions/models/DurableOrchestrationContext.py +++ b/azure/durable_functions/models/DurableOrchestrationContext.py @@ -243,8 +243,10 @@ def call_http(self, method: str, uri: str, content: Optional[str] = None, # validate parameters if (not isinstance(content, str)) and is_raw_str: - raise TypeError("Invalid use of 'is_raw_str' parameter: 'is_raw_str' is set to 'True' but 'content' is not an instance of type 'str'. " \ - "Either set 'is_raw_str' to 'False', or ensure your 'content' is of type 'str'.") + raise TypeError("Invalid use of 'is_raw_str' parameter: 'is_raw_str' is set to 'True' "\ + "but 'content' is not an instance of type 'str'. "\ + "Either set 'is_raw_str' to 'False', or ensure your 'content' "\ + "is of type 'str'.") if content is not None: if isinstance(content, str) and is_raw_str: From 795e0db0c2df06f054e5c3975eef60f9451476f5 Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Tue, 8 Oct 2024 11:28:06 -0700 Subject: [PATCH 17/20] re-arrange error msg --- .../models/DurableOrchestrationContext.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azure/durable_functions/models/DurableOrchestrationContext.py b/azure/durable_functions/models/DurableOrchestrationContext.py index b339ba28..ef97ce60 100644 --- a/azure/durable_functions/models/DurableOrchestrationContext.py +++ b/azure/durable_functions/models/DurableOrchestrationContext.py @@ -243,10 +243,10 @@ def call_http(self, method: str, uri: str, content: Optional[str] = None, # validate parameters if (not isinstance(content, str)) and is_raw_str: - raise TypeError("Invalid use of 'is_raw_str' parameter: 'is_raw_str' is set to 'True' "\ - "but 'content' is not an instance of type 'str'. "\ - "Either set 'is_raw_str' to 'False', or ensure your 'content' "\ - "is of type 'str'.") + raise TypeError("Invalid use of 'is_raw_str' parameter: 'is_raw_str' is "\ + "set to 'True' but 'content' is not an instance of type 'str'. "\ + "Either set 'is_raw_str' to 'False', or ensure your 'content' "\ + "is of type 'str'.") if content is not None: if isinstance(content, str) and is_raw_str: From d902774fe980acef7dcf52c6839cc88d78ecafd4 Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Tue, 8 Oct 2024 11:30:11 -0700 Subject: [PATCH 18/20] update error msg --- .../models/DurableOrchestrationContext.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/azure/durable_functions/models/DurableOrchestrationContext.py b/azure/durable_functions/models/DurableOrchestrationContext.py index ef97ce60..01ec9000 100644 --- a/azure/durable_functions/models/DurableOrchestrationContext.py +++ b/azure/durable_functions/models/DurableOrchestrationContext.py @@ -243,9 +243,10 @@ def call_http(self, method: str, uri: str, content: Optional[str] = None, # validate parameters if (not isinstance(content, str)) and is_raw_str: - raise TypeError("Invalid use of 'is_raw_str' parameter: 'is_raw_str' is "\ - "set to 'True' but 'content' is not an instance of type 'str'. "\ - "Either set 'is_raw_str' to 'False', or ensure your 'content' "\ + raise TypeError( + "Invalid use of 'is_raw_str' parameter: 'is_raw_str' is " + "set to 'True' but 'content' is not an instance of type 'str'. " + "Either set 'is_raw_str' to 'False', or ensure your 'content' " "is of type 'str'.") if content is not None: From ef9923e0d0a74294579eeedf679267ca213a4ae6 Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Tue, 8 Oct 2024 11:40:52 -0700 Subject: [PATCH 19/20] update test --- tests/orchestrator/test_call_http.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/tests/orchestrator/test_call_http.py b/tests/orchestrator/test_call_http.py index 6b8450f8..0c9c18ad 100644 --- a/tests/orchestrator/test_call_http.py +++ b/tests/orchestrator/test_call_http.py @@ -194,7 +194,6 @@ def test_post_completed_state(): ("string data", "string data", True), ('{"key": "value"}', '{"key": "value"}', True), ('[]', '[]', True), - (None, None, True), ]) def test_call_http_content_handling(content, expected_content, is_raw_str): def orchestrator_function(context): @@ -217,9 +216,20 @@ def orchestrator_function(context): context_builder = ContextBuilder('test_call_http_non_string_content_with_raw_str') - with pytest.raises(TypeError) as e: - get_orchestration_state_result(context_builder, orchestrator_function) + try: + result = get_orchestration_state_result(context_builder, orchestrator_function) + assert False + except Exception as e: + error_label = "\n\n$OutOfProcData$:" + error_str = str(e) - expected_error_message = "Invalid use of 'is_raw_str' parameter: 'is_raw_str' is set to 'True' but 'content' is not an instance of type 'str'. Either set 'is_raw_str' to 'False', or ensure your 'content' is of type 'str'." - assert e.type == TypeError - assert str(e.value) == expected_error_message \ No newline at end of file + expected_state = base_expected_state() + error_msg = "Invalid use of 'is_raw_str' parameter: 'is_raw_str' is " + "set to 'True' but 'content' is not an instance of type 'str'. " + "Either set 'is_raw_str' to 'False', or ensure your 'content' " + "is of type 'str'." + expected_state._error = error_msg + state_str = expected_state.to_json_string() + + expected_error_str = f"{error_msg}{error_label}{state_str}" + assert expected_error_str == error_str \ No newline at end of file From b851b5eb38a4b45cf58a772650bb2bed9c18f3ba Mon Sep 17 00:00:00 2001 From: "naiyuantian@microsoft.com" Date: Tue, 8 Oct 2024 11:42:20 -0700 Subject: [PATCH 20/20] updatetest --- tests/orchestrator/test_call_http.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/orchestrator/test_call_http.py b/tests/orchestrator/test_call_http.py index 0c9c18ad..b42b36cd 100644 --- a/tests/orchestrator/test_call_http.py +++ b/tests/orchestrator/test_call_http.py @@ -224,9 +224,9 @@ def orchestrator_function(context): error_str = str(e) expected_state = base_expected_state() - error_msg = "Invalid use of 'is_raw_str' parameter: 'is_raw_str' is " - "set to 'True' but 'content' is not an instance of type 'str'. " - "Either set 'is_raw_str' to 'False', or ensure your 'content' " + error_msg = "Invalid use of 'is_raw_str' parameter: 'is_raw_str' is "\ + "set to 'True' but 'content' is not an instance of type 'str'. "\ + "Either set 'is_raw_str' to 'False', or ensure your 'content' "\ "is of type 'str'." expected_state._error = error_msg state_str = expected_state.to_json_string()