flwr-nightly 1.14.0.dev20241204__py3-none-any.whl → 1.14.0.dev20241216__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 +5 -0
- flwr/cli/build.py +1 -0
- 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 +1 -0
- flwr/cli/log.py +11 -31
- flwr/cli/login/__init__.py +22 -0
- flwr/cli/login/login.py +81 -0
- flwr/cli/ls.py +25 -55
- flwr/cli/new/__init__.py +1 -0
- flwr/cli/new/new.py +2 -1
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +2 -2
- flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +1 -2
- flwr/cli/run/__init__.py +1 -0
- flwr/cli/run/run.py +17 -39
- flwr/cli/stop.py +129 -0
- flwr/cli/utils.py +96 -1
- flwr/client/app.py +14 -3
- flwr/client/client.py +1 -0
- flwr/client/clientapp/app.py +4 -1
- 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 -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/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 +6 -1
- flwr/common/logger.py +17 -1
- 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 +2 -1
- flwr/common/typing.py +12 -0
- flwr/common/version.py +1 -0
- flwr/proto/exec_pb2.py +27 -3
- flwr/proto/exec_pb2.pyi +103 -0
- 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 +52 -1
- 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/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 +72 -22
- 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/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 +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 +20 -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 -15
- 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_nightly-1.14.0.dev20241204.dist-info → flwr_nightly-1.14.0.dev20241216.dist-info}/METADATA +8 -7
- {flwr_nightly-1.14.0.dev20241204.dist-info → flwr_nightly-1.14.0.dev20241216.dist-info}/RECORD +101 -93
- {flwr_nightly-1.14.0.dev20241204.dist-info → flwr_nightly-1.14.0.dev20241216.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.14.0.dev20241204.dist-info → flwr_nightly-1.14.0.dev20241216.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.14.0.dev20241204.dist-info → flwr_nightly-1.14.0.dev20241216.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Copyright 2024 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
|
+
"""Abstract classes for Flower User Auth Plugin."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from abc import ABC, abstractmethod
|
|
19
|
+
from collections.abc import Sequence
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Any, Optional, Union
|
|
22
|
+
|
|
23
|
+
from flwr.proto.exec_pb2_grpc import ExecStub
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ExecAuthPlugin(ABC):
|
|
27
|
+
"""Abstract Flower Auth Plugin class for ExecServicer.
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
config : dict[str, Any]
|
|
32
|
+
The authentication configuration loaded from a YAML file.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
@abstractmethod
|
|
36
|
+
def __init__(self, config: dict[str, Any]):
|
|
37
|
+
"""Abstract constructor."""
|
|
38
|
+
|
|
39
|
+
@abstractmethod
|
|
40
|
+
def get_login_details(self) -> dict[str, str]:
|
|
41
|
+
"""Get the login details."""
|
|
42
|
+
|
|
43
|
+
@abstractmethod
|
|
44
|
+
def validate_tokens_in_metadata(
|
|
45
|
+
self, metadata: Sequence[tuple[str, Union[str, bytes]]]
|
|
46
|
+
) -> bool:
|
|
47
|
+
"""Validate authentication tokens in the provided metadata."""
|
|
48
|
+
|
|
49
|
+
@abstractmethod
|
|
50
|
+
def get_auth_tokens(self, auth_details: dict[str, str]) -> dict[str, str]:
|
|
51
|
+
"""Get authentication tokens."""
|
|
52
|
+
|
|
53
|
+
@abstractmethod
|
|
54
|
+
def refresh_tokens(
|
|
55
|
+
self, metadata: Sequence[tuple[str, Union[str, bytes]]]
|
|
56
|
+
) -> Optional[Sequence[tuple[str, Union[str, bytes]]]]:
|
|
57
|
+
"""Refresh authentication tokens in the provided metadata."""
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class CliAuthPlugin(ABC):
|
|
61
|
+
"""Abstract Flower Auth Plugin class for CLI.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
user_auth_config_path : Path
|
|
66
|
+
The path to the user's authentication configuration file.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
@staticmethod
|
|
70
|
+
@abstractmethod
|
|
71
|
+
def login(
|
|
72
|
+
login_details: dict[str, str],
|
|
73
|
+
exec_stub: ExecStub,
|
|
74
|
+
) -> dict[str, Any]:
|
|
75
|
+
"""Authenticate the user with the SuperLink.
|
|
76
|
+
|
|
77
|
+
Parameters
|
|
78
|
+
----------
|
|
79
|
+
login_details : dict[str, str]
|
|
80
|
+
A dictionary containing the user's login details.
|
|
81
|
+
exec_stub : ExecStub
|
|
82
|
+
An instance of `ExecStub` used for communication with the SuperLink.
|
|
83
|
+
|
|
84
|
+
Returns
|
|
85
|
+
-------
|
|
86
|
+
user_auth_config : dict[str, Any]
|
|
87
|
+
A dictionary containing the user's authentication configuration
|
|
88
|
+
in JSON format.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
@abstractmethod
|
|
92
|
+
def __init__(self, user_auth_config_path: Path):
|
|
93
|
+
"""Abstract constructor."""
|
|
94
|
+
|
|
95
|
+
@abstractmethod
|
|
96
|
+
def store_tokens(self, user_auth_config: dict[str, Any]) -> None:
|
|
97
|
+
"""Store authentication tokens from the provided user_auth_config.
|
|
98
|
+
|
|
99
|
+
The configuration, including tokens, will be saved as a JSON file
|
|
100
|
+
at `user_auth_config_path`.
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
@abstractmethod
|
|
104
|
+
def load_tokens(self) -> None:
|
|
105
|
+
"""Load authentication tokens from the user_auth_config_path."""
|
|
106
|
+
|
|
107
|
+
@abstractmethod
|
|
108
|
+
def write_tokens_to_metadata(
|
|
109
|
+
self, metadata: Sequence[tuple[str, Union[str, bytes]]]
|
|
110
|
+
) -> Sequence[tuple[str, Union[str, bytes]]]:
|
|
111
|
+
"""Write authentication tokens to the provided metadata."""
|
flwr/common/config.py
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
# ==============================================================================
|
|
15
15
|
"""Provide functions for managing global Flower config."""
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
import os
|
|
18
19
|
import re
|
|
19
20
|
from pathlib import Path
|
|
@@ -27,6 +28,7 @@ from flwr.common.constant import (
|
|
|
27
28
|
APP_DIR,
|
|
28
29
|
FAB_CONFIG_FILE,
|
|
29
30
|
FAB_HASH_TRUNCATION,
|
|
31
|
+
FLWR_DIR,
|
|
30
32
|
FLWR_HOME,
|
|
31
33
|
)
|
|
32
34
|
from flwr.common.typing import Run, UserConfig, UserConfigValue
|
|
@@ -38,7 +40,7 @@ def get_flwr_dir(provided_path: Optional[str] = None) -> Path:
|
|
|
38
40
|
return Path(
|
|
39
41
|
os.getenv(
|
|
40
42
|
FLWR_HOME,
|
|
41
|
-
Path(f"{os.getenv('XDG_DATA_HOME', os.getenv('HOME'))}") /
|
|
43
|
+
Path(f"{os.getenv('XDG_DATA_HOME', os.getenv('HOME'))}") / FLWR_DIR,
|
|
42
44
|
)
|
|
43
45
|
)
|
|
44
46
|
return Path(provided_path).absolute()
|
flwr/common/constant.py
CHANGED
|
@@ -80,7 +80,8 @@ FAB_ALLOWED_EXTENSIONS = {".py", ".toml", ".md"}
|
|
|
80
80
|
FAB_CONFIG_FILE = "pyproject.toml"
|
|
81
81
|
FAB_DATE = (2024, 10, 1, 0, 0, 0)
|
|
82
82
|
FAB_HASH_TRUNCATION = 8
|
|
83
|
-
|
|
83
|
+
FLWR_DIR = ".flwr" # The default Flower directory: ~/.flwr/
|
|
84
|
+
FLWR_HOME = "FLWR_HOME" # If set, override the default Flower directory
|
|
84
85
|
|
|
85
86
|
# Constants entries in Node config for Simulation
|
|
86
87
|
PARTITION_ID_KEY = "partition-id"
|
|
@@ -110,6 +111,10 @@ LOG_UPLOAD_INTERVAL = 0.2 # Minimum interval between two log uploads
|
|
|
110
111
|
# Retry configurations
|
|
111
112
|
MAX_RETRY_DELAY = 20 # Maximum delay duration between two consecutive retries.
|
|
112
113
|
|
|
114
|
+
# Constants for user authentication
|
|
115
|
+
CREDENTIALS_DIR = ".credentials"
|
|
116
|
+
AUTH_TYPE = "auth_type"
|
|
117
|
+
|
|
113
118
|
|
|
114
119
|
class MessageType:
|
|
115
120
|
"""Message type."""
|
flwr/common/logger.py
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
# ==============================================================================
|
|
15
15
|
"""Flower Logger."""
|
|
16
16
|
|
|
17
|
+
|
|
18
|
+
import json as _json
|
|
17
19
|
import logging
|
|
18
20
|
import re
|
|
19
21
|
import sys
|
|
@@ -26,6 +28,8 @@ from queue import Empty, Queue
|
|
|
26
28
|
from typing import TYPE_CHECKING, Any, Optional, TextIO, Union
|
|
27
29
|
|
|
28
30
|
import grpc
|
|
31
|
+
import typer
|
|
32
|
+
from rich.console import Console
|
|
29
33
|
|
|
30
34
|
from flwr.proto.log_pb2 import PushLogsRequest # pylint: disable=E0611
|
|
31
35
|
from flwr.proto.node_pb2 import Node # pylint: disable=E0611
|
|
@@ -376,7 +380,7 @@ def stop_log_uploader(
|
|
|
376
380
|
log_uploader.join()
|
|
377
381
|
|
|
378
382
|
|
|
379
|
-
def
|
|
383
|
+
def _remove_emojis(text: str) -> str:
|
|
380
384
|
"""Remove emojis from the provided text."""
|
|
381
385
|
emoji_pattern = re.compile(
|
|
382
386
|
"["
|
|
@@ -390,3 +394,15 @@ def remove_emojis(text: str) -> str:
|
|
|
390
394
|
flags=re.UNICODE,
|
|
391
395
|
)
|
|
392
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/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,18 @@ 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
|
+
from flwr.proto.simulationio_pb2_grpc import SimulationIoStub
|
|
34
|
+
|
|
25
35
|
|
|
26
36
|
def exponential(
|
|
27
37
|
base_delay: float = 1,
|
|
@@ -303,3 +313,70 @@ class RetryInvoker:
|
|
|
303
313
|
# Trigger success event
|
|
304
314
|
try_call_event_handler(self.on_success)
|
|
305
315
|
return ret
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def _make_simple_grpc_retry_invoker() -> RetryInvoker:
|
|
319
|
+
"""Create a simple gRPC retry invoker."""
|
|
320
|
+
|
|
321
|
+
def _on_sucess(retry_state: RetryState) -> None:
|
|
322
|
+
if retry_state.tries > 1:
|
|
323
|
+
log(
|
|
324
|
+
INFO,
|
|
325
|
+
"Connection successful after %.2f seconds and %s tries.",
|
|
326
|
+
retry_state.elapsed_time,
|
|
327
|
+
retry_state.tries,
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
def _on_backoff(retry_state: RetryState) -> None:
|
|
331
|
+
if retry_state.tries == 1:
|
|
332
|
+
log(WARN, "Connection attempt failed, retrying...")
|
|
333
|
+
else:
|
|
334
|
+
log(
|
|
335
|
+
WARN,
|
|
336
|
+
"Connection attempt failed, retrying in %.2f seconds",
|
|
337
|
+
retry_state.actual_wait,
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
def _on_giveup(retry_state: RetryState) -> None:
|
|
341
|
+
if retry_state.tries > 1:
|
|
342
|
+
log(
|
|
343
|
+
WARN,
|
|
344
|
+
"Giving up reconnection after %.2f seconds and %s tries.",
|
|
345
|
+
retry_state.elapsed_time,
|
|
346
|
+
retry_state.tries,
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
def _should_giveup_fn(e: Exception) -> bool:
|
|
350
|
+
if e.code() == grpc.StatusCode.PERMISSION_DENIED: # type: ignore
|
|
351
|
+
raise RunNotRunningException
|
|
352
|
+
if e.code() == grpc.StatusCode.UNAVAILABLE: # type: ignore
|
|
353
|
+
return False
|
|
354
|
+
return True
|
|
355
|
+
|
|
356
|
+
return RetryInvoker(
|
|
357
|
+
wait_gen_factory=lambda: exponential(max_delay=MAX_RETRY_DELAY),
|
|
358
|
+
recoverable_exceptions=grpc.RpcError,
|
|
359
|
+
max_tries=None,
|
|
360
|
+
max_time=None,
|
|
361
|
+
on_success=_on_sucess,
|
|
362
|
+
on_backoff=_on_backoff,
|
|
363
|
+
on_giveup=_on_giveup,
|
|
364
|
+
should_giveup=_should_giveup_fn,
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def _wrap_stub(
|
|
369
|
+
stub: Union[ServerAppIoStub, ClientAppIoStub, SimulationIoStub],
|
|
370
|
+
retry_invoker: RetryInvoker,
|
|
371
|
+
) -> None:
|
|
372
|
+
"""Wrap a gRPC stub with a retry invoker."""
|
|
373
|
+
|
|
374
|
+
def make_lambda(original_method: Any) -> Any:
|
|
375
|
+
return lambda *args, **kwargs: retry_invoker.invoke(
|
|
376
|
+
original_method, *args, **kwargs
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
for method_name in vars(stub):
|
|
380
|
+
method = getattr(stub, method_name)
|
|
381
|
+
if callable(method):
|
|
382
|
+
setattr(stub, method_name, make_lambda(method))
|
|
@@ -93,8 +93,8 @@ def pseudo_rand_gen(
|
|
|
93
93
|
output = []
|
|
94
94
|
for dimension in dimensions_list:
|
|
95
95
|
if len(dimension) == 0:
|
|
96
|
-
arr = np.array(gen.randint(0, num_range - 1), dtype=
|
|
96
|
+
arr = np.array(gen.randint(0, num_range - 1), dtype=np.int64)
|
|
97
97
|
else:
|
|
98
|
-
arr = gen.randint(0, num_range - 1, dimension)
|
|
98
|
+
arr = gen.randint(0, num_range - 1, dimension, dtype=np.int64)
|
|
99
99
|
output.append(arr)
|
|
100
100
|
return output
|
flwr/common/telemetry.py
CHANGED
|
@@ -27,6 +27,7 @@ from enum import Enum, auto
|
|
|
27
27
|
from pathlib import Path
|
|
28
28
|
from typing import Any, Optional, Union, cast
|
|
29
29
|
|
|
30
|
+
from flwr.common.constant import FLWR_DIR
|
|
30
31
|
from flwr.common.version import package_name, package_version
|
|
31
32
|
|
|
32
33
|
FLWR_TELEMETRY_ENABLED = os.getenv("FLWR_TELEMETRY_ENABLED", "1")
|
|
@@ -86,7 +87,7 @@ def _get_source_id() -> str:
|
|
|
86
87
|
# If the home directory can’t be resolved, RuntimeError is raised.
|
|
87
88
|
return source_id
|
|
88
89
|
|
|
89
|
-
flwr_dir = home.joinpath(
|
|
90
|
+
flwr_dir = home.joinpath(FLWR_DIR)
|
|
90
91
|
# Create .flwr directory if it does not exist yet.
|
|
91
92
|
try:
|
|
92
93
|
flwr_dir.mkdir(parents=True, exist_ok=True)
|
flwr/common/typing.py
CHANGED
|
@@ -254,3 +254,15 @@ class Fab:
|
|
|
254
254
|
|
|
255
255
|
hash_str: str
|
|
256
256
|
content: bytes
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class RunNotRunningException(BaseException):
|
|
260
|
+
"""Raised when a run is not running."""
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
class InvalidRunStatusException(BaseException):
|
|
264
|
+
"""Raised when an RPC is invalidated by the RunStatus."""
|
|
265
|
+
|
|
266
|
+
def __init__(self, message: str) -> None:
|
|
267
|
+
super().__init__(message)
|
|
268
|
+
self.message = message
|
flwr/common/version.py
CHANGED
flwr/proto/exec_pb2.py
CHANGED
|
@@ -18,7 +18,7 @@ from flwr.proto import recordset_pb2 as flwr_dot_proto_dot_recordset__pb2
|
|
|
18
18
|
from flwr.proto import run_pb2 as flwr_dot_proto_dot_run__pb2
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x66lwr/proto/exec.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x1a\x66lwr/proto/transport.proto\x1a\x1a\x66lwr/proto/recordset.proto\x1a\x14\x66lwr/proto/run.proto\"\xfb\x01\n\x0fStartRunRequest\x12\x1c\n\x03\x66\x61\x62\x18\x01 \x01(\x0b\x32\x0f.flwr.proto.Fab\x12H\n\x0foverride_config\x18\x02 \x03(\x0b\x32/.flwr.proto.StartRunRequest.OverrideConfigEntry\x12\x35\n\x12\x66\x65\x64\x65ration_options\x18\x03 \x01(\x0b\x32\x19.flwr.proto.ConfigsRecord\x1aI\n\x13OverrideConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\"2\n\x10StartRunResponse\x12\x13\n\x06run_id\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\t\n\x07_run_id\"<\n\x11StreamLogsRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x17\n\x0f\x61\x66ter_timestamp\x18\x02 \x01(\x01\"B\n\x12StreamLogsResponse\x12\x12\n\nlog_output\x18\x01 \x01(\t\x12\x18\n\x10latest_timestamp\x18\x02 \x01(\x01\"1\n\x0fListRunsRequest\x12\x13\n\x06run_id\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\t\n\x07_run_id\"\x9d\x01\n\x10ListRunsResponse\x12;\n\x08run_dict\x18\x01 \x03(\x0b\x32).flwr.proto.ListRunsResponse.RunDictEntry\x12\x0b\n\x03now\x18\x02 \x01(\t\x1a?\n\x0cRunDictEntry\x12\x0b\n\x03key\x18\x01 \x01(\x04\x12\x1e\n\x05value\x18\x02 \x01(\x0b\x32\x0f.flwr.proto.Run:\x02\x38\x01\x32\
|
|
21
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x66lwr/proto/exec.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x1a\x66lwr/proto/transport.proto\x1a\x1a\x66lwr/proto/recordset.proto\x1a\x14\x66lwr/proto/run.proto\"\xfb\x01\n\x0fStartRunRequest\x12\x1c\n\x03\x66\x61\x62\x18\x01 \x01(\x0b\x32\x0f.flwr.proto.Fab\x12H\n\x0foverride_config\x18\x02 \x03(\x0b\x32/.flwr.proto.StartRunRequest.OverrideConfigEntry\x12\x35\n\x12\x66\x65\x64\x65ration_options\x18\x03 \x01(\x0b\x32\x19.flwr.proto.ConfigsRecord\x1aI\n\x13OverrideConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\"2\n\x10StartRunResponse\x12\x13\n\x06run_id\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\t\n\x07_run_id\"<\n\x11StreamLogsRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x17\n\x0f\x61\x66ter_timestamp\x18\x02 \x01(\x01\"B\n\x12StreamLogsResponse\x12\x12\n\nlog_output\x18\x01 \x01(\t\x12\x18\n\x10latest_timestamp\x18\x02 \x01(\x01\"1\n\x0fListRunsRequest\x12\x13\n\x06run_id\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\t\n\x07_run_id\"\x9d\x01\n\x10ListRunsResponse\x12;\n\x08run_dict\x18\x01 \x03(\x0b\x32).flwr.proto.ListRunsResponse.RunDictEntry\x12\x0b\n\x03now\x18\x02 \x01(\t\x1a?\n\x0cRunDictEntry\x12\x0b\n\x03key\x18\x01 \x01(\x04\x12\x1e\n\x05value\x18\x02 \x01(\x0b\x32\x0f.flwr.proto.Run:\x02\x38\x01\"\x18\n\x16GetLoginDetailsRequest\"\x9c\x01\n\x17GetLoginDetailsResponse\x12L\n\rlogin_details\x18\x01 \x03(\x0b\x32\x35.flwr.proto.GetLoginDetailsResponse.LoginDetailsEntry\x1a\x33\n\x11LoginDetailsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x93\x01\n\x14GetAuthTokensRequest\x12G\n\x0c\x61uth_details\x18\x01 \x03(\x0b\x32\x31.flwr.proto.GetAuthTokensRequest.AuthDetailsEntry\x1a\x32\n\x10\x41uthDetailsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x92\x01\n\x15GetAuthTokensResponse\x12\x46\n\x0b\x61uth_tokens\x18\x01 \x03(\x0b\x32\x31.flwr.proto.GetAuthTokensResponse.AuthTokensEntry\x1a\x31\n\x0f\x41uthTokensEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\" \n\x0eStopRunRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\"\"\n\x0fStopRunResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x32\xe5\x03\n\x04\x45xec\x12G\n\x08StartRun\x12\x1b.flwr.proto.StartRunRequest\x1a\x1c.flwr.proto.StartRunResponse\"\x00\x12\x44\n\x07StopRun\x12\x1a.flwr.proto.StopRunRequest\x1a\x1b.flwr.proto.StopRunResponse\"\x00\x12O\n\nStreamLogs\x12\x1d.flwr.proto.StreamLogsRequest\x1a\x1e.flwr.proto.StreamLogsResponse\"\x00\x30\x01\x12G\n\x08ListRuns\x12\x1b.flwr.proto.ListRunsRequest\x1a\x1c.flwr.proto.ListRunsResponse\"\x00\x12\\\n\x0fGetLoginDetails\x12\".flwr.proto.GetLoginDetailsRequest\x1a#.flwr.proto.GetLoginDetailsResponse\"\x00\x12V\n\rGetAuthTokens\x12 .flwr.proto.GetAuthTokensRequest\x1a!.flwr.proto.GetAuthTokensResponse\"\x00\x62\x06proto3')
|
|
22
22
|
|
|
23
23
|
_globals = globals()
|
|
24
24
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -29,6 +29,12 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
|
29
29
|
_globals['_STARTRUNREQUEST_OVERRIDECONFIGENTRY']._serialized_options = b'8\001'
|
|
30
30
|
_globals['_LISTRUNSRESPONSE_RUNDICTENTRY']._options = None
|
|
31
31
|
_globals['_LISTRUNSRESPONSE_RUNDICTENTRY']._serialized_options = b'8\001'
|
|
32
|
+
_globals['_GETLOGINDETAILSRESPONSE_LOGINDETAILSENTRY']._options = None
|
|
33
|
+
_globals['_GETLOGINDETAILSRESPONSE_LOGINDETAILSENTRY']._serialized_options = b'8\001'
|
|
34
|
+
_globals['_GETAUTHTOKENSREQUEST_AUTHDETAILSENTRY']._options = None
|
|
35
|
+
_globals['_GETAUTHTOKENSREQUEST_AUTHDETAILSENTRY']._serialized_options = b'8\001'
|
|
36
|
+
_globals['_GETAUTHTOKENSRESPONSE_AUTHTOKENSENTRY']._options = None
|
|
37
|
+
_globals['_GETAUTHTOKENSRESPONSE_AUTHTOKENSENTRY']._serialized_options = b'8\001'
|
|
32
38
|
_globals['_STARTRUNREQUEST']._serialized_start=138
|
|
33
39
|
_globals['_STARTRUNREQUEST']._serialized_end=389
|
|
34
40
|
_globals['_STARTRUNREQUEST_OVERRIDECONFIGENTRY']._serialized_start=316
|
|
@@ -45,6 +51,24 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
|
45
51
|
_globals['_LISTRUNSRESPONSE']._serialized_end=782
|
|
46
52
|
_globals['_LISTRUNSRESPONSE_RUNDICTENTRY']._serialized_start=719
|
|
47
53
|
_globals['_LISTRUNSRESPONSE_RUNDICTENTRY']._serialized_end=782
|
|
48
|
-
_globals['
|
|
49
|
-
_globals['
|
|
54
|
+
_globals['_GETLOGINDETAILSREQUEST']._serialized_start=784
|
|
55
|
+
_globals['_GETLOGINDETAILSREQUEST']._serialized_end=808
|
|
56
|
+
_globals['_GETLOGINDETAILSRESPONSE']._serialized_start=811
|
|
57
|
+
_globals['_GETLOGINDETAILSRESPONSE']._serialized_end=967
|
|
58
|
+
_globals['_GETLOGINDETAILSRESPONSE_LOGINDETAILSENTRY']._serialized_start=916
|
|
59
|
+
_globals['_GETLOGINDETAILSRESPONSE_LOGINDETAILSENTRY']._serialized_end=967
|
|
60
|
+
_globals['_GETAUTHTOKENSREQUEST']._serialized_start=970
|
|
61
|
+
_globals['_GETAUTHTOKENSREQUEST']._serialized_end=1117
|
|
62
|
+
_globals['_GETAUTHTOKENSREQUEST_AUTHDETAILSENTRY']._serialized_start=1067
|
|
63
|
+
_globals['_GETAUTHTOKENSREQUEST_AUTHDETAILSENTRY']._serialized_end=1117
|
|
64
|
+
_globals['_GETAUTHTOKENSRESPONSE']._serialized_start=1120
|
|
65
|
+
_globals['_GETAUTHTOKENSRESPONSE']._serialized_end=1266
|
|
66
|
+
_globals['_GETAUTHTOKENSRESPONSE_AUTHTOKENSENTRY']._serialized_start=1217
|
|
67
|
+
_globals['_GETAUTHTOKENSRESPONSE_AUTHTOKENSENTRY']._serialized_end=1266
|
|
68
|
+
_globals['_STOPRUNREQUEST']._serialized_start=1268
|
|
69
|
+
_globals['_STOPRUNREQUEST']._serialized_end=1300
|
|
70
|
+
_globals['_STOPRUNRESPONSE']._serialized_start=1302
|
|
71
|
+
_globals['_STOPRUNRESPONSE']._serialized_end=1336
|
|
72
|
+
_globals['_EXEC']._serialized_start=1339
|
|
73
|
+
_globals['_EXEC']._serialized_end=1824
|
|
50
74
|
# @@protoc_insertion_point(module_scope)
|