flwr-nightly 1.15.0.dev20250115__py3-none-any.whl → 1.15.0.dev20250117__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.
flwr/client/app.py CHANGED
@@ -16,11 +16,11 @@
16
16
 
17
17
 
18
18
  import multiprocessing
19
- import signal
19
+ import os
20
20
  import sys
21
+ import threading
21
22
  import time
22
23
  from contextlib import AbstractContextManager
23
- from dataclasses import dataclass
24
24
  from logging import ERROR, INFO, WARN
25
25
  from os import urandom
26
26
  from pathlib import Path
@@ -346,10 +346,7 @@ def start_client_internal(
346
346
  transport, server_address
347
347
  )
348
348
 
349
- app_state_tracker = _AppStateTracker()
350
-
351
349
  def _on_sucess(retry_state: RetryState) -> None:
352
- app_state_tracker.is_connected = True
353
350
  if retry_state.tries > 1:
354
351
  log(
355
352
  INFO,
@@ -359,7 +356,6 @@ def start_client_internal(
359
356
  )
360
357
 
361
358
  def _on_backoff(retry_state: RetryState) -> None:
362
- app_state_tracker.is_connected = False
363
359
  if retry_state.tries == 1:
364
360
  log(WARN, "Connection attempt failed, retrying...")
365
361
  else:
@@ -396,7 +392,7 @@ def start_client_internal(
396
392
 
397
393
  runs: dict[int, Run] = {}
398
394
 
399
- while not app_state_tracker.interrupt:
395
+ while True:
400
396
  sleep_duration: int = 0
401
397
  with connection(
402
398
  address,
@@ -435,9 +431,8 @@ def start_client_internal(
435
431
  node_config=node_config,
436
432
  )
437
433
 
438
- app_state_tracker.register_signal_handler()
439
434
  # pylint: disable=too-many-nested-blocks
440
- while not app_state_tracker.interrupt:
435
+ while True:
441
436
  try:
442
437
  # Receive
443
438
  message = receive()
@@ -553,7 +548,7 @@ def start_client_internal(
553
548
 
554
549
  proc = mp_spawn_context.Process(
555
550
  target=_run_flwr_clientapp,
556
- args=(command,),
551
+ args=(command, os.getpid()),
557
552
  daemon=True,
558
553
  )
559
554
  proc.start()
@@ -595,10 +590,7 @@ def start_client_internal(
595
590
  e_code = ErrorCode.LOAD_CLIENT_APP_EXCEPTION
596
591
  exc_entity = "SuperNode"
597
592
 
598
- if not app_state_tracker.interrupt:
599
- log(
600
- ERROR, "%s raised an exception", exc_entity, exc_info=ex
601
- )
593
+ log(ERROR, "%s raised an exception", exc_entity, exc_info=ex)
602
594
 
603
595
  # Create error message
604
596
  reply_message = message.create_error_reply(
@@ -624,19 +616,14 @@ def start_client_internal(
624
616
  run_id,
625
617
  )
626
618
  log(INFO, "")
627
-
628
- except StopIteration:
629
- sleep_duration = 0
630
- break
631
619
  # pylint: enable=too-many-nested-blocks
632
620
 
633
621
  # Unregister node
634
- if delete_node is not None and app_state_tracker.is_connected:
622
+ if delete_node is not None:
635
623
  delete_node() # pylint: disable=not-callable
636
624
 
637
625
  if sleep_duration == 0:
638
626
  log(INFO, "Disconnect and shut down")
639
- del app_state_tracker
640
627
  break
641
628
 
642
629
  # Sleep and reconnect afterwards
@@ -812,24 +799,17 @@ def _init_connection(transport: Optional[str], server_address: str) -> tuple[
812
799
  return connection, address, error_type
813
800
 
814
801
 
815
- @dataclass
816
- class _AppStateTracker:
817
- interrupt: bool = False
818
- is_connected: bool = False
819
-
820
- def register_signal_handler(self) -> None:
821
- """Register handlers for exit signals."""
822
-
823
- def signal_handler(sig, frame): # type: ignore
824
- # pylint: disable=unused-argument
825
- self.interrupt = True
826
- raise StopIteration from None
827
-
828
- signal.signal(signal.SIGINT, signal_handler)
829
- signal.signal(signal.SIGTERM, signal_handler)
802
+ def _run_flwr_clientapp(args: list[str], main_pid: int) -> None:
803
+ # Monitor the main process in case of SIGKILL
804
+ def main_process_monitor() -> None:
805
+ while True:
806
+ time.sleep(1)
807
+ if os.getppid() != main_pid:
808
+ os.kill(os.getpid(), 9)
830
809
 
810
+ threading.Thread(target=main_process_monitor, daemon=True).start()
831
811
 
832
- def _run_flwr_clientapp(args: list[str]) -> None:
812
+ # Run the command
833
813
  sys.argv = args
834
814
  flwr_clientapp()
835
815
 
@@ -47,12 +47,6 @@ from flwr.proto.transport_pb2 import ( # pylint: disable=E0611
47
47
  )
48
48
  from flwr.proto.transport_pb2_grpc import FlowerServiceStub # pylint: disable=E0611
49
49
 
50
- # The following flags can be uncommented for debugging. Other possible values:
51
- # https://github.com/grpc/grpc/blob/master/doc/environment_variables.md
52
- # import os
53
- # os.environ["GRPC_VERBOSITY"] = "debug"
54
- # os.environ["GRPC_TRACE"] = "tcp,http"
55
-
56
50
 
57
51
  def on_channel_state_change(channel_connectivity: str) -> None:
58
52
  """Log channel connectivity."""
@@ -311,3 +311,13 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
311
311
  yield (receive, send, create_node, delete_node, get_run, get_fab)
312
312
  except Exception as exc: # pylint: disable=broad-except
313
313
  log(ERROR, exc)
314
+ # Cleanup
315
+ finally:
316
+ try:
317
+ if node is not None:
318
+ # Disable retrying
319
+ retry_invoker.max_tries = 1
320
+ delete_node()
321
+ except grpc.RpcError:
322
+ pass
323
+ channel.close()
@@ -26,6 +26,7 @@ from typing import Callable, Optional, TypeVar, Union
26
26
 
27
27
  from cryptography.hazmat.primitives.asymmetric import ec
28
28
  from google.protobuf.message import Message as GrpcMessage
29
+ from requests.exceptions import ConnectionError as RequestsConnectionError
29
30
 
30
31
  from flwr.client.heartbeat import start_ping_loop
31
32
  from flwr.client.message_handler.message_handler import validate_out_message
@@ -379,3 +380,12 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
379
380
  yield (receive, send, create_node, delete_node, get_run, get_fab)
380
381
  except Exception as exc: # pylint: disable=broad-except
381
382
  log(ERROR, exc)
383
+ # Cleanup
384
+ finally:
385
+ try:
386
+ if node is not None:
387
+ # Disable retrying
388
+ retry_invoker.max_tries = 1
389
+ delete_node()
390
+ except RequestsConnectionError:
391
+ pass
@@ -86,6 +86,11 @@ def run_supernode() -> None:
86
86
 
87
87
  log(DEBUG, "Isolation mode: %s", args.isolation)
88
88
 
89
+ # Register handlers for graceful shutdown
90
+ register_exit_handlers(
91
+ event_type=EventType.RUN_SUPERNODE_LEAVE,
92
+ )
93
+
89
94
  start_client_internal(
90
95
  server_address=args.superlink,
91
96
  load_client_app_fn=load_fn,
@@ -103,11 +108,6 @@ def run_supernode() -> None:
103
108
  clientappio_api_address=args.clientappio_api_address,
104
109
  )
105
110
 
106
- # Graceful shutdown
107
- register_exit_handlers(
108
- event_type=EventType.RUN_SUPERNODE_LEAVE,
109
- )
110
-
111
111
 
112
112
  def run_client_app() -> None:
113
113
  """Run Flower client app."""
flwr/common/grpc.py CHANGED
@@ -16,6 +16,7 @@
16
16
 
17
17
 
18
18
  import concurrent.futures
19
+ import os
19
20
  import sys
20
21
  from collections.abc import Sequence
21
22
  from logging import DEBUG, ERROR
@@ -35,6 +36,12 @@ INVALID_CERTIFICATES_ERR_MSG = """
35
36
 
36
37
  AddServicerToServerFn = Callable[..., Any]
37
38
 
39
+ if "GRPC_VERBOSITY" not in os.environ:
40
+ os.environ["GRPC_VERBOSITY"] = "error"
41
+ # The following flags can be uncommented for debugging. Other possible values:
42
+ # https://github.com/grpc/grpc/blob/master/doc/environment_variables.md
43
+ # os.environ["GRPC_TRACE"] = "tcp,http"
44
+
38
45
 
39
46
  def create_channel(
40
47
  server_address: str,
flwr/server/app.py CHANGED
@@ -20,6 +20,7 @@ import csv
20
20
  import importlib.util
21
21
  import multiprocessing
22
22
  import multiprocessing.context
23
+ import os
23
24
  import sys
24
25
  import threading
25
26
  from collections.abc import Sequence
@@ -447,7 +448,17 @@ def run_superlink() -> None:
447
448
  sys.exit(1)
448
449
 
449
450
 
450
- def _run_flwr_command(args: list[str]) -> None:
451
+ def _run_flwr_command(args: list[str], main_pid: int) -> None:
452
+ # Monitor the main process in case of SIGKILL
453
+ def main_process_monitor() -> None:
454
+ while True:
455
+ sleep(1)
456
+ if os.getppid() != main_pid:
457
+ os.kill(os.getpid(), 9)
458
+
459
+ threading.Thread(target=main_process_monitor, daemon=True).start()
460
+
461
+ # Run the command
451
462
  sys.argv = args
452
463
  if args[0] == "flwr-serverapp":
453
464
  flwr_serverapp()
@@ -493,7 +504,7 @@ def _flwr_scheduler(
493
504
  ]
494
505
 
495
506
  proc = mp_spawn_context.Process(
496
- target=_run_flwr_command, args=(command,), daemon=True
507
+ target=_run_flwr_command, args=(command, os.getpid()), daemon=True
497
508
  )
498
509
  proc.start()
499
510
 
@@ -117,6 +117,7 @@ def run_serverapp( # pylint: disable=R0914, disable=W0212, disable=R0915
117
117
  log_uploader = None
118
118
  success = True
119
119
  hash_run_id = None
120
+ run_status = None
120
121
  while True:
121
122
 
122
123
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr-nightly
3
- Version: 1.15.0.dev20250115
3
+ Version: 1.15.0.dev20250117
4
4
  Summary: Flower: A Friendly Federated AI Framework
5
5
  Home-page: https://flower.ai
6
6
  License: Apache-2.0
@@ -32,8 +32,8 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
32
32
  Classifier: Typing :: Typed
33
33
  Provides-Extra: rest
34
34
  Provides-Extra: simulation
35
- Requires-Dist: cryptography (>=42.0.4,<43.0.0)
36
- Requires-Dist: grpcio (>=1.60.0,<2.0.0,!=1.64.2,<=1.64.3)
35
+ Requires-Dist: cryptography (>=43.0.1,<44.0.0)
36
+ Requires-Dist: grpcio (>=1.69.0,<2.0.0)
37
37
  Requires-Dist: iterators (>=0.0.2,<0.0.3)
38
38
  Requires-Dist: numpy (>=1.26.0,<3.0.0)
39
39
  Requires-Dist: pathspec (>=0.12.1,<0.13.0)
@@ -69,7 +69,7 @@ flwr/cli/run/run.py,sha256=BvpjYyUvDhVMvO5cG711ihtdeSbls9p8zVAuFGETLA8,7893
69
69
  flwr/cli/stop.py,sha256=1T9RNRCH8dxjmBT38hFtKAWY9Gb7RMCMCML7kex9WzE,4613
70
70
  flwr/cli/utils.py,sha256=RXozds-T7HN8yH0mMj67q-0YktdNNm83N9Ptu_pdhsc,10604
71
71
  flwr/client/__init__.py,sha256=DGDoO0AEAfz-0CUFmLdyUUweAS64-07AOnmDfWUefK4,1192
72
- flwr/client/app.py,sha256=IboXEVp3TeCF_3KErGI7zHg0C7ZAwi4evcf9PLsCFm8,34987
72
+ flwr/client/app.py,sha256=rc_agtyI8XC0L5k5FnM5-ySDqlBPWt2G9Os_MyCI-Uo,34278
73
73
  flwr/client/client.py,sha256=8o58nd9o6ZFcMIaVYPGcV4MSjBG4H0oFgWiv8ZEO3oA,7895
74
74
  flwr/client/client_app.py,sha256=cTig-N00YzTucbo9zNi6I21J8PlbflU_8J_f5CI-Wpw,10390
75
75
  flwr/client/clientapp/__init__.py,sha256=kZqChGnTChQ1WGSUkIlW2S5bc0d0mzDubCAmZUGRpEY,800
@@ -80,10 +80,10 @@ flwr/client/dpfedavg_numpy_client.py,sha256=4KsEvzavDKyVDU1V0kMqffTwu1lNdUCYQN-i
80
80
  flwr/client/grpc_adapter_client/__init__.py,sha256=QyNWIbsq9DpyMk7oemiO1P3TBFfkfkctnJ1JoAkTl3s,742
81
81
  flwr/client/grpc_adapter_client/connection.py,sha256=nV-hPd5q5Eblg6PgUrGGYj74mbE1a0qjfN8G3wzJVAc,4006
82
82
  flwr/client/grpc_client/__init__.py,sha256=LsnbqXiJhgQcB0XzAlUQgPx011Uf7Y7yabIC1HxivJ8,735
83
- flwr/client/grpc_client/connection.py,sha256=gMwB87mlmRBbvPOvUA1m3C-Ci6bjMEmTRI4bJpgbyic,9416
83
+ flwr/client/grpc_client/connection.py,sha256=Y6VDDDEHCPlGxSf-bEyBua_khnY_F1OoXD-8gpIcYhE,9171
84
84
  flwr/client/grpc_rere_client/__init__.py,sha256=MK-oSoV3kwUEQnIwl0GN4OpiHR7eLOrMA8ikunET130,752
85
85
  flwr/client/grpc_rere_client/client_interceptor.py,sha256=9BEZNOHxNJFxIuXc9KzBF0ZkXECtOm7RgnZ9yHVUxCQ,5554
86
- flwr/client/grpc_rere_client/connection.py,sha256=tU9JmcmBQQD_hxo_SvL3ZmvD94Mf8vKNuoUaQnV7Jd4,11415
86
+ flwr/client/grpc_rere_client/connection.py,sha256=9XBcTn4myN_pgAGM6QFQ2Q35clSqxfgY8irrChQuF6I,11668
87
87
  flwr/client/grpc_rere_client/grpc_adapter.py,sha256=VrSqHosRcWv8xDLKEabuzyHpVnRhjAEJf_MUFQxhDh8,6155
88
88
  flwr/client/heartbeat.py,sha256=cx37mJBH8LyoIN4Lks85wtqT1mnU5GulQnr4pGCvAq0,2404
89
89
  flwr/client/message_handler/__init__.py,sha256=QxxQuBNpFPTHx3KiUNvQSlqMKlEnbRR1kFfc1KVje08,719
@@ -103,10 +103,10 @@ flwr/client/nodestate/nodestate.py,sha256=CmHZdR6kVO8tkffg42W0Yb9JdRmrUonZ9deXfU
103
103
  flwr/client/nodestate/nodestate_factory.py,sha256=apUbcJG0a_FUVsc0TkNN3q9yovc9u_J34u9iuLFKTLQ,1430
104
104
  flwr/client/numpy_client.py,sha256=chTkL9dOtK_wgUoYtzp5mfDOC1k8xPAd1qPIsB3hcjA,9581
105
105
  flwr/client/rest_client/__init__.py,sha256=5KGlp7pjc1dhNRkKlaNtUfQmg8wrRFh9lS3P3uRS-7Q,735
106
- flwr/client/rest_client/connection.py,sha256=4XGzq5znU1Ycu8bMtW8AcGvVtxekZXhAU27Xt3eqoUY,12663
106
+ flwr/client/rest_client/connection.py,sha256=B4jZ19TjSpjUsa1-v6TQFwn-U7xcqIZx4O_4FtHztCw,12977
107
107
  flwr/client/run_info_store.py,sha256=ZN2Phi4DSLbSyzg8RmzJcVYh1g6eurHOmWRCT7GMtw4,4040
108
108
  flwr/client/supernode/__init__.py,sha256=SUhWOzcgXRNXk1V9UgB5-FaWukqqrOEajVUHEcPkwyQ,865
109
- flwr/client/supernode/app.py,sha256=LCZs4ImGkleGgsn-b1AOK-u_P8Gi5nKeSvicEDRDF8Q,11400
109
+ flwr/client/supernode/app.py,sha256=ewC6PgE6ycEBoIAXoWAqP0g5dNjwmkLtZ6qZp2Fkac4,11422
110
110
  flwr/client/typing.py,sha256=dxoTBnTMfqXr5J7G3y-uNjqxYCddvxhu89spfj4Lm2U,1048
111
111
  flwr/common/__init__.py,sha256=TVaoFEJE158aui1TPZQiJCDZX4RNHRyI8I55VC80HhI,3901
112
112
  flwr/common/address.py,sha256=9KNYE69WW_QVcyumsux3Qn1wmn4J7f13Y9nHASpvzbA,3018
@@ -121,7 +121,7 @@ flwr/common/differential_privacy.py,sha256=XwcJ3rWr8S8BZUocc76vLSJAXIf6OHnWkBV6-
121
121
  flwr/common/differential_privacy_constants.py,sha256=c7b7tqgvT7yMK0XN9ndiTBs4mQf6d3qk6K7KBZGlV4Q,1074
122
122
  flwr/common/dp.py,sha256=vddkvyjV2FhRoN4VuU2LeAM1UBn7dQB8_W-Qdiveal8,1978
123
123
  flwr/common/exit_handlers.py,sha256=MracJaBeoCOC7TaXK9zCJQxhrMSx9ZtczK237qvhBpU,2806
124
- flwr/common/grpc.py,sha256=amBroQiRdRrczDAGbEZjaYsVoeH_52pyfyOvTSvIF_c,9362
124
+ flwr/common/grpc.py,sha256=GCdiTCppW-clhzOo7OIJbsKIWKnJ9pqNTsAKhj7y4So,9646
125
125
  flwr/common/logger.py,sha256=UPyI_98EDibqgf3epgWxFHxdXgYReSWtaKFf9Mj0hd0,12306
126
126
  flwr/common/message.py,sha256=Zv4ID2BLQsbff0F03DI_MeFoHbSqVZAdDD9NcKYv6Zo,13832
127
127
  flwr/common/object_ref.py,sha256=fIXf8aP5mG6Nuni7dvcKK5Di3zRfRWGs4ljvqIXplds,10115
@@ -211,7 +211,7 @@ flwr/proto/transport_pb2_grpc.py,sha256=vLN3EHtx2aEEMCO4f1Upu-l27BPzd3-5pV-u8wPc
211
211
  flwr/proto/transport_pb2_grpc.pyi,sha256=AGXf8RiIiW2J5IKMlm_3qT3AzcDa4F3P5IqUjve_esA,766
212
212
  flwr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
213
213
  flwr/server/__init__.py,sha256=cEg1oecBu4cKB69iJCqWEylC8b5XW47bl7rQiJsdTvM,1528
214
- flwr/server/app.py,sha256=uhX8FE2II2vv-34ENUDVsp1HOZXlS-8kBOfd7TOXn0E,31799
214
+ flwr/server/app.py,sha256=evM-HqxB_2u3iGZzvB3u9zoFi7IGNWMW-79wauQv_PI,32143
215
215
  flwr/server/client_manager.py,sha256=7Ese0tgrH-i-ms363feYZJKwB8gWnXSmg_hYF2Bju4U,6227
216
216
  flwr/server/client_proxy.py,sha256=4G-oTwhb45sfWLx2uZdcXD98IZwdTS6F88xe3akCdUg,2399
217
217
  flwr/server/compat/__init__.py,sha256=VxnJtJyOjNFQXMNi9hIuzNlZM5n0Hj1p3aq_Pm2udw4,892
@@ -230,7 +230,7 @@ flwr/server/server.py,sha256=1ZsFEptmAV-L2vP2etNC9Ed5CLSxpuKzUFkAPQ4l5Xc,17893
230
230
  flwr/server/server_app.py,sha256=RsgS6PRS5Z74cMUAHzsm8r3LWddwn00MjRs6rlacHt8,6297
231
231
  flwr/server/server_config.py,sha256=CZaHVAsMvGLjpWVcLPkiYxgJN4xfIyAiUrCI3fETKY4,1349
232
232
  flwr/server/serverapp/__init__.py,sha256=L0K-94UDdTyEZ8LDtYybGIIIv3HW6AhSVjXMUfYJQnQ,800
233
- flwr/server/serverapp/app.py,sha256=eh15kToGVRdIFXHyVKa58tWN5Hh3EIXHcYEbcIqqNb0,8467
233
+ flwr/server/serverapp/app.py,sha256=rHVfzr_H4-KCH5rac-MDhexrbreSlZG_N5XvikcAzn8,8489
234
234
  flwr/server/serverapp_components.py,sha256=-IV_CitOfrJclJj2jNdbN1Q65PyFmtKtrTIg1hc6WQw,2118
235
235
  flwr/server/strategy/__init__.py,sha256=tQer2SwjDnvgFFuJMZM-S01Z615N5XK6MaCvpm4BMU0,2836
236
236
  flwr/server/strategy/aggregate.py,sha256=PDvekufza13s9AsVmz9WASunaBs3yCtl8JVliFx9j6Q,13978
@@ -321,8 +321,8 @@ flwr/superexec/exec_servicer.py,sha256=X10ILT-AoGMrB3IgI2mBe9i-QcIVUAl9bucuqVOPY
321
321
  flwr/superexec/exec_user_auth_interceptor.py,sha256=K06OU-l4LnYhTDg071hGJuOaQWEJbZsYi5qxUmmtiG0,3704
322
322
  flwr/superexec/executor.py,sha256=_B55WW2TD1fBINpabSSDRenVHXYmvlfhv-k8hJKU4lQ,3115
323
323
  flwr/superexec/simulation.py,sha256=WQDon15oqpMopAZnwRZoTICYCfHqtkvFSqiTQ2hLD_g,4088
324
- flwr_nightly-1.15.0.dev20250115.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
325
- flwr_nightly-1.15.0.dev20250115.dist-info/METADATA,sha256=2XVW9E5lwPAiKYioV6AkIAg4kQKjEOYQ24cOiZbcNpc,15882
326
- flwr_nightly-1.15.0.dev20250115.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
327
- flwr_nightly-1.15.0.dev20250115.dist-info/entry_points.txt,sha256=JlNxX3qhaV18_2yj5a3kJW1ESxm31cal9iS_N_pf1Rk,538
328
- flwr_nightly-1.15.0.dev20250115.dist-info/RECORD,,
324
+ flwr_nightly-1.15.0.dev20250117.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
325
+ flwr_nightly-1.15.0.dev20250117.dist-info/METADATA,sha256=xPGZx-L2Ehs-dK3SjbDhghD5miEPd2eJk7rJ6MGfyYM,15864
326
+ flwr_nightly-1.15.0.dev20250117.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
327
+ flwr_nightly-1.15.0.dev20250117.dist-info/entry_points.txt,sha256=JlNxX3qhaV18_2yj5a3kJW1ESxm31cal9iS_N_pf1Rk,538
328
+ flwr_nightly-1.15.0.dev20250117.dist-info/RECORD,,