flwr-nightly 1.15.0.dev20250104__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 (98) hide show
  1. flwr/cli/cli_user_auth_interceptor.py +6 -2
  2. flwr/cli/config_utils.py +23 -146
  3. flwr/cli/constant.py +27 -0
  4. flwr/cli/install.py +1 -1
  5. flwr/cli/log.py +17 -2
  6. flwr/cli/login/login.py +20 -5
  7. flwr/cli/ls.py +10 -2
  8. flwr/cli/run/run.py +20 -10
  9. flwr/cli/stop.py +9 -1
  10. flwr/cli/utils.py +4 -4
  11. flwr/client/app.py +36 -48
  12. flwr/client/clientapp/app.py +4 -6
  13. flwr/client/clientapp/utils.py +1 -1
  14. flwr/client/grpc_client/connection.py +0 -6
  15. flwr/client/grpc_rere_client/client_interceptor.py +19 -119
  16. flwr/client/grpc_rere_client/connection.py +34 -24
  17. flwr/client/grpc_rere_client/grpc_adapter.py +16 -0
  18. flwr/client/rest_client/connection.py +34 -26
  19. flwr/client/supernode/app.py +14 -20
  20. flwr/common/auth_plugin/auth_plugin.py +34 -23
  21. flwr/common/config.py +152 -15
  22. flwr/common/constant.py +11 -8
  23. flwr/common/exit/__init__.py +24 -0
  24. flwr/common/exit/exit.py +99 -0
  25. flwr/common/exit/exit_code.py +93 -0
  26. flwr/common/exit_handlers.py +24 -10
  27. flwr/common/grpc.py +161 -3
  28. flwr/common/logger.py +1 -1
  29. flwr/common/secure_aggregation/crypto/symmetric_encryption.py +45 -0
  30. flwr/common/serde.py +6 -4
  31. flwr/common/typing.py +20 -0
  32. flwr/proto/clientappio_pb2.py +13 -3
  33. flwr/proto/clientappio_pb2_grpc.py +63 -12
  34. flwr/proto/error_pb2.py +13 -3
  35. flwr/proto/error_pb2_grpc.py +20 -0
  36. flwr/proto/exec_pb2.py +27 -29
  37. flwr/proto/exec_pb2.pyi +27 -54
  38. flwr/proto/exec_pb2_grpc.py +105 -24
  39. flwr/proto/fab_pb2.py +13 -3
  40. flwr/proto/fab_pb2_grpc.py +20 -0
  41. flwr/proto/fleet_pb2.py +54 -31
  42. flwr/proto/fleet_pb2.pyi +84 -0
  43. flwr/proto/fleet_pb2_grpc.py +207 -28
  44. flwr/proto/fleet_pb2_grpc.pyi +26 -0
  45. flwr/proto/grpcadapter_pb2.py +14 -4
  46. flwr/proto/grpcadapter_pb2_grpc.py +35 -4
  47. flwr/proto/log_pb2.py +13 -3
  48. flwr/proto/log_pb2_grpc.py +20 -0
  49. flwr/proto/message_pb2.py +15 -5
  50. flwr/proto/message_pb2_grpc.py +20 -0
  51. flwr/proto/node_pb2.py +15 -5
  52. flwr/proto/node_pb2.pyi +1 -4
  53. flwr/proto/node_pb2_grpc.py +20 -0
  54. flwr/proto/recordset_pb2.py +18 -8
  55. flwr/proto/recordset_pb2_grpc.py +20 -0
  56. flwr/proto/run_pb2.py +16 -6
  57. flwr/proto/run_pb2_grpc.py +20 -0
  58. flwr/proto/serverappio_pb2.py +32 -14
  59. flwr/proto/serverappio_pb2.pyi +56 -0
  60. flwr/proto/serverappio_pb2_grpc.py +261 -44
  61. flwr/proto/serverappio_pb2_grpc.pyi +20 -0
  62. flwr/proto/simulationio_pb2.py +13 -3
  63. flwr/proto/simulationio_pb2_grpc.py +105 -24
  64. flwr/proto/task_pb2.py +13 -3
  65. flwr/proto/task_pb2_grpc.py +20 -0
  66. flwr/proto/transport_pb2.py +20 -10
  67. flwr/proto/transport_pb2_grpc.py +35 -4
  68. flwr/server/app.py +87 -38
  69. flwr/server/compat/app_utils.py +0 -1
  70. flwr/server/compat/driver_client_proxy.py +1 -2
  71. flwr/server/driver/grpc_driver.py +5 -2
  72. flwr/server/driver/inmemory_driver.py +2 -1
  73. flwr/server/serverapp/app.py +5 -6
  74. flwr/server/superlink/driver/serverappio_grpc.py +1 -1
  75. flwr/server/superlink/driver/serverappio_servicer.py +132 -14
  76. flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +20 -88
  77. flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +2 -165
  78. flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +38 -0
  79. flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +95 -168
  80. flwr/server/superlink/fleet/message_handler/message_handler.py +66 -5
  81. flwr/server/superlink/fleet/rest_rere/rest_api.py +28 -3
  82. flwr/server/superlink/fleet/vce/vce_api.py +2 -2
  83. flwr/server/superlink/linkstate/in_memory_linkstate.py +40 -48
  84. flwr/server/superlink/linkstate/linkstate.py +15 -22
  85. flwr/server/superlink/linkstate/sqlite_linkstate.py +80 -99
  86. flwr/server/superlink/linkstate/utils.py +18 -8
  87. flwr/server/superlink/simulation/simulationio_grpc.py +1 -1
  88. flwr/server/utils/validator.py +9 -34
  89. flwr/simulation/app.py +4 -6
  90. flwr/simulation/legacy_app.py +4 -2
  91. flwr/simulation/run_simulation.py +1 -1
  92. flwr/superexec/exec_grpc.py +1 -1
  93. flwr/superexec/exec_servicer.py +23 -2
  94. {flwr_nightly-1.15.0.dev20250104.dist-info → flwr_nightly-1.15.0.dev20250123.dist-info}/METADATA +7 -7
  95. {flwr_nightly-1.15.0.dev20250104.dist-info → flwr_nightly-1.15.0.dev20250123.dist-info}/RECORD +98 -94
  96. {flwr_nightly-1.15.0.dev20250104.dist-info → flwr_nightly-1.15.0.dev20250123.dist-info}/LICENSE +0 -0
  97. {flwr_nightly-1.15.0.dev20250104.dist-info → flwr_nightly-1.15.0.dev20250123.dist-info}/WHEEL +0 -0
  98. {flwr_nightly-1.15.0.dev20250104.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
@@ -18,7 +18,9 @@
18
18
  import argparse
19
19
  import csv
20
20
  import importlib.util
21
- import subprocess
21
+ import multiprocessing
22
+ import multiprocessing.context
23
+ import os
22
24
  import sys
23
25
  import threading
24
26
  from collections.abc import Sequence
@@ -50,7 +52,6 @@ from flwr.common.constant import (
50
52
  FLEET_API_REST_DEFAULT_ADDRESS,
51
53
  ISOLATION_MODE_PROCESS,
52
54
  ISOLATION_MODE_SUBPROCESS,
53
- MISSING_EXTRA_REST,
54
55
  SERVER_OCTET,
55
56
  SERVERAPPIO_API_DEFAULT_SERVER_ADDRESS,
56
57
  SIMULATIONIO_API_DEFAULT_SERVER_ADDRESS,
@@ -58,7 +59,9 @@ from flwr.common.constant import (
58
59
  TRANSPORT_TYPE_GRPC_RERE,
59
60
  TRANSPORT_TYPE_REST,
60
61
  )
62
+ from flwr.common.exit import ExitCode, flwr_exit
61
63
  from flwr.common.exit_handlers import register_exit_handlers
64
+ from flwr.common.grpc import generic_create_grpc_server
62
65
  from flwr.common.logger import log, warn_deprecated_feature
63
66
  from flwr.common.secure_aggregation.crypto.symmetric_encryption import (
64
67
  private_key_to_bytes,
@@ -68,6 +71,8 @@ from flwr.proto.fleet_pb2_grpc import ( # pylint: disable=E0611
68
71
  add_FleetServicer_to_server,
69
72
  )
70
73
  from flwr.proto.grpcadapter_pb2_grpc import add_GrpcAdapterServicer_to_server
74
+ from flwr.server.serverapp.app import flwr_serverapp
75
+ from flwr.simulation.app import flwr_simulation
71
76
  from flwr.superexec.app import load_executor
72
77
  from flwr.superexec.exec_grpc import run_exec_api_grpc
73
78
 
@@ -79,10 +84,7 @@ from .strategy import Strategy
79
84
  from .superlink.driver.serverappio_grpc import run_serverappio_api_grpc
80
85
  from .superlink.ffs.ffs_factory import FfsFactory
81
86
  from .superlink.fleet.grpc_adapter.grpc_adapter_servicer import GrpcAdapterServicer
82
- from .superlink.fleet.grpc_bidi.grpc_server import (
83
- generic_create_grpc_server,
84
- start_grpc_server,
85
- )
87
+ from .superlink.fleet.grpc_bidi.grpc_server import start_grpc_server
86
88
  from .superlink.fleet.grpc_rere.fleet_servicer import FleetServicer
87
89
  from .superlink.fleet.grpc_rere.server_interceptor import AuthenticateServerInterceptor
88
90
  from .superlink.linkstate import LinkStateFactory
@@ -226,6 +228,13 @@ def start_server( # pylint: disable=too-many-arguments,too-many-locals
226
228
  "enabled" if certificates is not None else "disabled",
227
229
  )
228
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
+
229
238
  # Start training
230
239
  hist = run_fl(
231
240
  server=initialized_server,
@@ -263,11 +272,14 @@ def run_superlink() -> None:
263
272
  # Obtain certificates
264
273
  certificates = try_obtain_server_certificates(args, args.fleet_api_type)
265
274
 
266
- user_auth_config = _try_obtain_user_auth_config(args)
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
- # user_auth_config is None only if the args.user_auth_config is not provided
269
- if user_auth_config is not None:
270
- auth_plugin = _try_obtain_exec_auth_plugin(user_auth_config)
280
+ # Load the auth plugin if the args.user_auth_config is provided
281
+ if cfg_path := getattr(args, "user_auth_config", None):
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)
@@ -293,7 +305,7 @@ def run_superlink() -> None:
293
305
  # Determine Exec plugin
294
306
  # If simulation is used, don't start ServerAppIo and Fleet APIs
295
307
  sim_exec = executor.__class__.__qualname__ == "SimulationEngine"
296
- bckg_threads = []
308
+ bckg_threads: list[threading.Thread] = []
297
309
 
298
310
  if sim_exec:
299
311
  simulationio_server: grpc.Server = run_simulationio_api_grpc(
@@ -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)
@@ -361,6 +373,7 @@ def run_superlink() -> None:
361
373
  ffs_factory,
362
374
  num_workers,
363
375
  ),
376
+ daemon=True,
364
377
  )
365
378
  fleet_thread.start()
366
379
  bckg_threads.append(fleet_thread)
@@ -427,6 +440,7 @@ def run_superlink() -> None:
427
440
  address,
428
441
  cmd,
429
442
  ),
