flwr-nightly 1.10.0.dev20240707__py3-none-any.whl → 1.11.0.dev20240724__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.

Files changed (99) hide show
  1. flwr/cli/build.py +16 -2
  2. flwr/cli/config_utils.py +47 -27
  3. flwr/cli/install.py +17 -1
  4. flwr/cli/new/new.py +32 -21
  5. flwr/cli/new/templates/app/code/{client.hf.py.tpl → client.huggingface.py.tpl} +15 -5
  6. flwr/cli/new/templates/app/code/client.jax.py.tpl +2 -1
  7. flwr/cli/new/templates/app/code/client.mlx.py.tpl +36 -13
  8. flwr/cli/new/templates/app/code/client.numpy.py.tpl +2 -1
  9. flwr/cli/new/templates/app/code/client.pytorch.py.tpl +16 -5
  10. flwr/cli/new/templates/app/code/client.sklearn.py.tpl +6 -3
  11. flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +25 -5
  12. flwr/cli/new/templates/app/code/flwr_tune/app.py.tpl +22 -19
  13. flwr/cli/new/templates/app/code/flwr_tune/client.py.tpl +5 -3
  14. flwr/cli/new/templates/app/code/flwr_tune/server.py.tpl +1 -1
  15. flwr/cli/new/templates/app/code/server.huggingface.py.tpl +23 -0
  16. flwr/cli/new/templates/app/code/server.jax.py.tpl +16 -8
  17. flwr/cli/new/templates/app/code/server.mlx.py.tpl +12 -7
  18. flwr/cli/new/templates/app/code/server.numpy.py.tpl +16 -8
  19. flwr/cli/new/templates/app/code/server.pytorch.py.tpl +15 -13
  20. flwr/cli/new/templates/app/code/server.sklearn.py.tpl +17 -10
  21. flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +16 -13
  22. flwr/cli/new/templates/app/code/{task.hf.py.tpl → task.huggingface.py.tpl} +14 -2
  23. flwr/cli/new/templates/app/code/task.mlx.py.tpl +14 -2
  24. flwr/cli/new/templates/app/code/task.pytorch.py.tpl +14 -3
  25. flwr/cli/new/templates/app/code/task.tensorflow.py.tpl +13 -1
  26. flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +9 -12
  27. flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +38 -0
  28. flwr/cli/new/templates/app/pyproject.jax.toml.tpl +17 -11
  29. flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +17 -12
  30. flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +12 -12
  31. flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +13 -12
  32. flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +12 -12
  33. flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +15 -12
  34. flwr/cli/run/run.py +133 -54
  35. flwr/client/app.py +56 -24
  36. flwr/client/client_app.py +28 -8
  37. flwr/client/grpc_adapter_client/connection.py +3 -2
  38. flwr/client/grpc_client/connection.py +3 -2
  39. flwr/client/grpc_rere_client/connection.py +17 -6
  40. flwr/client/message_handler/message_handler.py +1 -1
  41. flwr/client/node_state.py +59 -12
  42. flwr/client/node_state_tests.py +4 -3
  43. flwr/client/rest_client/connection.py +19 -8
  44. flwr/client/supernode/app.py +39 -39
  45. flwr/client/typing.py +2 -2
  46. flwr/common/config.py +92 -2
  47. flwr/common/constant.py +3 -0
  48. flwr/common/context.py +24 -9
  49. flwr/common/logger.py +25 -0
  50. flwr/common/object_ref.py +84 -21
  51. flwr/common/serde.py +45 -0
  52. flwr/common/telemetry.py +17 -0
  53. flwr/common/typing.py +5 -0
  54. flwr/proto/common_pb2.py +36 -0
  55. flwr/proto/common_pb2.pyi +121 -0
  56. flwr/proto/common_pb2_grpc.py +4 -0
  57. flwr/proto/common_pb2_grpc.pyi +4 -0
  58. flwr/proto/driver_pb2.py +24 -19
  59. flwr/proto/driver_pb2.pyi +21 -1
  60. flwr/proto/exec_pb2.py +20 -11
  61. flwr/proto/exec_pb2.pyi +41 -1
  62. flwr/proto/run_pb2.py +12 -7
  63. flwr/proto/run_pb2.pyi +22 -1
  64. flwr/proto/task_pb2.py +7 -8
  65. flwr/server/__init__.py +2 -0
  66. flwr/server/compat/legacy_context.py +5 -4
  67. flwr/server/driver/grpc_driver.py +82 -140
  68. flwr/server/run_serverapp.py +40 -18
  69. flwr/server/server_app.py +56 -10
  70. flwr/server/serverapp_components.py +52 -0
  71. flwr/server/superlink/driver/driver_servicer.py +18 -3
  72. flwr/server/superlink/fleet/message_handler/message_handler.py +13 -2
  73. flwr/server/superlink/fleet/vce/backend/__init__.py +1 -1
  74. flwr/server/superlink/fleet/vce/backend/backend.py +4 -4
  75. flwr/server/superlink/fleet/vce/backend/raybackend.py +10 -10
  76. flwr/server/superlink/fleet/vce/vce_api.py +149 -117
  77. flwr/server/superlink/state/in_memory_state.py +11 -3
  78. flwr/server/superlink/state/sqlite_state.py +23 -8
  79. flwr/server/superlink/state/state.py +7 -2
  80. flwr/server/typing.py +2 -0
  81. flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +18 -2
  82. flwr/simulation/__init__.py +1 -1
  83. flwr/simulation/app.py +4 -3
  84. flwr/simulation/ray_transport/ray_actor.py +15 -19
  85. flwr/simulation/ray_transport/ray_client_proxy.py +22 -9
  86. flwr/simulation/run_simulation.py +269 -70
  87. flwr/superexec/app.py +17 -11
  88. flwr/superexec/deployment.py +111 -35
  89. flwr/superexec/exec_grpc.py +5 -1
  90. flwr/superexec/exec_servicer.py +6 -1
  91. flwr/superexec/executor.py +21 -0
  92. flwr/superexec/simulation.py +181 -0
  93. {flwr_nightly-1.10.0.dev20240707.dist-info → flwr_nightly-1.11.0.dev20240724.dist-info}/METADATA +3 -2
  94. {flwr_nightly-1.10.0.dev20240707.dist-info → flwr_nightly-1.11.0.dev20240724.dist-info}/RECORD +97 -91
  95. flwr/cli/new/templates/app/code/server.hf.py.tpl +0 -17
  96. flwr/cli/new/templates/app/pyproject.hf.toml.tpl +0 -37
  97. {flwr_nightly-1.10.0.dev20240707.dist-info → flwr_nightly-1.11.0.dev20240724.dist-info}/LICENSE +0 -0
  98. {flwr_nightly-1.10.0.dev20240707.dist-info → flwr_nightly-1.11.0.dev20240724.dist-info}/WHEEL +0 -0
  99. {flwr_nightly-1.10.0.dev20240707.dist-info → flwr_nightly-1.11.0.dev20240724.dist-info}/entry_points.txt +0 -0
