flwr-nightly 1.15.0.dev20250114__py3-none-any.whl → 1.15.0.dev20250123__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.
Files changed (82) hide show
  1. flwr/cli/config_utils.py +23 -146
  2. flwr/cli/constant.py +27 -0
  3. flwr/cli/install.py +1 -1
  4. flwr/cli/log.py +17 -2
  5. flwr/cli/login/login.py +9 -1
  6. flwr/cli/ls.py +10 -2
  7. flwr/cli/run/run.py +20 -10
  8. flwr/cli/stop.py +9 -1
  9. flwr/client/app.py +23 -43
  10. flwr/client/clientapp/app.py +4 -6
  11. flwr/client/clientapp/utils.py +1 -1
  12. flwr/client/grpc_client/connection.py +0 -6
  13. flwr/client/grpc_rere_client/client_interceptor.py +19 -125
  14. flwr/client/grpc_rere_client/connection.py +10 -0
  15. flwr/client/rest_client/connection.py +12 -3
  16. flwr/client/supernode/app.py +14 -20
  17. flwr/common/auth_plugin/auth_plugin.py +1 -0
  18. flwr/common/config.py +152 -15
  19. flwr/common/constant.py +9 -8
  20. flwr/common/exit/__init__.py +24 -0
  21. flwr/common/exit/exit.py +99 -0
  22. flwr/common/exit/exit_code.py +93 -0
  23. flwr/common/exit_handlers.py +24 -10
  24. flwr/common/grpc.py +7 -0
  25. flwr/common/logger.py +1 -1
  26. flwr/common/serde.py +6 -4
  27. flwr/proto/clientappio_pb2.py +13 -3
  28. flwr/proto/clientappio_pb2_grpc.py +63 -12
  29. flwr/proto/error_pb2.py +13 -3
  30. flwr/proto/error_pb2_grpc.py +20 -0
  31. flwr/proto/exec_pb2.py +15 -5
  32. flwr/proto/exec_pb2_grpc.py +105 -24
  33. flwr/proto/fab_pb2.py +13 -3
  34. flwr/proto/fab_pb2_grpc.py +20 -0
  35. flwr/proto/fleet_pb2.py +15 -5
  36. flwr/proto/fleet_pb2_grpc.py +147 -36
  37. flwr/proto/grpcadapter_pb2.py +14 -4
  38. flwr/proto/grpcadapter_pb2_grpc.py +35 -4
  39. flwr/proto/log_pb2.py +13 -3
  40. flwr/proto/log_pb2_grpc.py +20 -0
  41. flwr/proto/message_pb2.py +15 -5
  42. flwr/proto/message_pb2_grpc.py +20 -0
  43. flwr/proto/node_pb2.py +15 -5
  44. flwr/proto/node_pb2.pyi +1 -4
  45. flwr/proto/node_pb2_grpc.py +20 -0
  46. flwr/proto/recordset_pb2.py +18 -8
  47. flwr/proto/recordset_pb2_grpc.py +20 -0
  48. flwr/proto/run_pb2.py +16 -6
  49. flwr/proto/run_pb2_grpc.py +20 -0
  50. flwr/proto/serverappio_pb2.py +32 -14
  51. flwr/proto/serverappio_pb2.pyi +56 -0
  52. flwr/proto/serverappio_pb2_grpc.py +261 -44
  53. flwr/proto/serverappio_pb2_grpc.pyi +20 -0
  54. flwr/proto/simulationio_pb2.py +13 -3
  55. flwr/proto/simulationio_pb2_grpc.py +105 -24
  56. flwr/proto/task_pb2.py +13 -3
  57. flwr/proto/task_pb2_grpc.py +20 -0
  58. flwr/proto/transport_pb2.py +20 -10
  59. flwr/proto/transport_pb2_grpc.py +35 -4
  60. flwr/server/app.py +40 -11
  61. flwr/server/compat/app_utils.py +0 -1
  62. flwr/server/compat/driver_client_proxy.py +1 -2
  63. flwr/server/driver/grpc_driver.py +5 -2
  64. flwr/server/driver/inmemory_driver.py +2 -1
  65. flwr/server/serverapp/app.py +5 -6
  66. flwr/server/superlink/driver/serverappio_servicer.py +110 -6
  67. flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +20 -88
  68. flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +95 -169
  69. flwr/server/superlink/fleet/message_handler/message_handler.py +4 -5
  70. flwr/server/superlink/fleet/rest_rere/rest_api.py +2 -3
  71. flwr/server/superlink/linkstate/in_memory_linkstate.py +14 -26
  72. flwr/server/superlink/linkstate/linkstate.py +5 -18
  73. flwr/server/superlink/linkstate/sqlite_linkstate.py +30 -70
  74. flwr/server/superlink/linkstate/utils.py +18 -8
  75. flwr/server/utils/validator.py +9 -34
  76. flwr/simulation/app.py +4 -6
  77. flwr/simulation/legacy_app.py +4 -2
  78. {flwr_nightly-1.15.0.dev20250114.dist-info → flwr_nightly-1.15.0.dev20250123.dist-info}/METADATA +4 -4
  79. {flwr_nightly-1.15.0.dev20250114.dist-info → flwr_nightly-1.15.0.dev20250123.dist-info}/RECORD +82 -78
  80. {flwr_nightly-1.15.0.dev20250114.dist-info → flwr_nightly-1.15.0.dev20250123.dist-info}/LICENSE +0 -0
  81. {flwr_nightly-1.15.0.dev20250114.dist-info → flwr_nightly-1.15.0.dev20250123.dist-info}/WHEEL +0 -0
  82. {flwr_nightly-1.15.0.dev20250114.dist-info → flwr_nightly-1.15.0.dev20250123.dist-info}/entry_points.txt +0 -0
