flwr-nightly 1.14.0.dev20241211__py3-none-any.whl → 1.14.0.dev20241213__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/app.py +1 -0
- flwr/cli/build.py +1 -0
- flwr/cli/config_utils.py +1 -0
- flwr/cli/example.py +1 -0
- flwr/cli/install.py +1 -0
- flwr/cli/log.py +1 -0
- flwr/cli/login/__init__.py +1 -0
- flwr/cli/login/login.py +1 -0
- flwr/cli/new/__init__.py +1 -0
- flwr/cli/new/new.py +2 -1
- flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +1 -2
- flwr/cli/run/__init__.py +1 -0
- flwr/cli/run/run.py +1 -0
- flwr/cli/utils.py +1 -0
- flwr/client/app.py +3 -2
- flwr/client/client.py +1 -0
- flwr/client/clientapp/app.py +1 -0
- 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 +3 -3
- flwr/client/message_handler/message_handler.py +1 -0
- 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/rest_client/connection.py +3 -3
- flwr/client/supernode/app.py +1 -0
- flwr/common/address.py +1 -0
- flwr/common/args.py +1 -0
- flwr/common/config.py +1 -0
- flwr/common/logger.py +1 -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 +75 -0
- flwr/common/typing.py +4 -0
- flwr/common/version.py +1 -0
- flwr/proto/fab_pb2.py +4 -4
- flwr/proto/fab_pb2.pyi +4 -1
- flwr/server/app.py +1 -0
- flwr/server/compat/app_utils.py +7 -1
- flwr/server/driver/grpc_driver.py +5 -61
- flwr/server/driver/inmemory_driver.py +5 -1
- flwr/server/serverapp/app.py +9 -2
- flwr/server/strategy/dpfedavg_fixed.py +1 -0
- flwr/server/superlink/driver/serverappio_grpc.py +1 -0
- flwr/server/superlink/driver/serverappio_servicer.py +54 -22
- flwr/server/superlink/ffs/disk_ffs.py +1 -0
- flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +1 -0
- 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 +14 -30
- flwr/server/superlink/linkstate/linkstate.py +13 -2
- flwr/server/superlink/linkstate/sqlite_linkstate.py +24 -44
- flwr/server/superlink/simulation/simulationio_servicer.py +1 -0
- flwr/server/superlink/utils.py +65 -0
- flwr/simulation/app.py +1 -0
- flwr/simulation/ray_transport/ray_actor.py +1 -0
- flwr/simulation/ray_transport/utils.py +1 -0
- flwr/simulation/run_simulation.py +1 -0
- flwr/superexec/app.py +1 -0
- flwr/superexec/deployment.py +1 -0
- flwr/superexec/exec_grpc.py +1 -0
- flwr/superexec/exec_servicer.py +8 -0
- flwr/superexec/executor.py +1 -0
- {flwr_nightly-1.14.0.dev20241211.dist-info → flwr_nightly-1.14.0.dev20241213.dist-info}/METADATA +1 -1
- {flwr_nightly-1.14.0.dev20241211.dist-info → flwr_nightly-1.14.0.dev20241213.dist-info}/RECORD +75 -74
- {flwr_nightly-1.14.0.dev20241211.dist-info → flwr_nightly-1.14.0.dev20241213.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.14.0.dev20241211.dist-info → flwr_nightly-1.14.0.dev20241213.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.14.0.dev20241211.dist-info → flwr_nightly-1.14.0.dev20241213.dist-info}/entry_points.txt +0 -0
flwr/cli/app.py
CHANGED
flwr/cli/build.py
CHANGED
flwr/cli/config_utils.py
CHANGED
flwr/cli/example.py
CHANGED
flwr/cli/install.py
CHANGED
flwr/cli/log.py
CHANGED
flwr/cli/login/__init__.py
CHANGED
flwr/cli/login/login.py
CHANGED
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:
|
flwr/cli/run/__init__.py
CHANGED
flwr/cli/run/run.py
CHANGED
flwr/cli/utils.py
CHANGED
flwr/client/app.py
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
# ==============================================================================
|
|
15
15
|
"""Flower client app."""
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
import signal
|
|
18
19
|
import subprocess
|
|
19
20
|
import sys
|
|
@@ -474,7 +475,7 @@ def start_client_internal(
|
|
|
474
475
|
|
|
475
476
|
run: Run = runs[run_id]
|
|
476
477
|
if get_fab is not None and run.fab_hash:
|
|
477
|
-
fab = get_fab(run.fab_hash)
|
|
478
|
+
fab = get_fab(run.fab_hash, run_id)
|
|
478
479
|
if not isolation:
|
|
479
480
|
# If `ClientApp` runs in the same process, install the FAB
|
|
480
481
|
install_from_fab(fab.content, flwr_path, True)
|
|
@@ -752,7 +753,7 @@ def _init_connection(transport: Optional[str], server_address: str) -> tuple[
|
|
|
752
753
|
Optional[Callable[[], Optional[int]]],
|
|
753
754
|
Optional[Callable[[], None]],
|
|
754
755
|
Optional[Callable[[int], Run]],
|
|
755
|
-
Optional[Callable[[str], Fab]],
|
|
756
|
+
Optional[Callable[[str, int], Fab]],
|
|
756
757
|
]
|
|
757
758
|
],
|
|
758
759
|
],
|
flwr/client/client.py
CHANGED
flwr/client/clientapp/app.py
CHANGED
flwr/client/clientapp/utils.py
CHANGED
|
@@ -48,7 +48,7 @@ def grpc_adapter( # pylint: disable=R0913,too-many-positional-arguments
|
|
|
48
48
|
Optional[Callable[[], Optional[int]]],
|
|
49
49
|
Optional[Callable[[], None]],
|
|
50
50
|
Optional[Callable[[int], Run]],
|
|
51
|
-
Optional[Callable[[str], Fab]],
|
|
51
|
+
Optional[Callable[[str, int], Fab]],
|
|
52
52
|
]
|
|
53
53
|
]:
|
|
54
54
|
"""Primitives for request/response-based interaction with a server via GrpcAdapter.
|
|
@@ -76,7 +76,7 @@ def grpc_connection( # pylint: disable=R0913,R0915,too-many-positional-argument
|
|
|
76
76
|
Optional[Callable[[], Optional[int]]],
|
|
77
77
|
Optional[Callable[[], None]],
|
|
78
78
|
Optional[Callable[[int], Run]],
|
|
79
|
-
Optional[Callable[[str], Fab]],
|
|
79
|
+
Optional[Callable[[str, int], Fab]],
|
|
80
80
|
]
|
|
81
81
|
]:
|
|
82
82
|
"""Establish a gRPC connection to a gRPC server.
|
|
@@ -84,7 +84,7 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
|
84
84
|
Optional[Callable[[], Optional[int]]],
|
|
85
85
|
Optional[Callable[[], None]],
|
|
86
86
|
Optional[Callable[[int], Run]],
|
|
87
|
-
Optional[Callable[[str], Fab]],
|
|
87
|
+
Optional[Callable[[str, int], Fab]],
|
|
88
88
|
]
|
|
89
89
|
]:
|
|
90
90
|
"""Primitives for request/response-based interaction with a server.
|
|
@@ -290,9 +290,9 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
|
290
290
|
# Return fab_id and fab_version
|
|
291
291
|
return run_from_proto(get_run_response.run)
|
|
292
292
|
|
|
293
|
-
def get_fab(fab_hash: str) -> Fab:
|
|
293
|
+
def get_fab(fab_hash: str, run_id: int) -> Fab:
|
|
294
294
|
# Call FleetAPI
|
|
295
|
-
get_fab_request = GetFabRequest(node=node, hash_str=fab_hash)
|
|
295
|
+
get_fab_request = GetFabRequest(node=node, hash_str=fab_hash, run_id=run_id)
|
|
296
296
|
get_fab_response: GetFabResponse = retry_invoker.invoke(
|
|
297
297
|
stub.GetFab,
|
|
298
298
|
request=get_fab_request,
|
flwr/client/mod/comms_mods.py
CHANGED
flwr/client/mod/localdp_mod.py
CHANGED
|
@@ -136,7 +136,7 @@ class LocalDpMod:
|
|
|
136
136
|
fit_res.parameters = ndarrays_to_parameters(client_to_server_params)
|
|
137
137
|
|
|
138
138
|
# Add noise to model params
|
|
139
|
-
add_localdp_gaussian_noise_to_params(
|
|
139
|
+
fit_res.parameters = add_localdp_gaussian_noise_to_params(
|
|
140
140
|
fit_res.parameters, self.sensitivity, self.epsilon, self.delta
|
|
141
141
|
)
|
|
142
142
|
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
# ==============================================================================
|
|
15
15
|
"""Flower NodeState."""
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
from .in_memory_nodestate import InMemoryNodeState as InMemoryNodeState
|
|
18
19
|
from .nodestate import NodeState as NodeState
|
|
19
20
|
from .nodestate_factory import NodeStateFactory as NodeStateFactory
|
|
@@ -96,7 +96,7 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
|
96
96
|
Optional[Callable[[], Optional[int]]],
|
|
97
97
|
Optional[Callable[[], None]],
|
|
98
98
|
Optional[Callable[[int], Run]],
|
|
99
|
-
Optional[Callable[[str], Fab]],
|
|
99
|
+
Optional[Callable[[str, int], Fab]],
|
|
100
100
|
]
|
|
101
101
|
]:
|
|
102
102
|
"""Primitives for request/response-based interaction with a server.
|
|
@@ -361,9 +361,9 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
|
361
361
|
|
|
362
362
|
return run_from_proto(res.run)
|
|
363
363
|
|
|
364
|
-
def get_fab(fab_hash: str) -> Fab:
|
|
364
|
+
def get_fab(fab_hash: str, run_id: int) -> Fab:
|
|
365
365
|
# Construct the request
|
|
366
|
-
req = GetFabRequest(node=node, hash_str=fab_hash)
|
|
366
|
+
req = GetFabRequest(node=node, hash_str=fab_hash, run_id=run_id)
|
|
367
367
|
|
|
368
368
|
# Send the request
|
|
369
369
|
res = _request(req, GetFabResponse, PATH_GET_FAB)
|
flwr/client/supernode/app.py
CHANGED
flwr/common/address.py
CHANGED
flwr/common/args.py
CHANGED
flwr/common/config.py
CHANGED
flwr/common/logger.py
CHANGED
flwr/common/message.py
CHANGED
flwr/common/object_ref.py
CHANGED
|
@@ -21,6 +21,7 @@ import sys
|
|
|
21
21
|
from importlib.util import find_spec
|
|
22
22
|
from logging import WARN
|
|
23
23
|
from pathlib import Path
|
|
24
|
+
from threading import Lock
|
|
24
25
|
from typing import Any, Optional, Union
|
|
25
26
|
|
|
26
27
|
from .logger import log
|
|
@@ -34,6 +35,7 @@ attribute.
|
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
_current_sys_path: Optional[str] = None
|
|
38
|
+
_import_lock = Lock()
|
|
37
39
|
|
|
38
40
|
|
|
39
41
|
def validate(
|
|
@@ -146,60 +148,61 @@ def load_app( # pylint: disable= too-many-branches
|
|
|
146
148
|
- This function will modify `sys.path` by inserting the provided `project_dir`
|
|
147
149
|
and removing the previously inserted `project_dir`.
|
|
148
150
|
"""
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
project_dir
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
151
|
+
with _import_lock:
|
|
152
|
+
valid, error_msg = validate(module_attribute_str, check_module=False)
|
|
153
|
+
if not valid and error_msg:
|
|
154
|
+
raise error_type(error_msg) from None
|
|
155
|
+
|
|
156
|
+
module_str, _, attributes_str = module_attribute_str.partition(":")
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
# Initialize project path
|
|
160
|
+
if project_dir is None:
|
|
161
|
+
project_dir = Path.cwd()
|
|
162
|
+
project_dir = Path(project_dir).absolute()
|
|
163
|
+
|
|
164
|
+
# Unload modules if the project directory has changed
|
|
165
|
+
if _current_sys_path and _current_sys_path != str(project_dir):
|
|
166
|
+
_unload_modules(Path(_current_sys_path))
|
|
167
|
+
|
|
168
|
+
# Set the system path
|
|
169
|
+
_set_sys_path(project_dir)
|
|
170
|
+
|
|
171
|
+
# Import the module
|
|
172
|
+
if module_str not in sys.modules:
|
|
173
|
+
module = importlib.import_module(module_str)
|
|
174
|
+
# Hack: `tabnet` does not work with `importlib.reload`
|
|
175
|
+
elif "tabnet" in sys.modules:
|
|
176
|
+
log(
|
|
177
|
+
WARN,
|
|
178
|
+
"Cannot reload module `%s` from disk due to compatibility issues "
|
|
179
|
+
"with the `tabnet` library. The module will be loaded from the "
|
|
180
|
+
"cache instead. If you experience issues, consider restarting "
|
|
181
|
+
"the application.",
|
|
182
|
+
module_str,
|
|
183
|
+
)
|
|
184
|
+
module = sys.modules[module_str]
|
|
185
|
+
else:
|
|
186
|
+
module = sys.modules[module_str]
|
|
187
|
+
_reload_modules(project_dir)
|
|
188
|
+
|
|
189
|
+
except ModuleNotFoundError as err:
|
|
190
|
+
raise error_type(
|
|
191
|
+
f"Unable to load module {module_str}{OBJECT_REF_HELP_STR}",
|
|
192
|
+
) from err
|
|
193
|
+
|
|
194
|
+
# Recursively load attribute
|
|
195
|
+
attribute = module
|
|
196
|
+
try:
|
|
197
|
+
for attribute_str in attributes_str.split("."):
|
|
198
|
+
attribute = getattr(attribute, attribute_str)
|
|
199
|
+
except AttributeError as err:
|
|
200
|
+
raise error_type(
|
|
201
|
+
f"Unable to load attribute {attributes_str} from module {module_str}"
|
|
202
|
+
f"{OBJECT_REF_HELP_STR}",
|
|
203
|
+
) from err
|
|
204
|
+
|
|
205
|
+
return attribute
|
|
203
206
|
|
|
204
207
|
|
|
205
208
|
def _unload_modules(project_dir: Path) -> None:
|
flwr/common/pyproject.py
CHANGED
flwr/common/record/__init__.py
CHANGED
flwr/common/retry_invoker.py
CHANGED
|
@@ -20,8 +20,17 @@ import random
|
|
|
20
20
|
import time
|
|
21
21
|
from collections.abc import Generator, Iterable
|
|
22
22
|
from dataclasses import dataclass
|
|
23
|
+
from logging import INFO, WARN
|
|
23
24
|
from typing import Any, Callable, Optional, Union, cast
|
|
24
25
|
|
|
26
|
+
import grpc
|
|
27
|
+
|
|
28
|
+
from flwr.common.constant import MAX_RETRY_DELAY
|
|
29
|
+
from flwr.common.logger import log
|
|
30
|
+
from flwr.common.typing import RunNotRunningException
|
|
31
|
+
from flwr.proto.clientappio_pb2_grpc import ClientAppIoStub
|
|
32
|
+
from flwr.proto.serverappio_pb2_grpc import ServerAppIoStub
|
|
33
|
+
|
|
25
34
|
|
|
26
35
|
def exponential(
|
|
27
36
|
base_delay: float = 1,
|
|
@@ -303,3 +312,69 @@ class RetryInvoker:
|
|
|
303
312
|
# Trigger success event
|
|
304
313
|
try_call_event_handler(self.on_success)
|
|
305
314
|
return ret
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def _make_simple_grpc_retry_invoker() -> RetryInvoker:
|
|
318
|
+
"""Create a simple gRPC retry invoker."""
|
|
319
|
+
|
|
320
|
+
def _on_sucess(retry_state: RetryState) -> None:
|
|
321
|
+
if retry_state.tries > 1:
|
|
322
|
+
log(
|
|
323
|
+
INFO,
|
|
324
|
+
"Connection successful after %.2f seconds and %s tries.",
|
|
325
|
+
retry_state.elapsed_time,
|
|
326
|
+
retry_state.tries,
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
def _on_backoff(retry_state: RetryState) -> None:
|
|
330
|
+
if retry_state.tries == 1:
|
|
331
|
+
log(WARN, "Connection attempt failed, retrying...")
|
|
332
|
+
else:
|
|
333
|
+
log(
|
|
334
|
+
WARN,
|
|
335
|
+
"Connection attempt failed, retrying in %.2f seconds",
|
|
336
|
+
retry_state.actual_wait,
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
def _on_giveup(retry_state: RetryState) -> None:
|
|
340
|
+
if retry_state.tries > 1:
|
|
341
|
+
log(
|
|
342
|
+
WARN,
|
|
343
|
+
"Giving up reconnection after %.2f seconds and %s tries.",
|
|
344
|
+
retry_state.elapsed_time,
|
|
345
|
+
retry_state.tries,
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
def _should_giveup_fn(e: Exception) -> bool:
|
|
349
|
+
if e.code() == grpc.StatusCode.PERMISSION_DENIED: # type: ignore
|
|
350
|
+
raise RunNotRunningException
|
|
351
|
+
if e.code() == grpc.StatusCode.UNAVAILABLE: # type: ignore
|
|
352
|
+
return False
|
|
353
|
+
return True
|
|
354
|
+
|
|
355
|
+
return RetryInvoker(
|
|
356
|
+
wait_gen_factory=lambda: exponential(max_delay=MAX_RETRY_DELAY),
|
|
357
|
+
recoverable_exceptions=grpc.RpcError,
|
|
358
|
+
max_tries=None,
|
|
359
|
+
max_time=None,
|
|
360
|
+
on_success=_on_sucess,
|
|
361
|
+
on_backoff=_on_backoff,
|
|
362
|
+
on_giveup=_on_giveup,
|
|
363
|
+
should_giveup=_should_giveup_fn,
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def _wrap_stub(
|
|
368
|
+
stub: Union[ServerAppIoStub, ClientAppIoStub], retry_invoker: RetryInvoker
|
|
369
|
+
) -> None:
|
|
370
|
+
"""Wrap a gRPC stub with a retry invoker."""
|
|
371
|
+
|
|
372
|
+
def make_lambda(original_method: Any) -> Any:
|
|
373
|
+
return lambda *args, **kwargs: retry_invoker.invoke(
|
|
374
|
+
original_method, *args, **kwargs
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
for method_name in vars(stub):
|
|
378
|
+
method = getattr(stub, method_name)
|
|
379
|
+
if callable(method):
|
|
380
|
+
setattr(stub, method_name, make_lambda(method))
|
flwr/common/typing.py
CHANGED