flwr/server/server_app.py CHANGED
@@ -17,8 +17,11 @@
17
17
 
18
18
  from typing import Callable, Optional
19
19
 
20
- from flwr.common import Context, RecordSet
21
- from flwr.common.logger import warn_preview_feature
20
+ from flwr.common import Context
21
+ from flwr.common.logger import (
22
+ warn_deprecated_feature_with_example,
23
+ warn_preview_feature,
24
+ )
22
25
  from flwr.server.strategy import Strategy
23
26
 
24
27
  from .client_manager import ClientManager
@@ -26,7 +29,20 @@ from .compat import start_driver
26
29
  from .driver import Driver
27
30
  from .server import Server
28
31
  from .server_config import ServerConfig
29
- from .typing import ServerAppCallable
32
+ from .typing import ServerAppCallable, ServerFn
33
+
34
+ SERVER_FN_USAGE_EXAMPLE = """
35
+
36
+ def server_fn(context: Context):
37
+ server_config = ServerConfig(num_rounds=3)
38
+ strategy = FedAvg()
39
+ return ServerAppComponents(
40
+ strategy=strategy,
41
+ server_config=server_config,
42
+ )
43
+
44
+ app = ServerApp(server_fn=server_fn)
45
+ """
30
46
 
31
47
 
32
48
  class ServerApp:
