flwr-nightly 1.15.0.dev20250122__py3-none-any.whl → 1.15.0.dev20250124__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/config_utils.py CHANGED
@@ -21,7 +21,13 @@ from typing import Any, Optional, Union
21
21
  import tomli
22
22
  import typer
23
23
 
24
- from flwr.common.config import get_fab_config, get_metadata_from_config, validate_config
24
+ from flwr.common.config import (
25
+ fuse_dicts,
26
+ get_fab_config,
27
+ get_metadata_from_config,
28
+ parse_config_args,
29
+ validate_config,
30
+ )
25
31
 
26
32
 
27
33
  def get_fab_metadata(fab_file: Union[Path, bytes]) -> tuple[str, str]:
@@ -127,7 +133,9 @@ def process_loaded_project_config(
127
133
 
128
134
 
129
135
  def validate_federation_in_project_config(
130
- federation: Optional[str], config: dict[str, Any]
136
+ federation: Optional[str],
137
+ config: dict[str, Any],
138
+ overrides: Optional[list[str]] = None,
131
139
  ) -> tuple[str, dict[str, Any]]:
132
140
  """Validate the federation name in the Flower project configuration."""
133
141
  federation = federation or config["tool"]["flwr"]["federations"].get("default")
@@ -157,6 +165,11 @@ def validate_federation_in_project_config(
157
165
  )
158
166
  raise typer.Exit(code=1)
159
167
 
168
+ # Override the federation configuration if provided
169
+ if overrides:
170
+ overrides_dict = parse_config_args(overrides, flatten=False)
171
+ federation_config = fuse_dicts(federation_config, overrides_dict)
172
+
160
173
  return federation, federation_config
161
174
 
162
175
 
@@ -169,7 +182,7 @@ def validate_certificate_in_federation_config(
169
182
  root_certificates_bytes = (app / root_certificates).read_bytes()
170
183
  if insecure := bool(insecure_str):
171
184
  typer.secho(
172
- "❌ `root_certificates` were provided but the `insecure` parameter "
185
+ "❌ `root-certificates` were provided but the `insecure` parameter "
173
186
  "is set to `True`.",
174
187
  fg=typer.colors.RED,
175
188
  bold=True,
flwr/cli/constant.py ADDED
@@ -0,0 +1,27 @@
1
+ # Copyright 2025 Flower Labs GmbH. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # ==============================================================================
15
+ """Constants for CLI commands."""
16
+
17
+
18
+ # The help message for `--federation-config` option
19
+ FEDERATION_CONFIG_HELP_MESSAGE = (
20
+ "Override federation configuration values in the format:\n\n"
21
+ "`--federation-config 'key1=value1 key2=value2' --federation-config "
22
+ "'key3=value3'`\n\nValues can be of any type supported in TOML, such as "
23
+ "bool, int, float, or string. Ensure that the keys (`key1`, `key2`, `key3` "
24
+ "in this example) exist in the federation configuration under the "
25
+ "`[tool.flwr.federations.<YOUR_FEDERATION>]` table of the `pyproject.toml` "
26
+ "for proper overriding."
27
+ )
flwr/cli/log.py CHANGED
@@ -29,6 +29,7 @@ from flwr.cli.config_utils import (
29
29
  process_loaded_project_config,
30
30
  validate_federation_in_project_config,
31
31
  )
32
+ from flwr.cli.constant import FEDERATION_CONFIG_HELP_MESSAGE
32
33
  from flwr.common.constant import CONN_RECONNECT_INTERVAL, CONN_REFRESH_PERIOD
33
34
  from flwr.common.logger import log as logger
34
35
  from flwr.proto.exec_pb2 import StreamLogsRequest # pylint: disable=E0611
@@ -57,6 +58,8 @@ def start_stream(
57
58
  logger(ERROR, "Invalid run_id `%s`, exiting", run_id)
58
59
  if e.code() == grpc.StatusCode.CANCELLED:
59
60
  pass
61
+ else:
62
+ raise e
60
63
  finally:
61
64
  channel.close()
62
65
 
@@ -123,6 +126,7 @@ def print_logs(run_id: int, channel: grpc.Channel, timeout: int) -> None:
123
126
  break
124
127
  if e.code() == grpc.StatusCode.CANCELLED:
125
128
  break
129
+ raise e
126
130
  except KeyboardInterrupt:
127
131
  logger(DEBUG, "Stream interrupted by user")
128
132
  finally:
@@ -143,6 +147,13 @@ def log(
143
147
  Optional[str],
144
148
  typer.Argument(help="Name of the federation to run the app on"),
145
149
  ] = None,
150
+ federation_config_overrides: Annotated[
151
+ Optional[list[str]],
152
+ typer.Option(
153
+ "--federation-config",
154
+ help=FEDERATION_CONFIG_HELP_MESSAGE,
155
+ ),
156
+ ] = None,
146
157
  stream: Annotated[
147
158
  bool,
148
159
  typer.Option(
@@ -158,11 +169,15 @@ def log(
158
169
  config, errors, warnings = load_and_validate(path=pyproject_path)
159
170
  config = process_loaded_project_config(config, errors, warnings)
160
171
  federation, federation_config = validate_federation_in_project_config(
161
- federation, config
172
+ federation, config, federation_config_overrides
162
173
  )
163
174
  exit_if_no_address(federation_config, "log")
164
175
 
165
- _log_with_exec_api(app, federation, federation_config, run_id, stream)
176
+ try:
177
+ _log_with_exec_api(app, federation, federation_config, run_id, stream)
178
+ except Exception as err: # pylint: disable=broad-except
179
+ typer.secho(str(err), fg=typer.colors.RED, bold=True)
180
+ raise typer.Exit(code=1) from None
166
181
 
167
182
 
168
183
  def _log_with_exec_api(
@@ -172,7 +187,7 @@ def _log_with_exec_api(
172
187
  run_id: int,
173
188
  stream: bool,
174
189
  ) -> None:
175
- auth_plugin = try_obtain_cli_auth_plugin(app, federation)
190
+ auth_plugin = try_obtain_cli_auth_plugin(app, federation, federation_config)
176
191
  channel = init_channel(app, federation_config, auth_plugin)
177
192
 
178
193
  if stream:
flwr/cli/login/login.py CHANGED
@@ -26,6 +26,7 @@ from flwr.cli.config_utils import (
26
26
  process_loaded_project_config,
27
27
  validate_federation_in_project_config,
28
28
  )
29
+ from flwr.cli.constant import FEDERATION_CONFIG_HELP_MESSAGE
29
30
  from flwr.common.typing import UserAuthLoginDetails
30
31
  from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
31
32
  GetLoginDetailsRequest,
@@ -45,6 +46,13 @@ def login( # pylint: disable=R0914
45
46
  Optional[str],
46
47
  typer.Argument(help="Name of the federation to login into."),
47
48
  ] = None,
49
+ federation_config_overrides: Annotated[
50
+ Optional[list[str]],
51
+ typer.Option(
52
+ "--federation-config",
53
+ help=FEDERATION_CONFIG_HELP_MESSAGE,
54
+ ),
55
+ ] = None,
48
56
  ) -> None:
49
57
  """Login to Flower SuperLink."""
50
58
  typer.secho("Loading project configuration... ", fg=typer.colors.BLUE)
@@ -54,9 +62,21 @@ def login( # pylint: disable=R0914
54
62
 
55
63
  config = process_loaded_project_config(config, errors, warnings)
56
64
  federation, federation_config = validate_federation_in_project_config(
57
- federation, config
65
+ federation, config, federation_config_overrides
58
66
  )
59
67
  exit_if_no_address(federation_config, "login")
68
+
69
+ # Check if `enable-user-auth` is set to `true`
70
+ if not federation_config.get("enable-user-auth", False):
71
+ typer.secho(
72
+ f"❌ User authentication is not enabled for the federation '{federation}'. "
73
+ "To enable it, set `enable-user-auth = true` in the federation "
74
+ "configuration.",
75
+ fg=typer.colors.RED,
76
+ bold=True,
77
+ )
78
+ raise typer.Exit(code=1)
79
+
60
80
  channel = init_channel(app, federation_config, None)
61
81
  stub = ExecStub(channel)
62
82
 
@@ -65,7 +85,9 @@ def login( # pylint: disable=R0914
65
85
 
66
86
  # Get the auth plugin
67
87
  auth_type = login_response.auth_type
68
- auth_plugin = try_obtain_cli_auth_plugin(app, federation, auth_type)
88
+ auth_plugin = try_obtain_cli_auth_plugin(
89
+ app, federation, federation_config, auth_type
90
+ )
69
91
  if auth_plugin is None:
70
92
  typer.secho(
71
93
  f'❌ Authentication type "{auth_type}" not found',
flwr/cli/ls.py CHANGED
@@ -32,6 +32,7 @@ from flwr.cli.config_utils import (
32
32
  process_loaded_project_config,
33
33
  validate_federation_in_project_config,
34
34
  )
35
+ from flwr.cli.constant import FEDERATION_CONFIG_HELP_MESSAGE
35
36
  from flwr.common.constant import FAB_CONFIG_FILE, CliOutputFormat, SubStatus
36
37
  from flwr.common.date import format_timedelta, isoformat8601_utc
37
38
  from flwr.common.logger import print_json_error, redirect_output, restore_output
@@ -48,7 +49,7 @@ from .utils import init_channel, try_obtain_cli_auth_plugin, unauthenticated_exc
48
49
  _RunListType = tuple[int, str, str, str, str, str, str, str, str]
49
50
 
50
51
 
51
- def ls( # pylint: disable=too-many-locals, too-many-branches
52
+ def ls( # pylint: disable=too-many-locals, too-many-branches, R0913, R0917
52
53
  app: Annotated[
53
54
  Path,
54
55
  typer.Argument(help="Path of the Flower project"),
@@ -57,6 +58,13 @@ def ls( # pylint: disable=too-many-locals, too-many-branches
57
58
  Optional[str],
58
59
  typer.Argument(help="Name of the federation"),
59
60
  ] = None,
61
+ federation_config_overrides: Annotated[
62
+ Optional[list[str]],
63
+ typer.Option(
64
+ "--federation-config",
65
+ help=FEDERATION_CONFIG_HELP_MESSAGE,
66
+ ),
67
+ ] = None,
60
68
  runs: Annotated[
61
69
  bool,
62
70
  typer.Option(
@@ -106,7 +114,7 @@ def ls( # pylint: disable=too-many-locals, too-many-branches
106
114
  config, errors, warnings = load_and_validate(path=pyproject_path)
107
115
  config = process_loaded_project_config(config, errors, warnings)
108
116
  federation, federation_config = validate_federation_in_project_config(
109
- federation, config
117
+ federation, config, federation_config_overrides
110
118
  )
111
119
  exit_if_no_address(federation_config, "ls")
112
120
 
@@ -115,7 +123,7 @@ def ls( # pylint: disable=too-many-locals, too-many-branches
115
123
  raise ValueError(
116
124
  "The options '--runs' and '--run-id' are mutually exclusive."
117
125
  )
118
- auth_plugin = try_obtain_cli_auth_plugin(app, federation)
126
+ auth_plugin = try_obtain_cli_auth_plugin(app, federation, federation_config)
119
127
  channel = init_channel(app, federation_config, auth_plugin)
120
128
  stub = ExecStub(channel)
121
129
 
flwr/cli/run/run.py CHANGED
@@ -31,6 +31,7 @@ from flwr.cli.config_utils import (
31
31
  process_loaded_project_config,
32
32
  validate_federation_in_project_config,
33
33
  )
34
+ from flwr.cli.constant import FEDERATION_CONFIG_HELP_MESSAGE
34
35
  from flwr.common.config import (
35
36
  flatten_dict,
36
37
  parse_config_args,
@@ -57,7 +58,7 @@ from ..utils import (
57
58
  CONN_REFRESH_PERIOD = 60 # Connection refresh period for log streaming (seconds)
58
59
 
59
60
 
60
- # pylint: disable-next=too-many-locals
61
+ # pylint: disable-next=too-many-locals, R0913, R0917
61
62
  def run(
62
63
  app: Annotated[
63
64
  Path,
@@ -67,16 +68,23 @@ def run(
67
68
  Optional[str],
68
69
  typer.Argument(help="Name of the federation to run the app on."),
69
70
  ] = None,
70
- config_overrides: Annotated[
71
+ run_config_overrides: Annotated[
71
72
  Optional[list[str]],
72
73
  typer.Option(
73
74
  "--run-config",
74
75
  "-c",
75
- help="Override configuration key-value pairs, should be of the format:\n\n"
76
- '`--run-config \'key1="value1" key2="value2"\' '
77
- "--run-config 'key3=\"value3\"'`\n\n"
78
- "Note that `key1`, `key2`, and `key3` in this example need to exist "
79
- "inside the `pyproject.toml` in order to be properly overriden.",
76
+ help="Override run configuration values in the format:\n\n"
77
+ "`--run-config 'key1=value1 key2=value2' --run-config 'key3=value3'`\n\n"
78
+ "Values can be of any type supported in TOML, such as bool, int, "
79
+ "float, or string. Ensure that the keys (`key1`, `key2`, `key3` "
80
+ "in this example) exist in `pyproject.toml` for proper overriding.",
81
+ ),
82
+ ] = None,
83
+ federation_config_overrides: Annotated[
84
+ Optional[list[str]],
85
+ typer.Option(
86
+ "--federation-config",
87
+ help=FEDERATION_CONFIG_HELP_MESSAGE,
80
88
  ),
81
89
  ] = None,
82
90
  stream: Annotated[
@@ -108,7 +116,7 @@ def run(
108
116
  config, errors, warnings = load_and_validate(path=pyproject_path)
109
117
  config = process_loaded_project_config(config, errors, warnings)
110
118
  federation, federation_config = validate_federation_in_project_config(
111
- federation, config
119
+ federation, config, federation_config_overrides
112
120
  )
113
121
 
114
122
  if "address" in federation_config:
@@ -116,12 +124,14 @@ def run(
116
124
  app,
117
125
  federation,
118
126
  federation_config,
119
- config_overrides,
127
+ run_config_overrides,
120
128
  stream,
121
129
  output_format,
122
130
  )
123
131
  else:
124
- _run_without_exec_api(app, federation_config, config_overrides, federation)
132
+ _run_without_exec_api(
133
+ app, federation_config, run_config_overrides, federation
134
+ )
125
135
  except (typer.Exit, Exception) as err: # pylint: disable=broad-except
126
136
  if suppress_output:
127
137
  restore_output()
@@ -148,7 +158,7 @@ def _run_with_exec_api(
148
158
  stream: bool,
149
159
  output_format: str,
150
160
  ) -> None:
151
- auth_plugin = try_obtain_cli_auth_plugin(app, federation)
161
+ auth_plugin = try_obtain_cli_auth_plugin(app, federation, federation_config)
152
162
  channel = init_channel(app, federation_config, auth_plugin)
153
163
  stub = ExecStub(channel)
154
164
 
flwr/cli/stop.py CHANGED
@@ -29,6 +29,7 @@ from flwr.cli.config_utils import (
29
29
  process_loaded_project_config,
30
30
  validate_federation_in_project_config,
31
31
  )
32
+ from flwr.cli.constant import FEDERATION_CONFIG_HELP_MESSAGE
32
33
  from flwr.common.constant import FAB_CONFIG_FILE, CliOutputFormat
33
34
  from flwr.common.logger import print_json_error, redirect_output, restore_output
34
35
  from flwr.proto.exec_pb2 import StopRunRequest, StopRunResponse # pylint: disable=E0611
@@ -50,6 +51,13 @@ def stop( # pylint: disable=R0914
50
51
  Optional[str],
51
52
  typer.Argument(help="Name of the federation"),
52
53
  ] = None,
54
+ federation_config_overrides: Annotated[
55
+ Optional[list[str]],
56
+ typer.Option(
57
+ "--federation-config",
58
+ help=FEDERATION_CONFIG_HELP_MESSAGE,
59
+ ),
60
+ ] = None,
53
61
  output_format: Annotated[
54
62
  str,
55
63
  typer.Option(
@@ -73,12 +81,12 @@ def stop( # pylint: disable=R0914
73
81
  config, errors, warnings = load_and_validate(path=pyproject_path)
74
82
  config = process_loaded_project_config(config, errors, warnings)
75
83
  federation, federation_config = validate_federation_in_project_config(
76
- federation, config
84
+ federation, config, federation_config_overrides
77
85
  )
78
86
  exit_if_no_address(federation_config, "stop")
79
87
 
80
88
  try:
81
- auth_plugin = try_obtain_cli_auth_plugin(app, federation)
89
+ auth_plugin = try_obtain_cli_auth_plugin(app, federation, federation_config)
82
90
  channel = init_channel(app, federation_config, auth_plugin)
83
91
  stub = ExecStub(channel) # pylint: disable=unused-variable # noqa: F841
84
92
 
flwr/cli/utils.py CHANGED
@@ -217,25 +217,42 @@ def get_user_auth_config_path(root_dir: Path, federation: str) -> Path:
217
217
  def try_obtain_cli_auth_plugin(
218
218
  root_dir: Path,
219
219
  federation: str,
220
+ federation_config: dict[str, Any],
220
221
  auth_type: Optional[str] = None,
221
222
  ) -> Optional[CliAuthPlugin]:
222
223
  """Load the CLI-side user auth plugin for the given auth type."""
223
- config_path = get_user_auth_config_path(root_dir, federation)
224
-
225
- # Load the config file if it exists
226
- json_file: dict[str, Any] = {}
227
- if config_path.exists():
228
- with config_path.open("r", encoding="utf-8") as file:
229
- json_file = json.load(file)
230
- # This is the case when the user auth is not enabled
231
- elif auth_type is None:
224
+ # Check if user auth is enabled
225
+ if not federation_config.get("enable-user-auth", False):
232
226
  return None
233
227
 
228
+ # Check if TLS is enabled. If not, raise an error
229
+ if federation_config.get("root-certificates") is None:
230
+ typer.secho(
231
+ "❌ User authentication requires TLS to be enabled. "
232
+ "Please provide 'root-certificates' in the federation"
233
+ " configuration.",
234
+ fg=typer.colors.RED,
235
+ bold=True,
236
+ )
237
+ raise typer.Exit(code=1)
238
+
239
+ config_path = get_user_auth_config_path(root_dir, federation)
240
+
234
241
  # Get the auth type from the config if not provided
242
+ # auth_type will be None for all CLI commands except login
235
243
  if auth_type is None:
236
- if AUTH_TYPE not in json_file:
237
- return None
238
- auth_type = json_file[AUTH_TYPE]
244
+ try:
245
+ with config_path.open("r", encoding="utf-8") as file:
246
+ json_file = json.load(file)
247
+ auth_type = json_file[AUTH_TYPE]
248
+ except (FileNotFoundError, KeyError):
249
+ typer.secho(
250
+ "❌ Missing or invalid credentials for user authentication. "
251
+ "Please run `flwr login` to authenticate.",
252
+ fg=typer.colors.RED,
253
+ bold=True,
254
+ )
255
+ raise typer.Exit(code=1) from None
239
256
 
240
257
  # Retrieve auth plugin class and instantiate it
241
258
  try:
flwr/common/config.py CHANGED
@@ -20,7 +20,7 @@ import re
20
20
  import zipfile
21
21
  from io import BytesIO
22
22
  from pathlib import Path
23
- from typing import IO, Any, Optional, Union, cast, get_args
23
+ from typing import IO, Any, Optional, TypeVar, Union, cast, get_args
24
24
 
25
25
  import tomli
26
26
 
@@ -35,6 +35,8 @@ from flwr.common.typing import Run, UserConfig, UserConfigValue
35
35
 
36
36
  from . import ConfigsRecord, object_ref
37
37
 
38
+ T_dict = TypeVar("T_dict", bound=dict[str, Any]) # pylint: disable=invalid-name
39
+
38
40
 
39
41
  def get_flwr_dir(provided_path: Optional[str] = None) -> Path:
40
42
  """Return the Flower home directory based on env variables."""
@@ -93,19 +95,28 @@ def get_project_config(project_dir: Union[str, Path]) -> dict[str, Any]:
93
95
 
94
96
 
95
97
  def fuse_dicts(
96
- main_dict: UserConfig,
97
- override_dict: UserConfig,
98
- ) -> UserConfig:
98
+ main_dict: T_dict,
99
+ override_dict: T_dict,
100
+ check_keys: bool = True,
101
+ ) -> T_dict:
99
102
  """Merge a config with the overrides.
100
103
 
101
- Remove the nesting by adding the nested keys as prefixes separated by dots, and fuse
102
- it with the override dict.
104
+ If `check_keys` is set to True, an error will be raised if the override
105
+ dictionary contains keys that are not present in the main dictionary.
106
+ Otherwise, only the keys present in the main dictionary will be updated.
103
107
  """
104
- fused_dict = main_dict.copy()
108
+ if not isinstance(main_dict, dict) or not isinstance(override_dict, dict):
109
+ raise ValueError("Both dictionaries must be of type dict")
110
+
111
+ fused_dict = cast(T_dict, main_dict.copy())
105
112
 
106
113
  for key, value in override_dict.items():
107
114
  if key in main_dict:
115
+ if isinstance(value, dict):
116
+ fused_dict[key] = fuse_dicts(main_dict[key], value)
108
117
  fused_dict[key] = value
118
+ elif check_keys:
119
+ raise ValueError(f"Key '{key}' is not present in the main dictionary")
109
120
 
110
121
  return fused_dict
111
122
 
@@ -194,8 +205,8 @@ def unflatten_dict(flat_dict: dict[str, Any]) -> dict[str, Any]:
194
205
 
195
206
 
196
207
  def parse_config_args(
197
- config: Optional[list[str]],
198
- ) -> UserConfig:
208
+ config: Optional[list[str]], flatten: bool = True
209
+ ) -> dict[str, Any]:
199
210
  """Parse separator separated list of key-value pairs separated by '='."""
200
211
  overrides: UserConfig = {}
201
212
 
@@ -223,7 +234,7 @@ def parse_config_args(
223
234
  matches = pattern.findall(config_line)
224
235
  toml_str = "\n".join(f"{k} = {v}" for k, v in matches)
225
236
  overrides.update(tomli.loads(toml_str))
226
- flat_overrides = flatten_dict(overrides)
237
+ flat_overrides = flatten_dict(overrides) if flatten else overrides
227
238
 
228
239
  return flat_overrides
229
240
 
@@ -31,20 +31,20 @@ from flwr.common.constant import (
31
31
  from flwr.common.grpc import create_channel
32
32
  from flwr.common.logger import log
33
33
  from flwr.common.retry_invoker import _make_simple_grpc_retry_invoker, _wrap_stub
34
- from flwr.common.serde import message_from_taskres, message_to_taskins, run_from_proto
34
+ from flwr.common.serde import message_from_proto, message_to_proto, run_from_proto
35
35
  from flwr.common.typing import Run
36
+ from flwr.proto.message_pb2 import Message as ProtoMessage # pylint: disable=E0611
36
37
  from flwr.proto.node_pb2 import Node # pylint: disable=E0611
37
38
  from flwr.proto.run_pb2 import GetRunRequest, GetRunResponse # pylint: disable=E0611
38
39
  from flwr.proto.serverappio_pb2 import ( # pylint: disable=E0611
39
40
  GetNodesRequest,
40
41
  GetNodesResponse,
41
- PullTaskResRequest,
42
- PullTaskResResponse,
43
- PushTaskInsRequest,
44
- PushTaskInsResponse,
42
+ PullResMessagesRequest,
43
+ PullResMessagesResponse,
44
+ PushInsMessagesRequest,
45
+ PushInsMessagesResponse,
45
46
  )
46
47
  from flwr.proto.serverappio_pb2_grpc import ServerAppIoStub # pylint: disable=E0611
47
- from flwr.proto.task_pb2 import TaskIns # pylint: disable=E0611
48
48
 
49
49
  from .driver import Driver
50
50
 
@@ -196,22 +196,22 @@ class GrpcDriver(Driver):
196
196
  This method takes an iterable of messages and sends each message
197
197
  to the node specified in `dst_node_id`.
198
198
  """
199
- # Construct TaskIns
200
- task_ins_list: list[TaskIns] = []
199
+ # Construct Messages
200
+ message_proto_list: list[ProtoMessage] = []
201
201
  for msg in messages:
202
202
  # Check message
203
203
  self._check_message(msg)
204
- # Convert Message to TaskIns
205
- taskins = message_to_taskins(msg)
204
+ # Convert to proto
205
+ msg_proto = message_to_proto(msg)
206
206
  # Add to list
207
- task_ins_list.append(taskins)
207
+ message_proto_list.append(msg_proto)
208
208
  # Call GrpcDriverStub method
209
- res: PushTaskInsResponse = self._stub.PushTaskIns(
210
- PushTaskInsRequest(
211
- task_ins_list=task_ins_list, run_id=cast(Run, self._run).run_id
209
+ res: PushInsMessagesResponse = self._stub.PushMessages(
210
+ PushInsMessagesRequest(
211
+ messages_list=message_proto_list, run_id=cast(Run, self._run).run_id
212
212
  )
213
213
  )
214
- return list(res.task_ids)
214
+ return list(res.message_ids)
215
215
 
216
216
  def pull_messages(self, message_ids: Iterable[str]) -> Iterable[Message]:
217
217
  """Pull messages based on message IDs.
@@ -219,14 +219,15 @@ class GrpcDriver(Driver):
219
219
  This method is used to collect messages from the SuperLink that correspond to a
220
220
  set of given message IDs.
221
221
  """
222
- # Pull TaskRes
223
- res: PullTaskResResponse = self._stub.PullTaskRes(
224
- PullTaskResRequest(
225
- node=self.node, task_ids=message_ids, run_id=cast(Run, self._run).run_id
222
+ # Pull Messages
223
+ res: PullResMessagesResponse = self._stub.PullMessages(
224
+ PullResMessagesRequest(
225
+ message_ids=message_ids,
226
+ run_id=cast(Run, self._run).run_id,
226
227
  )
227
228
  )
228
- # Convert TaskRes to Message
229
- msgs = [message_from_taskres(taskres) for taskres in res.task_res_list]
229
+ # Convert Message from Protobuf representation
230
+ msgs = [message_from_proto(msg_proto) for msg_proto in res.messages_list]
230
231
  return msgs
231
232
 
232
233
  def send_and_receive(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr-nightly
3
- Version: 1.15.0.dev20250122
3
+ Version: 1.15.0.dev20250124
4
4
  Summary: Flower: A Friendly Federated AI Framework
5
5
  Home-page: https://flower.ai
6
6
  License: Apache-2.0
@@ -3,13 +3,14 @@ flwr/cli/__init__.py,sha256=cZJVgozlkC6Ni2Hd_FAIrqefrkCGOV18fikToq-6iLw,720
3
3
  flwr/cli/app.py,sha256=UeXrW5gxrUnFViDjAMIxGNZZKwu3a1oAj83v53IWIWM,1382
4
4
  flwr/cli/build.py,sha256=4P70i_FnUs0P21aTwjTXtFQSAfY-C04hUDF-2npfJdo,6345
5
5
  flwr/cli/cli_user_auth_interceptor.py,sha256=aZepPA298s-HjGmkJGMvI_uZe72O5aLC3jri-ilG53o,3126
6
- flwr/cli/config_utils.py,sha256=u4VMNgNTj1mGgCVzV4KfBz3Nyn0j46KJ-Ii8dUgZ4OM,7196
6
+ flwr/cli/config_utils.py,sha256=LelRR960I36n1IPw7BIu79fKoOh0JePA58kAtoXSTH0,7518
7
+ flwr/cli/constant.py,sha256=g7Ad7o3DJDkJNrWS0T3SSJETWSTkkVJWGpLM8zlbpcY,1289
7
8
  flwr/cli/example.py,sha256=uk5CoD0ZITgpY_ffsTbEKf8XOOCSUzByjHPcMSPqV18,2216
8
9
  flwr/cli/install.py,sha256=-RnrYGejN_zyXXp_CoddSQwoQfRTWWyt9WYlxphJzyU,8180
9
- flwr/cli/log.py,sha256=O7MBpsJp114PIZb-7Cru-KM6fqyneFQkqoQbQsqQmZU,6121
10
+ flwr/cli/log.py,sha256=vcO-r5EIc127mOQ26uxKVITX-w_Zib7AxSVuuN70_JY,6671
10
11
  flwr/cli/login/__init__.py,sha256=6_9zOzbPOAH72K2wX3-9dXTAbS7Mjpa5sEn2lA6eHHI,800
11
- flwr/cli/login/login.py,sha256=VaBPQBdLYmSfxXEJWVyu8U5dXztQgIv6rfTJkvz3zV8,3025
12
- flwr/cli/ls.py,sha256=K_3Bt2RfETw4V7J4qgo8_Wx-Y_bWZqttuO879Ppxo5Y,11056
12
+ flwr/cli/login/login.py,sha256=EOU1E-89VPn5Ns7ytaDdGNVVeOoC4ULFjtNPogjXGGQ,3783
13
+ flwr/cli/ls.py,sha256=5KCHdctN5f5GkCAkbZSC1OuKdhmLzobINpltsdtDtQU,11383
13
14
  flwr/cli/new/__init__.py,sha256=pOQtPT9W4kCIttcKne5m-FtJbvTqdjTVJxzQ9AUYK8I,790
14
15
  flwr/cli/new/new.py,sha256=scyyKt8mzkc3El1bypgkHjKwVQEc2-q4I50PxriPFdI,9922
15
16
  flwr/cli/new/templates/__init__.py,sha256=4luU8RL-CK8JJCstQ_ON809W9bNTkY1l9zSaPKBkgwY,725
@@ -65,9 +66,9 @@ flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl,sha256=PA_dEtWkY6Wf3Ektc9D
65
66
  flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl,sha256=d7TwWH-QJN0j-9rs9zHnng_bHeHV7mk138KXqdv5BoE,686
66
67
  flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl,sha256=r0SZnvoR5a5mEWKJIvQ3rW8C6-2DkhaC8A1fTA0avm0,710
67
68
  flwr/cli/run/__init__.py,sha256=cCsKVB0SFzh2b3QmGba6BHckB85xlhjh3mh4pBpACtY,790
68
- flwr/cli/run/run.py,sha256=BvpjYyUvDhVMvO5cG711ihtdeSbls9p8zVAuFGETLA8,7893
69
- flwr/cli/stop.py,sha256=1T9RNRCH8dxjmBT38hFtKAWY9Gb7RMCMCML7kex9WzE,4613
70
- flwr/cli/utils.py,sha256=RXozds-T7HN8yH0mMj67q-0YktdNNm83N9Ptu_pdhsc,10604
69
+ flwr/cli/run/run.py,sha256=kEOYKin9qPJy8SODxcAvIWk-OskKPsxvcbvhDhf2VD4,8299
70
+ flwr/cli/stop.py,sha256=DBCKg9AhB1WcJsyqfkHKR1_V_yT7D32zqa9QhmX9IAU,4926
71
+ flwr/cli/utils.py,sha256=z5WFbh2RwMirFcv6QtV_4rJlK7ad2XrUJUsinNhqE28,11310
71
72
  flwr/client/__init__.py,sha256=DGDoO0AEAfz-0CUFmLdyUUweAS64-07AOnmDfWUefK4,1192
72
73
  flwr/client/app.py,sha256=tNnef5wGVfqMiiGiWzAuULyy1QpvCKukiRmNi_a2cQc,34261
73
74
  flwr/client/client.py,sha256=8o58nd9o6ZFcMIaVYPGcV4MSjBG4H0oFgWiv8ZEO3oA,7895
@@ -113,7 +114,7 @@ flwr/common/address.py,sha256=9KNYE69WW_QVcyumsux3Qn1wmn4J7f13Y9nHASpvzbA,3018
113
114
  flwr/common/args.py,sha256=bCvtG0hhh_hVjl9NoWsY_g7kLMIN3jCN7B883HvZ7hg,6223
114
115
  flwr/common/auth_plugin/__init__.py,sha256=1Y8Oj3iB49IHDu9tvDih1J74Ygu7k85V9s2A4WORPyA,887
115
116
  flwr/common/auth_plugin/auth_plugin.py,sha256=wgDorBUB4IkK6twQ8vNawRVz7BDPmKdXZBNLqhU9RSs,3871
116
- flwr/common/config.py,sha256=GEnOmW1vw-0IF-NkekyXQLYqstSqetZFEtT_SShyBgA,12693
117
+ flwr/common/config.py,sha256=n6T5Vi6BUFul37GUpKp9Doqnz35phJqSud_G3ySWlIQ,13336
117
118
  flwr/common/constant.py,sha256=FLqav6UCcdCG61XZr31fmAFqOu4WRFG8zcbnwUyYJ4w,6202
118
119
  flwr/common/context.py,sha256=uJ-mnoC_8y_udEb3kAX-r8CPphNTWM72z1AlsvQEu54,2403
119
120
  flwr/common/date.py,sha256=NHHpESce5wYqEwoDXf09gp9U9l_5Bmlh2BsOcwS-kDM,1554
@@ -225,7 +226,7 @@ flwr/server/compat/legacy_context.py,sha256=wBzBcfV6YO6IQGriM_FdJ5XZfiBBEEJdS_Od
225
226
  flwr/server/criterion.py,sha256=ypbAexbztzGUxNen9RCHF91QeqiEQix4t4Ih3E-42MM,1061
226
227
  flwr/server/driver/__init__.py,sha256=bikRv6CjTwSvYh7tf10gziU5o2YotOWhhftz2tr3KDc,886
227
228
  flwr/server/driver/driver.py,sha256=u_fMfqLYTroTafGCNwKPHI4lttRL-Z5CqeT3_FHSq-Q,5701
228
- flwr/server/driver/grpc_driver.py,sha256=jJBQOlbPXT-qn1MzjReyFGFPTA6WpiJQoiXISrkAVsc,9668
229
+ flwr/server/driver/grpc_driver.py,sha256=VYIbYavkJO2m6TcqStHr-pQLiyEoWlX8lsOsWfljZRQ,9758
229
230
  flwr/server/driver/inmemory_driver.py,sha256=b1U1PrB_Vpn--vav8SX-sn0THD9BTlV9UFIpuWTWLro,6665
230
231
  flwr/server/history.py,sha256=qSb5_pPTrwofpSYGsZWzMPkl_4uJ4mJFWesxXDrEvDU,5026
231
232
  flwr/server/run_serverapp.py,sha256=vIPhvJx0i5sEZO4IKM6ruCXmx4ncat76rh0B4KhdhhM,2446
@@ -324,8 +325,8 @@ flwr/superexec/exec_servicer.py,sha256=X10ILT-AoGMrB3IgI2mBe9i-QcIVUAl9bucuqVOPY
324
325
  flwr/superexec/exec_user_auth_interceptor.py,sha256=K06OU-l4LnYhTDg071hGJuOaQWEJbZsYi5qxUmmtiG0,3704
325
326
  flwr/superexec/executor.py,sha256=_B55WW2TD1fBINpabSSDRenVHXYmvlfhv-k8hJKU4lQ,3115
326
327
  flwr/superexec/simulation.py,sha256=WQDon15oqpMopAZnwRZoTICYCfHqtkvFSqiTQ2hLD_g,4088
327
- flwr_nightly-1.15.0.dev20250122.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
328
- flwr_nightly-1.15.0.dev20250122.dist-info/METADATA,sha256=HNrdO4R0GWS2WA5_9eQjJrKDJhObz0BZJKPsVYErnso,15864
329
- flwr_nightly-1.15.0.dev20250122.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
330
- flwr_nightly-1.15.0.dev20250122.dist-info/entry_points.txt,sha256=JlNxX3qhaV18_2yj5a3kJW1ESxm31cal9iS_N_pf1Rk,538
331
- flwr_nightly-1.15.0.dev20250122.dist-info/RECORD,,
328
+ flwr_nightly-1.15.0.dev20250124.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
329
+ flwr_nightly-1.15.0.dev20250124.dist-info/METADATA,sha256=tr-JyBTsXNIUah1qY_BnD7Uhtsukv8Ktq5edbetabJs,15864
330
+ flwr_nightly-1.15.0.dev20250124.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
331
+ flwr_nightly-1.15.0.dev20250124.dist-info/entry_points.txt,sha256=JlNxX3qhaV18_2yj5a3kJW1ESxm31cal9iS_N_pf1Rk,538
332
+ flwr_nightly-1.15.0.dev20250124.dist-info/RECORD,,