flwr-nightly 1.19.0.dev20250529__py3-none-any.whl → 1.19.0.dev20250530__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.
@@ -19,7 +19,7 @@ from typing import Optional
19
19
 
20
20
  from flwr.common.inflatable import get_object_id, is_valid_sha256_hash
21
21
 
22
- from .object_store import ObjectStore
22
+ from .object_store import NoObjectInStoreError, ObjectStore
23
23
 
24
24
 
25
25
  class InMemoryObjectStore(ObjectStore):
@@ -48,7 +48,9 @@ class InMemoryObjectStore(ObjectStore):
48
48
  """Put an object into the store."""
49
49
  # Only allow adding the object if it has been preregistered
50
50
  if object_id not in self.store:
51
- raise KeyError(f"Object with id {object_id} was not preregistered.")
51
+ raise NoObjectInStoreError(
52
+ f"Object with ID '{object_id}' was not pre-registered."
53
+ )
52
54
 
53
55
  # Verify object_id and object_content match
54
56
  if self.verify:
@@ -71,6 +73,11 @@ class InMemoryObjectStore(ObjectStore):
71
73
 
72
74
  def get_message_descendant_ids(self, msg_object_id: str) -> list[str]:
73
75
  """Retrieve the object IDs of all descendants of a given Message."""
76
+ if msg_object_id not in self.msg_children_objects_mapping:
77
+ raise NoObjectInStoreError(
78
+ f"No message registered in Object Store with ID '{msg_object_id}'. "
79
+ "Mapping to descendants could not be found."
80
+ )
74
81
  return self.msg_children_objects_mapping[msg_object_id]
75
82
 
76
83
  def get(self, object_id: str) -> Optional[bytes]:
@@ -19,6 +19,18 @@ import abc
19
19
  from typing import Optional
20
20
 
21
21
 
22
+ class NoObjectInStoreError(Exception):
23
+ """Error when trying to access an element in the ObjectStore that does not exist."""
24
+
25
+ def __init__(self, message: str):
26
+ super().__init__(message)
27
+ self.message = message
28
+
29
+ def __str__(self) -> str:
30
+ """Return formatted exception message string."""
31
+ return f"NoObjectInStoreError: {self.message}"
32
+
33
+
22
34
  class ObjectStore(abc.ABC):
