Skip to content

Commit

Permalink
refactor(framework:skip) Drop Io from ClientApp{Input,Output} dat…
Browse files Browse the repository at this point in the history
…aclasses (#4042)
  • Loading branch information
jafermarq authored Aug 19, 2024
1 parent 35d8794 commit f4f045f
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 39 deletions.
4 changes: 2 additions & 2 deletions src/py/flwr/client/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
from flwr.server.superlink.fleet.grpc_bidi.grpc_server import generic_create_grpc_server
from flwr.server.superlink.state.utils import generate_rand_int_from_bytes

from .clientapp.clientappio_servicer import ClientAppIoInputs, ClientAppIoServicer
from .clientapp.clientappio_servicer import ClientAppInputs, ClientAppIoServicer
from .grpc_adapter_client.connection import grpc_adapter
from .grpc_client.connection import grpc_connection
from .grpc_rere_client.connection import grpc_request_response
Expand Down Expand Up @@ -480,7 +480,7 @@ def _on_backoff(retry_state: RetryState) -> None:

# Share Message and Context with servicer
clientappio_servicer.set_inputs(
clientapp_input=ClientAppIoInputs(
clientapp_input=ClientAppInputs(
message=message,
context=context,
run=run,
Expand Down
4 changes: 2 additions & 2 deletions src/py/flwr/client/clientapp/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ def get_token(stub: grpc.Channel) -> Optional[int]:

def pull_message(stub: grpc.Channel, token: int) -> Tuple[Message, Context, Run]:
"""Pull message from SuperNode to ClientApp."""
log(INFO, "Pulling ClientAppIoInputs for token %s", token)
log(INFO, "Pulling ClientAppInputs for token %s", token)
try:
res: PullClientAppInputsResponse = stub.PullClientAppInputs(
PullClientAppInputsRequest(token=token)
Expand All @@ -207,7 +207,7 @@ def push_message(
stub: grpc.Channel, token: int, message: Message, context: Context
) -> PushClientAppOutputsResponse:
"""Push message to SuperNode from ClientApp."""
log(INFO, "Pushing ClientAppIoOutputs for token %s", token)
log(INFO, "Pushing ClientAppOutputs for token %s", token)
proto_message = message_to_proto(message)
proto_context = context_to_proto(context)

Expand Down
38 changes: 19 additions & 19 deletions src/py/flwr/client/clientapp/clientappio_servicer.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@


@dataclass
class ClientAppIoInputs:
class ClientAppInputs:
"""Specify the inputs to the ClientApp."""

message: Message
Expand All @@ -56,7 +56,7 @@ class ClientAppIoInputs:


@dataclass
class ClientAppIoOutputs:
class ClientAppOutputs:
"""Specify the outputs from the ClientApp."""

message: Message
Expand All @@ -68,8 +68,8 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
"""ClientAppIo API servicer."""

def __init__(self) -> None:
self.clientapp_input: Optional[ClientAppIoInputs] = None
self.clientapp_output: Optional[ClientAppIoOutputs] = None
self.clientapp_input: Optional[ClientAppInputs] = None
self.clientapp_output: Optional[ClientAppOutputs] = None
self.token_returned: bool = False
self.inputs_returned: bool = False

Expand All @@ -79,13 +79,13 @@ def GetToken(
"""Get token."""
log(DEBUG, "ClientAppIo.GetToken")

# Fail if no ClientAppIoInputs are available
# Fail if no ClientAppInputs are available
if self.clientapp_input is None:
context.abort(
grpc.StatusCode.FAILED_PRECONDITION,
"No inputs available.",
)
clientapp_input = cast(ClientAppIoInputs, self.clientapp_input)
clientapp_input = cast(ClientAppInputs, self.clientapp_input)

# Fail if token was already returned in a previous call
if self.token_returned:
Expand All @@ -95,7 +95,7 @@ def GetToken(
)

# If
# - ClientAppIoInputs is set, and
# - ClientAppInputs is set, and
# - token hasn't been returned before,
# return token
self.token_returned = True
Expand All @@ -107,13 +107,13 @@ def PullClientAppInputs(
"""Pull Message, Context, and Run."""
log(DEBUG, "ClientAppIo.PullClientAppInputs")

# Fail if no ClientAppIoInputs are available
# Fail if no ClientAppInputs are available
if self.clientapp_input is None:
context.abort(
grpc.StatusCode.FAILED_PRECONDITION,
"No inputs available.",
)
clientapp_input = cast(ClientAppIoInputs, self.clientapp_input)
clientapp_input = cast(ClientAppInputs, self.clientapp_input)

# Fail if token wasn't returned in a previous call
if not self.token_returned:
Expand Down Expand Up @@ -144,13 +144,13 @@ def PushClientAppOutputs(
"""Push Message and Context."""
log(DEBUG, "ClientAppIo.PushClientAppOutputs")

# Fail if no ClientAppIoInputs are available
# Fail if no ClientAppInputs are available
if not self.clientapp_input:
context.abort(
grpc.StatusCode.FAILED_PRECONDITION,
"No inputs available.",
)
clientapp_input = cast(ClientAppIoInputs, self.clientapp_input)
clientapp_input = cast(ClientAppInputs, self.clientapp_input)

# Fail if token wasn't returned in a previous call
if not self.token_returned:
Expand Down Expand Up @@ -178,7 +178,7 @@ def PushClientAppOutputs(
# Preconditions met
try:
# Update Message and Context
self.clientapp_output = ClientAppIoOutputs(
self.clientapp_output = ClientAppOutputs(
message=message_from_proto(request.message),
context=context_from_proto(request.context),
)
Expand All @@ -196,13 +196,13 @@ def PushClientAppOutputs(
return PushClientAppOutputsResponse(status=proto_status)

def set_inputs(
self, clientapp_input: ClientAppIoInputs, token_returned: bool
self, clientapp_input: ClientAppInputs, token_returned: bool
) -> None:
"""Set ClientApp inputs.
Parameters
----------
clientapp_input : ClientAppIoInputs
clientapp_input : ClientAppInputs
The inputs to the ClientApp.
token_returned : bool
A boolean indicating if the token has been returned.
Expand All @@ -215,24 +215,24 @@ def set_inputs(
or self.token_returned
):
raise ValueError(
"ClientAppIoInputs and ClientAppIoOutputs must not be set before "
"ClientAppInputs and ClientAppOutputs must not be set before "
"calling `set_inputs`."
)
log(DEBUG, "ClientAppIoInputs set (token: %s)", clientapp_input.token)
log(DEBUG, "ClientAppInputs set (token: %s)", clientapp_input.token)
self.clientapp_input = clientapp_input
self.token_returned = token_returned

def has_outputs(self) -> bool:
"""Check if ClientAppOutputs are available."""
return self.clientapp_output is not None

def get_outputs(self) -> ClientAppIoOutputs:
def get_outputs(self) -> ClientAppOutputs:
"""Get ClientApp outputs."""
if self.clientapp_output is None:
raise ValueError("ClientAppIoOutputs not set before calling `get_outputs`.")
raise ValueError("ClientAppOutputs not set before calling `get_outputs`.")

# Set outputs to a local variable and clear state
output: ClientAppIoOutputs = self.clientapp_output
output: ClientAppOutputs = self.clientapp_output
self.clientapp_input = None
self.clientapp_output = None
self.token_returned = False
Expand Down
28 changes: 12 additions & 16 deletions src/py/flwr/client/clientapp/clientappio_servicer_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,7 @@
from flwr.proto.run_pb2 import Run as ProtoRun
from flwr.server.superlink.state.utils import generate_rand_int_from_bytes

from .clientappio_servicer import (
ClientAppIoInputs,
ClientAppIoOutputs,
ClientAppIoServicer,
)
from .clientappio_servicer import ClientAppInputs, ClientAppIoServicer, ClientAppOutputs


class TestClientAppIoServicer(unittest.TestCase):
Expand Down Expand Up @@ -81,32 +77,32 @@ def test_set_inputs(self) -> None:
fab_hash="dolor",
override_config=self.maker.user_config(),
)
client_input = ClientAppIoInputs(message, context, run, 1)
client_output = ClientAppIoOutputs(message, context)
client_input = ClientAppInputs(message, context, run, 1)
client_output = ClientAppOutputs(message, context)

# Execute and assert
# - when ClientAppIoInputs is not None, ClientAppIoOutputs is None
# - when ClientAppInputs is not None, ClientAppOutputs is None
with self.assertRaises(ValueError):
self.servicer.clientapp_input = client_input
self.servicer.clientapp_output = None
self.servicer.set_inputs(client_input, token_returned=True)

# Execute and assert
# - when ClientAppIoInputs is None, ClientAppIoOutputs is not None
# - when ClientAppInputs is None, ClientAppOutputs is not None
with self.assertRaises(ValueError):
self.servicer.clientapp_input = None
self.servicer.clientapp_output = client_output
self.servicer.set_inputs(client_input, token_returned=True)

# Execute and assert
# - when ClientAppIoInputs and ClientAppIoOutputs is not None
# - when ClientAppInputs and ClientAppOutputs is not None
with self.assertRaises(ValueError):
self.servicer.clientapp_input = client_input
self.servicer.clientapp_output = client_output
self.servicer.set_inputs(client_input, token_returned=True)

# Execute and assert
# - when ClientAppIoInputs is set at .clientapp_input
# - when ClientAppInputs is set at .clientapp_input
self.servicer.clientapp_input = None
self.servicer.clientapp_output = None
self.servicer.set_inputs(client_input, token_returned=True)
Expand All @@ -125,18 +121,18 @@ def test_get_outputs(self) -> None:
state=self.maker.recordset(2, 2, 1),
run_config={"runconfig1": 6.1},
)
client_output = ClientAppIoOutputs(message, context)
client_output = ClientAppOutputs(message, context)

# Execute and assert - when `ClientAppIoOutputs` is None
# Execute and assert - when `ClientAppOutputs` is None
self.servicer.clientapp_output = None
with self.assertRaises(ValueError):
# `ClientAppIoOutputs` should not be None
# `ClientAppOutputs` should not be None
_ = self.servicer.get_outputs()

# Execute and assert - when `ClientAppIoOutputs` is not None
# Execute and assert - when `ClientAppOutputs` is not None
self.servicer.clientapp_output = client_output
output = self.servicer.get_outputs()
assert isinstance(output, ClientAppIoOutputs)
assert isinstance(output, ClientAppOutputs)
assert output == client_output
assert self.servicer.clientapp_input is None
assert self.servicer.clientapp_output is None
Expand Down

0 comments on commit f4f045f

Please sign in to comment.