flwr-nightly 1.21.0.dev20250812__py3-none-any.whl → 1.21.0.dev20250813__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/common/args.py +13 -0
- flwr/proto/simulationio_pb2.py +2 -2
- flwr/proto/simulationio_pb2_grpc.py +34 -0
- flwr/proto/simulationio_pb2_grpc.pyi +13 -0
- flwr/server/app.py +16 -94
- flwr/server/serverapp/app.py +1 -14
- flwr/server/superlink/simulation/simulationio_servicer.py +42 -6
- flwr/simulation/app.py +23 -10
- flwr/supercore/app_utils.py +4 -1
- flwr/supernode/cli/flwr_clientapp.py +0 -13
- flwr/supernode/start_client_internal.py +10 -31
- {flwr_nightly-1.21.0.dev20250812.dist-info → flwr_nightly-1.21.0.dev20250813.dist-info}/METADATA +4 -3
- {flwr_nightly-1.21.0.dev20250812.dist-info → flwr_nightly-1.21.0.dev20250813.dist-info}/RECORD +15 -15
- {flwr_nightly-1.21.0.dev20250812.dist-info → flwr_nightly-1.21.0.dev20250813.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.21.0.dev20250812.dist-info → flwr_nightly-1.21.0.dev20250813.dist-info}/entry_points.txt +0 -0
flwr/common/args.py
CHANGED
@@ -28,6 +28,12 @@ from flwr.common.logger import log
|
|
28
28
|
|
29
29
|
def add_args_flwr_app_common(parser: argparse.ArgumentParser) -> None:
|
30
30
|
"""Add common Flower arguments for flwr-*app to the provided parser."""
|
31
|
+
parser.add_argument(
|
32
|
+
"--token",
|
33
|
+
type=str,
|
34
|
+
required=False,
|
35
|
+
help="Unique token generated by AppIo API for each app execution",
|
36
|
+
)
|
31
37
|
parser.add_argument(
|
32
38
|
"--flwr-dir",
|
33
39
|
default=None,
|
@@ -47,6 +53,13 @@ def add_args_flwr_app_common(parser: argparse.ArgumentParser) -> None:
|
|
47
53
|
"is not encrypted. By default, the server runs with HTTPS enabled. "
|
48
54
|
"Use this flag only if you understand the risks.",
|
49
55
|
)
|
56
|
+
parser.add_argument(
|
57
|
+
"--parent-pid",
|
58
|
+
type=int,
|
59
|
+
default=None,
|
60
|
+
help="The PID of the parent process. When set, the process will terminate "
|
61
|
+
"when the parent process exits.",
|
62
|
+
)
|
50
63
|
|
51
64
|
|
52
65
|
def try_obtain_root_certificates(
|
flwr/proto/simulationio_pb2.py
CHANGED
@@ -20,7 +20,7 @@ from flwr.proto import fab_pb2 as flwr_dot_proto_dot_fab__pb2
|
|
20
20
|
from flwr.proto import appio_pb2 as flwr_dot_proto_dot_appio__pb2
|
21
21
|
|
22
22
|
|
23
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1d\x66lwr/proto/simulationio.proto\x12\nflwr.proto\x1a\x1a\x66lwr/proto/heartbeat.proto\x1a\x14\x66lwr/proto/log.proto\x1a\x18\x66lwr/proto/message.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x16\x66lwr/proto/appio.proto2\
|
23
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1d\x66lwr/proto/simulationio.proto\x12\nflwr.proto\x1a\x1a\x66lwr/proto/heartbeat.proto\x1a\x14\x66lwr/proto/log.proto\x1a\x18\x66lwr/proto/message.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x16\x66lwr/proto/appio.proto2\x84\x07\n\x0cSimulationIo\x12_\n\x10ListAppsToLaunch\x12#.flwr.proto.ListAppsToLaunchRequest\x1a$.flwr.proto.ListAppsToLaunchResponse\"\x00\x12S\n\x0cRequestToken\x12\x1f.flwr.proto.RequestTokenRequest\x1a .flwr.proto.RequestTokenResponse\"\x00\x12\x41\n\x06GetRun\x12\x19.flwr.proto.GetRunRequest\x1a\x1a.flwr.proto.GetRunResponse\"\x00\x12V\n\rPullAppInputs\x12 .flwr.proto.PullAppInputsRequest\x1a!.flwr.proto.PullAppInputsResponse\"\x00\x12Y\n\x0ePushAppOutputs\x12!.flwr.proto.PushAppOutputsRequest\x1a\".flwr.proto.PushAppOutputsResponse\"\x00\x12\\\n\x0fUpdateRunStatus\x12\".flwr.proto.UpdateRunStatusRequest\x1a#.flwr.proto.UpdateRunStatusResponse\"\x00\x12G\n\x08PushLogs\x12\x1b.flwr.proto.PushLogsRequest\x1a\x1c.flwr.proto.PushLogsResponse\"\x00\x12k\n\x14GetFederationOptions\x12\'.flwr.proto.GetFederationOptionsRequest\x1a(.flwr.proto.GetFederationOptionsResponse\"\x00\x12S\n\x0cGetRunStatus\x12\x1f.flwr.proto.GetRunStatusRequest\x1a .flwr.proto.GetRunStatusResponse\"\x00\x12_\n\x10SendAppHeartbeat\x12#.flwr.proto.SendAppHeartbeatRequest\x1a$.flwr.proto.SendAppHeartbeatResponse\"\x00\x62\x06proto3')
|
24
24
|
|
25
25
|
_globals = globals()
|
26
26
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
@@ -28,5 +28,5 @@ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flwr.proto.simulationio_pb2
|
|
28
28
|
if _descriptor._USE_C_DESCRIPTORS == False:
|
29
29
|
DESCRIPTOR._options = None
|
30
30
|
_globals['_SIMULATIONIO']._serialized_start=190
|
31
|
-
_globals['_SIMULATIONIO']._serialized_end=
|
31
|
+
_globals['_SIMULATIONIO']._serialized_end=1090
|
32
32
|
# @@protoc_insertion_point(module_scope)
|
@@ -27,6 +27,11 @@ class SimulationIoStub(object):
|
|
27
27
|
request_serializer=flwr_dot_proto_dot_appio__pb2.RequestTokenRequest.SerializeToString,
|
28
28
|
response_deserializer=flwr_dot_proto_dot_appio__pb2.RequestTokenResponse.FromString,
|
29
29
|
)
|
30
|
+
self.GetRun = channel.unary_unary(
|
31
|
+
'/flwr.proto.SimulationIo/GetRun',
|
32
|
+
request_serializer=flwr_dot_proto_dot_run__pb2.GetRunRequest.SerializeToString,
|
33
|
+
response_deserializer=flwr_dot_proto_dot_run__pb2.GetRunResponse.FromString,
|
34
|
+
)
|
30
35
|
self.PullAppInputs = channel.unary_unary(
|
31
36
|
'/flwr.proto.SimulationIo/PullAppInputs',
|
32
37
|
request_serializer=flwr_dot_proto_dot_appio__pb2.PullAppInputsRequest.SerializeToString,
|
@@ -81,6 +86,13 @@ class SimulationIoServicer(object):
|
|
81
86
|
context.set_details('Method not implemented!')
|
82
87
|
raise NotImplementedError('Method not implemented!')
|
83
88
|
|
89
|
+
def GetRun(self, request, context):
|
90
|
+
"""Get run details
|
91
|
+
"""
|
92
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
93
|
+
context.set_details('Method not implemented!')
|
94
|
+
raise NotImplementedError('Method not implemented!')
|
95
|
+
|
84
96
|
def PullAppInputs(self, request, context):
|
85
97
|
"""Pull Simulation inputs
|
86
98
|
"""
|
@@ -143,6 +155,11 @@ def add_SimulationIoServicer_to_server(servicer, server):
|
|
143
155
|
request_deserializer=flwr_dot_proto_dot_appio__pb2.RequestTokenRequest.FromString,
|
144
156
|
response_serializer=flwr_dot_proto_dot_appio__pb2.RequestTokenResponse.SerializeToString,
|
145
157
|
),
|
158
|
+
'GetRun': grpc.unary_unary_rpc_method_handler(
|
159
|
+
servicer.GetRun,
|
160
|
+
request_deserializer=flwr_dot_proto_dot_run__pb2.GetRunRequest.FromString,
|
161
|
+
response_serializer=flwr_dot_proto_dot_run__pb2.GetRunResponse.SerializeToString,
|
162
|
+
),
|
146
163
|
'PullAppInputs': grpc.unary_unary_rpc_method_handler(
|
147
164
|
servicer.PullAppInputs,
|
148
165
|
request_deserializer=flwr_dot_proto_dot_appio__pb2.PullAppInputsRequest.FromString,
|
@@ -222,6 +239,23 @@ class SimulationIo(object):
|
|
222
239
|
options, channel_credentials,
|
223
240
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
224
241
|
|
242
|
+
@staticmethod
|
243
|
+
def GetRun(request,
|
244
|
+
target,
|
245
|
+
options=(),
|
246
|
+
channel_credentials=None,
|
247
|
+
call_credentials=None,
|
248
|
+
insecure=False,
|
249
|
+
compression=None,
|
250
|
+
wait_for_ready=None,
|
251
|
+
timeout=None,
|
252
|
+
metadata=None):
|
253
|
+
return grpc.experimental.unary_unary(request, target, '/flwr.proto.SimulationIo/GetRun',
|
254
|
+
flwr_dot_proto_dot_run__pb2.GetRunRequest.SerializeToString,
|
255
|
+
flwr_dot_proto_dot_run__pb2.GetRunResponse.FromString,
|
256
|
+
options, channel_credentials,
|
257
|
+
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
258
|
+
|
225
259
|
@staticmethod
|
226
260
|
def PullAppInputs(request,
|
227
261
|
target,
|
@@ -21,6 +21,11 @@ class SimulationIoStub:
|
|
21
21
|
flwr.proto.appio_pb2.RequestTokenResponse]
|
22
22
|
"""Request token for a run"""
|
23
23
|
|
24
|
+
GetRun: grpc.UnaryUnaryMultiCallable[
|
25
|
+
flwr.proto.run_pb2.GetRunRequest,
|
26
|
+
flwr.proto.run_pb2.GetRunResponse]
|
27
|
+
"""Get run details"""
|
28
|
+
|
24
29
|
PullAppInputs: grpc.UnaryUnaryMultiCallable[
|
25
30
|
flwr.proto.appio_pb2.PullAppInputsRequest,
|
26
31
|
flwr.proto.appio_pb2.PullAppInputsResponse]
|
@@ -74,6 +79,14 @@ class SimulationIoServicer(metaclass=abc.ABCMeta):
|
|
74
79
|
"""Request token for a run"""
|
75
80
|
pass
|
76
81
|
|
82
|
+
@abc.abstractmethod
|
83
|
+
def GetRun(self,
|
84
|
+
request: flwr.proto.run_pb2.GetRunRequest,
|
85
|
+
context: grpc.ServicerContext,
|
86
|
+
) -> flwr.proto.run_pb2.GetRunResponse:
|
87
|
+
"""Get run details"""
|
88
|
+
pass
|
89
|
+
|
77
90
|
@abc.abstractmethod
|
78
91
|
def PullAppInputs(self,
|
79
92
|
request: flwr.proto.appio_pb2.PullAppInputsRequest,
|
flwr/server/app.py
CHANGED
@@ -18,9 +18,8 @@
|
|
18
18
|
import argparse
|
19
19
|
import csv
|
20
20
|
import importlib.util
|
21
|
-
import multiprocessing
|
22
|
-
import multiprocessing.context
|
23
21
|
import os
|
22
|
+
import subprocess
|
24
23
|
import sys
|
25
24
|
import threading
|
26
25
|
from collections.abc import Sequence
|
@@ -55,6 +54,7 @@ from flwr.common.constant import (
|
|
55
54
|
TRANSPORT_TYPE_GRPC_RERE,
|
56
55
|
TRANSPORT_TYPE_REST,
|
57
56
|
EventLogWriterType,
|
57
|
+
ExecPluginType,
|
58
58
|
)
|
59
59
|
from flwr.common.event_log_plugin import EventLogWriterPlugin
|
60
60
|
from flwr.common.exit import ExitCode, flwr_exit
|
@@ -69,8 +69,6 @@ from flwr.proto.fleet_pb2_grpc import ( # pylint: disable=E0611
|
|
69
69
|
)
|
70
70
|
from flwr.proto.grpcadapter_pb2_grpc import add_GrpcAdapterServicer_to_server
|
71
71
|
from flwr.server.fleet_event_log_interceptor import FleetEventLogInterceptor
|
72
|
-
from flwr.server.serverapp.app import flwr_serverapp
|
73
|
-
from flwr.simulation.app import flwr_simulation
|
74
72
|
from flwr.supercore.ffs import FfsFactory
|
75
73
|
from flwr.supercore.object_store import ObjectStoreFactory
|
76
74
|
from flwr.superlink.executor import load_executor
|
@@ -219,10 +217,10 @@ def run_superlink() -> None:
|
|
219
217
|
|
220
218
|
# Determine Exec plugin
|
221
219
|
# If simulation is used, don't start ServerAppIo and Fleet APIs
|
222
|
-
|
220
|
+
is_simulation = executor.__class__.__qualname__ == "SimulationEngine"
|
223
221
|
bckg_threads: list[threading.Thread] = []
|
224
222
|
|
225
|
-
if
|
223
|
+
if is_simulation:
|
226
224
|
simulationio_server: grpc.Server = run_simulationio_api_grpc(
|
227
225
|
address=simulationio_address,
|
228
226
|
state_factory=state_factory,
|
@@ -340,25 +338,18 @@ def run_superlink() -> None:
|
|
340
338
|
io_address = (
|
341
339
|
f"{CLIENT_OCTET}:{_port}" if _octet == SERVER_OCTET else serverappio_address
|
342
340
|
)
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
address,
|
356
|
-
cmd,
|
357
|
-
),
|
358
|
-
daemon=True,
|
359
|
-
)
|
360
|
-
scheduler_th.start()
|
361
|
-
bckg_threads.append(scheduler_th)
|
341
|
+
command = ["flower-superexec", "--insecure"]
|
342
|
+
command += [
|
343
|
+
"--appio-api-address",
|
344
|
+
simulationio_address if is_simulation else io_address,
|
345
|
+
]
|
346
|
+
command += [
|
347
|
+
"--plugin-type",
|
348
|
+
ExecPluginType.SIMULATION if is_simulation else ExecPluginType.SERVER_APP,
|
349
|
+
]
|
350
|
+
command += ["--parent-pid", str(os.getpid())]
|
351
|
+
# pylint: disable-next=consider-using-with
|
352
|
+
subprocess.Popen(command)
|
362
353
|
|
363
354
|
# Graceful shutdown
|
364
355
|
register_exit_handlers(
|
@@ -376,75 +367,6 @@ def run_superlink() -> None:
|
|
376
367
|
flwr_exit(ExitCode.SUPERLINK_THREAD_CRASH)
|
377
368
|
|
378
369
|
|
379
|
-
def _run_flwr_command(args: list[str], main_pid: int) -> None:
|
380
|
-
# Monitor the main process in case of SIGKILL
|
381
|
-
def main_process_monitor() -> None:
|
382
|
-
while True:
|
383
|
-
sleep(1)
|
384
|
-
if os.getppid() != main_pid:
|
385
|
-
os.kill(os.getpid(), 9)
|
386
|
-
|
387
|
-
threading.Thread(target=main_process_monitor, daemon=True).start()
|
388
|
-
|
389
|
-
# Run the command
|
390
|
-
sys.argv = args
|
391
|
-
if args[0] == "flwr-serverapp":
|
392
|
-
flwr_serverapp()
|
393
|
-
elif args[0] == "flwr-simulation":
|
394
|
-
flwr_simulation()
|
395
|
-
else:
|
396
|
-
raise ValueError(f"Unknown command: {args[0]}")
|
397
|
-
|
398
|
-
|
399
|
-
def _flwr_scheduler(
|
400
|
-
state_factory: LinkStateFactory,
|
401
|
-
io_api_arg: str,
|
402
|
-
io_api_address: str,
|
403
|
-
cmd: str,
|
404
|
-
) -> None:
|
405
|
-
log(DEBUG, "Started %s scheduler thread.", cmd)
|
406
|
-
state = state_factory.state()
|
407
|
-
run_id_to_proc: dict[int, multiprocessing.context.SpawnProcess] = {}
|
408
|
-
|
409
|
-
# Use the "spawn" start method for multiprocessing.
|
410
|
-
mp_spawn_context = multiprocessing.get_context("spawn")
|
411
|
-
|
412
|
-
# Periodically check for a pending run in the LinkState
|
413
|
-
while True:
|
414
|
-
sleep(0.1)
|
415
|
-
pending_run_id = state.get_pending_run_id()
|
416
|
-
|
417
|
-
if pending_run_id and pending_run_id not in run_id_to_proc:
|
418
|
-
|
419
|
-
log(
|
420
|
-
INFO,
|
421
|
-
"Launching %s subprocess. Connects to SuperLink on %s",
|
422
|
-
cmd,
|
423
|
-
io_api_address,
|
424
|
-
)
|
425
|
-
# Start subprocess
|
426
|
-
command = [
|
427
|
-
cmd,
|
428
|
-
"--run-once",
|
429
|
-
io_api_arg,
|
430
|
-
io_api_address,
|
431
|
-
"--insecure",
|
432
|
-
]
|
433
|
-
|
434
|
-
proc = mp_spawn_context.Process(
|
435
|
-
target=_run_flwr_command, args=(command, os.getpid()), daemon=True
|
436
|
-
)
|
437
|
-
proc.start()
|
438
|
-
|
439
|
-
# Store the process
|
440
|
-
run_id_to_proc[pending_run_id] = proc
|
441
|
-
|
442
|
-
# Clean up finished processes
|
443
|
-
for run_id, proc in list(run_id_to_proc.items()):
|
444
|
-
if not proc.is_alive():
|
445
|
-
del run_id_to_proc[run_id]
|
446
|
-
|
447
|
-
|
448
370
|
def _format_address(address: str) -> tuple[str, str, int]:
|
449
371
|
parsed_address = parse_address(address)
|
450
372
|
if not parsed_address:
|
flwr/server/serverapp/app.py
CHANGED
@@ -92,7 +92,7 @@ def flwr_serverapp() -> None:
|
|
92
92
|
serverappio_api_address=args.serverappio_api_address,
|
93
93
|
log_queue=log_queue,
|
94
94
|
token=args.token,
|
95
|
-
run_once=args.run_once,
|
95
|
+
run_once=(args.token is not None) or args.run_once,
|
96
96
|
flwr_dir=args.flwr_dir,
|
97
97
|
certificates=None,
|
98
98
|
parent_pid=args.parent_pid,
|
@@ -287,19 +287,6 @@ def _parse_args_run_flwr_serverapp() -> argparse.ArgumentParser:
|
|
287
287
|
help="Address of SuperLink's ServerAppIo API (IPv4, IPv6, or a domain name)."
|
288
288
|
f"By default, it is set to {SERVERAPPIO_API_DEFAULT_CLIENT_ADDRESS}.",
|
289
289
|
)
|
290
|
-
parser.add_argument(
|
291
|
-
"--token",
|
292
|
-
type=str,
|
293
|
-
required=False,
|
294
|
-
help="Unique token generated by SuperNode for each ServerApp execution",
|
295
|
-
)
|
296
|
-
parser.add_argument(
|
297
|
-
"--parent-pid",
|
298
|
-
type=int,
|
299
|
-
default=None,
|
300
|
-
help="The PID of the parent process. When set, the process will terminate "
|
301
|
-
"when the parent process exits.",
|
302
|
-
)
|
303
290
|
parser.add_argument(
|
304
291
|
"--run-once",
|
305
292
|
action="store_true",
|
@@ -55,6 +55,8 @@ from flwr.proto.log_pb2 import ( # pylint: disable=E0611
|
|
55
55
|
from flwr.proto.run_pb2 import ( # pylint: disable=E0611
|
56
56
|
GetFederationOptionsRequest,
|
57
57
|
GetFederationOptionsResponse,
|
58
|
+
GetRunRequest,
|
59
|
+
GetRunResponse,
|
58
60
|
GetRunStatusRequest,
|
59
61
|
GetRunStatusResponse,
|
60
62
|
UpdateRunStatusRequest,
|
@@ -111,6 +113,23 @@ class SimulationIoServicer(simulationio_pb2_grpc.SimulationIoServicer):
|
|
111
113
|
# Return the token
|
112
114
|
return RequestTokenResponse(token=token or "")
|
113
115
|
|
116
|
+
def GetRun(
|
117
|
+
self, request: GetRunRequest, context: grpc.ServicerContext
|
118
|
+
) -> GetRunResponse:
|
119
|
+
"""Get run information."""
|
120
|
+
log(DEBUG, "SimulationIoServicer.GetRun")
|
121
|
+
|
122
|
+
# Init state
|
123
|
+
state = self.state_factory.state()
|
124
|
+
|
125
|
+
# Retrieve run information
|
126
|
+
run = state.get_run(request.run_id)
|
127
|
+
|
128
|
+
if run is None:
|
129
|
+
return GetRunResponse()
|
130
|
+
|
131
|
+
return GetRunResponse(run=run_to_proto(run))
|
132
|
+
|
114
133
|
def PullAppInputs(
|
115
134
|
self, request: PullAppInputsRequest, context: ServicerContext
|
116
135
|
) -> PullAppInputsResponse:
|
@@ -120,14 +139,11 @@ class SimulationIoServicer(simulationio_pb2_grpc.SimulationIoServicer):
|
|
120
139
|
state = self.state_factory.state()
|
121
140
|
ffs = self.ffs_factory.ffs()
|
122
141
|
|
142
|
+
# Validate the token
|
143
|
+
run_id = self._verify_token(request.token, context)
|
144
|
+
|
123
145
|
# Lock access to LinkState, preventing obtaining the same pending run_id
|
124
146
|
with self.lock:
|
125
|
-
# Attempt getting the run_id of a pending run
|
126
|
-
run_id = state.get_pending_run_id()
|
127
|
-
# If there's no pending run, return an empty response
|
128
|
-
if run_id is None:
|
129
|
-
return PullAppInputsResponse()
|
130
|
-
|
131
147
|
# Retrieve Context, Run and Fab for the run_id
|
132
148
|
serverapp_ctxt = state.get_serverapp_context(run_id)
|
133
149
|
run = state.get_run(run_id)
|
@@ -154,6 +170,11 @@ class SimulationIoServicer(simulationio_pb2_grpc.SimulationIoServicer):
|
|
154
170
|
) -> PushAppOutputsResponse:
|
155
171
|
"""Push Simulation process outputs."""
|
156
172
|
log(DEBUG, "SimultionIoServicer.PushAppOutputs")
|
173
|
+
|
174
|
+
# Validate the token
|
175
|
+
run_id = self._verify_token(request.token, context)
|
176
|
+
|
177
|
+
# Init access to LinkState
|
157
178
|
state = self.state_factory.state()
|
158
179
|
|
159
180
|
# Abort if the run is not running
|
@@ -166,6 +187,9 @@ class SimulationIoServicer(simulationio_pb2_grpc.SimulationIoServicer):
|
|
166
187
|
)
|
167
188
|
|
168
189
|
state.set_serverapp_context(request.run_id, context_from_proto(request.context))
|
190
|
+
|
191
|
+
# Remove the token
|
192
|
+
state.delete_token(run_id)
|
169
193
|
return PushAppOutputsResponse()
|
170
194
|
|
171
195
|
def UpdateRunStatus(
|
@@ -248,3 +272,15 @@ class SimulationIoServicer(simulationio_pb2_grpc.SimulationIoServicer):
|
|
248
272
|
)
|
249
273
|
|
250
274
|
return SendAppHeartbeatResponse(success=success)
|
275
|
+
|
276
|
+
def _verify_token(self, token: str, context: grpc.ServicerContext) -> int:
|
277
|
+
"""Verify the token and return the associated run ID."""
|
278
|
+
state = self.state_factory.state()
|
279
|
+
run_id = state.get_run_id_by_token(token)
|
280
|
+
if run_id is None or not state.verify_token(run_id, token):
|
281
|
+
context.abort(
|
282
|
+
grpc.StatusCode.PERMISSION_DENIED,
|
283
|
+
"Invalid token.",
|
284
|
+
)
|
285
|
+
raise RuntimeError("This line should never be reached.")
|
286
|
+
return run_id
|
flwr/simulation/app.py
CHANGED
@@ -19,7 +19,6 @@ import argparse
|
|
19
19
|
import gc
|
20
20
|
from logging import DEBUG, ERROR, INFO
|
21
21
|
from queue import Queue
|
22
|
-
from time import sleep
|
23
22
|
from typing import Optional
|
24
23
|
|
25
24
|
from flwr.cli.config_utils import get_fab_metadata
|
@@ -70,6 +69,7 @@ from flwr.proto.run_pb2 import ( # pylint: disable=E0611
|
|
70
69
|
from flwr.server.superlink.fleet.vce.backend.backend import BackendConfig
|
71
70
|
from flwr.simulation.run_simulation import _run_simulation
|
72
71
|
from flwr.simulation.simulationio_connection import SimulationIoConnection
|
72
|
+
from flwr.supercore.app_utils import simple_get_token, start_parent_process_monitor
|
73
73
|
|
74
74
|
|
75
75
|
def flwr_simulation() -> None:
|
@@ -97,23 +97,31 @@ def flwr_simulation() -> None:
|
|
97
97
|
run_simulation_process(
|
98
98
|
simulationio_api_address=args.simulationio_api_address,
|
99
99
|
log_queue=log_queue,
|
100
|
-
run_once=args.run_once,
|
100
|
+
run_once=(args.token is not None) or args.run_once,
|
101
|
+
token=args.token,
|
101
102
|
flwr_dir_=args.flwr_dir,
|
102
103
|
certificates=None,
|
104
|
+
parent_pid=args.parent_pid,
|
103
105
|
)
|
104
106
|
|
105
107
|
# Restore stdout/stderr
|
106
108
|
restore_output()
|
107
109
|
|
108
110
|
|
109
|
-
def run_simulation_process( # pylint: disable=R0914,
|
111
|
+
def run_simulation_process( # pylint: disable=R0913, R0914, R0915, R0917, W0212
|
110
112
|
simulationio_api_address: str,
|
111
113
|
log_queue: Queue[Optional[str]],
|
112
114
|
run_once: bool,
|
115
|
+
token: Optional[str] = None,
|
113
116
|
flwr_dir_: Optional[str] = None,
|
114
117
|
certificates: Optional[bytes] = None,
|
118
|
+
parent_pid: Optional[int] = None,
|
115
119
|
) -> None:
|
116
120
|
"""Run Flower Simulation process."""
|
121
|
+
# Start monitoring the parent process if a PID is provided
|
122
|
+
if parent_pid is not None:
|
123
|
+
start_parent_process_monitor(parent_pid)
|
124
|
+
|
117
125
|
conn = SimulationIoConnection(
|
118
126
|
simulationio_service_address=simulationio_api_address,
|
119
127
|
root_certificates=certificates,
|
@@ -127,14 +135,14 @@ def run_simulation_process( # pylint: disable=R0914, disable=W0212, disable=R09
|
|
127
135
|
while True:
|
128
136
|
|
129
137
|
try:
|
138
|
+
# If token is not set, loop until token is received from SuperNode
|
139
|
+
if token is None:
|
140
|
+
log(DEBUG, "[flwr-simulation] Request token")
|
141
|
+
token = simple_get_token(conn._stub)
|
142
|
+
|
130
143
|
# Pull SimulationInputs from LinkState
|
131
|
-
req = PullAppInputsRequest()
|
144
|
+
req = PullAppInputsRequest(token=token)
|
132
145
|
res: PullAppInputsResponse = conn._stub.PullAppInputs(req)
|
133
|
-
if not res.HasField("run"):
|
134
|
-
sleep(3)
|
135
|
-
run_status = None
|
136
|
-
continue
|
137
|
-
|
138
146
|
context = context_from_proto(res.context)
|
139
147
|
run = run_from_proto(res.run)
|
140
148
|
fab = fab_from_proto(res.fab)
|
@@ -240,7 +248,9 @@ def run_simulation_process( # pylint: disable=R0914, disable=W0212, disable=R09
|
|
240
248
|
|
241
249
|
# Send resulting context
|
242
250
|
context_proto = context_to_proto(updated_context)
|
243
|
-
out_req = PushAppOutputsRequest(
|
251
|
+
out_req = PushAppOutputsRequest(
|
252
|
+
token=token, run_id=run.run_id, context=context_proto
|
253
|
+
)
|
244
254
|
_ = conn._stub.PushAppOutputs(out_req)
|
245
255
|
|
246
256
|
run_status = RunStatus(Status.FINISHED, SubStatus.COMPLETED, "")
|
@@ -275,6 +285,9 @@ def run_simulation_process( # pylint: disable=R0914, disable=W0212, disable=R09
|
|
275
285
|
del updated_context
|
276
286
|
except NameError:
|
277
287
|
pass
|
288
|
+
|
289
|
+
# Remove the token
|
290
|
+
token = None
|
278
291
|
gc.collect()
|
279
292
|
|
280
293
|
# Stop the loop if `flwr-simulation` is expected to process a single run
|
flwr/supercore/app_utils.py
CHANGED
@@ -29,6 +29,7 @@ from flwr.proto.appio_pb2 import ( # pylint: disable=E0611
|
|
29
29
|
)
|
30
30
|
from flwr.proto.clientappio_pb2_grpc import ClientAppIoStub
|
31
31
|
from flwr.proto.serverappio_pb2_grpc import ServerAppIoStub
|
32
|
+
from flwr.proto.simulationio_pb2_grpc import SimulationIoStub
|
32
33
|
|
33
34
|
if os.name == "nt":
|
34
35
|
from ctypes import windll # type: ignore
|
@@ -70,7 +71,9 @@ def start_parent_process_monitor(
|
|
70
71
|
threading.Thread(target=monitor, daemon=True).start()
|
71
72
|
|
72
73
|
|
73
|
-
def simple_get_token(
|
74
|
+
def simple_get_token(
|
75
|
+
stub: Union[ClientAppIoStub, ServerAppIoStub, SimulationIoStub]
|
76
|
+
) -> str:
|
74
77
|
"""Get a token from SuperLink/SuperNode.
|
75
78
|
|
76
79
|
This shall be removed once the SuperExec is fully implemented.
|
@@ -65,19 +65,6 @@ def _parse_args_run_flwr_clientapp() -> argparse.ArgumentParser:
|
|
65
65
|
help="Address of SuperNode's ClientAppIo API (IPv4, IPv6, or a domain name)."
|
66
66
|
f"By default, it is set to {CLIENTAPPIO_API_DEFAULT_CLIENT_ADDRESS}.",
|
67
67
|
)
|
68
|
-
parser.add_argument(
|
69
|
-
"--token",
|
70
|
-
type=str,
|
71
|
-
required=False,
|
72
|
-
help="Unique token generated by SuperNode for each ClientApp execution",
|
73
|
-
)
|
74
|
-
parser.add_argument(
|
75
|
-
"--parent-pid",
|
76
|
-
type=int,
|
77
|
-
default=None,
|
78
|
-
help="The PID of the parent process. When set, the process will terminate "
|
79
|
-
"when the parent process exits.",
|
80
|
-
)
|
81
68
|
parser.add_argument(
|
82
69
|
"--run-once",
|
83
70
|
action="store_true",
|
@@ -35,14 +35,13 @@ from flwr.common import GRPC_MAX_MESSAGE_LENGTH, Context, Message, RecordDict
|
|
35
35
|
from flwr.common.address import parse_address
|
36
36
|
from flwr.common.config import get_flwr_dir, get_fused_config_from_fab
|
37
37
|
from flwr.common.constant import (
|
38
|
-
CLIENT_OCTET,
|
39
38
|
CLIENTAPPIO_API_DEFAULT_SERVER_ADDRESS,
|
40
39
|
ISOLATION_MODE_SUBPROCESS,
|
41
|
-
SERVER_OCTET,
|
42
40
|
TRANSPORT_TYPE_GRPC_ADAPTER,
|
43
41
|
TRANSPORT_TYPE_GRPC_RERE,
|
44
42
|
TRANSPORT_TYPE_REST,
|
45
43
|
TRANSPORT_TYPES,
|
44
|
+
ExecPluginType,
|
46
45
|
)
|
47
46
|
from flwr.common.exit import ExitCode, flwr_exit
|
48
47
|
from flwr.common.exit_handlers import register_exit_handlers
|
@@ -164,6 +163,15 @@ def start_client_internal(
|
|
164
163
|
ffs = ffs_factory.ffs()
|
165
164
|
store = object_store_factory.store()
|
166
165
|
|
166
|
+
# Launch the SuperExec if the isolation mode is `subprocess`
|
167
|
+
if isolation == ISOLATION_MODE_SUBPROCESS:
|
168
|
+
command = ["flower-superexec", "--insecure"]
|
169
|
+
command += ["--appio-api-address", clientappio_api_address]
|
170
|
+
command += ["--plugin-type", ExecPluginType.CLIENT_APP]
|
171
|
+
command += ["--parent-pid", str(os.getpid())]
|
172
|
+
# pylint: disable-next=consider-using-with
|
173
|
+
subprocess.Popen(command)
|
174
|
+
|
167
175
|
with _init_connection(
|
168
176
|
transport=transport,
|
169
177
|
server_address=server_address,
|
@@ -207,35 +215,6 @@ def start_client_internal(
|
|
207
215
|
confirm_message_received=confirm_message_received,
|
208
216
|
)
|
209
217
|
|
210
|
-
# Two isolation modes:
|
211
|
-
# 1. `subprocess`: SuperNode is starting the ClientApp
|
212
|
-
# process as a subprocess.
|
213
|
-
# 2. `process`: ClientApp process gets started separately
|
214
|
-
# (via `flwr-clientapp`), for example, in a separate
|
215
|
-
# Docker container.
|
216
|
-
|
217
|
-
# Mode 1: SuperNode starts ClientApp as subprocess
|
218
|
-
start_subprocess = isolation == ISOLATION_MODE_SUBPROCESS
|
219
|
-
|
220
|
-
if start_subprocess and run_id is not None:
|
221
|
-
_octet, _colon, _port = clientappio_api_address.rpartition(":")
|
222
|
-
io_address = (
|
223
|
-
f"{CLIENT_OCTET}:{_port}"
|
224
|
-
if _octet == SERVER_OCTET
|
225
|
-
else clientappio_api_address
|
226
|
-
)
|
227
|
-
# Start ClientApp subprocess
|
228
|
-
command = [
|
229
|
-
"flwr-clientapp",
|
230
|
-
"--clientappio-api-address",
|
231
|
-
io_address,
|
232
|
-
"--parent-pid",
|
233
|
-
str(os.getpid()),
|
234
|
-
"--insecure",
|
235
|
-
"--run-once",
|
236
|
-
]
|
237
|
-
subprocess.run(command, check=False)
|
238
|
-
|
239
218
|
# No message has been pulled therefore we can skip the push stage.
|
240
219
|
if run_id is None:
|
241
220
|
# If no message was received, wait for a while
|
{flwr_nightly-1.21.0.dev20250812.dist-info → flwr_nightly-1.21.0.dev20250813.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: flwr-nightly
|
3
|
-
Version: 1.21.0.
|
3
|
+
Version: 1.21.0.dev20250813
|
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
|
@@ -172,8 +172,9 @@ Flower Baselines is a collection of community-contributed projects that reproduc
|
|
172
172
|
- [FedOpt](https://github.com/adap/flower/tree/main/baselines/flwr_baselines/flwr_baselines/publications/adaptive_federated_optimization)
|
173
173
|
|
174
174
|
Please refer to the [Flower Baselines Documentation](https://flower.ai/docs/baselines/) for a detailed categorization of baselines and for additional info including:
|
175
|
-
|
176
|
-
|
175
|
+
|
176
|
+
- [How to use Flower Baselines](https://flower.ai/docs/baselines/how-to-use-baselines.html)
|
177
|
+
- [How to contribute a new Flower Baseline](https://flower.ai/docs/baselines/how-to-contribute-baselines.html)
|
177
178
|
|
178
179
|
## Flower Usage Examples
|
179
180
|
|
{flwr_nightly-1.21.0.dev20250812.dist-info → flwr_nightly-1.21.0.dev20250813.dist-info}/RECORD
RENAMED
@@ -104,7 +104,7 @@ flwr/client/typing.py,sha256=Jw3rawDzI_-ZDcRmEQcs5gZModY7oeQlEeltYsdOhlU,1048
|
|
104
104
|
flwr/clientapp/__init__.py,sha256=zGW4z49Ojzoi1hDiRC7kyhLjijUilc6fqHhtM_ATRVA,719
|
105
105
|
flwr/common/__init__.py,sha256=5GCLVk399Az_rTJHNticRlL0Sl_oPw_j5_LuFKfX7-M,4171
|
106
106
|
flwr/common/address.py,sha256=9JucdTwlc-jpeJkRKeUboZoacUtErwSVtnDR9kAtLqE,4119
|
107
|
-
flwr/common/args.py,sha256=
|
107
|
+
flwr/common/args.py,sha256=WVx-NI3d9kc1vCxfQ_JAHqoAulJHbvMXDqoGjz21hF0,5686
|
108
108
|
flwr/common/auth_plugin/__init__.py,sha256=DktrRcGZrRarLf7Jb_UlHtOyLp9_-kEplyq6PS5-vOA,988
|
109
109
|
flwr/common/auth_plugin/auth_plugin.py,sha256=mM7SuphO4OsVAVJR1GErYVgYT83ZjxDzS_gha12bT9E,4855
|
110
110
|
flwr/common/config.py,sha256=glcZDjco-amw1YfQcYTFJ4S1pt9APoexT-mf1QscuHs,13960
|
@@ -220,17 +220,17 @@ flwr/proto/serverappio_pb2.py,sha256=CRbRIJk9r4RvLng1a_2M32LdNM3PoZmBRlNLO7fKVFs
|
|
220
220
|
flwr/proto/serverappio_pb2.pyi,sha256=MDY9CEUnev_oi7Y-gZIXx8divcc0BufLAE2d7nmbo_Y,1319
|
221
221
|
flwr/proto/serverappio_pb2_grpc.py,sha256=hfRrdawakgu1uV6vf7lHSqB7IZNlxmsYmep3KJQXjjs,27446
|
222
222
|
flwr/proto/serverappio_pb2_grpc.pyi,sha256=65o7dZaEbqaYJKnJG84umeHGKGdJJQKK1FYMIUnvYwQ,7461
|
223
|
-
flwr/proto/simulationio_pb2.py,sha256=
|
223
|
+
flwr/proto/simulationio_pb2.py,sha256=9XIMVuYUP5GsRh2ppp6mWw-IF50TY1xt6MWGR0xveMs,2733
|
224
224
|
flwr/proto/simulationio_pb2.pyi,sha256=XbFvpZvvrS7QcH5AFXfpRGl4hQvhd3QdKO6x0oTlCCU,165
|
225
|
-
flwr/proto/simulationio_pb2_grpc.py,sha256=
|
226
|
-
flwr/proto/simulationio_pb2_grpc.pyi,sha256=
|
225
|
+
flwr/proto/simulationio_pb2_grpc.py,sha256=QJqP8njZpWbcG_vpbDI9wYEuULHPRcaEMiOxmshzgXU,17562
|
226
|
+
flwr/proto/simulationio_pb2_grpc.pyi,sha256=l9GDFkqrrHIEt3I5Eg1ZeMvEP3faN8Qcyh1pQe91DJA,4807
|
227
227
|
flwr/proto/transport_pb2.py,sha256=P-jX_tUyk_8xFe-vIUUSfZlHGtk2Ou3A8eXdBKkp5AY,9824
|
228
228
|
flwr/proto/transport_pb2.pyi,sha256=ipHQ03eFBqsxtAuAVefZ2lVr04BZ4YifJCS2eauNmy8,21627
|
229
229
|
flwr/proto/transport_pb2_grpc.py,sha256=vLN3EHtx2aEEMCO4f1Upu-l27BPzd3-5pV-u8wPcosk,2598
|
230
230
|
flwr/proto/transport_pb2_grpc.pyi,sha256=AGXf8RiIiW2J5IKMlm_3qT3AzcDa4F3P5IqUjve_esA,766
|
231
231
|
flwr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
232
232
|
flwr/server/__init__.py,sha256=LQQHiuL2jy7TpNaKastRdGsexlxSt5ZWAQNVqitDnrY,1598
|
233
|
-
flwr/server/app.py,sha256=
|
233
|
+
flwr/server/app.py,sha256=E7HFs_IB0y1haNFcuGy6dOqQ00zmW63O7pDbl8hfyLU,28639
|
234
234
|
flwr/server/client_manager.py,sha256=5jCGavVli7XdupvWWo7ru3PdFTlRU8IGvHFSSoUVLRs,6227
|
235
235
|
flwr/server/client_proxy.py,sha256=sv0E9AldBYOvc3pusqFh-GnyreeMfsXQ1cuTtxTq_wY,2399
|
236
236
|
flwr/server/compat/__init__.py,sha256=0IsttWvY15qO98_1GyzVC-vR1e_ZPXOdu2qUlOkYMPE,886
|
@@ -250,7 +250,7 @@ flwr/server/server.py,sha256=39m4FSN2T-uVA-no9nstN0eWW0co-IUUAIMmpd3V7Jc,17893
|
|
250
250
|
flwr/server/server_app.py,sha256=8uagoZX-3CY3tazPqkIV9jY-cN0YrRRrDmVe23o0AV0,9515
|
251
251
|
flwr/server/server_config.py,sha256=e_6ddh0riwOJsdNn2BFev344uMWfDk9n7dyjNpPgm1w,1349
|
252
252
|
flwr/server/serverapp/__init__.py,sha256=xcC0T_MQSMS9cicUzUUpMNCOsF2d8Oh_8jvnoBLuZvo,800
|
253
|
-
flwr/server/serverapp/app.py,sha256
|
253
|
+
flwr/server/serverapp/app.py,sha256=9S0B4yEuL1QFbPR7RQvn1N7BVu9t7jFhgNpIfXuRvGg,10067
|
254
254
|
flwr/server/serverapp_components.py,sha256=dfSqmrsVy3arKXpl3ZIBQWdV8rehfIms8aJooyzdmEM,2118
|
255
255
|
flwr/server/strategy/__init__.py,sha256=HhsSWMWaC7oCb2g7Kqn1MBKdrfvgi8VxACy9ZL706Q0,2836
|
256
256
|
flwr/server/strategy/aggregate.py,sha256=smlKKy-uFUuuFR12vlclucnwSQWRz78R79-Km4RWqbw,13978
|
@@ -308,7 +308,7 @@ flwr/server/superlink/serverappio/serverappio_grpc.py,sha256=zcvzDhCAnlFxAwCiJUH
|
|
308
308
|
flwr/server/superlink/serverappio/serverappio_servicer.py,sha256=3C_0boRbYuY1Vlf0DRGzBvTUX-D5UUzxYkFihSMZf-A,20094
|
309
309
|
flwr/server/superlink/simulation/__init__.py,sha256=Ry8DrNaZCMcQXvUc4FoCN2m3dvUQgWjasfp015o3Ec4,718
|
310
310
|
flwr/server/superlink/simulation/simulationio_grpc.py,sha256=VqWKxjpd4bCgPFKsgtIZPk9YcG0kc1EEmr5k20EKty4,2205
|
311
|
-
flwr/server/superlink/simulation/simulationio_servicer.py,sha256=
|
311
|
+
flwr/server/superlink/simulation/simulationio_servicer.py,sha256=aZp67AeNCGs1zI4mvj_WUOL8noxNcsYu_QIpYKhnHXg,9992
|
312
312
|
flwr/server/superlink/utils.py,sha256=zXmyU2o535b9dgz-TvFklzfuQk4irNnMtiK8vT4Dm1c,2454
|
313
313
|
flwr/server/typing.py,sha256=LvO6gq7H6TAWhA9JFx0WyqHxU7FycyvhSsLjBLPgpts,1011
|
314
314
|
flwr/server/utils/__init__.py,sha256=U4gM84-uUFddarODDQkO6SjNUuGhFcsHJZMjSEbezkU,884
|
@@ -322,7 +322,7 @@ flwr/server/workflow/secure_aggregation/secagg_workflow.py,sha256=b_pKk7gmbahwyj
|
|
322
322
|
flwr/server/workflow/secure_aggregation/secaggplus_workflow.py,sha256=DkayCsnlAya6Y2PZsueLgoUCMRtV-GbnW08RfWx_SXM,29460
|
323
323
|
flwr/serverapp/__init__.py,sha256=HPvC_ZvMS7GCM7ALVrG_Wwm4bSDr4DZETeC561v3T9w,719
|
324
324
|
flwr/simulation/__init__.py,sha256=Gg6OsP1Z-ixc3-xxzvl7j7rz2Fijy9rzyEPpxgAQCeM,1556
|
325
|
-
flwr/simulation/app.py,sha256=
|
325
|
+
flwr/simulation/app.py,sha256=et3bEZT4dstgZY9N4xKpftoDaKTbc39JjN3AKvaLn-s,11107
|
326
326
|
flwr/simulation/legacy_app.py,sha256=nMISQqW0otJL1-2Kfd94O6BLlGS2IEmEPKTM2WGKrIs,15861
|
327
327
|
flwr/simulation/ray_transport/__init__.py,sha256=ogd-0AMv2U-wBZ1r3sHWaDIOIrVqr88Xi6C8o4Dviy0,734
|
328
328
|
flwr/simulation/ray_transport/ray_actor.py,sha256=JN3xTqFIr5Z750k92CcA_uavzOHhSWDwE2WCaecvpks,19147
|
@@ -331,7 +331,7 @@ flwr/simulation/ray_transport/utils.py,sha256=KrexpWYCF-dAF3UHc9yDbPQWO-ahMT-BbD
|
|
331
331
|
flwr/simulation/run_simulation.py,sha256=-sp3dNZcp7MCAH0BlmZpVcFAGvozRdYXRdDYcH_2Zxk,20838
|
332
332
|
flwr/simulation/simulationio_connection.py,sha256=mzS1C6EEREwQDPceDo30anAasmTDLb9qqV2tXlBhOUA,3494
|
333
333
|
flwr/supercore/__init__.py,sha256=pqkFoow_E6UhbBlhmoD1gmTH-33yJRhBsIZqxRPFZ7U,755
|
334
|
-
flwr/supercore/app_utils.py,sha256=
|
334
|
+
flwr/supercore/app_utils.py,sha256=ogT14HdSIxToJoOgVngdKJ3nf7eY4b2wSjzkPT--kX0,2857
|
335
335
|
flwr/supercore/cli/__init__.py,sha256=EDl2aO-fuQfxSbL-T1W9RAfA2N0hpWHmqX_GSwblJbQ,845
|
336
336
|
flwr/supercore/cli/flower_superexec.py,sha256=J_rf7SCVW9L9wsBScOYa-oJOpyb_e1WOtwTGSyUFu1k,3882
|
337
337
|
flwr/supercore/corestate/__init__.py,sha256=Vau6-L_JG5QzNqtCTa9xCKGGljc09wY8avZmIjSJemg,774
|
@@ -377,7 +377,7 @@ flwr/superlink/servicer/control/control_user_auth_interceptor.py,sha256=9Aqhrt_U
|
|
377
377
|
flwr/supernode/__init__.py,sha256=KgeCaVvXWrU3rptNR1y0oBp4YtXbAcrnCcJAiOoWkI4,707
|
378
378
|
flwr/supernode/cli/__init__.py,sha256=JuEMr0-s9zv-PEWKuLB9tj1ocNfroSyNJ-oyv7ati9A,887
|
379
379
|
flwr/supernode/cli/flower_supernode.py,sha256=fAkk9zGhoP8Sv05EkdXRiCtirTAzWkSZBqRoaDdgflk,8529
|
380
|
-
flwr/supernode/cli/flwr_clientapp.py,sha256=
|
380
|
+
flwr/supernode/cli/flwr_clientapp.py,sha256=jxjR6etQRCHzG3zL04kyTZzicMMYdZ9dMiKdrW1uXs4,2759
|
381
381
|
flwr/supernode/nodestate/__init__.py,sha256=CyLLObbmmVgfRO88UCM0VMait1dL57mUauUDfuSHsbU,976
|
382
382
|
flwr/supernode/nodestate/in_memory_nodestate.py,sha256=rr_tg7YXhf_seYFipSB59TAfheKPratx3rrvHUOJ80g,7343
|
383
383
|
flwr/supernode/nodestate/nodestate.py,sha256=jCOewZyctecMxsM0-_-pQwef9P3O5QjnKCgCGyx2PK4,5047
|
@@ -387,8 +387,8 @@ flwr/supernode/runtime/run_clientapp.py,sha256=vAeBTgIi4SmV4IRq1dSjXaxrFUPEeHg-n
|
|
387
387
|
flwr/supernode/servicer/__init__.py,sha256=lucTzre5WPK7G1YLCfaqg3rbFWdNSb7ZTt-ca8gxdEo,717
|
388
388
|
flwr/supernode/servicer/clientappio/__init__.py,sha256=7Oy62Y_oijqF7Dxi6tpcUQyOpLc_QpIRZ83NvwmB0Yg,813
|
389
389
|
flwr/supernode/servicer/clientappio/clientappio_servicer.py,sha256=nIHRu38EWK-rpNOkcgBRAAKwYQQWFeCwu0lkO7OPZGQ,10239
|
390
|
-
flwr/supernode/start_client_internal.py,sha256=
|
391
|
-
flwr_nightly-1.21.0.
|
392
|
-
flwr_nightly-1.21.0.
|
393
|
-
flwr_nightly-1.21.0.
|
394
|
-
flwr_nightly-1.21.0.
|
390
|
+
flwr/supernode/start_client_internal.py,sha256=z2o92MQKzTRB-AZTELROueZ2ZQYouu947hiU-WJ_oq4,20257
|
391
|
+
flwr_nightly-1.21.0.dev20250813.dist-info/METADATA,sha256=0aRgIClEyMHvfwiaW40CrEwvVvE7hnUcjZ0XZ5zet7k,15967
|
392
|
+
flwr_nightly-1.21.0.dev20250813.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
393
|
+
flwr_nightly-1.21.0.dev20250813.dist-info/entry_points.txt,sha256=hxHD2ixb_vJFDOlZV-zB4Ao32_BQlL34ftsDh1GXv14,420
|
394
|
+
flwr_nightly-1.21.0.dev20250813.dist-info/RECORD,,
|
{flwr_nightly-1.21.0.dev20250812.dist-info → flwr_nightly-1.21.0.dev20250813.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|