flwr-nightly 1.19.0.dev20250515__py3-none-any.whl → 1.19.0.dev20250520__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.
Files changed (34) hide show
  1. flwr/app/__init__.py +15 -0
  2. flwr/app/error.py +68 -0
  3. flwr/app/metadata.py +223 -0
  4. flwr/client/app.py +1 -1
  5. flwr/client/client_app.py +1 -1
  6. flwr/client/clientapp/app.py +1 -1
  7. flwr/client/grpc_rere_client/connection.py +2 -1
  8. flwr/client/rest_client/connection.py +2 -1
  9. flwr/clientapp/__init__.py +15 -0
  10. flwr/common/__init__.py +2 -2
  11. flwr/common/constant.py +1 -1
  12. flwr/common/inflatable.py +41 -12
  13. flwr/common/inflatable_grpc_utils.py +97 -0
  14. flwr/common/message.py +4 -243
  15. flwr/common/record/array.py +2 -2
  16. flwr/common/record/arrayrecord.py +1 -1
  17. flwr/common/record/configrecord.py +2 -2
  18. flwr/common/record/metricrecord.py +1 -1
  19. flwr/common/record/recorddict.py +1 -1
  20. flwr/common/serde.py +4 -1
  21. flwr/compat/__init__.py +15 -0
  22. flwr/compat/client/__init__.py +15 -0
  23. flwr/compat/common/__init__.py +15 -0
  24. flwr/compat/server/__init__.py +15 -0
  25. flwr/compat/simulation/__init__.py +15 -0
  26. flwr/server/superlink/fleet/vce/vce_api.py +1 -1
  27. flwr/serverapp/__init__.py +15 -0
  28. flwr/supercore/__init__.py +15 -0
  29. flwr/superlink/__init__.py +15 -0
  30. flwr/supernode/__init__.py +15 -0
  31. {flwr_nightly-1.19.0.dev20250515.dist-info → flwr_nightly-1.19.0.dev20250520.dist-info}/METADATA +1 -1
  32. {flwr_nightly-1.19.0.dev20250515.dist-info → flwr_nightly-1.19.0.dev20250520.dist-info}/RECORD +34 -20
  33. {flwr_nightly-1.19.0.dev20250515.dist-info → flwr_nightly-1.19.0.dev20250520.dist-info}/WHEEL +0 -0
  34. {flwr_nightly-1.19.0.dev20250515.dist-info → flwr_nightly-1.19.0.dev20250520.dist-info}/entry_points.txt +0 -0
flwr/common/message.py CHANGED
@@ -18,12 +18,14 @@
18
18
  from __future__ import annotations
19
19
 
20
20
  from logging import WARNING
21
- from typing import Any, Optional, cast, overload
21
+ from typing import Any, cast, overload
22
22
 
23
23
  from flwr.common.date import now
24
24
  from flwr.common.logger import warn_deprecated_feature
25
25
 
26
- from .constant import MESSAGE_TTL_TOLERANCE, MessageType, MessageTypeLegacy
26
+ from ..app.error import Error
27
+ from ..app.metadata import Metadata
28
+ from .constant import MESSAGE_TTL_TOLERANCE
27
29
  from .logger import log
28
30
  from .record import RecordDict
29
31
 
@@ -56,202 +58,6 @@ class MessageInitializationError(TypeError):
56
58
  super().__init__(message or MESSAGE_INIT_ERROR_MESSAGE)
57
59
 
58
60
 
