flwr-nightly 1.21.0.dev20250809__py3-none-any.whl → 1.21.0.dev20250811__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/common/constant.py CHANGED
@@ -265,6 +265,8 @@ class ExecPluginType:
265
265
  """SuperExec plugin types."""
266
266
 
267
267
  CLIENT_APP = "clientapp"
268
+ SERVER_APP = "serverapp"
269
+ SIMULATION = "simulation"
268
270
 
269
271
  def __new__(cls) -> ExecPluginType:
270
272
  """Prevent instantiation."""
@@ -16,6 +16,7 @@
16
16
 
17
17
 
18
18
  import os
19
+ import signal
19
20
  import threading
20
21
  import time
21
22
  from typing import Union
@@ -29,6 +30,29 @@ from flwr.proto.appio_pb2 import ( # pylint: disable=E0611
29
30
  from flwr.proto.clientappio_pb2_grpc import ClientAppIoStub
30
31
  from flwr.proto.serverappio_pb2_grpc import ServerAppIoStub
31
32
 
33
+ if os.name == "nt":
34
+ from ctypes import windll # type: ignore
35
+
36
+
37
+ def _pid_exists(pid: int) -> bool:
38
+ """Check if a process with the given PID exists.
39
+
40
+ This works on Unix-like systems and Windows.
41
+ """
42
+ # Use `ctypes` to check if the process exists on Windows
43
+ if os.name == "nt":
44
+ handle = windll.kernel32.OpenProcess(0x1000, False, pid)
45
+ if handle:
46
+ windll.kernel32.CloseHandle(handle)
47
+ return True
48
+ return False
49
+ # Use `os.kill` on Unix-like systems
50
+ try:
51
+ os.kill(pid, 0)
52
+ except OSError:
53
+ return False
54
+ return True
55
+
32
56
 
33
57
  def start_parent_process_monitor(
34
58
  parent_pid: int,
@@ -38,8 +62,10 @@ def start_parent_process_monitor(
38
62
  def monitor() -> None:
39
63
  while True:
40
64
  time.sleep(0.2)
41
- if os.getppid() != parent_pid:
42
- os.kill(os.getpid(), 9)
65
+ if not _pid_exists(parent_pid):
66
+ # This works on Unix-like systems and Windows
67
+ # Avoid `os.kill` on Windows
68
+ signal.raise_signal(signal.SIGTERM)
43
69
 
44
70
  threading.Thread(target=monitor, daemon=True).start()
45
71
 
@@ -22,7 +22,14 @@ from flwr.common import EventType, event
22
22
  from flwr.common.constant import ExecPluginType
23
23
  from flwr.common.logger import log
24
24
  from flwr.proto.clientappio_pb2_grpc import ClientAppIoStub
25
- from flwr.supercore.superexec.plugin import ClientAppExecPlugin, ExecPlugin
25
+ from flwr.proto.serverappio_pb2_grpc import ServerAppIoStub
26
+ from flwr.proto.simulationio_pb2_grpc import SimulationIoStub
27
+ from flwr.supercore.superexec.plugin import (
28
+ ClientAppExecPlugin,
29
+ ExecPlugin,
30
+ ServerAppExecPlugin,
31
+ SimulationExecPlugin,
32
+ )
26
33
  from flwr.supercore.superexec.run_superexec import run_superexec
27
34
 
28
35
 
@@ -43,6 +50,7 @@ def flower_superexec() -> None:
43
50
  stub_class=stub_class, # type: ignore
44
51
  appio_api_address=args.appio_api_address,
45
52
  flwr_dir=args.flwr_dir,
53
+ parent_pid=args.parent_pid,
46
54
  )
47
55
 
48
56
 
@@ -79,6 +87,13 @@ def _parse_args() -> argparse.ArgumentParser:
79
87
  - `$HOME/.flwr/` in all other cases
80
88
  """,
81
89
  )
90
+ parser.add_argument(
91
+ "--parent-pid",
92
+ type=int,
93
+ default=None,
94
+ help="The PID of the parent process. When set, the process will terminate "
95
+ "when the parent process exits.",
96
+ )
82
97
  return parser
83
98
 
84
99
 
@@ -88,4 +103,8 @@ def _get_plugin_and_stub_class(
88
103
  """Get the plugin class and stub class based on the plugin type."""
89
104
  if plugin_type == ExecPluginType.CLIENT_APP:
90
105
  return ClientAppExecPlugin, ClientAppIoStub
106
+ if plugin_type == ExecPluginType.SERVER_APP:
107
+ return ServerAppExecPlugin, ServerAppIoStub
108
+ if plugin_type == ExecPluginType.SIMULATION:
109
+ return SimulationExecPlugin, SimulationIoStub
91
110
  raise ValueError(f"Unknown plugin type: {plugin_type}")
@@ -18,9 +18,11 @@
18
18
  from .clientapp_exec_plugin import ClientAppExecPlugin
19
19
  from .exec_plugin import ExecPlugin
20
20
  from .serverapp_exec_plugin import ServerAppExecPlugin
21
+ from .simulation_exec_plugin import SimulationExecPlugin
21
22
 
22
23
  __all__ = [
23
24
  "ClientAppExecPlugin",
24
25
  "ExecPlugin",
25
26
  "ServerAppExecPlugin",
27
+ "SimulationExecPlugin",
26
28
  ]
@@ -0,0 +1,28 @@
1
+ # Copyright 2025 Flower Labs GmbH. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # ==============================================================================
15
+ """Simple Flower SuperExec plugin for simulation processes."""
16
+
17
+
18
+ from .base_exec_plugin import BaseExecPlugin
19
+
20
+
21
+ class SimulationExecPlugin(BaseExecPlugin):
22
+ """Simple Flower SuperExec plugin for simulation processes.
23
+
24
+ The plugin always selects the first candidate run ID.
25
+ """
26
+
27
+ command = "flwr-simulation"
28
+ appio_api_address_arg = "--simulationio-api-address"
@@ -31,6 +31,7 @@ from flwr.proto.appio_pb2 import ( # pylint: disable=E0611
31
31
  )
32
32
  from flwr.proto.clientappio_pb2_grpc import ClientAppIoStub
33
33
  from flwr.proto.run_pb2 import GetRunRequest # pylint: disable=E0611
34
+ from flwr.supercore.app_utils import start_parent_process_monitor
34
35
 
35
36
  from .plugin import ExecPlugin
36
37
 
@@ -40,6 +41,7 @@ def run_superexec(
40
41
  stub_class: type[ClientAppIoStub],
41
42
  appio_api_address: str,
42
43
  flwr_dir: Optional[str] = None,
44
+ parent_pid: Optional[int] = None,
43
45
  ) -> None:
44
46
  """Run Flower SuperExec.
45
47
 
@@ -53,7 +55,14 @@ def run_superexec(
53
55
  The address of the AppIO API.
54
56
  flwr_dir : Optional[str] (default: None)
55
57
  The Flower directory.
58
+ parent_pid : Optional[int] (default: None)
59
+ The PID of the parent process. If provided, the SuperExec will terminate
60
+ when the parent process exits.
56
61
  """
62
+ # Start monitoring the parent process if a PID is provided
63
+ if parent_pid is not None:
64
+ start_parent_process_monitor(parent_pid)
65
+
57
66
  # Create the channel to the AppIO API
58
67
  # No TLS support for now, so insecure connection
59
68
  channel = create_channel(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: flwr-nightly
3
- Version: 1.21.0.dev20250809
3
+ Version: 1.21.0.dev20250811
4
4
  Summary: Flower: A Friendly Federated AI Framework
5
5
  License: Apache-2.0
6
6
  Keywords: Artificial Intelligence,Federated AI,Federated Analytics,Federated Evaluation,Federated Learning,Flower,Machine Learning
@@ -108,7 +108,7 @@ flwr/common/args.py,sha256=XFQ5PU0lU7NS1QCiKhhESHVeL8KSjcD3x8h4P3e5qlM,5298
108
108
  flwr/common/auth_plugin/__init__.py,sha256=DktrRcGZrRarLf7Jb_UlHtOyLp9_-kEplyq6PS5-vOA,988
109
109
  flwr/common/auth_plugin/auth_plugin.py,sha256=mM7SuphO4OsVAVJR1GErYVgYT83ZjxDzS_gha12bT9E,4855
110
110
  flwr/common/config.py,sha256=glcZDjco-amw1YfQcYTFJ4S1pt9APoexT-mf1QscuHs,13960
111
- flwr/common/constant.py,sha256=_E2ACR9F7oAaJcG0t1E7D9F7MtDyHVGnEe0_frCwMsQ,8710
111
+ flwr/common/constant.py,sha256=0w5GCaW078GMj_VMQX-Lb7OQDnA70GmWZMzufDvGv6E,8769
112
112
  flwr/common/context.py,sha256=Be8obQR_OvEDy1OmshuUKxGRQ7Qx89mf5F4xlhkR10s,2407
113
113
  flwr/common/date.py,sha256=1ZT2cRSpC2DJqprOVTLXYCR_O2_OZR0zXO_brJ3LqWc,1554
114
114
  flwr/common/differential_privacy.py,sha256=FdlpdpPl_H_2HJa8CQM1iCUGBBQ5Dc8CzxmHERM-EoE,6148
@@ -331,9 +331,9 @@ flwr/simulation/ray_transport/utils.py,sha256=KrexpWYCF-dAF3UHc9yDbPQWO-ahMT-BbD
331
331
  flwr/simulation/run_simulation.py,sha256=-sp3dNZcp7MCAH0BlmZpVcFAGvozRdYXRdDYcH_2Zxk,20838
332
332
  flwr/simulation/simulationio_connection.py,sha256=mzS1C6EEREwQDPceDo30anAasmTDLb9qqV2tXlBhOUA,3494
333
333
  flwr/supercore/__init__.py,sha256=pqkFoow_E6UhbBlhmoD1gmTH-33yJRhBsIZqxRPFZ7U,755
334
- flwr/supercore/app_utils.py,sha256=L4S6yNE7mAm0WFww8y2VruOouGfQOz_sguA9o9DqGuI,2029
334
+ flwr/supercore/app_utils.py,sha256=WS3tly_QIWE-NRogbtFVC5l6arxP3Md1XItI9idmt0M,2771
335
335
  flwr/supercore/cli/__init__.py,sha256=EDl2aO-fuQfxSbL-T1W9RAfA2N0hpWHmqX_GSwblJbQ,845
336
- flwr/supercore/cli/flower_superexec.py,sha256=i1quvC41nXUAscIhpLZ6gi834KFM_cUDq5rdbDjacbs,3235
336
+ flwr/supercore/cli/flower_superexec.py,sha256=J_rf7SCVW9L9wsBScOYa-oJOpyb_e1WOtwTGSyUFu1k,3882
337
337
  flwr/supercore/corestate/__init__.py,sha256=Vau6-L_JG5QzNqtCTa9xCKGGljc09wY8avZmIjSJemg,774
338
338
  flwr/supercore/corestate/corestate.py,sha256=rDAWWeG5DcpCyQso9Z3RhwL4zr2IroPlRMcDzqoSu8s,2328
339
339
  flwr/supercore/ffs/__init__.py,sha256=U3KXwG_SplEvchat27K0LYPoPHzh-cwwT_NHsGlYMt8,908
@@ -350,12 +350,13 @@ flwr/supercore/object_store/object_store.py,sha256=J-rI3X7ET-F6dqOyM-UfHKCCQtPJ_
350
350
  flwr/supercore/object_store/object_store_factory.py,sha256=QVwE2ywi7vsj2iKfvWWnNw3N_I7Rz91NUt2RpcbJ7iM,1527
351
351
  flwr/supercore/object_store/utils.py,sha256=DcPbrb9PenloAPoQRiKiXX9DrDfpXcSyY0cZpgn4PeQ,1680
352
352
  flwr/supercore/superexec/__init__.py,sha256=XKX208hZ6a9gZ4KT9kMqfpCtp_8VGxekzKFfHSu2esQ,707
353
- flwr/supercore/superexec/plugin/__init__.py,sha256=pdnH-bcyqjGyWqEhYTfnZFaLhw5v43HpUB--koNttSU,950
353
+ flwr/supercore/superexec/plugin/__init__.py,sha256=GNwq8uNdE8RB7ywEFRAvKjLFzgS3YXgz39-HBGsemWw,1035
354
354
  flwr/supercore/superexec/plugin/base_exec_plugin.py,sha256=fL-Ufc9Dp56OhWOzNSJUc7HumbkuSDYqZKwde2opG4g,2074
355
355
  flwr/supercore/superexec/plugin/clientapp_exec_plugin.py,sha256=9FT6ufEqV5K9g4FaAB9lVDbIv-VCH5LcxT4YKy23roE,1035
356
356
  flwr/supercore/superexec/plugin/exec_plugin.py,sha256=w3jmtxdv7ov_EdAgifKcm4q8nV39e2Xna4sNjqClwOM,2447
357
357
  flwr/supercore/superexec/plugin/serverapp_exec_plugin.py,sha256=IwRzdPV-cSKwrP2krGh0De4IkAuxsmgK0WU6J-2GXqM,1035
358
- flwr/supercore/superexec/run_superexec.py,sha256=MNmQd6HfPr7Ec5RvTsH6-pDnwGL8bbiqbZ5mkHaQQPY,3873
358
+ flwr/supercore/superexec/plugin/simulation_exec_plugin.py,sha256=upn5zE-YKkl_jTw8RzmeyQ58PU_UAlQ7CqnBXXdng8I,1060
359
+ flwr/supercore/superexec/run_superexec.py,sha256=2-W6UfPgdzEpHSGOvqkIr5OAhD3Zb_O4quk8ZU2oISw,4288
359
360
  flwr/supercore/utils.py,sha256=ebuHMbeA8eXisX0oMPqBK3hk7uVnIE_yiqWVz8YbkpQ,1324
360
361
  flwr/superexec/__init__.py,sha256=YFqER0IJc1XEWfsX6AxZ9LSRq0sawPYrNYki-brvTIc,715
361
362
  flwr/superexec/deployment.py,sha256=CEgWfkN_lH6Vci03RjwKLENw2z6kxNvUdVEErPbqYDY,830
@@ -387,7 +388,7 @@ flwr/supernode/servicer/__init__.py,sha256=lucTzre5WPK7G1YLCfaqg3rbFWdNSb7ZTt-ca
387
388
  flwr/supernode/servicer/clientappio/__init__.py,sha256=7Oy62Y_oijqF7Dxi6tpcUQyOpLc_QpIRZ83NvwmB0Yg,813
388
389
  flwr/supernode/servicer/clientappio/clientappio_servicer.py,sha256=nIHRu38EWK-rpNOkcgBRAAKwYQQWFeCwu0lkO7OPZGQ,10239
389
390
  flwr/supernode/start_client_internal.py,sha256=iqJR8WbCW-8RQIRNwARZYoxhnlaAo5KnluCOEfRoLWM,21020
390
- flwr_nightly-1.21.0.dev20250809.dist-info/METADATA,sha256=k1dHkYUIlLAE-9AG-gUw8_-KrH8DLnz5mPsIcCfDIpc,15966
391
- flwr_nightly-1.21.0.dev20250809.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
392
- flwr_nightly-1.21.0.dev20250809.dist-info/entry_points.txt,sha256=hxHD2ixb_vJFDOlZV-zB4Ao32_BQlL34ftsDh1GXv14,420
393
- flwr_nightly-1.21.0.dev20250809.dist-info/RECORD,,
391
+ flwr_nightly-1.21.0.dev20250811.dist-info/METADATA,sha256=oiloqTG58PFA094Vp2CmxyqFyCdrQTN74woSpLvclHA,15966
392
+ flwr_nightly-1.21.0.dev20250811.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
393
+ flwr_nightly-1.21.0.dev20250811.dist-info/entry_points.txt,sha256=hxHD2ixb_vJFDOlZV-zB4Ao32_BQlL34ftsDh1GXv14,420
394
+ flwr_nightly-1.21.0.dev20250811.dist-info/RECORD,,