443
+ daemon=True,
430
444
  )
431
445
  scheduler_th.start()
432
446
  bckg_threads.append(scheduler_th)
@@ -434,17 +448,37 @@ def run_superlink() -> None:
434
448
  # Graceful shutdown
435
449
  register_exit_handlers(
436
450
  event_type=EventType.RUN_SUPERLINK_LEAVE,
451
+ exit_message="SuperLink terminated gracefully.",
437
452
  grpc_servers=grpc_servers,
438
- bckg_threads=bckg_threads,
439
453
  )
440
454
 
441
- # Block
442
- while True:
443
- if bckg_threads:
444
- for thread in bckg_threads:
445
- if not thread.is_alive():
446
- sys.exit(1)
447
- exec_server.wait_for_termination(timeout=1)
455
+ # Block until a thread exits prematurely
456
+ while all(thread.is_alive() for thread in bckg_threads):
457
+ sleep(0.1)
458
+
459
+ # Exit if any thread has exited prematurely
460
+ # This code will not be reached if the SuperLink stops gracefully
461
+ flwr_exit(ExitCode.SUPERLINK_THREAD_CRASH)
462
+
463
+
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
475
+ sys.argv = args
476
+ if args[0] == "flwr-serverapp":
477
+ flwr_serverapp()
478
+ elif args[0] == "flwr-simulation":
479
+ flwr_simulation()
480
+ else:
481
+ raise ValueError(f"Unknown command: {args[0]}")
448
482
 