59
- class Metadata: # pylint: disable=too-many-instance-attributes
60
- """The class representing metadata associated with the current message.
61
-
62
- Parameters
63
- ----------
64
- run_id : int
65
- An identifier for the current run.
66
- message_id : str
67
- An identifier for the current message.
68
- src_node_id : int
69
- An identifier for the node sending this message.
70
- dst_node_id : int
71
- An identifier for the node receiving this message.
72
- reply_to_message_id : str
73
- An identifier for the message to which this message is a reply.
74
- group_id : str
75
- An identifier for grouping messages. In some settings,
76
- this is used as the FL round.
77
- created_at : float
78
- Unix timestamp when the message was created.
79
- ttl : float
80
- Time-to-live for this message in seconds.
81
- message_type : str
82
- A string that encodes the action to be executed on
83
- the receiving end.
84
- """
85
-
86
- def __init__( # pylint: disable=too-many-arguments,too-many-positional-arguments
87
- self,
88
- run_id: int,
89
- message_id: str,
90
- src_node_id: int,
91
- dst_node_id: int,
92
- reply_to_message_id: str,
93
- group_id: str,
94
- created_at: float,
95
- ttl: float,
96
- message_type: str,
97
- ) -> None:
98
- var_dict = {
99
- "_run_id": run_id,
100
- "_message_id": message_id,
101
- "_src_node_id": src_node_id,
102
- "_dst_node_id": dst_node_id,
103
- "_reply_to_message_id": reply_to_message_id,
104
- "_group_id": group_id,
105
- "_created_at": created_at,
106
- "_ttl": ttl,
107
- "_message_type": message_type,
108
- }
109
- self.__dict__.update(var_dict)
110
- self.message_type = message_type # Trigger validation
111
-
112
- @property
113
- def run_id(self) -> int:
114
- """An identifier for the current run."""
115
- return cast(int, self.__dict__["_run_id"])
116
-
117
- @property
118
- def message_id(self) -> str:
119
- """An identifier for the current message."""
120
- return cast(str, self.__dict__["_message_id"])
121
-
122
- @property
123
- def src_node_id(self) -> int:
124
- """An identifier for the node sending this message."""
125
- return cast(int, self.__dict__["_src_node_id"])
126
-
127
- @property
128
- def reply_to_message_id(self) -> str:
129
- """An identifier for the message to which this message is a reply."""
130
- return cast(str, self.__dict__["_reply_to_message_id"])
131
-
132
- @property
133
- def dst_node_id(self) -> int:
134
- """An identifier for the node receiving this message."""
135
- return cast(int, self.__dict__["_dst_node_id"])
136
-
137
- @dst_node_id.setter
138
- def dst_node_id(self, value: int) -> None:
139
- """Set dst_node_id."""
140
- self.__dict__["_dst_node_id"] = value
141
-
142
- @property
143
- def group_id(self) -> str:
144
- """An identifier for grouping messages."""
145
- return cast(str, self.__dict__["_group_id"])
146
-
147
- @group_id.setter
148
- def group_id(self, value: str) -> None:
149
- """Set group_id."""
150
- self.__dict__["_group_id"] = value
151
-
152
- @property
153
- def created_at(self) -> float:
154
- """Unix timestamp when the message was created."""
155
- return cast(float, self.__dict__["_created_at"])
156
-
157
- @created_at.setter
158
- def created_at(self, value: float) -> None:
159
- """Set creation timestamp of this message."""
160
- self.__dict__["_created_at"] = value
161
-
162
- @property
163
- def delivered_at(self) -> str:
164
- """Unix timestamp when the message was delivered."""
165
- return cast(str, self.__dict__["_delivered_at"])
166
-
167
- @delivered_at.setter
168
- def delivered_at(self, value: str) -> None:
169
- """Set delivery timestamp of this message."""
170
- self.__dict__["_delivered_at"] = value
171
-
172
- @property
173
- def ttl(self) -> float:
174
- """Time-to-live for this message."""
175
- return cast(float, self.__dict__["_ttl"])
176
-
177
- @ttl.setter
178
- def ttl(self, value: float) -> None:
179
- """Set ttl."""
180
- self.__dict__["_ttl"] = value
181
-
182
- @property
183
- def message_type(self) -> str:
184
- """A string that encodes the action to be executed on the receiving end."""
185
- return cast(str, self.__dict__["_message_type"])
186
-
187
- @message_type.setter
188
- def message_type(self, value: str) -> None:
189
- """Set message_type."""
190
- # Validate message type
191
- if validate_legacy_message_type(value):
192
- pass # Backward compatibility for legacy message types
193
- elif not validate_message_type(value):
194
- raise ValueError(
195
- f"Invalid message type: '{value}'. "
196
- "Expected format: '<category>' or '<category>.<action>', "
197
- "where <category> must be 'train', 'evaluate', or 'query', "
198
- "and <action> must be a valid Python identifier."
199
- )
200
-
201
- self.__dict__["_message_type"] = value
202
-
203
- def __repr__(self) -> str:
204
- """Return a string representation of this instance."""
205
- view = ", ".join([f"{k.lstrip('_')}={v!r}" for k, v in self.__dict__.items()])
206
- return f"{self.__class__.__qualname__}({view})"
207
-
208
- def __eq__(self, other: object) -> bool:
209
- """Compare two instances of the class."""
210
- if not isinstance(other, self.__class__):
211
- raise NotImplementedError
212
- return self.__dict__ == other.__dict__
213
-
214
-
215
- class Error:
216
- """The class storing information about an error that occurred.
217
-
218
- Parameters
219
- ----------
220
- code : int
221
- An identifier for the error.
222
- reason : Optional[str]
223
- A reason for why the error arose (e.g. an exception stack-trace)
224
- """
225
-
226
- def __init__(self, code: int, reason: str | None = None) -> None:
227
- var_dict = {
228
- "_code": code,
229
- "_reason": reason,
230
- }
231
- self.__dict__.update(var_dict)
232
-
233
- @property
234
- def code(self) -> int:
235
- """Error code."""
236
- return cast(int, self.__dict__["_code"])
237
-
238
- @property
239
- def reason(self) -> str | None:
240
- """Reason reported about the error."""
241
- return cast(Optional[str], self.__dict__["_reason"])
242
-
243
- def __repr__(self) -> str:
244
- """Return a string representation of this instance."""
245
- view = ", ".join([f"{k.lstrip('_')}={v!r}" for k, v in self.__dict__.items()])
246
- return f"{self.__class__.__qualname__}({view})"
247
-
248
- def __eq__(self, other: object) -> bool:
249
- """Compare two instances of the class."""
250
- if not isinstance(other, self.__class__):
251
- raise NotImplementedError
252
- return self.__dict__ == other.__dict__
253
-
254
-
255
61
  class Message:
