syft-flwr 0.1.7__py3-none-any.whl → 0.2.1__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 syft-flwr might be problematic. Click here for more details.
- syft_flwr/__init__.py +1 -1
- syft_flwr/consts.py +2 -0
- syft_flwr/flower_client.py +150 -61
- syft_flwr/flower_server.py +12 -4
- syft_flwr/grid.py +446 -109
- syft_flwr/mounts.py +1 -1
- syft_flwr/run.py +2 -1
- syft_flwr/run_simulation.py +124 -24
- syft_flwr/utils.py +79 -0
- {syft_flwr-0.1.7.dist-info → syft_flwr-0.2.1.dist-info}/METADATA +3 -3
- syft_flwr-0.2.1.dist-info/RECORD +21 -0
- syft_flwr/flwr_compatibility.py +0 -121
- syft_flwr-0.1.7.dist-info/RECORD +0 -21
- {syft_flwr-0.1.7.dist-info → syft_flwr-0.2.1.dist-info}/WHEEL +0 -0
- {syft_flwr-0.1.7.dist-info → syft_flwr-0.2.1.dist-info}/entry_points.txt +0 -0
- {syft_flwr-0.1.7.dist-info → syft_flwr-0.2.1.dist-info}/licenses/LICENSE +0 -0
syft_flwr/run_simulation.py
CHANGED
|
@@ -1,33 +1,109 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import os
|
|
3
|
-
import
|
|
3
|
+
import sys
|
|
4
|
+
import tempfile
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
|
|
6
7
|
from loguru import logger
|
|
8
|
+
from syft_core import Client
|
|
9
|
+
from syft_crypto import did_path, ensure_bootstrap, get_did_document, private_key_path
|
|
7
10
|
from syft_rds.client.rds_client import RDSClient
|
|
8
|
-
from syft_rds.orchestra import
|
|
9
|
-
from typing_extensions import Union
|
|
11
|
+
from syft_rds.orchestra import SingleRDSStack, remove_rds_stack_dir
|
|
12
|
+
from typing_extensions import Optional, Union
|
|
10
13
|
|
|
11
14
|
from syft_flwr.config import load_flwr_pyproject
|
|
15
|
+
from syft_flwr.consts import SYFT_FLWR_ENCRYPTION_ENABLED
|
|
16
|
+
from syft_flwr.utils import create_temp_client
|
|
12
17
|
|
|
13
18
|
|
|
14
19
|
def _setup_mock_rds_clients(
|
|
15
20
|
project_dir: Path, aggregator: str, datasites: list[str]
|
|
16
|
-
) -> tuple[
|
|
21
|
+
) -> tuple[Path, list[RDSClient], RDSClient]:
|
|
17
22
|
"""Setup mock RDS clients for the given project directory"""
|
|
18
|
-
|
|
19
|
-
remove_rds_stack_dir(
|
|
23
|
+
simulated_syftbox_network_dir = Path(tempfile.gettempdir(), project_dir.name)
|
|
24
|
+
remove_rds_stack_dir(root_dir=simulated_syftbox_network_dir)
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
ds_syftbox_client = create_temp_client(
|
|
27
|
+
email=aggregator, workspace_dir=simulated_syftbox_network_dir
|
|
28
|
+
)
|
|
29
|
+
ds_stack = SingleRDSStack(client=ds_syftbox_client)
|
|
30
|
+
ds_rds_client = ds_stack.init_session(host=aggregator)
|
|
23
31
|
|
|
24
|
-
|
|
32
|
+
do_rds_clients = []
|
|
25
33
|
for datasite in datasites:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
34
|
+
do_syftbox_client = create_temp_client(
|
|
35
|
+
email=datasite, workspace_dir=simulated_syftbox_network_dir
|
|
36
|
+
)
|
|
37
|
+
do_stack = SingleRDSStack(client=do_syftbox_client)
|
|
38
|
+
do_rds_client = do_stack.init_session(host=datasite)
|
|
39
|
+
do_rds_clients.append(do_rds_client)
|
|
40
|
+
|
|
41
|
+
return simulated_syftbox_network_dir, do_rds_clients, ds_rds_client
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _bootstrap_encryption_keys(
|
|
45
|
+
do_clients: list[RDSClient], ds_client: RDSClient
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Bootstrap the encryption keys for all clients if encryption is enabled."""
|
|
48
|
+
# Check if encryption is enabled
|
|
49
|
+
encryption_enabled = (
|
|
50
|
+
os.environ.get(SYFT_FLWR_ENCRYPTION_ENABLED, "true").lower() != "false"
|
|
51
|
+
)
|
|
29
52
|
|
|
30
|
-
|
|
53
|
+
if not encryption_enabled:
|
|
54
|
+
logger.warning("⚠️ Encryption disabled - skipping key bootstrap")
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
logger.info("🔐 Bootstrapping encryption keys for all participants...")
|
|
58
|
+
|
|
59
|
+
all_syftbox_clients: list[Client] = []
|
|
60
|
+
|
|
61
|
+
# Bootstrap server
|
|
62
|
+
try:
|
|
63
|
+
server_client: Client = ds_client._syftbox_client
|
|
64
|
+
ensure_bootstrap(server_client)
|
|
65
|
+
server_client_did_path = did_path(server_client, server_client.email)
|
|
66
|
+
server_client_private_key_path = private_key_path(server_client)
|
|
67
|
+
logger.debug(
|
|
68
|
+
f"✅ Server {ds_client.email} bootstrapped with private encryption keys at {server_client_private_key_path} and did path at {server_client_did_path}"
|
|
69
|
+
)
|
|
70
|
+
all_syftbox_clients.append(server_client)
|
|
71
|
+
except Exception as e:
|
|
72
|
+
logger.error(f"❌ Failed to bootstrap server {ds_client.email}: {e}")
|
|
73
|
+
raise
|
|
74
|
+
|
|
75
|
+
# Bootstrap each client
|
|
76
|
+
for do_client in do_clients:
|
|
77
|
+
try:
|
|
78
|
+
client: Client = do_client._syftbox_client
|
|
79
|
+
ensure_bootstrap(client)
|
|
80
|
+
client_did_path = did_path(client, client.email)
|
|
81
|
+
client_did_doc = get_did_document(client, client.email)
|
|
82
|
+
client_private_key_path = private_key_path(client)
|
|
83
|
+
logger.debug(
|
|
84
|
+
f"✅ Client {do_client.email} bootstrapped with private encryption keys at {client_private_key_path} and did path at {client_did_path} with content: {client_did_doc}"
|
|
85
|
+
)
|
|
86
|
+
all_syftbox_clients.append(client)
|
|
87
|
+
except Exception as e:
|
|
88
|
+
logger.error(f"❌ Failed to bootstrap client {do_client.email}: {e}")
|
|
89
|
+
raise
|
|
90
|
+
|
|
91
|
+
# Verify all DID documents are accessible
|
|
92
|
+
for checking_client in all_syftbox_clients:
|
|
93
|
+
for target_client in all_syftbox_clients:
|
|
94
|
+
if checking_client.email != target_client.email:
|
|
95
|
+
# Verify that checking_client can see target_client's DID document
|
|
96
|
+
did_file_path = did_path(checking_client, target_client.email)
|
|
97
|
+
if did_file_path.exists():
|
|
98
|
+
logger.debug(
|
|
99
|
+
f"✅ {checking_client.email} can see {target_client.email}'s DID at {did_file_path}"
|
|
100
|
+
)
|
|
101
|
+
else:
|
|
102
|
+
logger.warning(
|
|
103
|
+
f"⚠️ {checking_client.email} cannot find {target_client.email}'s DID at {did_file_path}"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
logger.info("🔐 All participants bootstrapped for E2E encryption ✅✅✅")
|
|
31
107
|
|
|
32
108
|
|
|
33
109
|
async def _run_main_py(
|
|
@@ -35,7 +111,7 @@ async def _run_main_py(
|
|
|
35
111
|
config_path: Path,
|
|
36
112
|
client_email: str,
|
|
37
113
|
log_dir: Path,
|
|
38
|
-
dataset_path: Union[str, Path]
|
|
114
|
+
dataset_path: Optional[Union[str, Path]] = None,
|
|
39
115
|
) -> int:
|
|
40
116
|
"""Run the `main.py` file for a given client"""
|
|
41
117
|
log_file_path = log_dir / f"{client_email}.log"
|
|
@@ -49,7 +125,7 @@ async def _run_main_py(
|
|
|
49
125
|
try:
|
|
50
126
|
with open(log_file_path, "w") as f:
|
|
51
127
|
process = await asyncio.create_subprocess_exec(
|
|
52
|
-
|
|
128
|
+
sys.executable, # Use the current Python executable
|
|
53
129
|
str(main_py_path),
|
|
54
130
|
"-s",
|
|
55
131
|
stdout=f,
|
|
@@ -131,7 +207,7 @@ async def _run_simulated_flwr_project(
|
|
|
131
207
|
return run_success
|
|
132
208
|
|
|
133
209
|
|
|
134
|
-
def
|
|
210
|
+
def validate_bootstraped_project(project_dir: Path) -> None:
|
|
135
211
|
"""Validate a bootstraped `syft_flwr` project directory"""
|
|
136
212
|
if not project_dir.exists():
|
|
137
213
|
raise FileNotFoundError(f"Project directory {project_dir} does not exist")
|
|
@@ -159,42 +235,65 @@ def _validate_mock_dataset_paths(mock_dataset_paths: list[str]) -> list[Path]:
|
|
|
159
235
|
|
|
160
236
|
def run(
|
|
161
237
|
project_dir: Union[str, Path], mock_dataset_paths: list[Union[str, Path]]
|
|
162
|
-
) ->
|
|
163
|
-
"""Run a syft_flwr project in simulation mode over mock data
|
|
238
|
+
) -> Union[bool, asyncio.Task]:
|
|
239
|
+
"""Run a syft_flwr project in simulation mode over mock data.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
bool: True if simulation succeeded, False otherwise (synchronous execution)
|
|
243
|
+
asyncio.Task: Task handle if running in async environment (e.g., Jupyter)
|
|
244
|
+
"""
|
|
164
245
|
|
|
165
246
|
project_dir = Path(project_dir).expanduser().resolve()
|
|
166
|
-
|
|
247
|
+
validate_bootstraped_project(project_dir)
|
|
167
248
|
mock_dataset_paths = _validate_mock_dataset_paths(mock_dataset_paths)
|
|
168
249
|
|
|
169
|
-
|
|
250
|
+
# Skip module validation during testing to avoid parallel test issues
|
|
251
|
+
skip_module_check = (
|
|
252
|
+
os.environ.get("SYFT_FLWR_SKIP_MODULE_CHECK", "false").lower() == "true"
|
|
253
|
+
)
|
|
254
|
+
pyproject_conf = load_flwr_pyproject(
|
|
255
|
+
project_dir, check_module=not skip_module_check
|
|
256
|
+
)
|
|
170
257
|
datasites = pyproject_conf["tool"]["syft_flwr"]["datasites"]
|
|
171
258
|
aggregator = pyproject_conf["tool"]["syft_flwr"]["aggregator"]
|
|
172
259
|
|
|
173
|
-
|
|
260
|
+
simulated_syftbox_network_dir, do_clients, ds_client = _setup_mock_rds_clients(
|
|
174
261
|
project_dir, aggregator, datasites
|
|
175
262
|
)
|
|
176
263
|
|
|
264
|
+
_bootstrap_encryption_keys(do_clients, ds_client)
|
|
265
|
+
|
|
266
|
+
simulation_success = False # Track success status
|
|
267
|
+
|
|
177
268
|
async def main():
|
|
269
|
+
nonlocal simulation_success
|
|
178
270
|
try:
|
|
179
271
|
run_success = await _run_simulated_flwr_project(
|
|
180
272
|
project_dir, do_clients, ds_client, mock_dataset_paths
|
|
181
273
|
)
|
|
274
|
+
simulation_success = run_success
|
|
182
275
|
if run_success:
|
|
183
276
|
logger.success("Simulation completed successfully ✅")
|
|
184
277
|
else:
|
|
185
278
|
logger.error("Simulation failed ❌")
|
|
186
279
|
except Exception as e:
|
|
187
280
|
logger.error(f"Simulation failed ❌: {e}")
|
|
281
|
+
simulation_success = False
|
|
188
282
|
finally:
|
|
189
283
|
# Clean up the RDS stack
|
|
190
|
-
remove_rds_stack_dir(
|
|
191
|
-
logger.debug(f"Removed RDS stack: {
|
|
284
|
+
remove_rds_stack_dir(simulated_syftbox_network_dir)
|
|
285
|
+
logger.debug(f"Removed RDS stack: {simulated_syftbox_network_dir}")
|
|
286
|
+
# Also remove the .syftbox folder that saves the config files and private keys
|
|
287
|
+
remove_rds_stack_dir(simulated_syftbox_network_dir.parent / ".syftbox")
|
|
288
|
+
|
|
289
|
+
return simulation_success
|
|
192
290
|
|
|
193
291
|
try:
|
|
194
292
|
loop = asyncio.get_running_loop()
|
|
195
293
|
logger.debug(f"Running in an environment with an existing event loop {loop}")
|
|
196
294
|
# We are in an environment with an existing event loop (like Jupyter)
|
|
197
|
-
asyncio.create_task(main())
|
|
295
|
+
task = asyncio.create_task(main())
|
|
296
|
+
return task # Return the task so callers can await it
|
|
198
297
|
except RuntimeError:
|
|
199
298
|
logger.debug("No existing event loop, creating and running one")
|
|
200
299
|
# No existing event loop, create and run one (for scripts)
|
|
@@ -202,3 +301,4 @@ def run(
|
|
|
202
301
|
asyncio.set_event_loop(loop)
|
|
203
302
|
loop.run_until_complete(main())
|
|
204
303
|
loop.close()
|
|
304
|
+
return simulation_success # Return success status for synchronous execution
|
syft_flwr/utils.py
CHANGED
|
@@ -3,6 +3,16 @@ import re
|
|
|
3
3
|
import zlib
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
|
+
from flwr.common import Metadata
|
|
7
|
+
from flwr.common.message import Error, Message
|
|
8
|
+
from flwr.common.record import RecordDict
|
|
9
|
+
from loguru import logger
|
|
10
|
+
from syft_core import Client, SyftClientConfig
|
|
11
|
+
from syft_crypto.x3dh_bootstrap import ensure_bootstrap
|
|
12
|
+
from typing_extensions import Optional, Tuple
|
|
13
|
+
|
|
14
|
+
from syft_flwr.consts import SYFT_FLWR_ENCRYPTION_ENABLED
|
|
15
|
+
|
|
6
16
|
EMAIL_REGEX = r"^[^@]+@[^@]+\.[^@]+$"
|
|
7
17
|
|
|
8
18
|
|
|
@@ -34,3 +44,72 @@ def run_syft_flwr() -> bool:
|
|
|
34
44
|
return True
|
|
35
45
|
except FileNotFoundError:
|
|
36
46
|
return False
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def create_temp_client(email: str, workspace_dir: Path) -> Client:
|
|
50
|
+
"""Create a temporary Client instance for testing"""
|
|
51
|
+
workspace_hash = hash(str(workspace_dir)) % 10000
|
|
52
|
+
server_port = 8080 + workspace_hash
|
|
53
|
+
client_port = 8082 + workspace_hash
|
|
54
|
+
config: SyftClientConfig = SyftClientConfig(
|
|
55
|
+
email=email,
|
|
56
|
+
data_dir=workspace_dir,
|
|
57
|
+
server_url=f"http://localhost:{server_port}",
|
|
58
|
+
client_url=f"http://localhost:{client_port}",
|
|
59
|
+
path=workspace_dir / ".syftbox" / f"{email.split('@')[0]}_config.json",
|
|
60
|
+
).save()
|
|
61
|
+
logger.debug(f"Created temp client {email} with config {config}")
|
|
62
|
+
return Client(config)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def setup_client(app_name: str) -> Tuple[Client, bool, str]:
|
|
66
|
+
"""Setup SyftBox client and encryption."""
|
|
67
|
+
client = Client.load()
|
|
68
|
+
|
|
69
|
+
# Check encryption setting
|
|
70
|
+
encryption_enabled = (
|
|
71
|
+
os.environ.get(SYFT_FLWR_ENCRYPTION_ENABLED, "true").lower() != "false"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Bootstrap encryption if needed
|
|
75
|
+
if encryption_enabled:
|
|
76
|
+
client = ensure_bootstrap(client)
|
|
77
|
+
logger.info("🔐 End-to-end encryption is ENABLED for FL messages")
|
|
78
|
+
else:
|
|
79
|
+
logger.warning("⚠️ Encryption disabled - skipping client key bootstrap")
|
|
80
|
+
logger.warning(
|
|
81
|
+
"⚠️ End-to-end encryption is DISABLED for FL messages (development mode / insecure)"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
return client, encryption_enabled, f"flwr/{app_name}"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def check_reply_to_field(metadata: Metadata) -> bool:
|
|
88
|
+
"""Check if reply_to field is empty (Flower 1.17+ format)."""
|
|
89
|
+
return metadata.reply_to_message_id == ""
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def create_flwr_message(
|
|
93
|
+
content: RecordDict,
|
|
94
|
+
message_type: str,
|
|
95
|
+
dst_node_id: int,
|
|
96
|
+
group_id: str,
|
|
97
|
+
ttl: Optional[float] = None,
|
|
98
|
+
error: Optional[Error] = None,
|
|
99
|
+
reply_to: Optional[Message] = None,
|
|
100
|
+
) -> Message:
|
|
101
|
+
"""Create a Flower message (requires Flower >= 1.17)."""
|
|
102
|
+
if reply_to is not None:
|
|
103
|
+
if error is not None:
|
|
104
|
+
return Message(reply_to=reply_to, error=error)
|
|
105
|
+
return Message(content=content, reply_to=reply_to)
|
|
106
|
+
else:
|
|
107
|
+
if error is not None:
|
|
108
|
+
raise ValueError("Error and reply_to cannot both be None")
|
|
109
|
+
return Message(
|
|
110
|
+
content=content,
|
|
111
|
+
dst_node_id=dst_node_id,
|
|
112
|
+
message_type=message_type,
|
|
113
|
+
ttl=ttl,
|
|
114
|
+
group_id=group_id,
|
|
115
|
+
)
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: syft-flwr
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: syft_flwr is an open source framework that facilitate federated learning projects using Flower over the SyftBox protocol
|
|
5
5
|
License-File: LICENSE
|
|
6
|
-
Requires-Python: >=3.
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
7
|
Requires-Dist: flwr-datasets[vision]>=0.5.0
|
|
8
8
|
Requires-Dist: flwr[simulation]>=1.20.0
|
|
9
9
|
Requires-Dist: loguru>=0.7.3
|
|
10
10
|
Requires-Dist: safetensors>=0.6.2
|
|
11
|
-
Requires-Dist: syft-rds
|
|
11
|
+
Requires-Dist: syft-rds>=0.2.1
|
|
12
12
|
Requires-Dist: tomli-w>=1.2.0
|
|
13
13
|
Requires-Dist: tomli>=2.2.1
|
|
14
14
|
Requires-Dist: typing-extensions>=4.13.0
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
syft_flwr/__init__.py,sha256=BdzYWTvuUs7ihkPtvHRELRjlOoSsnXcXPd63Ys6VpKI,426
|
|
2
|
+
syft_flwr/bootstrap.py,sha256=-T6SRh_p6u6uWpbTPZ6-URsAfMQAI2jakpjZAh0UUlw,3690
|
|
3
|
+
syft_flwr/cli.py,sha256=imctwdQMxQeGQZaiKSX1Mo2nU_-RmA-cGB3H4huuUeA,3274
|
|
4
|
+
syft_flwr/config.py,sha256=4hwkovGtFOLNULjJwoGYcA0uT4y3vZSrxndXqYXquMY,821
|
|
5
|
+
syft_flwr/consts.py,sha256=u3QK-Wp8D2Va7iZcp5z4ormVm_FAUDeK4u-w81UL_eY,107
|
|
6
|
+
syft_flwr/flower_client.py,sha256=dBM8QPJSyQmeoG41w2m9nXM5451VmqUviQz117z4FM4,7066
|
|
7
|
+
syft_flwr/flower_server.py,sha256=ZNDUR1U79M0BaG7n39TGUkVHV2NYi-LDsN8FqKJFfFQ,1508
|
|
8
|
+
syft_flwr/grid.py,sha256=5rbv6ncLKK2S1PAifkavaOG36gih-QexPJHh8nnwLws,20309
|
|
9
|
+
syft_flwr/mounts.py,sha256=hp0TKVot16SaPYO10Y_mSJGei7aiNteJfK4U4vynWmU,2330
|
|
10
|
+
syft_flwr/run.py,sha256=oy_ovAVmO84teKisLYYrY8a5ZmWH8tpWVDwXKB-O0rU,2144
|
|
11
|
+
syft_flwr/run_simulation.py,sha256=frHytbsxYLjiCM4r4m1NVQOc1j98hm4sQQoBLeagJi8,11539
|
|
12
|
+
syft_flwr/serde.py,sha256=5fCI-cRUOh5wE7cXQd4J6jex1grRGnyD1Jx-VlEDOXM,495
|
|
13
|
+
syft_flwr/utils.py,sha256=KYwijACpHOR7pkvezNBqbCE48y3o4G9OUtnvdm1NkaU,3672
|
|
14
|
+
syft_flwr/strategy/__init__.py,sha256=mpUmExjjFkqU8gg41XsOBKfO3aqCBe7XPJSU-_P7smU,97
|
|
15
|
+
syft_flwr/strategy/fedavg.py,sha256=N8jULUkjvuaBIEVINowyQln8W8yFhkO-J8k0-iPcGMA,1562
|
|
16
|
+
syft_flwr/templates/main.py.tpl,sha256=p0uK97jvLGk3LJdy1_HF1R5BQgIjaTGkYnr-csfh39M,791
|
|
17
|
+
syft_flwr-0.2.1.dist-info/METADATA,sha256=3qRf-wHKTe-uZGPY3bzgX3BsoT5Sp4q2FA07TN03TKY,1254
|
|
18
|
+
syft_flwr-0.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
19
|
+
syft_flwr-0.2.1.dist-info/entry_points.txt,sha256=o7oT0dCoHn-3WyIwdDw1lBh2q-GvhB_8s0hWeJU4myc,49
|
|
20
|
+
syft_flwr-0.2.1.dist-info/licenses/LICENSE,sha256=0msOUar8uPZTqkAOTBp4rCzd7Jl9eRhfKiNufwrsg7k,11361
|
|
21
|
+
syft_flwr-0.2.1.dist-info/RECORD,,
|
syft_flwr/flwr_compatibility.py
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import flwr
|
|
2
|
-
from flwr.common import Metadata
|
|
3
|
-
from flwr.common.message import Error, Message
|
|
4
|
-
from packaging.version import Version
|
|
5
|
-
from typing_extensions import Optional
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def flwr_later_than_1_17():
|
|
9
|
-
return Version(flwr.__version__) >= Version("1.17.0")
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
# Version-dependent imports
|
|
13
|
-
if flwr_later_than_1_17():
|
|
14
|
-
from flwr.common.record import RecordDict
|
|
15
|
-
from flwr.server.grid import Grid
|
|
16
|
-
else:
|
|
17
|
-
from flwr.common.record import RecordSet as RecordDict
|
|
18
|
-
from flwr.server.driver import Driver as Grid
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
__all__ = ["Grid", "RecordDict"]
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def check_reply_to_field(metadata: Metadata) -> bool:
|
|
25
|
-
"""Check if reply_to field is empty based on Flower version."""
|
|
26
|
-
if flwr_later_than_1_17():
|
|
27
|
-
return metadata.reply_to_message_id == ""
|
|
28
|
-
else:
|
|
29
|
-
return metadata.reply_to_message == ""
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def create_flwr_message(
|
|
33
|
-
content: RecordDict,
|
|
34
|
-
message_type: str,
|
|
35
|
-
src_node_id: int,
|
|
36
|
-
dst_node_id: int,
|
|
37
|
-
group_id: str,
|
|
38
|
-
run_id: int,
|
|
39
|
-
ttl: Optional[float] = None,
|
|
40
|
-
error: Optional[Error] = None,
|
|
41
|
-
reply_to: Optional[Message] = None,
|
|
42
|
-
) -> Message:
|
|
43
|
-
"""Create a Flower message with version-compatible parameters."""
|
|
44
|
-
if flwr_later_than_1_17():
|
|
45
|
-
return _create_message_v1_17_plus(
|
|
46
|
-
content,
|
|
47
|
-
message_type,
|
|
48
|
-
dst_node_id,
|
|
49
|
-
group_id,
|
|
50
|
-
ttl,
|
|
51
|
-
error,
|
|
52
|
-
reply_to,
|
|
53
|
-
)
|
|
54
|
-
else:
|
|
55
|
-
return _create_message_pre_v1_17(
|
|
56
|
-
content,
|
|
57
|
-
message_type,
|
|
58
|
-
src_node_id,
|
|
59
|
-
dst_node_id,
|
|
60
|
-
group_id,
|
|
61
|
-
run_id,
|
|
62
|
-
ttl,
|
|
63
|
-
error,
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def _create_message_v1_17_plus(
|
|
68
|
-
content: RecordDict,
|
|
69
|
-
message_type: str,
|
|
70
|
-
dst_node_id: int,
|
|
71
|
-
group_id: str,
|
|
72
|
-
ttl: Optional[float],
|
|
73
|
-
error: Optional[Error],
|
|
74
|
-
reply_to: Optional[Message],
|
|
75
|
-
) -> Message:
|
|
76
|
-
"""Create message for Flower version 1.17+."""
|
|
77
|
-
if reply_to is not None:
|
|
78
|
-
if error is not None:
|
|
79
|
-
return Message(reply_to=reply_to, error=error)
|
|
80
|
-
return Message(content=content, reply_to=reply_to)
|
|
81
|
-
else:
|
|
82
|
-
if error is not None:
|
|
83
|
-
raise ValueError("Error and reply_to cannot both be None")
|
|
84
|
-
return Message(
|
|
85
|
-
content=content,
|
|
86
|
-
dst_node_id=dst_node_id,
|
|
87
|
-
message_type=message_type,
|
|
88
|
-
ttl=ttl,
|
|
89
|
-
group_id=group_id,
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def _create_message_pre_v1_17(
|
|
94
|
-
content: RecordDict,
|
|
95
|
-
message_type: str,
|
|
96
|
-
src_node_id: int,
|
|
97
|
-
dst_node_id: int,
|
|
98
|
-
group_id: str,
|
|
99
|
-
run_id: int,
|
|
100
|
-
ttl: Optional[float],
|
|
101
|
-
error: Optional[Error],
|
|
102
|
-
) -> Message:
|
|
103
|
-
"""Create message for Flower versions before 1.17."""
|
|
104
|
-
from flwr.common import DEFAULT_TTL
|
|
105
|
-
|
|
106
|
-
ttl_ = DEFAULT_TTL if ttl is None else ttl
|
|
107
|
-
metadata = Metadata(
|
|
108
|
-
run_id=run_id,
|
|
109
|
-
message_id="", # Will be set when saving to file
|
|
110
|
-
src_node_id=src_node_id,
|
|
111
|
-
dst_node_id=dst_node_id,
|
|
112
|
-
reply_to_message="",
|
|
113
|
-
group_id=group_id,
|
|
114
|
-
ttl=ttl_,
|
|
115
|
-
message_type=message_type,
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
if error is not None:
|
|
119
|
-
return Message(metadata=metadata, error=error)
|
|
120
|
-
else:
|
|
121
|
-
return Message(metadata=metadata, content=content)
|
syft_flwr-0.1.7.dist-info/RECORD
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
syft_flwr/__init__.py,sha256=oGfKpHbO65Irb9RHFJHb7-RyS-rlcszl_tIxbssgdXU,426
|
|
2
|
-
syft_flwr/bootstrap.py,sha256=-T6SRh_p6u6uWpbTPZ6-URsAfMQAI2jakpjZAh0UUlw,3690
|
|
3
|
-
syft_flwr/cli.py,sha256=imctwdQMxQeGQZaiKSX1Mo2nU_-RmA-cGB3H4huuUeA,3274
|
|
4
|
-
syft_flwr/config.py,sha256=4hwkovGtFOLNULjJwoGYcA0uT4y3vZSrxndXqYXquMY,821
|
|
5
|
-
syft_flwr/flower_client.py,sha256=5UrtfwSTUDwPQlir7mQWLLVxulGcT4Mcy17uz1-UAlk,3685
|
|
6
|
-
syft_flwr/flower_server.py,sha256=sJwSEqePmkmWKGFXm2E44Ugoc6aaz-6tM7UaeWM2-co,1353
|
|
7
|
-
syft_flwr/flwr_compatibility.py,sha256=vURf9rfsZ1uPm04szw6RpGYxtlG3BE4tW3YijptiGyk,3197
|
|
8
|
-
syft_flwr/grid.py,sha256=Me2tivW0v1ApTjdjQffUc9f1UCHh1LtkYcKUjE82iZ8,7735
|
|
9
|
-
syft_flwr/mounts.py,sha256=ry3_3eD4aPkRahk9eibfu88TpQjgp_KQ96G7yj692x4,2319
|
|
10
|
-
syft_flwr/run.py,sha256=OPW9bVt366DT-U-SxMpMLNXASwTZjp7XNNXfDP767f4,2153
|
|
11
|
-
syft_flwr/run_simulation.py,sha256=t3shhfzAWDUlf6iQmwf5sS9APZQE9mkaZ9MLCYs9Ng0,6922
|
|
12
|
-
syft_flwr/serde.py,sha256=5fCI-cRUOh5wE7cXQd4J6jex1grRGnyD1Jx-VlEDOXM,495
|
|
13
|
-
syft_flwr/utils.py,sha256=3dDYEB7btq9hxZ9UsfQWh3i44OerAhGXc5XaX5wO3-o,955
|
|
14
|
-
syft_flwr/strategy/__init__.py,sha256=mpUmExjjFkqU8gg41XsOBKfO3aqCBe7XPJSU-_P7smU,97
|
|
15
|
-
syft_flwr/strategy/fedavg.py,sha256=N8jULUkjvuaBIEVINowyQln8W8yFhkO-J8k0-iPcGMA,1562
|
|
16
|
-
syft_flwr/templates/main.py.tpl,sha256=p0uK97jvLGk3LJdy1_HF1R5BQgIjaTGkYnr-csfh39M,791
|
|
17
|
-
syft_flwr-0.1.7.dist-info/METADATA,sha256=-FVHhD66zCCZ3FUZDGwzISjNFJuKhzWp3gHlKKRDqb4,1255
|
|
18
|
-
syft_flwr-0.1.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
19
|
-
syft_flwr-0.1.7.dist-info/entry_points.txt,sha256=o7oT0dCoHn-3WyIwdDw1lBh2q-GvhB_8s0hWeJU4myc,49
|
|
20
|
-
syft_flwr-0.1.7.dist-info/licenses/LICENSE,sha256=0msOUar8uPZTqkAOTBp4rCzd7Jl9eRhfKiNufwrsg7k,11361
|
|
21
|
-
syft_flwr-0.1.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|