@@ -36,13 +52,15 @@ class ServerApp:
36
52
  --------
37
53
  Use the `ServerApp` with an existing `Strategy`:
38
54
 
39
- >>> server_config = ServerConfig(num_rounds=3)
40
- >>> strategy = FedAvg()
55
+ >>> def server_fn(context: Context):
56
+ >>> server_config = ServerConfig(num_rounds=3)
57
+ >>> strategy = FedAvg()
58
+ >>> return ServerAppComponents(
59
+ >>> strategy=strategy,
60
+ >>> server_config=server_config,
61
+ >>> )
41
62
  >>>
42
- >>> app = ServerApp(
43
- >>> server_config=server_config,
44
- >>> strategy=strategy,
45
- >>> )
63
+ >>> app = ServerApp(server_fn=server_fn)
46
64
 
47
65
  Use the `ServerApp` with a custom main function:
48
66
 
@@ -53,23 +71,52 @@ class ServerApp:
53
71
  >>> print("ServerApp running")
54
72
  """
55
73
 
74
+ # pylint: disable=too-many-arguments
56
75
  def __init__(
57
76
  self,
58
77
  server: Optional[Server] = None,
59
78
  config: Optional[ServerConfig] = None,
60
79
  strategy: Optional[Strategy] = None,
61
80
  client_manager: Optional[ClientManager] = None,
81
+ server_fn: Optional[ServerFn] = None,
62
82
  ) -> None:
83
+ if any([server, config, strategy, client_manager]):
84
+ warn_deprecated_feature_with_example(
85
+ deprecation_message="Passing either `server`, `config`, `strategy` or "
86
+ "`client_manager` directly to the ServerApp "
87
+ "constructor is deprecated.",
88
+ example_message="Pass `ServerApp` arguments wrapped "
89
+ "in a `flwr.server.ServerAppComponents` object that gets "
90
+ "returned by a function passed as the `server_fn` argument "
91
+ "to the `ServerApp` constructor. For example: ",
92
+ code_example=SERVER_FN_USAGE_EXAMPLE,
93
+ )
94
+
95
+ if server_fn:
96
+ raise ValueError(
97
+ "Passing `server_fn` is incompatible with passing the "
98
+ "other arguments (now deprecated) to ServerApp. "
99
+ "Use `server_fn` exclusively."
100
+ )
101
+
63
102
  self._server = server
64
103
  self._config = config
65
104
  self._strategy = strategy
66
105
  self._client_manager = client_manager
106
+ self._server_fn = server_fn
67
107
  self._main: Optional[ServerAppCallable] = None
68
108
 
69
109
  def __call__(self, driver: Driver, context: Context) -> None:
70
110
  """Execute `ServerApp`."""
71
111
  # Compatibility mode
72
112
  if not self._main:
113
+ if self._server_fn:
114
+ # Execute server_fn()
115
+ components = self._server_fn(context)
116
+ self._server = components.server
117
+ self._config = components.config
118
+ self._strategy = components.strategy
119
+ self._client_manager = components.client_manager
73
120
  start_driver(
74
121
  server=self._server,
75
122
  config=self._config,
@@ -80,7 +127,6 @@ class ServerApp:
80
127
  return
81
128
 
82
129
  # New execution mode
83
- context = Context(state=RecordSet())
84
130
  self._main(driver, context)
85
131
 
86
132
  def main(self) -> Callable[[ServerAppCallable], ServerAppCallable]:
@@ -0,0 +1,52 @@
1
+ # Copyright 2024 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
+ """ServerAppComponents for the ServerApp."""
16
+
17
+
18
+ from dataclasses import dataclass
19
+ from typing import Optional
20
+
21
+ from .client_manager import ClientManager
22
+ from .server import Server
23
+ from .server_config import ServerConfig
24
+ from .strategy import Strategy
25
+
26
+
27
+ @dataclass
28
+ class ServerAppComponents: # pylint: disable=too-many-instance-attributes
29
+ """Components to construct a ServerApp.
30
+
31
+ Parameters
32
+ ----------
33
+ server : Optional[Server] (default: None)
34
+ A server implementation, either `flwr.server.Server` or a subclass
35
+ thereof. If no instance is provided, one will be created internally.
36
+ config : Optional[ServerConfig] (default: None)
37
+ Currently supported values are `num_rounds` (int, default: 1) and
38
+ `round_timeout` in seconds (float, default: None).
39
+ strategy : Optional[Strategy] (default: None)
40
+ An implementation of the abstract base class
41
+ `flwr.server.strategy.Strategy`. If no strategy is provided, then
42
+ `flwr.server.strategy.FedAvg` will be used.
43
+ client_manager : Optional[ClientManager] (default: None)
44
+ An implementation of the class `flwr.server.ClientManager`. If no
45
+ implementation is provided, then `flwr.server.SimpleClientManager`
46
+ will be used.
47
+ """
48
+
49
+ server: Optional[Server] = None
50
+ config: Optional[ServerConfig] = None
51
+ strategy: Optional[Strategy] = None
52
+ client_manager: Optional[ClientManager] = None
@@ -23,6 +23,7 @@ from uuid import UUID
23
23
  import grpc
24
24
 
25
25
  from flwr.common.logger import log
26
+ from flwr.common.serde import user_config_from_proto, user_config_to_proto
26
27
  from flwr.proto import driver_pb2_grpc # pylint: disable=E0611
27
28
  from flwr.proto.driver_pb2 import ( # pylint: disable=E0611
28
29
  CreateRunRequest,
@@ -69,7 +70,11 @@ class DriverServicer(driver_pb2_grpc.DriverServicer):
69
70
  """Create run ID."""
70
71
  log(DEBUG, "DriverServicer.CreateRun")
71
72
  state: State = self.state_factory.state()
72
- run_id = state.create_run(request.fab_id, request.fab_version)
73
+ run_id = state.create_run(
74
+ request.fab_id,
75
+ request.fab_version,
76
+ user_config_from_proto(request.override_config),
77
+ )
73
78
  return CreateRunResponse(run_id=run_id)
74
79
 
75
80
  def PushTaskIns(
@@ -145,8 +150,18 @@ class DriverServicer(driver_pb2_grpc.DriverServicer):
145
150
 
146
151
  # Retrieve run information
147
152
  run = state.get_run(request.run_id)
148
- run_proto = None if run is None else Run(**vars(run))
149
- return GetRunResponse(run=run_proto)
153
+
154
+ if run is None:
155
+ return GetRunResponse()
156
+
157
+ return GetRunResponse(
158
+ run=Run(
159
+ run_id=run.run_id,
160
+ fab_id=run.fab_id,
161
+ fab_version=run.fab_version,
162
+ override_config=user_config_to_proto(run.override_config),
163
+ )
164
+ )
150
165
 
151
166
 
152
167
  def _raise_if(validation_error: bool, detail: str) -> None:
@@ -19,6 +19,7 @@ import time
19
19
  from typing import List, Optional
20
20
  from uuid import UUID
21
21
 
22
+ from flwr.common.serde import user_config_to_proto
22
23
  from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
23
24
  CreateNodeRequest,
24
25
  CreateNodeResponse,
@@ -113,5 +114,15 @@ def get_run(
113
114
  ) -> GetRunResponse:
114
115
  """Get run information."""
115
116
  run = state.get_run(request.run_id)
116
- run_proto = None if run is None else Run(**vars(run))
117
- return GetRunResponse(run=run_proto)
117
+
118
+ if run is None:
119
+ return GetRunResponse()
120
+
121
+ return GetRunResponse(
122
+ run=Run(
123
+ run_id=run.run_id,
124
+ fab_id=run.fab_id,
125
+ fab_version=run.fab_version,
126
+ override_config=user_config_to_proto(run.override_config),
127
+ )
128
+ )
@@ -38,7 +38,7 @@ else:
38
38
 
39
39
  To install the necessary dependencies, install `flwr` with the `simulation` extra:
40
40
 
41
- pip install -U flwr["simulation"]
41
+ pip install -U "flwr[simulation]"
42
42
  """
