MEDfl 2.0.3__py3-none-any.whl → 2.0.4__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.
MEDfl/rw/server.py CHANGED
@@ -1,14 +1,20 @@
1
-
2
1
  import flwr as fl
3
2
  from flwr.server.strategy import FedAvg
4
3
  from flwr.server.server import ServerConfig
5
- from typing import Optional, Any
4
+ from typing import Optional, Any, List, Tuple, Dict, Callable
6
5
  from MEDfl.rw.strategy import Strategy
6
+ from MEDfl.rw.verbose_server import VerboseServer
7
+ import time
8
+ from flwr.server.client_manager import ClientManager
9
+ from flwr.server.client_proxy import ClientProxy
10
+ from flwr.common import GetPropertiesIns
11
+ import asyncio
7
12
 
8
13
  class FederatedServer:
9
14
  """
10
15
  Wrapper for launching a Flower federated-learning server,
11
16
  using a Strategy instance as its strategy attribute.
17
+ Now with client connection tracking.
12
18
  """
13
19
  def __init__(
14
20
  self,
@@ -28,15 +34,49 @@ class FederatedServer:
28
34
  raise ValueError("Strategy object not initialized. Call create_strategy() first.")
29
35
  self.strategy = self.strategy_wrapper.strategy_object
30
36
  self.certificates = certificates
37
+ self.connected_clients = []
31
38
 
32
39
  def start(self) -> None:
33
40
  """
34
41
  Start the Flower server with the configured strategy.
42
+ Now tracks and logs client connections before starting.
35
43
  """
44
+ print(f"Using strategy: {self.strategy_wrapper.name}")
36
45
  print(f"Starting Flower server on {self.server_address} with strategy {self.strategy_wrapper.name}")
46
+
47
+ # Create a custom client manager to track connections
48
+ client_manager = TrackingClientManager(self)
49
+
37
50
  fl.server.start_server(
38
51
  server_address=self.server_address,
39
52
  config=self.server_config,
40
53
  strategy=self.strategy,
41
54
  certificates=self.certificates,
42
- )
55
+ client_manager=client_manager,
56
+ )
57
+
58
+ class TrackingClientManager(fl.server.client_manager.SimpleClientManager):
59
+ """
60
+ Custom client manager that tracks and logs client connections.
61
+ """
62
+ def __init__(self, server: FederatedServer):
63
+ super().__init__()
64
+ self.server = server
65
+ self.client_properties = {} # Store client properties
66
+
67
+ def register(self, client: ClientProxy) -> bool:
68
+ success = super().register(client)
69
+ if success and client.cid not in self.server.connected_clients:
70
+ # Run the async fetch synchronously
71
+ asyncio.run(self._fetch_and_log_hostname(client))
72
+ return success
73
+
74
+ async def _fetch_and_log_hostname(self, client: ClientProxy):
75
+ # try:
76
+ # ins = GetPropertiesIns(config={})
77
+ # props = await client.get_properties(ins=ins, timeout=10.0, group_id=0)
78
+ # hostname = props.properties.get("hostname", "unknown")
79
+ # except Exception as e:
80
+ # hostname = f"Error: {e}"
81
+ print(f"✅ Client connected - CID: {client.cid}")
82
+ self.server.connected_clients.append(client.cid)
MEDfl/rw/strategy.py CHANGED
@@ -105,18 +105,36 @@ class Strategy:
105
105
  # 2) Wrap aggregate_fit to log
106
106
  original_agg_fit = strat.aggregate_fit
107
107
  def logged_aggregate_fit(rnd, results, failures):
108
+ # Print individual client fit metrics
109
+ print(f"\n[Server] 🔄 Round {rnd} - Client Training Metrics:")
110
+ for i, (client_id, fit_res) in enumerate(results):
111
+ print(f" Client {client_id.cid}: {fit_res.metrics}")
112
+
113
+ # Call original aggregation function
108
114
  aggregated_params, metrics = original_agg_fit(rnd, results, failures)
109
- print(f"[Server] ✔ Round {rnd} fit complete → Metrics: {metrics}")
115
+
116
+ # Print aggregated metrics
117
+ print(f"[Server] ✅ Round {rnd} - Aggregated Training Metrics: {metrics}\n")
110
118
  return aggregated_params, metrics
119
+
111
120
  strat.aggregate_fit = logged_aggregate_fit # type: ignore
112
121
 
113
122
  # 3) Wrap aggregate_evaluate to log
114
123
  original_agg_eval = strat.aggregate_evaluate
115
124
  def logged_aggregate_evaluate(rnd, results, failures):
125
+ # Print individual client evaluation metrics
126
+ print(f"\n[Server] 📊 Round {rnd} - Client Evaluation Metrics:")
127
+ for i, (client_id, eval_res) in enumerate(results):
128
+ print(f" Client {client_id.cid}: {eval_res.metrics}")
129
+
130
+ # Call original aggregation function
116
131
  loss, metrics = original_agg_eval(rnd, results, failures)
117
- print(results)
118
- print(f"[Server] Round {rnd} eval complete → Loss: {loss}, Metrics: {metrics}")
132
+
133
+ # Print aggregated metrics
134
+ print(f"[Server] ✅ Round {rnd} - Aggregated Evaluation Metrics:")
135
+ print(f" Loss: {loss}, Metrics: {metrics}\n")
119
136
  return loss, metrics
