flwr-nightly 1.21.0.dev20250811__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 +4 -11
- flwr/proto/simulationio_pb2.pyi +0 -58
- flwr/proto/simulationio_pb2_grpc.py +129 -27
- flwr/proto/simulationio_pb2_grpc.pyi +52 -13
- flwr/server/app.py +16 -94
- flwr/server/serverapp/app.py +1 -14
- flwr/server/superlink/simulation/simulationio_servicer.py +97 -21
- flwr/simulation/app.py +29 -18
- 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.dev20250811.dist-info → flwr_nightly-1.21.0.dev20250813.dist-info}/METADATA +4 -3
- {flwr_nightly-1.21.0.dev20250811.dist-info → flwr_nightly-1.21.0.dev20250813.dist-info}/RECORD +16 -16
- {flwr_nightly-1.21.0.dev20250811.dist-info → flwr_nightly-1.21.0.dev20250813.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.21.0.dev20250811.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
@@ -17,23 +17,16 @@ from flwr.proto import log_pb2 as flwr_dot_proto_dot_log__pb2
|
|
17
17
|
from flwr.proto import message_pb2 as flwr_dot_proto_dot_message__pb2
|
18
18
|
from flwr.proto import run_pb2 as flwr_dot_proto_dot_run__pb2
|
19
19
|
from flwr.proto import fab_pb2 as flwr_dot_proto_dot_fab__pb2
|
20
|
+
from flwr.proto import appio_pb2 as flwr_dot_proto_dot_appio__pb2
|
20
21
|
|
21
22
|
|
22
|
-
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\
|
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')
|
23
24
|
|
24
25
|
_globals = globals()
|
25
26
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
26
27
|
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flwr.proto.simulationio_pb2', _globals)
|
27
28
|
if _descriptor._USE_C_DESCRIPTORS == False:
|
28
29
|
DESCRIPTOR._options = None
|
29
|
-
_globals['
|
30
|
-
_globals['
|
31
|
-
_globals['_PULLSIMULATIONINPUTSRESPONSE']._serialized_start=197
|
32
|
-
_globals['_PULLSIMULATIONINPUTSRESPONSE']._serialized_end=325
|
33
|
-
_globals['_PUSHSIMULATIONOUTPUTSREQUEST']._serialized_start=327
|
34
|
-
_globals['_PUSHSIMULATIONOUTPUTSREQUEST']._serialized_end=411
|
35
|
-
_globals['_PUSHSIMULATIONOUTPUTSRESPONSE']._serialized_start=413
|
36
|
-
_globals['_PUSHSIMULATIONOUTPUTSRESPONSE']._serialized_end=444
|
37
|
-
_globals['_SIMULATIONIO']._serialized_start=447
|
38
|
-
_globals['_SIMULATIONIO']._serialized_end=1140
|
30
|
+
_globals['_SIMULATIONIO']._serialized_start=190
|
31
|
+
_globals['_SIMULATIONIO']._serialized_end=1090
|
39
32
|
# @@protoc_insertion_point(module_scope)
|
flwr/proto/simulationio_pb2.pyi
CHANGED
@@ -2,64 +2,6 @@
|
|
2
2
|
@generated by mypy-protobuf. Do not edit manually!
|
3
3
|
isort:skip_file
|
4
4
|
"""
|
5
|
-
import builtins
|
6
|
-
import flwr.proto.fab_pb2
|
7
|
-
import flwr.proto.message_pb2
|
8
|
-
import flwr.proto.run_pb2
|
9
5
|
import google.protobuf.descriptor
|
10
|
-
import google.protobuf.message
|
11
|
-
import typing
|
12
|
-
import typing_extensions
|
13
6
|
|
14
7
|
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
|
15
|
-
|
16
|
-
class PullSimulationInputsRequest(google.protobuf.message.Message):
|
17
|
-
"""PullSimulationInputs messages"""
|
18
|
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
19
|
-
def __init__(self,
|
20
|
-
) -> None: ...
|
21
|
-
global___PullSimulationInputsRequest = PullSimulationInputsRequest
|
22
|
-
|
23
|
-
class PullSimulationInputsResponse(google.protobuf.message.Message):
|
24
|
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
25
|
-
CONTEXT_FIELD_NUMBER: builtins.int
|
26
|
-
RUN_FIELD_NUMBER: builtins.int
|
27
|
-
FAB_FIELD_NUMBER: builtins.int
|
28
|
-
@property
|
29
|
-
def context(self) -> flwr.proto.message_pb2.Context: ...
|
30
|
-
@property
|
31
|
-
def run(self) -> flwr.proto.run_pb2.Run: ...
|
32
|
-
@property
|
33
|
-
def fab(self) -> flwr.proto.fab_pb2.Fab: ...
|
34
|
-
def __init__(self,
|
35
|
-
*,
|
36
|
-
context: typing.Optional[flwr.proto.message_pb2.Context] = ...,
|
37
|
-
run: typing.Optional[flwr.proto.run_pb2.Run] = ...,
|
38
|
-
fab: typing.Optional[flwr.proto.fab_pb2.Fab] = ...,
|
39
|
-
) -> None: ...
|
40
|
-
def HasField(self, field_name: typing_extensions.Literal["context",b"context","fab",b"fab","run",b"run"]) -> builtins.bool: ...
|
41
|
-
def ClearField(self, field_name: typing_extensions.Literal["context",b"context","fab",b"fab","run",b"run"]) -> None: ...
|
42
|
-
global___PullSimulationInputsResponse = PullSimulationInputsResponse
|
43
|
-
|
44
|
-
class PushSimulationOutputsRequest(google.protobuf.message.Message):
|
45
|
-
"""PushSimulationOutputs messages"""
|
46
|
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
47
|
-
RUN_ID_FIELD_NUMBER: builtins.int
|
48
|
-
CONTEXT_FIELD_NUMBER: builtins.int
|
49
|
-
run_id: builtins.int
|
50
|
-
@property
|
51
|
-
def context(self) -> flwr.proto.message_pb2.Context: ...
|
52
|
-
def __init__(self,
|
53
|
-
*,
|
54
|
-
run_id: builtins.int = ...,
|
55
|
-
context: typing.Optional[flwr.proto.message_pb2.Context] = ...,
|
56
|
-
) -> None: ...
|
57
|
-
def HasField(self, field_name: typing_extensions.Literal["context",b"context"]) -> builtins.bool: ...
|
58
|
-
def ClearField(self, field_name: typing_extensions.Literal["context",b"context","run_id",b"run_id"]) -> None: ...
|
59
|
-
global___PushSimulationOutputsRequest = PushSimulationOutputsRequest
|
60
|
-
|
61
|
-
class PushSimulationOutputsResponse(google.protobuf.message.Message):
|
62
|
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
63
|
-
def __init__(self,
|
64
|
-
) -> None: ...
|
65
|
-
global___PushSimulationOutputsResponse = PushSimulationOutputsResponse
|
@@ -2,10 +2,10 @@
|
|
2
2
|
"""Client and server classes corresponding to protobuf-defined services."""
|
3
3
|
import grpc
|
4
4
|
|
5
|
+
from flwr.proto import appio_pb2 as flwr_dot_proto_dot_appio__pb2
|
5
6
|
from flwr.proto import heartbeat_pb2 as flwr_dot_proto_dot_heartbeat__pb2
|
6
7
|
from flwr.proto import log_pb2 as flwr_dot_proto_dot_log__pb2
|
7
8
|
from flwr.proto import run_pb2 as flwr_dot_proto_dot_run__pb2
|
8
|
-
from flwr.proto import simulationio_pb2 as flwr_dot_proto_dot_simulationio__pb2
|
9
9
|
|
10
10
|
|
11
11
|
class SimulationIoStub(object):
|
@@ -17,15 +17,30 @@ class SimulationIoStub(object):
|
|
17
17
|
Args:
|
18
18
|
channel: A grpc.Channel.
|
19
19
|
"""
|
20
|
-
self.
|
21
|
-
'/flwr.proto.SimulationIo/
|
22
|
-
request_serializer=
|
23
|
-
response_deserializer=
|
20
|
+
self.ListAppsToLaunch = channel.unary_unary(
|
21
|
+
'/flwr.proto.SimulationIo/ListAppsToLaunch',
|
22
|
+
request_serializer=flwr_dot_proto_dot_appio__pb2.ListAppsToLaunchRequest.SerializeToString,
|
23
|
+
response_deserializer=flwr_dot_proto_dot_appio__pb2.ListAppsToLaunchResponse.FromString,
|
24
24
|
)
|
25
|
-
self.
|
26
|
-
'/flwr.proto.SimulationIo/
|
27
|
-
request_serializer=
|
28
|
-
response_deserializer=
|
25
|
+
self.RequestToken = channel.unary_unary(
|
26
|
+
'/flwr.proto.SimulationIo/RequestToken',
|
27
|
+
request_serializer=flwr_dot_proto_dot_appio__pb2.RequestTokenRequest.SerializeToString,
|
28
|
+
response_deserializer=flwr_dot_proto_dot_appio__pb2.RequestTokenResponse.FromString,
|
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
|
+
)
|
35
|
+
self.PullAppInputs = channel.unary_unary(
|
36
|
+
'/flwr.proto.SimulationIo/PullAppInputs',
|
37
|
+
request_serializer=flwr_dot_proto_dot_appio__pb2.PullAppInputsRequest.SerializeToString,
|
38
|
+
response_deserializer=flwr_dot_proto_dot_appio__pb2.PullAppInputsResponse.FromString,
|
39
|
+
)
|
40
|
+
self.PushAppOutputs = channel.unary_unary(
|
41
|
+
'/flwr.proto.SimulationIo/PushAppOutputs',
|
42
|
+
request_serializer=flwr_dot_proto_dot_appio__pb2.PushAppOutputsRequest.SerializeToString,
|
43
|
+
response_deserializer=flwr_dot_proto_dot_appio__pb2.PushAppOutputsResponse.FromString,
|
29
44
|
)
|
30
45
|
self.UpdateRunStatus = channel.unary_unary(
|
31
46
|
'/flwr.proto.SimulationIo/UpdateRunStatus',
|
@@ -57,14 +72,35 @@ class SimulationIoStub(object):
|
|
57
72
|
class SimulationIoServicer(object):
|
58
73
|
"""Missing associated documentation comment in .proto file."""
|
59
74
|
|
60
|
-
def
|
75
|
+
def ListAppsToLaunch(self, request, context):
|
76
|
+
"""List runs to launch
|
77
|
+
"""
|
78
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
79
|
+
context.set_details('Method not implemented!')
|
80
|
+
raise NotImplementedError('Method not implemented!')
|
81
|
+
|
82
|
+
def RequestToken(self, request, context):
|
83
|
+
"""Request token for a run
|
84
|
+
"""
|
85
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
86
|
+
context.set_details('Method not implemented!')
|
87
|
+
raise NotImplementedError('Method not implemented!')
|
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
|
+
|
96
|
+
def PullAppInputs(self, request, context):
|
61
97
|
"""Pull Simulation inputs
|
62
98
|
"""
|
63
99
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
64
100
|
context.set_details('Method not implemented!')
|
65
101
|
raise NotImplementedError('Method not implemented!')
|
66
102
|
|
67
|
-
def
|
103
|
+
def PushAppOutputs(self, request, context):
|
68
104
|
"""Push Simulation outputs
|
69
105
|
"""
|
70
106
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
@@ -109,15 +145,30 @@ class SimulationIoServicer(object):
|
|
109
145
|
|
110
146
|
def add_SimulationIoServicer_to_server(servicer, server):
|
111
147
|
rpc_method_handlers = {
|
112
|
-
'
|
113
|
-
servicer.
|
114
|
-
request_deserializer=
|
115
|
-
response_serializer=
|
148
|
+
'ListAppsToLaunch': grpc.unary_unary_rpc_method_handler(
|
149
|
+
servicer.ListAppsToLaunch,
|
150
|
+
request_deserializer=flwr_dot_proto_dot_appio__pb2.ListAppsToLaunchRequest.FromString,
|
151
|
+
response_serializer=flwr_dot_proto_dot_appio__pb2.ListAppsToLaunchResponse.SerializeToString,
|
152
|
+
),
|
153
|
+
'RequestToken': grpc.unary_unary_rpc_method_handler(
|
154
|
+
servicer.RequestToken,
|
155
|
+
request_deserializer=flwr_dot_proto_dot_appio__pb2.RequestTokenRequest.FromString,
|
156
|
+
response_serializer=flwr_dot_proto_dot_appio__pb2.RequestTokenResponse.SerializeToString,
|
116
157
|
),
|
117
|
-
'
|
118
|
-
servicer.
|
119
|
-
request_deserializer=
|
120
|
-
response_serializer=
|
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
|
+
),
|
163
|
+
'PullAppInputs': grpc.unary_unary_rpc_method_handler(
|
164
|
+
servicer.PullAppInputs,
|
165
|
+
request_deserializer=flwr_dot_proto_dot_appio__pb2.PullAppInputsRequest.FromString,
|
166
|
+
response_serializer=flwr_dot_proto_dot_appio__pb2.PullAppInputsResponse.SerializeToString,
|
167
|
+
),
|
168
|
+
'PushAppOutputs': grpc.unary_unary_rpc_method_handler(
|
169
|
+
servicer.PushAppOutputs,
|
170
|
+
request_deserializer=flwr_dot_proto_dot_appio__pb2.PushAppOutputsRequest.FromString,
|
171
|
+
response_serializer=flwr_dot_proto_dot_appio__pb2.PushAppOutputsResponse.SerializeToString,
|
121
172
|
),
|
122
173
|
'UpdateRunStatus': grpc.unary_unary_rpc_method_handler(
|
123
174
|
servicer.UpdateRunStatus,
|
@@ -155,7 +206,58 @@ class SimulationIo(object):
|
|
155
206
|
"""Missing associated documentation comment in .proto file."""
|
156
207
|
|
157
208
|
@staticmethod
|
158
|
-
def
|
209
|
+
def ListAppsToLaunch(request,
|
210
|
+
target,
|
211
|
+
options=(),
|
212
|
+
channel_credentials=None,
|
213
|
+
call_credentials=None,
|
214
|
+
insecure=False,
|
215
|
+
compression=None,
|
216
|
+
wait_for_ready=None,
|
217
|
+
timeout=None,
|
218
|
+
metadata=None):
|
219
|
+
return grpc.experimental.unary_unary(request, target, '/flwr.proto.SimulationIo/ListAppsToLaunch',
|
220
|
+
flwr_dot_proto_dot_appio__pb2.ListAppsToLaunchRequest.SerializeToString,
|
221
|
+
flwr_dot_proto_dot_appio__pb2.ListAppsToLaunchResponse.FromString,
|
222
|
+
options, channel_credentials,
|
223
|
+
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
224
|
+
|
225
|
+
@staticmethod
|
226
|
+
def RequestToken(request,
|
227
|
+
target,
|
228
|
+
options=(),
|
229
|
+
channel_credentials=None,
|
230
|
+
call_credentials=None,
|
231
|
+
insecure=False,
|
232
|
+
compression=None,
|
233
|
+
wait_for_ready=None,
|
234
|
+
timeout=None,
|
235
|
+
metadata=None):
|
236
|
+
return grpc.experimental.unary_unary(request, target, '/flwr.proto.SimulationIo/RequestToken',
|
237
|
+
flwr_dot_proto_dot_appio__pb2.RequestTokenRequest.SerializeToString,
|
238
|
+
flwr_dot_proto_dot_appio__pb2.RequestTokenResponse.FromString,
|
239
|
+
options, channel_credentials,
|
240
|
+
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
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
|
+
|
259
|
+
@staticmethod
|
260
|
+
def PullAppInputs(request,
|
159
261
|
target,
|
160
262
|
options=(),
|
161
263
|
channel_credentials=None,
|
@@ -165,14 +267,14 @@ class SimulationIo(object):
|
|
165
267
|
wait_for_ready=None,
|
166
268
|
timeout=None,
|
167
269
|
metadata=None):
|
168
|
-
return grpc.experimental.unary_unary(request, target, '/flwr.proto.SimulationIo/
|
169
|
-
|
170
|
-
|
270
|
+
return grpc.experimental.unary_unary(request, target, '/flwr.proto.SimulationIo/PullAppInputs',
|
271
|
+
flwr_dot_proto_dot_appio__pb2.PullAppInputsRequest.SerializeToString,
|
272
|
+
flwr_dot_proto_dot_appio__pb2.PullAppInputsResponse.FromString,
|
171
273
|
options, channel_credentials,
|
172
274
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
173
275
|
|
174
276
|
@staticmethod
|
175
|
-
def
|
277
|
+
def PushAppOutputs(request,
|
176
278
|
target,
|
177
279
|
options=(),
|
178
280
|
channel_credentials=None,
|
@@ -182,9 +284,9 @@ class SimulationIo(object):
|
|
182
284
|
wait_for_ready=None,
|
183
285
|
timeout=None,
|
184
286
|
metadata=None):
|
185
|
-
return grpc.experimental.unary_unary(request, target, '/flwr.proto.SimulationIo/
|
186
|
-
|
187
|
-
|
287
|
+
return grpc.experimental.unary_unary(request, target, '/flwr.proto.SimulationIo/PushAppOutputs',
|
288
|
+
flwr_dot_proto_dot_appio__pb2.PushAppOutputsRequest.SerializeToString,
|
289
|
+
flwr_dot_proto_dot_appio__pb2.PushAppOutputsResponse.FromString,
|
188
290
|
options, channel_credentials,
|
189
291
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
190
292
|
|
@@ -3,22 +3,37 @@
|
|
3
3
|
isort:skip_file
|
4
4
|
"""
|
5
5
|
import abc
|
6
|
+
import flwr.proto.appio_pb2
|
6
7
|
import flwr.proto.heartbeat_pb2
|
7
8
|
import flwr.proto.log_pb2
|
8
9
|
import flwr.proto.run_pb2
|
9
|
-
import flwr.proto.simulationio_pb2
|
10
10
|
import grpc
|
11
11
|
|
12
12
|
class SimulationIoStub:
|
13
13
|
def __init__(self, channel: grpc.Channel) -> None: ...
|
14
|
-
|
15
|
-
flwr.proto.
|
16
|
-
flwr.proto.
|
14
|
+
ListAppsToLaunch: grpc.UnaryUnaryMultiCallable[
|
15
|
+
flwr.proto.appio_pb2.ListAppsToLaunchRequest,
|
16
|
+
flwr.proto.appio_pb2.ListAppsToLaunchResponse]
|
17
|
+
"""List runs to launch"""
|
18
|
+
|
19
|
+
RequestToken: grpc.UnaryUnaryMultiCallable[
|
20
|
+
flwr.proto.appio_pb2.RequestTokenRequest,
|
21
|
+
flwr.proto.appio_pb2.RequestTokenResponse]
|
22
|
+
"""Request token for a run"""
|
23
|
+
|
24
|
+
GetRun: grpc.UnaryUnaryMultiCallable[
|
25
|
+
flwr.proto.run_pb2.GetRunRequest,
|
26
|
+
flwr.proto.run_pb2.GetRunResponse]
|
27
|
+
"""Get run details"""
|
28
|
+
|
29
|
+
PullAppInputs: grpc.UnaryUnaryMultiCallable[
|
30
|
+
flwr.proto.appio_pb2.PullAppInputsRequest,
|
31
|
+
flwr.proto.appio_pb2.PullAppInputsResponse]
|
17
32
|
"""Pull Simulation inputs"""
|
18
33
|
|
19
|
-
|
20
|
-
flwr.proto.
|
21
|
-
flwr.proto.
|
34
|
+
PushAppOutputs: grpc.UnaryUnaryMultiCallable[
|
35
|
+
flwr.proto.appio_pb2.PushAppOutputsRequest,
|
36
|
+
flwr.proto.appio_pb2.PushAppOutputsResponse]
|
22
37
|
"""Push Simulation outputs"""
|
23
38
|
|
24
39
|
UpdateRunStatus: grpc.UnaryUnaryMultiCallable[
|
@@ -49,18 +64,42 @@ class SimulationIoStub:
|
|
49
64
|
|
50
65
|
class SimulationIoServicer(metaclass=abc.ABCMeta):
|
51
66
|
@abc.abstractmethod
|
52
|
-
def
|
53
|
-
request: flwr.proto.
|
67
|
+
def ListAppsToLaunch(self,
|
68
|
+
request: flwr.proto.appio_pb2.ListAppsToLaunchRequest,
|
54
69
|
context: grpc.ServicerContext,
|
55
|
-
) -> flwr.proto.
|
70
|
+
) -> flwr.proto.appio_pb2.ListAppsToLaunchResponse:
|
71
|
+
"""List runs to launch"""
|
72
|
+
pass
|
73
|
+
|
74
|
+
@abc.abstractmethod
|
75
|
+
def RequestToken(self,
|
76
|
+
request: flwr.proto.appio_pb2.RequestTokenRequest,
|
77
|
+
context: grpc.ServicerContext,
|
78
|
+
) -> flwr.proto.appio_pb2.RequestTokenResponse:
|
79
|
+
"""Request token for a run"""
|
80
|
+
pass
|
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
|
+
|
90
|
+
@abc.abstractmethod
|
91
|
+
def PullAppInputs(self,
|
92
|
+
request: flwr.proto.appio_pb2.PullAppInputsRequest,
|
93
|
+
context: grpc.ServicerContext,
|
94
|
+
) -> flwr.proto.appio_pb2.PullAppInputsResponse:
|
56
95
|
"""Pull Simulation inputs"""
|
57
96
|
pass
|
58
97
|
|
59
98
|
@abc.abstractmethod
|
60
|
-
def
|
61
|
-
request: flwr.proto.
|
99
|
+
def PushAppOutputs(self,
|
100
|
+
request: flwr.proto.appio_pb2.PushAppOutputsRequest,
|
62
101
|
context: grpc.ServicerContext,
|
63
|
-
) -> flwr.proto.
|
102
|
+
) -> flwr.proto.appio_pb2.PushAppOutputsResponse:
|
64
103
|
"""Push Simulation outputs"""
|
65
104
|
pass
|
66
105
|
|
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",
|
@@ -34,6 +34,16 @@ from flwr.common.serde import (
|
|
34
34
|
)
|
35
35
|
from flwr.common.typing import Fab, RunStatus
|
36
36
|
from flwr.proto import simulationio_pb2_grpc
|
37
|
+
from flwr.proto.appio_pb2 import ( # pylint: disable=E0611
|
38
|
+
ListAppsToLaunchRequest,
|
39
|
+
ListAppsToLaunchResponse,
|
40
|
+
PullAppInputsRequest,
|
41
|
+
PullAppInputsResponse,
|
42
|
+
PushAppOutputsRequest,
|
43
|
+
PushAppOutputsResponse,
|
44
|
+
RequestTokenRequest,
|
45
|
+
RequestTokenResponse,
|
46
|
+
)
|
37
47
|
from flwr.proto.heartbeat_pb2 import ( # pylint: disable=E0611
|
38
48
|
SendAppHeartbeatRequest,
|
39
49
|
SendAppHeartbeatResponse,
|
@@ -45,17 +55,13 @@ from flwr.proto.log_pb2 import ( # pylint: disable=E0611
|
|
45
55
|
from flwr.proto.run_pb2 import ( # pylint: disable=E0611
|
46
56
|
GetFederationOptionsRequest,
|
47
57
|
GetFederationOptionsResponse,
|
58
|
+
GetRunRequest,
|
59
|
+
GetRunResponse,
|
48
60
|
GetRunStatusRequest,
|
49
61
|
GetRunStatusResponse,
|
50
62
|
UpdateRunStatusRequest,
|
51
63
|
UpdateRunStatusResponse,
|
52
64
|
)
|
53
|
-
from flwr.proto.simulationio_pb2 import ( # pylint: disable=E0611
|
54
|
-
PullSimulationInputsRequest,
|
55
|
-
PullSimulationInputsResponse,
|
56
|
-
PushSimulationOutputsRequest,
|
57
|
-
PushSimulationOutputsResponse,
|
58
|
-
)
|
59
65
|
from flwr.server.superlink.linkstate import LinkStateFactory
|
60
66
|
from flwr.server.superlink.utils import abort_if
|
61
67
|
from flwr.supercore.ffs import FfsFactory
|
@@ -71,23 +77,73 @@ class SimulationIoServicer(simulationio_pb2_grpc.SimulationIoServicer):
|
|
71
77
|
self.ffs_factory = ffs_factory
|
72
78
|
self.lock = threading.RLock()
|
73
79
|
|
74
|
-
def
|
75
|
-
self,
|
76
|
-
|
80
|
+
def ListAppsToLaunch(
|
81
|
+
self,
|
82
|
+
request: ListAppsToLaunchRequest,
|
83
|
+
context: grpc.ServicerContext,
|
84
|
+
) -> ListAppsToLaunchResponse:
|
85
|
+
"""Get run IDs with pending messages."""
|
86
|
+
log(DEBUG, "SimulationIoServicer.ListAppsToLaunch")
|
87
|
+
|
88
|
+
# Initialize state connection
|
89
|
+
state = self.state_factory.state()
|
90
|
+
|
91
|
+
# Get IDs of runs in pending status
|
92
|
+
run_ids = state.get_run_ids(flwr_aid=None)
|
93
|
+
pending_run_ids = []
|
94
|
+
for run_id, status in state.get_run_status(run_ids).items():
|
95
|
+
if status.status == Status.PENDING:
|
96
|
+
pending_run_ids.append(run_id)
|
97
|
+
|
98
|
+
# Return run IDs
|
99
|
+
return ListAppsToLaunchResponse(run_ids=pending_run_ids)
|
100
|
+
|
101
|
+
def RequestToken(
|
102
|
+
self, request: RequestTokenRequest, context: grpc.ServicerContext
|
103
|
+
) -> RequestTokenResponse:
|
104
|
+
"""Request token."""
|
105
|
+
log(DEBUG, "SimulationIoServicer.RequestToken")
|
106
|
+
|
107
|
+
# Initialize state connection
|
108
|
+
state = self.state_factory.state()
|
109
|
+
|
110
|
+
# Attempt to create a token for the provided run ID
|
111
|
+
token = state.create_token(request.run_id)
|
112
|
+
|
113
|
+
# Return the token
|
114
|
+
return RequestTokenResponse(token=token or "")
|
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
|
+
|
133
|
+
def PullAppInputs(
|
134
|
+
self, request: PullAppInputsRequest, context: ServicerContext
|
135
|
+
) -> PullAppInputsResponse:
|
77
136
|
"""Pull SimultionIo process inputs."""
|
78
137
|
log(DEBUG, "SimultionIoServicer.SimultionIoInputs")
|
79
138
|
# Init access to LinkState and Ffs
|
80
139
|
state = self.state_factory.state()
|
81
140
|
ffs = self.ffs_factory.ffs()
|
82
141
|
|
142
|
+
# Validate the token
|
143
|
+
run_id = self._verify_token(request.token, context)
|
144
|
+
|
83
145
|
# Lock access to LinkState, preventing obtaining the same pending run_id
|
84
146
|
with self.lock:
|
85
|
-
# Attempt getting the run_id of a pending run
|
86
|
-
run_id = state.get_pending_run_id()
|
87
|
-
# If there's no pending run, return an empty response
|
88
|
-
if run_id is None:
|
89
|
-
return PullSimulationInputsResponse()
|
90
|
-
|
91
147
|
# Retrieve Context, Run and Fab for the run_id
|
92
148
|
serverapp_ctxt = state.get_serverapp_context(run_id)
|
93
149
|
run = state.get_run(run_id)
|
@@ -99,7 +155,7 @@ class SimulationIoServicer(simulationio_pb2_grpc.SimulationIoServicer):
|
|
99
155
|
# Update run status to STARTING
|
100
156
|
if state.update_run_status(run_id, RunStatus(Status.STARTING, "", "")):
|
101
157
|
log(INFO, "Starting run %d", run_id)
|
102
|
-
return
|
158
|
+
return PullAppInputsResponse(
|
103
159
|
context=context_to_proto(serverapp_ctxt),
|
104
160
|
run=run_to_proto(run),
|
105
161
|
fab=fab_to_proto(fab),
|
@@ -109,11 +165,16 @@ class SimulationIoServicer(simulationio_pb2_grpc.SimulationIoServicer):
|
|
109
165
|
# or if the status cannot be updated to STARTING
|
110
166
|
raise RuntimeError(f"Failed to start run {run_id}")
|
111
167
|
|
112
|
-
def
|
113
|
-
self, request:
|
114
|
-
) ->
|
168
|
+
def PushAppOutputs(
|
169
|
+
self, request: PushAppOutputsRequest, context: ServicerContext
|
170
|
+
) -> PushAppOutputsResponse:
|
115
171
|
"""Push Simulation process outputs."""
|
116
|
-
log(DEBUG, "SimultionIoServicer.
|
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
|
117
178
|
state = self.state_factory.state()
|
118
179
|
|
119
180
|
# Abort if the run is not running
|
@@ -126,7 +187,10 @@ class SimulationIoServicer(simulationio_pb2_grpc.SimulationIoServicer):
|
|
126
187
|
)
|
127
188
|
|
128
189
|
state.set_serverapp_context(request.run_id, context_from_proto(request.context))
|
129
|
-
|
190
|
+
|
191
|
+
# Remove the token
|
192
|
+
state.delete_token(run_id)
|
193
|
+
return PushAppOutputsResponse()
|
130
194
|
|
131
195
|
def UpdateRunStatus(
|
132
196
|
self, request: UpdateRunStatusRequest, context: grpc.ServicerContext
|
@@ -208,3 +272,15 @@ class SimulationIoServicer(simulationio_pb2_grpc.SimulationIoServicer):
|
|
208
272
|
)
|
209
273
|
|
210
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
|
@@ -57,19 +56,20 @@ from flwr.common.serde import (
|
|
57
56
|
run_status_to_proto,
|
58
57
|
)
|
59
58
|
from flwr.common.typing import RunStatus
|
59
|
+
from flwr.proto.appio_pb2 import ( # pylint: disable=E0611
|
60
|
+
PullAppInputsRequest,
|
61
|
+
PullAppInputsResponse,
|
62
|
+
PushAppOutputsRequest,
|
63
|
+
)
|
60
64
|
from flwr.proto.run_pb2 import ( # pylint: disable=E0611
|
61
65
|
GetFederationOptionsRequest,
|
62
66
|
GetFederationOptionsResponse,
|
63
67
|
UpdateRunStatusRequest,
|
64
68
|
)
|
65
|
-
from flwr.proto.simulationio_pb2 import ( # pylint: disable=E0611
|
66
|
-
PullSimulationInputsRequest,
|
67
|
-
PullSimulationInputsResponse,
|
68
|
-
PushSimulationOutputsRequest,
|
69
|
-
)
|
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:
|
130
|
-
#
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
sleep(3)
|
135
|
-
run_status = None
|
136
|
-
continue
|
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)
|
137
142
|
|
143
|
+
# Pull SimulationInputs from LinkState
|
144
|
+
req = PullAppInputsRequest(token=token)
|
145
|
+
res: PullAppInputsResponse = conn._stub.PullAppInputs(req)
|
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,10 +248,10 @@ 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 =
|
244
|
-
run_id=run.run_id, context=context_proto
|
251
|
+
out_req = PushAppOutputsRequest(
|
252
|
+
token=token, run_id=run.run_id, context=context_proto
|
245
253
|
)
|
246
|
-
_ = conn._stub.
|
254
|
+
_ = conn._stub.PushAppOutputs(out_req)
|
247
255
|
|
248
256
|
run_status = RunStatus(Status.FINISHED, SubStatus.COMPLETED, "")
|
249
257
|
|
@@ -277,6 +285,9 @@ def run_simulation_process( # pylint: disable=R0914, disable=W0212, disable=R09
|
|
277
285
|
del updated_context
|
278
286
|
except NameError:
|
279
287
|
pass
|
288
|
+
|
289
|
+
# Remove the token
|
290
|
+
token = None
|
280
291
|
gc.collect()
|
281
292
|
|
282
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.dev20250811.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.dev20250811.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=
|
224
|
-
flwr/proto/simulationio_pb2.pyi,sha256=
|
225
|
-
flwr/proto/simulationio_pb2_grpc.py,sha256=
|
226
|
-
flwr/proto/simulationio_pb2_grpc.pyi,sha256=
|
223
|
+
flwr/proto/simulationio_pb2.py,sha256=9XIMVuYUP5GsRh2ppp6mWw-IF50TY1xt6MWGR0xveMs,2733
|
224
|
+
flwr/proto/simulationio_pb2.pyi,sha256=XbFvpZvvrS7QcH5AFXfpRGl4hQvhd3QdKO6x0oTlCCU,165
|
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.dev20250811.dist-info → flwr_nightly-1.21.0.dev20250813.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|