From 708786b0ae9128648b8cabc91af27cd33e4bfb41 Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Mon, 2 Dec 2019 16:41:29 +0000 Subject: [PATCH 1/5] Added functionality to specify proto return type or json return type for Seldon Client functions --- python/seldon_core/seldon_client.py | 95 ++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 9 deletions(-) diff --git a/python/seldon_core/seldon_client.py b/python/seldon_core/seldon_client.py index 534816cffe..1695d9d13c 100644 --- a/python/seldon_core/seldon_client.py +++ b/python/seldon_core/seldon_client.py @@ -73,8 +73,8 @@ class SeldonClientPrediction(object): def __init__( self, - request: Optional[prediction_pb2.SeldonMessage], - response: Optional[prediction_pb2.SeldonMessage], + request: Optional[Union[prediction_pb2.SeldonMessage, Dict]], + response: Optional[Union[prediction_pb2.SeldonMessage, Dict]], success: bool = True, msg: str = "", ): @@ -100,7 +100,7 @@ class SeldonClientFeedback(object): def __init__( self, request: Optional[prediction_pb2.Feedback], - response: Optional[prediction_pb2.SeldonMessage], + response: Optional[Union[prediction_pb2.SeldonMessage, Dict]], success: bool = True, msg: str = "", ): @@ -166,7 +166,8 @@ def __init__( grpc_max_receive_message_length: int = 4 * 1024 * 1024, channel_credentials: SeldonChannelCredentials = None, call_credentials: SeldonCallCredentials = None, - debug=False, + debug: bool = False, + client_return_type: str = "proto", ): """ @@ -198,6 +199,8 @@ def __init__( Max grpc send message size in bytes grpc_max_receive_message_length Max grpc receive message size in bytes + client_return_type + the return type of all functions can be either dict or proto """ if debug: logger.setLevel(logging.DEBUG) @@ -218,6 +221,7 @@ def _validate_args( transport: str = None, method: str = None, data: np.ndarray = None, + client_return_type: str = "proto", **kwargs, ): """ @@ -261,6 +265,13 @@ def _validate_args( ) if not (data is None or isinstance(data, np.ndarray)): raise SeldonClientException("Valid values for data are None or numpy array") + if not ( + client_return_type == "proto" + or client_return_type == "dict" + ): + raise SeldonClientException( + "Valid values for client_return_type are proto or dict" + ) def predict( self, @@ -285,6 +296,7 @@ def predict( gateway_prefix: str = None, headers: Dict = None, http_path: str = None, + client_return_type: str = "proto", ) -> SeldonClientPrediction: """ @@ -332,6 +344,8 @@ def predict( Headers to add to request http_path: Custom http path for predict call to use + client_return_type + the return type of all functions can be either dict or proto Returns ------- @@ -359,6 +373,7 @@ def predict( gateway_prefix=gateway_prefix, headers=headers, http_path=http_path, + client_return_type=client_return_type, ) self._validate_args(**k) if k["gateway"] == "ambassador" or k["gateway"] == "istio": @@ -397,6 +412,7 @@ def feedback( shape: Tuple = (1, 1), namespace: str = None, gateway_prefix: str = None, + client_return_type: str = "proto", ) -> SeldonClientFeedback: """ @@ -438,6 +454,8 @@ def feedback( The shape of the data to send namespace k8s namespace of running deployment + client_return_type + the return type of all functions can be either dict or proto Returns ------- @@ -458,6 +476,7 @@ def feedback( shape=shape, namespace=namespace, gateway_prefix=gateway_prefix, + client_return_type=client_return_type, ) self._validate_args(**k) if k["gateway"] == "ambassador" or k["gateway"] == "istio": @@ -506,6 +525,7 @@ def explain( gateway_prefix: str = None, headers: Dict = None, http_path: str = None, + client_return_type: str = "dict", ) -> Dict: """ @@ -549,6 +569,8 @@ def explain( Headers to add to request http_path: Custom http path for predict call to use + client_return_type + the return type of all functions can be either dict or proto Returns ------- @@ -574,6 +596,7 @@ def explain( gateway_prefix=gateway_prefix, headers=headers, http_path=http_path, + client_return_type=client_return_type, ) self._validate_args(**k) if k["gateway"] == "ambassador" or k["gateway"] == "istio": @@ -1259,6 +1282,7 @@ def rest_predict_seldon_oauth( str_data: str = None, json_data: Union[str, List, Dict] = None, names: Iterable[str] = None, + client_return_type: str = "proto", **kwargs, ) -> SeldonClientPrediction: """ @@ -1288,6 +1312,8 @@ def rest_predict_seldon_oauth( JSON data to send names column names + client_return_type + the return type of all functions can be either dict or proto kwargs Returns @@ -1323,7 +1349,10 @@ def rest_predict_seldon_oauth( try: if len(response_raw.text) > 0: try: - response = json_to_seldon_message(response_raw.json()) + if client_return_type == "proto": + response = json_to_seldon_message(response_raw.json()) + elif client_return_type == "dict": + response = response_raw.json() except: response = None else: @@ -1348,6 +1377,7 @@ def grpc_predict_seldon_oauth( grpc_max_send_message_length: int = 4 * 1024 * 1024, grpc_max_receive_message_length: int = 4 * 1024 * 1024, names: Iterable[str] = None, + client_return_type: str = "proto", **kwargs, ) -> SeldonClientPrediction: """ @@ -1379,6 +1409,8 @@ def grpc_predict_seldon_oauth( Max grpc receive message size in bytes names Column names + client_return_type + the return type of all functions can be either dict or proto kwargs Returns @@ -1409,6 +1441,9 @@ def grpc_predict_seldon_oauth( metadata = [("oauth_token", token)] try: response = stub.Predict(request=request, metadata=metadata) + if client_return_type == "dict": + request = seldon_message_to_json(request) + response = seldon_message_to_json(response) return SeldonClientPrediction(request, response, True, "") except Exception as e: return SeldonClientPrediction(request, None, False, str(e)) @@ -1430,6 +1465,7 @@ def rest_predict_gateway( call_credentials: SeldonCallCredentials = None, channel_credentials: SeldonChannelCredentials = None, http_path: str = None, + client_return_type: str = "proto", **kwargs, ) -> SeldonClientPrediction: """ @@ -1467,6 +1503,8 @@ def rest_predict_gateway( Channel credentials - see SeldonChannelCredentials http_path Custom http path + client_return_type + the return type of all functions can be either dict or proto Returns ------- @@ -1564,7 +1602,10 @@ def rest_predict_gateway( if len(response_raw.text) > 0: try: logger.debug("Raw response: %s", response_raw.text) - response = json_to_seldon_message(response_raw.json()) + if client_return_type == "proto": + response = json_to_seldon_message(response_raw.json()) + elif client_return_type == "dict": + response = response_raw.json() except: response = None else: @@ -1590,6 +1631,7 @@ def explain_predict_gateway( call_credentials: SeldonCallCredentials = None, channel_credentials: SeldonChannelCredentials = None, http_path: str = None, + client_return_type: str = "dict", **kwargs, ) -> Dict: """ @@ -1627,6 +1669,8 @@ def explain_predict_gateway( Channel credentials - see SeldonChannelCredentials http_path Custom http path + client_return_type + the return type of all functions can be either dict or proto Returns ------- @@ -1715,7 +1759,10 @@ def explain_predict_gateway( url, json=payload, headers=req_headers, verify=verify, cert=cert ) if response_raw.status_code == 200: - return response_raw.json() + if client_return_type == "proto": + response = json_to_seldon_message(response_raw.json()) + elif client_return_type == "dict": + response = response_raw.json() else: return {"success": False, "response_code": response_raw.status_code} @@ -1736,6 +1783,7 @@ def grpc_predict_gateway( names: Iterable[str] = None, call_credentials: SeldonCallCredentials = None, channel_credentials: SeldonChannelCredentials = None, + client_return_type: str = "proto", **kwargs, ) -> SeldonClientPrediction: """ @@ -1773,6 +1821,8 @@ def grpc_predict_gateway( Call credentials - see SeldonCallCredentials channel_credentials Channel credentials - see SeldonChannelCredentials + client_return_type + the return type of all functions can be either dict or proto Returns @@ -1852,6 +1902,9 @@ def grpc_predict_gateway( for k in headers: metadata.append((k, headers[k])) response = stub.Predict(request=request, metadata=metadata) + if client_return_type == "dict": + request = seldon_message_to_json(request) + response = seldon_message_to_json(response) return SeldonClientPrediction(request, response, True, "") @@ -1863,6 +1916,7 @@ def rest_feedback_seldon_oauth( oauth_secret: str = "", namespace: str = None, seldon_rest_endpoint: str = "localhost:8002", + client_return_type: str = "proto", **kwargs, ) -> SeldonClientFeedback: """ @@ -1884,6 +1938,8 @@ def rest_feedback_seldon_oauth( k8s namespace of running deployment seldon_rest_endpoint Endpoint of REST endpoint + client_return_type + the return type of all functions can be either dict or proto kwargs Returns @@ -1910,7 +1966,10 @@ def rest_feedback_seldon_oauth( try: if len(response_raw.text) > 0: try: - response = json_to_seldon_message(response_raw.json()) + if client_return_type == "proto": + response = json_to_seldon_message(response_raw.json()) + elif client_return_type == "dict": + response = response_raw.json() except: response = None else: @@ -1931,6 +1990,7 @@ def grpc_feedback_seldon_oauth( seldon_grpc_endpoint: str = "localhost:8004", grpc_max_send_message_length: int = 4 * 1024 * 1024, grpc_max_receive_message_length: int = 4 * 1024 * 1024, + client_return_type: str = "proto", **kwargs, ) -> SeldonClientFeedback: """ @@ -1958,6 +2018,8 @@ def grpc_feedback_seldon_oauth( Max grpc send message size in bytes grpc_max_receive_message_length Max grpc receive message size in bytes + client_return_type + the return type of all functions can be either dict or proto kwargs Returns @@ -1979,6 +2041,9 @@ def grpc_feedback_seldon_oauth( metadata = [("oauth_token", token)] try: response = stub.SendFeedback(request=request, metadata=metadata) + if client_return_type == "dict": + request = seldon_message_to_json(request) + response = seldon_message_to_json(response) return SeldonClientFeedback(request, response, True, "") except Exception as e: return SeldonClientFeedback(request, None, False, str(e)) @@ -1993,6 +2058,7 @@ def rest_feedback_gateway( gateway_endpoint: str = "localhost:8003", headers: Dict = None, gateway_prefix: str = None, + client_return_type: str = "proto", **kwargs, ) -> SeldonClientFeedback: """ @@ -2016,6 +2082,8 @@ def rest_feedback_gateway( Headers to add to the request gateway_prefix The prefix to add to the request path for gateway + client_return_type + the return type of all functions can be either dict or proto kwargs Returns @@ -2066,7 +2134,10 @@ def rest_feedback_gateway( try: if len(response_raw.text) > 0: try: - response = json_to_seldon_message(response_raw.json()) + if client_return_type == "proto": + response = json_to_seldon_message(response_raw.json()) + elif client_return_type == "dict": + response = response_raw.json() except: response = None else: @@ -2086,6 +2157,7 @@ def grpc_feedback_gateway( headers: Dict = None, grpc_max_send_message_length: int = 4 * 1024 * 1024, grpc_max_receive_message_length: int = 4 * 1024 * 1024, + client_return_type: str = "proto", **kwargs, ) -> SeldonClientFeedback: """ @@ -2110,6 +2182,8 @@ def grpc_feedback_gateway( Max grpc send message size in bytes grpc_max_receive_message_length Max grpc receive message size in bytes + client_return_type + the return type of all functions can be either dict or proto kwargs Returns @@ -2136,6 +2210,9 @@ def grpc_feedback_gateway( metadata.append((k, headers[k])) try: response = stub.SendFeedback(request=request, metadata=metadata) + if client_return_type == "dict": + request = seldon_message_to_json(request) + response = seldon_message_to_json(response) return SeldonClientFeedback(request, response, True, "") except Exception as e: return SeldonClientFeedback(request, None, False, str(e)) From 1bdd85d7b57f460feb9ac32a96ed6fa2e0687aaf Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Mon, 2 Dec 2019 17:11:00 +0000 Subject: [PATCH 2/5] Ran linter on files --- python/seldon_core/seldon_client.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/python/seldon_core/seldon_client.py b/python/seldon_core/seldon_client.py index 1695d9d13c..71cb00487c 100644 --- a/python/seldon_core/seldon_client.py +++ b/python/seldon_core/seldon_client.py @@ -265,10 +265,7 @@ def _validate_args( ) if not (data is None or isinstance(data, np.ndarray)): raise SeldonClientException("Valid values for data are None or numpy array") - if not ( - client_return_type == "proto" - or client_return_type == "dict" - ): + if not (client_return_type == "proto" or client_return_type == "dict"): raise SeldonClientException( "Valid values for client_return_type are proto or dict" ) From 1f1358a30139f3c4337c097106ca9893a6997c5b Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Mon, 2 Dec 2019 17:40:35 +0000 Subject: [PATCH 3/5] Added functionality for explain function returns an actual Seldon Message for consistency --- python/seldon_core/seldon_client.py | 22 ++++++++++++++++------ python/tests/test_seldon_client.py | 3 ++- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/python/seldon_core/seldon_client.py b/python/seldon_core/seldon_client.py index 71cb00487c..5eaddbd495 100644 --- a/python/seldon_core/seldon_client.py +++ b/python/seldon_core/seldon_client.py @@ -522,7 +522,7 @@ def explain( gateway_prefix: str = None, headers: Dict = None, http_path: str = None, - client_return_type: str = "dict", + client_return_type: str = "proto", ) -> Dict: """ @@ -1628,9 +1628,9 @@ def explain_predict_gateway( call_credentials: SeldonCallCredentials = None, channel_credentials: SeldonChannelCredentials = None, http_path: str = None, - client_return_type: str = "dict", + client_return_type: str = "proto", **kwargs, -) -> Dict: +) -> SeldonClientPrediction: """ REST explain request to Gateway Ingress @@ -1757,11 +1757,21 @@ def explain_predict_gateway( ) if response_raw.status_code == 200: if client_return_type == "proto": - response = json_to_seldon_message(response_raw.json()) + ret_request = json_to_seldon_message(payload) + ret_response = json_to_seldon_message(response_raw.json()) elif client_return_type == "dict": - response = response_raw.json() + ret_request = payload + ret_response = response_raw.json() + else: + SeldonClientException("Invalid client_return_type") + return SeldonClientPrediction(ret_request, ret_response, True, "") else: - return {"success": False, "response_code": response_raw.status_code} + return SeldonClientPrediction( + payload, + response_raw, + False, + f"Unsuccessful request with status code: {response_raw.status_code}", + ) def grpc_predict_gateway( diff --git a/python/tests/test_seldon_client.py b/python/tests/test_seldon_client.py index f9b81621bc..cbc66ef580 100644 --- a/python/tests/test_seldon_client.py +++ b/python/tests/test_seldon_client.py @@ -110,7 +110,8 @@ def test_predict_rest_json_data_seldon(mock_post, mock_token): @mock.patch("requests.post", side_effect=mocked_requests_post_success_json_data) def test_explain_rest_json_data_ambassador(mock_post): sc = SeldonClient(deployment_name="mymodel", gateway="ambassador") - json_response = sc.explain(json_data=JSON_TEST_DATA) + response = sc.explain(json_data=JSON_TEST_DATA) + json_response = seldon_message_to_json(response.response) # Currently this doesn't need to convert to JSON due to #1083 # i.e. json_response = seldon_message_to_json(response.response) assert "jsonData" in mock_post.call_args[1]["json"] From 4f9f11232edf28427bc1339ad4ec6abcfbcf693c Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Mon, 2 Dec 2019 18:07:26 +0000 Subject: [PATCH 4/5] added --- python/seldon_core/seldon_client.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/python/seldon_core/seldon_client.py b/python/seldon_core/seldon_client.py index 5eaddbd495..a3239c18f8 100644 --- a/python/seldon_core/seldon_client.py +++ b/python/seldon_core/seldon_client.py @@ -1350,6 +1350,8 @@ def rest_predict_seldon_oauth( response = json_to_seldon_message(response_raw.json()) elif client_return_type == "dict": response = response_raw.json() + else: + SeldonClientException("Invalid client_return_type") except: response = None else: @@ -1441,6 +1443,8 @@ def grpc_predict_seldon_oauth( if client_return_type == "dict": request = seldon_message_to_json(request) response = seldon_message_to_json(response) + elif client_return_type != "proto": + SeldonClientException("Invalid client_return_type") return SeldonClientPrediction(request, response, True, "") except Exception as e: return SeldonClientPrediction(request, None, False, str(e)) @@ -1603,6 +1607,8 @@ def rest_predict_gateway( response = json_to_seldon_message(response_raw.json()) elif client_return_type == "dict": response = response_raw.json() + else: + SeldonClientException("Invalid client_return_type") except: response = None else: @@ -1912,6 +1918,8 @@ def grpc_predict_gateway( if client_return_type == "dict": request = seldon_message_to_json(request) response = seldon_message_to_json(response) + elif client_return_type != "proto": + SeldonClientException("Invalid client_return_type") return SeldonClientPrediction(request, response, True, "") @@ -1977,6 +1985,8 @@ def rest_feedback_seldon_oauth( response = json_to_seldon_message(response_raw.json()) elif client_return_type == "dict": response = response_raw.json() + else: + SeldonClientException("Invalid client_return_type") except: response = None else: @@ -2051,6 +2061,8 @@ def grpc_feedback_seldon_oauth( if client_return_type == "dict": request = seldon_message_to_json(request) response = seldon_message_to_json(response) + elif client_return_type != "proto": + SeldonClientException("Invalid client_return_type") return SeldonClientFeedback(request, response, True, "") except Exception as e: return SeldonClientFeedback(request, None, False, str(e)) @@ -2145,6 +2157,8 @@ def rest_feedback_gateway( response = json_to_seldon_message(response_raw.json()) elif client_return_type == "dict": response = response_raw.json() + else: + SeldonClientException("Invalid client_return_type") except: response = None else: @@ -2220,6 +2234,8 @@ def grpc_feedback_gateway( if client_return_type == "dict": request = seldon_message_to_json(request) response = seldon_message_to_json(response) + elif client_return_type != "proto": + SeldonClientException("Invalid client_return_type") return SeldonClientFeedback(request, response, True, "") except Exception as e: return SeldonClientFeedback(request, None, False, str(e)) From c6543cdbe27e5c1e405116d71430285d82621910 Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Mon, 2 Dec 2019 18:30:32 +0000 Subject: [PATCH 5/5] Added documentation for the new feature on the Seldon Client --- doc/source/python/seldon_client.md | 13 +++++++ python/seldon_core/seldon_client.py | 6 +-- python/tests/test_seldon_client.py | 57 ++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/doc/source/python/seldon_client.md b/doc/source/python/seldon_client.md index 6d0a575d9f..5ea67d9a7b 100644 --- a/doc/source/python/seldon_client.md +++ b/doc/source/python/seldon_client.md @@ -28,6 +28,19 @@ To make a gRPC call with random payload: r = sc.predict(transport="grpc") ``` +The default return type is the protobuf of type "SeldonMessage", but you can also choose to return a JSON dictionary which could make it easier for interacting with the internal data. You can do this by passing the kwarg `client_return_type` with the value `dict` (default value is `proto`) when either initialising your Seldon Client or when sending a predict request. For example: + +``` +sc = SeldonClient(..., client_return_type="dict") +``` + +Or alternatively you can pass it when sending the request to override your default parameter: + +``` +sc = SeldonClient(..., client_return_type="proto") + +sc.predict(..., client_return_type="dict") # Here we override it +``` ## Advanced Examples diff --git a/python/seldon_core/seldon_client.py b/python/seldon_core/seldon_client.py index a3239c18f8..e34e83cf15 100644 --- a/python/seldon_core/seldon_client.py +++ b/python/seldon_core/seldon_client.py @@ -293,7 +293,7 @@ def predict( gateway_prefix: str = None, headers: Dict = None, http_path: str = None, - client_return_type: str = "proto", + client_return_type: str = None, ) -> SeldonClientPrediction: """ @@ -409,7 +409,7 @@ def feedback( shape: Tuple = (1, 1), namespace: str = None, gateway_prefix: str = None, - client_return_type: str = "proto", + client_return_type: str = None, ) -> SeldonClientFeedback: """ @@ -522,7 +522,7 @@ def explain( gateway_prefix: str = None, headers: Dict = None, http_path: str = None, - client_return_type: str = "proto", + client_return_type: str = None, ) -> Dict: """ diff --git a/python/tests/test_seldon_client.py b/python/tests/test_seldon_client.py index cbc66ef580..4b273a87a3 100644 --- a/python/tests/test_seldon_client.py +++ b/python/tests/test_seldon_client.py @@ -94,6 +94,20 @@ def test_predict_rest_json_data_ambassador(mock_post): assert mock_post.call_count == 1 +@mock.patch("requests.post", side_effect=mocked_requests_post_success_json_data) +def test_predict_rest_json_data_ambassador_dict_response(mock_post): + sc = SeldonClient( + deployment_name="mymodel", gateway="ambassador", client_return_type="dict" + ) + response = sc.predict(json_data=JSON_TEST_DATA) + json_response = response.response + assert "jsonData" in mock_post.call_args[1]["json"] + assert mock_post.call_args[1]["json"]["jsonData"] == JSON_TEST_DATA + assert response.success is True + assert json_response["jsonData"] == JSON_TEST_DATA + assert mock_post.call_count == 1 + + @mock.patch("seldon_core.seldon_client.get_token", side_effect=mock_get_token) @mock.patch("requests.post", side_effect=mocked_requests_post_success_json_data) def test_predict_rest_json_data_seldon(mock_post, mock_token): @@ -107,6 +121,21 @@ def test_predict_rest_json_data_seldon(mock_post, mock_token): assert mock_post.call_count == 1 +@mock.patch("seldon_core.seldon_client.get_token", side_effect=mock_get_token) +@mock.patch("requests.post", side_effect=mocked_requests_post_success_json_data) +def test_predict_rest_json_data_seldon_return_type(mock_post, mock_token): + sc = SeldonClient( + deployment_name="mymodel", gateway="seldon", client_return_type="dict" + ) + response = sc.predict(json_data=JSON_TEST_DATA) + json_response = response.response + assert "jsonData" in mock_post.call_args[1]["json"] + assert mock_post.call_args[1]["json"]["jsonData"] == JSON_TEST_DATA + assert response.success is True + assert json_response["jsonData"] == JSON_TEST_DATA + assert mock_post.call_count == 1 + + @mock.patch("requests.post", side_effect=mocked_requests_post_success_json_data) def test_explain_rest_json_data_ambassador(mock_post): sc = SeldonClient(deployment_name="mymodel", gateway="ambassador") @@ -120,6 +149,21 @@ def test_explain_rest_json_data_ambassador(mock_post): assert mock_post.call_count == 1 +@mock.patch("requests.post", side_effect=mocked_requests_post_success_json_data) +def test_explain_rest_json_data_ambassador_dict_response(mock_post): + sc = SeldonClient( + deployment_name="mymodel", gateway="ambassador", client_return_type="dict" + ) + response = sc.explain(json_data=JSON_TEST_DATA) + json_response = response.response + # Currently this doesn't need to convert to JSON due to #1083 + # i.e. json_response = seldon_message_to_json(response.response) + assert "jsonData" in mock_post.call_args[1]["json"] + assert mock_post.call_args[1]["json"]["jsonData"] == JSON_TEST_DATA + assert json_response["jsonData"] == JSON_TEST_DATA + assert mock_post.call_count == 1 + + @mock.patch("requests.post", side_effect=mocked_requests_post_success) def test_predict_rest_with_ambassador_prefix(mock_post): sc = SeldonClient(deployment_name="mymodel") @@ -132,6 +176,18 @@ def test_predict_rest_with_ambassador_prefix(mock_post): assert mock_post.call_count == 1 +@mock.patch("requests.post", side_effect=mocked_requests_post_success) +def test_predict_rest_with_ambassador_prefix_dict_response(mock_post): + sc = SeldonClient(deployment_name="mymodel", client_return_type="dict") + response = sc.predict( + gateway="ambassador", transport="rest", gateway_prefix="/mycompany/ml" + ) + assert mock_post.call_args[0][0].index("/mycompany/ml") > 0 + assert response.success == True + assert response.response["data"]["tensor"]["shape"] == [1, 1] + assert mock_post.call_count == 1 + + @mock.patch("requests.post", side_effect=mocked_requests_post_success) def test_predict_microservice_rest(mock_post): sc = SeldonClient(deployment_name="mymodel") @@ -164,7 +220,6 @@ def test_feedback_microservice_rest(mock_post): prediction_response=prediction_pb2.SeldonMessage(), reward=1.0, ) - print(response) assert response.success == True assert response.response.data.tensor.shape == [1, 1] assert mock_post.call_count == 1