flwr-nightly 1.19.0.dev20250521__py3-none-any.whl → 1.19.0.dev20250523__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/client/grpc_adapter_client/connection.py +4 -4
- flwr/client/grpc_rere_client/connection.py +4 -4
- flwr/client/rest_client/connection.py +4 -4
- flwr/common/inflatable.py +23 -0
- flwr/common/inflatable_grpc_utils.py +2 -0
- flwr/compat/client/app.py +2 -2
- flwr/proto/run_pb2.py +19 -27
- flwr/proto/run_pb2.pyi +0 -51
- flwr/proto/serverappio_pb2.py +2 -2
- flwr/proto/serverappio_pb2_grpc.py +0 -34
- flwr/proto/serverappio_pb2_grpc.pyi +0 -13
- flwr/server/app.py +12 -1
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +6 -1
- flwr/server/superlink/serverappio/serverappio_grpc.py +3 -0
- flwr/server/superlink/serverappio/serverappio_servicer.py +7 -32
- flwr/supercore/object_store/__init__.py +23 -0
- flwr/supercore/object_store/in_memory_object_store.py +65 -0
- flwr/supercore/object_store/object_store.py +86 -0
- flwr/supercore/object_store/object_store_factory.py +44 -0
- flwr/{client/supernode → supernode/cli}/__init__.py +3 -5
- flwr/{client/supernode/app.py → supernode/cli/flower_supernode.py} +2 -10
- flwr/{client → supernode}/start_client_internal.py +179 -301
- {flwr_nightly-1.19.0.dev20250521.dist-info → flwr_nightly-1.19.0.dev20250523.dist-info}/METADATA +1 -1
- {flwr_nightly-1.19.0.dev20250521.dist-info → flwr_nightly-1.19.0.dev20250523.dist-info}/RECORD +28 -24
- {flwr_nightly-1.19.0.dev20250521.dist-info → flwr_nightly-1.19.0.dev20250523.dist-info}/entry_points.txt +1 -1
- /flwr/{client → compat/client}/grpc_client/__init__.py +0 -0
- /flwr/{client → compat/client}/grpc_client/connection.py +0 -0
- {flwr_nightly-1.19.0.dev20250521.dist-info → flwr_nightly-1.19.0.dev20250523.dist-info}/WHEEL +0 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
# Copyright 2025 Flower Labs GmbH. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
# ==============================================================================
|
15
|
+
"""Flower in-memory ObjectStore implementation."""
|
16
|
+
|
17
|
+
|
18
|
+
from typing import Optional
|
19
|
+
|
20
|
+
from flwr.common.inflatable import get_object_id, is_valid_sha256_hash
|
21
|
+
|
22
|
+
from .object_store import ObjectStore
|
23
|
+
|
24
|
+
|
25
|
+
class InMemoryObjectStore(ObjectStore):
|
26
|
+
"""In-memory implementation of the ObjectStore interface."""
|
27
|
+
|
28
|
+
def __init__(self, verify: bool = True) -> None:
|
29
|
+
self.verify = verify
|
30
|
+
self.store: dict[str, bytes] = {}
|
31
|
+
|
32
|
+
def put(self, object_id: str, object_content: bytes) -> None:
|
33
|
+
"""Put an object into the store."""
|
34
|
+
# Verify object ID format (must be a valid sha256 hash)
|
35
|
+
if not is_valid_sha256_hash(object_id):
|
36
|
+
raise ValueError(f"Invalid object ID format: {object_id}")
|
37
|
+
|
38
|
+
# Verify object_id and object_content match
|
39
|
+
if self.verify:
|
40
|
+
object_id_from_content = get_object_id(object_content)
|
41
|
+
if object_id != object_id_from_content:
|
42
|
+
raise ValueError(f"Object ID {object_id} does not match content hash")
|
43
|
+
|
44
|
+
# Return if object is already present in the store
|
45
|
+
if object_id in self.store:
|
46
|
+
return
|
47
|
+
|
48
|
+
self.store[object_id] = object_content
|
49
|
+
|
50
|
+
def get(self, object_id: str) -> Optional[bytes]:
|
51
|
+
"""Get an object from the store."""
|
52
|
+
return self.store.get(object_id)
|
53
|
+
|
54
|
+
def delete(self, object_id: str) -> None:
|
55
|
+
"""Delete an object from the store."""
|
56
|
+
if object_id in self.store:
|
57
|
+
del self.store[object_id]
|
58
|
+
|
59
|
+
def clear(self) -> None:
|
60
|
+
"""Clear the store."""
|
61
|
+
self.store.clear()
|
62
|
+
|
63
|
+
def __contains__(self, object_id: str) -> bool:
|
64
|
+
"""Check if an object_id is in the store."""
|
65
|
+
return object_id in self.store
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# Copyright 2025 Flower Labs GmbH. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
# ==============================================================================
|
15
|
+
"""Flower abstract ObjectStore definition."""
|
16
|
+
|
17
|
+
|
18
|
+
import abc
|
19
|
+
from typing import Optional
|
20
|
+
|
21
|
+
|
22
|
+
class ObjectStore(abc.ABC):
|
23
|
+
"""Abstract base class for `ObjectStore` implementations.
|
24
|
+
|
25
|
+
This class defines the interface for an object store that can store, retrieve, and
|
26
|
+
delete objects identified by object IDs.
|
27
|
+
"""
|
28
|
+
|
29
|
+
@abc.abstractmethod
|
30
|
+
def put(self, object_id: str, object_content: bytes) -> None:
|
31
|
+
"""Put an object into the store.
|
32
|
+
|
33
|
+
Parameters
|
34
|
+
----------
|
35
|
+
object_id : str
|
36
|
+
The object_id under which to store the object.
|
37
|
+
object_content : bytes
|
38
|
+
The deflated object to store.
|
39
|
+
"""
|
40
|
+
|
41
|
+
@abc.abstractmethod
|
42
|
+
def get(self, object_id: str) -> Optional[bytes]:
|
43
|
+
"""Get an object from the store.
|
44
|
+
|
45
|
+
Parameters
|
46
|
+
----------
|
47
|
+
object_id : str
|
48
|
+
The object_id under which the object is stored.
|
49
|
+
|
50
|
+
Returns
|
51
|
+
-------
|
52
|
+
bytes
|
53
|
+
The object stored under the given object_id.
|
54
|
+
"""
|
55
|
+
|
56
|
+
@abc.abstractmethod
|
57
|
+
def delete(self, object_id: str) -> None:
|
58
|
+
"""Delete an object from the store.
|
59
|
+
|
60
|
+
Parameters
|
61
|
+
----------
|
62
|
+
object_id : str
|
63
|
+
The object_id under which the object is stored.
|
64
|
+
"""
|
65
|
+
|
66
|
+
@abc.abstractmethod
|
67
|
+
def clear(self) -> None:
|
68
|
+
"""Clear the store.
|
69
|
+
|
70
|
+
This method should remove all objects from the store.
|
71
|
+
"""
|
72
|
+
|
73
|
+
@abc.abstractmethod
|
74
|
+
def __contains__(self, object_id: str) -> bool:
|
75
|
+
"""Check if an object_id is in the store.
|
76
|
+
|
77
|
+
Parameters
|
78
|
+
----------
|
79
|
+
object_id : str
|
80
|
+
The object_id to check.
|
81
|
+
|
82
|
+
Returns
|
83
|
+
-------
|
84
|
+
bool
|
85
|
+
True if the object_id is in the store, False otherwise.
|
86
|
+
"""
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Copyright 2025 Flower Labs GmbH. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
# ==============================================================================
|
15
|
+
"""Factory class that creates ObjectStore instances."""
|
16
|
+
|
17
|
+
|
18
|
+
from logging import DEBUG
|
19
|
+
from typing import Optional
|
20
|
+
|
21
|
+
from flwr.common.logger import log
|
22
|
+
|
23
|
+
from .in_memory_object_store import InMemoryObjectStore
|
24
|
+
from .object_store import ObjectStore
|
25
|
+
|
26
|
+
|
27
|
+
class ObjectStoreFactory:
|
28
|
+
"""Factory class that creates ObjectStore instances."""
|
29
|
+
|
30
|
+
def __init__(self) -> None:
|
31
|
+
self.store_instance: Optional[ObjectStore] = None
|
32
|
+
|
33
|
+
def store(self) -> ObjectStore:
|
34
|
+
"""Return an ObjectStore instance and create it, if necessary.
|
35
|
+
|
36
|
+
Returns
|
37
|
+
-------
|
38
|
+
ObjectStore
|
39
|
+
An ObjectStore instance for storing objects by object_id.
|
40
|
+
"""
|
41
|
+
if self.store_instance is None:
|
42
|
+
self.store_instance = InMemoryObjectStore()
|
43
|
+
log(DEBUG, "Using InMemoryObjectStore")
|
44
|
+
return self.store_instance
|
@@ -12,11 +12,9 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
# ==============================================================================
|
15
|
-
"""Flower SuperNode."""
|
15
|
+
"""Flower command line interface for SuperNode."""
|
16
16
|
|
17
17
|
|
18
|
-
from .
|
18
|
+
from .flower_supernode import flower_supernode
|
19
19
|
|
20
|
-
__all__ = [
|
21
|
-
"run_supernode",
|
22
|
-
]
|
20
|
+
__all__ = ["flower_supernode"]
|
@@ -12,7 +12,7 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
# ==============================================================================
|
15
|
-
"""
|
15
|
+
"""`flower-supernode` command."""
|
16
16
|
|
17
17
|
|
18
18
|
import argparse
|
@@ -43,11 +43,10 @@ from flwr.common.exit import ExitCode, flwr_exit
|
|
43
43
|
from flwr.common.exit_handlers import register_exit_handlers
|
44
44
|
from flwr.common.logger import log
|
45
45
|
|
46
|
-
from ..clientapp.utils import get_load_client_app_fn
|
47
46
|
from ..start_client_internal import start_client_internal
|
48
47
|
|
49
48
|
|
50
|
-
def
|
49
|
+
def flower_supernode() -> None:
|
51
50
|
"""Run Flower SuperNode."""
|
52
51
|
args = _parse_args_run_supernode().parse_args()
|
53
52
|
|
@@ -64,12 +63,6 @@ def run_supernode() -> None:
|
|
64
63
|
)
|
65
64
|
|
66
65
|
root_certificates = try_obtain_root_certificates(args, args.superlink)
|
67
|
-
load_fn = get_load_client_app_fn(
|
68
|
-
default_app_ref="",
|
69
|
-
app_path=None,
|
70
|
-
flwr_dir=args.flwr_dir,
|
71
|
-
multi_app=True,
|
72
|
-
)
|
73
66
|
authentication_keys = _try_setup_client_authentication(args)
|
74
67
|
|
75
68
|
log(DEBUG, "Isolation mode: %s", args.isolation)
|
@@ -82,7 +75,6 @@ def run_supernode() -> None:
|
|
82
75
|
|
83
76
|
start_client_internal(
|
84
77
|
server_address=args.superlink,
|
85
|
-
load_client_app_fn=load_fn,
|
86
78
|
transport=args.transport,
|
87
79
|
root_certificates=root_certificates,
|
88
80
|
insecure=args.insecure,
|