flwr-nightly 1.26.0.dev20260126__py3-none-any.whl → 1.26.0.dev20260128__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/app.py +0 -2
- flwr/cli/config/ls.py +1 -1
- flwr/cli/config_migration.py +4 -4
- flwr/cli/constant.py +0 -3
- flwr/cli/federation/ls.py +1 -1
- flwr/cli/flower_config.py +0 -4
- flwr/cli/login/login.py +0 -8
- flwr/cli/ls.py +1 -1
- flwr/cli/supernode/ls.py +1 -1
- flwr/cli/typing.py +10 -24
- flwr/cli/utils.py +7 -3
- flwr/common/exit/exit_code.py +6 -0
- flwr/common/typing.py +2 -0
- flwr/proto/federation_pb2.py +5 -3
- flwr/proto/federation_pb2.pyi +23 -1
- flwr/server/app.py +4 -11
- flwr/server/superlink/fleet/message_handler/message_handler.py +2 -1
- flwr/supercore/address.py +9 -0
- flwr/supercore/app_utils.py +2 -1
- flwr/supercore/constant.py +3 -0
- flwr/supercore/sql_mixin.py +2 -2
- flwr/supercore/state/alembic/__init__.py +15 -0
- flwr/supercore/state/alembic/env.py +81 -0
- flwr/supercore/state/alembic/script.py.mako +43 -0
- flwr/supercore/state/alembic/utils.py +49 -0
- flwr/supercore/state/alembic/versions/__init__.py +15 -0
- flwr/supercore/state/alembic/versions/rev_2026_01_28_initialize_migration_of_state_tables.py +200 -0
- flwr/supercore/state/schema/README.md +2 -6
- flwr/supercore/utils.py +21 -0
- flwr/superlink/federation/noop_federation_manager.py +3 -1
- flwr/supernode/start_client_internal.py +5 -2
- {flwr_nightly-1.26.0.dev20260126.dist-info → flwr_nightly-1.26.0.dev20260128.dist-info}/METADATA +2 -1
- {flwr_nightly-1.26.0.dev20260126.dist-info → flwr_nightly-1.26.0.dev20260128.dist-info}/RECORD +35 -29
- {flwr_nightly-1.26.0.dev20260126.dist-info → flwr_nightly-1.26.0.dev20260128.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.26.0.dev20260126.dist-info → flwr_nightly-1.26.0.dev20260128.dist-info}/entry_points.txt +0 -0
flwr/cli/app.py
CHANGED
|
@@ -27,7 +27,6 @@ from .app_cmd import review as app_review
|
|
|
27
27
|
from .build import build
|
|
28
28
|
from .config import ls as config_list
|
|
29
29
|
from .federation import ls as federation_list
|
|
30
|
-
from .flower_config import init_flwr_config
|
|
31
30
|
from .install import install
|
|
32
31
|
from .log import log
|
|
33
32
|
from .login import login
|
|
@@ -115,7 +114,6 @@ def main(
|
|
|
115
114
|
),
|
|
116
115
|
) -> None:
|
|
117
116
|
"""Flower CLI."""
|
|
118
|
-
init_flwr_config()
|
|
119
117
|
if version:
|
|
120
118
|
typer.secho(f"Flower version: {package_version}", fg="blue")
|
|
121
119
|
raise typer.Exit()
|
flwr/cli/config/ls.py
CHANGED
|
@@ -40,7 +40,7 @@ def ls(
|
|
|
40
40
|
),
|
|
41
41
|
] = CliOutputFormat.DEFAULT,
|
|
42
42
|
) -> None:
|
|
43
|
-
"""List all SuperLink connections."""
|
|
43
|
+
"""List all SuperLink connections (alias: ls)."""
|
|
44
44
|
suppress_output = output_format == CliOutputFormat.JSON
|
|
45
45
|
captured_output = io.StringIO()
|
|
46
46
|
config_path = None
|
flwr/cli/config_migration.py
CHANGED
|
@@ -31,7 +31,7 @@ from .flower_config import (
|
|
|
31
31
|
)
|
|
32
32
|
|
|
33
33
|
CONFIG_MIGRATION_NOTICE = """
|
|
34
|
-
|
|
34
|
+
#######################################################################
|
|
35
35
|
# CONFIGURATION MIGRATION NOTICE:
|
|
36
36
|
#
|
|
37
37
|
# What was previously called "federation config" for SuperLink
|
|
@@ -43,8 +43,8 @@ CONFIG_MIGRATION_NOTICE = """
|
|
|
43
43
|
# The entries below are commented out intentionally and are kept
|
|
44
44
|
# only as a migration reference.
|
|
45
45
|
#
|
|
46
|
-
# Docs:
|
|
47
|
-
|
|
46
|
+
# Docs: https://flower.ai/docs/framework/ref-flower-configuration.html
|
|
47
|
+
#######################################################################
|
|
48
48
|
|
|
49
49
|
"""
|
|
50
50
|
|
|
@@ -53,7 +53,7 @@ CLI_NOTICE = (
|
|
|
53
53
|
+ "We detected legacy usage of this command that relies on connection\n"
|
|
54
54
|
+ "settings from your pyproject.toml.\n\n"
|
|
55
55
|
+ "Flower will migrate any relevant settings to the new Flower config.\n\n"
|
|
56
|
-
+ "Learn more: https://flower.ai/docs\n"
|
|
56
|
+
+ "Learn more: https://flower.ai/docs/framework/ref-flower-configuration.html\n"
|
|
57
57
|
)
|
|
58
58
|
|
|
59
59
|
|
flwr/cli/constant.py
CHANGED
|
@@ -57,7 +57,6 @@ class SuperLinkConnectionTomlKey:
|
|
|
57
57
|
ADDRESS = "address"
|
|
58
58
|
ROOT_CERTIFICATES = "root-certificates"
|
|
59
59
|
INSECURE = "insecure"
|
|
60
|
-
ENABLE_ACCOUNT_AUTH = "enable-account-auth"
|
|
61
60
|
FEDERATION = "federation"
|
|
62
61
|
OPTIONS = "options"
|
|
63
62
|
|
|
@@ -102,8 +101,6 @@ default = "local"
|
|
|
102
101
|
|
|
103
102
|
[superlink.supergrid]
|
|
104
103
|
address = "{SUPERGRID_ADDRESS}"
|
|
105
|
-
enable-account-auth = true
|
|
106
|
-
federation = "YOUR-FEDERATION-HERE"
|
|
107
104
|
|
|
108
105
|
[superlink.local]
|
|
109
106
|
options.num-supernodes = 10
|
flwr/cli/federation/ls.py
CHANGED
|
@@ -68,7 +68,7 @@ def ls( # pylint: disable=R0914, R0913, R0917, R0912
|
|
|
68
68
|
),
|
|
69
69
|
] = None,
|
|
70
70
|
) -> None:
|
|
71
|
-
"""List available federations."""
|
|
71
|
+
"""List available federations or details of a specific federation (alias: ls)."""
|
|
72
72
|
suppress_output = output_format == CliOutputFormat.JSON
|
|
73
73
|
captured_output = io.StringIO()
|
|
74
74
|
|
flwr/cli/flower_config.py
CHANGED
|
@@ -195,9 +195,6 @@ def parse_superlink_connection(
|
|
|
195
195
|
address=conn_dict.get(SuperLinkConnectionTomlKey.ADDRESS),
|
|
196
196
|
root_certificates=conn_dict.get(SuperLinkConnectionTomlKey.ROOT_CERTIFICATES),
|
|
197
197
|
insecure=conn_dict.get(SuperLinkConnectionTomlKey.INSECURE),
|
|
198
|
-
enable_account_auth=conn_dict.get(
|
|
199
|
-
SuperLinkConnectionTomlKey.ENABLE_ACCOUNT_AUTH
|
|
200
|
-
),
|
|
201
198
|
federation=conn_dict.get(SuperLinkConnectionTomlKey.FEDERATION),
|
|
202
199
|
options=simulation_options,
|
|
203
200
|
)
|
|
@@ -221,7 +218,6 @@ def serialize_superlink_connection(connection: SuperLinkConnection) -> dict[str,
|
|
|
221
218
|
SuperLinkConnectionTomlKey.ADDRESS: connection.address,
|
|
222
219
|
SuperLinkConnectionTomlKey.ROOT_CERTIFICATES: connection.root_certificates,
|
|
223
220
|
SuperLinkConnectionTomlKey.INSECURE: connection._insecure,
|
|
224
|
-
SuperLinkConnectionTomlKey.ENABLE_ACCOUNT_AUTH: connection._enable_account_auth,
|
|
225
221
|
SuperLinkConnectionTomlKey.FEDERATION: connection.federation,
|
|
226
222
|
}
|
|
227
223
|
# Remove None values
|
flwr/cli/login/login.py
CHANGED
|
@@ -61,14 +61,6 @@ def login(
|
|
|
61
61
|
superlink_connection = read_superlink_connection(superlink)
|
|
62
62
|
superlink = superlink_connection.name
|
|
63
63
|
|
|
64
|
-
# Check if `enable-account-auth` is set to `true`
|
|
65
|
-
if not superlink_connection.enable_account_auth:
|
|
66
|
-
raise click.ClickException(
|
|
67
|
-
"Account authentication is not enabled for the SuperLink connection "
|
|
68
|
-
f"'{superlink}'. To enable it, set `enable-account-auth = true` "
|
|
69
|
-
"in the configuration."
|
|
70
|
-
)
|
|
71
|
-
|
|
72
64
|
# Check if insecure flag is set to `True`
|
|
73
65
|
if superlink_connection.insecure:
|
|
74
66
|
raise click.ClickException(
|
flwr/cli/ls.py
CHANGED
|
@@ -79,7 +79,7 @@ def ls( # pylint: disable=too-many-locals, too-many-branches, R0913, R0917
|
|
|
79
79
|
),
|
|
80
80
|
] = CliOutputFormat.DEFAULT,
|
|
81
81
|
) -> None:
|
|
82
|
-
"""List the details of one provided run ID or all runs
|
|
82
|
+
"""List the details of one provided run ID or all runs (alias: ls).
|
|
83
83
|
|
|
84
84
|
The following details are displayed:
|
|
85
85
|
|
flwr/cli/supernode/ls.py
CHANGED
|
@@ -66,7 +66,7 @@ def ls( # pylint: disable=R0914, R0913, R0917
|
|
|
66
66
|
),
|
|
67
67
|
] = False,
|
|
68
68
|
) -> None:
|
|
69
|
-
"""List SuperNodes in the federation."""
|
|
69
|
+
"""List SuperNodes in the federation (alias: ls)."""
|
|
70
70
|
suppress_output = output_format == CliOutputFormat.JSON
|
|
71
71
|
captured_output = io.StringIO()
|
|
72
72
|
|
flwr/cli/typing.py
CHANGED
|
@@ -22,6 +22,7 @@ from flwr.cli.constant import (
|
|
|
22
22
|
DEFAULT_SIMULATION_BACKEND_NAME,
|
|
23
23
|
SuperLinkConnectionTomlKey,
|
|
24
24
|
)
|
|
25
|
+
from flwr.supercore.utils import check_federation_format
|
|
25
26
|
|
|
26
27
|
_ERROR_MSG_FMT = "SuperLinkConnection.%s is None"
|
|
27
28
|
|
|
@@ -106,8 +107,6 @@ class SuperLinkConnection:
|
|
|
106
107
|
insecure : bool (default: False)
|
|
107
108
|
Whether to use an insecure channel. If True, the
|
|
108
109
|
connection will not use TLS encryption.
|
|
109
|
-
enable_account_auth : bool (default: False)
|
|
110
|
-
Whether to enable account authentication.
|
|
111
110
|
federation : str
|
|
112
111
|
The name of the federation to interface with.
|
|
113
112
|
options : SuperLinkSimulationOptions
|
|
@@ -118,7 +117,6 @@ class SuperLinkConnection:
|
|
|
118
117
|
address: str | None = None
|
|
119
118
|
root_certificates: str | None = None
|
|
120
119
|
_insecure: bool | None = None
|
|
121
|
-
_enable_account_auth: bool | None = None
|
|
122
120
|
federation: str | None = None
|
|
123
121
|
options: SuperLinkSimulationOptions | None = None
|
|
124
122
|
|
|
@@ -129,7 +127,6 @@ class SuperLinkConnection:
|
|
|
129
127
|
address: str | None = None,
|
|
130
128
|
root_certificates: str | None = None,
|
|
131
129
|
insecure: bool | None = None,
|
|
132
|
-
enable_account_auth: bool | None = None,
|
|
133
130
|
federation: str | None = None,
|
|
134
131
|
options: SuperLinkSimulationOptions | None = None,
|
|
135
132
|
) -> None:
|
|
@@ -137,7 +134,6 @@ class SuperLinkConnection:
|
|
|
137
134
|
self.address = address
|
|
138
135
|
self.root_certificates = root_certificates
|
|
139
136
|
self._insecure = insecure
|
|
140
|
-
self._enable_account_auth = enable_account_auth
|
|
141
137
|
self.federation = federation
|
|
142
138
|
self.options = options
|
|
143
139
|
|
|
@@ -150,13 +146,6 @@ class SuperLinkConnection:
|
|
|
150
146
|
return False
|
|
151
147
|
return self._insecure
|
|
152
148
|
|
|
153
|
-
@property
|
|
154
|
-
def enable_account_auth(self) -> bool:
|
|
155
|
-
"""Return the enable_account_auth flag or its default (False) if unset."""
|
|
156
|
-
if self._enable_account_auth is None:
|
|
157
|
-
return False
|
|
158
|
-
return self._enable_account_auth
|
|
159
|
-
|
|
160
149
|
def __post_init__(self) -> None:
|
|
161
150
|
"""Validate SuperLink connection configuration."""
|
|
162
151
|
err_prefix = f"Invalid value for key '%s' in connection '{self.name}': "
|
|
@@ -187,19 +176,16 @@ class SuperLinkConnection:
|
|
|
187
176
|
err_prefix % SuperLinkConnectionTomlKey.INSECURE
|
|
188
177
|
+ f"expected bool, but got {type(self._insecure).__name__}."
|
|
189
178
|
)
|
|
190
|
-
if self._enable_account_auth is not None and not isinstance(
|
|
191
|
-
self._enable_account_auth, bool
|
|
192
|
-
):
|
|
193
|
-
raise ValueError(
|
|
194
|
-
err_prefix % SuperLinkConnectionTomlKey.ENABLE_ACCOUNT_AUTH
|
|
195
|
-
+ f"expected bool, but got {type(self._enable_account_auth).__name__}."
|
|
196
|
-
)
|
|
197
179
|
|
|
198
|
-
if self.federation is not None
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
180
|
+
if self.federation is not None:
|
|
181
|
+
if not isinstance(self.federation, str):
|
|
182
|
+
raise ValueError(
|
|
183
|
+
err_prefix % SuperLinkConnectionTomlKey.FEDERATION
|
|
184
|
+
+ f"expected str, but got {type(self.federation).__name__}."
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Check if the federation string is valid
|
|
188
|
+
check_federation_format(self.federation)
|
|
203
189
|
|
|
204
190
|
# The connection needs to have either an address or options (or both).
|
|
205
191
|
if self.address is None and self.options is None:
|
flwr/cli/utils.py
CHANGED
|
@@ -241,7 +241,9 @@ def require_superlink_address(connection: SuperLinkConnection) -> str:
|
|
|
241
241
|
cmd = click.get_current_context().command.name
|
|
242
242
|
raise click.ClickException(
|
|
243
243
|
f"`flwr {cmd}` currently works with a SuperLink. Ensure that the "
|
|
244
|
-
"correct SuperLink (Control API) address is provided
|
|
244
|
+
"correct SuperLink (Control API) address is provided SuperLink connection "
|
|
245
|
+
"you are using. Check your Flower configuration file. You may use `flwr "
|
|
246
|
+
"config list` to see its location in the file system."
|
|
245
247
|
)
|
|
246
248
|
return connection.address
|
|
247
249
|
|
|
@@ -326,8 +328,10 @@ def flwr_cli_grpc_exc_handler() -> Iterator[None]: # pylint: disable=too-many-b
|
|
|
326
328
|
raise click.ClickException(
|
|
327
329
|
"The SuperLink cannot process this request. Please verify that "
|
|
328
330
|
"you set the address to its Control API endpoint correctly in your "
|
|
329
|
-
"
|
|
330
|
-
"
|
|
331
|
+
"SuperLink connection in your Flower Configuration file. You may use "
|
|
332
|
+
"`flwr config list` to see its location in the file system. "
|
|
333
|
+
"Additonally, ensure that the Flower versions used by the CLI and "
|
|
334
|
+
"SuperLink are compatible."
|
|
331
335
|
) from None
|
|
332
336
|
if e.code() == grpc.StatusCode.PERMISSION_DENIED:
|
|
333
337
|
# pylint: disable-next=E1101
|
flwr/common/exit/exit_code.py
CHANGED
|
@@ -33,6 +33,7 @@ class ExitCode:
|
|
|
33
33
|
SUPERLINK_LICENSE_MISSING = 102
|
|
34
34
|
SUPERLINK_LICENSE_URL_INVALID = 103
|
|
35
35
|
SUPERLINK_INVALID_ARGS = 104
|
|
36
|
+
SUPERLINK_DATABASE_SCHEMA_MISMATCH = 105
|
|
36
37
|
|
|
37
38
|
# ServerApp-specific exit codes (200-299)
|
|
38
39
|
SERVERAPP_STRATEGY_PRECONDITION_UNMET = 200
|
|
@@ -91,6 +92,11 @@ EXIT_CODE_HELP = {
|
|
|
91
92
|
"Invalid arguments provided to SuperLink. Use `--help` check for the correct "
|
|
92
93
|
"usage. Alternatively, check the documentation."
|
|
93
94
|
),
|
|
95
|
+
ExitCode.SUPERLINK_DATABASE_SCHEMA_MISMATCH: (
|
|
96
|
+
"The database schema does not match the expected schema for this version of "
|
|
97
|
+
"SuperLink. Please refer to the documentation for guidance on how to resolve "
|
|
98
|
+
"this issue."
|
|
99
|
+
),
|
|
94
100
|
# ServerApp-specific exit codes (200-299)
|
|
95
101
|
ExitCode.SERVERAPP_STRATEGY_PRECONDITION_UNMET: (
|
|
96
102
|
"The strategy received replies that cannot be aggregated. Please ensure all "
|
flwr/common/typing.py
CHANGED
|
@@ -24,6 +24,7 @@ import numpy as np
|
|
|
24
24
|
import numpy.typing as npt
|
|
25
25
|
|
|
26
26
|
from flwr.app.user_config import UserConfig
|
|
27
|
+
from flwr.proto.federation_pb2 import Account # pylint: disable=E0611
|
|
27
28
|
from flwr.proto.node_pb2 import NodeInfo # pylint: disable=E0611
|
|
28
29
|
|
|
29
30
|
NDArray = npt.NDArray[Any]
|
|
@@ -343,5 +344,6 @@ class Federation:
|
|
|
343
344
|
|
|
344
345
|
name: str
|
|
345
346
|
member_aids: list[str]
|
|
347
|
+
accounts: list[Account]
|
|
346
348
|
nodes: list[NodeInfo]
|
|
347
349
|
runs: list[Run]
|
flwr/proto/federation_pb2.py
CHANGED
|
@@ -26,13 +26,15 @@ from flwr.proto import run_pb2 as flwr_dot_proto_dot_run__pb2
|
|
|
26
26
|
from flwr.proto import node_pb2 as flwr_dot_proto_dot_node__pb2
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1b\x66lwr/proto/federation.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x15\x66lwr/proto/node.proto\"
|
|
29
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1b\x66lwr/proto/federation.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x15\x66lwr/proto/node.proto\"#\n\x07\x41\x63\x63ount\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\"\x9a\x01\n\nFederation\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0bmember_aids\x18\x02 \x03(\t\x12%\n\x08\x61\x63\x63ounts\x18\x03 \x03(\x0b\x32\x13.flwr.proto.Account\x12#\n\x05nodes\x18\x04 \x03(\x0b\x32\x14.flwr.proto.NodeInfo\x12\x1d\n\x04runs\x18\x05 \x03(\x0b\x32\x0f.flwr.proto.Runb\x06proto3')
|
|
30
30
|
|
|
31
31
|
_globals = globals()
|
|
32
32
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
33
33
|
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flwr.proto.federation_pb2', _globals)
|
|
34
34
|
if not _descriptor._USE_C_DESCRIPTORS:
|
|
35
35
|
DESCRIPTOR._loaded_options = None
|
|
36
|
-
_globals['
|
|
37
|
-
_globals['
|
|
36
|
+
_globals['_ACCOUNT']._serialized_start=88
|
|
37
|
+
_globals['_ACCOUNT']._serialized_end=123
|
|
38
|
+
_globals['_FEDERATION']._serialized_start=126
|
|
39
|
+
_globals['_FEDERATION']._serialized_end=280
|
|
38
40
|
# @@protoc_insertion_point(module_scope)
|
flwr/proto/federation_pb2.pyi
CHANGED
|
@@ -28,18 +28,39 @@ import typing
|
|
|
28
28
|
|
|
29
29
|
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
|
|
30
30
|
|
|
31
|
+
@typing.final
|
|
32
|
+
class Account(google.protobuf.message.Message):
|
|
33
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
34
|
+
|
|
35
|
+
ID_FIELD_NUMBER: builtins.int
|
|
36
|
+
NAME_FIELD_NUMBER: builtins.int
|
|
37
|
+
id: builtins.str
|
|
38
|
+
name: builtins.str
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
*,
|
|
42
|
+
id: builtins.str = ...,
|
|
43
|
+
name: builtins.str = ...,
|
|
44
|
+
) -> None: ...
|
|
45
|
+
def ClearField(self, field_name: typing.Literal["id", b"id", "name", b"name"]) -> None: ...
|
|
46
|
+
|
|
47
|
+
global___Account = Account
|
|
48
|
+
|
|
31
49
|
@typing.final
|
|
32
50
|
class Federation(google.protobuf.message.Message):
|
|
33
51
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
34
52
|
|
|
35
53
|
NAME_FIELD_NUMBER: builtins.int
|
|
36
54
|
MEMBER_AIDS_FIELD_NUMBER: builtins.int
|
|
55
|
+
ACCOUNTS_FIELD_NUMBER: builtins.int
|
|
37
56
|
NODES_FIELD_NUMBER: builtins.int
|
|
38
57
|
RUNS_FIELD_NUMBER: builtins.int
|
|
39
58
|
name: builtins.str
|
|
40
59
|
@property
|
|
41
60
|
def member_aids(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
|
|
42
61
|
@property
|
|
62
|
+
def accounts(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___Account]: ...
|
|
63
|
+
@property
|
|
43
64
|
def nodes(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[flwr.proto.node_pb2.NodeInfo]: ...
|
|
44
65
|
@property
|
|
45
66
|
def runs(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[flwr.proto.run_pb2.Run]: ...
|
|
@@ -48,9 +69,10 @@ class Federation(google.protobuf.message.Message):
|
|
|
48
69
|
*,
|
|
49
70
|
name: builtins.str = ...,
|
|
50
71
|
member_aids: collections.abc.Iterable[builtins.str] | None = ...,
|
|
72
|
+
accounts: collections.abc.Iterable[global___Account] | None = ...,
|
|
51
73
|
nodes: collections.abc.Iterable[flwr.proto.node_pb2.NodeInfo] | None = ...,
|
|
52
74
|
runs: collections.abc.Iterable[flwr.proto.run_pb2.Run] | None = ...,
|
|
53
75
|
) -> None: ...
|
|
54
|
-
def ClearField(self, field_name: typing.Literal["member_aids", b"member_aids", "name", b"name", "nodes", b"nodes", "runs", b"runs"]) -> None: ...
|
|
76
|
+
def ClearField(self, field_name: typing.Literal["accounts", b"accounts", "member_aids", b"member_aids", "name", b"name", "nodes", b"nodes", "runs", b"runs"]) -> None: ...
|
|
55
77
|
|
|
56
78
|
global___Federation = Federation
|
flwr/server/app.py
CHANGED
|
@@ -36,13 +36,11 @@ from flwr.common.config import get_flwr_dir
|
|
|
36
36
|
from flwr.common.constant import (
|
|
37
37
|
AUTHN_TYPE_YAML_KEY,
|
|
38
38
|
AUTHZ_TYPE_YAML_KEY,
|
|
39
|
-
CLIENT_OCTET,
|
|
40
39
|
CONTROL_API_DEFAULT_SERVER_ADDRESS,
|
|
41
40
|
FLEET_API_GRPC_RERE_DEFAULT_ADDRESS,
|
|
42
41
|
FLEET_API_REST_DEFAULT_ADDRESS,
|
|
43
42
|
ISOLATION_MODE_PROCESS,
|
|
44
43
|
ISOLATION_MODE_SUBPROCESS,
|
|
45
|
-
SERVER_OCTET,
|
|
46
44
|
SERVERAPPIO_API_DEFAULT_SERVER_ADDRESS,
|
|
47
45
|
SIMULATIONIO_API_DEFAULT_SERVER_ADDRESS,
|
|
48
46
|
TRANSPORT_TYPE_GRPC_ADAPTER,
|
|
@@ -62,7 +60,7 @@ from flwr.proto.fleet_pb2_grpc import ( # pylint: disable=E0611
|
|
|
62
60
|
)
|
|
63
61
|
from flwr.proto.grpcadapter_pb2_grpc import add_GrpcAdapterServicer_to_server
|
|
64
62
|
from flwr.server.fleet_event_log_interceptor import FleetEventLogInterceptor
|
|
65
|
-
from flwr.supercore.address import parse_address
|
|
63
|
+
from flwr.supercore.address import parse_address, resolve_bind_address
|
|
66
64
|
from flwr.supercore.constant import FLWR_IN_MEMORY_DB_NAME
|
|
67
65
|
from flwr.supercore.ffs import FfsFactory
|
|
68
66
|
from flwr.supercore.grpc_health import add_args_health, run_health_server_grpc_no_tls
|
|
@@ -429,16 +427,11 @@ def run_superlink() -> None:
|
|
|
429
427
|
raise ValueError(f"Unknown fleet_api_type: {args.fleet_api_type}")
|
|
430
428
|
|
|
431
429
|
if args.isolation == ISOLATION_MODE_SUBPROCESS:
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
io_address = (
|
|
435
|
-
f"{CLIENT_OCTET}:{_port}" if _octet == SERVER_OCTET else serverappio_address
|
|
430
|
+
appio_address = resolve_bind_address(
|
|
431
|
+
simulationio_address if is_simulation else serverappio_address
|
|
436
432
|
)
|
|
437
433
|
command = ["flower-superexec", "--insecure"]
|
|
438
|
-
command += [
|
|
439
|
-
"--appio-api-address",
|
|
440
|
-
simulationio_address if is_simulation else io_address,
|
|
441
|
-
]
|
|
434
|
+
command += ["--appio-api-address", appio_address]
|
|
442
435
|
command += [
|
|
443
436
|
"--plugin-type",
|
|
444
437
|
ExecPluginType.SIMULATION if is_simulation else ExecPluginType.SERVER_APP,
|
|
@@ -321,7 +321,8 @@ def pull_object(
|
|
|
321
321
|
if content is not None:
|
|
322
322
|
object_available = content != b""
|
|
323
323
|
# Record bytes traffic pulled by SuperNode
|
|
324
|
-
|
|
324
|
+
if object_available:
|
|
325
|
+
state.store_traffic(request.run_id, bytes_sent=len(content), bytes_recv=0)
|
|
325
326
|
return PullObjectResponse(
|
|
326
327
|
object_found=True,
|
|
327
328
|
object_available=object_available,
|
flwr/supercore/address.py
CHANGED
|
@@ -100,3 +100,12 @@ def is_port_in_use(address: str) -> bool:
|
|
|
100
100
|
return True
|
|
101
101
|
|
|
102
102
|
return False
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def resolve_bind_address(address: str) -> str:
|
|
106
|
+
"""Replace bind-all addresses (0.0.0.0, ::) with localhost (127.0.0.1, ::1)."""
|
|
107
|
+
if address.startswith("[::]"):
|
|
108
|
+
return address.replace("[::]", "[::1]", 1)
|
|
109
|
+
if address.startswith("0.0.0.0"):
|
|
110
|
+
return address.replace("0.0.0.0", "127.0.0.1", 1)
|
|
111
|
+
return address
|
flwr/supercore/app_utils.py
CHANGED
flwr/supercore/constant.py
CHANGED
|
@@ -25,6 +25,9 @@ EXEC_PLUGIN_SECTION = "exec_plugin"
|
|
|
25
25
|
# Flower in-memory Python-based database name
|
|
26
26
|
FLWR_IN_MEMORY_DB_NAME = ":flwr-in-memory:"
|
|
27
27
|
|
|
28
|
+
# Flower in-memory SQLite database URL
|
|
29
|
+
FLWR_IN_MEMORY_SQLITE_DB_URL = "sqlite:///:memory:"
|
|
30
|
+
|
|
28
31
|
# Constants for Hub
|
|
29
32
|
APP_ID_PATTERN = r"^@[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$"
|
|
30
33
|
APP_VERSION_PATTERN = r"^\d+\.\d+\.\d+$"
|
flwr/supercore/sql_mixin.py
CHANGED
|
@@ -29,7 +29,7 @@ from sqlalchemy.exc import SQLAlchemyError
|
|
|
29
29
|
from sqlalchemy.orm import Session, sessionmaker
|
|
30
30
|
|
|
31
31
|
from flwr.common.logger import log
|
|
32
|
-
from flwr.supercore.constant import SQLITE_PRAGMAS
|
|
32
|
+
from flwr.supercore.constant import FLWR_IN_MEMORY_SQLITE_DB_URL, SQLITE_PRAGMAS
|
|
33
33
|
|
|
34
34
|
_current_session: ContextVar[Session | None] = ContextVar(
|
|
35
35
|
"current_sqlalchemy_session",
|
|
@@ -95,7 +95,7 @@ class SqlMixin(ABC):
|
|
|
95
95
|
|
|
96
96
|
# Auto-convert file path to SQLAlchemy SQLite URL if needed
|
|
97
97
|
if database_path == ":memory:":
|
|
98
|
-
self.database_url =
|
|
98
|
+
self.database_url = FLWR_IN_MEMORY_SQLITE_DB_URL
|
|
99
99
|
elif not database_path.startswith("sqlite://"):
|
|
100
100
|
# Treat as file path, convert to absolute and create SQLite URL
|
|
101
101
|
abs_path = Path(database_path).resolve()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright 2026 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
|
+
"""Alembic helpers and migration environment for SQL state."""
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Copyright 2026 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
|
+
"""Alembic environment configuration for State migrations."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from logging.config import fileConfig
|
|
19
|
+
|
|
20
|
+
from alembic import context
|
|
21
|
+
from sqlalchemy import engine_from_config, pool
|
|
22
|
+
|
|
23
|
+
from flwr.supercore.state.alembic.utils import get_combined_metadata
|
|
24
|
+
|
|
25
|
+
# Alembic Config object
|
|
26
|
+
config = context.config # pylint: disable=no-member
|
|
27
|
+
|
|
28
|
+
# Interpret the config file for Python logging
|
|
29
|
+
if config.config_file_name is not None:
|
|
30
|
+
fileConfig(config.config_file_name)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Target metadata for autogenerate
|
|
34
|
+
target_metadata = get_combined_metadata()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def run_migrations_offline() -> None:
|
|
38
|
+
"""Run migrations in 'offline' mode.
|
|
39
|
+
|
|
40
|
+
This configures the context with just a URL and not an Engine, though an Engine is
|
|
41
|
+
acceptable here as well. By skipping the Engine creation we don't even need a DBAPI
|
|
42
|
+
to be available.
|
|
43
|
+
|
|
44
|
+
Calls to context.execute() here emit the given string to the script output.
|
|
45
|
+
"""
|
|
46
|
+
url = config.get_main_option("sqlalchemy.url")
|
|
47
|
+
context.configure( # pylint: disable=no-member
|
|
48
|
+
url=url,
|
|
49
|
+
target_metadata=target_metadata,
|
|
50
|
+
literal_binds=True,
|
|
51
|
+
dialect_opts={"paramstyle": "named"},
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
with context.begin_transaction(): # pylint: disable=no-member
|
|
55
|
+
context.run_migrations() # pylint: disable=no-member
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def run_migrations_online() -> None:
|
|
59
|
+
"""Run migrations in 'online' mode.
|
|
60
|
+
|
|
61
|
+
In this scenario we need to create an Engine and associate a connection with the
|
|
62
|
+
context.
|
|
63
|
+
"""
|
|
64
|
+
connectable = engine_from_config(
|
|
65
|
+
config.get_section(config.config_ini_section, {}),
|
|
66
|
+
prefix="sqlalchemy.",
|
|
67
|
+
poolclass=pool.NullPool,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
with connectable.connect() as connection:
|
|
71
|
+
# pylint: disable-next=no-member
|
|
72
|
+
context.configure(connection=connection, target_metadata=target_metadata)
|
|
73
|
+
|
|
74
|
+
with context.begin_transaction(): # pylint: disable=no-member
|
|
75
|
+
context.run_migrations() # pylint: disable=no-member
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
if context.is_offline_mode(): # pylint: disable=no-member
|
|
79
|
+
run_migrations_offline()
|
|
80
|
+
else:
|
|
81
|
+
run_migrations_online()
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Copyright 2026 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
|
+
"""${message}.
|
|
16
|
+
|
|
17
|
+
Revision ID: ${up_revision}
|
|
18
|
+
Revises: ${down_revision | comma,n}
|
|
19
|
+
Create Date: ${create_date}
|
|
20
|
+
"""
|
|
21
|
+
from typing import Sequence, Union
|
|
22
|
+
|
|
23
|
+
from alembic import op
|
|
24
|
+
import sqlalchemy as sa
|
|
25
|
+
${imports if imports else ""}
|
|
26
|
+
|
|
27
|
+
# pylint: disable=no-member
|
|
28
|
+
|
|
29
|
+
# revision identifiers, used by Alembic.
|
|
30
|
+
revision: str = ${repr(up_revision)}
|
|
31
|
+
down_revision: Union[str, Sequence[str], None] = ${repr(down_revision)}
|
|
32
|
+
branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
|
|
33
|
+
depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def upgrade() -> None:
|
|
37
|
+
"""Upgrade schema."""
|
|
38
|
+
${upgrades if upgrades else "pass"}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def downgrade() -> None:
|
|
42
|
+
"""Downgrade schema."""
|
|
43
|
+
${downgrades if downgrades else "pass"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Copyright 2026 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
|
+
"""Helpers for running and validating Alembic migrations."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from sqlalchemy import MetaData
|
|
19
|
+
|
|
20
|
+
from flwr.supercore.state.schema.corestate_tables import create_corestate_metadata
|
|
21
|
+
from flwr.supercore.state.schema.linkstate_tables import create_linkstate_metadata
|
|
22
|
+
from flwr.supercore.state.schema.objectstore_tables import create_objectstore_metadata
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_combined_metadata() -> MetaData:
|
|
26
|
+
"""Combine all Flower state metadata objects into a single MetaData instance.
|
|
27
|
+
|
|
28
|
+
This ensures Alembic can track all tables across CoreState, LinkState, and
|
|
29
|
+
ObjectStore.
|
|
30
|
+
|
|
31
|
+
Returns
|
|
32
|
+
-------
|
|
33
|
+
MetaData
|
|
34
|
+
Combined SQLAlchemy MetaData with all Flower state tables.
|
|
35
|
+
"""
|
|
36
|
+
# Start with linkstate tables
|
|
37
|
+
metadata = create_linkstate_metadata()
|
|
38
|
+
|
|
39
|
+
# Add corestate tables
|
|
40
|
+
corestate_metadata = create_corestate_metadata()
|
|
41
|
+
for table in corestate_metadata.tables.values():
|
|
42
|
+
table.to_metadata(metadata)
|
|
43
|
+
|
|
44
|
+
# Add objectstore tables
|
|
45
|
+
objectstore_metadata = create_objectstore_metadata()
|
|
46
|
+
for table in objectstore_metadata.tables.values():
|
|
47
|
+
table.to_metadata(metadata)
|
|
48
|
+
|
|
49
|
+
return metadata
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright 2026 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
|
+
"""Alembic migration versions."""
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Copyright 2026 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
|
+
"""Initialize migration of state tables.
|
|
16
|
+
|
|
17
|
+
Revision ID: 8e65d8ae60b0
|
|
18
|
+
Revises:
|
|
19
|
+
Create Date: 2026-01-28 11:03:18.038794
|
|
20
|
+
"""
|
|
21
|
+
from collections.abc import Sequence
|
|
22
|
+
|
|
23
|
+
import sqlalchemy as sa
|
|
24
|
+
from alembic import op
|
|
25
|
+
|
|
26
|
+
# pylint: disable=no-member
|
|
27
|
+
|
|
28
|
+
# revision identifiers, used by Alembic.
|
|
29
|
+
revision: str = "8e65d8ae60b0"
|
|
30
|
+
down_revision: str | Sequence[str] | None = None
|
|
31
|
+
branch_labels: str | Sequence[str] | None = None
|
|
32
|
+
depends_on: str | Sequence[str] | None = None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def upgrade() -> None:
|
|
36
|
+
"""Upgrade schema."""
|
|
37
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
38
|
+
# LinkState tables
|
|
39
|
+
op.create_table(
|
|
40
|
+
"node",
|
|
41
|
+
sa.Column("node_id", sa.Integer(), nullable=True),
|
|
42
|
+
sa.Column("owner_aid", sa.String(), nullable=True),
|
|
43
|
+
sa.Column("owner_name", sa.String(), nullable=True),
|
|
44
|
+
sa.Column("status", sa.String(), nullable=True),
|
|
45
|
+
sa.Column("registered_at", sa.String(), nullable=True),
|
|
46
|
+
sa.Column("last_activated_at", sa.String(), nullable=True),
|
|
47
|
+
sa.Column("last_deactivated_at", sa.String(), nullable=True),
|
|
48
|
+
sa.Column("unregistered_at", sa.String(), nullable=True),
|
|
49
|
+
sa.Column("online_until", sa.TIMESTAMP(), nullable=True),
|
|
50
|
+
sa.Column("heartbeat_interval", sa.Float(), nullable=True),
|
|
51
|
+
sa.Column("public_key", sa.LargeBinary(), nullable=True),
|
|
52
|
+
sa.UniqueConstraint("node_id"),
|
|
53
|
+
sa.UniqueConstraint("public_key"),
|
|
54
|
+
)
|
|
55
|
+
op.create_index("idx_node_owner_aid", "node", ["owner_aid"], unique=False)
|
|
56
|
+
op.create_index("idx_node_status", "node", ["status"], unique=False)
|
|
57
|
+
op.create_index("idx_online_until", "node", ["online_until"], unique=False)
|
|
58
|
+
op.create_table(
|
|
59
|
+
"run",
|
|
60
|
+
sa.Column("run_id", sa.Integer(), nullable=True),
|
|
61
|
+
sa.Column("fab_id", sa.String(), nullable=True),
|
|
62
|
+
sa.Column("fab_version", sa.String(), nullable=True),
|
|
63
|
+
sa.Column("fab_hash", sa.String(), nullable=True),
|
|
64
|
+
sa.Column("override_config", sa.String(), nullable=True),
|
|
65
|
+
sa.Column("pending_at", sa.String(), nullable=True),
|
|
66
|
+
sa.Column("starting_at", sa.String(), nullable=True),
|
|
67
|
+
sa.Column("running_at", sa.String(), nullable=True),
|
|
68
|
+
sa.Column("finished_at", sa.String(), nullable=True),
|
|
69
|
+
sa.Column("sub_status", sa.String(), nullable=True),
|
|
70
|
+
sa.Column("details", sa.String(), nullable=True),
|
|
71
|
+
sa.Column("federation", sa.String(), nullable=True),
|
|
72
|
+
sa.Column("federation_options", sa.LargeBinary(), nullable=True),
|
|
73
|
+
sa.Column("flwr_aid", sa.String(), nullable=True),
|
|
74
|
+
sa.Column("bytes_sent", sa.Integer(), server_default="0", nullable=True),
|
|
75
|
+
sa.Column("bytes_recv", sa.Integer(), server_default="0", nullable=True),
|
|
76
|
+
sa.Column("clientapp_runtime", sa.Float(), server_default="0.0", nullable=True),
|
|
77
|
+
sa.UniqueConstraint("run_id"),
|
|
78
|
+
)
|
|
79
|
+
op.create_table(
|
|
80
|
+
"logs",
|
|
81
|
+
sa.Column("timestamp", sa.Float(), nullable=True),
|
|
82
|
+
sa.Column("run_id", sa.Integer(), nullable=True),
|
|
83
|
+
sa.Column("node_id", sa.Integer(), nullable=True),
|
|
84
|
+
sa.Column("log", sa.String(), nullable=True),
|
|
85
|
+
sa.ForeignKeyConstraint(
|
|
86
|
+
["run_id"],
|
|
87
|
+
["run.run_id"],
|
|
88
|
+
),
|
|
89
|
+
sa.UniqueConstraint("timestamp", "run_id", "node_id"),
|
|
90
|
+
)
|
|
91
|
+
op.create_table(
|
|
92
|
+
"context",
|
|
93
|
+
sa.Column("run_id", sa.Integer(), nullable=True),
|
|
94
|
+
sa.Column("context", sa.LargeBinary(), nullable=True),
|
|
95
|
+
sa.ForeignKeyConstraint(
|
|
96
|
+
["run_id"],
|
|
97
|
+
["run.run_id"],
|
|
98
|
+
),
|
|
99
|
+
sa.UniqueConstraint("run_id"),
|
|
100
|
+
)
|
|
101
|
+
op.create_table(
|
|
102
|
+
"message_ins",
|
|
103
|
+
sa.Column("message_id", sa.String(), nullable=True),
|
|
104
|
+
sa.Column("group_id", sa.String(), nullable=True),
|
|
105
|
+
sa.Column("run_id", sa.Integer(), nullable=True),
|
|
106
|
+
sa.Column("src_node_id", sa.Integer(), nullable=True),
|
|
107
|
+
sa.Column("dst_node_id", sa.Integer(), nullable=True),
|
|
108
|
+
sa.Column("reply_to_message_id", sa.String(), nullable=True),
|
|
109
|
+
sa.Column("created_at", sa.Float(), nullable=True),
|
|
110
|
+
sa.Column("delivered_at", sa.String(), nullable=True),
|
|
111
|
+
sa.Column("ttl", sa.Float(), nullable=True),
|
|
112
|
+
sa.Column("message_type", sa.String(), nullable=True),
|
|
113
|
+
sa.Column("content", sa.LargeBinary(), nullable=True),
|
|
114
|
+
sa.Column("error", sa.LargeBinary(), nullable=True),
|
|
115
|
+
sa.ForeignKeyConstraint(
|
|
116
|
+
["run_id"],
|
|
117
|
+
["run.run_id"],
|
|
118
|
+
),
|
|
119
|
+
sa.UniqueConstraint("message_id"),
|
|
120
|
+
)
|
|
121
|
+
op.create_table(
|
|
122
|
+
"message_res",
|
|
123
|
+
sa.Column("message_id", sa.String(), nullable=True),
|
|
124
|
+
sa.Column("group_id", sa.String(), nullable=True),
|
|
125
|
+
sa.Column("run_id", sa.Integer(), nullable=True),
|
|
126
|
+
sa.Column("src_node_id", sa.Integer(), nullable=True),
|
|
127
|
+
sa.Column("dst_node_id", sa.Integer(), nullable=True),
|
|
128
|
+
sa.Column("reply_to_message_id", sa.String(), nullable=True),
|
|
129
|
+
sa.Column("created_at", sa.Float(), nullable=True),
|
|
130
|
+
sa.Column("delivered_at", sa.String(), nullable=True),
|
|
131
|
+
sa.Column("ttl", sa.Float(), nullable=True),
|
|
132
|
+
sa.Column("message_type", sa.String(), nullable=True),
|
|
133
|
+
sa.Column("content", sa.LargeBinary(), nullable=True),
|
|
134
|
+
sa.Column("error", sa.LargeBinary(), nullable=True),
|
|
135
|
+
sa.ForeignKeyConstraint(
|
|
136
|
+
["run_id"],
|
|
137
|
+
["run.run_id"],
|
|
138
|
+
),
|
|
139
|
+
sa.UniqueConstraint("message_id"),
|
|
140
|
+
)
|
|
141
|
+
# CoreState tables
|
|
142
|
+
op.create_table(
|
|
143
|
+
"token_store",
|
|
144
|
+
sa.Column("run_id", sa.Integer(), nullable=True),
|
|
145
|
+
sa.Column("token", sa.String(), nullable=False),
|
|
146
|
+
sa.Column("active_until", sa.Float(), nullable=True),
|
|
147
|
+
sa.PrimaryKeyConstraint("run_id"),
|
|
148
|
+
sa.UniqueConstraint("token"),
|
|
149
|
+
)
|
|
150
|
+
# ObjectStore tables
|
|
151
|
+
op.create_table(
|
|
152
|
+
"objects",
|
|
153
|
+
sa.Column("object_id", sa.String(), nullable=True),
|
|
154
|
+
sa.Column("content", sa.LargeBinary(), nullable=True),
|
|
155
|
+
sa.Column("is_available", sa.Integer(), server_default="0", nullable=False),
|
|
156
|
+
sa.Column("ref_count", sa.Integer(), server_default="0", nullable=False),
|
|
157
|
+
sa.CheckConstraint("is_available IN (0, 1)", name="ck_objects_is_available"),
|
|
158
|
+
sa.PrimaryKeyConstraint("object_id"),
|
|
159
|
+
)
|
|
160
|
+
op.create_table(
|
|
161
|
+
"object_children",
|
|
162
|
+
sa.Column("parent_id", sa.String(), nullable=False),
|
|
163
|
+
sa.Column("child_id", sa.String(), nullable=False),
|
|
164
|
+
sa.ForeignKeyConstraint(
|
|
165
|
+
["child_id"], ["objects.object_id"], ondelete="CASCADE"
|
|
166
|
+
),
|
|
167
|
+
sa.ForeignKeyConstraint(
|
|
168
|
+
["parent_id"], ["objects.object_id"], ondelete="CASCADE"
|
|
169
|
+
),
|
|
170
|
+
sa.PrimaryKeyConstraint("parent_id", "child_id"),
|
|
171
|
+
)
|
|
172
|
+
op.create_table(
|
|
173
|
+
"run_objects",
|
|
174
|
+
sa.Column("run_id", sa.Integer(), nullable=False),
|
|
175
|
+
sa.Column("object_id", sa.String(), nullable=False),
|
|
176
|
+
sa.ForeignKeyConstraint(
|
|
177
|
+
["object_id"], ["objects.object_id"], ondelete="CASCADE"
|
|
178
|
+
),
|
|
179
|
+
sa.PrimaryKeyConstraint("run_id", "object_id"),
|
|
180
|
+
)
|
|
181
|
+
# ### end Alembic commands ###
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def downgrade() -> None:
|
|
185
|
+
"""Downgrade schema."""
|
|
186
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
187
|
+
op.drop_table("run_objects")
|
|
188
|
+
op.drop_table("object_children")
|
|
189
|
+
op.drop_table("objects")
|
|
190
|
+
op.drop_table("token_store")
|
|
191
|
+
op.drop_table("message_res")
|
|
192
|
+
op.drop_table("message_ins")
|
|
193
|
+
op.drop_table("context")
|
|
194
|
+
op.drop_table("logs")
|
|
195
|
+
op.drop_table("run")
|
|
196
|
+
op.drop_index("idx_online_until", table_name="node")
|
|
197
|
+
op.drop_index("idx_node_status", table_name="node")
|
|
198
|
+
op.drop_index("idx_node_owner_aid", table_name="node")
|
|
199
|
+
op.drop_table("node")
|
|
200
|
+
# ### end Alembic commands ###
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Schema
|
|
4
4
|
|
|
5
|
+
<!-- BEGIN_SQLALCHEMY_DOCS -->
|
|
5
6
|
```mermaid
|
|
6
7
|
|
|
7
8
|
---
|
|
@@ -77,7 +78,6 @@ erDiagram
|
|
|
77
78
|
INTEGER ref_count
|
|
78
79
|
}
|
|
79
80
|
|
|
80
|
-
<<<<<<< HEAD
|
|
81
81
|
run {
|
|
82
82
|
INTEGER bytes_recv "nullable"
|
|
83
83
|
INTEGER bytes_sent "nullable"
|
|
@@ -98,8 +98,6 @@ erDiagram
|
|
|
98
98
|
VARCHAR sub_status "nullable"
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
=======
|
|
102
|
-
>>>>>>> main
|
|
103
101
|
run_objects {
|
|
104
102
|
VARCHAR object_id PK,FK
|
|
105
103
|
INTEGER run_id PK
|
|
@@ -111,15 +109,13 @@ erDiagram
|
|
|
111
109
|
VARCHAR token UK
|
|
112
110
|
}
|
|
113
111
|
|
|
114
|
-
<<<<<<< HEAD
|
|
115
112
|
run ||--o| context : run_id
|
|
116
113
|
run ||--o{ logs : run_id
|
|
117
114
|
run ||--o{ message_ins : run_id
|
|
118
115
|
run ||--o{ message_res : run_id
|
|
119
|
-
=======
|
|
120
|
-
>>>>>>> main
|
|
121
116
|
objects ||--o| object_children : parent_id
|
|
122
117
|
objects ||--o| object_children : child_id
|
|
123
118
|
objects ||--o| run_objects : object_id
|
|
124
119
|
|
|
125
120
|
```
|
|
121
|
+
<!-- END_SQLALCHEMY_DOCS -->
|
flwr/supercore/utils.py
CHANGED
|
@@ -254,3 +254,24 @@ def humanize_bytes(num_bytes: int) -> str:
|
|
|
254
254
|
value /= 1024
|
|
255
255
|
|
|
256
256
|
raise RuntimeError("Unreachable code") # Make mypy happy
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def check_federation_format(federation: str) -> None:
|
|
260
|
+
"""Check if the federation string is valid.
|
|
261
|
+
|
|
262
|
+
Parameters
|
|
263
|
+
----------
|
|
264
|
+
federation : str
|
|
265
|
+
The federation string to check.
|
|
266
|
+
|
|
267
|
+
Raises
|
|
268
|
+
------
|
|
269
|
+
ValueError
|
|
270
|
+
If the federation string is not valid. The expected
|
|
271
|
+
format is '@<account-name>/<federation-name>'.
|
|
272
|
+
"""
|
|
273
|
+
if not re.match(r"^@[a-zA-Z0-9\-_]+/[a-zA-Z0-9\-_]+$", federation):
|
|
274
|
+
raise ValueError(
|
|
275
|
+
f"Invalid federation format: {federation}. "
|
|
276
|
+
f"Expected format: '@<account-name>/<federation-name>'."
|
|
277
|
+
)
|
|
@@ -15,8 +15,9 @@
|
|
|
15
15
|
"""NoOp implementation of FederationManager."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
from flwr.common.constant import NOOP_FLWR_AID
|
|
18
|
+
from flwr.common.constant import NOOP_ACCOUNT_NAME, NOOP_FLWR_AID
|
|
19
19
|
from flwr.common.typing import Federation
|
|
20
|
+
from flwr.proto.federation_pb2 import Account # pylint: disable=E0611
|
|
20
21
|
from flwr.supercore.constant import NOOP_FEDERATION
|
|
21
22
|
|
|
22
23
|
from .federation_manager import FederationManager
|
|
@@ -66,6 +67,7 @@ class NoOpFederationManager(FederationManager):
|
|
|
66
67
|
return Federation(
|
|
67
68
|
name=NOOP_FEDERATION,
|
|
68
69
|
member_aids=[NOOP_FLWR_AID],
|
|
70
|
+
accounts=[Account(id=NOOP_FLWR_AID, name=NOOP_ACCOUNT_NAME)],
|
|
69
71
|
nodes=nodes,
|
|
70
72
|
runs=runs,
|
|
71
73
|
)
|
|
@@ -65,7 +65,7 @@ from flwr.common.telemetry import EventType
|
|
|
65
65
|
from flwr.common.typing import Fab, Run, RunNotRunningException
|
|
66
66
|
from flwr.proto.clientappio_pb2_grpc import add_ClientAppIoServicer_to_server
|
|
67
67
|
from flwr.proto.message_pb2 import ObjectTree # pylint: disable=E0611
|
|
68
|
-
from flwr.supercore.address import parse_address
|
|
68
|
+
from flwr.supercore.address import parse_address, resolve_bind_address
|
|
69
69
|
from flwr.supercore.ffs import Ffs, FfsFactory
|
|
70
70
|
from flwr.supercore.grpc_health import run_health_server_grpc_no_tls
|
|
71
71
|
from flwr.supercore.object_store import ObjectStore, ObjectStoreFactory
|
|
@@ -213,7 +213,10 @@ def start_client_internal(
|
|
|
213
213
|
# Launch the SuperExec if the isolation mode is `subprocess`
|
|
214
214
|
if isolation == ISOLATION_MODE_SUBPROCESS:
|
|
215
215
|
command = ["flower-superexec", "--insecure"]
|
|
216
|
-
command += [
|
|
216
|
+
command += [
|
|
217
|
+
"--appio-api-address",
|
|
218
|
+
resolve_bind_address(clientappio_api_address),
|
|
219
|
+
]
|
|
217
220
|
command += ["--plugin-type", ExecPluginType.CLIENT_APP]
|
|
218
221
|
command += ["--parent-pid", str(os.getpid())]
|
|
219
222
|
# pylint: disable-next=consider-using-with
|
{flwr_nightly-1.26.0.dev20260126.dist-info → flwr_nightly-1.26.0.dev20260128.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: flwr-nightly
|
|
3
|
-
Version: 1.26.0.
|
|
3
|
+
Version: 1.26.0.dev20260128
|
|
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
|
|
@@ -31,6 +31,7 @@ Classifier: Typing :: Typed
|
|
|
31
31
|
Provides-Extra: rest
|
|
32
32
|
Provides-Extra: simulation
|
|
33
33
|
Requires-Dist: SQLAlchemy (>=2.0.45,<3.0.0)
|
|
34
|
+
Requires-Dist: alembic (>=1.18.1,<2.0.0)
|
|
34
35
|
Requires-Dist: click (<8.2.0)
|
|
35
36
|
Requires-Dist: cryptography (>=44.0.1,<45.0.0)
|
|
36
37
|
Requires-Dist: grpcio (>=1.70.0,<2.0.0)
|
{flwr_nightly-1.26.0.dev20260126.dist-info → flwr_nightly-1.26.0.dev20260128.dist-info}/RECORD
RENAMED
|
@@ -6,7 +6,7 @@ flwr/app/message_type.py,sha256=WABg74wnkIdrmjD_AhlA7tYOqwni5n5Isagc8O9IdOc,1002
|
|
|
6
6
|
flwr/app/metadata.py,sha256=rnfEHbw-IL1anLHwploK1YQQqKFHQmoF_M6rcSpRNCc,7422
|
|
7
7
|
flwr/app/user_config.py,sha256=7xsOVs-NYIvE710iE1qRFqxlA3LQNnmcoVXqcg_Ez2g,802
|
|
8
8
|
flwr/cli/__init__.py,sha256=EfMGmHoobET6P2blBt_eOByXL8299MgFfB7XNdaPQ6I,720
|
|
9
|
-
flwr/cli/app.py,sha256=
|
|
9
|
+
flwr/cli/app.py,sha256=AEm7JewC_0FT2esOqNcB9Xkot7s7sGBf6yitzp8z6E4,3784
|
|
10
10
|
flwr/cli/app_cmd/__init__.py,sha256=O_vTzS2u-n27fBYnDbjTMMKQQ2Bz80Y4JqGBHSAnK40,856
|
|
11
11
|
flwr/cli/app_cmd/publish.py,sha256=DAFRu12EAO1NtzrGN9uYN_hW20gQZ2vCyf0HggzqaZ0,8006
|
|
12
12
|
flwr/cli/app_cmd/review.py,sha256=FPusshF36519z_KN36mU2fcvRtb5DCh0esinsts8WEs,7200
|
|
@@ -17,19 +17,19 @@ flwr/cli/auth_plugin/oidc_cli_plugin.py,sha256=1gN00FifSrhUA5s5uaE_GpQ3N7U8fQec4
|
|
|
17
17
|
flwr/cli/build.py,sha256=wjLrxWHGnwRFp7WxZFgm8J0cwcdQY9-QHxjFnEa2dII,10097
|
|
18
18
|
flwr/cli/cli_account_auth_interceptor.py,sha256=mXgxThpZjU_2Xlae9xT8ewOw60GeE64comDd57asLIY,3680
|
|
19
19
|
flwr/cli/config/__init__.py,sha256=46z6whA3hvKkl9APRs-UG7Ym3K9VOqKx_pYcgelRjtE,788
|
|
20
|
-
flwr/cli/config/ls.py,sha256=
|
|
21
|
-
flwr/cli/config_migration.py,sha256=
|
|
20
|
+
flwr/cli/config/ls.py,sha256=i976g1rzpSLEagyjEFdxxYAM-FqaP0Unqlk2EiKj4B4,3549
|
|
21
|
+
flwr/cli/config_migration.py,sha256=KJIVqpVbEfhY53taELFZuVGY0-sTPGiPOI6_FwEjfDI,10932
|
|
22
22
|
flwr/cli/config_utils.py,sha256=t9GNUPnUH1nUNZQ3oGjx6Jd5VSO9SlnQXjz3-yro7Rs,7683
|
|
23
|
-
flwr/cli/constant.py,sha256=
|
|
23
|
+
flwr/cli/constant.py,sha256=N50fATyqwwFuy8Ty7nl4zvKOQtmdSjfoJH4bHggb6BU,3501
|
|
24
24
|
flwr/cli/example.py,sha256=SNTorkKPrx1rOryGREUyZu8TcOc1-vFv1zEddaysdY0,2216
|
|
25
25
|
flwr/cli/federation/__init__.py,sha256=okxswL4fAjApI9gV_alU1lRkTUcQRbwlzvtUTLz61fE,793
|
|
26
|
-
flwr/cli/federation/ls.py,sha256=
|
|
27
|
-
flwr/cli/flower_config.py,sha256=
|
|
26
|
+
flwr/cli/federation/ls.py,sha256=SZrQb_uUBrK2v4nAo3GETxyVBoNpBUJLjQuE_maX8_E,10737
|
|
27
|
+
flwr/cli/flower_config.py,sha256=EFsSJByBD-SmIReoBaSzuEriLz4716qh7LMU2_yfGzc,15065
|
|
28
28
|
flwr/cli/install.py,sha256=gBYg1SczpvBh8MMrXJxi0q4DUdzXCdvapK3jC3CBlPk,9114
|
|
29
29
|
flwr/cli/log.py,sha256=BPA0dvGlXx5PrtURPua5fJyF7iVrb28K4fEY2Uth0EE,7317
|
|
30
30
|
flwr/cli/login/__init__.py,sha256=B1SXKU3HCQhWfFDMJhlC7FOl8UsvH4mxysxeBnrfyUE,800
|
|
31
|
-
flwr/cli/login/login.py,sha256=
|
|
32
|
-
flwr/cli/ls.py,sha256=
|
|
31
|
+
flwr/cli/login/login.py,sha256=o-jm5QRMIpivE8kpY7cPTGbr7nQhsyFYaftMtBaaT0s,3649
|
|
32
|
+
flwr/cli/ls.py,sha256=7CUtSdqnEuAkAgN-7u9c8TBOoM-IYms0nh0h1SkLz7I,12782
|
|
33
33
|
flwr/cli/new/__init__.py,sha256=QA1E2QtzPvFCjLTUHnFnJbufuFiGyT_0Y53Wpbvg1F0,790
|
|
34
34
|
flwr/cli/new/new.py,sha256=15phs5dhEpo7ORs7uulGzHWtW9W5ZGn0EKFE_T5WXb8,7829
|
|
35
35
|
flwr/cli/pull.py,sha256=XzBvLrdYGrSCuky5OoCEU4V9UR9QlyZMT7Tj-W6wSw0,2946
|
|
@@ -38,11 +38,11 @@ flwr/cli/run/run.py,sha256=6yrVljd1CqqALq-wqiv0TnZlveiN5ymiUI5iTjuvUJM,8954
|
|
|
38
38
|
flwr/cli/run_utils.py,sha256=ZnlBOqFfRxVEPZKR_9zYrynNcohiCFY8QN6OFyOCrQs,5082
|
|
39
39
|
flwr/cli/stop.py,sha256=w3frNt3TD5AukGmlGq4CbWo-3PC3B-YSLO6PjJeHjH4,4692
|
|
40
40
|
flwr/cli/supernode/__init__.py,sha256=DBkjoPo2hS2Y-ghJxwLbrAbCQFBgD82_Itl2_892UBo,917
|
|
41
|
-
flwr/cli/supernode/ls.py,sha256=
|
|
41
|
+
flwr/cli/supernode/ls.py,sha256=o3YENA1e-W4oJjq2rHwwzZthllpLzEhSY--9-m_c6Qc,8236
|
|
42
42
|
flwr/cli/supernode/register.py,sha256=YPf28ZDvqPAQAt6c6OG73AJa9zZPONKgpxhnnb3NWQk,5498
|
|
43
43
|
flwr/cli/supernode/unregister.py,sha256=qWGg8G_KqF300ze4D1dYaSIRJZkl9zwM2ul8VLYjJMY,3719
|
|
44
|
-
flwr/cli/typing.py,sha256=
|
|
45
|
-
flwr/cli/utils.py,sha256=
|
|
44
|
+
flwr/cli/typing.py,sha256=COLEK_zVQuGGm4t_nYAW0_8EWu09zFiAv-tEZNg95_s,7367
|
|
45
|
+
flwr/cli/utils.py,sha256=HCQYvqAjO74awSWQ9dV_OfCZ9QSkMIoKQ5b0Y4EOeoo,15568
|
|
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
|
|
@@ -86,7 +86,7 @@ flwr/common/event_log_plugin/__init__.py,sha256=ts3VAL3Fk6Grp1EK_1Qg_V-BfOof9F86
|
|
|
86
86
|
flwr/common/event_log_plugin/event_log_plugin.py,sha256=uJYR363nVzjfJePay3UHwaifwgBx2rAbKHHAuQC10VU,2014
|
|
87
87
|
flwr/common/exit/__init__.py,sha256=8W7xaO1iw0vacgmQW7FTFbSh7csNv6XfsgIlnIbNF6U,978
|
|
88
88
|
flwr/common/exit/exit.py,sha256=EBHZos4EhZLxW1lmZXDVlFUOf0_eTQ1FxzQiZ466hZ0,4018
|
|
89
|
-
flwr/common/exit/exit_code.py,sha256=
|
|
89
|
+
flwr/common/exit/exit_code.py,sha256=xpvi_3UOhf6AT8pR0ZGXyBxWfnuFFE50O1cKqOGVxxE,7000
|
|
90
90
|
flwr/common/exit/exit_handler.py,sha256=zUAXHtp4rYK_sbkgsqS5zrVAzJUiSBrB-a4Ay3vSPE8,2302
|
|
91
91
|
flwr/common/exit/signal_handler.py,sha256=o_e33v9kP0jz13q-8BZDrKF7vNCzOApvDPZ3-nTXfIc,3697
|
|
92
92
|
flwr/common/grpc.py,sha256=8XoMTA5rJMze8fG6vOs1g4_rkxMhfpvMEYJPnqYPi2g,9799
|
|
@@ -119,7 +119,7 @@ flwr/common/secure_aggregation/secaggplus_utils.py,sha256=E_xU-Zd45daO1em7M6C2wO
|
|
|
119
119
|
flwr/common/serde.py,sha256=FqqJqNqCk-DryCOgTGkabENvFeU2Q0LieLe0bt3qBbU,22342
|
|
120
120
|
flwr/common/serde_utils.py,sha256=Vk49PnZWRgo0NrvBhFqH-Li7sMFVVgyrs3Ck7kHB-ZE,5820
|
|
121
121
|
flwr/common/telemetry.py,sha256=7HNy5ytioJ3SbFtaKNucwYYC-IXEOXphitZbdHmSlfk,8924
|
|
122
|
-
flwr/common/typing.py,sha256=
|
|
122
|
+
flwr/common/typing.py,sha256=LLL-4wB8LaijpiVCIJQBv-PI8SXM4RNjbClu3BHWQh0,7394
|
|
123
123
|
flwr/compat/__init__.py,sha256=gbfDQKKKMZzi3GswyVRgyLdDlHiWj3wU6dg7y6m5O_s,752
|
|
124
124
|
flwr/compat/client/__init__.py,sha256=qpbo0lcxdNL4qy5KHqiGm8OLxSxkYgI_-dLh5rwhtcI,746
|
|
125
125
|
flwr/compat/client/app.py,sha256=oBOB-gYm0oqxtfAp58QZtv3dyUsPxjFm__f1_teenHU,27178
|
|
@@ -151,8 +151,8 @@ flwr/proto/fab_pb2.py,sha256=QDkVHGRGmugjQQUiN8A_okppZ5e2pJi5KipjnWmF6e4,2320
|
|
|
151
151
|
flwr/proto/fab_pb2.pyi,sha256=PUUZ1FHeTwXxjVmTX14Vx5gmgRSFvoW_e5v_Z5qkT54,3948
|
|
152
152
|
flwr/proto/fab_pb2_grpc.py,sha256=jmhCnnwSqBpZ0329XGUGARbcz5sHrr0WrXwccqzc3Vs,895
|
|
153
153
|
flwr/proto/fab_pb2_grpc.pyi,sha256=fMwjLr-QCljWBa8uk0fvMCytnrF1-IzFLCbezqEmvdU,1071
|
|
154
|
-
flwr/proto/federation_pb2.py,sha256=
|
|
155
|
-
flwr/proto/federation_pb2.pyi,sha256=
|
|
154
|
+
flwr/proto/federation_pb2.py,sha256=1IAerSPg5O3DDx1Nixc9PL-0ELK4C_yjeCa3IpHLCjE,1927
|
|
155
|
+
flwr/proto/federation_pb2.pyi,sha256=EMPXcT0b6a6rs8oB-rHp-5dIQ_83aBDd7fTmamVzy60,2970
|
|
156
156
|
flwr/proto/federation_pb2_grpc.py,sha256=HPErt9uXJPbY8jLtTNFr941z82uMm7cOx10hTHgcwZM,902
|
|
157
157
|
flwr/proto/federation_pb2_grpc.pyi,sha256=fMwjLr-QCljWBa8uk0fvMCytnrF1-IzFLCbezqEmvdU,1071
|
|
158
158
|
flwr/proto/fleet_pb2.py,sha256=HnxtM2pqVdn2xhl3e1NlLazpSMaGoUUEG9Nd17egxqU,6543
|
|
@@ -201,7 +201,7 @@ flwr/proto/transport_pb2_grpc.py,sha256=jYsbV3KYdp4TaNfWxv3ljFEvB-Yjsa8MIPtTH-vV
|
|
|
201
201
|
flwr/proto/transport_pb2_grpc.pyi,sha256=qd2cOXq6HBZtwRfPpKuni27NGMJCAxyP5R95Vk8WWDU,2073
|
|
202
202
|
flwr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
203
203
|
flwr/server/__init__.py,sha256=LQQHiuL2jy7TpNaKastRdGsexlxSt5ZWAQNVqitDnrY,1598
|
|
204
|
-
flwr/server/app.py,sha256=
|
|
204
|
+
flwr/server/app.py,sha256=90rGFbhQw0vDrVDamqBVIm0RtUDfUUdUcXc9WpU7BKI,31678
|
|
205
205
|
flwr/server/client_manager.py,sha256=3WOqNWh5dlqPRG-DMGwXiyvGNEYS_jKqXKkFIkMqWLQ,6187
|
|
206
206
|
flwr/server/client_proxy.py,sha256=QS_RGgjSZ8V4StAHH8zc7W9_os2FyO4wNqkbylQMBTY,2341
|
|
207
207
|
flwr/server/compat/__init__.py,sha256=0IsttWvY15qO98_1GyzVC-vR1e_ZPXOdu2qUlOkYMPE,886
|
|
@@ -260,7 +260,7 @@ flwr/server/superlink/fleet/grpc_rere/__init__.py,sha256=ahDJJ1e-lDxBpeBMgPk7YZt
|
|
|
260
260
|
flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py,sha256=DtHuDP7fvgO-iamI48ACr0TQcD20eBYwMicHKIjhmXQ,12583
|
|
261
261
|
flwr/server/superlink/fleet/grpc_rere/node_auth_server_interceptor.py,sha256=88e9yEapAbk8fOoqG4f4-jvXMLuJAZYQF9j6whczegc,5811
|
|
262
262
|
flwr/server/superlink/fleet/message_handler/__init__.py,sha256=fHsRV0KvJ8HtgSA4_YBsEzuhJLjO8p6xx4aCY2oE1p4,731
|
|
263
|
-
flwr/server/superlink/fleet/message_handler/message_handler.py,sha256=
|
|
263
|
+
flwr/server/superlink/fleet/message_handler/message_handler.py,sha256=WrJkw8SX_0XMnZ8velhjjFHUIQ8SuGMpojkWkyhqB_E,12142
|
|
264
264
|
flwr/server/superlink/fleet/rest_rere/__init__.py,sha256=Lzc93nA7tDqoy-zRUaPG316oqFiZX1HUCL5ELaXY_xw,735
|
|
265
265
|
flwr/server/superlink/fleet/rest_rere/rest_api.py,sha256=cDWDQBf79F9tZ1mXOErc-nsnY4zFP9Tcv7Fs-bQIdiU,9616
|
|
266
266
|
flwr/server/superlink/fleet/vce/__init__.py,sha256=XOKbAWOzlCqEOQ3M2cBYkH7HKA7PxlbCJMunt-ty-DY,784
|
|
@@ -324,11 +324,11 @@ flwr/simulation/ray_transport/utils.py,sha256=KrexpWYCF-dAF3UHc9yDbPQWO-ahMT-BbD
|
|
|
324
324
|
flwr/simulation/run_simulation.py,sha256=hSJAqOfMd8I30Pq9x2TXYXDCXAeUtWqwBncX6JGEMOQ,20798
|
|
325
325
|
flwr/simulation/simulationio_connection.py,sha256=cS7yTOa5yeK-bQ2YjS9eJCXL8SOItEkiJD5sN5mBb_Y,3475
|
|
326
326
|
flwr/supercore/__init__.py,sha256=pqkFoow_E6UhbBlhmoD1gmTH-33yJRhBsIZqxRPFZ7U,755
|
|
327
|
-
flwr/supercore/address.py,sha256=
|
|
328
|
-
flwr/supercore/app_utils.py,sha256=
|
|
327
|
+
flwr/supercore/address.py,sha256=SgM_pazKsw1Avo5nms0WWgIZFUGS349O0gOP7N3bFW4,3318
|
|
328
|
+
flwr/supercore/app_utils.py,sha256=P558DOr5a4UPyOdRCxbDQueQF-L-kSc6qzouPPuqj0U,1773
|
|
329
329
|
flwr/supercore/cli/__init__.py,sha256=EDl2aO-fuQfxSbL-T1W9RAfA2N0hpWHmqX_GSwblJbQ,845
|
|
330
330
|
flwr/supercore/cli/flower_superexec.py,sha256=IQIGzxgaeLNMNzGXGemfYK3lp8God5bTkXpVkbeP_ig,6109
|
|
331
|
-
flwr/supercore/constant.py,sha256=
|
|
331
|
+
flwr/supercore/constant.py,sha256=ZtS-CpGSyth9iKjavNOLE7T-8xmCaEVoXi4ZarYry5s,2884
|
|
332
332
|
flwr/supercore/corestate/__init__.py,sha256=Vau6-L_JG5QzNqtCTa9xCKGGljc09wY8avZmIjSJemg,774
|
|
333
333
|
flwr/supercore/corestate/corestate.py,sha256=EZg4gPXqVOXwS7t0tlPfedajoWj5T80oeDBNxpV2y2I,2874
|
|
334
334
|
flwr/supercore/corestate/in_memory_corestate.py,sha256=9qa6RuRZfCp6vs-ARYdiZjCL31VOAAxw0a_VkBXR5zY,5116
|
|
@@ -355,9 +355,15 @@ flwr/supercore/object_store/sql_object_store.py,sha256=ZBmyc3a_GXZFNaefDCxhrri-_
|
|
|
355
355
|
flwr/supercore/primitives/__init__.py,sha256=Tx8GOjnmMo8Y74RsDGrMpfr-E0Nl8dcUDF784_ge6F8,745
|
|
356
356
|
flwr/supercore/primitives/asymmetric.py,sha256=1643niHYj3uEbfPd06VuMHwN3tKVwg0uVyR3RhTdWIU,3778
|
|
357
357
|
flwr/supercore/primitives/asymmetric_ed25519.py,sha256=eIhOTMibQW0FJX4MXdplHdL3HcfCiKuFu2mQ8GQTUz8,5025
|
|
358
|
-
flwr/supercore/sql_mixin.py,sha256=
|
|
358
|
+
flwr/supercore/sql_mixin.py,sha256=dAK_NCnXa0Ili0N5vYgQ9dlVOE-KeiQCRc2Z0RcS0sU,11765
|
|
359
359
|
flwr/supercore/state/__init__.py,sha256=FkKhsNVM4LjlRlOgXTz6twINmw5ohIUKS_OER0BNo_w,724
|
|
360
|
-
flwr/supercore/state/
|
|
360
|
+
flwr/supercore/state/alembic/__init__.py,sha256=pC-y-xsfgi9YwCrqnt814yOJ9ytlDRUFGqOY6Qzt-_U,746
|
|
361
|
+
flwr/supercore/state/alembic/env.py,sha256=fmRDLxsmJ77pC4LLDlpx3iBeBZXN2DFZ7LKhNTmGTIg,2739
|
|
362
|
+
flwr/supercore/state/alembic/script.py.mako,sha256=oNrcIBPuSq0jfg3ycPAg3vo18QhA-_OaGMTkKCix74I,1416
|
|
363
|
+
flwr/supercore/state/alembic/utils.py,sha256=6KpFEgR4_oNjq8KmNXuq-3ilOfNbzqlCw80NbBgjn9I,1813
|
|
364
|
+
flwr/supercore/state/alembic/versions/__init__.py,sha256=ri3OIpl8xD_Csv25uAAT7l-MtHhixqmAGt9Aa1OpM1s,717
|
|
365
|
+
flwr/supercore/state/alembic/versions/rev_2026_01_28_initialize_migration_of_state_tables.py,sha256=U4j4PdRUtIAZuWUGuLO7N8W_5Ixit1rfEqfcIp2SAmE,8407
|
|
366
|
+
flwr/supercore/state/schema/README.md,sha256=qVCGuyU-gObFrL5MRvH9LraNi0Z_LbXzolXykbOrY9w,2884
|
|
361
367
|
flwr/supercore/state/schema/__init__.py,sha256=Egnde6OY01wrpT4PuhL4NGn_NY4jdAH7kf7ktagN4Ws,724
|
|
362
368
|
flwr/supercore/state/schema/corestate_tables.py,sha256=TwonogWgEUtKeE-LY59wousWzhF0w3wMKAotRqvRxao,1392
|
|
363
369
|
flwr/supercore/state/schema/linkstate_tables.py,sha256=aKh9zR6cF4ecOJHS8SzniLXkcNGd4OG4xnZvwC_qers,5583
|
|
@@ -370,7 +376,7 @@ flwr/supercore/superexec/plugin/exec_plugin.py,sha256=iRRZcnTcM3wMwkkUElmfFka31a
|
|
|
370
376
|
flwr/supercore/superexec/plugin/serverapp_exec_plugin.py,sha256=IwRzdPV-cSKwrP2krGh0De4IkAuxsmgK0WU6J-2GXqM,1035
|
|
371
377
|
flwr/supercore/superexec/plugin/simulation_exec_plugin.py,sha256=upn5zE-YKkl_jTw8RzmeyQ58PU_UAlQ7CqnBXXdng8I,1060
|
|
372
378
|
flwr/supercore/superexec/run_superexec.py,sha256=yeV6_eI0XFfPyNwnlgqchR9jI80FzSI80oyekrIlO2M,7144
|
|
373
|
-
flwr/supercore/utils.py,sha256=
|
|
379
|
+
flwr/supercore/utils.py,sha256=2ywouz7y4M4NSdvZ_DMPYZX5xCpt5zIR5z5rEgl7znI,8410
|
|
374
380
|
flwr/supercore/version.py,sha256=7GAGzPn73Mkh09qhrjbmjZQtcqVhBuzhFBaK4Mk4VRk,1325
|
|
375
381
|
flwr/superlink/__init__.py,sha256=GNSuJ4-N6Z8wun2iZNlXqENt5beUyzC0Gi_tN396bbM,707
|
|
376
382
|
flwr/superlink/artifact_provider/__init__.py,sha256=pgZEcVPKRE874LSu3cgy0HbwSJBIpVy_HxQOmne4PAs,810
|
|
@@ -380,7 +386,7 @@ flwr/superlink/auth_plugin/auth_plugin.py,sha256=xLqAYFG7sjAhYgyeTvvEY6fSMjPRq0o
|
|
|
380
386
|
flwr/superlink/auth_plugin/noop_auth_plugin.py,sha256=0MWjNXZdz6zGRfitlnZfVKu4sKVn0HhJvnp09c3xVUA,2962
|
|
381
387
|
flwr/superlink/federation/__init__.py,sha256=A1pFFvkEQrHzvRAOstr2o7nphx3JbuJgkNRFKJ9qD3M,890
|
|
382
388
|
flwr/superlink/federation/federation_manager.py,sha256=-Vu1v_WWhWK7wgKEQua24lw9a6iPxG89VI-jqLO5E4g,2322
|
|
383
|
-
flwr/superlink/federation/noop_federation_manager.py,sha256=
|
|
389
|
+
flwr/superlink/federation/noop_federation_manager.py,sha256=YqAfmbxUPzFrivZNAheJtDEpUjTLaxPi-k7tuZTAvoU,3045
|
|
384
390
|
flwr/superlink/servicer/__init__.py,sha256=ZC-kILcUGeh6IxJsfu24cTzUqIGXmQfEKsGfhsnhBpM,717
|
|
385
391
|
flwr/superlink/servicer/control/__init__.py,sha256=qhUTMt_Mg4lxslCJYn5hDSrA-lXf5ya3617BT8kR-2Y,803
|
|
386
392
|
flwr/superlink/servicer/control/control_account_auth_interceptor.py,sha256=AJs7GE-fyUBLcUEUzB058TpFzC7gyDOL17THvYkJTn8,6529
|
|
@@ -401,8 +407,8 @@ flwr/supernode/runtime/run_clientapp.py,sha256=-JsN3h7jQC12vzDBmImzYmyccI3LveIu-
|
|
|
401
407
|
flwr/supernode/servicer/__init__.py,sha256=lucTzre5WPK7G1YLCfaqg3rbFWdNSb7ZTt-ca8gxdEo,717
|
|
402
408
|
flwr/supernode/servicer/clientappio/__init__.py,sha256=7Oy62Y_oijqF7Dxi6tpcUQyOpLc_QpIRZ83NvwmB0Yg,813
|
|
403
409
|
flwr/supernode/servicer/clientappio/clientappio_servicer.py,sha256=rRL4CQ0L78jF_p0ct4-JMGREt6wWRy__wy4czF4f54Y,11639
|
|
404
|
-
flwr/supernode/start_client_internal.py,sha256=
|
|
405
|
-
flwr_nightly-1.26.0.
|
|
406
|
-
flwr_nightly-1.26.0.
|
|
407
|
-
flwr_nightly-1.26.0.
|
|
408
|
-
flwr_nightly-1.26.0.
|
|
410
|
+
flwr/supernode/start_client_internal.py,sha256=AUzEUFJbKRvyJbOjE6b6kShJrd4aJkqqOZgCokY67_A,26252
|
|
411
|
+
flwr_nightly-1.26.0.dev20260128.dist-info/METADATA,sha256=vwyjsIU9OBUX7zRbFGbUOqciYyerGlRDba7iSXcEfOM,14439
|
|
412
|
+
flwr_nightly-1.26.0.dev20260128.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
413
|
+
flwr_nightly-1.26.0.dev20260128.dist-info/entry_points.txt,sha256=hxHD2ixb_vJFDOlZV-zB4Ao32_BQlL34ftsDh1GXv14,420
|
|
414
|
+
flwr_nightly-1.26.0.dev20260128.dist-info/RECORD,,
|
{flwr_nightly-1.26.0.dev20260126.dist-info → flwr_nightly-1.26.0.dev20260128.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|