Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def test_call_actions_parallel_with_extras(self):
"""
Test that call_actions_parallel works to call multiple actions run parallel on a single service using extra
kwargs to more finely control behavior.
"""
action_responses = self.client.call_actions_parallel(
'service_2',
[
ActionRequest(action='action_3'),
ActionRequest(action='action_with_errors'),
ActionRequest(action='action_4'),
],
timeout=2,
raise_action_errors=False,
)
self.assertIsNotNone(action_responses)
action_responses_list = list(action_responses)
self.assertEqual(3, len(action_responses_list))
self.assertEqual({'cat': 'dog'}, action_responses_list[0].body)
self.assertEqual({}, action_responses_list[1].body)
self.assertEqual(
[Error(code=ERROR_CODE_INVALID, message='Invalid input', field='foo', is_caller_error=True)],
action_responses_list[1].errors,
error = MessageSendError('Hello!')
def side_effect(*args, **kwargs):
side_effect_context['call'] += 1
if side_effect_context['call'] == 2:
raise error
return original_send(*args, **kwargs)
with mock.patch.object(self.client, 'send_request') as mock_send_request:
mock_send_request.side_effect = side_effect
action_responses = self.client.call_actions_parallel(
'error_service',
[
ActionRequest(action='okay_action'),
ActionRequest(action='job_error'),
ActionRequest(action='okay_action'),
],
timeout=2,
catch_transport_errors=True,
)
self.assertIsNotNone(action_responses)
action_responses_list = list(action_responses)
self.assertEqual(3, len(action_responses_list))
self.assertEqual({'no_error': True}, action_responses_list[0].body)
self.assertIs(error, action_responses_list[1])
self.assertEqual({'no_error': True}, action_responses_list[2].body)
def test_call_actions_parallel_suppress_response_is_prohibited(self):
"""
Test that call_actions_parallel works to call multiple actions run parallel on a single service.
"""
with pytest.raises(TypeError):
# noinspection PyArgumentList
self.client.call_actions_parallel( # type: ignore
'service_1',
[ActionRequest(action='action_1'), ActionRequest(action='action_2'), ActionRequest(action='action_1')],
suppress_response=True,
)
def test_call_actions_parallel_action_errors_raised(self):
"""
Test that call_actions_parallel raises action errors when they occur
"""
with self.assertRaises(self.client.CallActionError) as error_context:
self.client.call_actions_parallel(
'service_2',
[
ActionRequest(action='action_3'),
ActionRequest(action='action_with_errors'),
],
)
self.assertEqual(
[Error(code=ERROR_CODE_INVALID, message='Invalid input', field='foo', is_caller_error=True)],
error_context.exception.actions[0].errors,
)
def _convert_action_requests(actions):
# type: (Union[Iterable[Mapping[six.text_type, Any]], Iterable[ActionRequest]]) -> List[ActionRequest]
value = [] # type: List[ActionRequest]
for a in actions:
value.append(a if isinstance(a, ActionRequest) else ActionRequest(**a))
return value
def _convert_request_switch_set(value):
# type: (Union[RequestSwitchSet, Iterable[Union[SupportsInt, SupportsIntValue]]]) -> RequestSwitchSet
if isinstance(value, RequestSwitchSet):
return value
return RequestSwitchSet(value)
@attr.s
class EnrichedJobRequest(JobRequest):
client = attr.ib(default=None) # type: Client
run_coroutine = attr.ib(default=None) # type: RunCoroutineType
@attr.s
class EnrichedActionRequest(ActionRequest):
"""
The action request object that the Server passes to each Action class that it calls. It contains all the information
from ActionRequest, plus some extra information from the JobRequest, a client that can be used to call other
services, and a helper for running asyncio coroutines.
Also contains a helper for easily calling other local service actions from within an action.
Services and intermediate libraries can subclass this class and change the :class:`Server` attribute
`request_class` to their subclass in order to use more-advanced request classes. In order for any new attributes
such a subclass provides to be copied by `call_local_action`, they must be `attr.ib` attributes with a default
value.
:param switches: The set of all switches included in the request context.
:param context: The job request context header dictionary.
:param control: The job request control header dictionary.
:param client: A :class:`Client` instance created by the server based on its `client_routing` setting and the
{
'client': self.get_client(expansion_node.service),
'requests': {},
},
)
exp_client = exp_service['client']
value = obj_to_expand[expansion_node.source_field]
# Build the expansion JobRequest
exp_request = JobRequest(
control={
'continue_on_error': False,
'expansions': expansion_node.to_dict(),
},
context=context,
actions=[ActionRequest(
action=expansion_node.action,
body={
expansion_node.request_field: value,
}
)]
)
# Call the action and map the request_id to the
# object we're expanding and the corresponding
# expansion node.
request_id = exp_client.send_request(exp_request)
exp_service['requests'][request_id] = {
'object': obj_to_expand,
'expansion': expansion_node,
}
yield request_id, response
finally:
self.metrics.publish_all()
_FR = TypeVar(
'_FR',
ActionResponse,
JobResponse,
List[ActionResponse],
List[JobResponse],
Generator[ActionResponse, None, None],
Generator[JobResponse, None, None],
)
ActionRequestArgument = Union[
ActionRequest,
Dict[six.text_type, Any],
]
ActionRequestArgumentList = Union[
List[ActionRequest],
List[Dict[six.text_type, Any]],
]
ActionRequestArgumentIterable = Union[
Iterable[ActionRequest],
Iterable[Dict[six.text_type, Any]],
]
JobRequestArgument = Dict[six.text_type, Any]
class FutureSOAResponse(Generic[_FR]):
"""
A future representing a retrievable response after sending a request.