flwr-nightly 1.26.0.dev20260122__py3-none-any.whl → 1.26.0.dev20260123__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/cli/config_utils.py CHANGED
@@ -114,57 +114,6 @@ def load(toml_path: Path) -> dict[str, Any] | None:
114
114
  return None
115
115
 
116
116
 
117
- def process_loaded_project_config(
118
- config: dict[str, Any] | None, errors: list[str], warnings: list[str]
119
- ) -> dict[str, Any]:
120
- """Process and return the loaded project configuration.
121
-
122
- This function handles errors and warnings from the `load_and_validate` function,
123
- exits on critical issues, and returns the validated configuration.
124
-
125
- Parameters
126
- ----------
127
- config : dict[str, Any] | None
128
- The loaded configuration dictionary, or None if loading failed.
129
- errors : list[str]
130
- List of error messages from validation.
131
- warnings : list[str]
132
- List of warning messages from validation.
133
-
134
- Returns
135
- -------
136
- dict[str, Any]
137
- The validated configuration dictionary.
138
-
139
- Raises
140
- ------
141
- typer.Exit
142
- If config is None or contains critical errors.
143
- """
144
- if config is None:
145
- typer.secho(
146
- "Project configuration could not be loaded.\n"
147
- "pyproject.toml is invalid:\n"
148
- + "\n".join([f"- {line}" for line in errors]),
149
- fg=typer.colors.RED,
150
- bold=True,
151
- err=True,
152
- )
153
- raise typer.Exit(code=1)
154
-
155
- if warnings:
156
- typer.secho(
157
- "Project configuration is missing the following "
158
- "recommended properties:\n" + "\n".join([f"- {line}" for line in warnings]),
159
- fg=typer.colors.RED,
160
- bold=True,
161
- )
162
-
163
- typer.secho("Success", fg=typer.colors.GREEN)
164
-
165
- return config
166
-
167
-
168
117
  def validate_federation_in_project_config(
169
118
  federation: str | None,
170
119
  config: dict[str, Any],
@@ -229,61 +178,6 @@ def validate_federation_in_project_config(
229
178
  return federation, federation_config
230
179
 
231
180
 
232
- def validate_certificate_in_federation_config(
233
- app: Path, federation_config: dict[str, Any]
234
- ) -> tuple[bool, bytes | None]:
235
- """Validate the certificates in the Flower project configuration.
236
-
237
- Accepted configurations:
238
- 1. TLS enabled and gRPC will load(*) the trusted certificate bundle:
239
- - Only `address` is provided. `root-certificates` and `insecure` not set.
240
- - `address` is provided and `insecure` set to `false`. `root-certificates` not
241
- set.
242
- (*)gRPC uses a multi-step fallback mechanism to load the trusted certificate
243
- bundle in the following sequence:
244
- a. A configured file path (if set via configuration or environment),
245
- b. An override callback (if registered via
246
- `grpc_set_ssl_roots_override_callback`),
247
- c. The OS trust store (if available),
248
- d. A bundled default certificate file.
249
- 2. TLS enabled with self-signed certificates:
250
- - `address` and `root-certificates` are provided. `insecure` not set.
251
- - `address` and `root-certificates` are provided. `insecure` set to `false`.
252
- 3. TLS disabled. This is not recommended and should only be used for prototyping:
253
- - `address` is provided and `insecure = true`. If `root-certificates` is
254
- set, exit with an error.
255
- """
256
- insecure = get_insecure_flag(federation_config)
257
-
258
- # Process root certificates
259
- if root_certificates := federation_config.get("root-certificates"):
260
- if insecure:
261
- typer.secho(
262
- "❌ `root-certificates` were provided but the `insecure` parameter "
263
- "is set to `True`.",
264
- fg=typer.colors.RED,
265
- bold=True,
266
- err=True,
267
- )
268
- raise typer.Exit(code=1)
269
-
270
- # TLS is enabled with self-signed certificates: attempt to read the file
271
- try:
272
- root_certificates_bytes = (app / root_certificates).read_bytes()
273
- except Exception as e:
274
- typer.secho(
275
- f"❌ Failed to read certificate file `{root_certificates}`: {e}",
276
- fg=typer.colors.RED,
277
- bold=True,
278
- err=True,
279
- )
280
- raise typer.Exit(code=1) from e
281
- else:
282
- root_certificates_bytes = None
283
-
284
- return insecure, root_certificates_bytes
285
-
286
-
287
181
  def load_certificate_in_connection(
288
182
  connection: SuperLinkConnection,
289
183
  ) -> bytes | None:
@@ -336,32 +230,6 @@ def load_certificate_in_connection(
336
230
  return root_certificates_bytes
337
231
 
338
232
 
339
- def exit_if_no_address(federation_config: dict[str, Any], cmd: str) -> None:
340
- """Exit if the provided federation_config has no "address" key.
341
-
342
- Parameters
343
- ----------
344
- federation_config : dict[str, Any]
345
- The federation configuration dictionary to check.
346
- cmd : str
347
- The command name to display in the error message.
348
-
349
- Raises
350
- ------
351
- typer.Exit
352
- If 'address' key is not present in federation_config.
353
- """
354
- if "address" not in federation_config:
355
- typer.secho(
356
- f"❌ `flwr {cmd}` currently works with a SuperLink. Ensure that the "
357
- "correct SuperLink (Control API) address is provided in `pyproject.toml`.",
358
- fg=typer.colors.RED,
359
- bold=True,
360
- err=True,
361
- )
362
- raise typer.Exit(code=1)
363
-
364
-
365
233
  def get_insecure_flag(federation_config: dict[str, Any]) -> bool:
366
234
  """Extract and validate the `insecure` flag from the federation configuration.
367
235
 
flwr/cli/utils.py CHANGED
@@ -20,7 +20,7 @@ import json
20
20
  from collections.abc import Callable, Iterable, Iterator
21
21
  from contextlib import contextmanager
22
22
  from pathlib import Path
23
- from typing import Any, cast
23
+ from typing import cast
24
24
 
25
25
  import click
26
26
  import grpc
@@ -50,10 +50,7 @@ from flwr.supercore.credential_store import get_credential_store
50
50
 
51
51
  from .auth_plugin import CliAuthPlugin, get_cli_plugin_class
52
52
  from .cli_account_auth_interceptor import CliAccountAuthInterceptor
53
- from .config_utils import (
54
- load_certificate_in_connection,
55
- validate_certificate_in_federation_config,
56
- )
53
+ from .config_utils import load_certificate_in_connection
57
54
  from .constant import AUTHN_TYPE_STORE_KEY
58
55
 
59
56
 
@@ -197,18 +194,6 @@ def get_authn_type(host: str) -> str:
197
194
  return authn_type.decode("utf-8")
198
195
 
199
196
 
200
- def load_cli_auth_plugin(
201
- root_dir: Path,
202
- federation: str,
203
- federation_config: dict[str, Any],
204
- authn_type: str | None = None,
205
- ) -> CliAuthPlugin:
206
- """."""
207
- raise RuntimeError(
208
- "Deprecated function. Use `load_cli_auth_plugin_from_connection`"
209
- )
210
-
211
-
212
197
  def load_cli_auth_plugin_from_connection(
213
198
  host: str, authn_type: str | None = None
214
199
  ) -> CliAuthPlugin:
@@ -246,44 +231,6 @@ def load_cli_auth_plugin_from_connection(
246
231
  raise typer.Exit(code=1) from None
247
232
 
248
233
 
249
- def init_channel(
250
- app: Path, federation_config: dict[str, Any], auth_plugin: CliAuthPlugin
251
- ) -> grpc.Channel:
252
- """Initialize gRPC channel to the Control API.
253
-
254
- Parameters
255
- ----------
256
- app : Path
257
- Path to the Flower app directory.
258
- federation_config : dict[str, Any]
259
- Federation configuration dictionary containing address and TLS settings.
260
- auth_plugin : CliAuthPlugin
261
- Authentication plugin instance for handling credentials.
262
-
263
- Returns
264
- -------
265
- grpc.Channel
266
- Configured gRPC channel with authentication interceptors.
267
- """
268
- insecure, root_certificates_bytes = validate_certificate_in_federation_config(
269
- app, federation_config
270
- )
271
-
272
- # Load tokens
273
- auth_plugin.load_tokens()
274
-
275
- # Create the gRPC channel
276
- channel = create_channel(
277
- server_address=federation_config["address"],
278
- insecure=insecure,
279
- root_certificates=root_certificates_bytes,
280
- max_message_length=GRPC_MAX_MESSAGE_LENGTH,
281
- interceptors=[CliAccountAuthInterceptor(auth_plugin)],
282
- )
283
- channel.subscribe(on_channel_state_change)
284
- return channel
285
-
286
-
287
234
  def require_superlink_address(connection: SuperLinkConnection) -> str:
288
235
  """Return the SuperLink address or exit if it is not configured."""
289
236
  if connection.address is None:
@@ -19,12 +19,10 @@ from .in_memory_linkstate import InMemoryLinkState as InMemoryLinkState
19
19
  from .linkstate import LinkState as LinkState
20
20
  from .linkstate_factory import LinkStateFactory as LinkStateFactory
21
21
  from .sql_linkstate import SqlLinkState as SqlLinkState
22
- from .sqlite_linkstate import SqliteLinkState as SqliteLinkState
23
22
 
24
23
  __all__ = [
25
24
  "InMemoryLinkState",
26
25
  "LinkState",
27
26
  "LinkStateFactory",
28
27
  "SqlLinkState",
29
- "SqliteLinkState",
30
28
  ]
@@ -22,7 +22,7 @@ from flwr.supercore.constant import FLWR_IN_MEMORY_DB_NAME
22
22
 
23
23
  from .in_memory_object_store import InMemoryObjectStore
24
24
  from .object_store import ObjectStore
25
- from .sqlite_object_store import SqliteObjectStore
25
+ from .sql_object_store import SqlObjectStore
26
26
 
27
27
 
28
28
  class ObjectStoreFactory:
@@ -56,8 +56,8 @@ class ObjectStoreFactory:
56
56
  log(DEBUG, "Using InMemoryObjectStore")
57
57
  return self.store_instance
58
58
 
59
- # SqliteObjectStore
60
- store = SqliteObjectStore(self.database)
59
+ # SqlObjectStore
60
+ store = SqlObjectStore(self.database)
61
61
  store.initialize()
62
- log(DEBUG, "Using SqliteObjectStore")
62
+ log(DEBUG, "Using SqlObjectStore")
63
63
  return store
@@ -17,11 +17,18 @@
17
17
 
18
18
  from sqlalchemy import MetaData
19
19
 
20
+ from flwr.common.inflatable import (
21
+ get_object_id,
22
+ is_valid_sha256_hash,
23
+ iterate_object_tree,
24
+ )
25
+ from flwr.common.inflatable_utils import validate_object_content
20
26
  from flwr.proto.message_pb2 import ObjectTree # pylint: disable=E0611
21
27
  from flwr.supercore.sql_mixin import SqlMixin
22
28
  from flwr.supercore.state.schema.objectstore_tables import create_objectstore_metadata
29
+ from flwr.supercore.utils import uint64_to_int64
23
30
 
24
- from .object_store import ObjectStore
31
+ from .object_store import NoObjectInStoreError, ObjectStore
25
32
 
26
33
 
27
34
  class SqlObjectStore(ObjectStore, SqlMixin):
@@ -37,15 +44,119 @@ class SqlObjectStore(ObjectStore, SqlMixin):
37
44
 
38
45
  def preregister(self, run_id: int, object_tree: ObjectTree) -> list[str]:
39
46
  """Identify and preregister missing objects in the `ObjectStore`."""
40
- raise NotImplementedError()
47
+ new_objects = []
48
+ for tree_node in iterate_object_tree(object_tree):
49
+ obj_id = tree_node.object_id
50
+ if not is_valid_sha256_hash(obj_id):
51
+ raise ValueError(f"Invalid object ID format: {obj_id}")
52
+
53
+ child_ids = [child.object_id for child in tree_node.children]
54
+ with self.session():
55
+ rows = self.query(
56
+ "SELECT object_id, is_available FROM objects "
57
+ "WHERE object_id = :object_id",
58
+ {"object_id": obj_id},
59
+ )
60
+ if not rows:
61
+ # Insert new object
62
+ self.query(
63
+ "INSERT INTO objects "
64
+ "(object_id, content, is_available, ref_count) "
65
+ "VALUES (:object_id, :content, :is_available, :ref_count)",
66
+ {
67
+ "object_id": obj_id,
68
+ "content": b"",
69
+ "is_available": 0,
70
+ "ref_count": 0,
71
+ },
72
+ )
73
+ for cid in child_ids:
74
+ self.query(
75
+ "INSERT INTO object_children (parent_id, child_id) "
76
+ "VALUES (:parent_id, :child_id)",
77
+ {"parent_id": obj_id, "child_id": cid},
78
+ )
79
+ self.query(
80
+ "UPDATE objects SET ref_count = ref_count + 1 "
81
+ "WHERE object_id = :object_id",
82
+ {"object_id": cid},
83
+ )
84
+ new_objects.append(obj_id)
85
+ else:
86
+ # Add to the list of new objects if not available
87
+ if not rows[0]["is_available"]:
88
+ new_objects.append(obj_id)
89
+
90
+ # Ensure run mapping
91
+ self.query(
92
+ "INSERT INTO run_objects (run_id, object_id) "
93
+ "VALUES (:run_id, :object_id) ON CONFLICT DO NOTHING",
94
+ {"run_id": uint64_to_int64(run_id), "object_id": obj_id},
95
+ )
96
+ return new_objects
41
97
 
42
98
  def get_object_tree(self, object_id: str) -> ObjectTree:
43
99
  """Get the object tree for a given object ID."""
44
- raise NotImplementedError()
100
+ with self.session():
101
+ rows = self.query(
102
+ "SELECT object_id FROM objects WHERE object_id = :object_id",
103
+ {"object_id": object_id},
104
+ )
105
+ if not rows:
106
+ raise NoObjectInStoreError(
107
+ f"Object {object_id} was not pre-registered."
108
+ )
109
+ children = self.query(
110
+ "SELECT child_id FROM object_children WHERE parent_id = :parent_id",
111
+ {"parent_id": object_id},
112
+ )
113
+
114
+ # Build the object trees of all children
115
+ try:
116
+ child_trees = [self.get_object_tree(ch["child_id"]) for ch in children]
117
+ except NoObjectInStoreError as e:
118
+ # Raise an error if any child object is missing
119
+ # This indicates an integrity issue
120
+ raise NoObjectInStoreError(
121
+ f"Object tree for object ID '{object_id}' contains missing "
122
+ "children. This may indicate a corrupted object store."
123
+ ) from e
124
+
125
+ # Create and return the ObjectTree for the current object
126
+ return ObjectTree(object_id=object_id, children=child_trees)
45
127
 
46
128
  def put(self, object_id: str, object_content: bytes) -> None:
47
129
  """Put an object into the store."""
48
- raise NotImplementedError()
130
+ if self.verify:
131
+ # Verify object_id and object_content match
132
+ object_id_from_content = get_object_id(object_content)
133
+ if object_id != object_id_from_content:
134
+ raise ValueError(f"Object ID {object_id} does not match content hash")
135
+
136
+ # Validate object content
137
+ validate_object_content(content=object_content)
138
+
139
+ with self.session():
140
+ # Only allow adding the object if it has been preregistered
141
+ rows = self.query(
142
+ "SELECT is_available FROM objects WHERE object_id = :object_id",
143
+ {"object_id": object_id},
144
+ )
145
+ if not rows:
146
+ raise NoObjectInStoreError(
147
+ f"Object with ID '{object_id}' was not pre-registered."
148
+ )
149
+
150
+ # Return if object is already present in the store
151
+ if rows[0]["is_available"]:
152
+ return
153
+
154
+ # Update the object entry in the store
155
+ self.query(
156
+ "UPDATE objects SET content = :content, is_available = 1 "
157
+ "WHERE object_id = :object_id",
158
+ {"content": object_content, "object_id": object_id},
159
+ )
49
160
 
50
161
  def get(self, object_id: str) -> bytes | None:
51
162
  """Get an object from the store."""
@@ -56,11 +167,65 @@ class SqlObjectStore(ObjectStore, SqlMixin):
56
167
 
57
168
  def delete(self, object_id: str) -> None:
58
169
  """Delete an object and its unreferenced descendants from the store."""
59
- raise NotImplementedError()
170
+ with self.session():
171
+ rows = self.query(
172
+ "SELECT ref_count FROM objects WHERE object_id = :object_id",
173
+ {"object_id": object_id},
174
+ )
175
+
176
+ # If the object is not in the store, nothing to delete
177
+ if not rows:
178
+ return
179
+
180
+ # Skip deletion if there are still references
181
+ if rows[0]["ref_count"] > 0:
182
+ return
183
+
184
+ # Deleting will cascade via FK, but we need to decrement children first
185
+ children = self.query(
186
+ "SELECT child_id FROM object_children WHERE parent_id = :parent_id",
187
+ {"parent_id": object_id},
188
+ )
189
+ child_ids = [child["child_id"] for child in children]
190
+
191
+ if child_ids:
192
+ placeholders = ", ".join(f":cid{i}" for i in range(len(child_ids)))
193
+ params = {f"cid{i}": cid for i, cid in enumerate(child_ids)}
194
+ self.query(
195
+ "UPDATE objects SET ref_count = ref_count - 1 "
196
+ f"WHERE object_id IN ({placeholders})",
197
+ params,
198
+ )
199
+
200
+ self.query(
201
+ "DELETE FROM objects WHERE object_id = :object_id",
202
+ {"object_id": object_id},
203
+ )
204
+
205
+ # Recursively clean children
206
+ for child_id in child_ids:
207
+ self.delete(child_id)
60
208
 
61
209
  def delete_objects_in_run(self, run_id: int) -> None:
62
210
  """Delete all objects that were registered in a specific run."""
63
- raise NotImplementedError()
211
+ run_id_sint = uint64_to_int64(run_id)
212
+ with self.session():
213
+ objs = self.query(
214
+ "SELECT object_id FROM run_objects WHERE run_id = :run_id",
215
+ {"run_id": run_id_sint},
216
+ )
217
+ for obj in objs:
218
+ object_id = obj["object_id"]
219
+ rows = self.query(
220
+ "SELECT ref_count FROM objects WHERE object_id=:object_id",
221
+ {"object_id": object_id},
222
+ )
223
+ if rows and rows[0]["ref_count"] == 0:
224
+ self.delete(object_id)
225
+ self.query(
226
+ "DELETE FROM run_objects WHERE run_id = :run_id",
227
+ {"run_id": run_id_sint},
228
+ )
64
229
 
65
230
  def clear(self) -> None:
66
231
  """Clear the store."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: flwr-nightly
3
- Version: 1.26.0.dev20260122
3
+ Version: 1.26.0.dev20260123
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
@@ -45,7 +45,7 @@ Requires-Dist: ray (==2.51.1) ; (python_version >= "3.10" and python_version < "
45
45
  Requires-Dist: ray (==2.51.1) ; (sys_platform != "win32" and python_version == "3.13") and (extra == "simulation")
46
46
  Requires-Dist: requests (>=2.31.0,<3.0.0)
47
47
  Requires-Dist: rich (>=13.5.0,<14.0.0)
48
- Requires-Dist: starlette (>=0.45.2,<0.46.0) ; extra == "rest"
48
+ Requires-Dist: starlette (>=0.47.2,<0.48.0) ; extra == "rest"
49
49
  Requires-Dist: tomli (>=2.0.1,<3.0.0)
50
50
  Requires-Dist: tomli-w (>=1.0.0,<2.0.0)
51
51
  Requires-Dist: typer (>=0.12.5,<0.21.0)
@@ -19,7 +19,7 @@ flwr/cli/cli_account_auth_interceptor.py,sha256=mXgxThpZjU_2Xlae9xT8ewOw60GeE64c
19
19
  flwr/cli/config/__init__.py,sha256=46z6whA3hvKkl9APRs-UG7Ym3K9VOqKx_pYcgelRjtE,788
20
20
  flwr/cli/config/ls.py,sha256=ktRga1KWt4IDK5TQNT6ixfP66zcspkf-F2j3CkkpsGo,3665
21
21
  flwr/cli/config_migration.py,sha256=UM3lZU34TOhGXkjBBChyGaE6r7uaVV2NpyP4TZhFPyY,10848
22
- flwr/cli/config_utils.py,sha256=PiYlb1bAwpxtMH3OQ7V0VeCATfX4gwhULpkfe61SRJI,12832
22
+ flwr/cli/config_utils.py,sha256=FR24Q07mo97u8Yv2HlMc78GG1RgDo5CUr3865xetTBo,8174
23
23
  flwr/cli/constant.py,sha256=Ihww6e-6V_Ocv7pRnIQeezdy72_RBL9dPYv87Yf4ppI,3612
24
24
  flwr/cli/example.py,sha256=SNTorkKPrx1rOryGREUyZu8TcOc1-vFv1zEddaysdY0,2216
25
25
  flwr/cli/federation/__init__.py,sha256=okxswL4fAjApI9gV_alU1lRkTUcQRbwlzvtUTLz61fE,793
@@ -42,7 +42,7 @@ flwr/cli/supernode/ls.py,sha256=x4ghJHpqcpDGuZx91ZehzSdmrUJ8ZuZvpY_UybnP63U,8224
42
42
  flwr/cli/supernode/register.py,sha256=b5tt6rPAA2t4cUBqnzcaCUJzy2uqKETSB43bGR5ltH0,5871
43
43
  flwr/cli/supernode/unregister.py,sha256=O72yiDuJaNrXx-5Pv6DKFxNYwxAHwEDBkAcqrlpwpC8,3949
44
44
  flwr/cli/typing.py,sha256=MaY3NAca2PgmNByogksDKSCoRQLQpXTgO8NO9nLP0yA,8008
45
- flwr/cli/utils.py,sha256=GYMI6JvLQ9MgU25au-nTdIFZg2ZViAUwF3t4Q3HHRTk,17870
45
+ flwr/cli/utils.py,sha256=JfYmWbkalOzRHykHZvnD8TGn1R3Epk-F-dhEyXmZAYM,16394
46
46
  flwr/client/__init__.py,sha256=xwkPJfdeWxIIfmiPE5vnmnY_JbTlErP0Qs9eBP6qRFg,1252
47
47
  flwr/client/client.py,sha256=3HAchxvknKG9jYbB7swNyDj-e5vUWDuMKoLvbT7jCVM,7895
48
48
  flwr/client/dpfedavg_numpy_client.py,sha256=ELDHyEJcTB-FlLhHC-JXy8HuB3ZFHfT0HL3g1VSWY5w,7451
@@ -268,12 +268,11 @@ flwr/server/superlink/fleet/vce/backend/__init__.py,sha256=PPH89Yqd1XKm-sRJN6R0W
268
268
  flwr/server/superlink/fleet/vce/backend/backend.py,sha256=HPOXhT40bFwCA9pz8w2sATdamgNVotXNO8p1ZRCOg7M,2205
269
269
  flwr/server/superlink/fleet/vce/backend/raybackend.py,sha256=LhVmM2Mi6kOskOyDFnbIb7AH304J0eUU1r2B32bzUFc,7193
270
270
  flwr/server/superlink/fleet/vce/vce_api.py,sha256=A62Vx3r71bNI-v10IUen_27fDJoYXsOyvBM3JrkTvho,13609
271
- flwr/server/superlink/linkstate/__init__.py,sha256=LUtanSPAyjGBZBg42u79Riqo08bF7Yhe_cYPtsOdsUs,1140
271
+ flwr/server/superlink/linkstate/__init__.py,sha256=KSUCjOfJlW1g6GAjlqK3mTviqLvJLuQEzSJwO27Qokg,1052
272
272
  flwr/server/superlink/linkstate/in_memory_linkstate.py,sha256=1-aaSwad77SeYND3HEF2041KNG5ZA-8i1RcheYZMNq8,31689
273
273
  flwr/server/superlink/linkstate/linkstate.py,sha256=Zz2vBI0QFFnptCUIeNjqQCbpCvMMzfsZluprEMkkHio,16809
274
274
  flwr/server/superlink/linkstate/linkstate_factory.py,sha256=BTzPIqrWa797YKdOEHt0iu4ujxRcK4FNvUgjsOYQfMs,2859
275
275
  flwr/server/superlink/linkstate/sql_linkstate.py,sha256=EJHS1SC5acaxRQb1Nmpjen3elDK6L93s8pDUXNAE_Wk,47782
276
- flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=vMhViLnRJoxc-TNFHY3YaRKybRdS1zNzORRwsve9MUQ,48458
277
276
  flwr/server/superlink/linkstate/utils.py,sha256=IA1mKKhGVBPoD61VXKFa8dZ_prnfuyWIuKAeeHPLmuE,16000
278
277
  flwr/server/superlink/serverappio/__init__.py,sha256=Fy4zJuoccZe5mZSEIpOmQvU6YeXFBa1M4eZuXXmJcn8,717
279
278
  flwr/server/superlink/serverappio/serverappio_grpc.py,sha256=2NFPynJMpYpT9C98Fr4n0QrTTjWBWbeUzlHcc6pg2kY,2279
@@ -334,7 +333,6 @@ flwr/supercore/corestate/__init__.py,sha256=Vau6-L_JG5QzNqtCTa9xCKGGljc09wY8avZm
334
333
  flwr/supercore/corestate/corestate.py,sha256=EZg4gPXqVOXwS7t0tlPfedajoWj5T80oeDBNxpV2y2I,2874
335
334
  flwr/supercore/corestate/in_memory_corestate.py,sha256=9qa6RuRZfCp6vs-ARYdiZjCL31VOAAxw0a_VkBXR5zY,5116
336
335
  flwr/supercore/corestate/sql_corestate.py,sha256=4cJOpAjMLe7nS5HbdQ3KcV-nK_kXVRazX05xVMtR6dw,5736
337
- flwr/supercore/corestate/sqlite_corestate.py,sha256=2SAikyNG0dgxOUtQsy9WS5XCDibndw6y4xPGK61seWE,5740
338
336
  flwr/supercore/credential_store/__init__.py,sha256=csDOy8YgD-DnmXc2HwatMfXqXATHe6OLsBPKtDndhXw,1077
339
337
  flwr/supercore/credential_store/credential_store.py,sha256=m_YHW0_A8CBfuRVq-GJgGNYDldxo9grT_jwJ8oCM9xA,1194
340
338
  flwr/supercore/credential_store/file_credential_store.py,sha256=PeWuigqtMGMYnj_tKnWtlmJtu7OLuVaOB4D9GS47lHc,2771
@@ -352,14 +350,12 @@ flwr/supercore/license_plugin/license_plugin.py,sha256=BFhlCH5v9KKuY7crVCsi8fuYe
352
350
  flwr/supercore/object_store/__init__.py,sha256=cdfPAmjINY6iOp8oI_LdcVh2simg469Mkdl4LLV4kHI,911
353
351
  flwr/supercore/object_store/in_memory_object_store.py,sha256=-DU6n1Ef3EmllHY9SzeXw57ftoU0mR_6or4NIDSZlcs,9322
354
352
  flwr/supercore/object_store/object_store.py,sha256=XLo-xe258TmCel9dNLCJepFjXaQtEi0wBqzU9YsyJVg,5221
355
- flwr/supercore/object_store/object_store_factory.py,sha256=vcLJP7nVuIoRuGNImePA-MK8QvH18FtThSZSniA3k6Y,2323
356
- flwr/supercore/object_store/sql_object_store.py,sha256=IvnVmYaVPXfC9_V1QxIX-IlsJZjoO-XI5DZILHrafxo,3206
357
- flwr/supercore/object_store/sqlite_object_store.py,sha256=oDfqGe6TEr1HT6_ZoxLoi7T1qEF2_GBKmfKh3yKux_Y,10251
353
+ flwr/supercore/object_store/object_store_factory.py,sha256=gFATFiSdKIcwL_sjk2OMbpi3Fb5_C6K3sdTRxNbi-SY,2308
354
+ flwr/supercore/object_store/sql_object_store.py,sha256=ZBmyc3a_GXZFNaefDCxhrri-_BgcQPOj7OtUfrPcjKo,10130
358
355
  flwr/supercore/primitives/__init__.py,sha256=Tx8GOjnmMo8Y74RsDGrMpfr-E0Nl8dcUDF784_ge6F8,745
359
356
  flwr/supercore/primitives/asymmetric.py,sha256=1643niHYj3uEbfPd06VuMHwN3tKVwg0uVyR3RhTdWIU,3778
360
357
  flwr/supercore/primitives/asymmetric_ed25519.py,sha256=eIhOTMibQW0FJX4MXdplHdL3HcfCiKuFu2mQ8GQTUz8,5025
361
358
  flwr/supercore/sql_mixin.py,sha256=eT4JHaLG4gShZrC10pkUVIGcTvZszlJI1ARhOJEA_WY,11727
362
- flwr/supercore/sqlite_mixin.py,sha256=KrHxJQlJSuTdfc8YlFTft-COzT6FvVtQDWAWkdJ-jGQ,5064
363
359
  flwr/supercore/state/__init__.py,sha256=FkKhsNVM4LjlRlOgXTz6twINmw5ohIUKS_OER0BNo_w,724
364
360
  flwr/supercore/state/schema/README.md,sha256=-0QrXDhnv30gEYoIUJo7aLUolY0r_t_nC24yk7B2agM,2892
365
361
  flwr/supercore/state/schema/__init__.py,sha256=Egnde6OY01wrpT4PuhL4NGn_NY4jdAH7kf7ktagN4Ws,724
@@ -406,7 +402,7 @@ flwr/supernode/servicer/__init__.py,sha256=lucTzre5WPK7G1YLCfaqg3rbFWdNSb7ZTt-ca
406
402
  flwr/supernode/servicer/clientappio/__init__.py,sha256=7Oy62Y_oijqF7Dxi6tpcUQyOpLc_QpIRZ83NvwmB0Yg,813
407
403
  flwr/supernode/servicer/clientappio/clientappio_servicer.py,sha256=rRL4CQ0L78jF_p0ct4-JMGREt6wWRy__wy4czF4f54Y,11639
408
404
  flwr/supernode/start_client_internal.py,sha256=BYk69UBQ2gQJaDQxXhccUgfOWrb7ShAstrbcMOCZIIs,26173
409
- flwr_nightly-1.26.0.dev20260122.dist-info/METADATA,sha256=zBLPqvPPLqx7oTD3iaRZhDRChLOjlM2pG_WKqB9USG4,14398
410
- flwr_nightly-1.26.0.dev20260122.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
411
- flwr_nightly-1.26.0.dev20260122.dist-info/entry_points.txt,sha256=hxHD2ixb_vJFDOlZV-zB4Ao32_BQlL34ftsDh1GXv14,420
412
- flwr_nightly-1.26.0.dev20260122.dist-info/RECORD,,
405
+ flwr_nightly-1.26.0.dev20260123.dist-info/METADATA,sha256=6qgGCPCTOXXGCDUea3DHh770_NI9PSfIsF_sVY_ET-4,14398
406
+ flwr_nightly-1.26.0.dev20260123.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
407
+ flwr_nightly-1.26.0.dev20260123.dist-info/entry_points.txt,sha256=hxHD2ixb_vJFDOlZV-zB4Ao32_BQlL34ftsDh1GXv14,420
408
+ flwr_nightly-1.26.0.dev20260123.dist-info/RECORD,,