23
35
  """Abstract base class for `ObjectStore` implementations.
24
36
 
@@ -21,7 +21,7 @@ from typing import Optional
21
21
  import grpc
22
22
 
23
23
  from flwr.common import GRPC_MAX_MESSAGE_LENGTH
24
- from flwr.common.auth_plugin import ExecAuthPlugin
24
+ from flwr.common.auth_plugin import ExecAuthPlugin, ExecAuthzPlugin
25
25
  from flwr.common.event_log_plugin import EventLogWriterPlugin
26
26
  from flwr.common.grpc import generic_create_grpc_server
27
27
  from flwr.common.logger import log
@@ -45,6 +45,7 @@ def run_exec_api_grpc(
45
45
  certificates: Optional[tuple[bytes, bytes, bytes]],
46
46
  config: UserConfig,
47
47
  auth_plugin: Optional[ExecAuthPlugin] = None,
48
+ authz_plugin: Optional[ExecAuthzPlugin] = None,
48
49
  event_log_plugin: Optional[EventLogWriterPlugin] = None,
49
50
  ) -> grpc.Server:
50
51
  """Run Exec API (gRPC, request-response)."""
@@ -57,8 +58,8 @@ def run_exec_api_grpc(
57
58
  auth_plugin=auth_plugin,
58
59
  )
59
60
  interceptors: list[grpc.ServerInterceptor] = []
60
- if auth_plugin is not None:
61
- interceptors.append(ExecUserAuthInterceptor(auth_plugin))
61
+ if auth_plugin is not None and authz_plugin is not None:
62
+ interceptors.append(ExecUserAuthInterceptor(auth_plugin, authz_plugin))
62
63
  # Event log interceptor must be added after user auth interceptor
63
64
  if event_log_plugin is not None:
64
65
  interceptors.append(ExecEventLogInterceptor(event_log_plugin))
@@ -16,11 +16,11 @@
16
16
 
17
17
 
18
18
  import contextvars
19
- from typing import Any, Callable, Union, cast
19
+ from typing import Any, Callable, Union
20
20
 
21
21
  import grpc
22
22
 
23
- from flwr.common.auth_plugin import ExecAuthPlugin
23
+ from flwr.common.auth_plugin import ExecAuthPlugin, ExecAuthzPlugin
24
24
  from flwr.common.typing import UserInfo
25
25
  from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
26
26
  GetAuthTokensRequest,
@@ -56,8 +56,10 @@ class ExecUserAuthInterceptor(grpc.ServerInterceptor): # type: ignore
56
56
  def __init__(
57
57
  self,
58
58
  auth_plugin: ExecAuthPlugin,
59
+ authz_plugin: ExecAuthzPlugin,
59
60
  ):
60
61
  self.auth_plugin = auth_plugin
62
+ self.authz_plugin = authz_plugin
61
63
 
62
64
  def intercept_service(
63
65
  self,
@@ -95,13 +97,40 @@ class ExecUserAuthInterceptor(grpc.ServerInterceptor): # type: ignore
95
97
  metadata
96
98
  )
97
99
  if valid_tokens:
100
+ if user_info is None:
101
+ context.abort(
102
+ grpc.StatusCode.UNAUTHENTICATED,
103
+ "Tokens validated, but user info not found",
104
+ )
105
+ raise grpc.RpcError()
98
106
  # Store user info in contextvars for authenticated users
99
- shared_user_info.set(cast(UserInfo, user_info))
107
+ shared_user_info.set(user_info)
108
+ # Check if the user is authorized
109
+ if not self.authz_plugin.verify_user_authorization(user_info):
110
+ context.abort(
111
+ grpc.StatusCode.PERMISSION_DENIED, "User not authorized"
112
+ )
113
+ raise grpc.RpcError()
100
114
  return call(request, context) # type: ignore
101
115
 
102
116
  # If the user is not authenticated, refresh tokens
103
- tokens = self.auth_plugin.refresh_tokens(context.invocation_metadata())
117
+ tokens, user_info = self.auth_plugin.refresh_tokens(metadata)
104
118
  if tokens is not None:
119
+ if user_info is None:
120
+ context.abort(
121
+ grpc.StatusCode.UNAUTHENTICATED,
122
+ "Tokens refreshed, but user info not found",
123
+ )
124
+ raise grpc.RpcError()
125
+ # Store user info in contextvars for authenticated users
126
+ shared_user_info.set(user_info)
127
+ # Check if the user is authorized
128
+ if not self.authz_plugin.verify_user_authorization(user_info):
129
+ context.abort(
130
+ grpc.StatusCode.PERMISSION_DENIED, "User not authorized"
131
+ )
132
+ raise grpc.RpcError()
133
+
105
134
  context.send_initial_metadata(tokens)
106
135
  return call(request, context) # type: ignore
107
136
 
@@ -40,7 +40,6 @@ from flwr.client.clientapp.clientappio_servicer import (
40
40
  )
41
41
  from flwr.client.grpc_adapter_client.connection import grpc_adapter
42
42
  from flwr.client.grpc_rere_client.connection import grpc_request_response
43
- from flwr.client.message_handler.message_handler import handle_control_message
44
43
  from flwr.client.run_info_store import DeprecatedRunInfoStore
45
44
  from flwr.common import GRPC_MAX_MESSAGE_LENGTH, Message
46
45
  from flwr.common.address import parse_address
@@ -151,186 +150,161 @@ def start_client_internal(
151
150
 
152
151
  runs: dict[int, Run] = {}
153
152
 
154
- while True:
155
- sleep_duration: int = 0
156
- with _init_connection(
157
- transport=transport,
158
- server_address=server_address,
159
- insecure=insecure,
160
- root_certificates=root_certificates,
161
- authentication_keys=authentication_keys,
162
- max_retries=max_retries,
163
- max_wait_time=max_wait_time,
164
- ) as conn:
165
- receive, send, create_node, delete_node, get_run, get_fab = conn
166
-
167
- # Register node when connecting the first time
168
- if run_info_store is None:
169
- # Call create_node fn to register node
170
- # and store node_id in state
171
- if (node_id := create_node()) is None:
172
- raise ValueError("Failed to register SuperNode with the SuperLink")
173
- state.set_node_id(node_id)
174
- run_info_store = DeprecatedRunInfoStore(
175
- node_id=state.get_node_id(),
176
- node_config=node_config,
177
- )
153
+ with _init_connection(
154
+ transport=transport,
155
+ server_address=server_address,
156
+ insecure=insecure,
157
+ root_certificates=root_certificates,
158
+ authentication_keys=authentication_keys,
159
+ max_retries=max_retries,
160
+ max_wait_time=max_wait_time,
161
+ ) as conn:
162
+ receive, send, create_node, _, get_run, get_fab = conn
163
+
164
+ # Register node when connecting the first time
165
+ if run_info_store is None:
166
+ # Call create_node fn to register node
167
+ # and store node_id in state
168
+ if (node_id := create_node()) is None:
169
+ raise ValueError("Failed to register SuperNode with the SuperLink")
170
+ state.set_node_id(node_id)
171
+ run_info_store = DeprecatedRunInfoStore(
172
+ node_id=state.get_node_id(),
173
+ node_config=node_config,
174
+ )
178
175
 
179
- # pylint: disable=too-many-nested-blocks
180
- while True:
181
- try:
182
- # Receive
183
- message = receive()
184
- if message is None:
185
- time.sleep(3) # Wait for 3s before asking again
186
- continue
187
-
188
- log(INFO, "")
189
- if len(message.metadata.group_id) > 0:
190
- log(
191
- INFO,
192
- "[RUN %s, ROUND %s]",
193
- message.metadata.run_id,
194
- message.metadata.group_id,
195
- )
176
+ # pylint: disable=too-many-nested-blocks
177
+ while True:
178
+ try:
179
+ # Receive
180
+ message = receive()
181
+ if message is None:
182
+ time.sleep(3) # Wait for 3s before asking again
183
+ continue
184
+
185
+ log(INFO, "")
186
+ if len(message.metadata.group_id) > 0:
196
187
  log(
197
188
  INFO,
198
- "Received: %s message %s",
199
- message.metadata.message_type,
200
- message.metadata.message_id,
189
+ "[RUN %s, ROUND %s]",
190
+ message.metadata.run_id,
191
+ message.metadata.group_id,
201
192
  )
193
+ log(
194
+ INFO,
195
+ "Received: %s message %s",
196
+ message.metadata.message_type,
197
+ message.metadata.message_id,
198
+ )
202
199
 
203
- # Handle control message
204
- out_message, sleep_duration = handle_control_message(message)
205
- if out_message:
206
- send(out_message)
207
- break
208
-
209
- # Get run info
210
- run_id = message.metadata.run_id
211
- if run_id not in runs:
212
- runs[run_id] = get_run(run_id)
213
-
214
- run: Run = runs[run_id]
215
- if get_fab is not None and run.fab_hash:
216
- fab = get_fab(run.fab_hash, run_id)
217
- fab_id, fab_version = get_fab_metadata(fab.content)
218
- else:
219
- fab = None
220
- fab_id, fab_version = run.fab_id, run.fab_version
221
-
222
- run.fab_id, run.fab_version = fab_id, fab_version
223
-
224
- # Register context for this run
225
- run_info_store.register_context(
226
- run_id=run_id,
227
- run=run,
228
- flwr_path=flwr_path,
229
- fab=fab,
230
- )
200
+ # Get run info
201
+ run_id = message.metadata.run_id
202
+ if run_id not in runs:
203
+ runs[run_id] = get_run(run_id)
204
+
205
+ run: Run = runs[run_id]
206
+ if get_fab is not None and run.fab_hash:
207
+ fab = get_fab(run.fab_hash, run_id)
208
+ fab_id, fab_version = get_fab_metadata(fab.content)
209
+ else:
210
+ fab = None
211
+ fab_id, fab_version = run.fab_id, run.fab_version
212
+
213
+ run.fab_id, run.fab_version = fab_id, fab_version
214
+
215
+ # Register context for this run
216
+ run_info_store.register_context(
217
+ run_id=run_id,
218
+ run=run,
219
+ flwr_path=flwr_path,
220
+ fab=fab,
221
+ )
231
222
 
232
- # Retrieve context for this run
233
- context = run_info_store.retrieve_context(run_id=run_id)
234
- # Create an error reply message that will never be used to prevent
235
- # the used-before-assignment linting error
236
- reply_message = Message(
237
- Error(code=ErrorCode.UNKNOWN, reason="Unknown"),
238
- reply_to=message,
239
- )
223
+ # Retrieve context for this run
224
+ context = run_info_store.retrieve_context(run_id=run_id)
225
+ # Create an error reply message that will never be used to prevent
226
+ # the used-before-assignment linting error
227
+ reply_message = Message(
228
+ Error(code=ErrorCode.UNKNOWN, reason="Unknown"),
229
+ reply_to=message,
230
+ )
240
231
 
241
- # Two isolation modes:
242
- # 1. `subprocess`: SuperNode is starting the ClientApp
243
- # process as a subprocess.
244
- # 2. `process`: ClientApp process gets started separately
245
- # (via `flwr-clientapp`), for example, in a separate
246
- # Docker container.
247
-
248
- # Generate SuperNode token
249
- token = int.from_bytes(urandom(RUN_ID_NUM_BYTES), "little")
250
-
251
- # Mode 1: SuperNode starts ClientApp as subprocess
252
- start_subprocess = isolation == ISOLATION_MODE_SUBPROCESS
253
-
254
- # Share Message and Context with servicer
255
- clientappio_servicer.set_inputs(
256
- clientapp_input=ClientAppInputs(
257
- message=message,
258
- context=context,
259
- run=run,
260
- fab=fab,
261
- token=token,
262
- ),
263
- token_returned=start_subprocess,
264
- )
232
+ # Two isolation modes:
233
+ # 1. `subprocess`: SuperNode is starting the ClientApp
234
+ # process as a subprocess.
235
+ # 2. `process`: ClientApp process gets started separately
236
+ # (via `flwr-clientapp`), for example, in a separate
237
+ # Docker container.
265
238
 
266
- if start_subprocess:
267
- _octet, _colon, _port = clientappio_api_address.rpartition(":")
268
- io_address = (
269
- f"{CLIENT_OCTET}:{_port}"
270
- if _octet == SERVER_OCTET
271
- else clientappio_api_address
272
- )
273
- # Start ClientApp subprocess
274
- command = [
275
- "flwr-clientapp",
276
- "--clientappio-api-address",
277
- io_address,
278
- "--token",
279
- str(token),
280
- ]
281
- command.append("--insecure")
282
-
283
- proc = mp_spawn_context.Process(
284
- target=_run_flwr_clientapp,
285
- args=(command, os.getpid()),
286
- daemon=True,
287
- )
288
- proc.start()
289
- proc.join()
290
- else:
291
- # Wait for output to become available
292
- while not clientappio_servicer.has_outputs():
293
- time.sleep(0.1)
294
-
295
- outputs = clientappio_servicer.get_outputs()
296
- reply_message, context = outputs.message, outputs.context
297
-
298
- # Update node state
299
- run_info_store.update_context(
300
- run_id=run_id,
301
- context=context,
302
- )
239
+ # Generate SuperNode token
240
+ token = int.from_bytes(urandom(RUN_ID_NUM_BYTES), "little")
303
241
 
304
- # Send
305
- send(reply_message)
306
- log(INFO, "Sent reply")
242
+ # Mode 1: SuperNode starts ClientApp as subprocess
243
+ start_subprocess = isolation == ISOLATION_MODE_SUBPROCESS
307
244
 
308
- except RunNotRunningException:
309
- log(INFO, "")
310
- log(
311
- INFO,
312
- "SuperNode aborted sending the reply message. "
313
- "Run ID %s is not in `RUNNING` status.",
314
- run_id,
245
+ # Share Message and Context with servicer
246
+ clientappio_servicer.set_inputs(
247
+ clientapp_input=ClientAppInputs(
248
+ message=message,
249
+ context=context,
250
+ run=run,
251
+ fab=fab,
252
+ token=token,
253
+ ),
254
+ token_returned=start_subprocess,
255
+ )
256
+
257
+ if start_subprocess:
258
+ _octet, _colon, _port = clientappio_api_address.rpartition(":")
259
+ io_address = (
260
+ f"{CLIENT_OCTET}:{_port}"
261
+ if _octet == SERVER_OCTET
262
+ else clientappio_api_address
315
263
  )
316
- log(INFO, "")
317
- # pylint: enable=too-many-nested-blocks
318
-
319
- # Unregister node
320
- if delete_node is not None:
321
- delete_node() # pylint: disable=not-callable
322
-
323
- if sleep_duration == 0:
324
- log(INFO, "Disconnect and shut down")
325
- break
326
-
327
- # Sleep and reconnect afterwards
328
- log(
329
- INFO,
330
- "Disconnect, then re-establish connection after %s second(s)",
331
- sleep_duration,
332
- )
333
- time.sleep(sleep_duration)
264
+ # Start ClientApp subprocess
265
+ command = [
266
+ "flwr-clientapp",
267
+ "--clientappio-api-address",
268
+ io_address,
269
+ "--token",
270
+ str(token),
271
+ ]
272
+ command.append("--insecure")
273
+
274
+ proc = mp_spawn_context.Process(
275
+ target=_run_flwr_clientapp,
276
+ args=(command, os.getpid()),
277
+ daemon=True,
278
+ )
279
+ proc.start()
280
+ proc.join()
281
+ else:
282
+ # Wait for output to become available
283
+ while not clientappio_servicer.has_outputs():
284
+ time.sleep(0.1)
285
+
286
+ outputs = clientappio_servicer.get_outputs()
287
+ reply_message, context = outputs.message, outputs.context
288
+
289
+ # Update node state
290
+ run_info_store.update_context(
291
+ run_id=run_id,
292
+ context=context,
293
+ )
294
+
295
+ # Send
296
+ send(reply_message)
297
+ log(INFO, "Sent reply")
298
+
299
+ except RunNotRunningException:
300
+ log(INFO, "")
301
+ log(
302
+ INFO,
303
+ "SuperNode aborted sending the reply message. "
304
+ "Run ID %s is not in `RUNNING` status.",
305
+ run_id,
306
+ )
307
+ log(INFO, "")
334
308
 
335
309
 
336
310
  @contextmanager
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: flwr-nightly
3
- Version: 1.19.0.dev20250529
3
+ Version: 1.19.0.dev20250530
4
4
  Summary: Flower: A Friendly Federated AI Framework
5
5
  License: Apache-2.0
6
6
  Keywords: Artificial Intelligence,Federated AI,Federated Analytics,Federated Evaluation,Federated Learning,Flower,Machine Learning
@@ -73,7 +73,7 @@ flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl,sha256=7aOtbvAAnVXyTEYL
73
73
  flwr/cli/run/__init__.py,sha256=RPyB7KbYTFl6YRiilCch6oezxrLQrl1kijV7BMGkLbA,790
74
74
  flwr/cli/run/run.py,sha256=U_EHebzwiH8Lszm40oJM8a2I0vaiu1Iizci_GHSl25Y,8211
75
75
  flwr/cli/stop.py,sha256=l8DcRkA---CESVJgc7iTHLWIBAPGxWIfoem8qSU3lZQ,4972
76
- flwr/cli/utils.py,sha256=oHEP82x4mm0HpT4ZmMg9IU_JPzjSlRNp8BAl3pH_3n4,11222
76
+ flwr/cli/utils.py,sha256=brzc0HPhFxJDi4ctfyQi9lW35uOyvQzoOJ8XHeMDIfE,11575
77
77
  flwr/client/__init__.py,sha256=boIhKaK6I977zrILmoTutNx94x5jB0e6F1gnAjaRJnI,1250
78
78
  flwr/client/client.py,sha256=3HAchxvknKG9jYbB7swNyDj-e5vUWDuMKoLvbT7jCVM,7895
79
79
  flwr/client/client_app.py,sha256=zVhi-l3chAb06ozFsKwix3hU_RpOLjST13Ha50AVIPE,16918
@@ -108,7 +108,7 @@ flwr/common/__init__.py,sha256=5GCLVk399Az_rTJHNticRlL0Sl_oPw_j5_LuFKfX7-M,4171
108
108
  flwr/common/address.py,sha256=9JucdTwlc-jpeJkRKeUboZoacUtErwSVtnDR9kAtLqE,4119
109
109
  flwr/common/args.py,sha256=-aX_jVnSaDrJR2KZ8Wq0Y3dQHII4R4MJtJOIXzVUA0c,5417
110
110
  flwr/common/auth_plugin/__init__.py,sha256=3rzPkVLn9WyB5n7HLk1XGDw3SLCqRWAU1_CnglcWPfw,970
111
- flwr/common/auth_plugin/auth_plugin.py,sha256=_D23QATlSnXtyRhtRQr8_t8LJELWpYvCAJARN0Mhswo,4769
111
+ flwr/common/auth_plugin/auth_plugin.py,sha256=yEIapwim14tn99oGhkQKun_WifoY8hscAtU8Z6fcGXE,4796
112
112
  flwr/common/config.py,sha256=glcZDjco-amw1YfQcYTFJ4S1pt9APoexT-mf1QscuHs,13960
113
113
  flwr/common/constant.py,sha256=lQCel7YanrEdFzy7pHBejhrQ7ZIylJrhBD9pXY02qv0,7472
114
114
  flwr/common/context.py,sha256=Be8obQR_OvEDy1OmshuUKxGRQ7Qx89mf5F4xlhkR10s,2407
@@ -121,25 +121,25 @@ flwr/common/event_log_plugin/event_log_plugin.py,sha256=up7a9H0UxmxdDKlEMNLBhUn5
121
121
  flwr/common/exit/__init__.py,sha256=-ZOJYLaNnR729a7VzZiFsLiqngzKQh3xc27svYStZ_Q,826
122
122
  flwr/common/exit/exit.py,sha256=mJgbqMlVlwAgYtq-Vedj53wO4VxcDcy_P-GzqGK-1GQ,3452
123
123
  flwr/common/exit/exit_code.py,sha256=PNEnCrZfOILjfDAFu5m-2YWEJBrk97xglq4zCUlqV7E,3470
124
- flwr/common/exit_handlers.py,sha256=MEk5_savTLphn-6lW57UQlos-XrFA39XEBn-OF1vXXg,3174
124
+ flwr/common/exit_handlers.py,sha256=IaqJ60fXZuu7McaRYnoYKtlbH9t4Yl9goNExKqtmQbs,4304
125
125
  flwr/common/grpc.py,sha256=manTaHaPiyYngUq1ErZvvV2B2GxlXUUUGRy3jc3TBIQ,9798
126
126
  flwr/common/heartbeat.py,sha256=SyEpNDnmJ0lni0cWO67rcoJVKasCLmkNHm3dKLeNrLU,5749
127
127
  flwr/common/inflatable.py,sha256=vBDlaJlgF6sryjglhFcr22zylROmPFwM7QLjVV7XbtU,6837
128
- flwr/common/inflatable_grpc_utils.py,sha256=On_RT8cYChwE3-1MlY21s_cVXgYCGeKTONRafm-rmEk,3432
128
+ flwr/common/inflatable_grpc_utils.py,sha256=jue6T8bIBOvsocnGalkF_xqWcXJHdBDPAICWCZnPVwU,3973
129
129
  flwr/common/logger.py,sha256=JbRf6E2vQxXzpDBq1T8IDUJo_usu3gjWEBPQ6uKcmdg,13049
130
130
  flwr/common/message.py,sha256=HfSeqxwXgf90ilbMlM0vrF4cJWqJVx3jJ0gNmTfgdFw,19628
131
131
  flwr/common/object_ref.py,sha256=p3SfTeqo3Aj16SkB-vsnNn01zswOPdGNBitcbRnqmUk,9134
132
132
  flwr/common/parameter.py,sha256=UVw6sOgehEFhFs4uUCMl2kfVq1PD6ncmWgPLMsZPKPE,2095
133
133
  flwr/common/pyproject.py,sha256=2SU6yJW7059SbMXgzjOdK1GZRWO6AixDH7BmdxbMvHI,1386
134
134
  flwr/common/record/__init__.py,sha256=cNGccdDoxttqgnUgyKRIqLWULjW-NaSmOufVxtXq-sw,1197
135
- flwr/common/record/array.py,sha256=XtM-ooMPfpyc4RpR6gxZUHmr1xVCtl2HPL-fWyCzzCo,12140
136
- flwr/common/record/arrayrecord.py,sha256=vUNVBlHA_HsbsTdB9eom49abfPYrKHQNW9Ac0UCazTo,18007
135
+ flwr/common/record/array.py,sha256=3K01tAf_jedub2r2-vkRshbsjBSiKErAO4KqDgdDaSo,11776
136
+ flwr/common/record/arrayrecord.py,sha256=CpoqYXM6Iv4XEc9SryCMYmw-bIvP8ut6xWJzRwYJzdU,18008
137
137
  flwr/common/record/configrecord.py,sha256=nDoIc_-vh7XUx2BuojenpcqSgM2XxD4NyGFAYpmXabM,9652
138
138
  flwr/common/record/conversion_utils.py,sha256=wbNCzy7oAqaA3-arhls_EqRZYXRC4YrWIoE-Gy82fJ0,1191
139
139
  flwr/common/record/metricrecord.py,sha256=Gxl9TdVpMAHg6pNN2SxB-as8iPDnPx398KEhORU4n3A,8839
140
140
  flwr/common/record/recorddict.py,sha256=p7hBimFpKM1XKUe6OAkR_7pYGzGL_EwUJUvJ8odZEcY,14986
141
141
  flwr/common/record/typeddict.py,sha256=dDKgUThs2BscYUNcgP82KP8-qfAYXYftDrf2LszAC_o,3599
142
- flwr/common/recorddict_compat.py,sha256=Znn1xRGiqLpPPgviVqyb-GPTM-pCK6tpnEmhWSXafy8,14119
142
+ flwr/common/recorddict_compat.py,sha256=D5SqXWkqBddn5b6K_5UoH7aZ11UaN3lDTlzvHx3-rqk,14119
143
143
  flwr/common/retry_invoker.py,sha256=T6puUH3nCxdRzQHeanyr-0nTxhRiS1TH07rmef9vuLQ,14482
144
144
  flwr/common/secure_aggregation/__init__.py,sha256=MgW6uHGhyFLBAYQqa1Vzs5n2Gc0d4yEw1_NmerFir70,731
145
145
  flwr/common/secure_aggregation/crypto/__init__.py,sha256=5E4q4-Fw0CNz4tLah_QHj7m_rDeM4ucHcFlPWB_Na3Q,738
@@ -149,7 +149,7 @@ flwr/common/secure_aggregation/ndarrays_arithmetic.py,sha256=TrggOlizlny3V2KS7-3
149
149
  flwr/common/secure_aggregation/quantization.py,sha256=ssFZpiRyj9ltIh0Ai3vGkDqWFO4SoqgoD1mDU9XqMEM,2400
150
150
  flwr/common/secure_aggregation/secaggplus_constants.py,sha256=dGYhWOBMMDJcQH4_tQNC8-Efqm-ecEUNN9ANz59UnCk,2182
151
151
  flwr/common/secure_aggregation/secaggplus_utils.py,sha256=E_xU-Zd45daO1em7M6C2wOjFXVtJf-6tl7fp-7xq1wo,3214
152
- flwr/common/serde.py,sha256=KpEaiOZGpMce4CGPkZ6HrWRj4qheYi-MC18HXDKeycM,22378
152
+ flwr/common/serde.py,sha256=smtfWWALhn3YOanM9Vco63BJzcYSBCFYc_J2OBkepsE,22379
153
153
  flwr/common/serde_utils.py,sha256=zF99EnqTNhEd3Xh3tYy2bZ44_8B-QfwNqsuP7vfLVDs,5735
154
154
  flwr/common/telemetry.py,sha256=jF47v0SbnBd43XamHtl3wKxs3knFUY2p77cm_2lzZ8M,8762
155
155
  flwr/common/typing.py,sha256=97QRfRRS7sQnjkAI5FDZ01-38oQUSz4i1qqewQmBWRg,6886
@@ -226,7 +226,7 @@ flwr/proto/transport_pb2_grpc.py,sha256=vLN3EHtx2aEEMCO4f1Upu-l27BPzd3-5pV-u8wPc
226
226
  flwr/proto/transport_pb2_grpc.pyi,sha256=AGXf8RiIiW2J5IKMlm_3qT3AzcDa4F3P5IqUjve_esA,766
227
227
  flwr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
228
228
  flwr/server/__init__.py,sha256=LQQHiuL2jy7TpNaKastRdGsexlxSt5ZWAQNVqitDnrY,1598
229
- flwr/server/app.py,sha256=GJZHJdd9THHdsvda-vz6EzLL_edBFsvR5HKi6093Wog,30114
229
+ flwr/server/app.py,sha256=eI8oXdpYgHCVPNGqcyAxubxFd8huW1t3kE0tc9JKfCw,29878
230
230
  flwr/server/client_manager.py,sha256=5jCGavVli7XdupvWWo7ru3PdFTlRU8IGvHFSSoUVLRs,6227
231
231
  flwr/server/client_proxy.py,sha256=sv0E9AldBYOvc3pusqFh-GnyreeMfsXQ1cuTtxTq_wY,2399
232
232
  flwr/server/compat/__init__.py,sha256=0IsttWvY15qO98_1GyzVC-vR1e_ZPXOdu2qUlOkYMPE,886
@@ -286,12 +286,12 @@ flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py,sha256=KouR9PUcrPmMtoLooF4O
286
286
  flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py,sha256=iSf0mbBAlig7G6subQwBSVjcUCgSihONKdZ1RmQPTOk,4887
287
287
  flwr/server/superlink/fleet/grpc_bidi/grpc_server.py,sha256=OsS-6GgCIzMMZDVu5Y-OKjynHVUrpdc_5OrtuB-IbU0,5174
288
288
  flwr/server/superlink/fleet/grpc_rere/__init__.py,sha256=ahDJJ1e-lDxBpeBMgPk7YZt2wB38_QltcpOC0gLbpFs,758
289
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py,sha256=pYTltWgHwfou_uwXZ6xAaamZVW47MFRLsP49NvQ7FqI,7137
289
+ flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py,sha256=Y92dcvbaN4EHb4Rlut5O2saJsoAN_Tejs4iFtzCS0P0,7189
290
290
  flwr/server/superlink/fleet/grpc_rere/server_interceptor.py,sha256=DrHubsaLgJCwCeeJPYogQTiP0xYqjxwnT9rh7OP7BoU,6984
291
291
  flwr/server/superlink/fleet/message_handler/__init__.py,sha256=fHsRV0KvJ8HtgSA4_YBsEzuhJLjO8p6xx4aCY2oE1p4,731
292
- flwr/server/superlink/fleet/message_handler/message_handler.py,sha256=aF3y07kvFi9Kohs9Jt66x-CqgYF5A3a1RuA6SVwX2rw,5739
292
+ flwr/server/superlink/fleet/message_handler/message_handler.py,sha256=P43PapLZJKbZ0Oo0kP_KcO5zSMvO53SakQgPMiR5d1M,6500
293
293
  flwr/server/superlink/fleet/rest_rere/__init__.py,sha256=Lzc93nA7tDqoy-zRUaPG316oqFiZX1HUCL5ELaXY_xw,735
294
- flwr/server/superlink/fleet/rest_rere/rest_api.py,sha256=PrXXJQo0HZXLNFj81Efpig2YYFw5BWisIID3qyBSbbE,7091
294
+ flwr/server/superlink/fleet/rest_rere/rest_api.py,sha256=dKSSo5H-JUZ_J_9HXQqwzUdLFQ64ZbDj6MvYo68Uxn4,7187
295
295
  flwr/server/superlink/fleet/vce/__init__.py,sha256=XOKbAWOzlCqEOQ3M2cBYkH7HKA7PxlbCJMunt-ty-DY,784
296
296
  flwr/server/superlink/fleet/vce/backend/__init__.py,sha256=PPH89Yqd1XKm-sRJN6R0WQlKT_b4v54Kzl2yzHAFzM8,1437
297
297
  flwr/server/superlink/fleet/vce/backend/backend.py,sha256=-wDHjgAy5mrfEgXj0GxkJI7lhEbgSUyPwmNAf9ZcDzc,2193
@@ -302,10 +302,10 @@ flwr/server/superlink/linkstate/in_memory_linkstate.py,sha256=rw3h5cbF-T_9DNDM-f
302
302
  flwr/server/superlink/linkstate/linkstate.py,sha256=Jrgm1biGDkQZVGuecrgJSf4laWZ1WeBbScA-Zs7Gc3Y,13069
303
303
  flwr/server/superlink/linkstate/linkstate_factory.py,sha256=8RlosqSpKOoD_vhUUQPY0jtE3A84GeF96Z7sWNkRRcA,2069
304
304
  flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=sHJPK1w0tP0m2WCXH2F9lGxGyI3wBniPUBono30vwMY,43242
305
- flwr/server/superlink/linkstate/utils.py,sha256=i93ZXBPHR27YCPkTBLX0-LP-zKOxV4L-qi7spoBxJXE,15345
305
+ flwr/server/superlink/linkstate/utils.py,sha256=IeLh7iGRCHU5MEWOl7iriaSE4L__8GWOa2OleXadK5M,15444
306
306
  flwr/server/superlink/serverappio/__init__.py,sha256=Fy4zJuoccZe5mZSEIpOmQvU6YeXFBa1M4eZuXXmJcn8,717
307
307
  flwr/server/superlink/serverappio/serverappio_grpc.py,sha256=6-FUUt0GiLcBPljj8bBrUNeAITUoDQOLzaMihKo52hg,2326
308
- flwr/server/superlink/serverappio/serverappio_servicer.py,sha256=VxQdDolgfr8mI83tHpoyxfwRN1_ET80WarxfHUIwevE,14163
308
+ flwr/server/superlink/serverappio/serverappio_servicer.py,sha256=JkCqxYNV2Oou6CLdXndRzPjk281cSE4EVDKcuVh7jHE,15556
309
309
  flwr/server/superlink/simulation/__init__.py,sha256=Ry8DrNaZCMcQXvUc4FoCN2m3dvUQgWjasfp015o3Ec4,718
310
310
  flwr/server/superlink/simulation/simulationio_grpc.py,sha256=0l0F-UjYEk6W7HZmI28PbJQLFxSi_vBHRkdchgdaSMQ,2224
311
311
  flwr/server/superlink/simulation/simulationio_servicer.py,sha256=aJezU8RSJswcmWm7Eoy0BqsU13jrcfuFwX3ljm-cORM,7719
@@ -331,17 +331,17 @@ flwr/simulation/ray_transport/utils.py,sha256=KrexpWYCF-dAF3UHc9yDbPQWO-ahMT-BbD
331
331
  flwr/simulation/run_simulation.py,sha256=Nvw_6hI71aE2nU95_tt1F9VSo3OJWrvA97e3XZuqE4k,20310
332
332
  flwr/simulation/simulationio_connection.py,sha256=mzS1C6EEREwQDPceDo30anAasmTDLb9qqV2tXlBhOUA,3494
333
333
  flwr/supercore/__init__.py,sha256=pqkFoow_E6UhbBlhmoD1gmTH-33yJRhBsIZqxRPFZ7U,755
334
- flwr/supercore/object_store/__init__.py,sha256=7dvl-iNyZjEla9lLijc6Hn6HbdxXwsiA_ktF7PCYcSY,861
335
- flwr/supercore/object_store/in_memory_object_store.py,sha256=3q-v9_XRye0adQteDwckRpnVUGVbMZeSA4T326OTNO0,3579
336
- flwr/supercore/object_store/object_store.py,sha256=f627VkRmBl6HFt4gyC3lMka0_uemF_NaysAjkDGsEyY,3951
334
+ flwr/supercore/object_store/__init__.py,sha256=cdfPAmjINY6iOp8oI_LdcVh2simg469Mkdl4LLV4kHI,911
335
+ flwr/supercore/object_store/in_memory_object_store.py,sha256=OPZPNM2CLi5tZq9bVBKAzPch4CRXrUz_20Op1bRsFJc,3913
336
+ flwr/supercore/object_store/object_store.py,sha256=yZ6A_JgK_aGF54zlPISLK_d9FvxpYJlI2qNfmQBdlzM,4328
337
337
  flwr/supercore/object_store/object_store_factory.py,sha256=QVwE2ywi7vsj2iKfvWWnNw3N_I7Rz91NUt2RpcbJ7iM,1527
338
338
  flwr/superexec/__init__.py,sha256=YFqER0IJc1XEWfsX6AxZ9LSRq0sawPYrNYki-brvTIc,715
339
339
  flwr/superexec/app.py,sha256=U2jjOHb2LGWoU7vrl9_czTzre9O2mPxu3CPGUZ86sK4,1465
340
340
  flwr/superexec/deployment.py,sha256=2wBBZgdNAn1Ik1M3HGg4t23CV8oZqzDz1zkOBzHjZLE,6734
341
341
  flwr/superexec/exec_event_log_interceptor.py,sha256=IlQ_w-GpGNMJ4g1gTI3H4LHfWli1-8O7a2-pCqB3yeA,5753
342
- flwr/superexec/exec_grpc.py,sha256=KMaiPcg_wVM_cn_VPzrSP8AKVqGndOuei9XdHgy86tU,3252
342
+ flwr/superexec/exec_grpc.py,sha256=LS-CrwBayHQAvJz-zmzV5JsaEC49VumsS25nC0NgYXg,3364
343
343
  flwr/superexec/exec_servicer.py,sha256=nSqAzrWDQFQm9xE6oejoFZqgWhPchbdkC2mCMrWTbhE,8324
344
- flwr/superexec/exec_user_auth_interceptor.py,sha256=iqygALkOMBUu_s_R9G0mFThZA7HTUzuXCLgxLCefiwI,4440
344
+ flwr/superexec/exec_user_auth_interceptor.py,sha256=L-oYmcf35HJFnqNVyfAPwhbkyaTEjkNM_ooioOVATCQ,5771
345
345
  flwr/superexec/executor.py,sha256=M5ucqSE53jfRtuCNf59WFLqQvA1Mln4741TySeZE7qQ,3112
346
346
  flwr/superexec/simulation.py,sha256=j6YwUvBN7EQ09ID7MYOCVZ70PGbuyBy8f9bXU0EszEM,4088
347
347
  flwr/superlink/__init__.py,sha256=GNSuJ4-N6Z8wun2iZNlXqENt5beUyzC0Gi_tN396bbM,707
@@ -352,8 +352,8 @@ flwr/supernode/nodestate/__init__.py,sha256=CyLLObbmmVgfRO88UCM0VMait1dL57mUauUD
352
352
  flwr/supernode/nodestate/in_memory_nodestate.py,sha256=brV7TMMzS93tXk6ntpoYjtPK5qiSF3XD2W-uUdUVucc,1270
353
353
  flwr/supernode/nodestate/nodestate.py,sha256=-LAjZOnS7VyHC05ll3b31cYDjwAt6l4WmYt7duVLRKk,1024
354
354
  flwr/supernode/nodestate/nodestate_factory.py,sha256=UYTDCcwK_baHUmkzkJDxL0UEqvtTfOMlQRrROMCd0Xo,1430
355
- flwr/supernode/start_client_internal.py,sha256=4z9qtwT7ZwNwahpX1SRfuaoYw1HCICPFUvjPBLHgsA0,18806
356
- flwr_nightly-1.19.0.dev20250529.dist-info/METADATA,sha256=k8T_zqQ3VfowP5KCkRhclVAl6mM7FPfcIe41XwH9jI4,15910
357
- flwr_nightly-1.19.0.dev20250529.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
358
- flwr_nightly-1.19.0.dev20250529.dist-info/entry_points.txt,sha256=08k99PaHg3Wr6W49rFXYtjmgcfIdpFLNeu6O0bXDYnU,370
359
- flwr_nightly-1.19.0.dev20250529.dist-info/RECORD,,
355
+ flwr/supernode/start_client_internal.py,sha256=HktXGD-3hUnGmyr_o7bLnJoyNdHGEZ8mUnvQorhOxwY,17378
356
+ flwr_nightly-1.19.0.dev20250530.dist-info/METADATA,sha256=zTg94SmZNuBfw2Lhaik-CeKnBNPZaBvim7skQ4vhB4k,15910
357
+ flwr_nightly-1.19.0.dev20250530.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
358
+ flwr_nightly-1.19.0.dev20250530.dist-info/entry_points.txt,sha256=08k99PaHg3Wr6W49rFXYtjmgcfIdpFLNeu6O0bXDYnU,370
359
+ flwr_nightly-1.19.0.dev20250530.dist-info/RECORD,,