flwr-nightly 1.14.0.dev20241215__py3-none-any.whl → 1.14.0.dev20241217__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.
Potentially problematic release.
This version of flwr-nightly might be problematic. Click here for more details.
- flwr/cli/log.py +9 -7
- flwr/cli/login/login.py +1 -3
- flwr/cli/ls.py +25 -22
- flwr/cli/run/run.py +11 -18
- flwr/cli/stop.py +71 -32
- flwr/cli/utils.py +26 -16
- flwr/client/app.py +11 -1
- flwr/client/client.py +0 -32
- flwr/client/clientapp/app.py +3 -1
- flwr/client/grpc_rere_client/connection.py +10 -4
- flwr/client/message_handler/message_handler.py +0 -2
- flwr/client/numpy_client.py +0 -44
- flwr/common/logger.py +16 -1
- flwr/common/retry_invoker.py +3 -1
- flwr/server/app.py +7 -8
- flwr/server/superlink/driver/serverappio_servicer.py +9 -0
- flwr/server/superlink/fleet/message_handler/message_handler.py +1 -3
- flwr/server/superlink/linkstate/sqlite_linkstate.py +0 -2
- flwr/server/superlink/simulation/simulationio_servicer.py +13 -0
- flwr/simulation/app.py +3 -2
- flwr/simulation/run_simulation.py +27 -21
- flwr/simulation/simulationio_connection.py +3 -0
- {flwr_nightly-1.14.0.dev20241215.dist-info → flwr_nightly-1.14.0.dev20241217.dist-info}/METADATA +1 -1
- {flwr_nightly-1.14.0.dev20241215.dist-info → flwr_nightly-1.14.0.dev20241217.dist-info}/RECORD +27 -27
- {flwr_nightly-1.14.0.dev20241215.dist-info → flwr_nightly-1.14.0.dev20241217.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.14.0.dev20241215.dist-info → flwr_nightly-1.14.0.dev20241217.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.14.0.dev20241215.dist-info → flwr_nightly-1.14.0.dev20241217.dist-info}/entry_points.txt +0 -0
flwr/cli/log.py
CHANGED
|
@@ -34,7 +34,7 @@ from flwr.common.logger import log as logger
|
|
|
34
34
|
from flwr.proto.exec_pb2 import StreamLogsRequest # pylint: disable=E0611
|
|
35
35
|
from flwr.proto.exec_pb2_grpc import ExecStub
|
|
36
36
|
|
|
37
|
-
from .utils import init_channel, try_obtain_cli_auth_plugin
|
|
37
|
+
from .utils import init_channel, try_obtain_cli_auth_plugin, unauthenticated_exc_handler
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
def start_stream(
|
|
@@ -88,8 +88,9 @@ def stream_logs(
|
|
|
88
88
|
latest_timestamp = 0.0
|
|
89
89
|
res = None
|
|
90
90
|
try:
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
with unauthenticated_exc_handler():
|
|
92
|
+
for res in stub.StreamLogs(req, timeout=duration):
|
|
93
|
+
print(res.log_output, end="")
|
|
93
94
|
except grpc.RpcError as e:
|
|
94
95
|
# pylint: disable=E1101
|
|
95
96
|
if e.code() != grpc.StatusCode.DEADLINE_EXCEEDED:
|
|
@@ -109,9 +110,10 @@ def print_logs(run_id: int, channel: grpc.Channel, timeout: int) -> None:
|
|
|
109
110
|
try:
|
|
110
111
|
while True:
|
|
111
112
|
try:
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
with unauthenticated_exc_handler():
|
|
114
|
+
# Enforce timeout for graceful exit
|
|
115
|
+
for res in stub.StreamLogs(req, timeout=timeout):
|
|
116
|
+
print(res.log_output)
|
|
115
117
|
except grpc.RpcError as e:
|
|
116
118
|
# pylint: disable=E1101
|
|
117
119
|
if e.code() == grpc.StatusCode.DEADLINE_EXCEEDED:
|
|
@@ -170,7 +172,7 @@ def _log_with_exec_api(
|
|
|
170
172
|
run_id: int,
|
|
171
173
|
stream: bool,
|
|
172
174
|
) -> None:
|
|
173
|
-
auth_plugin = try_obtain_cli_auth_plugin(app, federation
|
|
175
|
+
auth_plugin = try_obtain_cli_auth_plugin(app, federation)
|
|
174
176
|
channel = init_channel(app, federation_config, auth_plugin)
|
|
175
177
|
|
|
176
178
|
if stream:
|
flwr/cli/login/login.py
CHANGED
|
@@ -65,9 +65,7 @@ def login( # pylint: disable=R0914
|
|
|
65
65
|
|
|
66
66
|
# Get the auth plugin
|
|
67
67
|
auth_type = login_response.login_details.get(AUTH_TYPE)
|
|
68
|
-
auth_plugin = try_obtain_cli_auth_plugin(
|
|
69
|
-
app, federation, federation_config, auth_type
|
|
70
|
-
)
|
|
68
|
+
auth_plugin = try_obtain_cli_auth_plugin(app, federation, auth_type)
|
|
71
69
|
if auth_plugin is None:
|
|
72
70
|
typer.secho(
|
|
73
71
|
f'❌ Authentication type "{auth_type}" not found',
|
flwr/cli/ls.py
CHANGED
|
@@ -19,13 +19,12 @@ import io
|
|
|
19
19
|
import json
|
|
20
20
|
from datetime import datetime, timedelta
|
|
21
21
|
from pathlib import Path
|
|
22
|
-
from typing import Annotated, Optional
|
|
22
|
+
from typing import Annotated, Optional
|
|
23
23
|
|
|
24
24
|
import typer
|
|
25
25
|
from rich.console import Console
|
|
26
26
|
from rich.table import Table
|
|
27
27
|
from rich.text import Text
|
|
28
|
-
from typer import Exit
|
|
29
28
|
|
|
30
29
|
from flwr.cli.config_utils import (
|
|
31
30
|
exit_if_no_address,
|
|
@@ -35,7 +34,7 @@ from flwr.cli.config_utils import (
|
|
|
35
34
|
)
|
|
36
35
|
from flwr.common.constant import FAB_CONFIG_FILE, CliOutputFormat, SubStatus
|
|
37
36
|
from flwr.common.date import format_timedelta, isoformat8601_utc
|
|
38
|
-
from flwr.common.logger import
|
|
37
|
+
from flwr.common.logger import print_json_error, redirect_output, restore_output
|
|
39
38
|
from flwr.common.serde import run_from_proto
|
|
40
39
|
from flwr.common.typing import Run
|
|
41
40
|
from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
|
|
@@ -44,7 +43,7 @@ from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
|
|
|
44
43
|
)
|
|
45
44
|
from flwr.proto.exec_pb2_grpc import ExecStub
|
|
46
45
|
|
|
47
|
-
from .utils import init_channel, try_obtain_cli_auth_plugin
|
|
46
|
+
from .utils import init_channel, try_obtain_cli_auth_plugin, unauthenticated_exc_handler
|
|
48
47
|
|
|
49
48
|
_RunListType = tuple[int, str, str, str, str, str, str, str, str]
|
|
50
49
|
|
|
@@ -81,13 +80,25 @@ def ls( # pylint: disable=too-many-locals, too-many-branches
|
|
|
81
80
|
),
|
|
82
81
|
] = CliOutputFormat.DEFAULT,
|
|
83
82
|
) -> None:
|
|
84
|
-
"""List runs.
|
|
83
|
+
"""List the details of one provided run ID or all runs in a Flower federation.
|
|
84
|
+
|
|
85
|
+
The following details are displayed:
|
|
86
|
+
|
|
87
|
+
- **Run ID:** Unique identifier for the run.
|
|
88
|
+
- **FAB:** Name of the FAB associated with the run (``{FAB_ID} (v{FAB_VERSION})``).
|
|
89
|
+
- **Status:** Current status of the run (pending, starting, running, finished).
|
|
90
|
+
- **Elapsed:** Time elapsed since the run started (``HH:MM:SS``).
|
|
91
|
+
- **Created At:** Timestamp when the run was created.
|
|
92
|
+
- **Running At:** Timestamp when the run started running.
|
|
93
|
+
- **Finished At:** Timestamp when the run finished.
|
|
94
|
+
|
|
95
|
+
All timestamps follow ISO 8601, UTC and are formatted as ``YYYY-MM-DD HH:MM:SSZ``.
|
|
96
|
+
"""
|
|
85
97
|
suppress_output = output_format == CliOutputFormat.JSON
|
|
86
98
|
captured_output = io.StringIO()
|
|
87
99
|
try:
|
|
88
100
|
if suppress_output:
|
|
89
101
|
redirect_output(captured_output)
|
|
90
|
-
|
|
91
102
|
# Load and validate federation config
|
|
92
103
|
typer.secho("Loading project configuration... ", fg=typer.colors.BLUE)
|
|
93
104
|
|
|
@@ -104,7 +115,7 @@ def ls( # pylint: disable=too-many-locals, too-many-branches
|
|
|
104
115
|
raise ValueError(
|
|
105
116
|
"The options '--runs' and '--run-id' are mutually exclusive."
|
|
106
117
|
)
|
|
107
|
-
auth_plugin = try_obtain_cli_auth_plugin(app, federation
|
|
118
|
+
auth_plugin = try_obtain_cli_auth_plugin(app, federation)
|
|
108
119
|
channel = init_channel(app, federation_config, auth_plugin)
|
|
109
120
|
stub = ExecStub(channel)
|
|
110
121
|
|
|
@@ -120,6 +131,8 @@ def ls( # pylint: disable=too-many-locals, too-many-branches
|
|
|
120
131
|
_list_runs(stub, output_format)
|
|
121
132
|
|
|
122
133
|
except ValueError as err:
|
|
134
|
+
if suppress_output:
|
|
135
|
+
redirect_output(captured_output)
|
|
123
136
|
typer.secho(
|
|
124
137
|
f"❌ {err}",
|
|
125
138
|
fg=typer.colors.RED,
|
|
@@ -132,7 +145,7 @@ def ls( # pylint: disable=too-many-locals, too-many-branches
|
|
|
132
145
|
if suppress_output:
|
|
133
146
|
restore_output()
|
|
134
147
|
e_message = captured_output.getvalue()
|
|
135
|
-
|
|
148
|
+
print_json_error(e_message, err)
|
|
136
149
|
else:
|
|
137
150
|
typer.secho(
|
|
138
151
|
f"{err}",
|
|
@@ -283,7 +296,8 @@ def _list_runs(
|
|
|
283
296
|
output_format: str = CliOutputFormat.DEFAULT,
|
|
284
297
|
) -> None:
|
|
285
298
|
"""List all runs."""
|
|
286
|
-
|
|
299
|
+
with unauthenticated_exc_handler():
|
|
300
|
+
res: ListRunsResponse = stub.ListRuns(ListRunsRequest())
|
|
287
301
|
run_dict = {run_id: run_from_proto(proto) for run_id, proto in res.run_dict.items()}
|
|
288
302
|
|
|
289
303
|
formatted_runs = _format_runs(run_dict, res.now)
|
|
@@ -299,7 +313,8 @@ def _display_one_run(
|
|
|
299
313
|
output_format: str = CliOutputFormat.DEFAULT,
|
|
300
314
|
) -> None:
|
|
301
315
|
"""Display information about a specific run."""
|
|
302
|
-
|
|
316
|
+
with unauthenticated_exc_handler():
|
|
317
|
+
res: ListRunsResponse = stub.ListRuns(ListRunsRequest(run_id=run_id))
|
|
303
318
|
if not res.run_dict:
|
|
304
319
|
raise ValueError(f"Run ID {run_id} not found")
|
|
305
320
|
|
|
@@ -310,15 +325,3 @@ def _display_one_run(
|
|
|
310
325
|
Console().print_json(_to_json(formatted_runs))
|
|
311
326
|
else:
|
|
312
327
|
Console().print(_to_table(formatted_runs))
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
def _print_json_error(msg: str, e: Union[Exit, Exception]) -> None:
|
|
316
|
-
"""Print error message as JSON."""
|
|
317
|
-
Console().print_json(
|
|
318
|
-
json.dumps(
|
|
319
|
-
{
|
|
320
|
-
"success": False,
|
|
321
|
-
"error-message": remove_emojis(str(msg) + "\n" + str(e)),
|
|
322
|
-
}
|
|
323
|
-
)
|
|
324
|
-
)
|
flwr/cli/run/run.py
CHANGED
|
@@ -19,7 +19,7 @@ import io
|
|
|
19
19
|
import json
|
|
20
20
|
import subprocess
|
|
21
21
|
from pathlib import Path
|
|
22
|
-
from typing import Annotated, Any, Optional
|
|
22
|
+
from typing import Annotated, Any, Optional
|
|
23
23
|
|
|
24
24
|
import typer
|
|
25
25
|
from rich.console import Console
|
|
@@ -37,7 +37,7 @@ from flwr.common.config import (
|
|
|
37
37
|
user_config_to_configsrecord,
|
|
38
38
|
)
|
|
39
39
|
from flwr.common.constant import CliOutputFormat
|
|
40
|
-
from flwr.common.logger import
|
|
40
|
+
from flwr.common.logger import print_json_error, redirect_output, restore_output
|
|
41
41
|
from flwr.common.serde import (
|
|
42
42
|
configs_record_to_proto,
|
|
43
43
|
fab_to_proto,
|
|
@@ -48,7 +48,11 @@ from flwr.proto.exec_pb2 import StartRunRequest # pylint: disable=E0611
|
|
|
48
48
|
from flwr.proto.exec_pb2_grpc import ExecStub
|
|
49
49
|
|
|
50
50
|
from ..log import start_stream
|
|
51
|
-
from ..utils import
|
|
51
|
+
from ..utils import (
|
|
52
|
+
init_channel,
|
|
53
|
+
try_obtain_cli_auth_plugin,
|
|
54
|
+
unauthenticated_exc_handler,
|
|
55
|
+
)
|
|
52
56
|
|
|
53
57
|
CONN_REFRESH_PERIOD = 60 # Connection refresh period for log streaming (seconds)
|
|
54
58
|
|
|
@@ -122,7 +126,7 @@ def run(
|
|
|
122
126
|
if suppress_output:
|
|
123
127
|
restore_output()
|
|
124
128
|
e_message = captured_output.getvalue()
|
|
125
|
-
|
|
129
|
+
print_json_error(e_message, err)
|
|
126
130
|
else:
|
|
127
131
|
typer.secho(
|
|
128
132
|
f"{err}",
|
|
@@ -144,7 +148,7 @@ def _run_with_exec_api(
|
|
|
144
148
|
stream: bool,
|
|
145
149
|
output_format: str,
|
|
146
150
|
) -> None:
|
|
147
|
-
auth_plugin = try_obtain_cli_auth_plugin(app, federation
|
|
151
|
+
auth_plugin = try_obtain_cli_auth_plugin(app, federation)
|
|
148
152
|
channel = init_channel(app, federation_config, auth_plugin)
|
|
149
153
|
stub = ExecStub(channel)
|
|
150
154
|
|
|
@@ -166,7 +170,8 @@ def _run_with_exec_api(
|
|
|
166
170
|
override_config=user_config_to_proto(parse_config_args(config_overrides)),
|
|
167
171
|
federation_options=configs_record_to_proto(c_record),
|
|
168
172
|
)
|
|
169
|
-
|
|
173
|
+
with unauthenticated_exc_handler():
|
|
174
|
+
res = stub.StartRun(req)
|
|
170
175
|
|
|
171
176
|
if res.HasField("run_id"):
|
|
172
177
|
typer.secho(f"🎊 Successfully started run {res.run_id}", fg=typer.colors.GREEN)
|
|
@@ -239,15 +244,3 @@ def _run_without_exec_api(
|
|
|
239
244
|
check=True,
|
|
240
245
|
text=True,
|
|
241
246
|
)
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
def _print_json_error(msg: str, e: Union[typer.Exit, Exception]) -> None:
|
|
245
|
-
"""Print error message as JSON."""
|
|
246
|
-
Console().print_json(
|
|
247
|
-
json.dumps(
|
|
248
|
-
{
|
|
249
|
-
"success": False,
|
|
250
|
-
"error-message": remove_emojis(str(msg) + "\n" + str(e)),
|
|
251
|
-
}
|
|
252
|
-
)
|
|
253
|
-
)
|
flwr/cli/stop.py
CHANGED
|
@@ -15,10 +15,13 @@
|
|
|
15
15
|
"""Flower command line interface `stop` command."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
import io
|
|
19
|
+
import json
|
|
18
20
|
from pathlib import Path
|
|
19
21
|
from typing import Annotated, Optional
|
|
20
22
|
|
|
21
23
|
import typer
|
|
24
|
+
from rich.console import Console
|
|
22
25
|
|
|
23
26
|
from flwr.cli.config_utils import (
|
|
24
27
|
exit_if_no_address,
|
|
@@ -26,14 +29,15 @@ from flwr.cli.config_utils import (
|
|
|
26
29
|
process_loaded_project_config,
|
|
27
30
|
validate_federation_in_project_config,
|
|
28
31
|
)
|
|
29
|
-
from flwr.common.constant import FAB_CONFIG_FILE
|
|
32
|
+
from flwr.common.constant import FAB_CONFIG_FILE, CliOutputFormat
|
|
33
|
+
from flwr.common.logger import print_json_error, redirect_output, restore_output
|
|
30
34
|
from flwr.proto.exec_pb2 import StopRunRequest, StopRunResponse # pylint: disable=E0611
|
|
31
35
|
from flwr.proto.exec_pb2_grpc import ExecStub
|
|
32
36
|
|
|
33
|
-
from .utils import init_channel, try_obtain_cli_auth_plugin
|
|
37
|
+
from .utils import init_channel, try_obtain_cli_auth_plugin, unauthenticated_exc_handler
|
|
34
38
|
|
|
35
39
|
|
|
36
|
-
def stop(
|
|
40
|
+
def stop( # pylint: disable=R0914
|
|
37
41
|
run_id: Annotated[ # pylint: disable=unused-argument
|
|
38
42
|
int,
|
|
39
43
|
typer.Argument(help="The Flower run ID to stop"),
|
|
@@ -46,46 +50,81 @@ def stop(
|
|
|
46
50
|
Optional[str],
|
|
47
51
|
typer.Argument(help="Name of the federation"),
|
|
48
52
|
] = None,
|
|
53
|
+
output_format: Annotated[
|
|
54
|
+
str,
|
|
55
|
+
typer.Option(
|
|
56
|
+
"--format",
|
|
57
|
+
case_sensitive=False,
|
|
58
|
+
help="Format output using 'default' view or 'json'",
|
|
59
|
+
),
|
|
60
|
+
] = CliOutputFormat.DEFAULT,
|
|
49
61
|
) -> None:
|
|
50
62
|
"""Stop a run."""
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
pyproject_path = app / FAB_CONFIG_FILE if app else None
|
|
55
|
-
config, errors, warnings = load_and_validate(path=pyproject_path)
|
|
56
|
-
config = process_loaded_project_config(config, errors, warnings)
|
|
57
|
-
federation, federation_config = validate_federation_in_project_config(
|
|
58
|
-
federation, config
|
|
59
|
-
)
|
|
60
|
-
exit_if_no_address(federation_config, "stop")
|
|
61
|
-
|
|
63
|
+
suppress_output = output_format == CliOutputFormat.JSON
|
|
64
|
+
captured_output = io.StringIO()
|
|
62
65
|
try:
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
stub = ExecStub(channel) # pylint: disable=unused-variable # noqa: F841
|
|
66
|
+
if suppress_output:
|
|
67
|
+
redirect_output(captured_output)
|
|
66
68
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
# Load and validate federation config
|
|
70
|
+
typer.secho("Loading project configuration... ", fg=typer.colors.BLUE)
|
|
69
71
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
pyproject_path = app / FAB_CONFIG_FILE if app else None
|
|
73
|
+
config, errors, warnings = load_and_validate(path=pyproject_path)
|
|
74
|
+
config = process_loaded_project_config(config, errors, warnings)
|
|
75
|
+
federation, federation_config = validate_federation_in_project_config(
|
|
76
|
+
federation, config
|
|
75
77
|
)
|
|
76
|
-
|
|
78
|
+
exit_if_no_address(federation_config, "stop")
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
auth_plugin = try_obtain_cli_auth_plugin(app, federation)
|
|
82
|
+
channel = init_channel(app, federation_config, auth_plugin)
|
|
83
|
+
stub = ExecStub(channel) # pylint: disable=unused-variable # noqa: F841
|
|
84
|
+
|
|
85
|
+
typer.secho(f"✋ Stopping run ID {run_id}...", fg=typer.colors.GREEN)
|
|
86
|
+
_stop_run(stub=stub, run_id=run_id, output_format=output_format)
|
|
87
|
+
|
|
88
|
+
except ValueError as err:
|
|
89
|
+
typer.secho(
|
|
90
|
+
f"❌ {err}",
|
|
91
|
+
fg=typer.colors.RED,
|
|
92
|
+
bold=True,
|
|
93
|
+
)
|
|
94
|
+
raise typer.Exit(code=1) from err
|
|
95
|
+
finally:
|
|
96
|
+
channel.close()
|
|
97
|
+
except (typer.Exit, Exception) as err: # pylint: disable=broad-except
|
|
98
|
+
if suppress_output:
|
|
99
|
+
restore_output()
|
|
100
|
+
e_message = captured_output.getvalue()
|
|
101
|
+
print_json_error(e_message, err)
|
|
102
|
+
else:
|
|
103
|
+
typer.secho(
|
|
104
|
+
f"{err}",
|
|
105
|
+
fg=typer.colors.RED,
|
|
106
|
+
bold=True,
|
|
107
|
+
)
|
|
77
108
|
finally:
|
|
78
|
-
|
|
109
|
+
if suppress_output:
|
|
110
|
+
restore_output()
|
|
111
|
+
captured_output.close()
|
|
79
112
|
|
|
80
113
|
|
|
81
|
-
def _stop_run(
|
|
82
|
-
stub: ExecStub, # pylint: disable=unused-argument
|
|
83
|
-
run_id: int, # pylint: disable=unused-argument
|
|
84
|
-
) -> None:
|
|
114
|
+
def _stop_run(stub: ExecStub, run_id: int, output_format: str) -> None:
|
|
85
115
|
"""Stop a run."""
|
|
86
|
-
|
|
87
|
-
|
|
116
|
+
with unauthenticated_exc_handler():
|
|
117
|
+
response: StopRunResponse = stub.StopRun(request=StopRunRequest(run_id=run_id))
|
|
88
118
|
if response.success:
|
|
89
119
|
typer.secho(f"✅ Run {run_id} successfully stopped.", fg=typer.colors.GREEN)
|
|
120
|
+
if output_format == CliOutputFormat.JSON:
|
|
121
|
+
run_output = json.dumps(
|
|
122
|
+
{
|
|
123
|
+
"success": True,
|
|
124
|
+
"run-id": run_id,
|
|
125
|
+
}
|
|
126
|
+
)
|
|
127
|
+
restore_output()
|
|
128
|
+
Console().print_json(run_output)
|
|
90
129
|
else:
|
|
91
130
|
typer.secho(f"❌ Run {run_id} couldn't be stopped.", fg=typer.colors.RED)
|
flwr/cli/utils.py
CHANGED
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
import hashlib
|
|
19
19
|
import json
|
|
20
20
|
import re
|
|
21
|
+
from collections.abc import Iterator
|
|
22
|
+
from contextlib import contextmanager
|
|
21
23
|
from logging import DEBUG
|
|
22
24
|
from pathlib import Path
|
|
23
25
|
from typing import Any, Callable, Optional, cast
|
|
@@ -26,7 +28,6 @@ import grpc
|
|
|
26
28
|
import typer
|
|
27
29
|
|
|
28
30
|
from flwr.cli.cli_user_auth_interceptor import CliUserAuthInterceptor
|
|
29
|
-
from flwr.common.address import parse_address
|
|
30
31
|
from flwr.common.auth_plugin import CliAuthPlugin
|
|
31
32
|
from flwr.common.constant import AUTH_TYPE, CREDENTIALS_DIR, FLWR_DIR
|
|
32
33
|
from flwr.common.grpc import GRPC_MAX_MESSAGE_LENGTH, create_channel
|
|
@@ -159,33 +160,21 @@ def get_sha256_hash(file_path: Path) -> str:
|
|
|
159
160
|
return sha256.hexdigest()
|
|
160
161
|
|
|
161
162
|
|
|
162
|
-
def get_user_auth_config_path(
|
|
163
|
-
root_dir: Path, federation: str, server_address: str
|
|
164
|
-
) -> Path:
|
|
163
|
+
def get_user_auth_config_path(root_dir: Path, federation: str) -> Path:
|
|
165
164
|
"""Return the path to the user auth config file."""
|
|
166
|
-
# Parse the server address
|
|
167
|
-
parsed_addr = parse_address(server_address)
|
|
168
|
-
if parsed_addr is None:
|
|
169
|
-
raise ValueError(f"Invalid server address: {server_address}")
|
|
170
|
-
host, port, is_v6 = parsed_addr
|
|
171
|
-
formatted_addr = f"[{host}]_{port}" if is_v6 else f"{host}_{port}"
|
|
172
|
-
|
|
173
165
|
# Locate the credentials directory
|
|
174
166
|
credentials_dir = root_dir.absolute() / FLWR_DIR / CREDENTIALS_DIR
|
|
175
167
|
credentials_dir.mkdir(parents=True, exist_ok=True)
|
|
176
|
-
return credentials_dir / f"{federation}
|
|
168
|
+
return credentials_dir / f"{federation}.json"
|
|
177
169
|
|
|
178
170
|
|
|
179
171
|
def try_obtain_cli_auth_plugin(
|
|
180
172
|
root_dir: Path,
|
|
181
173
|
federation: str,
|
|
182
|
-
federation_config: dict[str, Any],
|
|
183
174
|
auth_type: Optional[str] = None,
|
|
184
175
|
) -> Optional[CliAuthPlugin]:
|
|
185
176
|
"""Load the CLI-side user auth plugin for the given auth type."""
|
|
186
|
-
config_path = get_user_auth_config_path(
|
|
187
|
-
root_dir, federation, federation_config["address"]
|
|
188
|
-
)
|
|
177
|
+
config_path = get_user_auth_config_path(root_dir, federation)
|
|
189
178
|
|
|
190
179
|
# Load the config file if it exists
|
|
191
180
|
config: dict[str, Any] = {}
|
|
@@ -244,3 +233,24 @@ def init_channel(
|
|
|
244
233
|
)
|
|
245
234
|
channel.subscribe(on_channel_state_change)
|
|
246
235
|
return channel
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
@contextmanager
|
|
239
|
+
def unauthenticated_exc_handler() -> Iterator[None]:
|
|
240
|
+
"""Context manager to handle gRPC UNAUTHENTICATED errors.
|
|
241
|
+
|
|
242
|
+
It catches grpc.RpcError exceptions with UNAUTHENTICATED status, informs the user,
|
|
243
|
+
and exits the application. All other exceptions will be allowed to escape.
|
|
244
|
+
"""
|
|
245
|
+
try:
|
|
246
|
+
yield
|
|
247
|
+
except grpc.RpcError as e:
|
|
248
|
+
if e.code() != grpc.StatusCode.UNAUTHENTICATED:
|
|
249
|
+
raise
|
|
250
|
+
typer.secho(
|
|
251
|
+
"❌ Authentication failed. Please run `flwr login`"
|
|
252
|
+
" to authenticate and try again.",
|
|
253
|
+
fg=typer.colors.RED,
|
|
254
|
+
bold=True,
|
|
255
|
+
)
|
|
256
|
+
raise typer.Exit(code=1) from None
|
flwr/client/app.py
CHANGED
|
@@ -56,7 +56,7 @@ from flwr.common.constant import (
|
|
|
56
56
|
from flwr.common.logger import log, warn_deprecated_feature
|
|
57
57
|
from flwr.common.message import Error
|
|
58
58
|
from flwr.common.retry_invoker import RetryInvoker, RetryState, exponential
|
|
59
|
-
from flwr.common.typing import Fab, Run, UserConfig
|
|
59
|
+
from flwr.common.typing import Fab, Run, RunNotRunningException, UserConfig
|
|
60
60
|
from flwr.proto.clientappio_pb2_grpc import add_ClientAppIoServicer_to_server
|
|
61
61
|
from flwr.server.superlink.fleet.grpc_bidi.grpc_server import generic_create_grpc_server
|
|
62
62
|
from flwr.server.superlink.linkstate.utils import generate_rand_int_from_bytes
|
|
@@ -612,6 +612,16 @@ def start_client_internal(
|
|
|
612
612
|
send(reply_message)
|
|
613
613
|
log(INFO, "Sent reply")
|
|
614
614
|
|
|
615
|
+
except RunNotRunningException:
|
|
616
|
+
log(INFO, "")
|
|
617
|
+
log(
|
|
618
|
+
INFO,
|
|
619
|
+
"SuperNode aborted sending the reply message. "
|
|
620
|
+
"Run ID %s is not in `RUNNING` status.",
|
|
621
|
+
run_id,
|
|
622
|
+
)
|
|
623
|
+
log(INFO, "")
|
|
624
|
+
|
|
615
625
|
except StopIteration:
|
|
616
626
|
sleep_duration = 0
|
|
617
627
|
break
|
flwr/client/client.py
CHANGED
|
@@ -22,7 +22,6 @@ from abc import ABC
|
|
|
22
22
|
|
|
23
23
|
from flwr.common import (
|
|
24
24
|
Code,
|
|
25
|
-
Context,
|
|
26
25
|
EvaluateIns,
|
|
27
26
|
EvaluateRes,
|
|
28
27
|
FitIns,
|
|
@@ -34,14 +33,11 @@ from flwr.common import (
|
|
|
34
33
|
Parameters,
|
|
35
34
|
Status,
|
|
36
35
|
)
|
|
37
|
-
from flwr.common.logger import warn_deprecated_feature_with_example
|
|
38
36
|
|
|
39
37
|
|
|
40
38
|
class Client(ABC):
|
|
41
39
|
"""Abstract base class for Flower clients."""
|
|
42
40
|
|
|
43
|
-
_context: Context
|
|
44
|
-
|
|
45
41
|
def get_properties(self, ins: GetPropertiesIns) -> GetPropertiesRes:
|
|
46
42
|
"""Return set of client's properties.
|
|
47
43
|
|
|
@@ -143,34 +139,6 @@ class Client(ABC):
|
|
|
143
139
|
metrics={},
|
|
144
140
|
)
|
|
145
141
|
|
|
146
|
-
@property
|
|
147
|
-
def context(self) -> Context:
|
|
148
|
-
"""Getter for `Context` client attribute."""
|
|
149
|
-
warn_deprecated_feature_with_example(
|
|
150
|
-
"Accessing the context via the client's attribute is deprecated.",
|
|
151
|
-
example_message="Instead, pass it to the client's "
|
|
152
|
-
"constructor in your `client_fn()` which already "
|
|
153
|
-
"receives a context object.",
|
|
154
|
-
code_example="def client_fn(context: Context) -> Client:\n\n"
|
|
155
|
-
"\t\t# Your existing client_fn\n\n"
|
|
156
|
-
"\t\t# Pass `context` to the constructor\n"
|
|
157
|
-
"\t\treturn FlowerClient(context).to_client()",
|
|
158
|
-
)
|
|
159
|
-
return self._context
|
|
160
|
-
|
|
161
|
-
@context.setter
|
|
162
|
-
def context(self, context: Context) -> None:
|
|
163
|
-
"""Setter for `Context` client attribute."""
|
|
164
|
-
self._context = context
|
|
165
|
-
|
|
166
|
-
def get_context(self) -> Context:
|
|
167
|
-
"""Get the run context from this client."""
|
|
168
|
-
return self.context
|
|
169
|
-
|
|
170
|
-
def set_context(self, context: Context) -> None:
|
|
171
|
-
"""Apply a run context to this client."""
|
|
172
|
-
self.context = context
|
|
173
|
-
|
|
174
142
|
def to_client(self) -> Client:
|
|
175
143
|
"""Return client (itself)."""
|
|
176
144
|
return self
|
flwr/client/clientapp/app.py
CHANGED
|
@@ -32,6 +32,7 @@ from flwr.common.constant import CLIENTAPPIO_API_DEFAULT_CLIENT_ADDRESS, ErrorCo
|
|
|
32
32
|
from flwr.common.grpc import create_channel
|
|
33
33
|
from flwr.common.logger import log
|
|
34
34
|
from flwr.common.message import Error
|
|
35
|
+
from flwr.common.retry_invoker import _make_simple_grpc_retry_invoker, _wrap_stub
|
|
35
36
|
from flwr.common.serde import (
|
|
36
37
|
context_from_proto,
|
|
37
38
|
context_to_proto,
|
|
@@ -106,9 +107,9 @@ def run_clientapp( # pylint: disable=R0914
|
|
|
106
107
|
|
|
107
108
|
# Resolve directory where FABs are installed
|
|
108
109
|
flwr_dir_ = get_flwr_dir(flwr_dir)
|
|
109
|
-
|
|
110
110
|
try:
|
|
111
111
|
stub = ClientAppIoStub(channel)
|
|
112
|
+
_wrap_stub(stub, _make_simple_grpc_retry_invoker())
|
|
112
113
|
|
|
113
114
|
while True:
|
|
114
115
|
# If token is not set, loop until token is received from SuperNode
|
|
@@ -139,6 +140,7 @@ def run_clientapp( # pylint: disable=R0914
|
|
|
139
140
|
|
|
140
141
|
# Execute ClientApp
|
|
141
142
|
reply_message = client_app(message=message, context=context)
|
|
143
|
+
|
|
142
144
|
except Exception as ex: # pylint: disable=broad-exception-caught
|
|
143
145
|
# Don't update/change NodeState
|
|
144
146
|
|
|
@@ -42,7 +42,7 @@ from flwr.common.logger import log
|
|
|
42
42
|
from flwr.common.message import Message, Metadata
|
|
43
43
|
from flwr.common.retry_invoker import RetryInvoker
|
|
44
44
|
from flwr.common.serde import message_from_taskins, message_to_taskres, run_from_proto
|
|
45
|
-
from flwr.common.typing import Fab, Run
|
|
45
|
+
from flwr.common.typing import Fab, Run, RunNotRunningException
|
|
46
46
|
from flwr.proto.fab_pb2 import GetFabRequest, GetFabResponse # pylint: disable=E0611
|
|
47
47
|
from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
|
|
48
48
|
CreateNodeRequest,
|
|
@@ -155,10 +155,16 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
|
155
155
|
ping_thread: Optional[threading.Thread] = None
|
|
156
156
|
ping_stop_event = threading.Event()
|
|
157
157
|
|
|
158
|
+
def _should_giveup_fn(e: Exception) -> bool:
|
|
159
|
+
if e.code() == grpc.StatusCode.PERMISSION_DENIED: # type: ignore
|
|
160
|
+
raise RunNotRunningException
|
|
161
|
+
if e.code() == grpc.StatusCode.UNAVAILABLE: # type: ignore
|
|
162
|
+
return False
|
|
163
|
+
return True
|
|
164
|
+
|
|
158
165
|
# Restrict retries to cases where the status code is UNAVAILABLE
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
)
|
|
166
|
+
# If the status code is PERMISSION_DENIED, additionally raise RunNotRunningException
|
|
167
|
+
retry_invoker.should_giveup = _should_giveup_fn
|
|
162
168
|
|
|
163
169
|
###########################################################################
|
|
164
170
|
# ping/create_node/delete_node/receive/send/get_run functions
|
flwr/client/numpy_client.py
CHANGED
|
@@ -21,13 +21,11 @@ from typing import Callable
|
|
|
21
21
|
from flwr.client.client import Client
|
|
22
22
|
from flwr.common import (
|
|
23
23
|
Config,
|
|
24
|
-
Context,
|
|
25
24
|
NDArrays,
|
|
26
25
|
Scalar,
|
|
27
26
|
ndarrays_to_parameters,
|
|
28
27
|
parameters_to_ndarrays,
|
|
29
28
|
)
|
|
30
|
-
from flwr.common.logger import warn_deprecated_feature_with_example
|
|
31
29
|
from flwr.common.typing import (
|
|
32
30
|
Code,
|
|
33
31
|
EvaluateIns,
|
|
@@ -71,8 +69,6 @@ Example
|
|
|
71
69
|
class NumPyClient(ABC):
|
|
72
70
|
"""Abstract base class for Flower clients using NumPy."""
|
|
73
71
|
|
|
74
|
-
_context: Context
|
|
75
|
-
|
|
76
72
|
def get_properties(self, config: Config) -> dict[str, Scalar]:
|
|
77
73
|
"""Return a client's set of properties.
|
|
78
74
|
|
|
@@ -175,34 +171,6 @@ class NumPyClient(ABC):
|
|
|
175
171
|
_ = (self, parameters, config)
|
|
176
172
|
return 0.0, 0, {}
|
|
177
173
|
|
|
178
|
-
@property
|
|
179
|
-
def context(self) -> Context:
|
|
180
|
-
"""Getter for `Context` client attribute."""
|
|
181
|
-
warn_deprecated_feature_with_example(
|
|
182
|
-
"Accessing the context via the client's attribute is deprecated.",
|
|
183
|
-
example_message="Instead, pass it to the client's "
|
|
184
|
-
"constructor in your `client_fn()` which already "
|
|
185
|
-
"receives a context object.",
|
|
186
|
-
code_example="def client_fn(context: Context) -> Client:\n\n"
|
|
187
|
-
"\t\t# Your existing client_fn\n\n"
|
|
188
|
-
"\t\t# Pass `context` to the constructor\n"
|
|
189
|
-
"\t\treturn FlowerClient(context).to_client()",
|
|
190
|
-
)
|
|
191
|
-
return self._context
|
|
192
|
-
|
|
193
|
-
@context.setter
|
|
194
|
-
def context(self, context: Context) -> None:
|
|
195
|
-
"""Setter for `Context` client attribute."""
|
|
196
|
-
self._context = context
|
|
197
|
-
|
|
198
|
-
def get_context(self) -> Context:
|
|
199
|
-
"""Get the run context from this client."""
|
|
200
|
-
return self.context
|
|
201
|
-
|
|
202
|
-
def set_context(self, context: Context) -> None:
|
|
203
|
-
"""Apply a run context to this client."""
|
|
204
|
-
self.context = context
|
|
205
|
-
|
|
206
174
|
def to_client(self) -> Client:
|
|
207
175
|
"""Convert to object to Client type and return it."""
|
|
208
176
|
return _wrap_numpy_client(client=self)
|
|
@@ -299,21 +267,9 @@ def _evaluate(self: Client, ins: EvaluateIns) -> EvaluateRes:
|
|
|
299
267
|
)
|
|
300
268
|
|
|
301
269
|
|
|
302
|
-
def _get_context(self: Client) -> Context:
|
|
303
|
-
"""Return context of underlying NumPyClient."""
|
|
304
|
-
return self.numpy_client.get_context() # type: ignore
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
def _set_context(self: Client, context: Context) -> None:
|
|
308
|
-
"""Apply context to underlying NumPyClient."""
|
|
309
|
-
self.numpy_client.set_context(context) # type: ignore
|
|
310
|
-
|
|
311
|
-
|
|
312
270
|
def _wrap_numpy_client(client: NumPyClient) -> Client:
|
|
313
271
|
member_dict: dict[str, Callable] = { # type: ignore
|
|
314
272
|
"__init__": _constructor,
|
|
315
|
-
"get_context": _get_context,
|
|
316
|
-
"set_context": _set_context,
|
|
317
273
|
}
|
|
318
274
|
|
|
319
275
|
# Add wrapper type methods (if overridden)
|
flwr/common/logger.py
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"""Flower Logger."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
import json as _json
|
|
18
19
|
import logging
|
|
19
20
|
import re
|
|
20
21
|
import sys
|
|
@@ -27,6 +28,8 @@ from queue import Empty, Queue
|
|
|
27
28
|
from typing import TYPE_CHECKING, Any, Optional, TextIO, Union
|
|
28
29
|
|
|
29
30
|
import grpc
|
|
31
|
+
import typer
|
|
32
|
+
from rich.console import Console
|
|
30
33
|
|
|
31
34
|
from flwr.proto.log_pb2 import PushLogsRequest # pylint: disable=E0611
|
|
32
35
|
from flwr.proto.node_pb2 import Node # pylint: disable=E0611
|
|
@@ -377,7 +380,7 @@ def stop_log_uploader(
|
|
|
377
380
|
log_uploader.join()
|
|
378
381
|
|
|
379
382
|
|
|
380
|
-
def
|
|
383
|
+
def _remove_emojis(text: str) -> str:
|
|
381
384
|
"""Remove emojis from the provided text."""
|
|
382
385
|
emoji_pattern = re.compile(
|
|
383
386
|
"["
|
|
@@ -391,3 +394,15 @@ def remove_emojis(text: str) -> str:
|
|
|
391
394
|
flags=re.UNICODE,
|
|
392
395
|
)
|
|
393
396
|
return emoji_pattern.sub(r"", text)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def print_json_error(msg: str, e: Union[typer.Exit, Exception]) -> None:
|
|
400
|
+
"""Print error message as JSON."""
|
|
401
|
+
Console().print_json(
|
|
402
|
+
_json.dumps(
|
|
403
|
+
{
|
|
404
|
+
"success": False,
|
|
405
|
+
"error-message": _remove_emojis(str(msg) + "\n" + str(e)),
|
|
406
|
+
}
|
|
407
|
+
)
|
|
408
|
+
)
|
flwr/common/retry_invoker.py
CHANGED
|
@@ -30,6 +30,7 @@ from flwr.common.logger import log
|
|
|
30
30
|
from flwr.common.typing import RunNotRunningException
|
|
31
31
|
from flwr.proto.clientappio_pb2_grpc import ClientAppIoStub
|
|
32
32
|
from flwr.proto.serverappio_pb2_grpc import ServerAppIoStub
|
|
33
|
+
from flwr.proto.simulationio_pb2_grpc import SimulationIoStub
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
def exponential(
|
|
@@ -365,7 +366,8 @@ def _make_simple_grpc_retry_invoker() -> RetryInvoker:
|
|
|
365
366
|
|
|
366
367
|
|
|
367
368
|
def _wrap_stub(
|
|
368
|
-
stub: Union[ServerAppIoStub, ClientAppIoStub],
|
|
369
|
+
stub: Union[ServerAppIoStub, ClientAppIoStub, SimulationIoStub],
|
|
370
|
+
retry_invoker: RetryInvoker,
|
|
369
371
|
) -> None:
|
|
370
372
|
"""Wrap a gRPC stub with a retry invoker."""
|
|
371
373
|
|
flwr/server/app.py
CHANGED
|
@@ -93,9 +93,13 @@ BASE_DIR = get_flwr_dir() / "superlink" / "ffs"
|
|
|
93
93
|
|
|
94
94
|
|
|
95
95
|
try:
|
|
96
|
-
from flwr.ee import get_exec_auth_plugins
|
|
96
|
+
from flwr.ee import add_ee_args_superlink, get_exec_auth_plugins
|
|
97
97
|
except ImportError:
|
|
98
98
|
|
|
99
|
+
# pylint: disable-next=unused-argument
|
|
100
|
+
def add_ee_args_superlink(parser: argparse.ArgumentParser) -> None:
|
|
101
|
+
"""Add EE-specific arguments to the parser."""
|
|
102
|
+
|
|
99
103
|
def get_exec_auth_plugins() -> dict[str, type[ExecAuthPlugin]]:
|
|
100
104
|
"""Return all Exec API authentication plugins."""
|
|
101
105
|
raise NotImplementedError("No authentication plugins are currently supported.")
|
|
@@ -580,7 +584,7 @@ def _try_setup_node_authentication(
|
|
|
580
584
|
|
|
581
585
|
|
|
582
586
|
def _try_obtain_user_auth_config(args: argparse.Namespace) -> Optional[dict[str, Any]]:
|
|
583
|
-
if args
|
|
587
|
+
if getattr(args, "user_auth_config", None) is not None:
|
|
584
588
|
with open(args.user_auth_config, encoding="utf-8") as file:
|
|
585
589
|
config: dict[str, Any] = yaml.safe_load(file)
|
|
586
590
|
return config
|
|
@@ -703,6 +707,7 @@ def _parse_args_run_superlink() -> argparse.ArgumentParser:
|
|
|
703
707
|
)
|
|
704
708
|
|
|
705
709
|
_add_args_common(parser=parser)
|
|
710
|
+
add_ee_args_superlink(parser=parser)
|
|
706
711
|
_add_args_serverappio_api(parser=parser)
|
|
707
712
|
_add_args_fleet_api(parser=parser)
|
|
708
713
|
_add_args_exec_api(parser=parser)
|
|
@@ -792,12 +797,6 @@ def _add_args_common(parser: argparse.ArgumentParser) -> None:
|
|
|
792
797
|
type=str,
|
|
793
798
|
help="The SuperLink's public key (as a path str) to enable authentication.",
|
|
794
799
|
)
|
|
795
|
-
parser.add_argument(
|
|
796
|
-
"--user-auth-config",
|
|
797
|
-
help="The path to the user authentication configuration YAML file.",
|
|
798
|
-
type=str,
|
|
799
|
-
default=None,
|
|
800
|
-
)
|
|
801
800
|
|
|
802
801
|
|
|
803
802
|
def _add_args_serverappio_api(parser: argparse.ArgumentParser) -> None:
|
|
@@ -159,6 +159,9 @@ class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
|
|
|
159
159
|
for task_ins in request.task_ins_list:
|
|
160
160
|
validation_errors = validate_task_ins_or_res(task_ins)
|
|
161
161
|
_raise_if(bool(validation_errors), ", ".join(validation_errors))
|
|
162
|
+
_raise_if(
|
|
163
|
+
request.run_id != task_ins.run_id, "`task_ins` has mismatched `run_id`"
|
|
164
|
+
)
|
|
162
165
|
|
|
163
166
|
# Store each TaskIns
|
|
164
167
|
task_ids: list[Optional[UUID]] = []
|
|
@@ -193,6 +196,12 @@ class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
|
|
|
193
196
|
# Read from state
|
|
194
197
|
task_res_list: list[TaskRes] = state.get_task_res(task_ids=task_ids)
|
|
195
198
|
|
|
199
|
+
# Validate request
|
|
200
|
+
for task_res in task_res_list:
|
|
201
|
+
_raise_if(
|
|
202
|
+
request.run_id != task_res.run_id, "`task_res` has mismatched `run_id`"
|
|
203
|
+
)
|
|
204
|
+
|
|
196
205
|
# Delete the TaskIns/TaskRes pairs if TaskRes is found
|
|
197
206
|
task_ins_ids_to_delete = {
|
|
198
207
|
UUID(task_res.task.ancestry[0]) for task_res in task_res_list
|
|
@@ -123,9 +123,7 @@ def push_task_res(request: PushTaskResRequest, state: LinkState) -> PushTaskResR
|
|
|
123
123
|
return response
|
|
124
124
|
|
|
125
125
|
|
|
126
|
-
def get_run(
|
|
127
|
-
request: GetRunRequest, state: LinkState # pylint: disable=W0613
|
|
128
|
-
) -> GetRunResponse:
|
|
126
|
+
def get_run(request: GetRunRequest, state: LinkState) -> GetRunResponse:
|
|
129
127
|
"""Get run information."""
|
|
130
128
|
run = state.get_run(request.run_id)
|
|
131
129
|
|
|
@@ -761,8 +761,6 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
|
761
761
|
"federation_options, pending_at, starting_at, running_at, finished_at, "
|
|
762
762
|
"sub_status, details) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"
|
|
763
763
|
)
|
|
764
|
-
if fab_hash:
|
|
765
|
-
fab_id, fab_version = "", ""
|
|
766
764
|
override_config_json = json.dumps(override_config)
|
|
767
765
|
data = [
|
|
768
766
|
sint64_run_id,
|
|
@@ -54,6 +54,7 @@ from flwr.proto.simulationio_pb2 import ( # pylint: disable=E0611
|
|
|
54
54
|
)
|
|
55
55
|
from flwr.server.superlink.ffs.ffs_factory import FfsFactory
|
|
56
56
|
from flwr.server.superlink.linkstate import LinkStateFactory
|
|
57
|
+
from flwr.server.superlink.utils import abort_if
|
|
57
58
|
|
|
58
59
|
|
|
59
60
|
class SimulationIoServicer(simulationio_pb2_grpc.SimulationIoServicer):
|
|
@@ -110,6 +111,15 @@ class SimulationIoServicer(simulationio_pb2_grpc.SimulationIoServicer):
|
|
|
110
111
|
"""Push Simulation process outputs."""
|
|
111
112
|
log(DEBUG, "SimultionIoServicer.PushSimulationOutputs")
|
|
112
113
|
state = self.state_factory.state()
|
|
114
|
+
|
|
115
|
+
# Abort if the run is not running
|
|
116
|
+
abort_if(
|
|
117
|
+
request.run_id,
|
|
118
|
+
[Status.PENDING, Status.STARTING, Status.FINISHED],
|
|
119
|
+
state,
|
|
120
|
+
context,
|
|
121
|
+
)
|
|
122
|
+
|
|
113
123
|
state.set_serverapp_context(request.run_id, context_from_proto(request.context))
|
|
114
124
|
return PushSimulationOutputsResponse()
|
|
115
125
|
|
|
@@ -120,6 +130,9 @@ class SimulationIoServicer(simulationio_pb2_grpc.SimulationIoServicer):
|
|
|
120
130
|
log(DEBUG, "SimultionIoServicer.UpdateRunStatus")
|
|
121
131
|
state = self.state_factory.state()
|
|
122
132
|
|
|
133
|
+
# Abort if the run is finished
|
|
134
|
+
abort_if(request.run_id, [Status.FINISHED], state, context)
|
|
135
|
+
|
|
123
136
|
# Update the run status
|
|
124
137
|
state.update_run_status(
|
|
125
138
|
run_id=request.run_id, new_status=run_status_from_proto(request.run_status)
|
flwr/simulation/app.py
CHANGED
|
@@ -48,6 +48,7 @@ from flwr.common.logger import (
|
|
|
48
48
|
from flwr.common.serde import (
|
|
49
49
|
configs_record_from_proto,
|
|
50
50
|
context_from_proto,
|
|
51
|
+
context_to_proto,
|
|
51
52
|
fab_from_proto,
|
|
52
53
|
run_from_proto,
|
|
53
54
|
run_status_to_proto,
|
|
@@ -202,7 +203,7 @@ def run_simulation_process( # pylint: disable=R0914, disable=W0212, disable=R09
|
|
|
202
203
|
enable_tf_gpu_growth: bool = fed_opt.get("enable_tf_gpu_growth", False)
|
|
203
204
|
|
|
204
205
|
# Launch the simulation
|
|
205
|
-
_run_simulation(
|
|
206
|
+
updated_context = _run_simulation(
|
|
206
207
|
server_app_attr=server_app_attr,
|
|
207
208
|
client_app_attr=client_app_attr,
|
|
208
209
|
num_supernodes=num_supernodes,
|
|
@@ -217,7 +218,7 @@ def run_simulation_process( # pylint: disable=R0914, disable=W0212, disable=R09
|
|
|
217
218
|
)
|
|
218
219
|
|
|
219
220
|
# Send resulting context
|
|
220
|
-
context_proto =
|
|
221
|
+
context_proto = context_to_proto(updated_context)
|
|
221
222
|
out_req = PushSimulationOutputsRequest(
|
|
222
223
|
run_id=run.run_id, context=context_proto
|
|
223
224
|
)
|
|
@@ -24,7 +24,7 @@ import threading
|
|
|
24
24
|
import traceback
|
|
25
25
|
from logging import DEBUG, ERROR, INFO, WARNING
|
|
26
26
|
from pathlib import Path
|
|
27
|
-
from
|
|
27
|
+
from queue import Empty, Queue
|
|
28
28
|
from typing import Any, Optional
|
|
29
29
|
|
|
30
30
|
from flwr.cli.config_utils import load_and_validate
|
|
@@ -127,7 +127,7 @@ def run_simulation_from_cli() -> None:
|
|
|
127
127
|
run = Run.create_empty(run_id)
|
|
128
128
|
run.override_config = override_config
|
|
129
129
|
|
|
130
|
-
_run_simulation(
|
|
130
|
+
_ = _run_simulation(
|
|
131
131
|
server_app_attr=server_app_attr,
|
|
132
132
|
client_app_attr=client_app_attr,
|
|
133
133
|
num_supernodes=args.num_supernodes,
|
|
@@ -136,7 +136,6 @@ def run_simulation_from_cli() -> None:
|
|
|
136
136
|
app_dir=args.app,
|
|
137
137
|
run=run,
|
|
138
138
|
enable_tf_gpu_growth=args.enable_tf_gpu_growth,
|
|
139
|
-
delay_start=args.delay_start,
|
|
140
139
|
verbose_logging=args.verbose,
|
|
141
140
|
server_app_run_config=fused_config,
|
|
142
141
|
is_app=True,
|
|
@@ -208,7 +207,7 @@ def run_simulation(
|
|
|
208
207
|
"\n\tflwr.simulation.run_simulationt(...)",
|
|
209
208
|
)
|
|
210
209
|
|
|
211
|
-
_run_simulation(
|
|
210
|
+
_ = _run_simulation(
|
|
212
211
|
num_supernodes=num_supernodes,
|
|
213
212
|
client_app=client_app,
|
|
214
213
|
server_app=server_app,
|
|
@@ -231,6 +230,7 @@ def run_serverapp_th(
|
|
|
231
230
|
has_exception: threading.Event,
|
|
232
231
|
enable_tf_gpu_growth: bool,
|
|
233
232
|
run_id: int,
|
|
233
|
+
ctx_queue: "Queue[Context]",
|
|
234
234
|
) -> threading.Thread:
|
|
235
235
|
"""Run SeverApp in a thread."""
|
|
236
236
|
|
|
@@ -243,6 +243,7 @@ def run_serverapp_th(
|
|
|
243
243
|
_server_app_run_config: UserConfig,
|
|
244
244
|
_server_app_attr: Optional[str],
|
|
245
245
|
_server_app: Optional[ServerApp],
|
|
246
|
+
_ctx_queue: "Queue[Context]",
|
|
246
247
|
) -> None:
|
|
247
248
|
"""Run SeverApp, after check if GPU memory growth has to be set.
|
|
248
249
|
|
|
@@ -263,13 +264,14 @@ def run_serverapp_th(
|
|
|
263
264
|
)
|
|
264
265
|
|
|
265
266
|
# Run ServerApp
|
|
266
|
-
_run(
|
|
267
|
+
updated_context = _run(
|
|
267
268
|
driver=_driver,
|
|
268
269
|
context=context,
|
|
269
270
|
server_app_dir=_server_app_dir,
|
|
270
271
|
server_app_attr=_server_app_attr,
|
|
271
272
|
loaded_server_app=_server_app,
|
|
272
273
|
)
|
|
274
|
+
_ctx_queue.put(updated_context)
|
|
273
275
|
except Exception as ex: # pylint: disable=broad-exception-caught
|
|
274
276
|
log(ERROR, "ServerApp thread raised an exception: %s", ex)
|
|
275
277
|
log(ERROR, traceback.format_exc())
|
|
@@ -293,6 +295,7 @@ def run_serverapp_th(
|
|
|
293
295
|
server_app_run_config,
|
|
294
296
|
server_app_attr,
|
|
295
297
|
server_app,
|
|
298
|
+
ctx_queue,
|
|
296
299
|
),
|
|
297
300
|
)
|
|
298
301
|
serverapp_th.start()
|
|
@@ -309,14 +312,13 @@ def _main_loop(
|
|
|
309
312
|
enable_tf_gpu_growth: bool,
|
|
310
313
|
run: Run,
|
|
311
314
|
exit_event: EventType,
|
|
312
|
-
delay_start: int,
|
|
313
315
|
flwr_dir: Optional[str] = None,
|
|
314
316
|
client_app: Optional[ClientApp] = None,
|
|
315
317
|
client_app_attr: Optional[str] = None,
|
|
316
318
|
server_app: Optional[ServerApp] = None,
|
|
317
319
|
server_app_attr: Optional[str] = None,
|
|
318
320
|
server_app_run_config: Optional[UserConfig] = None,
|
|
319
|
-
) ->
|
|
321
|
+
) -> Context:
|
|
320
322
|
"""Start ServerApp on a separate thread, then launch Simulation Engine."""
|
|
321
323
|
# Initialize StateFactory
|
|
322
324
|
state_factory = LinkStateFactory(":flwr-in-memory-state:")
|
|
@@ -326,6 +328,13 @@ def _main_loop(
|
|
|
326
328
|
server_app_thread_has_exception = threading.Event()
|
|
327
329
|
serverapp_th = None
|
|
328
330
|
success = True
|
|
331
|
+
updated_context = Context(
|
|
332
|
+
run_id=run.run_id,
|
|
333
|
+
node_id=0,
|
|
334
|
+
node_config=UserConfig(),
|
|
335
|
+
state=RecordSet(),
|
|
336
|
+
run_config=UserConfig(),
|
|
337
|
+
)
|
|
329
338
|
try:
|
|
330
339
|
# Register run
|
|
331
340
|
log(DEBUG, "Pre-registering run with id %s", run.run_id)
|
|
@@ -340,6 +349,7 @@ def _main_loop(
|
|
|
340
349
|
# Initialize Driver
|
|
341
350
|
driver = InMemoryDriver(state_factory=state_factory)
|
|
342
351
|
driver.set_run(run_id=run.run_id)
|
|
352
|
+
output_context_queue: "Queue[Context]" = Queue()
|
|
343
353
|
|
|
344
354
|
# Get and run ServerApp thread
|
|
345
355
|
serverapp_th = run_serverapp_th(
|
|
@@ -352,11 +362,9 @@ def _main_loop(
|
|
|
352
362
|
has_exception=server_app_thread_has_exception,
|
|
353
363
|
enable_tf_gpu_growth=enable_tf_gpu_growth,
|
|
354
364
|
run_id=run.run_id,
|
|
365
|
+
ctx_queue=output_context_queue,
|
|
355
366
|
)
|
|
356
367
|
|
|
357
|
-
# Buffer time so the `ServerApp` in separate thread is ready
|
|
358
|
-
log(DEBUG, "Buffer time delay: %ds", delay_start)
|
|
359
|
-
sleep(delay_start)
|
|
360
368
|
# Start Simulation Engine
|
|
361
369
|
vce.start_vce(
|
|
362
370
|
num_supernodes=num_supernodes,
|
|
@@ -372,6 +380,11 @@ def _main_loop(
|
|
|
372
380
|
flwr_dir=flwr_dir,
|
|
373
381
|
)
|
|
374
382
|
|
|
383
|
+
updated_context = output_context_queue.get(timeout=3)
|
|
384
|
+
|
|
385
|
+
except Empty:
|
|
386
|
+
log(DEBUG, "Queue timeout. No context received.")
|
|
387
|
+
|
|
375
388
|
except Exception as ex:
|
|
376
389
|
log(ERROR, "An exception occurred !! %s", ex)
|
|
377
390
|
log(ERROR, traceback.format_exc())
|
|
@@ -388,6 +401,7 @@ def _main_loop(
|
|
|
388
401
|
raise RuntimeError("Exception in ServerApp thread")
|
|
389
402
|
|
|
390
403
|
log(DEBUG, "Stopping Simulation Engine now.")
|
|
404
|
+
return updated_context
|
|
391
405
|
|
|
392
406
|
|
|
393
407
|
# pylint: disable=too-many-arguments,too-many-locals,too-many-positional-arguments
|
|
@@ -405,10 +419,9 @@ def _run_simulation(
|
|
|
405
419
|
flwr_dir: Optional[str] = None,
|
|
406
420
|
run: Optional[Run] = None,
|
|
407
421
|
enable_tf_gpu_growth: bool = False,
|
|
408
|
-
delay_start: int = 5,
|
|
409
422
|
verbose_logging: bool = False,
|
|
410
423
|
is_app: bool = False,
|
|
411
|
-
) ->
|
|
424
|
+
) -> Context:
|
|
412
425
|
"""Launch the Simulation Engine."""
|
|
413
426
|
if backend_config is None:
|
|
414
427
|
backend_config = {}
|
|
@@ -460,7 +473,6 @@ def _run_simulation(
|
|
|
460
473
|
enable_tf_gpu_growth,
|
|
461
474
|
run,
|
|
462
475
|
exit_event,
|
|
463
|
-
delay_start,
|
|
464
476
|
flwr_dir,
|
|
465
477
|
client_app,
|
|
466
478
|
client_app_attr,
|
|
@@ -488,7 +500,8 @@ def _run_simulation(
|
|
|
488
500
|
# Set logger propagation to False to prevent duplicated log output in Colab.
|
|
489
501
|
logger = set_logger_propagation(logger, False)
|
|
490
502
|
|
|
491
|
-
_main_loop(*args)
|
|
503
|
+
updated_context = _main_loop(*args)
|
|
504
|
+
return updated_context
|
|
492
505
|
|
|
493
506
|
|
|
494
507
|
def _parse_args_run_simulation() -> argparse.ArgumentParser:
|
|
@@ -538,13 +551,6 @@ def _parse_args_run_simulation() -> argparse.ArgumentParser:
|
|
|
538
551
|
"Read more about how `tf.config.experimental.set_memory_growth()` works in "
|
|
539
552
|
"the TensorFlow documentation: https://www.tensorflow.org/api/stable.",
|
|
540
553
|
)
|
|
541
|
-
parser.add_argument(
|
|
542
|
-
"--delay-start",
|
|
543
|
-
type=int,
|
|
544
|
-
default=3,
|
|
545
|
-
help="Buffer time (in seconds) to delay the start the simulation engine after "
|
|
546
|
-
"the `ServerApp`, which runs in a separate thread, has been launched.",
|
|
547
|
-
)
|
|
548
554
|
parser.add_argument(
|
|
549
555
|
"--verbose",
|
|
550
556
|
action="store_true",
|
|
@@ -23,6 +23,7 @@ import grpc
|
|
|
23
23
|
from flwr.common.constant import SIMULATIONIO_API_DEFAULT_CLIENT_ADDRESS
|
|
24
24
|
from flwr.common.grpc import create_channel
|
|
25
25
|
from flwr.common.logger import log
|
|
26
|
+
from flwr.common.retry_invoker import _make_simple_grpc_retry_invoker, _wrap_stub
|
|
26
27
|
from flwr.proto.simulationio_pb2_grpc import SimulationIoStub # pylint: disable=E0611
|
|
27
28
|
|
|
28
29
|
|
|
@@ -48,6 +49,7 @@ class SimulationIoConnection:
|
|
|
48
49
|
self._cert = root_certificates
|
|
49
50
|
self._grpc_stub: Optional[SimulationIoStub] = None
|
|
50
51
|
self._channel: Optional[grpc.Channel] = None
|
|
52
|
+
self._retry_invoker = _make_simple_grpc_retry_invoker()
|
|
51
53
|
|
|
52
54
|
@property
|
|
53
55
|
def _is_connected(self) -> bool:
|
|
@@ -72,6 +74,7 @@ class SimulationIoConnection:
|
|
|
72
74
|
root_certificates=self._cert,
|
|
73
75
|
)
|
|
74
76
|
self._grpc_stub = SimulationIoStub(self._channel)
|
|
77
|
+
_wrap_stub(self._grpc_stub, self._retry_invoker)
|
|
75
78
|
log(DEBUG, "[SimulationIO] Connected to %s", self._addr)
|
|
76
79
|
|
|
77
80
|
def _disconnect(self) -> None:
|
{flwr_nightly-1.14.0.dev20241215.dist-info → flwr_nightly-1.14.0.dev20241217.dist-info}/RECORD
RENAMED
|
@@ -6,10 +6,10 @@ flwr/cli/cli_user_auth_interceptor.py,sha256=rEjgAZmzHO0GjwdyZib6bkTI2X59ErJAZlu
|
|
|
6
6
|
flwr/cli/config_utils.py,sha256=I4_EMv2f68mfrL_QuOYoAG--yDfKisE7tGiIg09G2YQ,12079
|
|
7
7
|
flwr/cli/example.py,sha256=uk5CoD0ZITgpY_ffsTbEKf8XOOCSUzByjHPcMSPqV18,2216
|
|
8
8
|
flwr/cli/install.py,sha256=0AD0qJD79SKgBnWOQlphcubfr4zHk8jTpFgwZbJBI_g,8180
|
|
9
|
-
flwr/cli/log.py,sha256=
|
|
9
|
+
flwr/cli/log.py,sha256=O7MBpsJp114PIZb-7Cru-KM6fqyneFQkqoQbQsqQmZU,6121
|
|
10
10
|
flwr/cli/login/__init__.py,sha256=6_9zOzbPOAH72K2wX3-9dXTAbS7Mjpa5sEn2lA6eHHI,800
|
|
11
|
-
flwr/cli/login/login.py,sha256=
|
|
12
|
-
flwr/cli/ls.py,sha256=
|
|
11
|
+
flwr/cli/login/login.py,sha256=bZZ3hVeGpF5805R0Eg_SBZUGwrLAWmyaoLhLw6vQFcg,2764
|
|
12
|
+
flwr/cli/ls.py,sha256=K_3Bt2RfETw4V7J4qgo8_Wx-Y_bWZqttuO879Ppxo5Y,11056
|
|
13
13
|
flwr/cli/new/__init__.py,sha256=pOQtPT9W4kCIttcKne5m-FtJbvTqdjTVJxzQ9AUYK8I,790
|
|
14
14
|
flwr/cli/new/new.py,sha256=scyyKt8mzkc3El1bypgkHjKwVQEc2-q4I50PxriPFdI,9922
|
|
15
15
|
flwr/cli/new/templates/__init__.py,sha256=4luU8RL-CK8JJCstQ_ON809W9bNTkY1l9zSaPKBkgwY,725
|
|
@@ -65,15 +65,15 @@ flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl,sha256=UtH3Vslg2S8fIKIHC-d
|
|
|
65
65
|
flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl,sha256=01HArBqRrbZT3O7pXOM9MqduXMNm525wv7Sj6dvYMJE,686
|
|
66
66
|
flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl,sha256=KVCIOEYNWnq6j7XOboXqZshc9aQ2PyRDUu7bZtmfJ24,710
|
|
67
67
|
flwr/cli/run/__init__.py,sha256=cCsKVB0SFzh2b3QmGba6BHckB85xlhjh3mh4pBpACtY,790
|
|
68
|
-
flwr/cli/run/run.py,sha256=
|
|
69
|
-
flwr/cli/stop.py,sha256=
|
|
70
|
-
flwr/cli/utils.py,sha256=
|
|
68
|
+
flwr/cli/run/run.py,sha256=BvpjYyUvDhVMvO5cG711ihtdeSbls9p8zVAuFGETLA8,7893
|
|
69
|
+
flwr/cli/stop.py,sha256=1T9RNRCH8dxjmBT38hFtKAWY9Gb7RMCMCML7kex9WzE,4613
|
|
70
|
+
flwr/cli/utils.py,sha256=kko38Sci_yy5V5f8ZXwKyAzG-7BRlkKi2l2vlFOx5ug,8626
|
|
71
71
|
flwr/client/__init__.py,sha256=DGDoO0AEAfz-0CUFmLdyUUweAS64-07AOnmDfWUefK4,1192
|
|
72
|
-
flwr/client/app.py,sha256=
|
|
73
|
-
flwr/client/client.py,sha256=
|
|
72
|
+
flwr/client/app.py,sha256=XJWu-kPswM52oLYXaOLKr0gj87KPNRI7M0Na9oBsDK4,34784
|
|
73
|
+
flwr/client/client.py,sha256=8o58nd9o6ZFcMIaVYPGcV4MSjBG4H0oFgWiv8ZEO3oA,7895
|
|
74
74
|
flwr/client/client_app.py,sha256=cTig-N00YzTucbo9zNi6I21J8PlbflU_8J_f5CI-Wpw,10390
|
|
75
75
|
flwr/client/clientapp/__init__.py,sha256=kZqChGnTChQ1WGSUkIlW2S5bc0d0mzDubCAmZUGRpEY,800
|
|
76
|
-
flwr/client/clientapp/app.py,sha256=
|
|
76
|
+
flwr/client/clientapp/app.py,sha256=n3IbbQ__QBjd4n7hhP2oydYg66IvrnSXvwi3sZvnWeU,8949
|
|
77
77
|
flwr/client/clientapp/clientappio_servicer.py,sha256=5L6bjw_j3Mnx9kRFwYwxDNABKurBO5q1jZOWE_X11wQ,8522
|
|
78
78
|
flwr/client/clientapp/utils.py,sha256=TTihPRO_AUhA3ZCszPsLyLZ30D_tnhTfe1ndMNVOBPg,4344
|
|
79
79
|
flwr/client/dpfedavg_numpy_client.py,sha256=4KsEvzavDKyVDU1V0kMqffTwu1lNdUCYQN-i0DTYVN8,7404
|
|
@@ -83,11 +83,11 @@ flwr/client/grpc_client/__init__.py,sha256=LsnbqXiJhgQcB0XzAlUQgPx011Uf7Y7yabIC1
|
|
|
83
83
|
flwr/client/grpc_client/connection.py,sha256=gMwB87mlmRBbvPOvUA1m3C-Ci6bjMEmTRI4bJpgbyic,9416
|
|
84
84
|
flwr/client/grpc_rere_client/__init__.py,sha256=MK-oSoV3kwUEQnIwl0GN4OpiHR7eLOrMA8ikunET130,752
|
|
85
85
|
flwr/client/grpc_rere_client/client_interceptor.py,sha256=q08lIEeJLvvonNOiejNXvmySbPObteGnbDHhEKDmWzE,5380
|
|
86
|
-
flwr/client/grpc_rere_client/connection.py,sha256=
|
|
86
|
+
flwr/client/grpc_rere_client/connection.py,sha256=NqKSoYIJblB4lElZ7EKIgDjLb6KYEcI-7CBrTbyiKfg,11475
|
|
87
87
|
flwr/client/grpc_rere_client/grpc_adapter.py,sha256=sQo0I9T65t97LFGoW_PrmgaTbd18GFgi2DoAI5wQJ4k,5589
|
|
88
88
|
flwr/client/heartbeat.py,sha256=cx37mJBH8LyoIN4Lks85wtqT1mnU5GulQnr4pGCvAq0,2404
|
|
89
89
|
flwr/client/message_handler/__init__.py,sha256=QxxQuBNpFPTHx3KiUNvQSlqMKlEnbRR1kFfc1KVje08,719
|
|
90
|
-
flwr/client/message_handler/message_handler.py,sha256=
|
|
90
|
+
flwr/client/message_handler/message_handler.py,sha256=s7FEfYJp5QB259Pj1L94_9AC24Kh5JyKC2U-E6eNkkY,6492
|
|
91
91
|
flwr/client/message_handler/task_handler.py,sha256=ZDJBKmrn2grRMNl1rU1iGs7FiMHL5VmZiSp_6h9GHVU,1824
|
|
92
92
|
flwr/client/mod/__init__.py,sha256=37XeXZLFq_tzFVKVtC9JaigM2bSAU7BrGQvMPCE3Q28,1159
|
|
93
93
|
flwr/client/mod/centraldp_mods.py,sha256=UGwNuqpmOWfLdfJITFgdi1TG-nLjuSb-cbEyoyfDgxQ,5415
|
|
@@ -101,7 +101,7 @@ flwr/client/nodestate/__init__.py,sha256=6FTlzydo1j0n55Tb-Qo0XmuqTUyRxg3x7jHgo3g
|
|
|
101
101
|
flwr/client/nodestate/in_memory_nodestate.py,sha256=MKI3jVPARPWJmNGw61k1-9LIXROkTx2PrhWjDM8cpHk,1291
|
|
102
102
|
flwr/client/nodestate/nodestate.py,sha256=CmHZdR6kVO8tkffg42W0Yb9JdRmrUonZ9deXfUNK6Hg,1024
|
|
103
103
|
flwr/client/nodestate/nodestate_factory.py,sha256=apUbcJG0a_FUVsc0TkNN3q9yovc9u_J34u9iuLFKTLQ,1430
|
|
104
|
-
flwr/client/numpy_client.py,sha256=
|
|
104
|
+
flwr/client/numpy_client.py,sha256=chTkL9dOtK_wgUoYtzp5mfDOC1k8xPAd1qPIsB3hcjA,9581
|
|
105
105
|
flwr/client/rest_client/__init__.py,sha256=5KGlp7pjc1dhNRkKlaNtUfQmg8wrRFh9lS3P3uRS-7Q,735
|
|
106
106
|
flwr/client/rest_client/connection.py,sha256=NWBu7Cc8LUTlf7GjJl3rgdCAykrE5suul_xZUV21OgI,12659
|
|
107
107
|
flwr/client/run_info_store.py,sha256=ZN2Phi4DSLbSyzg8RmzJcVYh1g6eurHOmWRCT7GMtw4,4040
|
|
@@ -122,7 +122,7 @@ flwr/common/differential_privacy_constants.py,sha256=c7b7tqgvT7yMK0XN9ndiTBs4mQf
|
|
|
122
122
|
flwr/common/dp.py,sha256=vddkvyjV2FhRoN4VuU2LeAM1UBn7dQB8_W-Qdiveal8,1978
|
|
123
123
|
flwr/common/exit_handlers.py,sha256=MracJaBeoCOC7TaXK9zCJQxhrMSx9ZtczK237qvhBpU,2806
|
|
124
124
|
flwr/common/grpc.py,sha256=AIPMAHsvcTlduaYKCgnoBnst1A7RZEgGqh0Ulm7qfJ0,2621
|
|
125
|
-
flwr/common/logger.py,sha256=
|
|
125
|
+
flwr/common/logger.py,sha256=qwiOc9N_Dqh-NlxtENcMa-dCPqint20ZLuWEvnAEwHU,12323
|
|
126
126
|
flwr/common/message.py,sha256=Zv4ID2BLQsbff0F03DI_MeFoHbSqVZAdDD9NcKYv6Zo,13832
|
|
127
127
|
flwr/common/object_ref.py,sha256=fIXf8aP5mG6Nuni7dvcKK5Di3zRfRWGs4ljvqIXplds,10115
|
|
128
128
|
flwr/common/parameter.py,sha256=-bFAUayToYDF50FZGrBC1hQYJCQDtB2bbr3ZuVLMtdE,2095
|
|
@@ -135,7 +135,7 @@ flwr/common/record/parametersrecord.py,sha256=SasHn35JRHsj8G1UT76FgRjaP4ZJasejvg
|
|
|
135
135
|
flwr/common/record/recordset.py,sha256=sSofrBycZSqiHR4TzfI4_QoIIN-5B1LnMG0C9CiByAo,8312
|
|
136
136
|
flwr/common/record/typeddict.py,sha256=q5hL2xkXymuiCprHWb69mUmLpWQk_XXQq0hGQ69YPaw,3599
|
|
137
137
|
flwr/common/recordset_compat.py,sha256=ViSwA26h6Q55ZmV1LLjSJpcKiipV-p_JpCj4wxdE-Ow,14230
|
|
138
|
-
flwr/common/retry_invoker.py,sha256=
|
|
138
|
+
flwr/common/retry_invoker.py,sha256=UIDKsn0AitS3fOr43WTqZAdD-TaHkBeTj1QxD7SGba0,14481
|
|
139
139
|
flwr/common/secure_aggregation/__init__.py,sha256=erPnTWdOfMH0K0HQTmj5foDJ6t3iYcExy2aACy8iZNQ,731
|
|
140
140
|
flwr/common/secure_aggregation/crypto/__init__.py,sha256=nlHesCWy8xxE5s6qHWnauCtyClcMQ2K0CEXAHakY5n0,738
|
|
141
141
|
flwr/common/secure_aggregation/crypto/shamir.py,sha256=wCSfEfeaPgJ9Om580-YPUF2ljiyRhq33TRC4HtwxYl8,2779
|
|
@@ -211,7 +211,7 @@ flwr/proto/transport_pb2_grpc.py,sha256=vLN3EHtx2aEEMCO4f1Upu-l27BPzd3-5pV-u8wPc
|
|
|
211
211
|
flwr/proto/transport_pb2_grpc.pyi,sha256=AGXf8RiIiW2J5IKMlm_3qT3AzcDa4F3P5IqUjve_esA,766
|
|
212
212
|
flwr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
213
213
|
flwr/server/__init__.py,sha256=cEg1oecBu4cKB69iJCqWEylC8b5XW47bl7rQiJsdTvM,1528
|
|
214
|
-
flwr/server/app.py,sha256=
|
|
214
|
+
flwr/server/app.py,sha256=t2N5Q2CEOptaCBxmos397Re9UDPDvNvgnXxNy7xqj-g,30944
|
|
215
215
|
flwr/server/client_manager.py,sha256=7Ese0tgrH-i-ms363feYZJKwB8gWnXSmg_hYF2Bju4U,6227
|
|
216
216
|
flwr/server/client_proxy.py,sha256=4G-oTwhb45sfWLx2uZdcXD98IZwdTS6F88xe3akCdUg,2399
|
|
217
217
|
flwr/server/compat/__init__.py,sha256=VxnJtJyOjNFQXMNi9hIuzNlZM5n0Hj1p3aq_Pm2udw4,892
|
|
@@ -259,7 +259,7 @@ flwr/server/strategy/strategy.py,sha256=cXapkD5uDrt5C-RbmWDn9FLoap3Q41i7GKvbmfbC
|
|
|
259
259
|
flwr/server/superlink/__init__.py,sha256=8tHYCfodUlRD8PCP9fHgvu8cz5N31A2QoRVL0jDJ15E,707
|
|
260
260
|
flwr/server/superlink/driver/__init__.py,sha256=5soEK5QSvxNjmJQ-CGTWROc4alSAeU0e9Ad9RDhsd3E,717
|
|
261
261
|
flwr/server/superlink/driver/serverappio_grpc.py,sha256=62371xIRzp3k-eQTaSpb9c4TiSfueSuI7Iw5X3IafOY,2186
|
|
262
|
-
flwr/server/superlink/driver/serverappio_servicer.py,sha256=
|
|
262
|
+
flwr/server/superlink/driver/serverappio_servicer.py,sha256=mgyV0XTONO7Vqb7sGOLu6AkCXWpBSeJ2s7ksadK1vE4,12197
|
|
263
263
|
flwr/server/superlink/ffs/__init__.py,sha256=FAY-zShcfPmOxosok2QyT6hTNMNctG8cH9s_nIl8jkI,840
|
|
264
264
|
flwr/server/superlink/ffs/disk_ffs.py,sha256=n_Ah0sQwXGVQ9wj5965nLjdkQQbpoHCljjXKFnwftsU,3297
|
|
265
265
|
flwr/server/superlink/ffs/ffs.py,sha256=qLI1UfosJugu2BKOJWqHIhafTm-YiuKqGf3OGWPH0NM,2395
|
|
@@ -276,7 +276,7 @@ flwr/server/superlink/fleet/grpc_rere/__init__.py,sha256=j2hyC342am-_Hgp1g80Y3fG
|
|
|
276
276
|
flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py,sha256=KBVsGt57G2_OWB_74N29TYVzD36G0xJg2l5m0ArPoEU,5389
|
|
277
277
|
flwr/server/superlink/fleet/grpc_rere/server_interceptor.py,sha256=8PHzqtW_rKBvqI5XVwYN-CBEpEonnj85iN0daSWliyI,8299
|
|
278
278
|
flwr/server/superlink/fleet/message_handler/__init__.py,sha256=h8oLD7uo5lKICPy0rRdKRjTYe62u8PKkT_fA4xF5JPA,731
|
|
279
|
-
flwr/server/superlink/fleet/message_handler/message_handler.py,sha256=
|
|
279
|
+
flwr/server/superlink/fleet/message_handler/message_handler.py,sha256=hzL8t6uUqO1lu5UHLF_NerdJuce4S5cK9fIWkKDzJfA,5298
|
|
280
280
|
flwr/server/superlink/fleet/rest_rere/__init__.py,sha256=5jbYbAn75sGv-gBwOPDySE0kz96F6dTYLeMrGqNi4lM,735
|
|
281
281
|
flwr/server/superlink/fleet/rest_rere/rest_api.py,sha256=0b10l9zz381GXgCmTZGoz76Z_fdRaa8XcqMGwuLqJ38,6723
|
|
282
282
|
flwr/server/superlink/fleet/vce/__init__.py,sha256=TZJsKTpYO_djv2EXx9Ji62I8TA0JiZF8jvRyJRZkAes,784
|
|
@@ -288,11 +288,11 @@ flwr/server/superlink/linkstate/__init__.py,sha256=v-2JyJlCB3qyhMNwMjmcNVOq4rkoo
|
|
|
288
288
|
flwr/server/superlink/linkstate/in_memory_linkstate.py,sha256=haJiQ0TkinyVH4vOG-EUuEhhI78YESgjKYU6qVgXics,21638
|
|
289
289
|
flwr/server/superlink/linkstate/linkstate.py,sha256=sbI7JLAZNMtVH1ZRjRjWDrws4mL0fjvrywxAKgCw9Mw,12936
|
|
290
290
|
flwr/server/superlink/linkstate/linkstate_factory.py,sha256=ISSMjDlwuN7swxjOeYlTNpI_kuZ8PGkMcJnf1dbhUSE,2069
|
|
291
|
-
flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=
|
|
291
|
+
flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=q_XyGRxL6vTT-fe0L6dKnPEZq0ARIT4D_ytGajU9Zzk,42592
|
|
292
292
|
flwr/server/superlink/linkstate/utils.py,sha256=d5uqqIOCKfd54X8CFNfUr3AWqPLpgmzsC_RagRwFugM,13321
|
|
293
293
|
flwr/server/superlink/simulation/__init__.py,sha256=mg-oapC9dkzEfjXPQFior5lpWj4g9kwbLovptyYM_g0,718
|
|
294
294
|
flwr/server/superlink/simulation/simulationio_grpc.py,sha256=5wflYW_TS0mjmPG6OYuHMJwXD2_cYmUNhFkdOU0jMWQ,2237
|
|
295
|
-
flwr/server/superlink/simulation/simulationio_servicer.py,sha256=
|
|
295
|
+
flwr/server/superlink/simulation/simulationio_servicer.py,sha256=J_TmdqM-Bxgp-iPEI3tvCuBpykw1UX0FouMQalEYAF4,6907
|
|
296
296
|
flwr/server/superlink/utils.py,sha256=KVb3K_g2vYfu9TnftcN0ewmev133WZcjuEePMm8d7GE,2137
|
|
297
297
|
flwr/server/typing.py,sha256=5kaRLZuxTEse9A0g7aVna2VhYxU3wTq1f3d3mtw7kXs,1019
|
|
298
298
|
flwr/server/utils/__init__.py,sha256=pltsPHJoXmUIr3utjwwYxu7_ZAGy5u4MVHzv9iA5Un8,908
|
|
@@ -305,14 +305,14 @@ flwr/server/workflow/secure_aggregation/__init__.py,sha256=3XlgDOjD_hcukTGl6Bc1B
|
|
|
305
305
|
flwr/server/workflow/secure_aggregation/secagg_workflow.py,sha256=l2IdMdJjs1bgHs5vQgLSOVzar7v2oxUn46oCrnVE1rM,5839
|
|
306
306
|
flwr/server/workflow/secure_aggregation/secaggplus_workflow.py,sha256=rfn2etO1nb7u-1oRl-H9q3enJZz3shMINZaBB7rPsC4,29671
|
|
307
307
|
flwr/simulation/__init__.py,sha256=5UcDVJNjFoSwWqHbGM1hKfTTUUNdwAtuoNvNrfvdkUY,1556
|
|
308
|
-
flwr/simulation/app.py,sha256=
|
|
308
|
+
flwr/simulation/app.py,sha256=Q9vZFVUvy2_QNNUpyElCmAMfe4d90mSoX9rGpzgZjD4,9412
|
|
309
309
|
flwr/simulation/legacy_app.py,sha256=ySggtKEtXe8L77n8qyGXDA7UPv840MXh-QoalzoGiLU,15780
|
|
310
310
|
flwr/simulation/ray_transport/__init__.py,sha256=wzcEEwUUlulnXsg6raCA1nGpP3LlAQDtJ8zNkCXcVbA,734
|
|
311
311
|
flwr/simulation/ray_transport/ray_actor.py,sha256=k11yoAPQzFGQU-KnCCP0ZrfPPdUPXXrBe-1DKM5VdW4,18997
|
|
312
312
|
flwr/simulation/ray_transport/ray_client_proxy.py,sha256=2vjOKoom3B74C6XU-jC3N6DwYmsLdB-lmkHZ_Xrv96o,7367
|
|
313
313
|
flwr/simulation/ray_transport/utils.py,sha256=wtbQhKQ4jGoiQDLJNQP17m1DSfL22ERhDBGuoeUFaAQ,2393
|
|
314
|
-
flwr/simulation/run_simulation.py,sha256=
|
|
315
|
-
flwr/simulation/simulationio_connection.py,sha256=
|
|
314
|
+
flwr/simulation/run_simulation.py,sha256=MSD2USh40j8vRrUyJeb3ngtghB8evtFLBMi6nUfpljY,20169
|
|
315
|
+
flwr/simulation/simulationio_connection.py,sha256=8aAh6MKQkQPMSnWEqA5vua_QzZtoMxG-_-AB23RPhS4,3412
|
|
316
316
|
flwr/superexec/__init__.py,sha256=fcj366jh4RFby_vDwLroU4kepzqbnJgseZD_jUr_Mko,715
|
|
317
317
|
flwr/superexec/app.py,sha256=Z6kYHWd62YL0Q4YKyCAbt_BcefNfbKH6V-jCC-1NkZM,1842
|
|
318
318
|
flwr/superexec/deployment.py,sha256=wZ9G42gGS91knfplswh95MnQ83Fzu-rs6wcuNgDmmvY,6735
|
|
@@ -321,8 +321,8 @@ flwr/superexec/exec_servicer.py,sha256=8tFwj1fDBF6PzwLhByTlxM-KNZc83bG1UdE92-8DS
|
|
|
321
321
|
flwr/superexec/exec_user_auth_interceptor.py,sha256=K06OU-l4LnYhTDg071hGJuOaQWEJbZsYi5qxUmmtiG0,3704
|
|
322
322
|
flwr/superexec/executor.py,sha256=_B55WW2TD1fBINpabSSDRenVHXYmvlfhv-k8hJKU4lQ,3115
|
|
323
323
|
flwr/superexec/simulation.py,sha256=WQDon15oqpMopAZnwRZoTICYCfHqtkvFSqiTQ2hLD_g,4088
|
|
324
|
-
flwr_nightly-1.14.0.
|
|
325
|
-
flwr_nightly-1.14.0.
|
|
326
|
-
flwr_nightly-1.14.0.
|
|
327
|
-
flwr_nightly-1.14.0.
|
|
328
|
-
flwr_nightly-1.14.0.
|
|
324
|
+
flwr_nightly-1.14.0.dev20241217.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
|
325
|
+
flwr_nightly-1.14.0.dev20241217.dist-info/METADATA,sha256=U7ytaeqIXkDuNUF0Dt5_nCAgh6ILjoWnyYiX1gpo2gM,15799
|
|
326
|
+
flwr_nightly-1.14.0.dev20241217.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
327
|
+
flwr_nightly-1.14.0.dev20241217.dist-info/entry_points.txt,sha256=JlNxX3qhaV18_2yj5a3kJW1ESxm31cal9iS_N_pf1Rk,538
|
|
328
|
+
flwr_nightly-1.14.0.dev20241217.dist-info/RECORD,,
|
{flwr_nightly-1.14.0.dev20241215.dist-info → flwr_nightly-1.14.0.dev20241217.dist-info}/LICENSE
RENAMED
|
File without changes
|
{flwr_nightly-1.14.0.dev20241215.dist-info → flwr_nightly-1.14.0.dev20241217.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|