flwr-nightly 1.20.0.dev20250718__py3-none-any.whl → 1.20.0.dev20250720__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.
- flwr/cli/build.py +1 -1
- flwr/client/grpc_adapter_client/connection.py +6 -0
- flwr/client/grpc_rere_client/connection.py +57 -1
- flwr/client/rest_client/connection.py +91 -21
- flwr/common/inflatable_utils.py +50 -12
- flwr/server/superlink/fleet/message_handler/message_handler.py +1 -2
- flwr/server/superlink/serverappio/serverappio_servicer.py +1 -2
- flwr/supercore/object_store/utils.py +48 -0
- flwr/supernode/runtime/run_clientapp.py +64 -11
- flwr/supernode/servicer/clientappio/clientappio_servicer.py +16 -4
- flwr/supernode/start_client_internal.py +27 -3
- {flwr_nightly-1.20.0.dev20250718.dist-info → flwr_nightly-1.20.0.dev20250720.dist-info}/METADATA +1 -1
- {flwr_nightly-1.20.0.dev20250718.dist-info → flwr_nightly-1.20.0.dev20250720.dist-info}/RECORD +15 -14
- {flwr_nightly-1.20.0.dev20250718.dist-info → flwr_nightly-1.20.0.dev20250720.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.20.0.dev20250718.dist-info → flwr_nightly-1.20.0.dev20250720.dist-info}/entry_points.txt +0 -0
flwr/cli/build.py
CHANGED
@@ -184,7 +184,7 @@ def build_fab(app: Path) -> tuple[bytes, str, dict[str, Any]]:
|
|
184
184
|
# Read the file content manually
|
185
185
|
file_contents = file_path.read_bytes()
|
186
186
|
|
187
|
-
archive_path = str(file_path.relative_to(app))
|
187
|
+
archive_path = str(file_path.relative_to(app)).replace("\\", "/")
|
188
188
|
write_to_zip(fab_file, archive_path, file_contents)
|
189
189
|
|
190
190
|
# Calculate file info
|
@@ -49,6 +49,9 @@ def grpc_adapter( # pylint: disable=R0913,too-many-positional-arguments
|
|
49
49
|
Callable[[], None],
|
50
50
|
Callable[[int], Run],
|
51
51
|
Callable[[str, int], Fab],
|
52
|
+
Callable[[int, str], bytes],
|
53
|
+
Callable[[int, str, bytes], None],
|
54
|
+
Callable[[int, str], None],
|
52
55
|
]
|
53
56
|
]:
|
54
57
|
"""Primitives for request/response-based interaction with a server via GrpcAdapter.
|
@@ -83,6 +86,9 @@ def grpc_adapter( # pylint: disable=R0913,too-many-positional-arguments
|
|
83
86
|
delete_node : Optional[Callable]
|
84
87
|
get_run : Optional[Callable]
|
85
88
|
get_fab : Optional[Callable]
|
89
|
+
pull_object : Callable[[str], bytes]
|
90
|
+
push_object : Callable[[str, bytes], None]
|
91
|
+
confirm_message_received : Callable[[str], None]
|
86
92
|
"""
|
87
93
|
if authentication_keys is not None:
|
88
94
|
log(ERROR, "Client authentication is not supported for this transport type.")
|
@@ -35,6 +35,7 @@ from flwr.common.inflatable import (
|
|
35
35
|
no_object_id_recompute,
|
36
36
|
)
|
37
37
|
from flwr.common.inflatable_protobuf_utils import (
|
38
|
+
make_confirm_message_received_fn_protobuf,
|
38
39
|
make_pull_object_fn_protobuf,
|
39
40
|
make_push_object_fn_protobuf,
|
40
41
|
)
|
@@ -94,6 +95,9 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
94
95
|
Callable[[], None],
|
95
96
|
Callable[[int], Run],
|
96
97
|
Callable[[str, int], Fab],
|
98
|
+
Callable[[int, str], bytes],
|
99
|
+
Callable[[int, str, bytes], None],
|
100
|
+
Callable[[int, str], None],
|
97
101
|
]
|
98
102
|
]:
|
99
103
|
"""Primitives for request/response-based interaction with a server.
|
@@ -136,6 +140,9 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
136
140
|
create_node : Optional[Callable]
|
137
141
|
delete_node : Optional[Callable]
|
138
142
|
get_run : Optional[Callable]
|
143
|
+
pull_object : Callable[[str], bytes]
|
144
|
+
push_object : Callable[[str, bytes], None]
|
145
|
+
confirm_message_received : Callable[[str], None]
|
139
146
|
"""
|
140
147
|
if isinstance(root_certificates, str):
|
141
148
|
root_certificates = Path(root_certificates).read_bytes()
|
@@ -354,9 +361,58 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
354
361
|
|
355
362
|
return Fab(get_fab_response.fab.hash_str, get_fab_response.fab.content)
|
356
363
|
|
364
|
+
def pull_object(run_id: int, object_id: str) -> bytes:
|
365
|
+
"""Pull the object from the SuperLink."""
|
366
|
+
# Check Node
|
367
|
+
if node is None:
|
368
|
+
raise RuntimeError("Node instance missing")
|
369
|
+
|
370
|
+
fn = make_pull_object_fn_protobuf(
|
371
|
+
pull_object_protobuf=stub.PullObject,
|
372
|
+
node=node,
|
373
|
+
run_id=run_id,
|
374
|
+
)
|
375
|
+
return fn(object_id)
|
376
|
+
|
377
|
+
def push_object(run_id: int, object_id: str, contents: bytes) -> None:
|
378
|
+
"""Push the object to the SuperLink."""
|
379
|
+
# Check Node
|
380
|
+
if node is None:
|
381
|
+
raise RuntimeError("Node instance missing")
|
382
|
+
|
383
|
+
fn = make_push_object_fn_protobuf(
|
384
|
+
push_object_protobuf=stub.PushObject,
|
385
|
+
node=node,
|
386
|
+
run_id=run_id,
|
387
|
+
)
|
388
|
+
fn(object_id, contents)
|
389
|
+
|
390
|
+
def confirm_message_received(run_id: int, object_id: str) -> None:
|
391
|
+
"""Confirm that the message has been received."""
|
392
|
+
# Check Node
|
393
|
+
if node is None:
|
394
|
+
raise RuntimeError("Node instance missing")
|
395
|
+
|
396
|
+
fn = make_confirm_message_received_fn_protobuf(
|
397
|
+
confirm_message_received_protobuf=stub.ConfirmMessageReceived,
|
398
|
+
node=node,
|
399
|
+
run_id=run_id,
|
400
|
+
)
|
401
|
+
fn(object_id)
|
402
|
+
|
357
403
|
try:
|
358
404
|
# Yield methods
|
359
|
-
yield (
|
405
|
+
yield (
|
406
|
+
receive,
|
407
|
+
send,
|
408
|
+
create_node,
|
409
|
+
delete_node,
|
410
|
+
get_run,
|
411
|
+
get_fab,
|
412
|
+
pull_object,
|
413
|
+
push_object,
|
414
|
+
confirm_message_received,
|
415
|
+
)
|
360
416
|
except Exception as exc: # pylint: disable=broad-except
|
361
417
|
log(ERROR, exc)
|
362
418
|
# Cleanup
|
@@ -35,6 +35,7 @@ from flwr.common.inflatable import (
|
|
35
35
|
no_object_id_recompute,
|
36
36
|
)
|
37
37
|
from flwr.common.inflatable_protobuf_utils import (
|
38
|
+
make_confirm_message_received_fn_protobuf,
|
38
39
|
make_pull_object_fn_protobuf,
|
39
40
|
make_push_object_fn_protobuf,
|
40
41
|
)
|
@@ -114,6 +115,9 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
114
115
|
Callable[[], None],
|
115
116
|
Callable[[int], Run],
|
116
117
|
Callable[[str, int], Fab],
|
118
|
+
Callable[[int, str], bytes],
|
119
|
+
Callable[[int, str, bytes], None],
|
120
|
+
Callable[[int, str], None],
|
117
121
|
]
|
118
122
|
]:
|
119
123
|
"""Primitives for request/response-based interaction with a server.
|
@@ -149,6 +153,9 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
149
153
|
create_node : Optional[Callable]
|
150
154
|
delete_node : Optional[Callable]
|
151
155
|
get_run : Optional[Callable]
|
156
|
+
pull_object : Callable[[str], bytes]
|
157
|
+
push_object : Callable[[str, bytes], None]
|
158
|
+
confirm_message_received : Callable[[str], None]
|
152
159
|
"""
|
153
160
|
log(
|
154
161
|
WARN,
|
@@ -230,6 +237,38 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
230
237
|
grpc_res.ParseFromString(res.content)
|
231
238
|
return grpc_res
|
232
239
|
|
240
|
+
def _pull_object_protobuf(request: PullObjectRequest) -> PullObjectResponse:
|
241
|
+
res = _request(
|
242
|
+
req=request,
|
243
|
+
res_type=PullObjectResponse,
|
244
|
+
api_path=PATH_PULL_OBJECT,
|
245
|
+
)
|
246
|
+
if res is None:
|
247
|
+
raise ValueError(f"{PullObjectResponse.__name__} is None.")
|
248
|
+
return res
|
249
|
+
|
250
|
+
def _push_object_protobuf(request: PushObjectRequest) -> PushObjectResponse:
|
251
|
+
res = _request(
|
252
|
+
req=request,
|
253
|
+
res_type=PushObjectResponse,
|
254
|
+
api_path=PATH_PUSH_OBJECT,
|
255
|
+
)
|
256
|
+
if res is None:
|
257
|
+
raise ValueError(f"{PushObjectResponse.__name__} is None.")
|
258
|
+
return res
|
259
|
+
|
260
|
+
def _confirm_message_received_protobuf(
|
261
|
+
request: ConfirmMessageReceivedRequest,
|
262
|
+
) -> ConfirmMessageReceivedResponse:
|
263
|
+
res = _request(
|
264
|
+
req=request,
|
265
|
+
res_type=ConfirmMessageReceivedResponse,
|
266
|
+
api_path=PATH_CONFIRM_MESSAGE_RECEIVED,
|
267
|
+
)
|
268
|
+
if res is None:
|
269
|
+
raise ValueError(f"{ConfirmMessageReceivedResponse.__name__} is None.")
|
270
|
+
return res
|
271
|
+
|
233
272
|
def send_node_heartbeat() -> bool:
|
234
273
|
# Get Node
|
235
274
|
if node is None:
|
@@ -326,20 +365,12 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
326
365
|
msg_id = message_proto.metadata.message_id
|
327
366
|
run_id = message_proto.metadata.run_id
|
328
367
|
|
329
|
-
def fn(request: PullObjectRequest) -> PullObjectResponse:
|
330
|
-
res = _request(
|
331
|
-
req=request, res_type=PullObjectResponse, api_path=PATH_PULL_OBJECT
|
332
|
-
)
|
333
|
-
if res is None:
|
334
|
-
raise ValueError("PushObjectResponse is None.")
|
335
|
-
return res
|
336
|
-
|
337
368
|
try:
|
338
369
|
object_tree = res.message_object_trees[0]
|
339
370
|
all_object_contents = pull_objects(
|
340
371
|
[tree.object_id for tree in iterate_object_tree(object_tree)],
|
341
372
|
pull_object_fn=make_pull_object_fn_protobuf(
|
342
|
-
pull_object_protobuf=
|
373
|
+
pull_object_protobuf=_pull_object_protobuf,
|
343
374
|
node=node,
|
344
375
|
run_id=run_id,
|
345
376
|
),
|
@@ -403,21 +434,11 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
403
434
|
if res and res.objects_to_push:
|
404
435
|
objs_to_push = set(res.objects_to_push[message.object_id].object_ids)
|
405
436
|
|
406
|
-
def fn(request: PushObjectRequest) -> PushObjectResponse:
|
407
|
-
res = _request(
|
408
|
-
req=request,
|
409
|
-
res_type=PushObjectResponse,
|
410
|
-
api_path=PATH_PUSH_OBJECT,
|
411
|
-
)
|
412
|
-
if res is None:
|
413
|
-
raise ValueError("PushObjectResponse is None.")
|
414
|
-
return res
|
415
|
-
|
416
437
|
try:
|
417
438
|
push_objects(
|
418
439
|
all_objects,
|
419
440
|
push_object_fn=make_push_object_fn_protobuf(
|
420
|
-
push_object_protobuf=
|
441
|
+
push_object_protobuf=_push_object_protobuf,
|
421
442
|
node=node,
|
422
443
|
run_id=message_proto.metadata.run_id,
|
423
444
|
),
|
@@ -457,9 +478,58 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
457
478
|
res.fab.content,
|
458
479
|
)
|
459
480
|
|
481
|
+
def pull_object(run_id: int, object_id: str) -> bytes:
|
482
|
+
"""Pull the object from the SuperLink."""
|
483
|
+
# Check Node
|
484
|
+
if node is None:
|
485
|
+
raise RuntimeError("Node instance missing")
|
486
|
+
|
487
|
+
fn = make_pull_object_fn_protobuf(
|
488
|
+
pull_object_protobuf=_pull_object_protobuf,
|
489
|
+
node=node,
|
490
|
+
run_id=run_id,
|
491
|
+
)
|
492
|
+
return fn(object_id)
|
493
|
+
|
494
|
+
def push_object(run_id: int, object_id: str, contents: bytes) -> None:
|
495
|
+
"""Push the object to the SuperLink."""
|
496
|
+
# Check Node
|
497
|
+
if node is None:
|
498
|
+
raise RuntimeError("Node instance missing")
|
499
|
+
|
500
|
+
fn = make_push_object_fn_protobuf(
|
501
|
+
push_object_protobuf=_push_object_protobuf,
|
502
|
+
node=node,
|
503
|
+
run_id=run_id,
|
504
|
+
)
|
505
|
+
fn(object_id, contents)
|
506
|
+
|
507
|
+
def confirm_message_received(run_id: int, object_id: str) -> None:
|
508
|
+
"""Confirm that the message has been received."""
|
509
|
+
# Check Node
|
510
|
+
if node is None:
|
511
|
+
raise RuntimeError("Node instance missing")
|
512
|
+
|
513
|
+
fn = make_confirm_message_received_fn_protobuf(
|
514
|
+
confirm_message_received_protobuf=_confirm_message_received_protobuf,
|
515
|
+
node=node,
|
516
|
+
run_id=run_id,
|
517
|
+
)
|
518
|
+
fn(object_id)
|
519
|
+
|
460
520
|
try:
|
461
521
|
# Yield methods
|
462
|
-
yield (
|
522
|
+
yield (
|
523
|
+
receive,
|
524
|
+
send,
|
525
|
+
create_node,
|
526
|
+
delete_node,
|
527
|
+
get_run,
|
528
|
+
get_fab,
|
529
|
+
pull_object,
|
530
|
+
push_object,
|
531
|
+
confirm_message_received,
|
532
|
+
)
|
463
533
|
except Exception as exc: # pylint: disable=broad-except
|
464
534
|
log(ERROR, exc)
|
465
535
|
# Cleanup
|
flwr/common/inflatable_utils.py
CHANGED
@@ -19,6 +19,7 @@ import os
|
|
19
19
|
import random
|
20
20
|
import threading
|
21
21
|
import time
|
22
|
+
from collections.abc import Iterable, Iterator
|
22
23
|
from typing import Callable, Optional, TypeVar
|
23
24
|
|
24
25
|
from flwr.proto.message_pb2 import ObjectTree # pylint: disable=E0611
|
@@ -110,24 +111,61 @@ def push_objects(
|
|
110
111
|
max_concurrent_pushes : int (default: MAX_CONCURRENT_PUSHES)
|
111
112
|
The maximum number of concurrent pushes to perform.
|
112
113
|
"""
|
113
|
-
if object_ids_to_push is not None:
|
114
|
-
# Filter objects to push only those with IDs in the set
|
115
|
-
objects = {k: v for k, v in objects.items() if k in object_ids_to_push}
|
116
|
-
|
117
114
|
lock = threading.Lock()
|
118
115
|
|
119
|
-
def
|
116
|
+
def iter_dict_items() -> Iterator[tuple[str, bytes]]:
|
117
|
+
"""Iterate over the dictionary items."""
|
118
|
+
for obj_id in list(objects.keys()):
|
119
|
+
# Skip the object if no need to push it
|
120
|
+
if object_ids_to_push is not None and obj_id not in object_ids_to_push:
|
121
|
+
continue
|
122
|
+
|
123
|
+
# Deflate the object content
|
124
|
+
object_content = objects[obj_id].deflate()
|
125
|
+
if not keep_objects:
|
126
|
+
with lock:
|
127
|
+
del objects[obj_id]
|
128
|
+
|
129
|
+
yield obj_id, object_content
|
130
|
+
|
131
|
+
push_object_contents_from_iterable(
|
132
|
+
iter_dict_items(),
|
133
|
+
push_object_fn,
|
134
|
+
max_concurrent_pushes=max_concurrent_pushes,
|
135
|
+
)
|
136
|
+
|
137
|
+
|
138
|
+
def push_object_contents_from_iterable(
|
139
|
+
object_contents: Iterable[tuple[str, bytes]],
|
140
|
+
push_object_fn: Callable[[str, bytes], None],
|
141
|
+
*,
|
142
|
+
max_concurrent_pushes: int = MAX_CONCURRENT_PUSHES,
|
143
|
+
) -> None:
|
144
|
+
"""Push multiple object contents to the servicer.
|
145
|
+
|
146
|
+
Parameters
|
147
|
+
----------
|
148
|
+
object_contents : Iterable[tuple[str, bytes]]
|
149
|
+
An iterable of `(object_id, object_content)` pairs.
|
150
|
+
`object_id` is the object ID, and `object_content` is the object content.
|
151
|
+
push_object_fn : Callable[[str, bytes], None]
|
152
|
+
A function that takes an object ID and its content as bytes, and pushes
|
153
|
+
it to the servicer. This function should raise `ObjectIdNotPreregisteredError`
|
154
|
+
if the object ID is not pre-registered.
|
155
|
+
max_concurrent_pushes : int (default: MAX_CONCURRENT_PUSHES)
|
156
|
+
The maximum number of concurrent pushes to perform.
|
157
|
+
"""
|
158
|
+
|
159
|
+
def push(args: tuple[str, bytes]) -> None:
|
120
160
|
"""Push a single object."""
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
del objects[obj_id]
|
125
|
-
push_object_fn(obj_id, object_content)
|
161
|
+
obj_id, obj_content = args
|
162
|
+
# Push the object using the provided function
|
163
|
+
push_object_fn(obj_id, obj_content)
|
126
164
|
|
127
|
-
# Push all
|
165
|
+
# Push all object contents concurrently
|
128
166
|
num_workers = get_num_workers(max_concurrent_pushes)
|
129
167
|
with concurrent.futures.ThreadPoolExecutor(max_workers=num_workers) as executor:
|
130
|
-
list(executor.map(push,
|
168
|
+
list(executor.map(push, object_contents))
|
131
169
|
|
132
170
|
|
133
171
|
def pull_objects( # pylint: disable=too-many-arguments,too-many-locals
|
@@ -61,8 +61,7 @@ from flwr.server.superlink.linkstate import LinkState
|
|
61
61
|
from flwr.server.superlink.utils import check_abort
|
62
62
|
from flwr.supercore.ffs import Ffs
|
63
63
|
from flwr.supercore.object_store import NoObjectInStoreError, ObjectStore
|
64
|
-
|
65
|
-
from ...utils import store_mapping_and_register_objects
|
64
|
+
from flwr.supercore.object_store.utils import store_mapping_and_register_objects
|
66
65
|
|
67
66
|
|
68
67
|
def create_node(
|
@@ -87,8 +87,7 @@ from flwr.server.superlink.utils import abort_if
|
|
87
87
|
from flwr.server.utils.validator import validate_message
|
88
88
|
from flwr.supercore.ffs import Ffs, FfsFactory
|
89
89
|
from flwr.supercore.object_store import NoObjectInStoreError, ObjectStoreFactory
|
90
|
-
|
91
|
-
from ..utils import store_mapping_and_register_objects
|
90
|
+
from flwr.supercore.object_store.utils import store_mapping_and_register_objects
|
92
91
|
|
93
92
|
|
94
93
|
class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# Copyright 2025 Flower Labs GmbH. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
# ==============================================================================
|
15
|
+
"""Utils for ObjectStore."""
|
16
|
+
|
17
|
+
|
18
|
+
from typing import Union
|
19
|
+
|
20
|
+
from flwr.proto.appio_pb2 import PushAppMessagesRequest # pylint: disable=E0611
|
21
|
+
from flwr.proto.fleet_pb2 import PushMessagesRequest # pylint: disable=E0611
|
22
|
+
from flwr.proto.message_pb2 import ObjectIDs # pylint: disable=E0611
|
23
|
+
|
24
|
+
from . import ObjectStore
|
25
|
+
|
26
|
+
|
27
|
+
def store_mapping_and_register_objects(
|
28
|
+
store: ObjectStore, request: Union[PushAppMessagesRequest, PushMessagesRequest]
|
29
|
+
) -> dict[str, ObjectIDs]:
|
30
|
+
"""Store Message object to descendants mapping and preregister objects."""
|
31
|
+
if not request.messages_list:
|
32
|
+
return {}
|
33
|
+
|
34
|
+
objects_to_push: dict[str, ObjectIDs] = {}
|
35
|
+
|
36
|
+
# Get run_id from the first message in the list
|
37
|
+
# All messages of a request should in the same run
|
38
|
+
run_id = request.messages_list[0].metadata.run_id
|
39
|
+
|
40
|
+
for object_tree in request.message_object_trees:
|
41
|
+
# Preregister
|
42
|
+
object_ids_just_registered = store.preregister(run_id, object_tree)
|
43
|
+
# Keep track of objects that need to be pushed
|
44
|
+
objects_to_push[object_tree.object_id] = ObjectIDs(
|
45
|
+
object_ids=object_ids_just_registered
|
46
|
+
)
|
47
|
+
|
48
|
+
return objects_to_push
|
@@ -32,13 +32,23 @@ from flwr.common import Context, Message
|
|
32
32
|
from flwr.common.config import get_flwr_dir
|
33
33
|
from flwr.common.constant import ErrorCode
|
34
34
|
from flwr.common.grpc import create_channel, on_channel_state_change
|
35
|
+
from flwr.common.inflatable import (
|
36
|
+
get_all_nested_objects,
|
37
|
+
get_object_tree,
|
38
|
+
no_object_id_recompute,
|
39
|
+
)
|
40
|
+
from flwr.common.inflatable_protobuf_utils import (
|
41
|
+
make_confirm_message_received_fn_protobuf,
|
42
|
+
make_pull_object_fn_protobuf,
|
43
|
+
make_push_object_fn_protobuf,
|
44
|
+
)
|
45
|
+
from flwr.common.inflatable_utils import pull_and_inflate_object_from_tree, push_objects
|
35
46
|
from flwr.common.logger import log
|
36
47
|
from flwr.common.retry_invoker import _make_simple_grpc_retry_invoker, _wrap_stub
|
37
48
|
from flwr.common.serde import (
|
38
49
|
context_from_proto,
|
39
50
|
context_to_proto,
|
40
51
|
fab_from_proto,
|
41
|
-
message_from_proto,
|
42
52
|
message_to_proto,
|
43
53
|
run_from_proto,
|
44
54
|
)
|
@@ -61,6 +71,7 @@ from flwr.proto.clientappio_pb2 import (
|
|
61
71
|
RequestTokenResponse,
|
62
72
|
)
|
63
73
|
from flwr.proto.clientappio_pb2_grpc import ClientAppIoStub
|
74
|
+
from flwr.proto.node_pb2 import Node # pylint: disable=E0611
|
64
75
|
from flwr.supercore.utils import mask_string
|
65
76
|
|
66
77
|
|
@@ -204,12 +215,6 @@ def pull_clientappinputs(
|
|
204
215
|
masked_token = mask_string(token)
|
205
216
|
log(INFO, "[flwr-clientapp] Pull `ClientAppInputs` for token %s", masked_token)
|
206
217
|
try:
|
207
|
-
# Pull Message
|
208
|
-
pull_msg_res: PullAppMessagesResponse = stub.PullMessage(
|
209
|
-
PullAppMessagesRequest(token=token)
|
210
|
-
)
|
211
|
-
message = message_from_proto(pull_msg_res.messages_list[0])
|
212
|
-
|
213
218
|
# Pull Context, Run and (optional) FAB
|
214
219
|
res: PullAppInputsResponse = stub.PullClientAppInputs(
|
215
220
|
PullAppInputsRequest(token=token)
|
@@ -217,6 +222,26 @@ def pull_clientappinputs(
|
|
217
222
|
context = context_from_proto(res.context)
|
218
223
|
run = run_from_proto(res.run)
|
219
224
|
fab = fab_from_proto(res.fab) if res.fab else None
|
225
|
+
|
226
|
+
# Pull and inflate the message
|
227
|
+
pull_msg_res: PullAppMessagesResponse = stub.PullMessage(
|
228
|
+
PullAppMessagesRequest(token=token)
|
229
|
+
)
|
230
|
+
run_id = context.run_id
|
231
|
+
node = Node(node_id=context.node_id)
|
232
|
+
object_tree = pull_msg_res.message_object_trees[0]
|
233
|
+
message = pull_and_inflate_object_from_tree(
|
234
|
+
object_tree,
|
235
|
+
make_pull_object_fn_protobuf(stub.PullObject, node, run_id),
|
236
|
+
make_confirm_message_received_fn_protobuf(
|
237
|
+
stub.ConfirmMessageReceived, node, run_id
|
238
|
+
),
|
239
|
+
return_type=Message,
|
240
|
+
)
|
241
|
+
|
242
|
+
# Set the message ID
|
243
|
+
# The deflated message doesn't contain the message_id (its own object_id)
|
244
|
+
message.metadata.__dict__["_message_id"] = object_tree.object_id
|
220
245
|
return message, context, run, fab
|
221
246
|
except grpc.RpcError as e:
|
222
247
|
log(ERROR, "[PullClientAppInputs] gRPC error occurred: %s", str(e))
|
@@ -236,10 +261,38 @@ def push_clientappoutputs(
|
|
236
261
|
|
237
262
|
try:
|
238
263
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
264
|
+
with no_object_id_recompute():
|
265
|
+
# Get object tree and all objects to push
|
266
|
+
object_tree = get_object_tree(message)
|
267
|
+
|
268
|
+
# Push Message
|
269
|
+
# This is temporary. The message should not contain its content
|
270
|
+
push_msg_res = stub.PushMessage(
|
271
|
+
PushAppMessagesRequest(
|
272
|
+
token=token,
|
273
|
+
messages_list=[proto_message],
|
274
|
+
message_object_trees=[object_tree],
|
275
|
+
)
|
276
|
+
)
|
277
|
+
del proto_message
|
278
|
+
|
279
|
+
# Retrieve the object IDs to push
|
280
|
+
object_ids_to_push = set(
|
281
|
+
push_msg_res.objects_to_push[object_tree.object_id].object_ids
|
282
|
+
)
|
283
|
+
|
284
|
+
# Push all objects
|
285
|
+
all_objects = get_all_nested_objects(message)
|
286
|
+
del message
|
287
|
+
push_objects(
|
288
|
+
all_objects,
|
289
|
+
make_push_object_fn_protobuf(
|
290
|
+
stub.PushObject,
|
291
|
+
Node(node_id=context.node_id),
|
292
|
+
run_id=context.run_id,
|
293
|
+
),
|
294
|
+
object_ids_to_push=object_ids_to_push,
|
295
|
+
)
|
243
296
|
|
244
297
|
# Push Context
|
245
298
|
res: PushAppOutputsResponse = stub.PushClientAppOutputs(
|
@@ -63,6 +63,7 @@ from flwr.proto.message_pb2 import (
|
|
63
63
|
# pylint: disable=E0601
|
64
64
|
from flwr.supercore.ffs import FfsFactory
|
65
65
|
from flwr.supercore.object_store import NoObjectInStoreError, ObjectStoreFactory
|
66
|
+
from flwr.supercore.object_store.utils import store_mapping_and_register_objects
|
66
67
|
from flwr.supernode.nodestate import NodeStateFactory
|
67
68
|
|
68
69
|
|
@@ -178,8 +179,9 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
|
|
178
179
|
self, request: PullAppMessagesRequest, context: grpc.ServicerContext
|
179
180
|
) -> PullAppMessagesResponse:
|
180
181
|
"""Pull one Message."""
|
181
|
-
# Initialize state and
|
182
|
+
# Initialize state and store connection
|
182
183
|
state = self.state_factory.state()
|
184
|
+
store = self.objectstore_factory.store()
|
183
185
|
|
184
186
|
# Validate the token
|
185
187
|
run_id = state.get_run_id_by_token(request.token)
|
@@ -193,14 +195,21 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
|
|
193
195
|
# Retrieve message for this run
|
194
196
|
message = state.get_messages(run_ids=[run_id], is_reply=False)[0]
|
195
197
|
|
196
|
-
|
198
|
+
# Retrieve the object tree for the message
|
199
|
+
object_tree = store.get_object_tree(message.metadata.message_id)
|
200
|
+
|
201
|
+
return PullAppMessagesResponse(
|
202
|
+
messages_list=[message_to_proto(message)],
|
203
|
+
message_object_trees=[object_tree],
|
204
|
+
)
|
197
205
|
|
198
206
|
def PushMessage(
|
199
207
|
self, request: PushAppMessagesRequest, context: grpc.ServicerContext
|
200
208
|
) -> PushAppMessagesResponse:
|
201
209
|
"""Push one Message."""
|
202
|
-
# Initialize state connection
|
210
|
+
# Initialize state and store connection
|
203
211
|
state = self.state_factory.state()
|
212
|
+
store = self.objectstore_factory.store()
|
204
213
|
|
205
214
|
# Validate the token
|
206
215
|
run_id = state.get_run_id_by_token(request.token)
|
@@ -214,7 +223,10 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
|
|
214
223
|
# Save the message to the state
|
215
224
|
state.store_message(message_from_proto(request.messages_list[0]))
|
216
225
|
|
217
|
-
|
226
|
+
# Store Message object to descendants mapping and preregister objects
|
227
|
+
objects_to_push = store_mapping_and_register_objects(store, request=request)
|
228
|
+
|
229
|
+
return PushAppMessagesResponse(objects_to_push=objects_to_push)
|
218
230
|
|
219
231
|
def PushObject(
|
220
232
|
self, request: PushObjectRequest, context: grpc.ServicerContext
|
@@ -172,7 +172,17 @@ def start_client_internal(
|
|
172
172
|
max_retries=max_retries,
|
173
173
|
max_wait_time=max_wait_time,
|
174
174
|
) as conn:
|
175
|
-
|
175
|
+
(
|
176
|
+
receive,
|
177
|
+
send,
|
178
|
+
create_node,
|
179
|
+
_,
|
180
|
+
get_run,
|
181
|
+
get_fab,
|
182
|
+
pull_object,
|
183
|
+
push_object,
|
184
|
+
confirm_message_received,
|
185
|
+
) = conn
|
176
186
|
|
177
187
|
# Call create_node fn to register node
|
178
188
|
# and store node_id in state
|
@@ -192,6 +202,8 @@ def start_client_internal(
|
|
192
202
|
receive=receive,
|
193
203
|
get_run=get_run,
|
194
204
|
get_fab=get_fab,
|
205
|
+
pull_object=pull_object,
|
206
|
+
confirm_message_received=confirm_message_received,
|
195
207
|
)
|
196
208
|
|
197
209
|
# Two isolation modes:
|
@@ -223,7 +235,12 @@ def start_client_internal(
|
|
223
235
|
]
|
224
236
|
subprocess.run(command, check=False)
|
225
237
|
|
226
|
-
_push_messages(
|
238
|
+
_push_messages(
|
239
|
+
state=state,
|
240
|
+
store=store,
|
241
|
+
send=send,
|
242
|
+
push_object=push_object,
|
243
|
+
)
|
227
244
|
|
228
245
|
# Sleep for 3 seconds before the next iteration
|
229
246
|
time.sleep(3)
|
@@ -232,11 +249,13 @@ def start_client_internal(
|
|
232
249
|
def _pull_and_store_message( # pylint: disable=too-many-positional-arguments
|
233
250
|
state: NodeState,
|
234
251
|
ffs: Ffs,
|
235
|
-
object_store: ObjectStore,
|
252
|
+
object_store: ObjectStore,
|
236
253
|
node_config: UserConfig,
|
237
254
|
receive: Callable[[], Optional[Message]],
|
238
255
|
get_run: Callable[[int], Run],
|
239
256
|
get_fab: Callable[[str, int], Fab],
|
257
|
+
pull_object: Callable[[int, str], bytes], # pylint: disable=W0613
|
258
|
+
confirm_message_received: Callable[[int, str], None], # pylint: disable=W0613
|
240
259
|
) -> Optional[int]:
|
241
260
|
"""Pull a message from the SuperLink and store it in the state.
|
242
261
|
|
@@ -325,7 +344,9 @@ def _pull_and_store_message( # pylint: disable=too-many-positional-arguments
|
|
325
344
|
|
326
345
|
def _push_messages(
|
327
346
|
state: NodeState,
|
347
|
+
store: ObjectStore, # pylint: disable=W0613
|
328
348
|
send: Callable[[Message], None],
|
349
|
+
push_object: Callable[[int, str, bytes], None], # pylint: disable=W0613
|
329
350
|
) -> None:
|
330
351
|
"""Push reply messages to the SuperLink."""
|
331
352
|
# Get messages to send
|
@@ -389,6 +410,9 @@ def _init_connection( # pylint: disable=too-many-positional-arguments
|
|
389
410
|
Callable[[], None],
|
390
411
|
Callable[[int], Run],
|
391
412
|
Callable[[str, int], Fab],
|
413
|
+
Callable[[int, str], bytes],
|
414
|
+
Callable[[int, str, bytes], None],
|
415
|
+
Callable[[int, str], None],
|
392
416
|
]
|
393
417
|
]:
|
394
418
|
"""Establish a connection to the Fleet API server at SuperLink."""
|
{flwr_nightly-1.20.0.dev20250718.dist-info → flwr_nightly-1.20.0.dev20250720.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: flwr-nightly
|
3
|
-
Version: 1.20.0.
|
3
|
+
Version: 1.20.0.dev20250720
|
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
|
{flwr_nightly-1.20.0.dev20250718.dist-info → flwr_nightly-1.20.0.dev20250720.dist-info}/RECORD
RENAMED
@@ -6,7 +6,7 @@ flwr/cli/__init__.py,sha256=EfMGmHoobET6P2blBt_eOByXL8299MgFfB7XNdaPQ6I,720
|
|
6
6
|
flwr/cli/app.py,sha256=AKCP45Dkbpvdil_4Ir9S93L3HP3iUOnHmcZjscoM8uU,1856
|
7
7
|
flwr/cli/auth_plugin/__init__.py,sha256=FyaoqPzcxlBTFfJ2sBRC5USwQLmAhFr5KuBwfMO4bmo,1052
|
8
8
|
flwr/cli/auth_plugin/oidc_cli_plugin.py,sha256=gIhW6Jg9QAo-jL43LYPpw_kn7pdUZZae0s0H8dEgjLM,5384
|
9
|
-
flwr/cli/build.py,sha256=
|
9
|
+
flwr/cli/build.py,sha256=hE54Q_eMdWLpVKSVC2aQaUxVaiUlWnAosGNvIPSEg6Y,7284
|
10
10
|
flwr/cli/cli_user_auth_interceptor.py,sha256=-JqDXpeZNQVwoSG7hMKsiS5qY5k5oklNSlQOVpM0-aY,3126
|
11
11
|
flwr/cli/config_utils.py,sha256=IAVn2uWTXpN72YYt7raLtwp8ziwZugUKSURpc471VzU,9123
|
12
12
|
flwr/cli/constant.py,sha256=g7Ad7o3DJDkJNrWS0T3SSJETWSTkkVJWGpLM8zlbpcY,1289
|
@@ -81,10 +81,10 @@ flwr/client/clientapp/__init__.py,sha256=Zw9qP5nHFnJ9K1dcR4cdY0fRqN-FaMYFSHJFXoF
|
|
81
81
|
flwr/client/clientapp/utils.py,sha256=LsiW1OL2VPcjom3xN29pgBQC0UrttQ-xWL_GF1fkKDo,4344
|
82
82
|
flwr/client/dpfedavg_numpy_client.py,sha256=3hul067cT2E9jBhzp7bFnFAZ_D2nWcIUEdHYE05FpzU,7404
|
83
83
|
flwr/client/grpc_adapter_client/__init__.py,sha256=RQWP5mFPROLHKgombiRvPXVWSoVrQ81wvZm0-lOuuBA,742
|
84
|
-
flwr/client/grpc_adapter_client/connection.py,sha256=
|
84
|
+
flwr/client/grpc_adapter_client/connection.py,sha256=GnEGIejz8QFlmldQUXrFQ3Rle1wHroJOCVoYIT5V1Og,4223
|
85
85
|
flwr/client/grpc_rere_client/__init__.py,sha256=i7iS0Lt8B7q0E2L72e4F_YrKm6ClRKnd71PNA6PW2O0,752
|
86
86
|
flwr/client/grpc_rere_client/client_interceptor.py,sha256=zFaVHw6AxeNO-7eCKKb-RxrPa7zbM5Z-2-1Efc4adQY,2451
|
87
|
-
flwr/client/grpc_rere_client/connection.py,sha256=
|
87
|
+
flwr/client/grpc_rere_client/connection.py,sha256=mfbaS2IZwd5vZ3whmy6XRb4c8kKzRLlbWy8SsG74LJU,15460
|
88
88
|
flwr/client/grpc_rere_client/grpc_adapter.py,sha256=dLGB5GriszAmtgvuFGuz_F7rIwpzLfDxhJ7T3Un-Ce0,6694
|
89
89
|
flwr/client/message_handler/__init__.py,sha256=0lyljDVqre3WljiZbPcwCCf8GiIaSVI_yo_ylEyPwSE,719
|
90
90
|
flwr/client/message_handler/message_handler.py,sha256=X9SXX6et97Lw9_DGD93HKsEBGNjXClcFgc_5aLK0oiU,6541
|
@@ -98,7 +98,7 @@ flwr/client/mod/secure_aggregation/secaggplus_mod.py,sha256=aKqjZCrikF73y3E-7h40
|
|
98
98
|
flwr/client/mod/utils.py,sha256=FUgD2TfcWqSeF6jUKZ4i6Ke56U4Nrv85AeVb93s6R9g,1201
|
99
99
|
flwr/client/numpy_client.py,sha256=Qq6ghsIAop2slKqAfgiI5NiHJ4LIxGmrik3Ror4_XVc,9581
|
100
100
|
flwr/client/rest_client/__init__.py,sha256=MBiuK62hj439m9rtwSwI184Hth6Tt5GbmpNMyl3zkZY,735
|
101
|
-
flwr/client/rest_client/connection.py,sha256=
|
101
|
+
flwr/client/rest_client/connection.py,sha256=nmmC3D3CB2SQKd-emQD1uVnqoUS-qHmteNlmBgZwGqs,18521
|
102
102
|
flwr/client/run_info_store.py,sha256=MaJ3UQ-07hWtK67wnWu0zR29jrk0fsfgJX506dvEOfE,4042
|
103
103
|
flwr/client/typing.py,sha256=Jw3rawDzI_-ZDcRmEQcs5gZModY7oeQlEeltYsdOhlU,1048
|
104
104
|
flwr/clientapp/__init__.py,sha256=zGW4z49Ojzoi1hDiRC7kyhLjijUilc6fqHhtM_ATRVA,719
|
@@ -124,7 +124,7 @@ flwr/common/grpc.py,sha256=y70hUFvXkIf3l03xOhlb7qhS6W1UJZRSZqCdB0ir0v8,10381
|
|
124
124
|
flwr/common/heartbeat.py,sha256=SyEpNDnmJ0lni0cWO67rcoJVKasCLmkNHm3dKLeNrLU,5749
|
125
125
|
flwr/common/inflatable.py,sha256=GDL9oBKs16_yyVdlH6kBf493O5xll_h9V7XB5Mpx1Hc,9524
|
126
126
|
flwr/common/inflatable_protobuf_utils.py,sha256=JtRqp-fV47goDM2y8JRQ7AmwwjeGaWexwoMWLcxX5gE,5056
|
127
|
-
flwr/common/inflatable_utils.py,sha256=
|
127
|
+
flwr/common/inflatable_utils.py,sha256=tYNrsdUWIw94p1oBPojg2wlD_-tnspWU2tbmIRafB6U,17401
|
128
128
|
flwr/common/logger.py,sha256=JbRf6E2vQxXzpDBq1T8IDUJo_usu3gjWEBPQ6uKcmdg,13049
|
129
129
|
flwr/common/message.py,sha256=xAL7iZN5-n-xPQpgoSFvxNrzs8fmiiPfoU0DjNQEhRw,19953
|
130
130
|
flwr/common/object_ref.py,sha256=p3SfTeqo3Aj16SkB-vsnNn01zswOPdGNBitcbRnqmUk,9134
|
@@ -289,7 +289,7 @@ flwr/server/superlink/fleet/grpc_rere/__init__.py,sha256=ahDJJ1e-lDxBpeBMgPk7YZt
|
|
289
289
|
flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py,sha256=X7-z4oReIH5ghMfmMXML3SSpa2bhRsuIvt2OZs82BUk,8675
|
290
290
|
flwr/server/superlink/fleet/grpc_rere/server_interceptor.py,sha256=9_RaYWMqFdpFi8QcE7Nv8-pRjWJ2dLHxezrwhd1tAYk,6845
|
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=
|
292
|
+
flwr/server/superlink/fleet/message_handler/message_handler.py,sha256=3Wg20bFo1tZfkzTQUerPVSHXyOuUqNuitEib3W_Dy-U,8691
|
293
293
|
flwr/server/superlink/fleet/rest_rere/__init__.py,sha256=Lzc93nA7tDqoy-zRUaPG316oqFiZX1HUCL5ELaXY_xw,735
|
294
294
|
flwr/server/superlink/fleet/rest_rere/rest_api.py,sha256=mxWKwGpgHPqd7cGFqd2ASnR-KZduIzLfT-d2yiNCqQ0,9257
|
295
295
|
flwr/server/superlink/fleet/vce/__init__.py,sha256=XOKbAWOzlCqEOQ3M2cBYkH7HKA7PxlbCJMunt-ty-DY,784
|
@@ -305,7 +305,7 @@ flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=E699Ak0jMF3N7i1SIeFRu
|
|
305
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=zcvzDhCAnlFxAwCiJUHNm6IE7-rk5jeZqSmPgjEY3AU,2307
|
308
|
-
flwr/server/superlink/serverappio/serverappio_servicer.py,sha256=
|
308
|
+
flwr/server/superlink/serverappio/serverappio_servicer.py,sha256=m0c05XQwRWwymOqbVYWDuDKRryIT3PxGhB8OM6YPyaM,18253
|
309
309
|
flwr/server/superlink/simulation/__init__.py,sha256=Ry8DrNaZCMcQXvUc4FoCN2m3dvUQgWjasfp015o3Ec4,718
|
310
310
|
flwr/server/superlink/simulation/simulationio_grpc.py,sha256=VqWKxjpd4bCgPFKsgtIZPk9YcG0kc1EEmr5k20EKty4,2205
|
311
311
|
flwr/server/superlink/simulation/simulationio_servicer.py,sha256=m1T1zvEn81jlfx9hVTqmeWxAu6APCS2YW8l5O0OQvhU,7724
|
@@ -343,6 +343,7 @@ flwr/supercore/object_store/__init__.py,sha256=cdfPAmjINY6iOp8oI_LdcVh2simg469Mk
|
|
343
343
|
flwr/supercore/object_store/in_memory_object_store.py,sha256=CGY43syxDGrUPcdOzRH3hNrfeqmoTOY_wjo3qaAHuNk,9612
|
344
344
|
flwr/supercore/object_store/object_store.py,sha256=wC6Pxq89a7FwmIMJE3ZLPPy2i7Gdss7-8RUapECCAPY,5099
|
345
345
|
flwr/supercore/object_store/object_store_factory.py,sha256=QVwE2ywi7vsj2iKfvWWnNw3N_I7Rz91NUt2RpcbJ7iM,1527
|
346
|
+
flwr/supercore/object_store/utils.py,sha256=-WwBa6ejMNm9ahmNZP39IHutS0cwingmeqCoxTmATQM,1845
|
346
347
|
flwr/supercore/utils.py,sha256=ebuHMbeA8eXisX0oMPqBK3hk7uVnIE_yiqWVz8YbkpQ,1324
|
347
348
|
flwr/superexec/__init__.py,sha256=YFqER0IJc1XEWfsX6AxZ9LSRq0sawPYrNYki-brvTIc,715
|
348
349
|
flwr/superexec/app.py,sha256=U2jjOHb2LGWoU7vrl9_czTzre9O2mPxu3CPGUZ86sK4,1465
|
@@ -364,12 +365,12 @@ flwr/supernode/nodestate/in_memory_nodestate.py,sha256=LF3AbaW0bcZHY5yKWwUJSU2RZ
|
|
364
365
|
flwr/supernode/nodestate/nodestate.py,sha256=kkGFxYnLIwT4-UmlPnf6HvAUpPey2urUNrweGybAIY4,6398
|
365
366
|
flwr/supernode/nodestate/nodestate_factory.py,sha256=UYTDCcwK_baHUmkzkJDxL0UEqvtTfOMlQRrROMCd0Xo,1430
|
366
367
|
flwr/supernode/runtime/__init__.py,sha256=JQdqd2EMTn-ORMeTvewYYh52ls0YKP68jrps1qioxu4,718
|
367
|
-
flwr/supernode/runtime/run_clientapp.py,sha256=
|
368
|
+
flwr/supernode/runtime/run_clientapp.py,sha256=YI7su6aJDqIOvBUe4byLx05Us-wqLFSqIqoDWKSnCBM,10676
|
368
369
|
flwr/supernode/servicer/__init__.py,sha256=lucTzre5WPK7G1YLCfaqg3rbFWdNSb7ZTt-ca8gxdEo,717
|
369
370
|
flwr/supernode/servicer/clientappio/__init__.py,sha256=7Oy62Y_oijqF7Dxi6tpcUQyOpLc_QpIRZ83NvwmB0Yg,813
|
370
|
-
flwr/supernode/servicer/clientappio/clientappio_servicer.py,sha256=
|
371
|
-
flwr/supernode/start_client_internal.py,sha256=
|
372
|
-
flwr_nightly-1.20.0.
|
373
|
-
flwr_nightly-1.20.0.
|
374
|
-
flwr_nightly-1.20.0.
|
375
|
-
flwr_nightly-1.20.0.
|
371
|
+
flwr/supernode/servicer/clientappio/clientappio_servicer.py,sha256=SOx719uqdkIHryBri-XpuYpALQE__hxNtDjSAdeUtug,10059
|
372
|
+
flwr/supernode/start_client_internal.py,sha256=na3wQ5Ny-eDSsKKeN87guD0bTjfH4XugKDYhcmU23qI,19531
|
373
|
+
flwr_nightly-1.20.0.dev20250720.dist-info/METADATA,sha256=n-8GKATRVeEv833raNa0eqHt4C17AnBgeBkIv1_6teY,15966
|
374
|
+
flwr_nightly-1.20.0.dev20250720.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
375
|
+
flwr_nightly-1.20.0.dev20250720.dist-info/entry_points.txt,sha256=jNpDXGBGgs21RqUxelF_jwGaxtqFwm-MQyfz-ZqSjrA,367
|
376
|
+
flwr_nightly-1.20.0.dev20250720.dist-info/RECORD,,
|
{flwr_nightly-1.20.0.dev20250718.dist-info → flwr_nightly-1.20.0.dev20250720.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|