@@ -1,11 +1,31 @@
1
1
  # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
2
  """Client and server classes corresponding to protobuf-defined services."""
3
3
  import grpc
4
+ import warnings
4
5
 
5
6
  from flwr.proto import log_pb2 as flwr_dot_proto_dot_log__pb2
6
7
  from flwr.proto import run_pb2 as flwr_dot_proto_dot_run__pb2
7
8
  from flwr.proto import simulationio_pb2 as flwr_dot_proto_dot_simulationio__pb2
8
9
 
10
+ GRPC_GENERATED_VERSION = '1.69.0'
11
+ GRPC_VERSION = grpc.__version__
12
+ _version_not_supported = False
13
+
14
+ try:
15
+ from grpc._utilities import first_version_is_lower
16
+ _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
17
+ except ImportError:
18
+ _version_not_supported = True
19
+
20
+ if _version_not_supported:
21
+ raise RuntimeError(
22
+ f'The grpc package installed is at version {GRPC_VERSION},'
23
+ + f' but the generated code in flwr/proto/simulationio_pb2_grpc.py depends on'
24
+ + f' grpcio>={GRPC_GENERATED_VERSION}.'
25
+ + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
26
+ + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
27
+ )
28
+
9
29
 
10
30
  class SimulationIoStub(object):
11
31
  """Missing associated documentation comment in .proto file."""
@@ -20,32 +40,32 @@ class SimulationIoStub(object):
20
40
  '/flwr.proto.SimulationIo/PullSimulationInputs',
21
41
  request_serializer=flwr_dot_proto_dot_simulationio__pb2.PullSimulationInputsRequest.SerializeToString,
22
42
  response_deserializer=flwr_dot_proto_dot_simulationio__pb2.PullSimulationInputsResponse.FromString,
23
- )
43
+ _registered_method=True)
24
44
  self.PushSimulationOutputs = channel.unary_unary(
25
45
  '/flwr.proto.SimulationIo/PushSimulationOutputs',
26
46
  request_serializer=flwr_dot_proto_dot_simulationio__pb2.PushSimulationOutputsRequest.SerializeToString,
27
47
  response_deserializer=flwr_dot_proto_dot_simulationio__pb2.PushSimulationOutputsResponse.FromString,
28
- )
48
+ _registered_method=True)
29
49
  self.UpdateRunStatus = channel.unary_unary(
30
50
  '/flwr.proto.SimulationIo/UpdateRunStatus',
31
51
  request_serializer=flwr_dot_proto_dot_run__pb2.UpdateRunStatusRequest.SerializeToString,
32
52
  response_deserializer=flwr_dot_proto_dot_run__pb2.UpdateRunStatusResponse.FromString,
33
- )
53
+ _registered_method=True)
34
54
  self.PushLogs = channel.unary_unary(
35
55
  '/flwr.proto.SimulationIo/PushLogs',
36
56
  request_serializer=flwr_dot_proto_dot_log__pb2.PushLogsRequest.SerializeToString,
37
57
  response_deserializer=flwr_dot_proto_dot_log__pb2.PushLogsResponse.FromString,
38
- )
58
+ _registered_method=True)
39
59
  self.GetFederationOptions = channel.unary_unary(
40
60
  '/flwr.proto.SimulationIo/GetFederationOptions',
41
61
  request_serializer=flwr_dot_proto_dot_run__pb2.GetFederationOptionsRequest.SerializeToString,
42
62
  response_deserializer=flwr_dot_proto_dot_run__pb2.GetFederationOptionsResponse.FromString,
43
- )
63
+ _registered_method=True)
44
64
  self.GetRunStatus = channel.unary_unary(
45
65
  '/flwr.proto.SimulationIo/GetRunStatus',
46
66
  request_serializer=flwr_dot_proto_dot_run__pb2.GetRunStatusRequest.SerializeToString,
47
67
  response_deserializer=flwr_dot_proto_dot_run__pb2.GetRunStatusResponse.FromString,
48
- )
68
+ _registered_method=True)
49
69
 
