flwr-nightly 1.26.0.dev20260127__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/config/ls.py +1 -1
- flwr/cli/constant.py +0 -1
- flwr/cli/federation/ls.py +1 -1
- flwr/cli/ls.py +1 -1
- flwr/cli/supernode/ls.py +1 -1
- flwr/cli/typing.py +10 -5
- 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/supercore/address.py +9 -0
- 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/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.dev20260127.dist-info → flwr_nightly-1.26.0.dev20260128.dist-info}/METADATA +2 -1
- {flwr_nightly-1.26.0.dev20260127.dist-info → flwr_nightly-1.26.0.dev20260128.dist-info}/RECORD +27 -21
- {flwr_nightly-1.26.0.dev20260127.dist-info → flwr_nightly-1.26.0.dev20260128.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.26.0.dev20260127.dist-info → flwr_nightly-1.26.0.dev20260128.dist-info}/entry_points.txt +0 -0
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/constant.py
CHANGED
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/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
|
|
|
@@ -176,11 +177,15 @@ class SuperLinkConnection:
|
|
|
176
177
|
+ f"expected bool, but got {type(self._insecure).__name__}."
|
|
177
178
|
)
|
|
178
179
|
|
|
179
|
-
if self.federation is not None
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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)
|
|
184
189
|
|
|
185
190
|
# The connection needs to have either an address or options (or both).
|
|
186
191
|
if self.address is None and self.options is None:
|
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,
|
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/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 ###
|
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.dev20260127.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.dev20260127.dist-info → flwr_nightly-1.26.0.dev20260128.dist-info}/RECORD
RENAMED
|
@@ -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=
|
|
20
|
+
flwr/cli/config/ls.py,sha256=i976g1rzpSLEagyjEFdxxYAM-FqaP0Unqlk2EiKj4B4,3549
|
|
21
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=
|
|
26
|
+
flwr/cli/federation/ls.py,sha256=SZrQb_uUBrK2v4nAo3GETxyVBoNpBUJLjQuE_maX8_E,10737
|
|
27
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
31
|
flwr/cli/login/login.py,sha256=o-jm5QRMIpivE8kpY7cPTGbr7nQhsyFYaftMtBaaT0s,3649
|
|
32
|
-
flwr/cli/ls.py,sha256=
|
|
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,10 +38,10 @@ 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=
|
|
44
|
+
flwr/cli/typing.py,sha256=COLEK_zVQuGGm4t_nYAW0_8EWu09zFiAv-tEZNg95_s,7367
|
|
45
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
|
|
@@ -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
|
|
@@ -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=
|
|
327
|
+
flwr/supercore/address.py,sha256=SgM_pazKsw1Avo5nms0WWgIZFUGS349O0gOP7N3bFW4,3318
|
|
328
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,8 +355,14 @@ 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/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
|
|
360
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
|
|
@@ -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.dev20260127.dist-info → flwr_nightly-1.26.0.dev20260128.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|