flwr-nightly 1.11.0.dev20240805__py3-none-any.whl → 1.11.0.dev20240811__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/build.py +22 -20
- flwr/cli/new/new.py +18 -18
- flwr/cli/run/run.py +15 -12
- flwr/client/supernode/app.py +36 -28
- flwr/common/config.py +30 -0
- flwr/common/typing.py +8 -0
- flwr/proto/fab_pb2.py +6 -6
- flwr/proto/fab_pb2.pyi +8 -8
- flwr/server/run_serverapp.py +28 -46
- flwr/server/superlink/fleet/vce/backend/backend.py +1 -1
- flwr/server/superlink/fleet/vce/backend/raybackend.py +4 -35
- flwr/server/superlink/fleet/vce/vce_api.py +3 -3
- {flwr_nightly-1.11.0.dev20240805.dist-info → flwr_nightly-1.11.0.dev20240811.dist-info}/METADATA +2 -2
- {flwr_nightly-1.11.0.dev20240805.dist-info → flwr_nightly-1.11.0.dev20240811.dist-info}/RECORD +17 -17
- {flwr_nightly-1.11.0.dev20240805.dist-info → flwr_nightly-1.11.0.dev20240811.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.11.0.dev20240805.dist-info → flwr_nightly-1.11.0.dev20240811.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.11.0.dev20240805.dist-info → flwr_nightly-1.11.0.dev20240811.dist-info}/entry_points.txt +0 -0
flwr/cli/build.py
CHANGED
|
@@ -30,32 +30,34 @@ from .utils import get_sha256_hash, is_valid_project_name
|
|
|
30
30
|
|
|
31
31
|
# pylint: disable=too-many-locals
|
|
32
32
|
def build(
|
|
33
|
-
|
|
33
|
+
app: Annotated[
|
|
34
34
|
Optional[Path],
|
|
35
|
-
typer.Option(help="Path of the Flower
|
|
35
|
+
typer.Option(help="Path of the Flower App to bundle into a FAB"),
|
|
36
36
|
] = None,
|
|
37
37
|
) -> str:
|
|
38
|
-
"""Build a Flower
|
|
38
|
+
"""Build a Flower App into a Flower App Bundle (FAB).
|
|
39
39
|
|
|
40
|
-
You can run ``flwr build`` without any arguments to bundle the
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
You can run ``flwr build`` without any arguments to bundle the app located in the
|
|
41
|
+
current directory. Alternatively, you can you can specify a path using the ``--app``
|
|
42
|
+
option to bundle an app located at the provided path. For example:
|
|
43
|
+
|
|
44
|
+
``flwr build --app ./apps/flower-hello-world``.
|
|
43
45
|
"""
|
|
44
|
-
if
|
|
45
|
-
|
|
46
|
+
if app is None:
|
|
47
|
+
app = Path.cwd()
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
if not
|
|
49
|
+
app = app.resolve()
|
|
50
|
+
if not app.is_dir():
|
|
49
51
|
typer.secho(
|
|
50
|
-
f"❌ The path {
|
|
52
|
+
f"❌ The path {app} is not a valid path to a Flower app.",
|
|
51
53
|
fg=typer.colors.RED,
|
|
52
54
|
bold=True,
|
|
53
55
|
)
|
|
54
56
|
raise typer.Exit(code=1)
|
|
55
57
|
|
|
56
|
-
if not is_valid_project_name(
|
|
58
|
+
if not is_valid_project_name(app.name):
|
|
57
59
|
typer.secho(
|
|
58
|
-
f"❌ The project name {
|
|
60
|
+
f"❌ The project name {app.name} is invalid, "
|
|
59
61
|
"a valid project name must start with a letter or an underscore, "
|
|
60
62
|
"and can only contain letters, digits, and underscores.",
|
|
61
63
|
fg=typer.colors.RED,
|
|
@@ -63,7 +65,7 @@ def build(
|
|
|
63
65
|
)
|
|
64
66
|
raise typer.Exit(code=1)
|
|
65
67
|
|
|
66
|
-
conf, errors, warnings = load_and_validate(
|
|
68
|
+
conf, errors, warnings = load_and_validate(app / "pyproject.toml")
|
|
67
69
|
if conf is None:
|
|
68
70
|
typer.secho(
|
|
69
71
|
"Project configuration could not be loaded.\npyproject.toml is invalid:\n"
|
|
@@ -82,12 +84,12 @@ def build(
|
|
|
82
84
|
)
|
|
83
85
|
|
|
84
86
|
# Load .gitignore rules if present
|
|
85
|
-
ignore_spec = _load_gitignore(
|
|
87
|
+
ignore_spec = _load_gitignore(app)
|
|
86
88
|
|
|
87
89
|
# Set the name of the zip file
|
|
88
90
|
fab_filename = (
|
|
89
91
|
f"{conf['tool']['flwr']['app']['publisher']}"
|
|
90
|
-
f".{
|
|
92
|
+
f".{app.name}"
|
|
91
93
|
f".{conf['project']['version'].replace('.', '-')}.fab"
|
|
92
94
|
)
|
|
93
95
|
list_file_content = ""
|
|
@@ -108,7 +110,7 @@ def build(
|
|
|
108
110
|
fab_file.writestr("pyproject.toml", toml_contents)
|
|
109
111
|
|
|
110
112
|
# Continue with adding other files
|
|
111
|
-
for root, _, files in os.walk(
|
|
113
|
+
for root, _, files in os.walk(app, topdown=True):
|
|
112
114
|
files = [
|
|
113
115
|
f
|
|
114
116
|
for f in files
|
|
@@ -120,7 +122,7 @@ def build(
|
|
|
120
122
|
|
|
121
123
|
for file in files:
|
|
122
124
|
file_path = Path(root) / file
|
|
123
|
-
archive_path = file_path.relative_to(
|
|
125
|
+
archive_path = file_path.relative_to(app)
|
|
124
126
|
fab_file.write(file_path, archive_path)
|
|
125
127
|
|
|
126
128
|
# Calculate file info
|
|
@@ -138,9 +140,9 @@ def build(
|
|
|
138
140
|
return fab_filename
|
|
139
141
|
|
|
140
142
|
|
|
141
|
-
def _load_gitignore(
|
|
143
|
+
def _load_gitignore(app: Path) -> pathspec.PathSpec:
|
|
142
144
|
"""Load and parse .gitignore file, returning a pathspec."""
|
|
143
|
-
gitignore_path =
|
|
145
|
+
gitignore_path = app / ".gitignore"
|
|
144
146
|
patterns = ["__pycache__/"] # Default pattern
|
|
145
147
|
if gitignore_path.exists():
|
|
146
148
|
with open(gitignore_path, encoding="UTF-8") as file:
|
flwr/cli/new/new.py
CHANGED
|
@@ -34,13 +34,13 @@ from ..utils import (
|
|
|
34
34
|
class MlFramework(str, Enum):
|
|
35
35
|
"""Available frameworks."""
|
|
36
36
|
|
|
37
|
-
NUMPY = "NumPy"
|
|
38
37
|
PYTORCH = "PyTorch"
|
|
39
38
|
TENSORFLOW = "TensorFlow"
|
|
40
|
-
|
|
39
|
+
SKLEARN = "sklearn"
|
|
41
40
|
HUGGINGFACE = "HuggingFace"
|
|
41
|
+
JAX = "JAX"
|
|
42
42
|
MLX = "MLX"
|
|
43
|
-
|
|
43
|
+
NUMPY = "NumPy"
|
|
44
44
|
FLOWERTUNE = "FlowerTune"
|
|
45
45
|
|
|
46
46
|
|
|
@@ -92,9 +92,9 @@ def render_and_create(file_path: Path, template: str, context: Dict[str, str]) -
|
|
|
92
92
|
|
|
93
93
|
# pylint: disable=too-many-locals,too-many-branches,too-many-statements
|
|
94
94
|
def new(
|
|
95
|
-
|
|
95
|
+
app_name: Annotated[
|
|
96
96
|
Optional[str],
|
|
97
|
-
typer.Argument(
|
|
97
|
+
typer.Argument(help="The name of the Flower App"),
|
|
98
98
|
] = None,
|
|
99
99
|
framework: Annotated[
|
|
100
100
|
Optional[MlFramework],
|
|
@@ -105,26 +105,26 @@ def new(
|
|
|
105
105
|
typer.Option(case_sensitive=False, help="The Flower username of the author"),
|
|
106
106
|
] = None,
|
|
107
107
|
) -> None:
|
|
108
|
-
"""Create new Flower
|
|
109
|
-
if
|
|
110
|
-
|
|
111
|
-
if not is_valid_project_name(
|
|
112
|
-
|
|
108
|
+
"""Create new Flower App."""
|
|
109
|
+
if app_name is None:
|
|
110
|
+
app_name = prompt_text("Please provide the app name")
|
|
111
|
+
if not is_valid_project_name(app_name):
|
|
112
|
+
app_name = prompt_text(
|
|
113
113
|
"Please provide a name that only contains "
|
|
114
114
|
"characters in {'-', a-zA-Z', '0-9'}",
|
|
115
115
|
predicate=is_valid_project_name,
|
|
116
|
-
default=sanitize_project_name(
|
|
116
|
+
default=sanitize_project_name(app_name),
|
|
117
117
|
)
|
|
118
118
|
|
|
119
119
|
# Set project directory path
|
|
120
|
-
package_name = re.sub(r"[-_.]+", "-",
|
|
120
|
+
package_name = re.sub(r"[-_.]+", "-", app_name).lower()
|
|
121
121
|
import_name = package_name.replace("-", "_")
|
|
122
122
|
project_dir = Path.cwd() / package_name
|
|
123
123
|
|
|
124
124
|
if project_dir.exists():
|
|
125
125
|
if not typer.confirm(
|
|
126
126
|
typer.style(
|
|
127
|
-
f"\n💬 {
|
|
127
|
+
f"\n💬 {app_name} already exists, do you want to override it?",
|
|
128
128
|
fg=typer.colors.MAGENTA,
|
|
129
129
|
bold=True,
|
|
130
130
|
)
|
|
@@ -139,7 +139,7 @@ def new(
|
|
|
139
139
|
else:
|
|
140
140
|
framework_value = prompt_options(
|
|
141
141
|
"Please select ML framework by typing in the number",
|
|
142
|
-
|
|
142
|
+
[mlf.value for mlf in MlFramework],
|
|
143
143
|
)
|
|
144
144
|
selected_value = [
|
|
145
145
|
name
|
|
@@ -166,7 +166,7 @@ def new(
|
|
|
166
166
|
|
|
167
167
|
print(
|
|
168
168
|
typer.style(
|
|
169
|
-
f"\n🔨 Creating Flower
|
|
169
|
+
f"\n🔨 Creating Flower App {app_name}...",
|
|
170
170
|
fg=typer.colors.GREEN,
|
|
171
171
|
bold=True,
|
|
172
172
|
)
|
|
@@ -176,7 +176,7 @@ def new(
|
|
|
176
176
|
"framework_str": framework_str_upper,
|
|
177
177
|
"import_name": import_name.replace("-", "_"),
|
|
178
178
|
"package_name": package_name,
|
|
179
|
-
"project_name":
|
|
179
|
+
"project_name": app_name,
|
|
180
180
|
"username": username,
|
|
181
181
|
}
|
|
182
182
|
|
|
@@ -268,8 +268,8 @@ def new(
|
|
|
268
268
|
|
|
269
269
|
print(
|
|
270
270
|
typer.style(
|
|
271
|
-
"🎊
|
|
272
|
-
"Use the following command to run your
|
|
271
|
+
"🎊 Flower App creation successful.\n\n"
|
|
272
|
+
"Use the following command to run your Flower App:\n",
|
|
273
273
|
fg=typer.colors.GREEN,
|
|
274
274
|
bold=True,
|
|
275
275
|
)
|
flwr/cli/run/run.py
CHANGED
|
@@ -35,9 +35,9 @@ from flwr.proto.exec_pb2_grpc import ExecStub
|
|
|
35
35
|
|
|
36
36
|
# pylint: disable-next=too-many-locals
|
|
37
37
|
def run(
|
|
38
|
-
|
|
38
|
+
app: Annotated[
|
|
39
39
|
Path,
|
|
40
|
-
typer.Argument(help="Path of the Flower
|
|
40
|
+
typer.Argument(help="Path of the Flower App to run."),
|
|
41
41
|
] = Path("."),
|
|
42
42
|
federation: Annotated[
|
|
43
43
|
Optional[str],
|
|
@@ -55,10 +55,10 @@ def run(
|
|
|
55
55
|
),
|
|
56
56
|
] = None,
|
|
57
57
|
) -> None:
|
|
58
|
-
"""Run Flower
|
|
58
|
+
"""Run Flower App."""
|
|
59
59
|
typer.secho("Loading project configuration... ", fg=typer.colors.BLUE)
|
|
60
60
|
|
|
61
|
-
pyproject_path =
|
|
61
|
+
pyproject_path = app / "pyproject.toml" if app else None
|
|
62
62
|
config, errors, warnings = load_and_validate(path=pyproject_path)
|
|
63
63
|
|
|
64
64
|
if config is None:
|
|
@@ -109,14 +109,14 @@ def run(
|
|
|
109
109
|
raise typer.Exit(code=1)
|
|
110
110
|
|
|
111
111
|
if "address" in federation_config:
|
|
112
|
-
_run_with_superexec(
|
|
112
|
+
_run_with_superexec(app, federation_config, config_overrides)
|
|
113
113
|
else:
|
|
114
|
-
_run_without_superexec(
|
|
114
|
+
_run_without_superexec(app, federation_config, config_overrides, federation)
|
|
115
115
|
|
|
116
116
|
|
|
117
117
|
def _run_with_superexec(
|
|
118
|
+
app: Optional[Path],
|
|
118
119
|
federation_config: Dict[str, Any],
|
|
119
|
-
app_dir: Optional[Path],
|
|
120
120
|
config_overrides: Optional[List[str]],
|
|
121
121
|
) -> None:
|
|
122
122
|
|
|
@@ -162,10 +162,10 @@ def _run_with_superexec(
|
|
|
162
162
|
channel.subscribe(on_channel_state_change)
|
|
163
163
|
stub = ExecStub(channel)
|
|
164
164
|
|
|
165
|
-
fab_path = build(
|
|
165
|
+
fab_path = Path(build(app))
|
|
166
166
|
|
|
167
167
|
req = StartRunRequest(
|
|
168
|
-
fab_file=
|
|
168
|
+
fab_file=fab_path.read_bytes(),
|
|
169
169
|
override_config=user_config_to_proto(
|
|
170
170
|
parse_config_args(config_overrides, separator=",")
|
|
171
171
|
),
|
|
@@ -174,14 +174,17 @@ def _run_with_superexec(
|
|
|
174
174
|
),
|
|
175
175
|
)
|
|
176
176
|
res = stub.StartRun(req)
|
|
177
|
+
|
|
178
|
+
# Delete FAB file once it has been sent to the SuperExec
|
|
179
|
+
fab_path.unlink()
|
|
177
180
|
typer.secho(f"🎊 Successfully started run {res.run_id}", fg=typer.colors.GREEN)
|
|
178
181
|
|
|
179
182
|
|
|
180
183
|
def _run_without_superexec(
|
|
181
|
-
|
|
184
|
+
app: Optional[Path],
|
|
182
185
|
federation_config: Dict[str, Any],
|
|
183
|
-
federation: str,
|
|
184
186
|
config_overrides: Optional[List[str]],
|
|
187
|
+
federation: str,
|
|
185
188
|
) -> None:
|
|
186
189
|
try:
|
|
187
190
|
num_supernodes = federation_config["options"]["num-supernodes"]
|
|
@@ -200,7 +203,7 @@ def _run_without_superexec(
|
|
|
200
203
|
command = [
|
|
201
204
|
"flower-simulation",
|
|
202
205
|
"--app",
|
|
203
|
-
f"{
|
|
206
|
+
f"{app}",
|
|
204
207
|
"--num-supernodes",
|
|
205
208
|
f"{num_supernodes}",
|
|
206
209
|
]
|
flwr/client/supernode/app.py
CHANGED
|
@@ -31,6 +31,7 @@ from flwr.client.client_app import ClientApp, LoadClientAppError
|
|
|
31
31
|
from flwr.common import EventType, event
|
|
32
32
|
from flwr.common.config import (
|
|
33
33
|
get_flwr_dir,
|
|
34
|
+
get_metadata_from_config,
|
|
34
35
|
get_project_config,
|
|
35
36
|
get_project_dir,
|
|
36
37
|
parse_config_args,
|
|
@@ -61,8 +62,8 @@ def run_supernode() -> None:
|
|
|
61
62
|
|
|
62
63
|
root_certificates = _get_certificates(args)
|
|
63
64
|
load_fn = _get_load_client_app_fn(
|
|
64
|
-
default_app_ref=
|
|
65
|
-
|
|
65
|
+
default_app_ref="",
|
|
66
|
+
app_path=args.app,
|
|
66
67
|
flwr_dir=args.flwr_dir,
|
|
67
68
|
multi_app=True,
|
|
68
69
|
)
|
|
@@ -100,7 +101,7 @@ def run_client_app() -> None:
|
|
|
100
101
|
root_certificates = _get_certificates(args)
|
|
101
102
|
load_fn = _get_load_client_app_fn(
|
|
102
103
|
default_app_ref=getattr(args, "client-app"),
|
|
103
|
-
|
|
104
|
+
app_path=args.dir,
|
|
104
105
|
multi_app=False,
|
|
105
106
|
)
|
|
106
107
|
authentication_keys = _try_setup_client_authentication(args)
|
|
@@ -176,7 +177,7 @@ def _get_certificates(args: argparse.Namespace) -> Optional[bytes]:
|
|
|
176
177
|
|
|
177
178
|
def _get_load_client_app_fn(
|
|
178
179
|
default_app_ref: str,
|
|
179
|
-
|
|
180
|
+
app_path: Optional[str],
|
|
180
181
|
multi_app: bool,
|
|
181
182
|
flwr_dir: Optional[str] = None,
|
|
182
183
|
) -> Callable[[str, str], ClientApp]:
|
|
@@ -196,34 +197,39 @@ def _get_load_client_app_fn(
|
|
|
196
197
|
default_app_ref,
|
|
197
198
|
)
|
|
198
199
|
|
|
199
|
-
valid, error_msg = validate(default_app_ref, project_dir=
|
|
200
|
+
valid, error_msg = validate(default_app_ref, project_dir=app_path)
|
|
200
201
|
if not valid and error_msg:
|
|
201
202
|
raise LoadClientAppError(error_msg) from None
|
|
202
203
|
|
|
203
204
|
def _load(fab_id: str, fab_version: str) -> ClientApp:
|
|
204
|
-
|
|
205
|
+
runtime_app_dir = Path(app_path if app_path else "").absolute()
|
|
205
206
|
# If multi-app feature is disabled
|
|
206
207
|
if not multi_app:
|
|
207
208
|
# Set app reference
|
|
208
209
|
client_app_ref = default_app_ref
|
|
209
|
-
# If multi-app feature is enabled but
|
|
210
|
-
elif
|
|
211
|
-
|
|
210
|
+
# If multi-app feature is enabled but app directory is provided
|
|
211
|
+
elif app_path is not None:
|
|
212
|
+
config = get_project_config(runtime_app_dir)
|
|
213
|
+
this_fab_version, this_fab_id = get_metadata_from_config(config)
|
|
214
|
+
|
|
215
|
+
if this_fab_version != fab_version or this_fab_id != fab_id:
|
|
212
216
|
raise LoadClientAppError(
|
|
213
|
-
"
|
|
217
|
+
f"FAB ID or version mismatch: Expected FAB ID '{this_fab_id}' and "
|
|
218
|
+
f"FAB version '{this_fab_version}', but received FAB ID '{fab_id}' "
|
|
219
|
+
f"and FAB version '{fab_version}'.",
|
|
214
220
|
) from None
|
|
215
221
|
|
|
216
|
-
log(WARN, "FAB ID is not provided; the default ClientApp will be loaded.")
|
|
222
|
+
# log(WARN, "FAB ID is not provided; the default ClientApp will be loaded.")
|
|
217
223
|
|
|
218
224
|
# Set app reference
|
|
219
|
-
client_app_ref =
|
|
225
|
+
client_app_ref = config["tool"]["flwr"]["app"]["components"]["clientapp"]
|
|
220
226
|
# If multi-app feature is enabled
|
|
221
227
|
else:
|
|
222
228
|
try:
|
|
223
|
-
|
|
229
|
+
runtime_app_dir = get_project_dir(
|
|
224
230
|
fab_id, fab_version, get_flwr_dir(flwr_dir)
|
|
225
231
|
)
|
|
226
|
-
config = get_project_config(
|
|
232
|
+
config = get_project_config(runtime_app_dir)
|
|
227
233
|
except Exception as e:
|
|
228
234
|
raise LoadClientAppError("Failed to load ClientApp") from e
|
|
229
235
|
|
|
@@ -236,7 +242,7 @@ def _get_load_client_app_fn(
|
|
|
236
242
|
"Loading ClientApp `%s`",
|
|
237
243
|
client_app_ref,
|
|
238
244
|
)
|
|
239
|
-
client_app = load_app(client_app_ref, LoadClientAppError,
|
|
245
|
+
client_app = load_app(client_app_ref, LoadClientAppError, runtime_app_dir)
|
|
240
246
|
|
|
241
247
|
if not isinstance(client_app, ClientApp):
|
|
242
248
|
raise LoadClientAppError(
|
|
@@ -255,13 +261,15 @@ def _parse_args_run_supernode() -> argparse.ArgumentParser:
|
|
|
255
261
|
)
|
|
256
262
|
|
|
257
263
|
parser.add_argument(
|
|
258
|
-
"
|
|
264
|
+
"app",
|
|
259
265
|
nargs="?",
|
|
260
|
-
default=
|
|
261
|
-
help="
|
|
262
|
-
"
|
|
263
|
-
"
|
|
264
|
-
"
|
|
266
|
+
default=None,
|
|
267
|
+
help="Specify the path of the Flower App to load and run the `ClientApp`. "
|
|
268
|
+
"The `pyproject.toml` file must be located in the root of this path. "
|
|
269
|
+
"When this argument is provided, the SuperNode will exclusively respond to "
|
|
270
|
+
"messages from the corresponding `ServerApp` by matching the FAB ID and FAB "
|
|
271
|
+
"version. An error will be raised if a message is received from any other "
|
|
272
|
+
"`ServerApp`.",
|
|
265
273
|
)
|
|
266
274
|
_parse_args_common(parser)
|
|
267
275
|
parser.add_argument(
|
|
@@ -290,6 +298,13 @@ def _parse_args_run_client_app() -> argparse.ArgumentParser:
|
|
|
290
298
|
help="For example: `client:app` or `project.package.module:wrapper.app`",
|
|
291
299
|
)
|
|
292
300
|
_parse_args_common(parser=parser)
|
|
301
|
+
parser.add_argument(
|
|
302
|
+
"--dir",
|
|
303
|
+
default="",
|
|
304
|
+
help="Add specified directory to the PYTHONPATH and load Flower "
|
|
305
|
+
"app from there."
|
|
306
|
+
" Default: current working directory.",
|
|
307
|
+
)
|
|
293
308
|
|
|
294
309
|
return parser
|
|
295
310
|
|
|
@@ -357,13 +372,6 @@ def _parse_args_common(parser: argparse.ArgumentParser) -> None:
|
|
|
357
372
|
"connect to the SuperLink in case of connection error. By default, it"
|
|
358
373
|
"is set to None, meaning there is no limit to the total time.",
|
|
359
374
|
)
|
|
360
|
-
parser.add_argument(
|
|
361
|
-
"--dir",
|
|
362
|
-
default="",
|
|
363
|
-
help="Add specified directory to the PYTHONPATH and load Flower "
|
|
364
|
-
"app from there."
|
|
365
|
-
" Default: current working directory.",
|
|
366
|
-
)
|
|
367
375
|
parser.add_argument(
|
|
368
376
|
"--auth-supernode-private-key",
|
|
369
377
|
type=str,
|
flwr/common/config.py
CHANGED
|
@@ -105,11 +105,16 @@ def get_fused_config(run: Run, flwr_dir: Optional[Path]) -> UserConfig:
|
|
|
105
105
|
Get the config using the fab_id and the fab_version, remove the nesting by adding
|
|
106
106
|
the nested keys as prefixes separated by dots, and fuse it with the override dict.
|
|
107
107
|
"""
|
|
108
|
+
# Return empty dict if fab_id or fab_version is empty
|
|
108
109
|
if not run.fab_id or not run.fab_version:
|
|
109
110
|
return {}
|
|
110
111
|
|
|
111
112
|
project_dir = get_project_dir(run.fab_id, run.fab_version, flwr_dir)
|
|
112
113
|
|
|
114
|
+
# Return empty dict if project directory does not exist
|
|
115
|
+
if not project_dir.is_dir():
|
|
116
|
+
return {}
|
|
117
|
+
|
|
113
118
|
return get_fused_config_from_dir(project_dir, run.override_config)
|
|
114
119
|
|
|
115
120
|
|
|
@@ -136,6 +141,23 @@ def flatten_dict(
|
|
|
136
141
|
return dict(items)
|
|
137
142
|
|
|
138
143
|
|
|
144
|
+
def unflatten_dict(flat_dict: Dict[str, Any]) -> Dict[str, Any]:
|
|
145
|
+
"""Unflatten a dict with keys containing separators into a nested dict."""
|
|
146
|
+
unflattened_dict: Dict[str, Any] = {}
|
|
147
|
+
separator: str = "."
|
|
148
|
+
|
|
149
|
+
for key, value in flat_dict.items():
|
|
150
|
+
parts = key.split(separator)
|
|
151
|
+
d = unflattened_dict
|
|
152
|
+
for part in parts[:-1]:
|
|
153
|
+
if part not in d:
|
|
154
|
+
d[part] = {}
|
|
155
|
+
d = d[part]
|
|
156
|
+
d[parts[-1]] = value
|
|
157
|
+
|
|
158
|
+
return unflattened_dict
|
|
159
|
+
|
|
160
|
+
|
|
139
161
|
def parse_config_args(
|
|
140
162
|
config: Optional[List[str]],
|
|
141
163
|
separator: str = ",",
|
|
@@ -161,3 +183,11 @@ def parse_config_args(
|
|
|
161
183
|
overrides.update(tomli.loads(toml_str))
|
|
162
184
|
|
|
163
185
|
return overrides
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def get_metadata_from_config(config: Dict[str, Any]) -> Tuple[str, str]:
|
|
189
|
+
"""Extract `fab_version` and `fab_id` from a project config."""
|
|
190
|
+
return (
|
|
191
|
+
config["project"]["version"],
|
|
192
|
+
f"{config['tool']['flwr']['app']['publisher']}/{config['project']['name']}",
|
|
193
|
+
)
|
flwr/common/typing.py
CHANGED
flwr/proto/fab_pb2.py
CHANGED
|
@@ -14,7 +14,7 @@ _sym_db = _symbol_database.Default()
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14\x66lwr/proto/fab.proto\x12\nflwr.proto\"
|
|
17
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14\x66lwr/proto/fab.proto\x12\nflwr.proto\"(\n\x03\x46\x61\x62\x12\x10\n\x08hash_str\x18\x01 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x02 \x01(\x0c\"!\n\rGetFabRequest\x12\x10\n\x08hash_str\x18\x01 \x01(\t\".\n\x0eGetFabResponse\x12\x1c\n\x03\x66\x61\x62\x18\x01 \x01(\x0b\x32\x0f.flwr.proto.Fabb\x06proto3')
|
|
18
18
|
|
|
19
19
|
_globals = globals()
|
|
20
20
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -22,9 +22,9 @@ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flwr.proto.fab_pb2', _globa
|
|
|
22
22
|
if _descriptor._USE_C_DESCRIPTORS == False:
|
|
23
23
|
DESCRIPTOR._options = None
|
|
24
24
|
_globals['_FAB']._serialized_start=36
|
|
25
|
-
_globals['_FAB']._serialized_end=
|
|
26
|
-
_globals['_GETFABREQUEST']._serialized_start=
|
|
27
|
-
_globals['_GETFABREQUEST']._serialized_end=
|
|
28
|
-
_globals['_GETFABRESPONSE']._serialized_start=
|
|
29
|
-
_globals['_GETFABRESPONSE']._serialized_end=
|
|
25
|
+
_globals['_FAB']._serialized_end=76
|
|
26
|
+
_globals['_GETFABREQUEST']._serialized_start=78
|
|
27
|
+
_globals['_GETFABREQUEST']._serialized_end=111
|
|
28
|
+
_globals['_GETFABRESPONSE']._serialized_start=113
|
|
29
|
+
_globals['_GETFABRESPONSE']._serialized_end=159
|
|
30
30
|
# @@protoc_insertion_point(module_scope)
|
flwr/proto/fab_pb2.pyi
CHANGED
|
@@ -12,9 +12,9 @@ DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
|
|
|
12
12
|
|
|
13
13
|
class Fab(google.protobuf.message.Message):
|
|
14
14
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
15
|
-
|
|
15
|
+
HASH_STR_FIELD_NUMBER: builtins.int
|
|
16
16
|
CONTENT_FIELD_NUMBER: builtins.int
|
|
17
|
-
|
|
17
|
+
hash_str: typing.Text
|
|
18
18
|
"""This field is the hash of the data field. It is used to identify the data.
|
|
19
19
|
The hash is calculated using the SHA-256 algorithm and is represented as a
|
|
20
20
|
hex string (sha256hex).
|
|
@@ -25,21 +25,21 @@ class Fab(google.protobuf.message.Message):
|
|
|
25
25
|
|
|
26
26
|
def __init__(self,
|
|
27
27
|
*,
|
|
28
|
-
|
|
28
|
+
hash_str: typing.Text = ...,
|
|
29
29
|
content: builtins.bytes = ...,
|
|
30
30
|
) -> None: ...
|
|
31
|
-
def ClearField(self, field_name: typing_extensions.Literal["content",b"content","
|
|
31
|
+
def ClearField(self, field_name: typing_extensions.Literal["content",b"content","hash_str",b"hash_str"]) -> None: ...
|
|
32
32
|
global___Fab = Fab
|
|
33
33
|
|
|
34
34
|
class GetFabRequest(google.protobuf.message.Message):
|
|
35
35
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
HASH_STR_FIELD_NUMBER: builtins.int
|
|
37
|
+
hash_str: typing.Text
|
|
38
38
|
def __init__(self,
|
|
39
39
|
*,
|
|
40
|
-
|
|
40
|
+
hash_str: typing.Text = ...,
|
|
41
41
|
) -> None: ...
|
|
42
|
-
def ClearField(self, field_name: typing_extensions.Literal["
|
|
42
|
+
def ClearField(self, field_name: typing_extensions.Literal["hash_str",b"hash_str"]) -> None: ...
|
|
43
43
|
global___GetFabRequest = GetFabRequest
|
|
44
44
|
|
|
45
45
|
class GetFabResponse(google.protobuf.message.Message):
|
flwr/server/run_serverapp.py
CHANGED
|
@@ -24,7 +24,8 @@ from typing import Optional
|
|
|
24
24
|
from flwr.common import Context, EventType, RecordSet, event
|
|
25
25
|
from flwr.common.config import (
|
|
26
26
|
get_flwr_dir,
|
|
27
|
-
|
|
27
|
+
get_fused_config_from_dir,
|
|
28
|
+
get_metadata_from_config,
|
|
28
29
|
get_project_config,
|
|
29
30
|
get_project_dir,
|
|
30
31
|
)
|
|
@@ -146,51 +147,50 @@ def run_server_app() -> None: # pylint: disable=too-many-branches
|
|
|
146
147
|
cert_path,
|
|
147
148
|
)
|
|
148
149
|
|
|
149
|
-
|
|
150
|
-
if not (
|
|
150
|
+
app_path: Optional[str] = args.app
|
|
151
|
+
if not (app_path is None) ^ (args.run_id is None):
|
|
151
152
|
raise sys.exit(
|
|
152
|
-
"Please provide either a
|
|
153
|
+
"Please provide either a Flower App path or a Run ID, but not both. "
|
|
153
154
|
"For more details, use: ``flower-server-app -h``"
|
|
154
155
|
)
|
|
155
156
|
|
|
156
157
|
# Initialize GrpcDriver
|
|
157
|
-
if
|
|
158
|
-
# User provided `--run-id`, but not `
|
|
158
|
+
if app_path is None:
|
|
159
|
+
# User provided `--run-id`, but not `app_dir`
|
|
159
160
|
driver = GrpcDriver(
|
|
160
161
|
run_id=args.run_id,
|
|
161
162
|
driver_service_address=args.superlink,
|
|
162
163
|
root_certificates=root_certificates,
|
|
163
164
|
)
|
|
165
|
+
flwr_dir = get_flwr_dir(args.flwr_dir)
|
|
166
|
+
run_ = driver.run
|
|
167
|
+
app_path = str(get_project_dir(run_.fab_id, run_.fab_version, flwr_dir))
|
|
168
|
+
config = get_project_config(app_path)
|
|
164
169
|
else:
|
|
165
|
-
# User provided `
|
|
170
|
+
# User provided `app_dir`, but not `--run-id`
|
|
166
171
|
# Create run if run_id is not provided
|
|
167
172
|
driver = GrpcDriver(
|
|
168
173
|
run_id=0, # Will be overwritten
|
|
169
174
|
driver_service_address=args.superlink,
|
|
170
175
|
root_certificates=root_certificates,
|
|
171
176
|
)
|
|
177
|
+
# Load config from the project directory
|
|
178
|
+
config = get_project_config(app_path)
|
|
179
|
+
fab_version, fab_id = get_metadata_from_config(config)
|
|
180
|
+
|
|
172
181
|
# Create run
|
|
173
|
-
req = CreateRunRequest(fab_id=
|
|
182
|
+
req = CreateRunRequest(fab_id=fab_id, fab_version=fab_version)
|
|
174
183
|
res: CreateRunResponse = driver._stub.CreateRun(req) # pylint: disable=W0212
|
|
175
184
|
# Overwrite driver._run_id
|
|
176
185
|
driver._run_id = res.run_id # pylint: disable=W0212
|
|
177
186
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
flwr_dir = get_flwr_dir(args.flwr_dir)
|
|
184
|
-
run_ = driver.run
|
|
185
|
-
server_app_dir = str(get_project_dir(run_.fab_id, run_.fab_version, flwr_dir))
|
|
186
|
-
config = get_project_config(server_app_dir)
|
|
187
|
-
server_app_attr = config["tool"]["flwr"]["app"]["components"]["serverapp"]
|
|
188
|
-
server_app_run_config = get_fused_config(run_, flwr_dir)
|
|
189
|
-
else:
|
|
190
|
-
# User provided `server-app`, but not `--run-id`
|
|
191
|
-
server_app_dir = str(Path(args.dir).absolute())
|
|
187
|
+
# Obtain server app reference and the run config
|
|
188
|
+
server_app_attr = config["tool"]["flwr"]["app"]["components"]["serverapp"]
|
|
189
|
+
server_app_run_config = get_fused_config_from_dir(
|
|
190
|
+
Path(app_path), driver.run.override_config
|
|
191
|
+
)
|
|
192
192
|
|
|
193
|
-
log(DEBUG, "Flower will load ServerApp `%s` in %s", server_app_attr,
|
|
193
|
+
log(DEBUG, "Flower will load ServerApp `%s` in %s", server_app_attr, app_path)
|
|
194
194
|
|
|
195
195
|
log(
|
|
196
196
|
DEBUG,
|
|
@@ -201,7 +201,7 @@ def run_server_app() -> None: # pylint: disable=too-many-branches
|
|
|
201
201
|
# Run the ServerApp with the Driver
|
|
202
202
|
run(
|
|
203
203
|
driver=driver,
|
|
204
|
-
server_app_dir=
|
|
204
|
+
server_app_dir=app_path,
|
|
205
205
|
server_app_run_config=server_app_run_config,
|
|
206
206
|
server_app_attr=server_app_attr,
|
|
207
207
|
)
|
|
@@ -219,15 +219,16 @@ def _parse_args_run_server_app() -> argparse.ArgumentParser:
|
|
|
219
219
|
)
|
|
220
220
|
|
|
221
221
|
parser.add_argument(
|
|
222
|
-
"
|
|
222
|
+
"app",
|
|
223
223
|
nargs="?",
|
|
224
224
|
default=None,
|
|
225
|
-
help="
|
|
225
|
+
help="Load and run the `ServerApp` from the specified Flower App path. "
|
|
226
|
+
"The `pyproject.toml` file must be located in the root of this path.",
|
|
226
227
|
)
|
|
227
228
|
parser.add_argument(
|
|
228
229
|
"--insecure",
|
|
229
230
|
action="store_true",
|
|
230
|
-
help="Run the
|
|
231
|
+
help="Run the `ServerApp` without HTTPS. By default, the app runs with "
|
|
231
232
|
"HTTPS enabled. Use this flag only if you understand the risks.",
|
|
232
233
|
)
|
|
233
234
|
parser.add_argument(
|
|
@@ -252,25 +253,6 @@ def _parse_args_run_server_app() -> argparse.ArgumentParser:
|
|
|
252
253
|
default=ADDRESS_DRIVER_API,
|
|
253
254
|
help="SuperLink Driver API (gRPC-rere) address (IPv4, IPv6, or a domain name)",
|
|
254
255
|
)
|
|
255
|
-
parser.add_argument(
|
|
256
|
-
"--dir",
|
|
257
|
-
default="",
|
|
258
|
-
help="Add specified directory to the PYTHONPATH and load Flower "
|
|
259
|
-
"app from there."
|
|
260
|
-
" Default: current working directory.",
|
|
261
|
-
)
|
|
262
|
-
parser.add_argument(
|
|
263
|
-
"--fab-id",
|
|
264
|
-
default=None,
|
|
265
|
-
type=str,
|
|
266
|
-
help="The identifier of the FAB used in the run.",
|
|
267
|
-
)
|
|
268
|
-
parser.add_argument(
|
|
269
|
-
"--fab-version",
|
|
270
|
-
default=None,
|
|
271
|
-
type=str,
|
|
272
|
-
help="The version of the FAB used in the run.",
|
|
273
|
-
)
|
|
274
256
|
parser.add_argument(
|
|
275
257
|
"--run-id",
|
|
276
258
|
default=None,
|
|
@@ -29,7 +29,7 @@ BackendConfig = Dict[str, Dict[str, ConfigsRecordValues]]
|
|
|
29
29
|
class Backend(ABC):
|
|
30
30
|
"""Abstract base class for a Simulation Engine Backend."""
|
|
31
31
|
|
|
32
|
-
def __init__(self, backend_config: BackendConfig
|
|
32
|
+
def __init__(self, backend_config: BackendConfig) -> None:
|
|
33
33
|
"""Construct a backend."""
|
|
34
34
|
|
|
35
35
|
@abstractmethod
|
|
@@ -14,9 +14,8 @@
|
|
|
14
14
|
# ==============================================================================
|
|
15
15
|
"""Ray backend for the Fleet API using the Simulation Engine."""
|
|
16
16
|
|
|
17
|
-
import pathlib
|
|
18
17
|
from logging import DEBUG, ERROR
|
|
19
|
-
from typing import Callable, Dict,
|
|
18
|
+
from typing import Callable, Dict, Tuple, Union
|
|
20
19
|
|
|
21
20
|
import ray
|
|
22
21
|
|
|
@@ -33,7 +32,6 @@ from .backend import Backend, BackendConfig
|
|
|
33
32
|
|
|
34
33
|
ClientResourcesDict = Dict[str, Union[int, float]]
|
|
35
34
|
ActorArgsDict = Dict[str, Union[int, float, Callable[[], None]]]
|
|
36
|
-
RunTimeEnvDict = Dict[str, Union[str, List[str]]]
|
|
37
35
|
|
|
38
36
|
|
|
39
37
|
class RayBackend(Backend):
|
|
@@ -42,18 +40,14 @@ class RayBackend(Backend):
|
|
|
42
40
|
def __init__(
|
|
43
41
|
self,
|
|
44
42
|
backend_config: BackendConfig,
|
|
45
|
-
work_dir: str,
|
|
46
43
|
) -> None:
|
|
47
44
|
"""Prepare RayBackend by initialising Ray and creating the ActorPool."""
|
|
48
45
|
log(DEBUG, "Initialising: %s", self.__class__.__name__)
|
|
49
46
|
log(DEBUG, "Backend config: %s", backend_config)
|
|
50
47
|
|
|
51
|
-
if not pathlib.Path(work_dir).exists():
|
|
52
|
-
raise ValueError(f"Specified work_dir {work_dir} does not exist.")
|
|
53
|
-
|
|
54
48
|
# Initialise ray
|
|
55
49
|
self.init_args_key = "init_args"
|
|
56
|
-
self.init_ray(backend_config
|
|
50
|
+
self.init_ray(backend_config)
|
|
57
51
|
|
|
58
52
|
# Validate client resources
|
|
59
53
|
self.client_resources_key = "client_resources"
|
|
@@ -68,23 +62,6 @@ class RayBackend(Backend):
|
|
|
68
62
|
actor_kwargs=actor_kwargs,
|
|
69
63
|
)
|
|
70
64
|
|
|
71
|
-
def _configure_runtime_env(self, work_dir: str) -> RunTimeEnvDict:
|
|
72
|
-
"""Return list of files/subdirectories to exclude relative to work_dir.
|
|
73
|
-
|
|
74
|
-
Without this, Ray will push everything to the Ray Cluster.
|
|
75
|
-
"""
|
|
76
|
-
runtime_env: RunTimeEnvDict = {"working_dir": work_dir}
|
|
77
|
-
|
|
78
|
-
excludes = []
|
|
79
|
-
path = pathlib.Path(work_dir)
|
|
80
|
-
for p in path.rglob("*"):
|
|
81
|
-
# Exclude files need to be relative to the working_dir
|
|
82
|
-
if p.is_file() and not str(p).endswith(".py"):
|
|
83
|
-
excludes.append(str(p.relative_to(path)))
|
|
84
|
-
runtime_env["excludes"] = excludes
|
|
85
|
-
|
|
86
|
-
return runtime_env
|
|
87
|
-
|
|
88
65
|
def _validate_client_resources(self, config: BackendConfig) -> ClientResourcesDict:
|
|
89
66
|
client_resources_config = config.get(self.client_resources_key)
|
|
90
67
|
client_resources: ClientResourcesDict = {}
|
|
@@ -123,26 +100,18 @@ class RayBackend(Backend):
|
|
|
123
100
|
actor_args["on_actor_init_fn"] = enable_tf_gpu_growth
|
|
124
101
|
return actor_args
|
|
125
102
|
|
|
126
|
-
def init_ray(self, backend_config: BackendConfig
|
|
103
|
+
def init_ray(self, backend_config: BackendConfig) -> None:
|
|
127
104
|
"""Intialises Ray if not already initialised."""
|
|
128
105
|
if not ray.is_initialized():
|
|
129
|
-
# Init ray and append working dir if needed
|
|
130
|
-
runtime_env = (
|
|
131
|
-
self._configure_runtime_env(work_dir=work_dir) if work_dir else None
|
|
132
|
-
)
|
|
133
|
-
|
|
134
106
|
ray_init_args: Dict[
|
|
135
107
|
str,
|
|
136
|
-
|
|
108
|
+
ConfigsRecordValues,
|
|
137
109
|
] = {}
|
|
138
110
|
|
|
139
111
|
if backend_config.get(self.init_args_key):
|
|
140
112
|
for k, v in backend_config[self.init_args_key].items():
|
|
141
113
|
ray_init_args[k] = v
|
|
142
114
|
|
|
143
|
-
if runtime_env is not None:
|
|
144
|
-
ray_init_args["runtime_env"] = runtime_env
|
|
145
|
-
|
|
146
115
|
ray.init(**ray_init_args)
|
|
147
116
|
|
|
148
117
|
@property
|
|
@@ -339,7 +339,7 @@ def start_vce(
|
|
|
339
339
|
|
|
340
340
|
def backend_fn() -> Backend:
|
|
341
341
|
"""Instantiate a Backend."""
|
|
342
|
-
return backend_type(backend_config
|
|
342
|
+
return backend_type(backend_config)
|
|
343
343
|
|
|
344
344
|
# Load ClientApp if needed
|
|
345
345
|
def _load() -> ClientApp:
|
|
@@ -347,9 +347,9 @@ def start_vce(
|
|
|
347
347
|
if client_app_attr:
|
|
348
348
|
app = _get_load_client_app_fn(
|
|
349
349
|
default_app_ref=client_app_attr,
|
|
350
|
-
|
|
350
|
+
app_path=app_dir,
|
|
351
351
|
flwr_dir=flwr_dir,
|
|
352
|
-
multi_app=
|
|
352
|
+
multi_app=False,
|
|
353
353
|
)(run.fab_id, run.fab_version)
|
|
354
354
|
|
|
355
355
|
if client_app:
|
{flwr_nightly-1.11.0.dev20240805.dist-info → flwr_nightly-1.11.0.dev20240811.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: flwr-nightly
|
|
3
|
-
Version: 1.11.0.
|
|
3
|
+
Version: 1.11.0.dev20240811
|
|
4
4
|
Summary: Flower: A Friendly Federated Learning Framework
|
|
5
5
|
Home-page: https://flower.ai
|
|
6
6
|
License: Apache-2.0
|
|
@@ -33,7 +33,7 @@ Classifier: Typing :: Typed
|
|
|
33
33
|
Provides-Extra: rest
|
|
34
34
|
Provides-Extra: simulation
|
|
35
35
|
Requires-Dist: cryptography (>=42.0.4,<43.0.0)
|
|
36
|
-
Requires-Dist: grpcio (>=1.60.0,<2.0.0,!=1.64.2,!=1.65.1)
|
|
36
|
+
Requires-Dist: grpcio (>=1.60.0,<2.0.0,!=1.64.2,!=1.65.1,!=1.65.2,!=1.65.4)
|
|
37
37
|
Requires-Dist: iterators (>=0.0.2,<0.0.3)
|
|
38
38
|
Requires-Dist: numpy (>=1.21.0,<2.0.0)
|
|
39
39
|
Requires-Dist: pathspec (>=0.12.1,<0.13.0)
|
{flwr_nightly-1.11.0.dev20240805.dist-info → flwr_nightly-1.11.0.dev20240811.dist-info}/RECORD
RENAMED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
flwr/__init__.py,sha256=VmBWedrCxqmt4QvUHBLqyVEH6p7zaFMD_oCHerXHSVw,937
|
|
2
2
|
flwr/cli/__init__.py,sha256=cZJVgozlkC6Ni2Hd_FAIrqefrkCGOV18fikToq-6iLw,720
|
|
3
3
|
flwr/cli/app.py,sha256=FBcSrE35ll88VE11ib67qgsJe2GYDN25UswV9-cYcX8,1267
|
|
4
|
-
flwr/cli/build.py,sha256=
|
|
4
|
+
flwr/cli/build.py,sha256=gIR-nTgmLJY5ZtJFLN5ebFBCN3_hoqaioFT77AHojNU,5159
|
|
5
5
|
flwr/cli/config_utils.py,sha256=WK6ywT-mHt2iMG90bspkSGMewv8jXh7yQPVdcPuT2JE,7540
|
|
6
6
|
flwr/cli/example.py,sha256=1bGDYll3BXQY2kRqSN-oICqS5n1b9m0g0RvXTopXHl4,2215
|
|
7
7
|
flwr/cli/install.py,sha256=AI6Zv2dQVDHpLDX1Z_vX5XHVxmZo1OU3ndCSrD2stzQ,7059
|
|
8
8
|
flwr/cli/new/__init__.py,sha256=cQzK1WH4JP2awef1t2UQ2xjl1agVEz9rwutV18SWV1k,789
|
|
9
|
-
flwr/cli/new/new.py,sha256=
|
|
9
|
+
flwr/cli/new/new.py,sha256=VNb31-NLedm-_OK_D0aed0QxHO-tVlXjnf9UWVhC_Jk,9612
|
|
10
10
|
flwr/cli/new/templates/__init__.py,sha256=4luU8RL-CK8JJCstQ_ON809W9bNTkY1l9zSaPKBkgwY,725
|
|
11
11
|
flwr/cli/new/templates/app/.gitignore.tpl,sha256=XixnHdyeMB2vwkGtGnwHqoWpH-9WChdyG0GXe57duhc,3078
|
|
12
12
|
flwr/cli/new/templates/app/README.flowertune.md.tpl,sha256=PqzkGm0g6Zy-vZK9_0EO3f_U6g1r69lGc4UL8kds5Q8,2696
|
|
@@ -50,7 +50,7 @@ flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl,sha256=vIO1ArukTC76ogYLNmJ
|
|
|
50
50
|
flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl,sha256=jk_5teoyOVM9QdBea8J-nk10S6TKw81QZiiKB54ATF0,654
|
|
51
51
|
flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl,sha256=bRIvPCPvTTI4Eo5b61Rmw8WdDw3sjcohciTXgULN5l8,702
|
|
52
52
|
flwr/cli/run/__init__.py,sha256=oCd6HmQDx-sqver1gecgx-uMA38BLTSiiKpl7RGNceg,789
|
|
53
|
-
flwr/cli/run/run.py,sha256=
|
|
53
|
+
flwr/cli/run/run.py,sha256=te6J1HxOOzyC47HMIrvbh-_4xVEGM1x_yXLIhlCBkb8,7521
|
|
54
54
|
flwr/cli/utils.py,sha256=l65Ul0YsSBPuypk0uorAtEDmLEYiUrzpCXi6zCg9mJ4,4506
|
|
55
55
|
flwr/client/__init__.py,sha256=wzJZsYJIHf_8-PMzvfbinyzzjgh1UP1vLrAw2_yEbKI,1345
|
|
56
56
|
flwr/client/app.py,sha256=VJ_vPMVfur5_SqUjHa18VWLB6I9kOav78f5myC_iWuk,26110
|
|
@@ -83,11 +83,11 @@ flwr/client/numpy_client.py,sha256=u76GWAdHmJM88Agm2EgLQSvO8Jnk225mJTk-_TmPjFE,1
|
|
|
83
83
|
flwr/client/rest_client/__init__.py,sha256=5KGlp7pjc1dhNRkKlaNtUfQmg8wrRFh9lS3P3uRS-7Q,735
|
|
84
84
|
flwr/client/rest_client/connection.py,sha256=8LPk7zPvX3l3-5QQXNym8DkIe6V14uEHmTzQ8jCcsnQ,12198
|
|
85
85
|
flwr/client/supernode/__init__.py,sha256=SUhWOzcgXRNXk1V9UgB5-FaWukqqrOEajVUHEcPkwyQ,865
|
|
86
|
-
flwr/client/supernode/app.py,sha256=
|
|
86
|
+
flwr/client/supernode/app.py,sha256=A_0VKCoNREjLPdzngJYPl2Pt5ZKWxbmdGgsJqWqzzy4,15236
|
|
87
87
|
flwr/client/typing.py,sha256=dxoTBnTMfqXr5J7G3y-uNjqxYCddvxhu89spfj4Lm2U,1048
|
|
88
88
|
flwr/common/__init__.py,sha256=4cBLNNnNTwHDnL_HCxhU5ILCSZ6fYh3A_aMBtlvHTVw,3721
|
|
89
89
|
flwr/common/address.py,sha256=wRu1Luezx1PWadwV9OA_KNko01oVvbRnPqfzaDn8QOk,1882
|
|
90
|
-
flwr/common/config.py,sha256=
|
|
90
|
+
flwr/common/config.py,sha256=soJEX0bo3gcKpYlZBzu4NGiNVmwF0tEvqSnwWQsu3pw,6548
|
|
91
91
|
flwr/common/constant.py,sha256=1XxuRezsr9fl3xvQNPR2kyFkwNeG_f5vZayv0PFh0kY,3012
|
|
92
92
|
flwr/common/context.py,sha256=5Bd9RCrhLkYZOVR7vr97OVhzVBHQkS1fUsYiIKTwpxU,2239
|
|
93
93
|
flwr/common/date.py,sha256=OcQuwpb2HxcblTqYm6H223ufop5UZw5N_fzalbpOVzY,891
|
|
@@ -120,7 +120,7 @@ flwr/common/secure_aggregation/secaggplus_constants.py,sha256=9MF-oQh62uD7rt9VeN
|
|
|
120
120
|
flwr/common/secure_aggregation/secaggplus_utils.py,sha256=3VssKgYF7HQIkSpROnEUoYWVt47p12PE_Rj4nYqqg04,3221
|
|
121
121
|
flwr/common/serde.py,sha256=0lXwbnILK16r1uFeV62pKJGxN78pArfOxo1AxAtGs6Q,23679
|
|
122
122
|
flwr/common/telemetry.py,sha256=nSjJHDitPhzB2qUl6LeSMT9Zld5lIk9uW98RpxQwiZw,8366
|
|
123
|
-
flwr/common/typing.py,sha256=
|
|
123
|
+
flwr/common/typing.py,sha256=ISp8UF94dtqml7ElaR6NeGCqcZX3xeab7KWMdjQEqcU,4730
|
|
124
124
|
flwr/common/version.py,sha256=W1ntylR04xkCP6zeSet6sRtBn7P1cje2lOqBJgYBjJY,1349
|
|
125
125
|
flwr/proto/__init__.py,sha256=hbY7JYakwZwCkYgCNlmHdc8rtvfoJbAZLalMdc--CGc,683
|
|
126
126
|
flwr/proto/common_pb2.py,sha256=uzSmq0FJdC-MriN9UGPFs7QVIFTKJmX5lyLnzcyZ5WE,2405
|
|
@@ -139,8 +139,8 @@ flwr/proto/exec_pb2.py,sha256=7b1JUZgt04lBxdXpnd3WOOwmY2egUausm4G1wbmXFPs,3120
|
|
|
139
139
|
flwr/proto/exec_pb2.pyi,sha256=R9xCAUxkLvuXcvQfhNGZ5Qy8qiUCdjN-gp3Iy5BmkNo,4110
|
|
140
140
|
flwr/proto/exec_pb2_grpc.py,sha256=faAN19XEMP8GTKrcIU6jvlWkN44n2KiUsZh_OG0sYcg,4072
|
|
141
141
|
flwr/proto/exec_pb2_grpc.pyi,sha256=VrFhT1Um3Nb8UC2YqnR9GIiM-Yyx0FqaxVOWljh-G_w,1208
|
|
142
|
-
flwr/proto/fab_pb2.py,sha256=
|
|
143
|
-
flwr/proto/fab_pb2.pyi,sha256=
|
|
142
|
+
flwr/proto/fab_pb2.py,sha256=ztC3HnD5e-bYpp7lxrlxkdc30haAlBHswTnt4X5G1eg,1432
|
|
143
|
+
flwr/proto/fab_pb2.pyi,sha256=wQXdQkcij6CrkmclIT5tU9SkOSZHTqm3PxWJWu4-CPI,1970
|
|
144
144
|
flwr/proto/fab_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
|
|
145
145
|
flwr/proto/fab_pb2_grpc.pyi,sha256=ff2TSiLVnG6IVQcTGzb2DIH3XRSoAvAo_RMcvbMFyc0,76
|
|
146
146
|
flwr/proto/fleet_pb2.py,sha256=euBC2M_LfQSwiSK9kFi18OvoV1gnQT4cC9lAMCCiOGY,4729
|
|
@@ -187,7 +187,7 @@ flwr/server/driver/driver.py,sha256=NT_yaeit7_kZEIsCEqOWPID1GrVD3ywH4xZ2wtIh5lM,
|
|
|
187
187
|
flwr/server/driver/grpc_driver.py,sha256=4LMLDXjMU1VdHsj9nyqFIF71GWVsUR85fsO6biWMHRU,9710
|
|
188
188
|
flwr/server/driver/inmemory_driver.py,sha256=RcK94_NtjGZ4aZDIscnU7A3Uv1u8jGx29-xcbjQvZTM,6444
|
|
189
189
|
flwr/server/history.py,sha256=bBOHKyX1eQONIsUx4EUU-UnAk1i0EbEl8ioyMq_UWQ8,5063
|
|
190
|
-
flwr/server/run_serverapp.py,sha256=
|
|
190
|
+
flwr/server/run_serverapp.py,sha256=8HCGSVaNYd2cnd_j-JpVTRH7Cg8_U7ATZUejiMmJe0o,8894
|
|
191
191
|
flwr/server/server.py,sha256=wsXsxMZ9SQ0B42nBnUlcV83NJPycgrgg5bFwcQ4BYBE,17821
|
|
192
192
|
flwr/server/server_app.py,sha256=1hul76ospG8L_KooK_ewn1sWPNTNYLTtZMeGNOBNruA,6267
|
|
193
193
|
flwr/server/server_config.py,sha256=CZaHVAsMvGLjpWVcLPkiYxgJN4xfIyAiUrCI3fETKY4,1349
|
|
@@ -237,9 +237,9 @@ flwr/server/superlink/fleet/rest_rere/__init__.py,sha256=5jbYbAn75sGv-gBwOPDySE0
|
|
|
237
237
|
flwr/server/superlink/fleet/rest_rere/rest_api.py,sha256=yoSU-6nCJF9ASHGNpSY69nZbUhPGXkMIKYDgybKQX3c,7672
|
|
238
238
|
flwr/server/superlink/fleet/vce/__init__.py,sha256=36MHKiefnJeyjwMQzVUK4m06Ojon3WDcwZGQsAcyVhQ,783
|
|
239
239
|
flwr/server/superlink/fleet/vce/backend/__init__.py,sha256=psQjI1DQHOM5uWVXM27l_wPHjfEkMUTP-_8-lEFH1JA,1466
|
|
240
|
-
flwr/server/superlink/fleet/vce/backend/backend.py,sha256=
|
|
241
|
-
flwr/server/superlink/fleet/vce/backend/raybackend.py,sha256=
|
|
242
|
-
flwr/server/superlink/fleet/vce/vce_api.py,sha256=
|
|
240
|
+
flwr/server/superlink/fleet/vce/backend/backend.py,sha256=KL0eHScWr_YfP2eY3VP8_OOMgZwnRNW7qpu5J-ISpXI,2212
|
|
241
|
+
flwr/server/superlink/fleet/vce/backend/raybackend.py,sha256=6-CjUTv1cFnAb53cZzEYCuVLrVu60tPczTo8meqeqbk,6289
|
|
242
|
+
flwr/server/superlink/fleet/vce/vce_api.py,sha256=AeJBEZIC3V54Wg4bzBJa0aO4IXUNiRzRDRv-EKhqtpQ,12750
|
|
243
243
|
flwr/server/superlink/state/__init__.py,sha256=Gj2OTFLXvA-mAjBvwuKDM3rDrVaQPcIoybSa2uskMTE,1003
|
|
244
244
|
flwr/server/superlink/state/in_memory_state.py,sha256=LnKlnXe9JjVHb5_XOo6eD1RQhlCvJVKgz_CkXrMz8DY,13069
|
|
245
245
|
flwr/server/superlink/state/sqlite_state.py,sha256=LdLnHtF8C-1L1IAglfZPqIuKa782Qo7qAYzTXMdMYGM,29052
|
|
@@ -270,8 +270,8 @@ flwr/superexec/exec_grpc.py,sha256=PhqGoZEpTMxSQmUSV8Wgtzb1Za_pHJ-adZqo5RYnDyE,1
|
|
|
270
270
|
flwr/superexec/exec_servicer.py,sha256=fxQAKfgmQRSnYq5anjryfGeRbsZrNFEkuiNcTZhRwiE,2320
|
|
271
271
|
flwr/superexec/executor.py,sha256=k_adivto6R2U82DADOHNvdtobehBYreRek1gOEBIQnQ,2318
|
|
272
272
|
flwr/superexec/simulation.py,sha256=lfdClQYSAIMHe43aJ0Pk-kBw_xoV09LsIMfHo2eo-Ck,6775
|
|
273
|
-
flwr_nightly-1.11.0.
|
|
274
|
-
flwr_nightly-1.11.0.
|
|
275
|
-
flwr_nightly-1.11.0.
|
|
276
|
-
flwr_nightly-1.11.0.
|
|
277
|
-
flwr_nightly-1.11.0.
|
|
273
|
+
flwr_nightly-1.11.0.dev20240811.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
|
274
|
+
flwr_nightly-1.11.0.dev20240811.dist-info/METADATA,sha256=_auggocO__wMNHqoNJK1_XN8doddMwaMl6rvFt6xd0I,15690
|
|
275
|
+
flwr_nightly-1.11.0.dev20240811.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
276
|
+
flwr_nightly-1.11.0.dev20240811.dist-info/entry_points.txt,sha256=7qBQcA-bDGDxnJmLd9FYqglFQubjCNqyg9M8a-lukps,336
|
|
277
|
+
flwr_nightly-1.11.0.dev20240811.dist-info/RECORD,,
|
{flwr_nightly-1.11.0.dev20240805.dist-info → flwr_nightly-1.11.0.dev20240811.dist-info}/LICENSE
RENAMED
|
File without changes
|
{flwr_nightly-1.11.0.dev20240805.dist-info → flwr_nightly-1.11.0.dev20240811.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|