137
+
120
138
  strat.aggregate_evaluate = logged_aggregate_evaluate # type: ignore
121
139
 
122
140
  self.strategy_object = strat
@@ -0,0 +1,21 @@
1
+ from flwr.server import Server
2
+ from flwr.server.client_manager import SimpleClientManager
3
+ from flwr.server.client_proxy import ClientProxy
4
+ from flwr.common.logger import log
5
+ from logging import INFO
6
+
7
+ class VerboseServer(Server):
8
+ def __init__(self, strategy):
9
+ super().__init__(client_manager=SimpleClientManager(), strategy=strategy)
10
+
11
+ def client_manager_fn(self):
12
+ return self.client_manager
13
+
14
+ def on_client_connect(self, client: ClientProxy):
15
+ super().on_client_connect(client)
16
+ log(INFO, f"[Server] ➕ Client connected: {client.cid}")
17
+ log(INFO, f"[Server] Currently connected: {len(self.client_manager.all().values())} clients")
18
+
19
+ def on_client_disconnect(self, client: ClientProxy):
20
+ super().on_client_disconnect(client)
21
+ log(INFO, f"[Server] ❌ Client disconnected: {client.cid}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MEDfl
3
- Version: 2.0.3
3
+ Version: 2.0.4
4
4
  Summary: Python Open-source package for simulating federated learning and differential privacy
5
5
  Home-page: https://github.com/MEDomics-UdeS/MEDfl
6
6
  Author: MEDomics consortium
@@ -23,8 +23,9 @@ MEDfl/rw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  MEDfl/rw/client.py,sha256=k8y8Wxh2KNe2oy5gRD-KXpTEGCYzp7X2oF5-Z6Rk1_E,1329
24
24
  MEDfl/rw/model.py,sha256=a3mrACDqg4K1V4Qyhh0PBEmWL5SpUYsiEarWHwsVcGk,2704
25
25
  MEDfl/rw/rwConfig.py,sha256=nK3Inv7v7Dm9gZnUnK5EqA4DmQ7TqiH4UoCZ8MlgFjA,823
26
- MEDfl/rw/server.py,sha256=JTexQ5KVOrXWmGOMoLstiVrwUNDHaEhWYnImvAF1Fiw,1557
27
- MEDfl/rw/strategy.py,sha256=NvpDpuU5_4Xv9vYyfvGLeaHaYd9h7V-b330G-PgPFCE,5469
26
+ MEDfl/rw/server.py,sha256=PiCrUTlnx7rVcO9DcT-vnJF5WkOCe4eEzWXeRSUBh10,3286
27
+ MEDfl/rw/strategy.py,sha256=DbgitZzW9Hu7rUnkHdRCq8sKkOGLjMMHPsHRIEVZXwM,6203
28
+ MEDfl/rw/verbose_server.py,sha256=B_abnpCy43e3YrjotLFOm7cLiuiB5PSTeXD5sMP0CxA,851
28
29
  MEDfl/scripts/__init__.py,sha256=Pq1weevsPaU7MRMHfBYeyT0EOFeWLeVM6Y1DVz6jw1A,48
29
30
  MEDfl/scripts/base.py,sha256=QrmG7gkiPYkAy-5tXxJgJmOSLGAKeIVH6i0jq7G9xnA,752
30
31
  MEDfl/scripts/create_db.py,sha256=MnFtZkTueRZ-3qXPNX4JsXjOKj-4mlkxoRhSFdRcvJw,3817
@@ -54,8 +55,8 @@ Medfl/scripts/base.py,sha256=QrmG7gkiPYkAy-5tXxJgJmOSLGAKeIVH6i0jq7G9xnA,752
54
55
  Medfl/scripts/create_db.py,sha256=MnFtZkTueRZ-3qXPNX4JsXjOKj-4mlkxoRhSFdRcvJw,3817
55
56
  alembic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
57
  alembic/env.py,sha256=-aSZ6SlJeK1ZeqHgM-54hOi9LhJRFP0SZGjut-JnY-4,1588
57
- medfl-2.0.3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
58
- medfl-2.0.3.dist-info/METADATA,sha256=U9hqDT2qdSxEyYvtVFKQmjjuHx51XJ-RaKmg8ruzu_M,4579
59
- medfl-2.0.3.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
60
- medfl-2.0.3.dist-info/top_level.txt,sha256=dIL9X8HOFuaVSzpg40DVveDPrymWRoShHtspH7kkjdI,14
61
- medfl-2.0.3.dist-info/RECORD,,
58
+ medfl-2.0.4.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
59
+ medfl-2.0.4.dist-info/METADATA,sha256=hFoRqPRyKiqNCbBw3RcrYEh9fSRlAZChdEGaoNrLIGQ,4579
60
+ medfl-2.0.4.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
61
+ medfl-2.0.4.dist-info/top_level.txt,sha256=dIL9X8HOFuaVSzpg40DVveDPrymWRoShHtspH7kkjdI,14
62
+ medfl-2.0.4.dist-info/RECORD,,
File without changes