flwr-nightly 1.7.0.dev20240125__py3-none-any.whl → 1.7.0.dev20240126__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/app.py +5 -5
- flwr/client/client.py +8 -8
- flwr/client/flower.py +3 -3
- flwr/client/message_handler/message_handler.py +15 -15
- flwr/client/node_state.py +16 -15
- flwr/client/node_state_tests.py +18 -13
- flwr/client/numpy_client.py +16 -16
- flwr/client/typing.py +3 -3
- flwr/common/serde.py +14 -4
- flwr/simulation/ray_transport/ray_actor.py +19 -19
- flwr/simulation/ray_transport/ray_client_proxy.py +4 -4
- {flwr_nightly-1.7.0.dev20240125.dist-info → flwr_nightly-1.7.0.dev20240126.dist-info}/METADATA +1 -1
- {flwr_nightly-1.7.0.dev20240125.dist-info → flwr_nightly-1.7.0.dev20240126.dist-info}/RECORD +16 -17
- flwr/client/run_state.py +0 -25
- {flwr_nightly-1.7.0.dev20240125.dist-info → flwr_nightly-1.7.0.dev20240126.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.7.0.dev20240125.dist-info → flwr_nightly-1.7.0.dev20240126.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.7.0.dev20240125.dist-info → flwr_nightly-1.7.0.dev20240126.dist-info}/entry_points.txt +0 -0
flwr/client/app.py
CHANGED
@@ -352,7 +352,7 @@ def _start_client_internal(
|
|
352
352
|
break
|
353
353
|
|
354
354
|
# Register state
|
355
|
-
node_state.
|
355
|
+
node_state.register_context(run_id=task_ins.run_id)
|
356
356
|
|
357
357
|
# Load app
|
358
358
|
app: Flower = load_flower_callable_fn()
|
@@ -360,14 +360,14 @@ def _start_client_internal(
|
|
360
360
|
# Handle task message
|
361
361
|
fwd_msg: Fwd = Fwd(
|
362
362
|
task_ins=task_ins,
|
363
|
-
|
363
|
+
context=node_state.retrieve_context(run_id=task_ins.run_id),
|
364
364
|
)
|
365
365
|
bwd_msg: Bwd = app(fwd=fwd_msg)
|
366
366
|
|
367
367
|
# Update node state
|
368
|
-
node_state.
|
369
|
-
run_id=
|
370
|
-
|
368
|
+
node_state.update_context(
|
369
|
+
run_id=fwd_msg.task_ins.run_id,
|
370
|
+
context=bwd_msg.context,
|
371
371
|
)
|
372
372
|
|
373
373
|
# Send
|
flwr/client/client.py
CHANGED
@@ -19,7 +19,6 @@ from __future__ import annotations
|
|
19
19
|
|
20
20
|
from abc import ABC
|
21
21
|
|
22
|
-
from flwr.client.run_state import RunState
|
23
22
|
from flwr.common import (
|
24
23
|
Code,
|
25
24
|
EvaluateIns,
|
@@ -33,12 +32,13 @@ from flwr.common import (
|
|
33
32
|
Parameters,
|
34
33
|
Status,
|
35
34
|
)
|
35
|
+
from flwr.common.context import Context
|
36
36
|
|
37
37
|
|
38
38
|
class Client(ABC):
|
39
39
|
"""Abstract base class for Flower clients."""
|
40
40
|
|
41
|
-
|
41
|
+
context: Context
|
42
42
|
|
43
43
|
def get_properties(self, ins: GetPropertiesIns) -> GetPropertiesRes:
|
44
44
|
"""Return set of client's properties.
|
@@ -141,13 +141,13 @@ class Client(ABC):
|
|
141
141
|
metrics={},
|
142
142
|
)
|
143
143
|
|
144
|
-
def
|
145
|
-
"""Get the run
|
146
|
-
return self.
|
144
|
+
def get_context(self) -> Context:
|
145
|
+
"""Get the run context from this client."""
|
146
|
+
return self.context
|
147
147
|
|
148
|
-
def
|
149
|
-
"""Apply a run
|
150
|
-
self.
|
148
|
+
def set_context(self, context: Context) -> None:
|
149
|
+
"""Apply a run context to this client."""
|
150
|
+
self.context = context
|
151
151
|
|
152
152
|
def to_client(self) -> Client:
|
153
153
|
"""Return client (itself)."""
|
flwr/client/flower.py
CHANGED
@@ -56,12 +56,12 @@ class Flower:
|
|
56
56
|
) -> None:
|
57
57
|
# Create wrapper function for `handle`
|
58
58
|
def ffn(fwd: Fwd) -> Bwd: # pylint: disable=invalid-name
|
59
|
-
task_res,
|
59
|
+
task_res, context_updated = handle(
|
60
60
|
client_fn=client_fn,
|
61
|
-
|
61
|
+
context=fwd.context,
|
62
62
|
task_ins=fwd.task_ins,
|
63
63
|
)
|
64
|
-
return Bwd(task_res=task_res,
|
64
|
+
return Bwd(task_res=task_res, context=context_updated)
|
65
65
|
|
66
66
|
# Wrap middleware layers around the wrapped handle function
|
67
67
|
self._call = make_ffn(ffn, layers if layers is not None else [])
|
@@ -28,10 +28,10 @@ from flwr.client.message_handler.task_handler import (
|
|
28
28
|
get_server_message_from_task_ins,
|
29
29
|
wrap_client_message_in_task_res,
|
30
30
|
)
|
31
|
-
from flwr.client.run_state import RunState
|
32
31
|
from flwr.client.secure_aggregation import SecureAggregationHandler
|
33
32
|
from flwr.client.typing import ClientFn
|
34
33
|
from flwr.common import serde
|
34
|
+
from flwr.common.context import Context
|
35
35
|
from flwr.proto.task_pb2 import ( # pylint: disable=E0611
|
36
36
|
SecureAggregation,
|
37
37
|
Task,
|
@@ -88,16 +88,16 @@ def handle_control_message(task_ins: TaskIns) -> Tuple[Optional[TaskRes], int]:
|
|
88
88
|
|
89
89
|
|
90
90
|
def handle(
|
91
|
-
client_fn: ClientFn,
|
92
|
-
) -> Tuple[TaskRes,
|
91
|
+
client_fn: ClientFn, context: Context, task_ins: TaskIns
|
92
|
+
) -> Tuple[TaskRes, Context]:
|
93
93
|
"""Handle incoming TaskIns from the server.
|
94
94
|
|
95
95
|
Parameters
|
96
96
|
----------
|
97
97
|
client_fn : ClientFn
|
98
98
|
A callable that instantiates a Client.
|
99
|
-
|
100
|
-
A dataclass storing the
|
99
|
+
context : Context
|
100
|
+
A dataclass storing the context for the run being executed by the client.
|
101
101
|
task_ins: TaskIns
|
102
102
|
The task instruction coming from the server, to be processed by the client.
|
103
103
|
|
@@ -110,7 +110,7 @@ def handle(
|
|
110
110
|
if server_msg is None:
|
111
111
|
# Instantiate the client
|
112
112
|
client = client_fn("-1")
|
113
|
-
client.
|
113
|
+
client.set_context(context)
|
114
114
|
# Secure Aggregation
|
115
115
|
if task_ins.task.HasField("sa") and isinstance(
|
116
116
|
client, SecureAggregationHandler
|
@@ -127,24 +127,24 @@ def handle(
|
|
127
127
|
sa=SecureAggregation(named_values=serde.named_values_to_proto(res)),
|
128
128
|
),
|
129
129
|
)
|
130
|
-
return task_res, client.
|
130
|
+
return task_res, client.get_context()
|
131
131
|
raise NotImplementedError()
|
132
|
-
client_msg,
|
132
|
+
client_msg, updated_context = handle_legacy_message(client_fn, context, server_msg)
|
133
133
|
task_res = wrap_client_message_in_task_res(client_msg)
|
134
|
-
return task_res,
|
134
|
+
return task_res, updated_context
|
135
135
|
|
136
136
|
|
137
137
|
def handle_legacy_message(
|
138
|
-
client_fn: ClientFn,
|
139
|
-
) -> Tuple[ClientMessage,
|
138
|
+
client_fn: ClientFn, context: Context, server_msg: ServerMessage
|
139
|
+
) -> Tuple[ClientMessage, Context]:
|
140
140
|
"""Handle incoming messages from the server.
|
141
141
|
|
142
142
|
Parameters
|
143
143
|
----------
|
144
144
|
client_fn : ClientFn
|
145
145
|
A callable that instantiates a Client.
|
146
|
-
|
147
|
-
A dataclass storing the
|
146
|
+
context : Context
|
147
|
+
A dataclass storing the context for the run being executed by the client.
|
148
148
|
server_msg: ServerMessage
|
149
149
|
The message coming from the server, to be processed by the client.
|
150
150
|
|
@@ -161,7 +161,7 @@ def handle_legacy_message(
|
|
161
161
|
|
162
162
|
# Instantiate the client
|
163
163
|
client = client_fn("-1")
|
164
|
-
client.
|
164
|
+
client.set_context(context)
|
165
165
|
# Execute task
|
166
166
|
message = None
|
167
167
|
if field == "get_properties_ins":
|
@@ -173,7 +173,7 @@ def handle_legacy_message(
|
|
173
173
|
if field == "evaluate_ins":
|
174
174
|
message = _evaluate(client, server_msg.evaluate_ins)
|
175
175
|
if message:
|
176
|
-
return message, client.
|
176
|
+
return message, client.get_context()
|
177
177
|
raise UnknownServerMessage()
|
178
178
|
|
179
179
|
|
flwr/client/node_state.py
CHANGED
@@ -17,7 +17,8 @@
|
|
17
17
|
|
18
18
|
from typing import Any, Dict
|
19
19
|
|
20
|
-
from flwr.
|
20
|
+
from flwr.common.context import Context
|
21
|
+
from flwr.common.recordset import RecordSet
|
21
22
|
|
22
23
|
|
23
24
|
class NodeState:
|
@@ -25,24 +26,24 @@ class NodeState:
|
|
25
26
|
|
26
27
|
def __init__(self) -> None:
|
27
28
|
self._meta: Dict[str, Any] = {} # holds metadata about the node
|
28
|
-
self.
|
29
|
+
self.run_contexts: Dict[int, Context] = {}
|
29
30
|
|
30
|
-
def
|
31
|
-
"""Register new run
|
32
|
-
if run_id not in self.
|
33
|
-
self.
|
31
|
+
def register_context(self, run_id: int) -> None:
|
32
|
+
"""Register new run context for this node."""
|
33
|
+
if run_id not in self.run_contexts:
|
34
|
+
self.run_contexts[run_id] = Context(state=RecordSet())
|
34
35
|
|
35
|
-
def
|
36
|
-
"""Get run
|
37
|
-
if run_id in self.
|
38
|
-
return self.
|
36
|
+
def retrieve_context(self, run_id: int) -> Context:
|
37
|
+
"""Get run context given a run_id."""
|
38
|
+
if run_id in self.run_contexts:
|
39
|
+
return self.run_contexts[run_id]
|
39
40
|
|
40
41
|
raise RuntimeError(
|
41
|
-
f"
|
42
|
-
" A run must be registered before it can be retrieved or updated "
|
42
|
+
f"Context for run_id={run_id} doesn't exist."
|
43
|
+
" A run context must be registered before it can be retrieved or updated "
|
43
44
|
" by a client."
|
44
45
|
)
|
45
46
|
|
46
|
-
def
|
47
|
-
"""Update run
|
48
|
-
self.
|
47
|
+
def update_context(self, run_id: int, context: Context) -> None:
|
48
|
+
"""Update run context."""
|
49
|
+
self.run_contexts[run_id] = context
|
flwr/client/node_state_tests.py
CHANGED
@@ -16,17 +16,22 @@
|
|
16
16
|
|
17
17
|
|
18
18
|
from flwr.client.node_state import NodeState
|
19
|
-
from flwr.
|
19
|
+
from flwr.common.configsrecord import ConfigsRecord
|
20
|
+
from flwr.common.context import Context
|
20
21
|
from flwr.proto.task_pb2 import TaskIns # pylint: disable=E0611
|
21
22
|
|
22
23
|
|
23
|
-
def _run_dummy_task(
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
def _run_dummy_task(context: Context) -> Context:
|
25
|
+
counter_value: str = "1"
|
26
|
+
if "counter" in context.state.configs.keys():
|
27
|
+
counter_value = context.get_configs("counter")["count"] # type: ignore
|
28
|
+
counter_value += "1"
|
28
29
|
|
29
|
-
|
30
|
+
context.state.set_configs(
|
31
|
+
name="counter", record=ConfigsRecord({"count": counter_value})
|
32
|
+
)
|
33
|
+
|
34
|
+
return context
|
30
35
|
|
31
36
|
|
32
37
|
def test_multirun_in_node_state() -> None:
|
@@ -43,17 +48,17 @@ def test_multirun_in_node_state() -> None:
|
|
43
48
|
run_id = task.run_id
|
44
49
|
|
45
50
|
# Register
|
46
|
-
node_state.
|
51
|
+
node_state.register_context(run_id=run_id)
|
47
52
|
|
48
53
|
# Get run state
|
49
|
-
|
54
|
+
context = node_state.retrieve_context(run_id=run_id)
|
50
55
|
|
51
56
|
# Run "task"
|
52
|
-
updated_state = _run_dummy_task(
|
57
|
+
updated_state = _run_dummy_task(context)
|
53
58
|
|
54
59
|
# Update run state
|
55
|
-
node_state.
|
60
|
+
node_state.update_context(run_id=run_id, context=updated_state)
|
56
61
|
|
57
62
|
# Verify values
|
58
|
-
for run_id,
|
59
|
-
assert state.
|
63
|
+
for run_id, context in node_state.run_contexts.items():
|
64
|
+
assert context.state.get_configs("counter")["count"] == expected_values[run_id]
|
flwr/client/numpy_client.py
CHANGED
@@ -19,7 +19,6 @@ from abc import ABC
|
|
19
19
|
from typing import Callable, Dict, Tuple
|
20
20
|
|
21
21
|
from flwr.client.client import Client
|
22
|
-
from flwr.client.run_state import RunState
|
23
22
|
from flwr.common import (
|
24
23
|
Config,
|
25
24
|
NDArrays,
|
@@ -27,6 +26,7 @@ from flwr.common import (
|
|
27
26
|
ndarrays_to_parameters,
|
28
27
|
parameters_to_ndarrays,
|
29
28
|
)
|
29
|
+
from flwr.common.context import Context
|
30
30
|
from flwr.common.typing import (
|
31
31
|
Code,
|
32
32
|
EvaluateIns,
|
@@ -70,7 +70,7 @@ Example
|
|
70
70
|
class NumPyClient(ABC):
|
71
71
|
"""Abstract base class for Flower clients using NumPy."""
|
72
72
|
|
73
|
-
|
73
|
+
context: Context
|
74
74
|
|
75
75
|
def get_properties(self, config: Config) -> Dict[str, Scalar]:
|
76
76
|
"""Return a client's set of properties.
|
@@ -174,13 +174,13 @@ class NumPyClient(ABC):
|
|
174
174
|
_ = (self, parameters, config)
|
175
175
|
return 0.0, 0, {}
|
176
176
|
|
177
|
-
def
|
178
|
-
"""Get the run
|
179
|
-
return self.
|
177
|
+
def get_context(self) -> Context:
|
178
|
+
"""Get the run context from this client."""
|
179
|
+
return self.context
|
180
180
|
|
181
|
-
def
|
182
|
-
"""Apply a run
|
183
|
-
self.
|
181
|
+
def set_context(self, context: Context) -> None:
|
182
|
+
"""Apply a run context to this client."""
|
183
|
+
self.context = context
|
184
184
|
|
185
185
|
def to_client(self) -> Client:
|
186
186
|
"""Convert to object to Client type and return it."""
|
@@ -278,21 +278,21 @@ def _evaluate(self: Client, ins: EvaluateIns) -> EvaluateRes:
|
|
278
278
|
)
|
279
279
|
|
280
280
|
|
281
|
-
def
|
282
|
-
"""Return
|
283
|
-
return self.numpy_client.
|
281
|
+
def _get_context(self: Client) -> Context:
|
282
|
+
"""Return context of underlying NumPyClient."""
|
283
|
+
return self.numpy_client.get_context() # type: ignore
|
284
284
|
|
285
285
|
|
286
|
-
def
|
287
|
-
"""Apply
|
288
|
-
self.numpy_client.
|
286
|
+
def _set_context(self: Client, context: Context) -> None:
|
287
|
+
"""Apply context to underlying NumPyClient."""
|
288
|
+
self.numpy_client.set_context(context) # type: ignore
|
289
289
|
|
290
290
|
|
291
291
|
def _wrap_numpy_client(client: NumPyClient) -> Client:
|
292
292
|
member_dict: Dict[str, Callable] = { # type: ignore
|
293
293
|
"__init__": _constructor,
|
294
|
-
"
|
295
|
-
"
|
294
|
+
"get_context": _get_context,
|
295
|
+
"set_context": _set_context,
|
296
296
|
}
|
297
297
|
|
298
298
|
# Add wrapper type methods (if overridden)
|
flwr/client/typing.py
CHANGED
@@ -17,7 +17,7 @@
|
|
17
17
|
from dataclasses import dataclass
|
18
18
|
from typing import Callable
|
19
19
|
|
20
|
-
from flwr.
|
20
|
+
from flwr.common.context import Context
|
21
21
|
from flwr.proto.task_pb2 import TaskIns, TaskRes # pylint: disable=E0611
|
22
22
|
|
23
23
|
from .client import Client as Client
|
@@ -28,7 +28,7 @@ class Fwd:
|
|
28
28
|
"""."""
|
29
29
|
|
30
30
|
task_ins: TaskIns
|
31
|
-
|
31
|
+
context: Context
|
32
32
|
|
33
33
|
|
34
34
|
@dataclass
|
@@ -36,7 +36,7 @@ class Bwd:
|
|
36
36
|
"""."""
|
37
37
|
|
38
38
|
task_res: TaskRes
|
39
|
-
|
39
|
+
context: Context
|
40
40
|
|
41
41
|
|
42
42
|
FlowerCallable = Callable[[Fwd], Bwd]
|
flwr/common/serde.py
CHANGED
@@ -601,12 +601,15 @@ T = TypeVar("T")
|
|
601
601
|
def _record_value_to_proto(
|
602
602
|
value: Any, allowed_types: List[type], proto_class: Type[T]
|
603
603
|
) -> T:
|
604
|
-
"""Serialize `*RecordValue` to ProtoBuf.
|
604
|
+
"""Serialize `*RecordValue` to ProtoBuf.
|
605
|
+
|
606
|
+
Note: `bool` MUST be put in the front of allowd_types if it exists.
|
607
|
+
"""
|
605
608
|
arg = {}
|
606
609
|
for t in allowed_types:
|
607
610
|
# Single element
|
608
611
|
# Note: `isinstance(False, int) == True`.
|
609
|
-
if
|
612
|
+
if isinstance(value, t):
|
610
613
|
arg[_type_to_field[t]] = value
|
611
614
|
return proto_class(**arg)
|
612
615
|
# List
|
@@ -634,7 +637,14 @@ def _record_value_from_proto(value_proto: GrpcMessage) -> Any:
|
|
634
637
|
def _record_value_dict_to_proto(
|
635
638
|
value_dict: Dict[str, Any], allowed_types: List[type], value_proto_class: Type[T]
|
636
639
|
) -> Dict[str, T]:
|
637
|
-
"""Serialize the record value dict to ProtoBuf.
|
640
|
+
"""Serialize the record value dict to ProtoBuf.
|
641
|
+
|
642
|
+
Note: `bool` MUST be put in the front of allowd_types if it exists.
|
643
|
+
"""
|
644
|
+
# Move bool to the front
|
645
|
+
if bool in allowed_types and allowed_types[0] != bool:
|
646
|
+
allowed_types.remove(bool)
|
647
|
+
allowed_types.insert(0, bool)
|
638
648
|
|
639
649
|
def proto(_v: Any) -> T:
|
640
650
|
return _record_value_to_proto(_v, allowed_types, value_proto_class)
|
@@ -708,7 +718,7 @@ def configs_record_to_proto(record: ConfigsRecord) -> ProtoConfigsRecord:
|
|
708
718
|
"""Serialize ConfigsRecord to ProtoBuf."""
|
709
719
|
return ProtoConfigsRecord(
|
710
720
|
data=_record_value_dict_to_proto(
|
711
|
-
record.data, [int, float,
|
721
|
+
record.data, [bool, int, float, str, bytes], ProtoConfigsRecordValue
|
712
722
|
)
|
713
723
|
)
|
714
724
|
|
@@ -27,7 +27,7 @@ from ray.util.actor_pool import ActorPool
|
|
27
27
|
|
28
28
|
from flwr import common
|
29
29
|
from flwr.client import Client, ClientFn
|
30
|
-
from flwr.
|
30
|
+
from flwr.common.context import Context
|
31
31
|
from flwr.common.logger import log
|
32
32
|
from flwr.simulation.ray_transport.utils import check_clientfn_returns_client
|
33
33
|
|
@@ -61,8 +61,8 @@ class VirtualClientEngineActor(ABC):
|
|
61
61
|
client_fn: ClientFn,
|
62
62
|
job_fn: JobFn,
|
63
63
|
cid: str,
|
64
|
-
|
65
|
-
) -> Tuple[str, ClientRes,
|
64
|
+
context: Context,
|
65
|
+
) -> Tuple[str, ClientRes, Context]:
|
66
66
|
"""Run a client run."""
|
67
67
|
# Execute tasks and return result
|
68
68
|
# return also cid which is needed to ensure results
|
@@ -70,12 +70,12 @@ class VirtualClientEngineActor(ABC):
|
|
70
70
|
try:
|
71
71
|
# Instantiate client (check 'Client' type is returned)
|
72
72
|
client = check_clientfn_returns_client(client_fn(cid))
|
73
|
-
# Inject
|
74
|
-
client.
|
73
|
+
# Inject context
|
74
|
+
client.set_context(context)
|
75
75
|
# Run client job
|
76
76
|
job_results = job_fn(client)
|
77
|
-
# Retrieve
|
78
|
-
|
77
|
+
# Retrieve context (potentially updated)
|
78
|
+
updated_context = client.get_context()
|
79
79
|
except Exception as ex:
|
80
80
|
client_trace = traceback.format_exc()
|
81
81
|
message = (
|
@@ -89,7 +89,7 @@ class VirtualClientEngineActor(ABC):
|
|
89
89
|
)
|
90
90
|
raise ClientException(str(message)) from ex
|
91
91
|
|
92
|
-
return cid, job_results,
|
92
|
+
return cid, job_results, updated_context
|
93
93
|
|
94
94
|
|
95
95
|
@ray.remote
|
@@ -237,16 +237,16 @@ class VirtualClientEngineActorPool(ActorPool):
|
|
237
237
|
self._idle_actors.extend(new_actors)
|
238
238
|
self.num_actors += num_actors
|
239
239
|
|
240
|
-
def submit(self, fn: Any, value: Tuple[ClientFn, JobFn, str,
|
240
|
+
def submit(self, fn: Any, value: Tuple[ClientFn, JobFn, str, Context]) -> None:
|
241
241
|
"""Take idle actor and assign it a client run.
|
242
242
|
|
243
243
|
Submit a job to an actor by first removing it from the list of idle actors, then
|
244
244
|
check if this actor was flagged to be removed from the pool
|
245
245
|
"""
|
246
|
-
client_fn, job_fn, cid,
|
246
|
+
client_fn, job_fn, cid, context = value
|
247
247
|
actor = self._idle_actors.pop()
|
248
248
|
if self._check_and_remove_actor_from_pool(actor):
|
249
|
-
future = fn(actor, client_fn, job_fn, cid,
|
249
|
+
future = fn(actor, client_fn, job_fn, cid, context)
|
250
250
|
future_key = tuple(future) if isinstance(future, List) else future
|
251
251
|
self._future_to_actor[future_key] = (self._next_task_index, actor, cid)
|
252
252
|
self._next_task_index += 1
|
@@ -255,7 +255,7 @@ class VirtualClientEngineActorPool(ActorPool):
|
|
255
255
|
self._cid_to_future[cid]["future"] = future_key
|
256
256
|
|
257
257
|
def submit_client_job(
|
258
|
-
self, actor_fn: Any, job: Tuple[ClientFn, JobFn, str,
|
258
|
+
self, actor_fn: Any, job: Tuple[ClientFn, JobFn, str, Context]
|
259
259
|
) -> None:
|
260
260
|
"""Submit a job while tracking client ids."""
|
261
261
|
_, _, cid, _ = job
|
@@ -295,17 +295,17 @@ class VirtualClientEngineActorPool(ActorPool):
|
|
295
295
|
|
296
296
|
return self._cid_to_future[cid]["ready"] # type: ignore
|
297
297
|
|
298
|
-
def _fetch_future_result(self, cid: str) -> Tuple[ClientRes,
|
299
|
-
"""Fetch result and updated
|
298
|
+
def _fetch_future_result(self, cid: str) -> Tuple[ClientRes, Context]:
|
299
|
+
"""Fetch result and updated context for a VirtualClient from Object Store.
|
300
300
|
|
301
301
|
The job submitted by the ClientProxy interfacing with client with cid=cid is
|
302
302
|
ready. Here we fetch it from the object store and return.
|
303
303
|
"""
|
304
304
|
try:
|
305
305
|
future: ObjectRef[Any] = self._cid_to_future[cid]["future"] # type: ignore
|
306
|
-
res_cid, res,
|
306
|
+
res_cid, res, updated_context = ray.get(
|
307
307
|
future
|
308
|
-
) # type: (str, ClientRes,
|
308
|
+
) # type: (str, ClientRes, Context)
|
309
309
|
except ray.exceptions.RayActorError as ex:
|
310
310
|
log(ERROR, ex)
|
311
311
|
if hasattr(ex, "actor_id"):
|
@@ -322,7 +322,7 @@ class VirtualClientEngineActorPool(ActorPool):
|
|
322
322
|
# Reset mapping
|
323
323
|
self._reset_cid_to_future_dict(cid)
|
324
324
|
|
325
|
-
return res,
|
325
|
+
return res, updated_context
|
326
326
|
|
327
327
|
def _flag_actor_for_removal(self, actor_id_hex: str) -> None:
|
328
328
|
"""Flag actor that should be removed from pool."""
|
@@ -409,7 +409,7 @@ class VirtualClientEngineActorPool(ActorPool):
|
|
409
409
|
|
410
410
|
def get_client_result(
|
411
411
|
self, cid: str, timeout: Optional[float]
|
412
|
-
) -> Tuple[ClientRes,
|
412
|
+
) -> Tuple[ClientRes, Context]:
|
413
413
|
"""Get result from VirtualClient with specific cid."""
|
414
414
|
# Loop until all jobs submitted to the pool are completed. Break early
|
415
415
|
# if the result for the ClientProxy calling this method is ready
|
@@ -421,5 +421,5 @@ class VirtualClientEngineActorPool(ActorPool):
|
|
421
421
|
break
|
422
422
|
|
423
423
|
# Fetch result belonging to the VirtualClient calling this method
|
424
|
-
# Return both result from tasks and (potentially) updated run
|
424
|
+
# Return both result from tasks and (potentially) updated run context
|
425
425
|
return self._fetch_future_result(cid)
|
@@ -138,20 +138,20 @@ class RayActorClientProxy(ClientProxy):
|
|
138
138
|
run_id = 0
|
139
139
|
|
140
140
|
# Register state
|
141
|
-
self.proxy_state.
|
141
|
+
self.proxy_state.register_context(run_id=run_id)
|
142
142
|
|
143
143
|
# Retrieve state
|
144
|
-
state = self.proxy_state.
|
144
|
+
state = self.proxy_state.retrieve_context(run_id=run_id)
|
145
145
|
|
146
146
|
try:
|
147
147
|
self.actor_pool.submit_client_job(
|
148
148
|
lambda a, c_fn, j_fn, cid, state: a.run.remote(c_fn, j_fn, cid, state),
|
149
149
|
(self.client_fn, job_fn, self.cid, state),
|
150
150
|
)
|
151
|
-
res,
|
151
|
+
res, updated_context = self.actor_pool.get_client_result(self.cid, timeout)
|
152
152
|
|
153
153
|
# Update state
|
154
|
-
self.proxy_state.
|
154
|
+
self.proxy_state.update_context(run_id=run_id, context=updated_context)
|
155
155
|
|
156
156
|
except Exception as ex:
|
157
157
|
if self.actor_pool.num_actors == 0:
|
{flwr_nightly-1.7.0.dev20240125.dist-info → flwr_nightly-1.7.0.dev20240126.dist-info}/RECORD
RENAMED
@@ -1,28 +1,27 @@
|
|
1
1
|
flwr/__init__.py,sha256=6zbcS7z2q-VUdmpFppLH6BacsE-ZFmfq6OvtKNOyYE0,981
|
2
2
|
flwr/client/__init__.py,sha256=2T4enmlE4PsoKiGTvXwBKSlhOjZ7MXRy5oCGNf0UH9Y,1111
|
3
|
-
flwr/client/app.py,sha256=
|
4
|
-
flwr/client/client.py,sha256=
|
3
|
+
flwr/client/app.py,sha256=B0pa8BZ5oLYRs1Fs7KhqYOxM3Sy6w9LmUt-hQfjTlBA,19242
|
4
|
+
flwr/client/client.py,sha256=ATcsqAMS9zpMBJ9ZUbBeB7BEPWX_VWISONy0p6Wxl5g,8210
|
5
5
|
flwr/client/dpfedavg_numpy_client.py,sha256=0XryFdCMM_RLiNLCr6evLp-6R7ZjeMmRUROIgzRmtmc,7215
|
6
|
-
flwr/client/flower.py,sha256=
|
6
|
+
flwr/client/flower.py,sha256=Xh3v7NgAliaLEjwMC6hhq_E0YxaVbHqwEd0HqwWe2lo,4059
|
7
7
|
flwr/client/grpc_client/__init__.py,sha256=LsnbqXiJhgQcB0XzAlUQgPx011Uf7Y7yabIC1HxivJ8,735
|
8
8
|
flwr/client/grpc_client/connection.py,sha256=WJazRjWZuSLnE4jsGtJ86g9THewbAfspQ-XtmfGR8uQ,5115
|
9
9
|
flwr/client/grpc_rere_client/__init__.py,sha256=avn6W_vHEM_yZEB1S7hCZgnTbXb6ZujqRP_vAzyXu-0,752
|
10
10
|
flwr/client/grpc_rere_client/connection.py,sha256=NtYxwJCucI9RYieU9rVMi5wzrnvLNxhSWYmi5IiWAtc,6660
|
11
11
|
flwr/client/message_handler/__init__.py,sha256=abHvBRJJiiaAMNgeILQbMOa6h8WqMK2BcnvxwQZFpic,719
|
12
|
-
flwr/client/message_handler/message_handler.py,sha256=
|
12
|
+
flwr/client/message_handler/message_handler.py,sha256=vhVhFdohM3q6xz5bqcDLSTyR9viFUAkbBKHCTiB4qyQ,8414
|
13
13
|
flwr/client/message_handler/task_handler.py,sha256=36g-gP7oH_VDpsjW2P9LH4uzlDkygY8S9FyGxjbSw34,5823
|
14
14
|
flwr/client/middleware/__init__.py,sha256=Eo3JvAV5XqmyRySNqeiw93YNETmmP5ixEOMeBA6ah4w,769
|
15
15
|
flwr/client/middleware/utils.py,sha256=QUghso_SWsKTUPfKwrtBwPyyJoEI9AV9hRY2acu1TYE,1168
|
16
|
-
flwr/client/node_state.py,sha256=
|
17
|
-
flwr/client/node_state_tests.py,sha256=
|
18
|
-
flwr/client/numpy_client.py,sha256=
|
16
|
+
flwr/client/node_state.py,sha256=0hk1RZuFZ3_S7Y8Q0BCP60NljxnT9vqPmIflvCCGxnQ,1819
|
17
|
+
flwr/client/node_state_tests.py,sha256=H3sO526boAlDS491fO5xvZhl5XNDzzl-I8DiaVmnsXM,2195
|
18
|
+
flwr/client/numpy_client.py,sha256=42e8_gZU5gwzpvVXQr6LEWEGfpWYTcQ0MY0F0owNlAc,10310
|
19
19
|
flwr/client/rest_client/__init__.py,sha256=ThwOnkMdzxo_UuyTI47Q7y9oSpuTgNT2OuFvJCfuDiw,735
|
20
20
|
flwr/client/rest_client/connection.py,sha256=j8BpGRM4mGJrkw7Yncpwk-BJ6KOw0C3PS3tqLfsUUes,11762
|
21
|
-
flwr/client/run_state.py,sha256=d4UmHLt9zMd0sTgnVdRsLgr1QEx0l5PtJ0dPv2NSVVw,867
|
22
21
|
flwr/client/secure_aggregation/__init__.py,sha256=XCDycteBTivym0zwkwqXhFMCAoDoHBZQg5GxdMnFCfA,888
|
23
22
|
flwr/client/secure_aggregation/handler.py,sha256=oRyGCerz92aED7UydYwJ7OFVxUwHqedG3PshHrdZq-Y,1522
|
24
23
|
flwr/client/secure_aggregation/secaggplus_handler.py,sha256=2jKtRhoJaVRmMJgJ2v8VRUCw2ko7uhTL2_h8CZVFwZA,18928
|
25
|
-
flwr/client/typing.py,sha256=
|
24
|
+
flwr/client/typing.py,sha256=F6E2sDRrUirWdGQlfBR4YOaAJ-TYn7XiLuQMG6bMXrI,1218
|
26
25
|
flwr/common/__init__.py,sha256=qttep0POwoigzB5pcraZa4YMt9jsCSfeibcrTQMUjIc,2884
|
27
26
|
flwr/common/address.py,sha256=iTAN9jtmIGMrWFnx9XZQl45ZEtQJVZZLYPRBSNVARGI,1882
|
28
27
|
flwr/common/configsrecord.py,sha256=i41syiXeG4CyWr4ujOCxTDBZKiClNnNgR4xbufxThh0,4799
|
@@ -47,7 +46,7 @@ flwr/common/secure_aggregation/ndarrays_arithmetic.py,sha256=KAHCEHGSTJ6mCgnC8dT
|
|
47
46
|
flwr/common/secure_aggregation/quantization.py,sha256=appui7GGrkRPsupF59TkapeV4Na_CyPi73JtJ1pimdI,2310
|
48
47
|
flwr/common/secure_aggregation/secaggplus_constants.py,sha256=m5UDo7IgRkMS3yixhzz7DhhAv6VAQMCghglMygSPU_k,1606
|
49
48
|
flwr/common/secure_aggregation/secaggplus_utils.py,sha256=PleDyDu7jHNAfbRoEaoQiOjxG6iMl9yA8rNKYTfnyFw,3155
|
50
|
-
flwr/common/serde.py,sha256=
|
49
|
+
flwr/common/serde.py,sha256=mI4K91XJ2lnxbdLSK93djkdrQmc_iZENvH_yKKSHo-E,26794
|
51
50
|
flwr/common/telemetry.py,sha256=se_-pHgEWcmN09ChSpTeek72l1UJHf7GbwXBB1KXBjQ,7683
|
52
51
|
flwr/common/typing.py,sha256=3Wu6Ol1Ja6Gb0WdlcXVEn1EHYJbc4oRRJA81vEegxBo,4382
|
53
52
|
flwr/common/version.py,sha256=A0MKvyKPrV8wLg0YCAODTqM71v26NEH36c6JYtfgg0o,667
|
@@ -139,11 +138,11 @@ flwr/server/utils/validator.py,sha256=b_3ahGkSPn4M3TPYaNiY5DyJmnkQHJsyarccPgrhFo
|
|
139
138
|
flwr/simulation/__init__.py,sha256=E2eD5FlTmZZ80u21FmWCkacrM7O4mrEHD8iXqeCaBUQ,1278
|
140
139
|
flwr/simulation/app.py,sha256=pbkldpm3Uc9_0M2R5-8Ako26g9WxNhZW4fLJY-4YtJY,13879
|
141
140
|
flwr/simulation/ray_transport/__init__.py,sha256=FsaAnzC4cw4DqoouBCix6496k29jACkfeIam55BvW9g,734
|
142
|
-
flwr/simulation/ray_transport/ray_actor.py,sha256=
|
143
|
-
flwr/simulation/ray_transport/ray_client_proxy.py,sha256=
|
141
|
+
flwr/simulation/ray_transport/ray_actor.py,sha256=G_g50ISt3Knf0zuX1wmw39gsDXSoMI5f3rmYZWGrUh4,17062
|
142
|
+
flwr/simulation/ray_transport/ray_client_proxy.py,sha256=UxQEzWmklp3WO2V7LH5vNyAgYL7KYFFZQa1HTUSgEqY,9429
|
144
143
|
flwr/simulation/ray_transport/utils.py,sha256=e0mkFOgOXSJHSQdiipoggF-DLBXaJZVytx9auQ35fCg,3368
|
145
|
-
flwr_nightly-1.7.0.
|
146
|
-
flwr_nightly-1.7.0.
|
147
|
-
flwr_nightly-1.7.0.
|
148
|
-
flwr_nightly-1.7.0.
|
149
|
-
flwr_nightly-1.7.0.
|
144
|
+
flwr_nightly-1.7.0.dev20240126.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
145
|
+
flwr_nightly-1.7.0.dev20240126.dist-info/METADATA,sha256=kigwmhoqGNgCqt0T-xOjxzJDhDvu4ycW1vttbQpB5lk,13578
|
146
|
+
flwr_nightly-1.7.0.dev20240126.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
|
147
|
+
flwr_nightly-1.7.0.dev20240126.dist-info/entry_points.txt,sha256=1uLlD5tIunkzALMfMWnqjdE_D5hRUX_I1iMmOMv6tZI,181
|
148
|
+
flwr_nightly-1.7.0.dev20240126.dist-info/RECORD,,
|
flwr/client/run_state.py
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
# Copyright 2023 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
|
-
"""Run state."""
|
16
|
-
|
17
|
-
from dataclasses import dataclass
|
18
|
-
from typing import Dict
|
19
|
-
|
20
|
-
|
21
|
-
@dataclass
|
22
|
-
class RunState:
|
23
|
-
"""State of a run executed by a client node."""
|
24
|
-
|
25
|
-
state: Dict[str, str]
|
{flwr_nightly-1.7.0.dev20240125.dist-info → flwr_nightly-1.7.0.dev20240126.dist-info}/LICENSE
RENAMED
File without changes
|
File without changes
|
File without changes
|