flwr-nightly 1.11.0.dev20240811__py3-none-any.whl → 1.11.0.dev20240821__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of flwr-nightly might be problematic. Click here for more details.

Files changed (62) hide show
  1. flwr/cli/config_utils.py +2 -2
  2. flwr/cli/install.py +3 -1
  3. flwr/cli/run/run.py +15 -11
  4. flwr/client/app.py +134 -15
  5. flwr/client/clientapp/__init__.py +22 -0
  6. flwr/client/clientapp/app.py +233 -0
  7. flwr/client/clientapp/clientappio_servicer.py +244 -0
  8. flwr/client/clientapp/utils.py +108 -0
  9. flwr/client/grpc_adapter_client/connection.py +3 -1
  10. flwr/client/grpc_client/connection.py +3 -2
  11. flwr/client/grpc_rere_client/connection.py +15 -2
  12. flwr/client/node_state.py +17 -4
  13. flwr/client/rest_client/connection.py +21 -3
  14. flwr/client/supernode/app.py +37 -97
  15. flwr/common/__init__.py +4 -0
  16. flwr/common/config.py +31 -10
  17. flwr/common/record/configsrecord.py +49 -15
  18. flwr/common/record/metricsrecord.py +54 -14
  19. flwr/common/record/parametersrecord.py +84 -17
  20. flwr/common/record/recordset.py +80 -8
  21. flwr/common/record/typeddict.py +20 -58
  22. flwr/common/recordset_compat.py +6 -6
  23. flwr/common/serde.py +178 -1
  24. flwr/common/typing.py +17 -0
  25. flwr/proto/clientappio_pb2.py +45 -0
  26. flwr/proto/clientappio_pb2.pyi +132 -0
  27. flwr/proto/clientappio_pb2_grpc.py +135 -0
  28. flwr/proto/clientappio_pb2_grpc.pyi +53 -0
  29. flwr/proto/exec_pb2.py +16 -15
  30. flwr/proto/exec_pb2.pyi +7 -4
  31. flwr/proto/message_pb2.py +41 -0
  32. flwr/proto/message_pb2.pyi +125 -0
  33. flwr/proto/message_pb2_grpc.py +4 -0
  34. flwr/proto/message_pb2_grpc.pyi +4 -0
  35. flwr/server/app.py +15 -0
  36. flwr/server/driver/grpc_driver.py +1 -0
  37. flwr/server/run_serverapp.py +18 -2
  38. flwr/server/server.py +3 -1
  39. flwr/server/superlink/driver/driver_grpc.py +3 -0
  40. flwr/server/superlink/driver/driver_servicer.py +32 -4
  41. flwr/server/superlink/ffs/__init__.py +24 -0
  42. flwr/server/superlink/ffs/disk_ffs.py +107 -0
  43. flwr/server/superlink/ffs/ffs.py +79 -0
  44. flwr/server/superlink/ffs/ffs_factory.py +47 -0
  45. flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +12 -4
  46. flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +8 -2
  47. flwr/server/superlink/fleet/message_handler/message_handler.py +16 -1
  48. flwr/server/superlink/fleet/vce/backend/raybackend.py +5 -2
  49. flwr/server/superlink/fleet/vce/vce_api.py +2 -2
  50. flwr/server/superlink/state/in_memory_state.py +7 -5
  51. flwr/server/superlink/state/sqlite_state.py +17 -7
  52. flwr/server/superlink/state/state.py +4 -3
  53. flwr/server/workflow/default_workflows.py +3 -1
  54. flwr/simulation/run_simulation.py +5 -67
  55. flwr/superexec/app.py +3 -3
  56. flwr/superexec/deployment.py +8 -9
  57. flwr/superexec/exec_servicer.py +1 -1
  58. {flwr_nightly-1.11.0.dev20240811.dist-info → flwr_nightly-1.11.0.dev20240821.dist-info}/METADATA +2 -2
  59. {flwr_nightly-1.11.0.dev20240811.dist-info → flwr_nightly-1.11.0.dev20240821.dist-info}/RECORD +62 -46
  60. {flwr_nightly-1.11.0.dev20240811.dist-info → flwr_nightly-1.11.0.dev20240821.dist-info}/entry_points.txt +1 -0
  61. {flwr_nightly-1.11.0.dev20240811.dist-info → flwr_nightly-1.11.0.dev20240821.dist-info}/LICENSE +0 -0
  62. {flwr_nightly-1.11.0.dev20240811.dist-info → flwr_nightly-1.11.0.dev20240821.dist-info}/WHEEL +0 -0
