flwr-nightly 1.16.0.dev20250226__py3-none-any.whl → 1.16.0.dev20250227__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/common/auth_plugin/auth_plugin.py +2 -1
- flwr/common/constant.py +16 -0
- flwr/common/event_log_plugin/__init__.py +26 -0
- flwr/common/event_log_plugin/event_log_plugin.py +87 -0
- flwr/common/record/recordset.py +97 -82
- flwr/common/secure_aggregation/quantization.py +5 -1
- flwr/common/typing.py +36 -0
- flwr/server/app.py +16 -1
- flwr/superexec/exec_user_auth_interceptor.py +1 -1
- {flwr_nightly-1.16.0.dev20250226.dist-info → flwr_nightly-1.16.0.dev20250227.dist-info}/METADATA +1 -1
- {flwr_nightly-1.16.0.dev20250226.dist-info → flwr_nightly-1.16.0.dev20250227.dist-info}/RECORD +14 -12
- {flwr_nightly-1.16.0.dev20250226.dist-info → flwr_nightly-1.16.0.dev20250227.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.16.0.dev20250226.dist-info → flwr_nightly-1.16.0.dev20250227.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.16.0.dev20250226.dist-info → flwr_nightly-1.16.0.dev20250227.dist-info}/entry_points.txt +0 -0
@@ -20,6 +20,7 @@ from collections.abc import Sequence
|
|
20
20
|
from pathlib import Path
|
21
21
|
from typing import Optional, Union
|
22
22
|
|
23
|
+
from flwr.common.typing import UserInfo
|
23
24
|
from flwr.proto.exec_pb2_grpc import ExecStub
|
24
25
|
|
25
26
|
from ..typing import UserAuthCredentials, UserAuthLoginDetails
|
@@ -49,7 +50,7 @@ class ExecAuthPlugin(ABC):
|
|
49
50
|
@abstractmethod
|
50
51
|
def validate_tokens_in_metadata(
|
51
52
|
self, metadata: Sequence[tuple[str, Union[str, bytes]]]
|
52
|
-
) -> bool:
|
53
|
+
) -> tuple[bool, Optional[UserInfo]]:
|
53
54
|
"""Validate authentication tokens in the provided metadata."""
|
54
55
|
|
55
56
|
@abstractmethod
|
flwr/common/constant.py
CHANGED
@@ -212,3 +212,19 @@ class AuthType:
|
|
212
212
|
def __new__(cls) -> AuthType:
|
213
213
|
"""Prevent instantiation."""
|
214
214
|
raise TypeError(f"{cls.__name__} cannot be instantiated.")
|
215
|
+
|
216
|
+
|
217
|
+
class EventLogWriterType:
|
218
|
+
"""Event log writer types."""
|
219
|
+
|
220
|
+
FALSE = "false"
|
221
|
+
STDOUT = "stdout"
|
222
|
+
|
223
|
+
def __new__(cls) -> EventLogWriterType:
|
224
|
+
"""Prevent instantiation."""
|
225
|
+
raise TypeError(f"{cls.__name__} cannot be instantiated.")
|
226
|
+
|
227
|
+
@classmethod
|
228
|
+
def choices(cls) -> list[str]:
|
229
|
+
"""Return a list of available log writer choices."""
|
230
|
+
return [cls.FALSE, cls.STDOUT]
|
@@ -0,0 +1,26 @@
|
|
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
|
+
"""Event log plugin components."""
|
16
|
+
|
17
|
+
|
18
|
+
from .event_log_plugin import EventLogRequest as EventLogRequest
|
19
|
+
from .event_log_plugin import EventLogResponse as EventLogResponse
|
20
|
+
from .event_log_plugin import EventLogWriterPlugin as EventLogWriterPlugin
|
21
|
+
|
22
|
+
__all__ = [
|
23
|
+
"EventLogRequest",
|
24
|
+
"EventLogResponse",
|
25
|
+
"EventLogWriterPlugin",
|
26
|
+
]
|
@@ -0,0 +1,87 @@
|
|
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
|
+
"""Abstract class for Flower Event Log Writer Plugin."""
|
16
|
+
|
17
|
+
|
18
|
+
from abc import ABC, abstractmethod
|
19
|
+
from typing import Union
|
20
|
+
|
21
|
+
import grpc
|
22
|
+
|
23
|
+
from flwr.common.typing import LogEntry, UserInfo
|
24
|
+
from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
|
25
|
+
GetLoginDetailsRequest,
|
26
|
+
GetLoginDetailsResponse,
|
27
|
+
ListRunsRequest,
|
28
|
+
ListRunsResponse,
|
29
|
+
StartRunRequest,
|
30
|
+
StartRunResponse,
|
31
|
+
StopRunRequest,
|
32
|
+
StopRunResponse,
|
33
|
+
StreamLogsRequest,
|
34
|
+
StreamLogsResponse,
|
35
|
+
)
|
36
|
+
|
37
|
+
# Type variables for request and response messages
|
38
|
+
EventLogRequest = Union[
|
39
|
+
StartRunRequest,
|
40
|
+
ListRunsRequest,
|
41
|
+
StreamLogsRequest,
|
42
|
+
StopRunRequest,
|
43
|
+
GetLoginDetailsRequest,
|
44
|
+
]
|
45
|
+
EventLogResponse = Union[
|
46
|
+
StartRunResponse,
|
47
|
+
ListRunsResponse,
|
48
|
+
StreamLogsResponse,
|
49
|
+
StopRunResponse,
|
50
|
+
GetLoginDetailsResponse,
|
51
|
+
]
|
52
|
+
|
53
|
+
|
54
|
+
class EventLogWriterPlugin(ABC):
|
55
|
+
"""Abstract Flower Event Log Writer Plugin class for ExecServicer."""
|
56
|
+
|
57
|
+
@abstractmethod
|
58
|
+
def __init__(self) -> None:
|
59
|
+
"""Abstract constructor."""
|
60
|
+
|
61
|
+
@abstractmethod
|
62
|
+
def compose_log_before_event( # pylint: disable=too-many-arguments
|
63
|
+
self,
|
64
|
+
request: EventLogRequest,
|
65
|
+
context: grpc.ServicerContext,
|
66
|
+
user_info: UserInfo,
|
67
|
+
method_name: str,
|
68
|
+
) -> LogEntry:
|
69
|
+
"""Compose pre-event log entry from the provided request and context."""
|
70
|
+
|
71
|
+
@abstractmethod
|
72
|
+
def compose_log_after_event( # pylint: disable=too-many-arguments,R0917
|
73
|
+
self,
|
74
|
+
request: EventLogRequest,
|
75
|
+
context: grpc.ServicerContext,
|
76
|
+
user_info: UserInfo,
|
77
|
+
method_name: str,
|
78
|
+
response: EventLogResponse,
|
79
|
+
) -> LogEntry:
|
80
|
+
"""Compose post-event log entry from the provided response and context."""
|
81
|
+
|
82
|
+
@abstractmethod
|
83
|
+
def write_log(
|
84
|
+
self,
|
85
|
+
log_entry: LogEntry,
|
86
|
+
) -> None:
|
87
|
+
"""Write the event log to the specified data sink."""
|
flwr/common/record/recordset.py
CHANGED
@@ -17,82 +17,79 @@
|
|
17
17
|
|
18
18
|
from __future__ import annotations
|
19
19
|
|
20
|
-
from
|
21
|
-
from
|
20
|
+
from logging import WARN
|
21
|
+
from textwrap import indent
|
22
|
+
from typing import TypeVar, Union, cast
|
22
23
|
|
24
|
+
from ..logger import log
|
23
25
|
from .configsrecord import ConfigsRecord
|
24
26
|
from .metricsrecord import MetricsRecord
|
25
27
|
from .parametersrecord import ParametersRecord
|
26
28
|
from .typeddict import TypedDict
|
27
29
|
|
30
|
+
RecordType = Union[ParametersRecord, MetricsRecord, ConfigsRecord]
|
28
31
|
|
29
|
-
|
30
|
-
class RecordSetData:
|
31
|
-
"""Inner data container for the RecordSet class."""
|
32
|
+
T = TypeVar("T")
|
32
33
|
|
33
|
-
parameters_records: TypedDict[str, ParametersRecord]
|
34
|
-
metrics_records: TypedDict[str, MetricsRecord]
|
35
|
-
configs_records: TypedDict[str, ConfigsRecord]
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
) -> None:
|
43
|
-
self.parameters_records = TypedDict[str, ParametersRecord](
|
44
|
-
self._check_fn_str, self._check_fn_params
|
45
|
-
)
|
46
|
-
self.metrics_records = TypedDict[str, MetricsRecord](
|
47
|
-
self._check_fn_str, self._check_fn_metrics
|
35
|
+
def _check_key(key: str) -> None:
|
36
|
+
if not isinstance(key, str):
|
37
|
+
raise TypeError(
|
38
|
+
f"Expected `{str.__name__}`, but "
|
39
|
+
f"received `{type(key).__name__}` for the key."
|
48
40
|
)
|
49
|
-
|
50
|
-
|
41
|
+
|
42
|
+
|
43
|
+
def _check_value(value: RecordType) -> None:
|
44
|
+
if not isinstance(value, (ParametersRecord, MetricsRecord, ConfigsRecord)):
|
45
|
+
raise TypeError(
|
46
|
+
f"Expected `{ParametersRecord.__name__}`, `{MetricsRecord.__name__}`, "
|
47
|
+
f"or `{ConfigsRecord.__name__}` but received "
|
48
|
+
f"`{type(value).__name__}` for the value."
|
51
49
|
)
|
52
|
-
if parameters_records is not None:
|
53
|
-
self.parameters_records.update(parameters_records)
|
54
|
-
if metrics_records is not None:
|
55
|
-
self.metrics_records.update(metrics_records)
|
56
|
-
if configs_records is not None:
|
57
|
-
self.configs_records.update(configs_records)
|
58
|
-
|
59
|
-
def _check_fn_str(self, key: str) -> None:
|
60
|
-
if not isinstance(key, str):
|
61
|
-
raise TypeError(
|
62
|
-
f"Expected `{str.__name__}`, but "
|
63
|
-
f"received `{type(key).__name__}` for the key."
|
64
|
-
)
|
65
50
|
|
66
|
-
def _check_fn_params(self, record: ParametersRecord) -> None:
|
67
|
-
if not isinstance(record, ParametersRecord):
|
68
|
-
raise TypeError(
|
69
|
-
f"Expected `{ParametersRecord.__name__}`, but "
|
70
|
-
f"received `{type(record).__name__}` for the value."
|
71
|
-
)
|
72
51
|
|
73
|
-
|
74
|
-
|
75
|
-
raise TypeError(
|
76
|
-
f"Expected `{MetricsRecord.__name__}`, but "
|
77
|
-
f"received `{type(record).__name__}` for the value."
|
78
|
-
)
|
52
|
+
class _SyncedDict(TypedDict[str, T]):
|
53
|
+
"""A synchronized dictionary that mirrors changes to an underlying RecordSet.
|
79
54
|
|
80
|
-
|
81
|
-
|
55
|
+
This dictionary ensures that any modifications (set or delete operations)
|
56
|
+
are automatically reflected in the associated `RecordSet`. Only values of
|
57
|
+
the specified `allowed_type` are permitted.
|
58
|
+
"""
|
59
|
+
|
60
|
+
def __init__(self, ref_recordset: RecordSet, allowed_type: type[T]) -> None:
|
61
|
+
if not issubclass(
|
62
|
+
allowed_type, (ParametersRecord, MetricsRecord, ConfigsRecord)
|
63
|
+
):
|
64
|
+
raise TypeError(f"{allowed_type} is not a valid type.")
|
65
|
+
super().__init__(_check_key, self.check_value)
|
66
|
+
self.recordset = ref_recordset
|
67
|
+
self.allowed_type = allowed_type
|
68
|
+
|
69
|
+
def __setitem__(self, key: str, value: T) -> None:
|
70
|
+
super().__setitem__(key, value)
|
71
|
+
self.recordset[key] = cast(RecordType, value)
|
72
|
+
|
73
|
+
def __delitem__(self, key: str) -> None:
|
74
|
+
super().__delitem__(key)
|
75
|
+
del self.recordset[key]
|
76
|
+
|
77
|
+
def check_value(self, value: T) -> None:
|
78
|
+
"""Check if value is of expected type."""
|
79
|
+
if not isinstance(value, self.allowed_type):
|
82
80
|
raise TypeError(
|
83
|
-
f"Expected `{
|
84
|
-
f"received `{type(
|
81
|
+
f"Expected `{self.allowed_type.__name__}`, but "
|
82
|
+
f"received `{type(value).__name__}` for the value."
|
85
83
|
)
|
86
84
|
|
87
85
|
|
88
|
-
class RecordSet:
|
86
|
+
class RecordSet(TypedDict[str, RecordType]):
|
89
87
|
"""RecordSet stores groups of parameters, metrics and configs.
|
90
88
|
|
91
|
-
A :
|
92
|
-
metrics and configs can be either stored as part of a
|
93
|
-
|
94
|
-
|
95
|
-
`flwr.common.Message <flwr.common.Message.html>`_ between your apps.
|
89
|
+
A :class:`RecordSet` is the unified mechanism by which parameters,
|
90
|
+
metrics and configs can be either stored as part of a :class:`Context`
|
91
|
+
in your apps or communicated as part of a :class:`Message` between
|
92
|
+
your apps.
|
96
93
|
|
97
94
|
Parameters
|
98
95
|
----------
|
@@ -127,12 +124,12 @@ class RecordSet:
|
|
127
124
|
>>> # We can create a ConfigsRecord
|
128
125
|
>>> c_record = ConfigsRecord({"lr": 0.1, "batch-size": 128})
|
129
126
|
>>> # Adding it to the record_set would look like this
|
130
|
-
>>> my_recordset
|
127
|
+
>>> my_recordset["my_config"] = c_record
|
131
128
|
>>>
|
132
129
|
>>> # We can create a MetricsRecord following a similar process
|
133
130
|
>>> m_record = MetricsRecord({"accuracy": 0.93, "losses": [0.23, 0.1]})
|
134
131
|
>>> # Adding it to the record_set would look like this
|
135
|
-
>>> my_recordset
|
132
|
+
>>> my_recordset["my_metrics"] = m_record
|
136
133
|
|
137
134
|
Adding a :code:`ParametersRecord` follows the same steps as above but first,
|
138
135
|
the array needs to be serialized and represented as a :code:`flwr.common.Array`.
|
@@ -151,7 +148,7 @@ class RecordSet:
|
|
151
148
|
>>> p_record = ParametersRecord({"my_array": arr})
|
152
149
|
>>>
|
153
150
|
>>> # Adding it to the record_set would look like this
|
154
|
-
>>> my_recordset
|
151
|
+
>>> my_recordset["my_parameters"] = p_record
|
155
152
|
|
156
153
|
For additional examples on how to construct each of the records types shown
|
157
154
|
above, please refer to the documentation for :code:`ConfigsRecord`,
|
@@ -164,39 +161,57 @@ class RecordSet:
|
|
164
161
|
metrics_records: dict[str, MetricsRecord] | None = None,
|
165
162
|
configs_records: dict[str, ConfigsRecord] | None = None,
|
166
163
|
) -> None:
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
164
|
+
super().__init__(_check_key, _check_value)
|
165
|
+
for key, p_record in (parameters_records or {}).items():
|
166
|
+
self[key] = p_record
|
167
|
+
for key, m_record in (metrics_records or {}).items():
|
168
|
+
self[key] = m_record
|
169
|
+
for key, c_record in (configs_records or {}).items():
|
170
|
+
self[key] = c_record
|
173
171
|
|
174
172
|
@property
|
175
173
|
def parameters_records(self) -> TypedDict[str, ParametersRecord]:
|
176
|
-
"""Dictionary holding ParametersRecord instances."""
|
177
|
-
|
178
|
-
|
174
|
+
"""Dictionary holding only ParametersRecord instances."""
|
175
|
+
synced_dict = _SyncedDict[ParametersRecord](self, ParametersRecord)
|
176
|
+
for key, record in self.items():
|
177
|
+
if isinstance(record, ParametersRecord):
|
178
|
+
synced_dict[key] = record
|
179
|
+
return synced_dict
|
179
180
|
|
180
181
|
@property
|
181
182
|
def metrics_records(self) -> TypedDict[str, MetricsRecord]:
|
182
|
-
"""Dictionary holding MetricsRecord instances."""
|
183
|
-
|
184
|
-
|
183
|
+
"""Dictionary holding only MetricsRecord instances."""
|
184
|
+
synced_dict = _SyncedDict[MetricsRecord](self, MetricsRecord)
|
185
|
+
for key, record in self.items():
|
186
|
+
if isinstance(record, MetricsRecord):
|
187
|
+
synced_dict[key] = record
|
188
|
+
return synced_dict
|
185
189
|
|
186
190
|
@property
|
187
191
|
def configs_records(self) -> TypedDict[str, ConfigsRecord]:
|
188
|
-
"""Dictionary holding ConfigsRecord instances."""
|
189
|
-
|
190
|
-
|
192
|
+
"""Dictionary holding only ConfigsRecord instances."""
|
193
|
+
synced_dict = _SyncedDict[ConfigsRecord](self, ConfigsRecord)
|
194
|
+
for key, record in self.items():
|
195
|
+
if isinstance(record, ConfigsRecord):
|
196
|
+
synced_dict[key] = record
|
197
|
+
return synced_dict
|
191
198
|
|
192
199
|
def __repr__(self) -> str:
|
193
200
|
"""Return a string representation of this instance."""
|
194
201
|
flds = ("parameters_records", "metrics_records", "configs_records")
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
202
|
+
fld_views = [f"{fld}={dict(getattr(self, fld))!r}" for fld in flds]
|
203
|
+
view = indent(",\n".join(fld_views), " ")
|
204
|
+
return f"{self.__class__.__qualname__}(\n{view}\n)"
|
205
|
+
|
206
|
+
def __setitem__(self, key: str, value: RecordType) -> None:
|
207
|
+
"""Set the given key to the given value after type checking."""
|
208
|
+
original_value = self.get(key, None)
|
209
|
+
super().__setitem__(key, value)
|
210
|
+
if original_value is not None and not isinstance(value, type(original_value)):
|
211
|
+
log(
|
212
|
+
WARN,
|
213
|
+
"Key '%s' was overwritten: record of type `%s` replaced with type `%s`",
|
214
|
+
key,
|
215
|
+
type(original_value).__name__,
|
216
|
+
type(value).__name__,
|
217
|
+
)
|
@@ -25,7 +25,11 @@ from flwr.common.typing import NDArrayFloat, NDArrayInt
|
|
25
25
|
def _stochastic_round(arr: NDArrayFloat) -> NDArrayInt:
|
26
26
|
ret: NDArrayInt = np.ceil(arr).astype(np.int32)
|
27
27
|
rand_arr = np.random.rand(*ret.shape)
|
28
|
-
|
28
|
+
if len(ret.shape) == 0:
|
29
|
+
if rand_arr < ret - arr:
|
30
|
+
ret -= 1
|
31
|
+
else:
|
32
|
+
ret[rand_arr < ret - arr] -= 1
|
29
33
|
return ret
|
30
34
|
|
31
35
|
|
flwr/common/typing.py
CHANGED
@@ -286,3 +286,39 @@ class UserAuthCredentials:
|
|
286
286
|
|
287
287
|
access_token: str
|
288
288
|
refresh_token: str
|
289
|
+
|
290
|
+
|
291
|
+
@dataclass
|
292
|
+
class UserInfo:
|
293
|
+
"""User information for event log."""
|
294
|
+
|
295
|
+
user_id: Optional[str]
|
296
|
+
user_name: Optional[str]
|
297
|
+
|
298
|
+
|
299
|
+
@dataclass
|
300
|
+
class Actor:
|
301
|
+
"""Event log actor."""
|
302
|
+
|
303
|
+
actor_id: Optional[str]
|
304
|
+
description: Optional[str]
|
305
|
+
ip_address: str
|
306
|
+
|
307
|
+
|
308
|
+
@dataclass
|
309
|
+
class Event:
|
310
|
+
"""Event log description."""
|
311
|
+
|
312
|
+
action: str
|
313
|
+
run_id: Optional[int]
|
314
|
+
fab_hash: Optional[str]
|
315
|
+
|
316
|
+
|
317
|
+
@dataclass
|
318
|
+
class LogEntry:
|
319
|
+
"""Event log record."""
|
320
|
+
|
321
|
+
timestamp: str
|
322
|
+
actor: Actor
|
323
|
+
event: Event
|
324
|
+
status: str
|
flwr/server/app.py
CHANGED
@@ -90,7 +90,11 @@ BASE_DIR = get_flwr_dir() / "superlink" / "ffs"
|
|
90
90
|
|
91
91
|
|
92
92
|
try:
|
93
|
-
from flwr.ee import
|
93
|
+
from flwr.ee import (
|
94
|
+
add_ee_args_superlink,
|
95
|
+
get_dashboard_server,
|
96
|
+
get_exec_auth_plugins,
|
97
|
+
)
|
94
98
|
except ImportError:
|
95
99
|
|
96
100
|
# pylint: disable-next=unused-argument
|
@@ -431,6 +435,17 @@ def run_superlink() -> None:
|
|
431
435
|
scheduler_th.start()
|
432
436
|
bckg_threads.append(scheduler_th)
|
433
437
|
|
438
|
+
# Add Dashboard server if available
|
439
|
+
if dashboard_address := getattr(args, "dashboard_address", None):
|
440
|
+
dashboard_address_str, _, _ = _format_address(dashboard_address)
|
441
|
+
dashboard_server = get_dashboard_server(
|
442
|
+
address=dashboard_address_str,
|
443
|
+
state_factory=state_factory,
|
444
|
+
certificates=None,
|
445
|
+
)
|
446
|
+
|
447
|
+
grpc_servers.append(dashboard_server)
|
448
|
+
|
434
449
|
# Graceful shutdown
|
435
450
|
register_exit_handlers(
|
436
451
|
event_type=EventType.RUN_SUPERLINK_LEAVE,
|
@@ -85,7 +85,7 @@ class ExecUserAuthInterceptor(grpc.ServerInterceptor): # type: ignore
|
|
85
85
|
tokens = self.auth_plugin.refresh_tokens(context.invocation_metadata())
|
86
86
|
if tokens is not None:
|
87
87
|
context.send_initial_metadata(tokens)
|
88
|
-
return call(request, context)
|
88
|
+
return call(request, context)
|
89
89
|
|
90
90
|
context.abort(grpc.StatusCode.UNAUTHENTICATED, "Access denied")
|
91
91
|
raise grpc.RpcError() # This line is unreachable
|
{flwr_nightly-1.16.0.dev20250226.dist-info → flwr_nightly-1.16.0.dev20250227.dist-info}/RECORD
RENAMED
@@ -115,14 +115,16 @@ flwr/common/__init__.py,sha256=TVaoFEJE158aui1TPZQiJCDZX4RNHRyI8I55VC80HhI,3901
|
|
115
115
|
flwr/common/address.py,sha256=rRaN1JpiCJnit7ImEqZVxURQ69dPihRoyyWn_3I2wh4,4119
|
116
116
|
flwr/common/args.py,sha256=MgkTUXACuySHyNdxrb7-pK0_R-S2Q7W5MnE3onYUf5I,5183
|
117
117
|
flwr/common/auth_plugin/__init__.py,sha256=1Y8Oj3iB49IHDu9tvDih1J74Ygu7k85V9s2A4WORPyA,887
|
118
|
-
flwr/common/auth_plugin/auth_plugin.py,sha256=
|
118
|
+
flwr/common/auth_plugin/auth_plugin.py,sha256=dQU5U4uJIA5XqgOJ3PankHWq-uXCaMvO74khaMPGdiU,3938
|
119
119
|
flwr/common/config.py,sha256=SAkG3BztnA6iupXxF3GAIpGmWVVCH0ptyMpC9yjr_14,13965
|
120
|
-
flwr/common/constant.py,sha256=
|
120
|
+
flwr/common/constant.py,sha256=6NtDbh_RgQebtPfn01a8yN_7poMOuwy6jbtVLQdBbQc,7026
|
121
121
|
flwr/common/context.py,sha256=uJ-mnoC_8y_udEb3kAX-r8CPphNTWM72z1AlsvQEu54,2403
|
122
122
|
flwr/common/date.py,sha256=NHHpESce5wYqEwoDXf09gp9U9l_5Bmlh2BsOcwS-kDM,1554
|
123
123
|
flwr/common/differential_privacy.py,sha256=YA01NqjddKNAEVmf7hXmOVxOjhekgzvJudk3mBGq-2k,6148
|
124
124
|
flwr/common/differential_privacy_constants.py,sha256=c7b7tqgvT7yMK0XN9ndiTBs4mQf6d3qk6K7KBZGlV4Q,1074
|
125
125
|
flwr/common/dp.py,sha256=vddkvyjV2FhRoN4VuU2LeAM1UBn7dQB8_W-Qdiveal8,1978
|
126
|
+
flwr/common/event_log_plugin/__init__.py,sha256=iLGSlmIta-qY4Jm5Os8IBl5cvVYXyFGlqkUiUXQDlU0,1017
|
127
|
+
flwr/common/event_log_plugin/event_log_plugin.py,sha256=OdyYsBTqhLRRC0HL3_hv29LXJvHyhLCANXcLUqgAFTI,2568
|
126
128
|
flwr/common/exit/__init__.py,sha256=-ZOJYLaNnR729a7VzZiFsLiqngzKQh3xc27svYStZ_Q,826
|
127
129
|
flwr/common/exit/exit.py,sha256=DmZFyksp-w1sFDQekq5Z-qfnr-ivCAv78aQkqj-TDps,3458
|
128
130
|
flwr/common/exit/exit_code.py,sha256=PNEnCrZfOILjfDAFu5m-2YWEJBrk97xglq4zCUlqV7E,3470
|
@@ -138,7 +140,7 @@ flwr/common/record/configsrecord.py,sha256=i40jOzBx04ysZKECwaw4FdUXMdY9HgdY8GAqK
|
|
138
140
|
flwr/common/record/conversion_utils.py,sha256=ZcsM-vTm_rVtLXLFD2RY3N47V_hUr3ywTdtnpVXnOGU,1202
|
139
141
|
flwr/common/record/metricsrecord.py,sha256=UywkEPbifiu_IyPUFoDJCi8WEVLujlqZERUWAWpc3vs,5752
|
140
142
|
flwr/common/record/parametersrecord.py,sha256=rR0LbeNrKrdK37CiAA56Z5WBq-ZzZ2YNSUkcmr5i2lI,12950
|
141
|
-
flwr/common/record/recordset.py,sha256=
|
143
|
+
flwr/common/record/recordset.py,sha256=gY3nmE--8sXSIPEFMReq7nh6hMiF-sr0HpfUtiB65E8,8890
|
142
144
|
flwr/common/record/typeddict.py,sha256=q5hL2xkXymuiCprHWb69mUmLpWQk_XXQq0hGQ69YPaw,3599
|
143
145
|
flwr/common/recordset_compat.py,sha256=ViSwA26h6Q55ZmV1LLjSJpcKiipV-p_JpCj4wxdE-Ow,14230
|
144
146
|
flwr/common/retry_invoker.py,sha256=UIDKsn0AitS3fOr43WTqZAdD-TaHkBeTj1QxD7SGba0,14481
|
@@ -147,12 +149,12 @@ flwr/common/secure_aggregation/crypto/__init__.py,sha256=nlHesCWy8xxE5s6qHWnauCt
|
|
147
149
|
flwr/common/secure_aggregation/crypto/shamir.py,sha256=wCSfEfeaPgJ9Om580-YPUF2ljiyRhq33TRC4HtwxYl8,2779
|
148
150
|
flwr/common/secure_aggregation/crypto/symmetric_encryption.py,sha256=J_pRkxbogc7e1fxRZStZFBdzzG5jeUycshJPpvyCt6g,5333
|
149
151
|
flwr/common/secure_aggregation/ndarrays_arithmetic.py,sha256=zvVAIrIyI6OSzGhpCi8NNaTvPXmoMYQIPJT-NkBg8RU,3013
|
150
|
-
flwr/common/secure_aggregation/quantization.py,sha256=
|
152
|
+
flwr/common/secure_aggregation/quantization.py,sha256=NE_ltC3Fx5Z3bMKqJHA95wQf2tkGQlN0VZf3d1w5ABA,2400
|
151
153
|
flwr/common/secure_aggregation/secaggplus_constants.py,sha256=9MF-oQh62uD7rt9VeNB-rHf2gBLd5GL3S9OejCxmILY,2183
|
152
154
|
flwr/common/secure_aggregation/secaggplus_utils.py,sha256=OgYd68YBRaHQYLc-YdExj9CSpwL58bVTaPrdHoAj2AE,3214
|
153
155
|
flwr/common/serde.py,sha256=iDVS5IXGKqEuzQAvnroH9c6KFEHxKFEWmkGP89PMOO0,31064
|
154
156
|
flwr/common/telemetry.py,sha256=APKVubU_zJNrE-M_rip6S6Fsu41DxY3tAjFWNOgTmC0,9086
|
155
|
-
flwr/common/typing.py,sha256=
|
157
|
+
flwr/common/typing.py,sha256=Prl8_4tKnIl_Kh5UjJGbw1tnld543EkXrX0RWffJpiA,6900
|
156
158
|
flwr/common/version.py,sha256=aNSxLL49RKeLz8sPcZrsTEWtrAeQ0uxu6tjmfba4O60,1325
|
157
159
|
flwr/proto/__init__.py,sha256=hbY7JYakwZwCkYgCNlmHdc8rtvfoJbAZLalMdc--CGc,683
|
158
160
|
flwr/proto/clientappio_pb2.py,sha256=aroQDv0D2GquQ5Ujqml7n7l6ObZoXqMvDa0XVO-_8Cc,3703
|
@@ -217,7 +219,7 @@ flwr/proto/transport_pb2_grpc.py,sha256=vLN3EHtx2aEEMCO4f1Upu-l27BPzd3-5pV-u8wPc
|
|
217
219
|
flwr/proto/transport_pb2_grpc.pyi,sha256=AGXf8RiIiW2J5IKMlm_3qT3AzcDa4F3P5IqUjve_esA,766
|
218
220
|
flwr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
219
221
|
flwr/server/__init__.py,sha256=cEg1oecBu4cKB69iJCqWEylC8b5XW47bl7rQiJsdTvM,1528
|
220
|
-
flwr/server/app.py,sha256=
|
222
|
+
flwr/server/app.py,sha256=a_3hM-RktaPp3QTKDlBuHATB9oS2deGShZGEtmhlnX0,31005
|
221
223
|
flwr/server/client_manager.py,sha256=7Ese0tgrH-i-ms363feYZJKwB8gWnXSmg_hYF2Bju4U,6227
|
222
224
|
flwr/server/client_proxy.py,sha256=4G-oTwhb45sfWLx2uZdcXD98IZwdTS6F88xe3akCdUg,2399
|
223
225
|
flwr/server/compat/__init__.py,sha256=VxnJtJyOjNFQXMNi9hIuzNlZM5n0Hj1p3aq_Pm2udw4,892
|
@@ -324,11 +326,11 @@ flwr/superexec/app.py,sha256=Z6kYHWd62YL0Q4YKyCAbt_BcefNfbKH6V-jCC-1NkZM,1842
|
|
324
326
|
flwr/superexec/deployment.py,sha256=wZ9G42gGS91knfplswh95MnQ83Fzu-rs6wcuNgDmmvY,6735
|
325
327
|
flwr/superexec/exec_grpc.py,sha256=ttA9qoZzSLF0Mfk1L4hzOkMSNuj5rR58_kKBYwcyrAg,2864
|
326
328
|
flwr/superexec/exec_servicer.py,sha256=X10ILT-AoGMrB3IgI2mBe9i-QcIVUAl9bucuqVOPYkU,8341
|
327
|
-
flwr/superexec/exec_user_auth_interceptor.py,sha256=
|
329
|
+
flwr/superexec/exec_user_auth_interceptor.py,sha256=XvLRxIsZ5m90pg6COx-tKkixFWxF-FaBeP3PqJFtksw,3688
|
328
330
|
flwr/superexec/executor.py,sha256=_B55WW2TD1fBINpabSSDRenVHXYmvlfhv-k8hJKU4lQ,3115
|
329
331
|
flwr/superexec/simulation.py,sha256=WQDon15oqpMopAZnwRZoTICYCfHqtkvFSqiTQ2hLD_g,4088
|
330
|
-
flwr_nightly-1.16.0.
|
331
|
-
flwr_nightly-1.16.0.
|
332
|
-
flwr_nightly-1.16.0.
|
333
|
-
flwr_nightly-1.16.0.
|
334
|
-
flwr_nightly-1.16.0.
|
332
|
+
flwr_nightly-1.16.0.dev20250227.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
333
|
+
flwr_nightly-1.16.0.dev20250227.dist-info/METADATA,sha256=E--UFuJfhErjNYm6D4cvC1efJ_ZXAFNGII1jKTbC6mc,15877
|
334
|
+
flwr_nightly-1.16.0.dev20250227.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
335
|
+
flwr_nightly-1.16.0.dev20250227.dist-info/entry_points.txt,sha256=JlNxX3qhaV18_2yj5a3kJW1ESxm31cal9iS_N_pf1Rk,538
|
336
|
+
flwr_nightly-1.16.0.dev20250227.dist-info/RECORD,,
|
{flwr_nightly-1.16.0.dev20250226.dist-info → flwr_nightly-1.16.0.dev20250227.dist-info}/LICENSE
RENAMED
File without changes
|
{flwr_nightly-1.16.0.dev20250226.dist-info → flwr_nightly-1.16.0.dev20250227.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|