256
62
  """Represents a message exchanged between ClientApp and ServerApp.
257
63
 
@@ -614,48 +420,3 @@ def _check_arg_types( # pylint: disable=too-many-arguments, R0917
614
420
  ):
615
421
  return
616
422
  raise MessageInitializationError()
617
-
618
-
619
- def validate_message_type(message_type: str) -> bool:
620
- """Validate if the message type is valid.
621
-
622
- A valid message type format must be one of the following:
623
-
624
- - "<category>"
625
- - "<category>.<action>"
626
-
627
- where `category` must be one of "train", "evaluate", or "query",
628
- and `action` must be a valid Python identifier.
629
- """
630
- # Check if conforming to the format "<category>"
631
- valid_types = {
632
- MessageType.TRAIN,
633
- MessageType.EVALUATE,
634
- MessageType.QUERY,
635
- MessageType.SYSTEM,
636
- }
637
- if message_type in valid_types:
638
- return True
639
-
640
- # Check if conforming to the format "<category>.<action>"
641
- if message_type.count(".") != 1:
642
- return False
643
-
644
- category, action = message_type.split(".")
645
- if category in valid_types and action.isidentifier():
646
- return True
647
-
648
- return False
649
-
650
-
651
- def validate_legacy_message_type(message_type: str) -> bool:
652
- """Validate if the legacy message type is valid."""
653
- # Backward compatibility for legacy message types
654
- if message_type in (
655
- MessageTypeLegacy.GET_PARAMETERS,
656
- MessageTypeLegacy.GET_PROPERTIES,
657
- "reconnect",
658
- ):
659
- return True
660
-
661
- return False
@@ -262,7 +262,7 @@ class Array(InflatableObject):
262
262
  )
263
263
 
264
264
  obj_body = array_proto.SerializeToString(deterministic=True)
265
- return add_header_to_object_body(object_body=obj_body, cls=self)
265
+ return add_header_to_object_body(object_body=obj_body, obj=self)
266
266
 
267
267
  @classmethod
268
268
  def inflate(
@@ -284,7 +284,7 @@ class Array(InflatableObject):
284
284
  Array
285
285
  The inflated Array.
286
286
  """
287
- if children is not None:
287
+ if children:
288
288
  raise ValueError("`Array` objects do not have children.")
289
289
 
290
290
  obj_body = get_object_body(object_content, cls)
@@ -382,7 +382,7 @@ class ArrayRecord(TypedDict[str, Array], InflatableObject):
382
382
 
383
383
  # Serialize references dict
384
384
  object_body = json.dumps(array_refs).encode("utf-8")
385
- return add_header_to_object_body(object_body=object_body, cls=self)
385
+ return add_header_to_object_body(object_body=object_body, obj=self)
386
386
 
387
387
  @classmethod