43
43
 
44
44
 
@@ -33,8 +33,8 @@ class Backend(ABC):
33
33
  """Construct a backend."""
34
34
 
35
35
  @abstractmethod
36
- async def build(self) -> None:
37
- """Build backend asynchronously.
36
+ def build(self) -> None:
37
+ """Build backend.
38
38
 
39
39
  Different components need to be in place before workers in a backend are ready
40
40
  to accept jobs. When this method finishes executing, the backend should be fully
@@ -54,11 +54,11 @@ class Backend(ABC):
54
54
  """Report whether a backend worker is idle and can therefore run a ClientApp."""
55
55
 
56
56
  @abstractmethod
57
- async def terminate(self) -> None:
57
+ def terminate(self) -> None:
58
58
  """Terminate backend."""
59
59
 
60
60
  @abstractmethod
61
- async def process_message(
61
+ def process_message(
62
62
  self,
63
63
  app: Callable[[], ClientApp],
64
64
  message: Message,
@@ -21,6 +21,7 @@ from typing import Callable, Dict, List, Tuple, Union
21
21
  import ray
22
22
 
23
23
  from flwr.client.client_app import ClientApp
24
+ from flwr.common.constant import PARTITION_ID_KEY
24
25
  from flwr.common.context import Context
25
26
  from flwr.common.logger import log
26
27
  from flwr.common.message import Message
@@ -153,12 +154,12 @@ class RayBackend(Backend):
153
154
  """Report whether the pool has idle actors."""
154
155
  return self.pool.is_actor_available()
155
156
 
156
- async def build(self) -> None:
157
+ def build(self) -> None:
157
158
  """Build pool of Ray actors that this backend will submit jobs to."""
158
- await self.pool.add_actors_to_pool(self.pool.actors_capacity)
159
+ self.pool.add_actors_to_pool(self.pool.actors_capacity)
159
160
  log(DEBUG, "Constructed ActorPool with: %i actors", self.pool.num_actors)
160
161
 
161
- async def process_message(
162
+ def process_message(
162
163
  self,
163
164
  app: Callable[[], ClientApp],
164
165
  message: Message,
@@ -168,21 +169,20 @@ class RayBackend(Backend):
168
169
 
169
170
  Return output message and updated context.
170
171
  """
171
- partition_id = context.partition_id
172
+ partition_id = context.node_config[PARTITION_ID_KEY]
172
173
 
173
174
  try:
174
175
  # Submit a task to the pool
175
- future = await self.pool.submit(
176
+ future = self.pool.submit(
176
177
  lambda a, a_fn, mssg, cid, state: a.run.remote(a_fn, mssg, cid, state),
177
178
  (app, message, str(partition_id), context),
178
179
  )
179
180
 
180
- await future
181
181
  # Fetch result
182
182
  (
183
183
  out_mssg,
184
184
  updated_context,
185
- ) = await self.pool.fetch_result_and_return_actor_to_pool(future)
185
+ ) = self.pool.fetch_result_and_return_actor_to_pool(future)
186
186
 
187
187
  return out_mssg, updated_context
188
188
 
@@ -193,11 +193,11 @@ class RayBackend(Backend):
193
193
  self.__class__.__name__,
194
194
  )
195
195
  # add actor back into pool
196
- await self.pool.add_actor_back_to_pool(future)
196
+ self.pool.add_actor_back_to_pool(future)
197
197
  raise ex
198
198
 
199
- async def terminate(self) -> None:
199
+ def terminate(self) -> None:
200
200
  """Terminate all actors in actor pool."""
201
- await self.pool.terminate_all_actors()
201
+ self.pool.terminate_all_actors()
202
202
  ray.shutdown()
203
203
  log(DEBUG, "Terminated %s", self.__class__.__name__)