@@ -0,0 +1,132 @@
1
+ """
2
+ @generated by mypy-protobuf. Do not edit manually!
3
+ isort:skip_file
4
+ """
5
+ import builtins
6
+ import flwr.proto.fab_pb2
7
+ import flwr.proto.message_pb2
8
+ import flwr.proto.run_pb2
9
+ import google.protobuf.descriptor
10
+ import google.protobuf.internal.enum_type_wrapper
11
+ import google.protobuf.message
12
+ import typing
13
+ import typing_extensions
14
+
15
+ DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
16
+
17
+ class _ClientAppOutputCode:
18
+ ValueType = typing.NewType('ValueType', builtins.int)
19
+ V: typing_extensions.TypeAlias = ValueType
20
+ class _ClientAppOutputCodeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_ClientAppOutputCode.ValueType], builtins.type):
21
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
22
+ SUCCESS: _ClientAppOutputCode.ValueType # 0
23
+ DEADLINE_EXCEEDED: _ClientAppOutputCode.ValueType # 1
24
+ UNKNOWN_ERROR: _ClientAppOutputCode.ValueType # 2
25
+ class ClientAppOutputCode(_ClientAppOutputCode, metaclass=_ClientAppOutputCodeEnumTypeWrapper):
26
+ pass
27
+
28
+ SUCCESS: ClientAppOutputCode.ValueType # 0
29
+ DEADLINE_EXCEEDED: ClientAppOutputCode.ValueType # 1
30
+ UNKNOWN_ERROR: ClientAppOutputCode.ValueType # 2
31
+ global___ClientAppOutputCode = ClientAppOutputCode
32
+
33
+
34
+ class ClientAppOutputStatus(google.protobuf.message.Message):
35
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
36
+ CODE_FIELD_NUMBER: builtins.int
37
+ MESSAGE_FIELD_NUMBER: builtins.int
38
+ code: global___ClientAppOutputCode.ValueType
39
+ message: typing.Text
40
+ def __init__(self,
41
+ *,
42
+ code: global___ClientAppOutputCode.ValueType = ...,
43
+ message: typing.Text = ...,
44
+ ) -> None: ...
45
+ def ClearField(self, field_name: typing_extensions.Literal["code",b"code","message",b"message"]) -> None: ...
46
+ global___ClientAppOutputStatus = ClientAppOutputStatus
47
+
48
+ class GetTokenRequest(google.protobuf.message.Message):
49
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
50
+ def __init__(self,
51
+ ) -> None: ...
52
+ global___GetTokenRequest = GetTokenRequest
53
+
54
+ class GetTokenResponse(google.protobuf.message.Message):
55
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
56
+ TOKEN_FIELD_NUMBER: builtins.int
57
+ token: builtins.int
58
+ def __init__(self,
59
+ *,
60
+ token: builtins.int = ...,
61
+ ) -> None: ...
62
+ def ClearField(self, field_name: typing_extensions.Literal["token",b"token"]) -> None: ...
63
+ global___GetTokenResponse = GetTokenResponse
64
+
65
+ class PullClientAppInputsRequest(google.protobuf.message.Message):
66
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
67
+ TOKEN_FIELD_NUMBER: builtins.int
68
+ token: builtins.int
69
+ def __init__(self,
70
+ *,
71
+ token: builtins.int = ...,
72
+ ) -> None: ...
73
+ def ClearField(self, field_name: typing_extensions.Literal["token",b"token"]) -> None: ...
74
+ global___PullClientAppInputsRequest = PullClientAppInputsRequest
75
+
76
+ class PullClientAppInputsResponse(google.protobuf.message.Message):
77
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
78
+ MESSAGE_FIELD_NUMBER: builtins.int
79
+ CONTEXT_FIELD_NUMBER: builtins.int
80
+ RUN_FIELD_NUMBER: builtins.int
81
+ FAB_FIELD_NUMBER: builtins.int
82
+ @property
83
+ def message(self) -> flwr.proto.message_pb2.Message: ...
84
+ @property
85
+ def context(self) -> flwr.proto.message_pb2.Context: ...
86
+ @property
87
+ def run(self) -> flwr.proto.run_pb2.Run: ...
88
+ @property
89
+ def fab(self) -> flwr.proto.fab_pb2.Fab: ...
90
+ def __init__(self,
91
+ *,
92
+ message: typing.Optional[flwr.proto.message_pb2.Message] = ...,
93
+ context: typing.Optional[flwr.proto.message_pb2.Context] = ...,
94
+ run: typing.Optional[flwr.proto.run_pb2.Run] = ...,
95
+ fab: typing.Optional[flwr.proto.fab_pb2.Fab] = ...,
96
+ ) -> None: ...
97
+ def HasField(self, field_name: typing_extensions.Literal["context",b"context","fab",b"fab","message",b"message","run",b"run"]) -> builtins.bool: ...
98
+ def ClearField(self, field_name: typing_extensions.Literal["context",b"context","fab",b"fab","message",b"message","run",b"run"]) -> None: ...
99
+ global___PullClientAppInputsResponse = PullClientAppInputsResponse
100
+
101
+ class PushClientAppOutputsRequest(google.protobuf.message.Message):
102
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
103
+ TOKEN_FIELD_NUMBER: builtins.int
104
+ MESSAGE_FIELD_NUMBER: builtins.int
105
+ CONTEXT_FIELD_NUMBER: builtins.int
106
+ token: builtins.int
107
+ @property
108
+ def message(self) -> flwr.proto.message_pb2.Message: ...
109
+ @property
110
+ def context(self) -> flwr.proto.message_pb2.Context: ...
111
+ def __init__(self,
112
+ *,
113
+ token: builtins.int = ...,
114
+ message: typing.Optional[flwr.proto.message_pb2.Message] = ...,
115
+ context: typing.Optional[flwr.proto.message_pb2.Context] = ...,
116
+ ) -> None: ...
117
+ def HasField(self, field_name: typing_extensions.Literal["context",b"context","message",b"message"]) -> builtins.bool: ...
118
+ def ClearField(self, field_name: typing_extensions.Literal["context",b"context","message",b"message","token",b"token"]) -> None: ...
119
+ global___PushClientAppOutputsRequest = PushClientAppOutputsRequest
120
+
121
+ class PushClientAppOutputsResponse(google.protobuf.message.Message):
122
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
123
+ STATUS_FIELD_NUMBER: builtins.int
124
+ @property
125
+ def status(self) -> global___ClientAppOutputStatus: ...
126
+ def __init__(self,
127
+ *,
128
+ status: typing.Optional[global___ClientAppOutputStatus] = ...,
129
+ ) -> None: ...
130
+ def HasField(self, field_name: typing_extensions.Literal["status",b"status"]) -> builtins.bool: ...
131
+ def ClearField(self, field_name: typing_extensions.Literal["status",b"status"]) -> None: ...
132
+ global___PushClientAppOutputsResponse = PushClientAppOutputsResponse
@@ -0,0 +1,135 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+
5
+ from flwr.proto import clientappio_pb2 as flwr_dot_proto_dot_clientappio__pb2
6
+
7
+
8
+ class ClientAppIoStub(object):
9
+ """Missing associated documentation comment in .proto file."""
10
+
11
+ def __init__(self, channel):
12
+ """Constructor.
13
+
14
+ Args:
15
+ channel: A grpc.Channel.
16
+ """
17
+ self.GetToken = channel.unary_unary(
18
+ '/flwr.proto.ClientAppIo/GetToken',
19
+ request_serializer=flwr_dot_proto_dot_clientappio__pb2.GetTokenRequest.SerializeToString,
20
+ response_deserializer=flwr_dot_proto_dot_clientappio__pb2.GetTokenResponse.FromString,
21
+ )
22
+ self.PullClientAppInputs = channel.unary_unary(
23
+ '/flwr.proto.ClientAppIo/PullClientAppInputs',
24
+ request_serializer=flwr_dot_proto_dot_clientappio__pb2.PullClientAppInputsRequest.SerializeToString,
25
+ response_deserializer=flwr_dot_proto_dot_clientappio__pb2.PullClientAppInputsResponse.FromString,
26
+ )
27
+ self.PushClientAppOutputs = channel.unary_unary(
28
+ '/flwr.proto.ClientAppIo/PushClientAppOutputs',
29
+ request_serializer=flwr_dot_proto_dot_clientappio__pb2.PushClientAppOutputsRequest.SerializeToString,
30
+ response_deserializer=flwr_dot_proto_dot_clientappio__pb2.PushClientAppOutputsResponse.FromString,
31
+ )
32
+
33
+
34
+ class ClientAppIoServicer(object):
35
+ """Missing associated documentation comment in .proto file."""
36
+
37
+ def GetToken(self, request, context):
38
+ """Get token
39
+ """
40
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
41
+ context.set_details('Method not implemented!')
42
+ raise NotImplementedError('Method not implemented!')
43
+
44
+ def PullClientAppInputs(self, request, context):
45
+ """Get Message, Context, and Run
46
+ """
47
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
48
+ context.set_details('Method not implemented!')
49
+ raise NotImplementedError('Method not implemented!')
50
+
51
+ def PushClientAppOutputs(self, request, context):
52
+ """Send updated Message and Context
53
+ """
54
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
55
+ context.set_details('Method not implemented!')
56
+ raise NotImplementedError('Method not implemented!')
57
+
58
+
59
+ def add_ClientAppIoServicer_to_server(servicer, server):
60
+ rpc_method_handlers = {
61
+ 'GetToken': grpc.unary_unary_rpc_method_handler(
62
+ servicer.GetToken,
63
+ request_deserializer=flwr_dot_proto_dot_clientappio__pb2.GetTokenRequest.FromString,
64
+ response_serializer=flwr_dot_proto_dot_clientappio__pb2.GetTokenResponse.SerializeToString,
65
+ ),
66
+ 'PullClientAppInputs': grpc.unary_unary_rpc_method_handler(
67
+ servicer.PullClientAppInputs,
68
+ request_deserializer=flwr_dot_proto_dot_clientappio__pb2.PullClientAppInputsRequest.FromString,
69
+ response_serializer=flwr_dot_proto_dot_clientappio__pb2.PullClientAppInputsResponse.SerializeToString,
70
+ ),
71
+ 'PushClientAppOutputs': grpc.unary_unary_rpc_method_handler(
72
+ servicer.PushClientAppOutputs,
73
+ request_deserializer=flwr_dot_proto_dot_clientappio__pb2.PushClientAppOutputsRequest.FromString,
74
+ response_serializer=flwr_dot_proto_dot_clientappio__pb2.PushClientAppOutputsResponse.SerializeToString,
75
+ ),
76
+ }
77
+ generic_handler = grpc.method_handlers_generic_handler(
78
+ 'flwr.proto.ClientAppIo', rpc_method_handlers)
79
+ server.add_generic_rpc_handlers((generic_handler,))
80
+
81
+
82
+ # This class is part of an EXPERIMENTAL API.
83
+ class ClientAppIo(object):
84
+ """Missing associated documentation comment in .proto file."""
85
+
86
+ @staticmethod
87
+ def GetToken(request,
88
+ target,
89
+ options=(),
90
+ channel_credentials=None,
91
+ call_credentials=None,
92
+ insecure=False,
93
+ compression=None,
94
+ wait_for_ready=None,
95
+ timeout=None,
96
+ metadata=None):
97
+ return grpc.experimental.unary_unary(request, target, '/flwr.proto.ClientAppIo/GetToken',
98
+ flwr_dot_proto_dot_clientappio__pb2.GetTokenRequest.SerializeToString,
99
+ flwr_dot_proto_dot_clientappio__pb2.GetTokenResponse.FromString,
100
+ options, channel_credentials,
101
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
102
+
103
+ @staticmethod
104
+ def PullClientAppInputs(request,
105
+ target,
106
+ options=(),
107
+ channel_credentials=None,
108
+ call_credentials=None,
109
+ insecure=False,
110
+ compression=None,
111
+ wait_for_ready=None,
112
+ timeout=None,
113
+ metadata=None):
114
+ return grpc.experimental.unary_unary(request, target, '/flwr.proto.ClientAppIo/PullClientAppInputs',
115
+ flwr_dot_proto_dot_clientappio__pb2.PullClientAppInputsRequest.SerializeToString,
116
+ flwr_dot_proto_dot_clientappio__pb2.PullClientAppInputsResponse.FromString,
117
+ options, channel_credentials,
118
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
119
+
120
+ @staticmethod
121
+ def PushClientAppOutputs(request,
122
+ target,
123
+ options=(),
124
+ channel_credentials=None,
125
+ call_credentials=None,
126
+ insecure=False,
127
+ compression=None,
128
+ wait_for_ready=None,
129
+ timeout=None,
130
+ metadata=None):
131
+ return grpc.experimental.unary_unary(request, target, '/flwr.proto.ClientAppIo/PushClientAppOutputs',
132
+ flwr_dot_proto_dot_clientappio__pb2.PushClientAppOutputsRequest.SerializeToString,
133
+ flwr_dot_proto_dot_clientappio__pb2.PushClientAppOutputsResponse.FromString,
134
+ options, channel_credentials,
135
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@@ -0,0 +1,53 @@
1
+ """
2
+ @generated by mypy-protobuf. Do not edit manually!
3
+ isort:skip_file
4
+ """
5
+ import abc
6
+ import flwr.proto.clientappio_pb2
7
+ import grpc
8
+
9
+ class ClientAppIoStub:
10
+ def __init__(self, channel: grpc.Channel) -> None: ...
11
+ GetToken: grpc.UnaryUnaryMultiCallable[
12
+ flwr.proto.clientappio_pb2.GetTokenRequest,
13
+ flwr.proto.clientappio_pb2.GetTokenResponse]
14
+ """Get token"""
15
+
16
+ PullClientAppInputs: grpc.UnaryUnaryMultiCallable[
17
+ flwr.proto.clientappio_pb2.PullClientAppInputsRequest,
18
+ flwr.proto.clientappio_pb2.PullClientAppInputsResponse]
19
+ """Get Message, Context, and Run"""
20
+
21
+ PushClientAppOutputs: grpc.UnaryUnaryMultiCallable[
22
+ flwr.proto.clientappio_pb2.PushClientAppOutputsRequest,
23
+ flwr.proto.clientappio_pb2.PushClientAppOutputsResponse]
24
+ """Send updated Message and Context"""
25
+
26
+
27
+ class ClientAppIoServicer(metaclass=abc.ABCMeta):
28
+ @abc.abstractmethod
29
+ def GetToken(self,
30
+ request: flwr.proto.clientappio_pb2.GetTokenRequest,
31
+ context: grpc.ServicerContext,
32
+ ) -> flwr.proto.clientappio_pb2.GetTokenResponse:
33
+ """Get token"""
34
+ pass
35
+
36
+ @abc.abstractmethod
37
+ def PullClientAppInputs(self,
38
+ request: flwr.proto.clientappio_pb2.PullClientAppInputsRequest,
39
+ context: grpc.ServicerContext,
40
+ ) -> flwr.proto.clientappio_pb2.PullClientAppInputsResponse:
41
+ """Get Message, Context, and Run"""
42
+ pass
43
+
44
+ @abc.abstractmethod
45
+ def PushClientAppOutputs(self,
46
+ request: flwr.proto.clientappio_pb2.PushClientAppOutputsRequest,
47
+ context: grpc.ServicerContext,
48
+ ) -> flwr.proto.clientappio_pb2.PushClientAppOutputsResponse:
49
+ """Send updated Message and Context"""
50
+ pass
51
+
52
+
53
+ def add_ClientAppIoServicer_to_server(servicer: ClientAppIoServicer, server: grpc.Server) -> None: ...
flwr/proto/exec_pb2.py CHANGED
@@ -12,10 +12,11 @@ from google.protobuf.internal import builder as _builder
12
12
  _sym_db = _symbol_database.Default()
13
13
 
14
14
 
15
+ from flwr.proto import fab_pb2 as flwr_dot_proto_dot_fab__pb2
15
16
  from flwr.proto import transport_pb2 as flwr_dot_proto_dot_transport__pb2
16
17
 
17
18
 
18
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x66lwr/proto/exec.proto\x12\nflwr.proto\x1a\x1a\x66lwr/proto/transport.proto\"\xd3\x02\n\x0fStartRunRequest\x12\x10\n\x08\x66\x61\x62_file\x18\x01 \x01(\x0c\x12H\n\x0foverride_config\x18\x02 \x03(\x0b\x32/.flwr.proto.StartRunRequest.OverrideConfigEntry\x12L\n\x11\x66\x65\x64\x65ration_config\x18\x03 \x03(\x0b\x32\x31.flwr.proto.StartRunRequest.FederationConfigEntry\x1aI\n\x13OverrideConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\x1aK\n\x15\x46\x65\x64\x65rationConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\"\"\n\x10StartRunResponse\x12\x0e\n\x06run_id\x18\x01 \x01(\x12\"#\n\x11StreamLogsRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x12\"(\n\x12StreamLogsResponse\x12\x12\n\nlog_output\x18\x01 \x01(\t2\xa0\x01\n\x04\x45xec\x12G\n\x08StartRun\x12\x1b.flwr.proto.StartRunRequest\x1a\x1c.flwr.proto.StartRunResponse\"\x00\x12O\n\nStreamLogs\x12\x1d.flwr.proto.StreamLogsRequest\x1a\x1e.flwr.proto.StreamLogsResponse\"\x00\x30\x01\x62\x06proto3')
19
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x66lwr/proto/exec.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x1a\x66lwr/proto/transport.proto\"\xdf\x02\n\x0fStartRunRequest\x12\x1c\n\x03\x66\x61\x62\x18\x01 \x01(\x0b\x32\x0f.flwr.proto.Fab\x12H\n\x0foverride_config\x18\x02 \x03(\x0b\x32/.flwr.proto.StartRunRequest.OverrideConfigEntry\x12L\n\x11\x66\x65\x64\x65ration_config\x18\x03 \x03(\x0b\x32\x31.flwr.proto.StartRunRequest.FederationConfigEntry\x1aI\n\x13OverrideConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\x1aK\n\x15\x46\x65\x64\x65rationConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\"\"\n\x10StartRunResponse\x12\x0e\n\x06run_id\x18\x01 \x01(\x12\"#\n\x11StreamLogsRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x12\"(\n\x12StreamLogsResponse\x12\x12\n\nlog_output\x18\x01 \x01(\t2\xa0\x01\n\x04\x45xec\x12G\n\x08StartRun\x12\x1b.flwr.proto.StartRunRequest\x1a\x1c.flwr.proto.StartRunResponse\"\x00\x12O\n\nStreamLogs\x12\x1d.flwr.proto.StreamLogsRequest\x1a\x1e.flwr.proto.StreamLogsResponse\"\x00\x30\x01\x62\x06proto3')
19
20
 
20
21
  _globals = globals()
21
22
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -26,18 +27,18 @@ if _descriptor._USE_C_DESCRIPTORS == False:
26
27
  _globals['_STARTRUNREQUEST_OVERRIDECONFIGENTRY']._serialized_options = b'8\001'
27
28
  _globals['_STARTRUNREQUEST_FEDERATIONCONFIGENTRY']._options = None
28
29
  _globals['_STARTRUNREQUEST_FEDERATIONCONFIGENTRY']._serialized_options = b'8\001'
29
- _globals['_STARTRUNREQUEST']._serialized_start=66
30
- _globals['_STARTRUNREQUEST']._serialized_end=405
31
- _globals['_STARTRUNREQUEST_OVERRIDECONFIGENTRY']._serialized_start=255
32
- _globals['_STARTRUNREQUEST_OVERRIDECONFIGENTRY']._serialized_end=328
33
- _globals['_STARTRUNREQUEST_FEDERATIONCONFIGENTRY']._serialized_start=330
34
- _globals['_STARTRUNREQUEST_FEDERATIONCONFIGENTRY']._serialized_end=405
35
- _globals['_STARTRUNRESPONSE']._serialized_start=407
36
- _globals['_STARTRUNRESPONSE']._serialized_end=441
37
- _globals['_STREAMLOGSREQUEST']._serialized_start=443
38
- _globals['_STREAMLOGSREQUEST']._serialized_end=478
39
- _globals['_STREAMLOGSRESPONSE']._serialized_start=480
40
- _globals['_STREAMLOGSRESPONSE']._serialized_end=520
41
- _globals['_EXEC']._serialized_start=523
42
- _globals['_EXEC']._serialized_end=683
30
+ _globals['_STARTRUNREQUEST']._serialized_start=88
31
+ _globals['_STARTRUNREQUEST']._serialized_end=439
32
+ _globals['_STARTRUNREQUEST_OVERRIDECONFIGENTRY']._serialized_start=289
33
+ _globals['_STARTRUNREQUEST_OVERRIDECONFIGENTRY']._serialized_end=362
34
+ _globals['_STARTRUNREQUEST_FEDERATIONCONFIGENTRY']._serialized_start=364
35
+ _globals['_STARTRUNREQUEST_FEDERATIONCONFIGENTRY']._serialized_end=439
36
+ _globals['_STARTRUNRESPONSE']._serialized_start=441
37
+ _globals['_STARTRUNRESPONSE']._serialized_end=475
38
+ _globals['_STREAMLOGSREQUEST']._serialized_start=477
39
+ _globals['_STREAMLOGSREQUEST']._serialized_end=512
40
+ _globals['_STREAMLOGSRESPONSE']._serialized_start=514
41
+ _globals['_STREAMLOGSRESPONSE']._serialized_end=554
42
+ _globals['_EXEC']._serialized_start=557
43
+ _globals['_EXEC']._serialized_end=717
43
44
  # @@protoc_insertion_point(module_scope)
flwr/proto/exec_pb2.pyi CHANGED
@@ -3,6 +3,7 @@
3
3
  isort:skip_file
4
4
  """
5
5
  import builtins
6
+ import flwr.proto.fab_pb2
6
7
  import flwr.proto.transport_pb2
7
8
  import google.protobuf.descriptor
8
9
  import google.protobuf.internal.containers
@@ -44,21 +45,23 @@ class StartRunRequest(google.protobuf.message.Message):
44
45
  def HasField(self, field_name: typing_extensions.Literal["value",b"value"]) -> builtins.bool: ...
45
46
  def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ...
46
47
 
47
- FAB_FILE_FIELD_NUMBER: builtins.int
48
+ FAB_FIELD_NUMBER: builtins.int
48
49
  OVERRIDE_CONFIG_FIELD_NUMBER: builtins.int
49
50
  FEDERATION_CONFIG_FIELD_NUMBER: builtins.int
50
- fab_file: builtins.bytes
51
+ @property
52
+ def fab(self) -> flwr.proto.fab_pb2.Fab: ...
51
53
  @property
52
54
  def override_config(self) -> google.protobuf.internal.containers.MessageMap[typing.Text, flwr.proto.transport_pb2.Scalar]: ...
53
55
  @property
54
56
  def federation_config(self) -> google.protobuf.internal.containers.MessageMap[typing.Text, flwr.proto.transport_pb2.Scalar]: ...
55
57
  def __init__(self,
56
58
  *,
57
- fab_file: builtins.bytes = ...,
59
+ fab: typing.Optional[flwr.proto.fab_pb2.Fab] = ...,
58
60
  override_config: typing.Optional[typing.Mapping[typing.Text, flwr.proto.transport_pb2.Scalar]] = ...,
59
61
  federation_config: typing.Optional[typing.Mapping[typing.Text, flwr.proto.transport_pb2.Scalar]] = ...,
60
62
  ) -> None: ...
61
- def ClearField(self, field_name: typing_extensions.Literal["fab_file",b"fab_file","federation_config",b"federation_config","override_config",b"override_config"]) -> None: ...
63
+ def HasField(self, field_name: typing_extensions.Literal["fab",b"fab"]) -> builtins.bool: ...
64
+ def ClearField(self, field_name: typing_extensions.Literal["fab",b"fab","federation_config",b"federation_config","override_config",b"override_config"]) -> None: ...
62
65
  global___StartRunRequest = StartRunRequest
63
66
 
64
67
  class StartRunResponse(google.protobuf.message.Message):
@@ -0,0 +1,41 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: flwr/proto/message.proto
4
+ # Protobuf Python Version: 4.25.0
5
+ """Generated protocol buffer code."""
6
+ from google.protobuf import descriptor as _descriptor
7
+ from google.protobuf import descriptor_pool as _descriptor_pool
8
+ from google.protobuf import symbol_database as _symbol_database
9
+ from google.protobuf.internal import builder as _builder
10
+ # @@protoc_insertion_point(imports)
11
+
12
+ _sym_db = _symbol_database.Default()
13
+
14
+
15
+ from flwr.proto import error_pb2 as flwr_dot_proto_dot_error__pb2
16
+ from flwr.proto import recordset_pb2 as flwr_dot_proto_dot_recordset__pb2
17
+ from flwr.proto import transport_pb2 as flwr_dot_proto_dot_transport__pb2
18
+
19
+
20
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18\x66lwr/proto/message.proto\x12\nflwr.proto\x1a\x16\x66lwr/proto/error.proto\x1a\x1a\x66lwr/proto/recordset.proto\x1a\x1a\x66lwr/proto/transport.proto\"{\n\x07Message\x12&\n\x08metadata\x18\x01 \x01(\x0b\x32\x14.flwr.proto.Metadata\x12&\n\x07\x63ontent\x18\x02 \x01(\x0b\x32\x15.flwr.proto.RecordSet\x12 \n\x05\x65rror\x18\x03 \x01(\x0b\x32\x11.flwr.proto.Error\"\xbf\x02\n\x07\x43ontext\x12\x0f\n\x07node_id\x18\x01 \x01(\x12\x12\x38\n\x0bnode_config\x18\x02 \x03(\x0b\x32#.flwr.proto.Context.NodeConfigEntry\x12$\n\x05state\x18\x03 \x01(\x0b\x32\x15.flwr.proto.RecordSet\x12\x36\n\nrun_config\x18\x04 \x03(\x0b\x32\".flwr.proto.Context.RunConfigEntry\x1a\x45\n\x0fNodeConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\x1a\x44\n\x0eRunConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\"\xbb\x01\n\x08Metadata\x12\x0e\n\x06run_id\x18\x01 \x01(\x12\x12\x12\n\nmessage_id\x18\x02 \x01(\t\x12\x13\n\x0bsrc_node_id\x18\x03 \x01(\x12\x12\x13\n\x0b\x64st_node_id\x18\x04 \x01(\x12\x12\x18\n\x10reply_to_message\x18\x05 \x01(\t\x12\x10\n\x08group_id\x18\x06 \x01(\t\x12\x0b\n\x03ttl\x18\x07 \x01(\x01\x12\x14\n\x0cmessage_type\x18\x08 \x01(\t\x12\x12\n\ncreated_at\x18\t \x01(\x01\x62\x06proto3')
21
+
22
+ _globals = globals()
23
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
24
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flwr.proto.message_pb2', _globals)
25
+ if _descriptor._USE_C_DESCRIPTORS == False:
26
+ DESCRIPTOR._options = None
27
+ _globals['_CONTEXT_NODECONFIGENTRY']._options = None
28
+ _globals['_CONTEXT_NODECONFIGENTRY']._serialized_options = b'8\001'
29
+ _globals['_CONTEXT_RUNCONFIGENTRY']._options = None
30
+ _globals['_CONTEXT_RUNCONFIGENTRY']._serialized_options = b'8\001'
31
+ _globals['_MESSAGE']._serialized_start=120
32
+ _globals['_MESSAGE']._serialized_end=243
33
+ _globals['_CONTEXT']._serialized_start=246
34
+ _globals['_CONTEXT']._serialized_end=565
35
+ _globals['_CONTEXT_NODECONFIGENTRY']._serialized_start=426
36
+ _globals['_CONTEXT_NODECONFIGENTRY']._serialized_end=495
37
+ _globals['_CONTEXT_RUNCONFIGENTRY']._serialized_start=497
38
+ _globals['_CONTEXT_RUNCONFIGENTRY']._serialized_end=565
39
+ _globals['_METADATA']._serialized_start=568
40
+ _globals['_METADATA']._serialized_end=755
41
+ # @@protoc_insertion_point(module_scope)
@@ -0,0 +1,125 @@
1
+ """
2
+ @generated by mypy-protobuf. Do not edit manually!
3
+ isort:skip_file
4
+ """
5
+ import builtins
6
+ import flwr.proto.error_pb2
7
+ import flwr.proto.recordset_pb2
8
+ import flwr.proto.transport_pb2
9
+ import google.protobuf.descriptor
10
+ import google.protobuf.internal.containers
11
+ import google.protobuf.message
12
+ import typing
13
+ import typing_extensions
14
+
15
+ DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
16
+
17
+ class Message(google.protobuf.message.Message):
18
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
19
+ METADATA_FIELD_NUMBER: builtins.int
20
+ CONTENT_FIELD_NUMBER: builtins.int
21
+ ERROR_FIELD_NUMBER: builtins.int
22
+ @property
23
+ def metadata(self) -> global___Metadata: ...
24
+ @property
25
+ def content(self) -> flwr.proto.recordset_pb2.RecordSet: ...
26
+ @property
27
+ def error(self) -> flwr.proto.error_pb2.Error: ...
28
+ def __init__(self,
29
+ *,
30
+ metadata: typing.Optional[global___Metadata] = ...,
31
+ content: typing.Optional[flwr.proto.recordset_pb2.RecordSet] = ...,
32
+ error: typing.Optional[flwr.proto.error_pb2.Error] = ...,
33
+ ) -> None: ...
34
+ def HasField(self, field_name: typing_extensions.Literal["content",b"content","error",b"error","metadata",b"metadata"]) -> builtins.bool: ...
35
+ def ClearField(self, field_name: typing_extensions.Literal["content",b"content","error",b"error","metadata",b"metadata"]) -> None: ...
36
+ global___Message = Message
37
+
38
+ class Context(google.protobuf.message.Message):
39
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
40
+ class NodeConfigEntry(google.protobuf.message.Message):
41
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
42
+ KEY_FIELD_NUMBER: builtins.int
43
+ VALUE_FIELD_NUMBER: builtins.int
44
+ key: typing.Text
45
+ @property
46
+ def value(self) -> flwr.proto.transport_pb2.Scalar: ...
47
+ def __init__(self,
48
+ *,
49
+ key: typing.Text = ...,
50
+ value: typing.Optional[flwr.proto.transport_pb2.Scalar] = ...,
51
+ ) -> None: ...
52
+ def HasField(self, field_name: typing_extensions.Literal["value",b"value"]) -> builtins.bool: ...
53
+ def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ...
54
+
55
+ class RunConfigEntry(google.protobuf.message.Message):
56
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
57
+ KEY_FIELD_NUMBER: builtins.int
58
+ VALUE_FIELD_NUMBER: builtins.int
59
+ key: typing.Text
60
+ @property
61
+ def value(self) -> flwr.proto.transport_pb2.Scalar: ...
62
+ def __init__(self,
63
+ *,
64
+ key: typing.Text = ...,
65
+ value: typing.Optional[flwr.proto.transport_pb2.Scalar] = ...,
66
+ ) -> None: ...
67
+ def HasField(self, field_name: typing_extensions.Literal["value",b"value"]) -> builtins.bool: ...
68
+ def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ...
69
+
70
+ NODE_ID_FIELD_NUMBER: builtins.int
71
+ NODE_CONFIG_FIELD_NUMBER: builtins.int
72
+ STATE_FIELD_NUMBER: builtins.int
73
+ RUN_CONFIG_FIELD_NUMBER: builtins.int
74
+ node_id: builtins.int
75
+ @property
76
+ def node_config(self) -> google.protobuf.internal.containers.MessageMap[typing.Text, flwr.proto.transport_pb2.Scalar]: ...
77
+ @property
78
+ def state(self) -> flwr.proto.recordset_pb2.RecordSet: ...
79
+ @property
80
+ def run_config(self) -> google.protobuf.internal.containers.MessageMap[typing.Text, flwr.proto.transport_pb2.Scalar]: ...
81
+ def __init__(self,
82
+ *,
83
+ node_id: builtins.int = ...,
84
+ node_config: typing.Optional[typing.Mapping[typing.Text, flwr.proto.transport_pb2.Scalar]] = ...,
85
+ state: typing.Optional[flwr.proto.recordset_pb2.RecordSet] = ...,
86
+ run_config: typing.Optional[typing.Mapping[typing.Text, flwr.proto.transport_pb2.Scalar]] = ...,
87
+ ) -> None: ...
88
+ def HasField(self, field_name: typing_extensions.Literal["state",b"state"]) -> builtins.bool: ...
89
+ def ClearField(self, field_name: typing_extensions.Literal["node_config",b"node_config","node_id",b"node_id","run_config",b"run_config","state",b"state"]) -> None: ...
90
+ global___Context = Context
91
+
92
+ class Metadata(google.protobuf.message.Message):
93
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
94
+ RUN_ID_FIELD_NUMBER: builtins.int
95
+ MESSAGE_ID_FIELD_NUMBER: builtins.int
96
+ SRC_NODE_ID_FIELD_NUMBER: builtins.int
97
+ DST_NODE_ID_FIELD_NUMBER: builtins.int
98
+ REPLY_TO_MESSAGE_FIELD_NUMBER: builtins.int
99
+ GROUP_ID_FIELD_NUMBER: builtins.int
100
+ TTL_FIELD_NUMBER: builtins.int
101
+ MESSAGE_TYPE_FIELD_NUMBER: builtins.int
102
+ CREATED_AT_FIELD_NUMBER: builtins.int
103
+ run_id: builtins.int
104
+ message_id: typing.Text
105
+ src_node_id: builtins.int
106
+ dst_node_id: builtins.int
107
+ reply_to_message: typing.Text
108
+ group_id: typing.Text
109
+ ttl: builtins.float
110
+ message_type: typing.Text
111
+ created_at: builtins.float
112
+ def __init__(self,
113
+ *,
114
+ run_id: builtins.int = ...,
115
+ message_id: typing.Text = ...,
116
+ src_node_id: builtins.int = ...,
117
+ dst_node_id: builtins.int = ...,
118
+ reply_to_message: typing.Text = ...,
119
+ group_id: typing.Text = ...,
120
+ ttl: builtins.float = ...,
121
+ message_type: typing.Text = ...,
122
+ created_at: builtins.float = ...,
123
+ ) -> None: ...
124
+ def ClearField(self, field_name: typing_extensions.Literal["created_at",b"created_at","dst_node_id",b"dst_node_id","group_id",b"group_id","message_id",b"message_id","message_type",b"message_type","reply_to_message",b"reply_to_message","run_id",b"run_id","src_node_id",b"src_node_id","ttl",b"ttl"]) -> None: ...
125
+ global___Metadata = Metadata
@@ -0,0 +1,4 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+
@@ -0,0 +1,4 @@
1
+ """
2
+ @generated by mypy-protobuf. Do not edit manually!
3
+ isort:skip_file
4
+ """
flwr/server/app.py CHANGED
@@ -34,6 +34,7 @@ from cryptography.hazmat.primitives.serialization import (
34
34
 
35
35
  from flwr.common import GRPC_MAX_MESSAGE_LENGTH, EventType, event
36
36
  from flwr.common.address import parse_address
37
+ from flwr.common.config import get_flwr_dir
37
38
  from flwr.common.constant import (
38
39
  MISSING_EXTRA_REST,
39
40
  TRANSPORT_TYPE_GRPC_ADAPTER,
@@ -57,6 +58,7 @@ from .server import Server, init_defaults, run_fl
57
58
  from .server_config import ServerConfig
58
59
  from .strategy import Strategy
59
60
  from .superlink.driver.driver_grpc import run_driver_api_grpc
61
+ from .superlink.ffs.ffs_factory import FfsFactory
60
62
  from .superlink.fleet.grpc_adapter.grpc_adapter_servicer import GrpcAdapterServicer
61
63
  from .superlink.fleet.grpc_bidi.grpc_server import (
62
64
  generic_create_grpc_server,
@@ -72,6 +74,7 @@ ADDRESS_FLEET_API_GRPC_BIDI = "[::]:8080" # IPv6 to keep start_server compatibl
72
74
  ADDRESS_FLEET_API_REST = "0.0.0.0:9093"
73
75
 
74
76
  DATABASE = ":flwr-in-memory-state:"
77
+ BASE_DIR = get_flwr_dir() / "superlink" / "ffs"
75
78
 
76
79
 
77
80
  def start_server( # pylint: disable=too-many-arguments,too-many-locals
@@ -211,10 +214,14 @@ def run_superlink() -> None:
211
214
  # Initialize StateFactory
212
215
  state_factory = StateFactory(args.database)
213
216
 
217
+ # Initialize FfsFactory
218
+ ffs_factory = FfsFactory(args.storage_dir)
219
+
214
220
  # Start Driver API
215
221
  driver_server: grpc.Server = run_driver_api_grpc(
216
222
  address=driver_address,
217
223
  state_factory=state_factory,
224
+ ffs_factory=ffs_factory,
218
225
  certificates=certificates,
219
226
  )
220
227
 
@@ -294,6 +301,7 @@ def run_superlink() -> None:
294
301
  fleet_server = _run_fleet_api_grpc_rere(
295
302
  address=fleet_address,
296
303
  state_factory=state_factory,
304
+ ffs_factory=ffs_factory,
297
305
  certificates=certificates,
298
306
  interceptors=interceptors,
299
307
  )
@@ -480,6 +488,7 @@ def _try_obtain_certificates(
480
488
  def _run_fleet_api_grpc_rere(
481
489
  address: str,
482
490
  state_factory: StateFactory,
491
+ ffs_factory: FfsFactory,
483
492
  certificates: Optional[Tuple[bytes, bytes, bytes]],
484
493
  interceptors: Optional[Sequence[grpc.ServerInterceptor]] = None,
485
494
  ) -> grpc.Server:
@@ -487,6 +496,7 @@ def _run_fleet_api_grpc_rere(
487
496
  # Create Fleet API gRPC server
488
497
  fleet_servicer = FleetServicer(
489
498
  state_factory=state_factory,
499
+ ffs_factory=ffs_factory,
490
500
  )
491
501
  fleet_add_servicer_to_server_fn = add_FleetServicer_to_server
492
502
  fleet_grpc_server = generic_create_grpc_server(
@@ -610,6 +620,11 @@ def _add_args_common(parser: argparse.ArgumentParser) -> None:
610
620
  "Flower will just create a state in memory.",
611
621
  default=DATABASE,
612
622
  )
623
+ parser.add_argument(
624
+ "--storage-dir",
625
+ help="The base directory to store the objects for the Flower File System.",
626
+ default=BASE_DIR,
627
+ )
613
628
  parser.add_argument(
614
629
  "--auth-list-public-keys",
615
630
  type=str,