388
388
  def inflate(
@@ -182,7 +182,7 @@ class ConfigRecord(TypedDict[str, ConfigRecordValues], InflatableObject):
182
182
  ProtoConfigRecordValue,
183
183
  )
184
184
  ).SerializeToString(deterministic=True)
185
- return add_header_to_object_body(object_body=obj_body, cls=self)
185
+ return add_header_to_object_body(object_body=obj_body, obj=self)
186
186
 
187
187
  @classmethod
188
188
  def inflate(
@@ -204,7 +204,7 @@ class ConfigRecord(TypedDict[str, ConfigRecordValues], InflatableObject):
204
204
  ConfigRecord
205
205
  The inflated ConfigRecord.
206
206
  """
207
- if children is not None:
207
+ if children:
208
208
  raise ValueError("`ConfigRecord` objects do not have children.")
209
209
 
210
210
  obj_body = get_object_body(object_content, cls)
@@ -157,7 +157,7 @@ class MetricRecord(TypedDict[str, MetricRecordValues], InflatableObject):
157
157
  obj_body = ProtoMetricRecord(
158
158
  data=record_value_dict_to_proto(self, [float, int], ProtoMetricRecordValue)
159
159
  ).SerializeToString(deterministic=True)
160
- return add_header_to_object_body(object_body=obj_body, cls=self)
160
+ return add_header_to_object_body(object_body=obj_body, obj=self)
161
161
 
162
162
  @classmethod
163
163
  def inflate(
@@ -303,7 +303,7 @@ class RecordDict(TypedDict[str, RecordType], InflatableObject):
303
303
 
304
304
  # Serialize references dict
305
305
  object_body = json.dumps(record_refs).encode("utf-8")
306
- return add_header_to_object_body(object_body=object_body, cls=self)
306
+ return add_header_to_object_body(object_body=object_body, obj=self)
307
307
 
308
308
  @classmethod
309
309
  def inflate(
flwr/common/serde.py CHANGED
@@ -44,6 +44,9 @@ from flwr.proto.transport_pb2 import (
44
44
  Status,
45
45
  )
46
46
 
47
+ from ..app.error import Error
48
+ from ..app.metadata import Metadata
49
+
47
50
  # pylint: enable=E0611
48
51
  from . import (
49
52
  Array,
@@ -55,7 +58,7 @@ from . import (
55
58
  typing,
56
59
  )
57
60
  from .constant import INT64_MAX_VALUE
58
- from .message import Error, Message, Metadata, make_message
61
+ from .message import Message, make_message
59
62
  from .serde_utils import record_value_dict_from_proto, record_value_dict_to_proto
60
63
 
61
64
  # === Parameters message ===
@@ -0,0 +1,15 @@
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
+ """Compatibility package containing deprecated legacy components."""
@@ -0,0 +1,15 @@
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
+ """Legacy components previously located in ``flwr.client``."""
@@ -0,0 +1,15 @@
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
+ """Legacy components previously located in ``flwr.common``."""
@@ -0,0 +1,15 @@
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
+ """Legacy components previously located in ``flwr.server``."""
@@ -0,0 +1,15 @@
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
+ """Legacy components previously located in ``flwr.simulation``."""
@@ -26,6 +26,7 @@ from queue import Empty, Queue
26
26
  from time import sleep
27
27
  from typing import Callable, Optional
28
28
 
29
+ from flwr.app.error import Error
29
30
  from flwr.client.client_app import ClientApp, ClientAppException, LoadClientAppError
30
31
  from flwr.client.clientapp.utils import get_load_client_app_fn
31
32
  from flwr.client.run_info_store import DeprecatedRunInfoStore
@@ -37,7 +38,6 @@ from flwr.common.constant import (
37
38
  ErrorCode,
38
39
  )
39
40
  from flwr.common.logger import log
40
- from flwr.common.message import Error
41
41
  from flwr.common.typing import Run
42
42
  from flwr.server.superlink.linkstate import LinkState, LinkStateFactory
43
43
 
@@ -0,0 +1,15 @@
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
+ """Public Flower ServerApp APIs."""
@@ -0,0 +1,15 @@
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
+ """Infrastructure components shared between SuperLink and SuperNode."""
@@ -0,0 +1,15 @@
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
+ """Flower SuperLink."""
@@ -0,0 +1,15 @@
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
+ """Flower SuperNode."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: flwr-nightly
3
- Version: 1.19.0.dev20250515
3
+ Version: 1.19.0.dev20250520
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