flwr 1.13.0__py3-none-any.whl → 1.14.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flwr/cli/app.py +5 -0
- flwr/cli/build.py +1 -37
- flwr/cli/cli_user_auth_interceptor.py +86 -0
- flwr/cli/config_utils.py +19 -2
- flwr/cli/example.py +1 -0
- flwr/cli/install.py +2 -19
- flwr/cli/log.py +18 -36
- flwr/cli/login/__init__.py +22 -0
- flwr/cli/login/login.py +81 -0
- flwr/cli/ls.py +205 -106
- flwr/cli/new/__init__.py +1 -0
- flwr/cli/new/new.py +25 -14
- flwr/cli/new/templates/app/.gitignore.tpl +3 -0
- flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +3 -3
- flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.jax.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +2 -3
- flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +1 -1
- flwr/cli/run/__init__.py +1 -0
- flwr/cli/run/run.py +89 -39
- flwr/cli/stop.py +130 -0
- flwr/cli/utils.py +172 -8
- flwr/client/app.py +14 -3
- flwr/client/client.py +1 -32
- flwr/client/clientapp/app.py +4 -8
- flwr/client/clientapp/utils.py +1 -0
- flwr/client/grpc_adapter_client/connection.py +1 -1
- flwr/client/grpc_client/connection.py +1 -1
- flwr/client/grpc_rere_client/connection.py +13 -7
- flwr/client/message_handler/message_handler.py +1 -2
- flwr/client/mod/comms_mods.py +1 -0
- flwr/client/mod/localdp_mod.py +1 -1
- flwr/client/nodestate/__init__.py +1 -0
- flwr/client/nodestate/nodestate.py +1 -0
- flwr/client/nodestate/nodestate_factory.py +1 -0
- flwr/client/numpy_client.py +0 -44
- flwr/client/rest_client/connection.py +3 -3
- flwr/client/supernode/app.py +2 -2
- flwr/common/address.py +1 -0
- flwr/common/args.py +1 -0
- flwr/common/auth_plugin/__init__.py +24 -0
- flwr/common/auth_plugin/auth_plugin.py +111 -0
- flwr/common/config.py +3 -1
- flwr/common/constant.py +17 -1
- flwr/common/logger.py +40 -0
- flwr/common/message.py +1 -0
- flwr/common/object_ref.py +57 -54
- flwr/common/pyproject.py +1 -0
- flwr/common/record/__init__.py +1 -0
- flwr/common/record/parametersrecord.py +1 -0
- flwr/common/retry_invoker.py +77 -0
- flwr/common/secure_aggregation/secaggplus_utils.py +2 -2
- flwr/common/telemetry.py +15 -4
- flwr/common/typing.py +12 -0
- flwr/common/version.py +1 -0
- flwr/proto/exec_pb2.py +38 -14
- flwr/proto/exec_pb2.pyi +107 -2
- flwr/proto/exec_pb2_grpc.py +102 -0
- flwr/proto/exec_pb2_grpc.pyi +39 -0
- flwr/proto/fab_pb2.py +4 -4
- flwr/proto/fab_pb2.pyi +4 -1
- flwr/proto/serverappio_pb2.py +18 -18
- flwr/proto/serverappio_pb2.pyi +8 -2
- flwr/proto/serverappio_pb2_grpc.py +34 -0
- flwr/proto/serverappio_pb2_grpc.pyi +13 -0
- flwr/proto/simulationio_pb2.py +2 -2
- flwr/proto/simulationio_pb2_grpc.py +34 -0
- flwr/proto/simulationio_pb2_grpc.pyi +13 -0
- flwr/server/app.py +62 -7
- flwr/server/compat/app_utils.py +7 -1
- flwr/server/driver/grpc_driver.py +11 -63
- flwr/server/driver/inmemory_driver.py +5 -1
- flwr/server/run_serverapp.py +8 -9
- flwr/server/serverapp/app.py +25 -10
- flwr/server/strategy/dpfedavg_fixed.py +1 -0
- flwr/server/superlink/driver/serverappio_grpc.py +1 -0
- flwr/server/superlink/driver/serverappio_servicer.py +82 -23
- flwr/server/superlink/ffs/disk_ffs.py +1 -0
- flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +1 -0
- flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +1 -0
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +32 -12
- flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +12 -11
- flwr/server/superlink/fleet/message_handler/message_handler.py +32 -5
- flwr/server/superlink/fleet/rest_rere/rest_api.py +4 -1
- flwr/server/superlink/fleet/vce/__init__.py +1 -0
- flwr/server/superlink/fleet/vce/backend/__init__.py +1 -0
- flwr/server/superlink/fleet/vce/backend/raybackend.py +1 -0
- flwr/server/superlink/linkstate/in_memory_linkstate.py +21 -30
- flwr/server/superlink/linkstate/linkstate.py +17 -2
- flwr/server/superlink/linkstate/sqlite_linkstate.py +30 -49
- flwr/server/superlink/simulation/simulationio_servicer.py +33 -0
- flwr/server/superlink/utils.py +65 -0
- flwr/simulation/app.py +59 -52
- flwr/simulation/ray_transport/ray_actor.py +1 -0
- flwr/simulation/ray_transport/utils.py +1 -0
- flwr/simulation/run_simulation.py +36 -22
- flwr/simulation/simulationio_connection.py +3 -0
- flwr/superexec/app.py +1 -0
- flwr/superexec/deployment.py +1 -0
- flwr/superexec/exec_grpc.py +19 -1
- flwr/superexec/exec_servicer.py +76 -2
- flwr/superexec/exec_user_auth_interceptor.py +101 -0
- flwr/superexec/executor.py +1 -0
- {flwr-1.13.0.dist-info → flwr-1.14.0.dist-info}/METADATA +8 -8
- {flwr-1.13.0.dist-info → flwr-1.14.0.dist-info}/RECORD +112 -112
- flwr/proto/common_pb2.py +0 -36
- flwr/proto/common_pb2.pyi +0 -121
- flwr/proto/common_pb2_grpc.py +0 -4
- flwr/proto/common_pb2_grpc.pyi +0 -4
- flwr/proto/control_pb2.py +0 -27
- flwr/proto/control_pb2.pyi +0 -7
- flwr/proto/control_pb2_grpc.py +0 -135
- flwr/proto/control_pb2_grpc.pyi +0 -53
- {flwr-1.13.0.dist-info → flwr-1.14.0.dist-info}/LICENSE +0 -0
- {flwr-1.13.0.dist-info → flwr-1.14.0.dist-info}/WHEEL +0 -0
- {flwr-1.13.0.dist-info → flwr-1.14.0.dist-info}/entry_points.txt +0 -0
flwr/cli/ls.py
CHANGED
|
@@ -15,27 +15,26 @@
|
|
|
15
15
|
"""Flower command line interface `ls` command."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
import io
|
|
19
|
+
import json
|
|
18
20
|
from datetime import datetime, timedelta
|
|
19
|
-
from logging import DEBUG
|
|
20
21
|
from pathlib import Path
|
|
21
|
-
from typing import Annotated,
|
|
22
|
+
from typing import Annotated, Optional
|
|
22
23
|
|
|
23
|
-
import grpc
|
|
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
28
|
|
|
29
29
|
from flwr.cli.config_utils import (
|
|
30
|
+
exit_if_no_address,
|
|
30
31
|
load_and_validate,
|
|
31
|
-
|
|
32
|
+
process_loaded_project_config,
|
|
32
33
|
validate_federation_in_project_config,
|
|
33
|
-
validate_project_config,
|
|
34
34
|
)
|
|
35
|
-
from flwr.common.constant import FAB_CONFIG_FILE, SubStatus
|
|
35
|
+
from flwr.common.constant import FAB_CONFIG_FILE, CliOutputFormat, SubStatus
|
|
36
36
|
from flwr.common.date import format_timedelta, isoformat8601_utc
|
|
37
|
-
from flwr.common.
|
|
38
|
-
from flwr.common.logger import log
|
|
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,8 +43,12 @@ from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
|
|
|
44
43
|
)
|
|
45
44
|
from flwr.proto.exec_pb2_grpc import ExecStub
|
|
46
45
|
|
|
46
|
+
from .utils import init_channel, try_obtain_cli_auth_plugin, unauthenticated_exc_handler
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
_RunListType = tuple[int, str, str, str, str, str, str, str, str]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def ls( # pylint: disable=too-many-locals, too-many-branches
|
|
49
52
|
app: Annotated[
|
|
50
53
|
Path,
|
|
51
54
|
typer.Argument(help="Path of the Flower project"),
|
|
@@ -68,94 +71,100 @@ def ls(
|
|
|
68
71
|
help="Specific run ID to display",
|
|
69
72
|
),
|
|
70
73
|
] = None,
|
|
74
|
+
output_format: Annotated[
|
|
75
|
+
str,
|
|
76
|
+
typer.Option(
|
|
77
|
+
"--format",
|
|
78
|
+
case_sensitive=False,
|
|
79
|
+
help="Format output using 'default' view or 'json'",
|
|
80
|
+
),
|
|
81
|
+
] = CliOutputFormat.DEFAULT,
|
|
71
82
|
) -> None:
|
|
72
|
-
"""List runs.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
bold=True,
|
|
89
|
-
)
|
|
90
|
-
raise typer.Exit(code=1)
|
|
91
|
-
|
|
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
|
+
"""
|
|
97
|
+
suppress_output = output_format == CliOutputFormat.JSON
|
|
98
|
+
captured_output = io.StringIO()
|
|
92
99
|
try:
|
|
93
|
-
if
|
|
94
|
-
|
|
95
|
-
|
|
100
|
+
if suppress_output:
|
|
101
|
+
redirect_output(captured_output)
|
|
102
|
+
# Load and validate federation config
|
|
103
|
+
typer.secho("Loading project configuration... ", fg=typer.colors.BLUE)
|
|
104
|
+
|
|
105
|
+
pyproject_path = app / FAB_CONFIG_FILE if app else None
|
|
106
|
+
config, errors, warnings = load_and_validate(path=pyproject_path)
|
|
107
|
+
config = process_loaded_project_config(config, errors, warnings)
|
|
108
|
+
federation, federation_config = validate_federation_in_project_config(
|
|
109
|
+
federation, config
|
|
110
|
+
)
|
|
111
|
+
exit_if_no_address(federation_config, "ls")
|
|
112
|
+
|
|
113
|
+
try:
|
|
114
|
+
if runs and run_id is not None:
|
|
115
|
+
raise ValueError(
|
|
116
|
+
"The options '--runs' and '--run-id' are mutually exclusive."
|
|
117
|
+
)
|
|
118
|
+
auth_plugin = try_obtain_cli_auth_plugin(app, federation)
|
|
119
|
+
channel = init_channel(app, federation_config, auth_plugin)
|
|
120
|
+
stub = ExecStub(channel)
|
|
121
|
+
|
|
122
|
+
# Display information about a specific run ID
|
|
123
|
+
if run_id is not None:
|
|
124
|
+
typer.echo(f"🔍 Displaying information for run ID {run_id}...")
|
|
125
|
+
restore_output()
|
|
126
|
+
_display_one_run(stub, run_id, output_format)
|
|
127
|
+
# By default, list all runs
|
|
128
|
+
else:
|
|
129
|
+
typer.echo("📄 Listing all runs...")
|
|
130
|
+
restore_output()
|
|
131
|
+
_list_runs(stub, output_format)
|
|
132
|
+
|
|
133
|
+
except ValueError as err:
|
|
134
|
+
if suppress_output:
|
|
135
|
+
redirect_output(captured_output)
|
|
136
|
+
typer.secho(
|
|
137
|
+
f"❌ {err}",
|
|
138
|
+
fg=typer.colors.RED,
|
|
139
|
+
bold=True,
|
|
96
140
|
)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
# By default, list all runs
|
|
141
|
+
raise typer.Exit(code=1) from err
|
|
142
|
+
finally:
|
|
143
|
+
channel.close()
|
|
144
|
+
except (typer.Exit, Exception) as err: # pylint: disable=broad-except
|
|
145
|
+
if suppress_output:
|
|
146
|
+
restore_output()
|
|
147
|
+
e_message = captured_output.getvalue()
|
|
148
|
+
print_json_error(e_message, err)
|
|
106
149
|
else:
|
|
107
|
-
typer.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
f"❌ {err}",
|
|
113
|
-
fg=typer.colors.RED,
|
|
114
|
-
bold=True,
|
|
115
|
-
)
|
|
116
|
-
raise typer.Exit(code=1) from err
|
|
150
|
+
typer.secho(
|
|
151
|
+
f"{err}",
|
|
152
|
+
fg=typer.colors.RED,
|
|
153
|
+
bold=True,
|
|
154
|
+
)
|
|
117
155
|
finally:
|
|
118
|
-
|
|
156
|
+
if suppress_output:
|
|
157
|
+
restore_output()
|
|
158
|
+
captured_output.close()
|
|
119
159
|
|
|
120
160
|
|
|
121
|
-
def
|
|
122
|
-
"""
|
|
123
|
-
log(DEBUG, channel_connectivity)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
def _init_channel(app: Path, federation_config: dict[str, Any]) -> grpc.Channel:
|
|
127
|
-
"""Initialize gRPC channel to the Exec API."""
|
|
128
|
-
insecure, root_certificates_bytes = validate_certificate_in_federation_config(
|
|
129
|
-
app, federation_config
|
|
130
|
-
)
|
|
131
|
-
channel = create_channel(
|
|
132
|
-
server_address=federation_config["address"],
|
|
133
|
-
insecure=insecure,
|
|
134
|
-
root_certificates=root_certificates_bytes,
|
|
135
|
-
max_message_length=GRPC_MAX_MESSAGE_LENGTH,
|
|
136
|
-
interceptors=None,
|
|
137
|
-
)
|
|
138
|
-
channel.subscribe(on_channel_state_change)
|
|
139
|
-
return channel
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def _format_run_table(run_dict: dict[int, Run], now_isoformat: str) -> Table:
|
|
143
|
-
"""Format run status as a rich Table."""
|
|
144
|
-
table = Table(header_style="bold cyan", show_lines=True)
|
|
161
|
+
def _format_runs(run_dict: dict[int, Run], now_isoformat: str) -> list[_RunListType]:
|
|
162
|
+
"""Format runs to a list."""
|
|
145
163
|
|
|
146
164
|
def _format_datetime(dt: Optional[datetime]) -> str:
|
|
147
165
|
return isoformat8601_utc(dt).replace("T", " ") if dt else "N/A"
|
|
148
166
|
|
|
149
|
-
|
|
150
|
-
table.add_column(
|
|
151
|
-
Text("Run ID", justify="center"), style="bright_white", overflow="fold"
|
|
152
|
-
)
|
|
153
|
-
table.add_column(Text("FAB", justify="center"), style="dim white")
|
|
154
|
-
table.add_column(Text("Status", justify="center"))
|
|
155
|
-
table.add_column(Text("Elapsed", justify="center"), style="blue")
|
|
156
|
-
table.add_column(Text("Created At", justify="center"), style="dim white")
|
|
157
|
-
table.add_column(Text("Running At", justify="center"), style="dim white")
|
|
158
|
-
table.add_column(Text("Finished At", justify="center"), style="dim white")
|
|
167
|
+
run_list: list[_RunListType] = []
|
|
159
168
|
|
|
160
169
|
# Add rows
|
|
161
170
|
for run in sorted(
|
|
@@ -167,15 +176,6 @@ def _format_run_table(run_dict: dict[int, Run], now_isoformat: str) -> Table:
|
|
|
167
176
|
else:
|
|
168
177
|
status_text = f"{run.status.status}:{run.status.sub_status}"
|
|
169
178
|
|
|
170
|
-
# Style the status based on its value
|
|
171
|
-
sub_status = run.status.sub_status
|
|
172
|
-
if sub_status == SubStatus.COMPLETED:
|
|
173
|
-
status_style = "green"
|
|
174
|
-
elif sub_status == SubStatus.FAILED:
|
|
175
|
-
status_style = "red"
|
|
176
|
-
else:
|
|
177
|
-
status_style = "yellow"
|
|
178
|
-
|
|
179
179
|
# Convert isoformat to datetime
|
|
180
180
|
pending_at = datetime.fromisoformat(run.pending_at) if run.pending_at else None
|
|
181
181
|
running_at = datetime.fromisoformat(run.running_at) if run.running_at else None
|
|
@@ -192,37 +192,136 @@ def _format_run_table(run_dict: dict[int, Run], now_isoformat: str) -> Table:
|
|
|
192
192
|
end_time = datetime.fromisoformat(now_isoformat)
|
|
193
193
|
elapsed_time = end_time - running_at
|
|
194
194
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
195
|
+
run_list.append(
|
|
196
|
+
(
|
|
197
|
+
run.run_id,
|
|
198
|
+
run.fab_id,
|
|
199
|
+
run.fab_version,
|
|
200
|
+
run.fab_hash,
|
|
201
|
+
status_text,
|
|
202
|
+
format_timedelta(elapsed_time),
|
|
203
|
+
_format_datetime(pending_at),
|
|
204
|
+
_format_datetime(running_at),
|
|
205
|
+
_format_datetime(finished_at),
|
|
206
|
+
)
|
|
207
|
+
)
|
|
208
|
+
return run_list
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _to_table(run_list: list[_RunListType]) -> Table:
|
|
212
|
+
"""Format the provided run list to a rich Table."""
|
|
213
|
+
table = Table(header_style="bold cyan", show_lines=True)
|
|
214
|
+
|
|
215
|
+
# Add columns
|
|
216
|
+
table.add_column(
|
|
217
|
+
Text("Run ID", justify="center"), style="bright_white", overflow="fold"
|
|
218
|
+
)
|
|
219
|
+
table.add_column(Text("FAB", justify="center"), style="dim white")
|
|
220
|
+
table.add_column(Text("Status", justify="center"))
|
|
221
|
+
table.add_column(Text("Elapsed", justify="center"), style="blue")
|
|
222
|
+
table.add_column(Text("Created At", justify="center"), style="dim white")
|
|
223
|
+
table.add_column(Text("Running At", justify="center"), style="dim white")
|
|
224
|
+
table.add_column(Text("Finished At", justify="center"), style="dim white")
|
|
225
|
+
|
|
226
|
+
for row in run_list:
|
|
227
|
+
(
|
|
228
|
+
run_id,
|
|
229
|
+
fab_id,
|
|
230
|
+
fab_version,
|
|
231
|
+
_,
|
|
232
|
+
status_text,
|
|
233
|
+
elapsed,
|
|
234
|
+
created_at,
|
|
235
|
+
running_at,
|
|
236
|
+
finished_at,
|
|
237
|
+
) = row
|
|
238
|
+
# Style the status based on its value
|
|
239
|
+
sub_status = status_text.rsplit(":", maxsplit=1)[-1]
|
|
240
|
+
if sub_status == SubStatus.COMPLETED:
|
|
241
|
+
status_style = "green"
|
|
242
|
+
elif sub_status == SubStatus.FAILED:
|
|
243
|
+
status_style = "red"
|
|
244
|
+
else:
|
|
245
|
+
status_style = "yellow"
|
|
246
|
+
|
|
247
|
+
formatted_row = (
|
|
248
|
+
f"[bold]{run_id}[/bold]",
|
|
249
|
+
f"{fab_id} (v{fab_version})",
|
|
198
250
|
f"[{status_style}]{status_text}[/{status_style}]",
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
251
|
+
elapsed,
|
|
252
|
+
created_at,
|
|
253
|
+
running_at,
|
|
254
|
+
finished_at,
|
|
203
255
|
)
|
|
256
|
+
table.add_row(*formatted_row)
|
|
257
|
+
|
|
204
258
|
return table
|
|
205
259
|
|
|
206
260
|
|
|
261
|
+
def _to_json(run_list: list[_RunListType]) -> str:
|
|
262
|
+
"""Format run status list to a JSON formatted string."""
|
|
263
|
+
runs_list = []
|
|
264
|
+
for row in run_list:
|
|
265
|
+
(
|
|
266
|
+
run_id,
|
|
267
|
+
fab_id,
|
|
268
|
+
fab_version,
|
|
269
|
+
fab_hash,
|
|
270
|
+
status_text,
|
|
271
|
+
elapsed,
|
|
272
|
+
created_at,
|
|
273
|
+
running_at,
|
|
274
|
+
finished_at,
|
|
275
|
+
) = row
|
|
276
|
+
runs_list.append(
|
|
277
|
+
{
|
|
278
|
+
"run-id": run_id,
|
|
279
|
+
"fab-id": fab_id,
|
|
280
|
+
"fab-name": fab_id.split("/")[-1],
|
|
281
|
+
"fab-version": fab_version,
|
|
282
|
+
"fab-hash": fab_hash[:8],
|
|
283
|
+
"status": status_text,
|
|
284
|
+
"elapsed": elapsed,
|
|
285
|
+
"created-at": created_at,
|
|
286
|
+
"running-at": running_at,
|
|
287
|
+
"finished-at": finished_at,
|
|
288
|
+
}
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
return json.dumps({"success": True, "runs": runs_list})
|
|
292
|
+
|
|
293
|
+
|
|
207
294
|
def _list_runs(
|
|
208
295
|
stub: ExecStub,
|
|
296
|
+
output_format: str = CliOutputFormat.DEFAULT,
|
|
209
297
|
) -> None:
|
|
210
298
|
"""List all runs."""
|
|
211
|
-
|
|
299
|
+
with unauthenticated_exc_handler():
|
|
300
|
+
res: ListRunsResponse = stub.ListRuns(ListRunsRequest())
|
|
212
301
|
run_dict = {run_id: run_from_proto(proto) for run_id, proto in res.run_dict.items()}
|
|
213
302
|
|
|
214
|
-
|
|
303
|
+
formatted_runs = _format_runs(run_dict, res.now)
|
|
304
|
+
if output_format == CliOutputFormat.JSON:
|
|
305
|
+
Console().print_json(_to_json(formatted_runs))
|
|
306
|
+
else:
|
|
307
|
+
Console().print(_to_table(formatted_runs))
|
|
215
308
|
|
|
216
309
|
|
|
217
310
|
def _display_one_run(
|
|
218
311
|
stub: ExecStub,
|
|
219
312
|
run_id: int,
|
|
313
|
+
output_format: str = CliOutputFormat.DEFAULT,
|
|
220
314
|
) -> None:
|
|
221
315
|
"""Display information about a specific run."""
|
|
222
|
-
|
|
316
|
+
with unauthenticated_exc_handler():
|
|
317
|
+
res: ListRunsResponse = stub.ListRuns(ListRunsRequest(run_id=run_id))
|
|
223
318
|
if not res.run_dict:
|
|
224
319
|
raise ValueError(f"Run ID {run_id} not found")
|
|
225
320
|
|
|
226
321
|
run_dict = {run_id: run_from_proto(proto) for run_id, proto in res.run_dict.items()}
|
|
227
322
|
|
|
228
|
-
|
|
323
|
+
formatted_runs = _format_runs(run_dict, res.now)
|
|
324
|
+
if output_format == CliOutputFormat.JSON:
|
|
325
|
+
Console().print_json(_to_json(formatted_runs))
|
|
326
|
+
else:
|
|
327
|
+
Console().print(_to_table(formatted_runs))
|
flwr/cli/new/__init__.py
CHANGED
flwr/cli/new/new.py
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
# ==============================================================================
|
|
15
15
|
"""Flower command line interface `new` command."""
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
import re
|
|
18
19
|
from enum import Enum
|
|
19
20
|
from pathlib import Path
|
|
@@ -81,7 +82,7 @@ def render_template(template: str, data: dict[str, str]) -> str:
|
|
|
81
82
|
def create_file(file_path: Path, content: str) -> None:
|
|
82
83
|
"""Create file including all nessecary directories and write content into file."""
|
|
83
84
|
file_path.parent.mkdir(exist_ok=True)
|
|
84
|
-
file_path.write_text(content)
|
|
85
|
+
file_path.write_text(content, encoding="utf-8")
|
|
85
86
|
|
|
86
87
|
|
|
87
88
|
def render_and_create(file_path: Path, template: str, context: dict[str, str]) -> None:
|
|
@@ -268,20 +269,30 @@ def new(
|
|
|
268
269
|
context=context,
|
|
269
270
|
)
|
|
270
271
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
bold=True,
|
|
277
|
-
)
|
|
272
|
+
prompt = typer.style(
|
|
273
|
+
"🎊 Flower App creation successful.\n\n"
|
|
274
|
+
"To run your Flower App, use the following command:\n\n",
|
|
275
|
+
fg=typer.colors.GREEN,
|
|
276
|
+
bold=True,
|
|
278
277
|
)
|
|
279
278
|
|
|
280
279
|
_add = " huggingface-cli login\n" if llm_challenge_str else ""
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
280
|
+
prompt += typer.style(
|
|
281
|
+
_add + f" flwr run {package_name}\n\n",
|
|
282
|
+
fg=typer.colors.BRIGHT_CYAN,
|
|
283
|
+
bold=True,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
prompt += typer.style(
|
|
287
|
+
"If you haven't installed all dependencies yet, follow these steps:\n\n",
|
|
288
|
+
fg=typer.colors.GREEN,
|
|
289
|
+
bold=True,
|
|
287
290
|
)
|
|
291
|
+
|
|
292
|
+
prompt += typer.style(
|
|
293
|
+
f" cd {package_name}\n" + " pip install -e .\n" + _add + " flwr run .\n",
|
|
294
|
+
fg=typer.colors.BRIGHT_CYAN,
|
|
295
|
+
bold=True,
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
print(prompt)
|
|
@@ -8,14 +8,14 @@ version = "1.0.0"
|
|
|
8
8
|
description = ""
|
|
9
9
|
license = "Apache-2.0"
|
|
10
10
|
dependencies = [
|
|
11
|
-
"flwr[simulation]>=1.
|
|
11
|
+
"flwr[simulation]>=1.13.1",
|
|
12
12
|
"flwr-datasets>=0.3.0",
|
|
13
13
|
"torch==2.3.1",
|
|
14
14
|
"trl==0.8.1",
|
|
15
|
-
"bitsandbytes==0.
|
|
15
|
+
"bitsandbytes==0.45.0",
|
|
16
16
|
"scipy==1.13.0",
|
|
17
17
|
"peft==0.6.2",
|
|
18
|
-
"transformers==4.
|
|
18
|
+
"transformers==4.47.0",
|
|
19
19
|
"sentencepiece==0.2.0",
|
|
20
20
|
"omegaconf==2.3.0",
|
|
21
21
|
"hf_transfer==0.1.8",
|
|
@@ -8,10 +8,9 @@ version = "1.0.0"
|
|
|
8
8
|
description = ""
|
|
9
9
|
license = "Apache-2.0"
|
|
10
10
|
dependencies = [
|
|
11
|
-
"flwr[simulation]>=1.
|
|
11
|
+
"flwr[simulation]>=1.13.1",
|
|
12
12
|
"flwr-datasets[vision]>=0.3.0",
|
|
13
|
-
"mlx==0.
|
|
14
|
-
"numpy==1.24.4",
|
|
13
|
+
"mlx==0.21.1",
|
|
15
14
|
]
|
|
16
15
|
|
|
17
16
|
[tool.hatch.build.targets.wheel]
|