449
483
 
450
484
  def _flwr_scheduler(
@@ -454,15 +488,18 @@ def _flwr_scheduler(
454
488
  cmd: str,
455
489
  ) -> None:
456
490
  log(DEBUG, "Started %s scheduler thread.", cmd)
457
-
458
491
  state = state_factory.state()
492
+ run_id_to_proc: dict[int, multiprocessing.context.SpawnProcess] = {}
493
+
494
+ # Use the "spawn" start method for multiprocessing.
495
+ mp_spawn_context = multiprocessing.get_context("spawn")
459
496
 
460
497
  # Periodically check for a pending run in the LinkState
461
498
  while True:
462
- sleep(3)
499
+ sleep(0.1)
463
500
  pending_run_id = state.get_pending_run_id()
464
501
 
465
- if pending_run_id:
502
+ if pending_run_id and pending_run_id not in run_id_to_proc:
466
503
 
467
504
  log(
468
505
  INFO,
@@ -479,17 +516,26 @@ def _flwr_scheduler(
479
516
  "--insecure",
480
517
  ]
481
518
 
482
- subprocess.Popen( # pylint: disable=consider-using-with
483
- command,
484
- text=True,
519
+ proc = mp_spawn_context.Process(
520
+ target=_run_flwr_command, args=(command, os.getpid()), daemon=True
485
521
  )
522
+ proc.start()
523
+
524
+ # Store the process
525
+ run_id_to_proc[pending_run_id] = proc
526
+
527
+ # Clean up finished processes
528
+ for run_id, proc in list(run_id_to_proc.items()):
529
+ if not proc.is_alive():
530
+ del run_id_to_proc[run_id]
486
531
 
487
532
 
488
533
  def _format_address(address: str) -> tuple[str, str, int]:
489
534
  parsed_address = parse_address(address)
490
535
  if not parsed_address:
491
- sys.exit(
492
- 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.",
493
539
  )
494
540
  host, port, is_v6 = parsed_address
495
541
  return (f"[{host}]:{port}" if is_v6 else f"{host}:{port}", host, port)
@@ -584,21 +630,24 @@ def _try_setup_node_authentication(
584
630
  )
585
631
 
586
632
 
587
- def _try_obtain_user_auth_config(args: argparse.Namespace) -> Optional[dict[str, Any]]:
588
- if getattr(args, "user_auth_config", None) is not None:
589
- with open(args.user_auth_config, encoding="utf-8") as file:
590
- config: dict[str, Any] = yaml.safe_load(file)
591
- return config
592
- return None
593
-
633
+ def _try_obtain_exec_auth_plugin(
634
+ config_path: Path, verify_tls_cert: bool
635
+ ) -> Optional[ExecAuthPlugin]:
636
+ # Load YAML file
637
+ with config_path.open("r", encoding="utf-8") as file:
638
+ config: dict[str, Any] = yaml.safe_load(file)
594
639
 
595
- def _try_obtain_exec_auth_plugin(config: dict[str, Any]) -> Optional[ExecAuthPlugin]:
640
+ # Load authentication configuration
596
641
  auth_config: dict[str, Any] = config.get("authentication", {})
597
642
  auth_type: str = auth_config.get(AUTH_TYPE, "")
643
+
644
+ # Load authentication plugin
598
645
  try:
599
646
  all_plugins: dict[str, type[ExecAuthPlugin]] = get_exec_auth_plugins()
600
647
  auth_plugin_class = all_plugins[auth_type]
601
- return auth_plugin_class(config=auth_config)
648
+ return auth_plugin_class(
649
+ user_auth_config_path=config_path, verify_tls_cert=verify_tls_cert
650
+ )
602
651
  except KeyError:
603
652
  if auth_type != "":
604
653
  sys.exit(
@@ -681,7 +730,7 @@ def _run_fleet_api_rest(
681
730
 
682
731
  from flwr.server.superlink.fleet.rest_rere.rest_api import app as fast_api_app
683
732
  except ModuleNotFoundError:
684
- sys.exit(MISSING_EXTRA_REST)
733
+ flwr_exit(ExitCode.COMMON_MISSING_EXTRA_REST)
685
734
 
686
735
  log(INFO, "Starting Flower REST server")
687
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):