Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(framework:skip) Drop Io from ClientApp{Input,Output} dataclasses #4042

Merged
merged 7 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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