50
70
 
51
71
  class SimulationIoServicer(object):
@@ -130,6 +150,7 @@ def add_SimulationIoServicer_to_server(servicer, server):
130
150
  generic_handler = grpc.method_handlers_generic_handler(
131
151
  'flwr.proto.SimulationIo', rpc_method_handlers)
132
152
  server.add_generic_rpc_handlers((generic_handler,))
153
+ server.add_registered_method_handlers('flwr.proto.SimulationIo', rpc_method_handlers)
133
154
 
134
155
 
135
156
  # This class is part of an EXPERIMENTAL API.
@@ -147,11 +168,21 @@ class SimulationIo(object):
147
168
  wait_for_ready=None,
148
169
  timeout=None,
149
170
  metadata=None):
150
- return grpc.experimental.unary_unary(request, target, '/flwr.proto.SimulationIo/PullSimulationInputs',
171
+ return grpc.experimental.unary_unary(
172
+ request,
173
+ target,
174
+ '/flwr.proto.SimulationIo/PullSimulationInputs',
151
175
  flwr_dot_proto_dot_simulationio__pb2.PullSimulationInputsRequest.SerializeToString,
152
176
  flwr_dot_proto_dot_simulationio__pb2.PullSimulationInputsResponse.FromString,
153
- options, channel_credentials,
154
- insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
177
+ options,
178
+ channel_credentials,
179
+ insecure,
180
+ call_credentials,
181
+ compression,
182
+ wait_for_ready,
183
+ timeout,
184
+ metadata,
185
+ _registered_method=True)
155
186
 
156
187
  @staticmethod
157
188
  def PushSimulationOutputs(request,
@@ -164,11 +195,21 @@ class SimulationIo(object):
164
195
  wait_for_ready=None,
165
196
  timeout=None,
166
197
  metadata=None):
167
- return grpc.experimental.unary_unary(request, target, '/flwr.proto.SimulationIo/PushSimulationOutputs',
198
+ return grpc.experimental.unary_unary(
199
+ request,
200
+ target,
201
+ '/flwr.proto.SimulationIo/PushSimulationOutputs',
168
202
  flwr_dot_proto_dot_simulationio__pb2.PushSimulationOutputsRequest.SerializeToString,
169
203
  flwr_dot_proto_dot_simulationio__pb2.PushSimulationOutputsResponse.FromString,
170
- options, channel_credentials,
171
- insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
204
+ options,
205
+ channel_credentials,
206
+ insecure,
207
+ call_credentials,
208
+ compression,
209
+ wait_for_ready,
210
+ timeout,
211
+ metadata,
212
+ _registered_method=True)
172
213
 
173
214
  @staticmethod
174
215
  def UpdateRunStatus(request,
@@ -181,11 +222,21 @@ class SimulationIo(object):
181
222
  wait_for_ready=None,
182
223
  timeout=None,
183
224
  metadata=None):
184
- return grpc.experimental.unary_unary(request, target, '/flwr.proto.SimulationIo/UpdateRunStatus',
225
+ return grpc.experimental.unary_unary(
226
+ request,
227
+ target,
228
+ '/flwr.proto.SimulationIo/UpdateRunStatus',
185
229
  flwr_dot_proto_dot_run__pb2.UpdateRunStatusRequest.SerializeToString,
186
230
  flwr_dot_proto_dot_run__pb2.UpdateRunStatusResponse.FromString,
187
- options, channel_credentials,
188
- insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
231
+ options,
232
+ channel_credentials,
233
+ insecure,
234
+ call_credentials,
235
+ compression,
236
+ wait_for_ready,
237
+ timeout,
238
+ metadata,
239
+ _registered_method=True)
189
240
 
190
241
  @staticmethod
191
242
  def PushLogs(request,
@@ -198,11 +249,21 @@ class SimulationIo(object):
198
249
  wait_for_ready=None,
199
250
  timeout=None,
200
251
  metadata=None):
201
- return grpc.experimental.unary_unary(request, target, '/flwr.proto.SimulationIo/PushLogs',
252
+ return grpc.experimental.unary_unary(
253
+ request,
254
+ target,
255
+ '/flwr.proto.SimulationIo/PushLogs',
202
256
  flwr_dot_proto_dot_log__pb2.PushLogsRequest.SerializeToString,
203
257
  flwr_dot_proto_dot_log__pb2.PushLogsResponse.FromString,
204
- options, channel_credentials,
205
- insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
258
+ options,
259
+ channel_credentials,
260
+ insecure,
261
+ call_credentials,
262
+ compression,
263
+ wait_for_ready,
264
+ timeout,
265
+ metadata,
266
+ _registered_method=True)
206
267
 
207
268
  @staticmethod
208
269
  def GetFederationOptions(request,
@@ -215,11 +276,21 @@ class SimulationIo(object):
215
276
  wait_for_ready=None,
216
277
  timeout=None,
217
278
  metadata=None):
218
- return grpc.experimental.unary_unary(request, target, '/flwr.proto.SimulationIo/GetFederationOptions',
279
+ return grpc.experimental.unary_unary(
280
+ request,
281
+ target,
282
+ '/flwr.proto.SimulationIo/GetFederationOptions',
219
283
  flwr_dot_proto_dot_run__pb2.GetFederationOptionsRequest.SerializeToString,
220
284
  flwr_dot_proto_dot_run__pb2.GetFederationOptionsResponse.FromString,
221
- options, channel_credentials,
222
- insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
285
+ options,
286
+ channel_credentials,
287
+ insecure,
288
+ call_credentials,
289
+ compression,
290
+ wait_for_ready,
291
+ timeout,
292
+ metadata,
293
+ _registered_method=True)
223
294
 
224
295
  @staticmethod
225
296
  def GetRunStatus(request,
@@ -232,8 +303,18 @@ class SimulationIo(object):
232
303
  wait_for_ready=None,
233
304
  timeout=None,
234
305
  metadata=None):
235
- return grpc.experimental.unary_unary(request, target, '/flwr.proto.SimulationIo/GetRunStatus',
306
+ return grpc.experimental.unary_unary(
307
+ request,
308
+ target,
309
+ '/flwr.proto.SimulationIo/GetRunStatus',
236
310
  flwr_dot_proto_dot_run__pb2.GetRunStatusRequest.SerializeToString,
237
311
  flwr_dot_proto_dot_run__pb2.GetRunStatusResponse.FromString,
238
- options, channel_credentials,
239
- insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
312
+ options,
313
+ channel_credentials,
314
+ insecure,
315
+ call_credentials,
316
+ compression,
317
+ wait_for_ready,
318
+ timeout,
319
+ metadata,
320
+ _registered_method=True)
flwr/proto/task_pb2.py CHANGED
@@ -1,12 +1,22 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # NO CHECKED-IN PROTOBUF GENCODE
3
4
  # source: flwr/proto/task.proto
4
- # Protobuf Python Version: 4.25.0
5
+ # Protobuf Python Version: 5.29.0
5
6
  """Generated protocol buffer code."""
6
7
  from google.protobuf import descriptor as _descriptor
7
8
  from google.protobuf import descriptor_pool as _descriptor_pool
9
+ from google.protobuf import runtime_version as _runtime_version
8
10
  from google.protobuf import symbol_database as _symbol_database
9
11
  from google.protobuf.internal import builder as _builder
12
+ _runtime_version.ValidateProtobufRuntimeVersion(
13
+ _runtime_version.Domain.PUBLIC,
14
+ 5,
15
+ 29,
16
+ 0,
17
+ '',
18
+ 'flwr/proto/task.proto'
19
+ )
10
20
  # @@protoc_insertion_point(imports)
11
21
 
12
22
  _sym_db = _symbol_database.Default()
@@ -22,8 +32,8 @@ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x66lwr/proto/
22
32
  _globals = globals()
23
33
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
24
34
  _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flwr.proto.task_pb2', _globals)
25
- if _descriptor._USE_C_DESCRIPTORS == False:
26
- DESCRIPTOR._options = None
35
+ if not _descriptor._USE_C_DESCRIPTORS:
36
+ DESCRIPTOR._loaded_options = None
27
37
  _globals['_TASK']._serialized_start=113
28
38
  _globals['_TASK']._serialized_end=378
29
39
  _globals['_TASKINS']._serialized_start=380
@@ -1,4 +1,24 @@
1
1
  # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
2
  """Client and server classes corresponding to protobuf-defined services."""
3
3
  import grpc
4
+ import warnings
4
5
 
6
+
7
+ GRPC_GENERATED_VERSION = '1.69.0'
8
+ GRPC_VERSION = grpc.__version__
9
+ _version_not_supported = False
10
+
11
+ try:
12
+ from grpc._utilities import first_version_is_lower
13
+ _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
14
+ except ImportError:
15
+ _version_not_supported = True
16
+
17
+ if _version_not_supported:
18
+ raise RuntimeError(
19
+ f'The grpc package installed is at version {GRPC_VERSION},'
20
+ + f' but the generated code in flwr/proto/task_pb2_grpc.py depends on'
21
+ + f' grpcio>={GRPC_GENERATED_VERSION}.'
22
+ + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
23
+ + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
24
+ )
@@ -1,12 +1,22 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # NO CHECKED-IN PROTOBUF GENCODE
3
4
  # source: flwr/proto/transport.proto
4
- # Protobuf Python Version: 4.25.0
5
+ # Protobuf Python Version: 5.29.0
5
6
  """Generated protocol buffer code."""
6
7
  from google.protobuf import descriptor as _descriptor
7
8
  from google.protobuf import descriptor_pool as _descriptor_pool
9
+ from google.protobuf import runtime_version as _runtime_version
8
10
  from google.protobuf import symbol_database as _symbol_database
9
11
  from google.protobuf.internal import builder as _builder
12
+ _runtime_version.ValidateProtobufRuntimeVersion(
13
+ _runtime_version.Domain.PUBLIC,
14
+ 5,
15
+ 29,
16
+ 0,
17
+ '',
18
+ 'flwr/proto/transport.proto'
19
+ )
10
20
  # @@protoc_insertion_point(imports)
11
21
 
12
22
  _sym_db = _symbol_database.Default()
@@ -19,21 +29,21 @@ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1a\x66lwr/proto/
19
29
  _globals = globals()
20
30
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
21
31
  _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flwr.proto.transport_pb2', _globals)
22
- if _descriptor._USE_C_DESCRIPTORS == False:
23
- DESCRIPTOR._options = None
24
- _globals['_SERVERMESSAGE_GETPROPERTIESINS_CONFIGENTRY']._options = None
32
+ if not _descriptor._USE_C_DESCRIPTORS:
33
+ DESCRIPTOR._loaded_options = None
34
+ _globals['_SERVERMESSAGE_GETPROPERTIESINS_CONFIGENTRY']._loaded_options = None
25
35
  _globals['_SERVERMESSAGE_GETPROPERTIESINS_CONFIGENTRY']._serialized_options = b'8\001'
26
- _globals['_SERVERMESSAGE_GETPARAMETERSINS_CONFIGENTRY']._options = None
36
+ _globals['_SERVERMESSAGE_GETPARAMETERSINS_CONFIGENTRY']._loaded_options = None
27
37
  _globals['_SERVERMESSAGE_GETPARAMETERSINS_CONFIGENTRY']._serialized_options = b'8\001'
28
- _globals['_SERVERMESSAGE_FITINS_CONFIGENTRY']._options = None
38
+ _globals['_SERVERMESSAGE_FITINS_CONFIGENTRY']._loaded_options = None
29
39
  _globals['_SERVERMESSAGE_FITINS_CONFIGENTRY']._serialized_options = b'8\001'
30
- _globals['_SERVERMESSAGE_EVALUATEINS_CONFIGENTRY']._options = None
40
+ _globals['_SERVERMESSAGE_EVALUATEINS_CONFIGENTRY']._loaded_options = None
31
41
  _globals['_SERVERMESSAGE_EVALUATEINS_CONFIGENTRY']._serialized_options = b'8\001'
32
- _globals['_CLIENTMESSAGE_GETPROPERTIESRES_PROPERTIESENTRY']._options = None
42
+ _globals['_CLIENTMESSAGE_GETPROPERTIESRES_PROPERTIESENTRY']._loaded_options = None
33
43
  _globals['_CLIENTMESSAGE_GETPROPERTIESRES_PROPERTIESENTRY']._serialized_options = b'8\001'
34
- _globals['_CLIENTMESSAGE_FITRES_METRICSENTRY']._options = None
44
+ _globals['_CLIENTMESSAGE_FITRES_METRICSENTRY']._loaded_options = None
35
45
  _globals['_CLIENTMESSAGE_FITRES_METRICSENTRY']._serialized_options = b'8\001'
36
- _globals['_CLIENTMESSAGE_EVALUATERES_METRICSENTRY']._options = None
46
+ _globals['_CLIENTMESSAGE_EVALUATERES_METRICSENTRY']._loaded_options = None
37
47
  _globals['_CLIENTMESSAGE_EVALUATERES_METRICSENTRY']._serialized_options = b'8\001'
38
48
  _globals['_CODE']._serialized_start=2551
39
49
  _globals['_CODE']._serialized_end=2692
@@ -1,9 +1,29 @@
1
1
  # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
2
  """Client and server classes corresponding to protobuf-defined services."""
3
3
  import grpc
4
+ import warnings
4
5
 
5
6
  from flwr.proto import transport_pb2 as flwr_dot_proto_dot_transport__pb2
6
7
 
8
+ GRPC_GENERATED_VERSION = '1.69.0'
9
+ GRPC_VERSION = grpc.__version__
10
+ _version_not_supported = False
11
+
12
+ try:
13
+ from grpc._utilities import first_version_is_lower
14
+ _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
15
+ except ImportError:
16
+ _version_not_supported = True
17
+
18
+ if _version_not_supported:
19
+ raise RuntimeError(
20
+ f'The grpc package installed is at version {GRPC_VERSION},'
21
+ + f' but the generated code in flwr/proto/transport_pb2_grpc.py depends on'
22
+ + f' grpcio>={GRPC_GENERATED_VERSION}.'
23
+ + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
24
+ + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
25
+ )
26
+
7
27
 
8
28
  class FlowerServiceStub(object):
9
29
  """Missing associated documentation comment in .proto file."""
@@ -18,7 +38,7 @@ class FlowerServiceStub(object):
18
38
  '/flwr.proto.FlowerService/Join',
19
39
  request_serializer=flwr_dot_proto_dot_transport__pb2.ClientMessage.SerializeToString,
20
40
  response_deserializer=flwr_dot_proto_dot_transport__pb2.ServerMessage.FromString,
21
- )
41
+ _registered_method=True)
22
42
 
23
43
 
24
44
  class FlowerServiceServicer(object):
@@ -42,6 +62,7 @@ def add_FlowerServiceServicer_to_server(servicer, server):
42
62
  generic_handler = grpc.method_handlers_generic_handler(
43
63
  'flwr.proto.FlowerService', rpc_method_handlers)
44
64
  server.add_generic_rpc_handlers((generic_handler,))
65
+ server.add_registered_method_handlers('flwr.proto.FlowerService', rpc_method_handlers)
45
66
 
46
67
 
47
68
  # This class is part of an EXPERIMENTAL API.
@@ -59,8 +80,18 @@ class FlowerService(object):
59
80
  wait_for_ready=None,
60
81
  timeout=None,
61
82
  metadata=None):
62
- return grpc.experimental.stream_stream(request_iterator, target, '/flwr.proto.FlowerService/Join',
83
+ return grpc.experimental.stream_stream(
84
+ request_iterator,
85
+ target,
86
+ '/flwr.proto.FlowerService/Join',
63
87
  flwr_dot_proto_dot_transport__pb2.ClientMessage.SerializeToString,
64
88
  flwr_dot_proto_dot_transport__pb2.ServerMessage.FromString,
65
- options, channel_credentials,
66
- insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
89
+ options,
90
+ channel_credentials,
91
+ insecure,
92
+ call_credentials,
93
+ compression,
94
+ wait_for_ready,
95
+ timeout,
96
+ metadata,
97
+ _registered_method=True)
flwr/server/app.py CHANGED
@@ -20,6 +20,7 @@ import csv
20
20
  import importlib.util
21
21
  import multiprocessing
22
22
  import multiprocessing.context
23
+ import os
23
24
  import sys
24
25
  import threading
25
26
  from collections.abc import Sequence
@@ -51,7 +52,6 @@ from flwr.common.constant import (
51
52
  FLEET_API_REST_DEFAULT_ADDRESS,
52
53
  ISOLATION_MODE_PROCESS,
53
54
  ISOLATION_MODE_SUBPROCESS,
54
- MISSING_EXTRA_REST,
55
55
  SERVER_OCTET,
56
56
  SERVERAPPIO_API_DEFAULT_SERVER_ADDRESS,
57
57
  SIMULATIONIO_API_DEFAULT_SERVER_ADDRESS,
@@ -59,6 +59,7 @@ from flwr.common.constant import (
59
59
  TRANSPORT_TYPE_GRPC_RERE,
60
60
  TRANSPORT_TYPE_REST,
61
61
  )
62
+ from flwr.common.exit import ExitCode, flwr_exit
62
63
  from flwr.common.exit_handlers import register_exit_handlers
63
64
  from flwr.common.grpc import generic_create_grpc_server
64
65
  from flwr.common.logger import log, warn_deprecated_feature
@@ -227,6 +228,13 @@ def start_server( # pylint: disable=too-many-arguments,too-many-locals
227
228
  "enabled" if certificates is not None else "disabled",
228
229
  )
229
230
 
231
+ # Graceful shutdown
232
+ register_exit_handlers(
233
+ event_type=EventType.START_SERVER_LEAVE,
234
+ exit_message="Flower server terminated gracefully.",
235
+ grpc_servers=[grpc_server],
236
+ )
237
+
230
238
  # Start training
231
239
  hist = run_fl(
232
240
  server=initialized_server,
@@ -264,10 +272,14 @@ def run_superlink() -> None:
264
272
  # Obtain certificates
265
273
  certificates = try_obtain_server_certificates(args, args.fleet_api_type)
266
274
 
275
+ # Disable the user auth TLS check if args.disable_oidc_tls_cert_verification is
276
+ # provided
277
+ verify_tls_cert = not getattr(args, "disable_oidc_tls_cert_verification", None)
278
+
267
279
  auth_plugin: Optional[ExecAuthPlugin] = None
268
280
  # Load the auth plugin if the args.user_auth_config is provided
269
281
  if cfg_path := getattr(args, "user_auth_config", None):
270
- auth_plugin = _try_obtain_exec_auth_plugin(Path(cfg_path))
282
+ auth_plugin = _try_obtain_exec_auth_plugin(Path(cfg_path), verify_tls_cert)
271
283
 
272
284
  # Initialize StateFactory
273
285
  state_factory = LinkStateFactory(args.database)
@@ -344,7 +356,7 @@ def run_superlink() -> None:
344
356
  and importlib.util.find_spec("starlette")
345
357
  and importlib.util.find_spec("uvicorn")
346
358
  ) is None:
347
- sys.exit(MISSING_EXTRA_REST)
359
+ flwr_exit(ExitCode.COMMON_MISSING_EXTRA_REST)
348
360
 
349
361
  _, ssl_certfile, ssl_keyfile = (
350
362
  certificates if certificates is not None else (None, None, None)
@@ -436,6 +448,7 @@ def run_superlink() -> None:
436
448
  # Graceful shutdown
437
449
  register_exit_handlers(
438
450
  event_type=EventType.RUN_SUPERLINK_LEAVE,
451
+ exit_message="SuperLink terminated gracefully.",
439
452
  grpc_servers=grpc_servers,
440
453
  )
441
454
 
@@ -444,10 +457,21 @@ def run_superlink() -> None:
444
457
  sleep(0.1)
445
458
 
446
459
  # Exit if any thread has exited prematurely
447
- sys.exit(1)
460
+ # This code will not be reached if the SuperLink stops gracefully
461
+ flwr_exit(ExitCode.SUPERLINK_THREAD_CRASH)
448
462
 
449
463
 
450
- def _run_flwr_command(args: list[str]) -> None:
464
+ def _run_flwr_command(args: list[str], main_pid: int) -> None:
465
+ # Monitor the main process in case of SIGKILL
466
+ def main_process_monitor() -> None:
467
+ while True:
468
+ sleep(1)
469
+ if os.getppid() != main_pid:
470
+ os.kill(os.getpid(), 9)
471
+
472
+ threading.Thread(target=main_process_monitor, daemon=True).start()
473
+
474
+ # Run the command
451
475
  sys.argv = args
452
476
  if args[0] == "flwr-serverapp":
453
477
  flwr_serverapp()
@@ -493,7 +517,7 @@ def _flwr_scheduler(
493
517
  ]
494
518
 
495
519
  proc = mp_spawn_context.Process(
496
- target=_run_flwr_command, args=(command,), daemon=True
520
+ target=_run_flwr_command, args=(command, os.getpid()), daemon=True
497
521
  )
498
522
  proc.start()
499
523
 
@@ -509,8 +533,9 @@ def _flwr_scheduler(
509
533
  def _format_address(address: str) -> tuple[str, str, int]:
510
534
  parsed_address = parse_address(address)
511
535
  if not parsed_address:
512
- sys.exit(
513
- f"Address ({address}) cannot be parsed (expected: URL or IPv4 or IPv6)."
536
+ flwr_exit(
537
+ ExitCode.COMMON_ADDRESS_INVALID,
538
+ f"Address ({address}) cannot be parsed.",
514
539
  )
515
540
  host, port, is_v6 = parsed_address
516
541
  return (f"[{host}]:{port}" if is_v6 else f"{host}:{port}", host, port)
@@ -605,7 +630,9 @@ def _try_setup_node_authentication(
605
630
  )
606
631
 
607
632
 
608
- def _try_obtain_exec_auth_plugin(config_path: Path) -> Optional[ExecAuthPlugin]:
633
+ def _try_obtain_exec_auth_plugin(
634
+ config_path: Path, verify_tls_cert: bool
635
+ ) -> Optional[ExecAuthPlugin]:
609
636
  # Load YAML file
610
637
  with config_path.open("r", encoding="utf-8") as file:
611
638
  config: dict[str, Any] = yaml.safe_load(file)
@@ -618,7 +645,9 @@ def _try_obtain_exec_auth_plugin(config_path: Path) -> Optional[ExecAuthPlugin]:
618
645
  try:
619
646
  all_plugins: dict[str, type[ExecAuthPlugin]] = get_exec_auth_plugins()
620
647
  auth_plugin_class = all_plugins[auth_type]
621
- return auth_plugin_class(user_auth_config_path=config_path)
648
+ return auth_plugin_class(
649
+ user_auth_config_path=config_path, verify_tls_cert=verify_tls_cert
650
+ )
622
651
  except KeyError:
623
652
  if auth_type != "":
624
653
  sys.exit(
@@ -701,7 +730,7 @@ def _run_fleet_api_rest(
701
730
 
702
731
  from flwr.server.superlink.fleet.rest_rere.rest_api import app as fast_api_app
703
732
  except ModuleNotFoundError:
704
- sys.exit(MISSING_EXTRA_REST)
733
+ flwr_exit(ExitCode.COMMON_MISSING_EXTRA_REST)
705
734
 
706
735
  log(INFO, "Starting Flower REST server")
707
736
 
@@ -95,7 +95,6 @@ def _update_client_manager(
95
95
  client_proxy = DriverClientProxy(
96
96
  node_id=node_id,
97
97
  driver=driver,
98
- anonymous=False,
99
98
  run_id=driver.run.run_id,
100
99
  )
101
100
  if client_manager.register(client_proxy):
@@ -28,12 +28,11 @@ from ..driver.driver import Driver
28
28
  class DriverClientProxy(ClientProxy):
29
29
  """Flower client proxy which delegates work using the Driver API."""
30
30
 
31
- def __init__(self, node_id: int, driver: Driver, anonymous: bool, run_id: int):
31
+ def __init__(self, node_id: int, driver: Driver, run_id: int):
32
32
  super().__init__(str(node_id))
33
33
  self.node_id = node_id
34
34
  self.driver = driver
35
35
  self.run_id = run_id
36
- self.anonymous = anonymous
37
36
 
38
37
  def get_properties(
39
38
  self,
@@ -24,7 +24,10 @@ from typing import Optional, cast
24
24
  import grpc
25
25
 
26
26
  from flwr.common import DEFAULT_TTL, Message, Metadata, RecordSet
27
- from flwr.common.constant import SERVERAPPIO_API_DEFAULT_CLIENT_ADDRESS
27
+ from flwr.common.constant import (
28
+ SERVERAPPIO_API_DEFAULT_CLIENT_ADDRESS,
29
+ SUPERLINK_NODE_ID,
30
+ )
28
31
  from flwr.common.grpc import create_channel
29
32
  from flwr.common.logger import log
30
33
  from flwr.common.retry_invoker import _make_simple_grpc_retry_invoker, _wrap_stub
@@ -76,7 +79,7 @@ class GrpcDriver(Driver):
76
79
  self._run: Optional[Run] = None
77
80
  self._grpc_stub: Optional[ServerAppIoStub] = None
78
81
  self._channel: Optional[grpc.Channel] = None
79
- self.node = Node(node_id=0, anonymous=True)
82
+ self.node = Node(node_id=SUPERLINK_NODE_ID)
80
83
  self._retry_invoker = _make_simple_grpc_retry_invoker()
81
84
 
82
85
  @property
@@ -22,6 +22,7 @@ from typing import Optional, cast
22
22
  from uuid import UUID
23
23
 
24
24
  from flwr.common import DEFAULT_TTL, Message, Metadata, RecordSet
25
+ from flwr.common.constant import SUPERLINK_NODE_ID
25
26
  from flwr.common.serde import message_from_taskres, message_to_taskins
26
27
  from flwr.common.typing import Run
27
28
  from flwr.proto.node_pb2 import Node # pylint: disable=E0611
@@ -49,7 +50,7 @@ class InMemoryDriver(Driver):
49
50
  self._run: Optional[Run] = None
50
51
  self.state = state_factory.state()
51
52
  self.pull_interval = pull_interval
52
- self.node = Node(node_id=0, anonymous=True)
53
+ self.node = Node(node_id=SUPERLINK_NODE_ID)
53
54
 
54
55
  def _check_message(self, message: Message) -> None:
55
56
  # Check if the message is valid
@@ -16,7 +16,6 @@
16
16
 
17
17
 
18
18
  import argparse
19
- import sys
20
19
  from logging import DEBUG, ERROR, INFO
21
20
  from pathlib import Path
22
21
  from queue import Queue
@@ -38,6 +37,7 @@ from flwr.common.constant import (
38
37
  Status,
39
38
  SubStatus,
40
39
  )
40
+ from flwr.common.exit import ExitCode, flwr_exit
41
41
  from flwr.common.logger import (
42
42
  log,
43
43
  mirror_output_to_queue,
@@ -75,12 +75,10 @@ def flwr_serverapp() -> None:
75
75
  log(INFO, "Starting Flower ServerApp")
76
76
 
77
77
  if not args.insecure:
78
- log(
79
- ERROR,
80
- "`flwr-serverapp` does not support TLS yet. "
81
- "Please use the '--insecure' flag.",
78
+ flwr_exit(
79
+ ExitCode.COMMON_TLS_NOT_SUPPORTED,
80
+ "`flwr-serverapp` does not support TLS yet.",
82
81
  )
83
- sys.exit(1)
84
82
 
85
83
  log(
86
84
  DEBUG,
@@ -117,6 +115,7 @@ def run_serverapp( # pylint: disable=R0914, disable=W0212, disable=R0915
117
115
  log_uploader = None
118
116
  success = True
119
117
  hash_run_id = None
118
+ run_status = None
120
119
  while True:
121
120
 
122
121
  try: