flwr-nightly 1.20.0.dev20250627__py3-none-any.whl → 1.20.0.dev20250701__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/utils.py +1 -2
- flwr/common/constant.py +1 -0
- flwr/common/exit/exit_code.py +5 -0
- flwr/common/inflatable_utils.py +2 -0
- flwr/common/record/array.py +88 -22
- flwr/common/record/arraychunk.py +62 -0
- flwr/supercore/license_plugin/__init__.py +22 -0
- flwr/supercore/license_plugin/license_plugin.py +34 -0
- flwr/superexec/exec_grpc.py +19 -1
- flwr/superexec/exec_license_interceptor.py +74 -0
- {flwr_nightly-1.20.0.dev20250627.dist-info → flwr_nightly-1.20.0.dev20250701.dist-info}/METADATA +1 -1
- {flwr_nightly-1.20.0.dev20250627.dist-info → flwr_nightly-1.20.0.dev20250701.dist-info}/RECORD +14 -10
- {flwr_nightly-1.20.0.dev20250627.dist-info → flwr_nightly-1.20.0.dev20250701.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.20.0.dev20250627.dist-info → flwr_nightly-1.20.0.dev20250701.dist-info}/entry_points.txt +0 -0
flwr/cli/utils.py
CHANGED
@@ -320,8 +320,7 @@ def flwr_cli_grpc_exc_handler() -> Iterator[None]:
|
|
320
320
|
raise typer.Exit(code=1) from None
|
321
321
|
if e.code() == grpc.StatusCode.PERMISSION_DENIED:
|
322
322
|
typer.secho(
|
323
|
-
"❌
|
324
|
-
" to check your permissions.",
|
323
|
+
"❌ Permission denied. Please contact the SuperLink administrator.",
|
325
324
|
fg=typer.colors.RED,
|
326
325
|
bold=True,
|
327
326
|
)
|
flwr/common/constant.py
CHANGED
@@ -135,6 +135,7 @@ GC_THRESHOLD = 200_000_000 # 200 MB
|
|
135
135
|
# Constants for Inflatable
|
136
136
|
HEAD_BODY_DIVIDER = b"\x00"
|
137
137
|
HEAD_VALUE_DIVIDER = " "
|
138
|
+
MAX_ARRAY_CHUNK_SIZE = 20_971_520 # 20 MB
|
138
139
|
|
139
140
|
# Constants for serialization
|
140
141
|
INT64_MAX_VALUE = 9223372036854775807 # (1 << 63) - 1
|
flwr/common/exit/exit_code.py
CHANGED
@@ -29,6 +29,7 @@ class ExitCode:
|
|
29
29
|
|
30
30
|
# SuperLink-specific exit codes (100-199)
|
31
31
|
SUPERLINK_THREAD_CRASH = 100
|
32
|
+
SUPERLINK_LICENSE_INVALID = 101
|
32
33
|
|
33
34
|
# ServerApp-specific exit codes (200-299)
|
34
35
|
|
@@ -60,6 +61,10 @@ EXIT_CODE_HELP = {
|
|
60
61
|
ExitCode.GRACEFUL_EXIT_SIGTERM: "",
|
61
62
|
# SuperLink-specific exit codes (100-199)
|
62
63
|
ExitCode.SUPERLINK_THREAD_CRASH: "An important background thread has crashed.",
|
64
|
+
ExitCode.SUPERLINK_LICENSE_INVALID: (
|
65
|
+
"The license is invalid or has expired. "
|
66
|
+
"Please contact `hello@flower.ai` for assistance."
|
67
|
+
),
|
63
68
|
# ServerApp-specific exit codes (200-299)
|
64
69
|
# SuperNode-specific exit codes (300-399)
|
65
70
|
ExitCode.SUPERNODE_REST_ADDRESS_INVALID: (
|
flwr/common/inflatable_utils.py
CHANGED
@@ -40,9 +40,11 @@ from .inflatable import (
|
|
40
40
|
)
|
41
41
|
from .message import Message
|
42
42
|
from .record import Array, ArrayRecord, ConfigRecord, MetricRecord, RecordDict
|
43
|
+
from .record.arraychunk import ArrayChunk
|
43
44
|
|
44
45
|
# Helper registry that maps names of classes to their type
|
45
46
|
inflatable_class_registry: dict[str, type[InflatableObject]] = {
|
47
|
+
ArrayChunk.__qualname__: ArrayChunk,
|
46
48
|
Array.__qualname__: Array,
|
47
49
|
ArrayRecord.__qualname__: ArrayRecord,
|
48
50
|
ConfigRecord.__qualname__: ConfigRecord,
|
flwr/common/record/array.py
CHANGED
@@ -17,6 +17,7 @@
|
|
17
17
|
|
18
18
|
from __future__ import annotations
|
19
19
|
|
20
|
+
import json
|
20
21
|
import sys
|
21
22
|
from dataclasses import dataclass
|
22
23
|
from io import BytesIO
|
@@ -24,11 +25,15 @@ from typing import TYPE_CHECKING, Any, cast, overload
|
|
24
25
|
|
25
26
|
import numpy as np
|
26
27
|
|
27
|
-
from
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
from ..constant import MAX_ARRAY_CHUNK_SIZE, SType
|
29
|
+
from ..inflatable import (
|
30
|
+
InflatableObject,
|
31
|
+
add_header_to_object_body,
|
32
|
+
get_object_body,
|
33
|
+
get_object_children_ids_from_object_content,
|
34
|
+
)
|
31
35
|
from ..typing import NDArray
|
36
|
+
from .arraychunk import ArrayChunk
|
32
37
|
|
33
38
|
if TYPE_CHECKING:
|
34
39
|
import torch
|
@@ -252,16 +257,48 @@ class Array(InflatableObject):
|
|
252
257
|
ndarray_deserialized = np.load(bytes_io, allow_pickle=False)
|
253
258
|
return cast(NDArray, ndarray_deserialized)
|
254
259
|
|
260
|
+
@property
|
261
|
+
def children(self) -> dict[str, InflatableObject]:
|
262
|
+
"""Return a dictionary of ArrayChunks with their Object IDs as keys."""
|
263
|
+
return dict(self.slice_array())
|
264
|
+
|
265
|
+
def slice_array(self) -> list[tuple[str, InflatableObject]]:
|
266
|
+
"""Slice Array data and construct a list of ArrayChunks."""
|
267
|
+
children: list[tuple[str, InflatableObject]] = []
|
268
|
+
# memoryview allows for zero-copy slicing
|
269
|
+
data_view = memoryview(self.data)
|
270
|
+
for start in range(0, len(data_view), MAX_ARRAY_CHUNK_SIZE):
|
271
|
+
end = min(start + MAX_ARRAY_CHUNK_SIZE, len(data_view))
|
272
|
+
ac = ArrayChunk(data_view[start:end])
|
273
|
+
children.append((ac.object_id, ac))
|
274
|
+
return children
|
275
|
+
|
255
276
|
def deflate(self) -> bytes:
|
256
277
|
"""Deflate the Array."""
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
)
|
263
|
-
|
264
|
-
|
278
|
+
array_metadata: dict[str, str | tuple[int, ...] | list[int]] = {}
|
279
|
+
|
280
|
+
# We want to record all object_id even if repeated
|
281
|
+
# it can happend that chunks carry the exact same data
|
282
|
+
# for example when the array has only zeros
|
283
|
+
children_list = self.slice_array()
|
284
|
+
# Let's not save the entire object_id but a mapping to those
|
285
|
+
# that will be carried in the object head
|
286
|
+
# (replace a long object_id with a single scalar)
|
287
|
+
unique_children = list(self.children.keys())
|
288
|
+
arraychunk_ids = [unique_children.index(ch_id) for ch_id, _ in children_list]
|
289
|
+
|
290
|
+
# The deflated Array carries everything but the data
|
291
|
+
# The `arraychunk_ids` will be used during Array inflation
|
292
|
+
# to rematerialize the data from ArrayChunk objects.
|
293
|
+
array_metadata = {
|
294
|
+
"dtype": self.dtype,
|
295
|
+
"shape": self.shape,
|
296
|
+
"stype": self.stype,
|
297
|
+
"arraychunk_ids": arraychunk_ids,
|
298
|
+
}
|
299
|
+
|
300
|
+
# Serialize metadata dict
|
301
|
+
obj_body = json.dumps(array_metadata).encode("utf-8")
|
265
302
|
return add_header_to_object_body(object_body=obj_body, obj=self)
|
266
303
|
|
267
304
|
@classmethod
|
@@ -276,26 +313,55 @@ class Array(InflatableObject):
|
|
276
313
|
The deflated object content of the Array.
|
277
314
|
|
278
315
|
children : Optional[dict[str, InflatableObject]] (default: None)
|
279
|
-
Must be ``None``. ``Array``
|
280
|
-
Providing
|
316
|
+
Must be ``None``. ``Array`` must have child objects.
|
317
|
+
Providing no children will raise a ``ValueError``.
|
281
318
|
|
282
319
|
Returns
|
283
320
|
-------
|
284
321
|
Array
|
285
322
|
The inflated Array.
|
286
323
|
"""
|
287
|
-
if children:
|
288
|
-
raise ValueError("`Array` objects
|
324
|
+
if not children:
|
325
|
+
raise ValueError("`Array` objects must have children.")
|
289
326
|
|
290
327
|
obj_body = get_object_body(object_content, cls)
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
328
|
+
|
329
|
+
# Extract children IDs from head
|
330
|
+
children_ids = get_object_children_ids_from_object_content(object_content)
|
331
|
+
# Decode the Array body
|
332
|
+
array_metadata: dict[str, str | tuple[int, ...] | list[int]] = json.loads(
|
333
|
+
obj_body.decode(encoding="utf-8")
|
297
334
|
)
|
298
335
|
|
336
|
+
# Verify children ids in body match those passed for inflation
|
337
|
+
chunk_ids_indices = cast(list[int], array_metadata["arraychunk_ids"])
|
338
|
+
# Convert indices back to IDs
|
339
|
+
chunk_ids = [children_ids[i] for i in chunk_ids_indices]
|
340
|
+
# Check consistency
|
341
|
+
unique_arrayschunks = set(chunk_ids)
|
342
|
+
children_obj_ids = set(children.keys())
|
343
|
+
if unique_arrayschunks != children_obj_ids:
|
344
|
+
raise ValueError(
|
345
|
+
"Unexpected set of `children`. "
|
346
|
+
f"Expected {unique_arrayschunks} but got {children_obj_ids}."
|
347
|
+
)
|
348
|
+
|
349
|
+
# Materialize Array with empty data
|
350
|
+
array = cls(
|
351
|
+
dtype=cast(str, array_metadata["dtype"]),
|
352
|
+
shape=cast(tuple[int], tuple(array_metadata["shape"])),
|
353
|
+
stype=cast(str, array_metadata["stype"]),
|
354
|
+
data=b"",
|
355
|
+
)
|
356
|
+
|
357
|
+
# Now inject data from chunks
|
358
|
+
buff = bytearray()
|
359
|
+
for ch_id in chunk_ids:
|
360
|
+
buff += cast(ArrayChunk, children[ch_id]).data
|
361
|
+
|
362
|
+
array.data = bytes(buff)
|
363
|
+
return array
|
364
|
+
|
299
365
|
@property
|
300
366
|
def object_id(self) -> str:
|
301
367
|
"""Get object ID."""
|
@@ -0,0 +1,62 @@
|
|
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
|
+
"""ArrayChunk."""
|
16
|
+
|
17
|
+
|
18
|
+
from __future__ import annotations
|
19
|
+
|
20
|
+
from dataclasses import dataclass
|
21
|
+
|
22
|
+
from ..inflatable import InflatableObject, add_header_to_object_body, get_object_body
|
23
|
+
|
24
|
+
|
25
|
+
@dataclass
|
26
|
+
class ArrayChunk(InflatableObject):
|
27
|
+
"""ArrayChunk type."""
|
28
|
+
|
29
|
+
data: memoryview
|
30
|
+
|
31
|
+
def __init__(self, data: bytes) -> None:
|
32
|
+
self.data = memoryview(data)
|
33
|
+
|
34
|
+
def deflate(self) -> bytes:
|
35
|
+
"""Deflate the ArrayChunk."""
|
36
|
+
return add_header_to_object_body(object_body=self.data, obj=self)
|
37
|
+
|
38
|
+
@classmethod
|
39
|
+
def inflate(
|
40
|
+
cls, object_content: bytes, children: dict[str, InflatableObject] | None = None
|
41
|
+
) -> ArrayChunk:
|
42
|
+
"""Inflate an ArrayChunk from bytes.
|
43
|
+
|
44
|
+
Parameters
|
45
|
+
----------
|
46
|
+
object_content : bytes
|
47
|
+
The deflated object content of the ArrayChunk.
|
48
|
+
|
49
|
+
children : Optional[dict[str, InflatableObject]] (default: None)
|
50
|
+
Must be ``None``. ``ArrayChunk`` does not support child objects.
|
51
|
+
Providing any children will raise a ``ValueError``.
|
52
|
+
|
53
|
+
Returns
|
54
|
+
-------
|
55
|
+
ArrayChunk
|
56
|
+
The inflated ArrayChunk.
|
57
|
+
"""
|
58
|
+
if children:
|
59
|
+
raise ValueError("`ArrayChunk` objects do not have children.")
|
60
|
+
|
61
|
+
obj_body = get_object_body(object_content, cls)
|
62
|
+
return cls(data=memoryview(obj_body))
|
@@ -0,0 +1,22 @@
|
|
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 license plugin components."""
|
16
|
+
|
17
|
+
|
18
|
+
from .license_plugin import LicensePlugin as LicensePlugin
|
19
|
+
|
20
|
+
__all__ = [
|
21
|
+
"LicensePlugin",
|
22
|
+
]
|
@@ -0,0 +1,34 @@
|
|
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 License Plugin."""
|
16
|
+
|
17
|
+
|
18
|
+
from abc import ABC, abstractmethod
|
19
|
+
|
20
|
+
|
21
|
+
class LicensePlugin(ABC):
|
22
|
+
"""Abstract Flower License Plugin class."""
|
23
|
+
|
24
|
+
@abstractmethod
|
25
|
+
def __init__(self) -> None:
|
26
|
+
"""Abstract constructor."""
|
27
|
+
|
28
|
+
@abstractmethod
|
29
|
+
def check_license(self) -> bool:
|
30
|
+
"""Check if the license is valid."""
|
31
|
+
|
32
|
+
@abstractmethod
|
33
|
+
def get_license_info(self) -> None:
|
34
|
+
"""Get information about the license."""
|
flwr/superexec/exec_grpc.py
CHANGED
@@ -23,21 +23,31 @@ import grpc
|
|
23
23
|
from flwr.common import GRPC_MAX_MESSAGE_LENGTH
|
24
24
|
from flwr.common.auth_plugin import ExecAuthPlugin, ExecAuthzPlugin
|
25
25
|
from flwr.common.event_log_plugin import EventLogWriterPlugin
|
26
|
+
from flwr.common.exit import ExitCode, flwr_exit
|
26
27
|
from flwr.common.grpc import generic_create_grpc_server
|
27
28
|
from flwr.common.logger import log
|
28
29
|
from flwr.common.typing import UserConfig
|
29
30
|
from flwr.proto.exec_pb2_grpc import add_ExecServicer_to_server
|
30
31
|
from flwr.server.superlink.linkstate import LinkStateFactory
|
31
32
|
from flwr.supercore.ffs import FfsFactory
|
33
|
+
from flwr.supercore.license_plugin import LicensePlugin
|
32
34
|
from flwr.supercore.object_store import ObjectStoreFactory
|
33
35
|
from flwr.superexec.exec_event_log_interceptor import ExecEventLogInterceptor
|
36
|
+
from flwr.superexec.exec_license_interceptor import ExecLicenseInterceptor
|
34
37
|
from flwr.superexec.exec_user_auth_interceptor import ExecUserAuthInterceptor
|
35
38
|
|
36
39
|
from .exec_servicer import ExecServicer
|
37
40
|
from .executor import Executor
|
38
41
|
|
42
|
+
try:
|
43
|
+
from flwr.ee import get_license_plugin
|
44
|
+
except ImportError:
|
39
45
|
|
40
|
-
|
46
|
+
def get_license_plugin() -> Optional[LicensePlugin]:
|
47
|
+
"""Return the license plugin."""
|
48
|
+
|
49
|
+
|
50
|
+
# pylint: disable-next=too-many-arguments,too-many-positional-arguments,too-many-locals
|
41
51
|
def run_exec_api_grpc(
|
42
52
|
address: str,
|
43
53
|
executor: Executor,
|
@@ -53,6 +63,12 @@ def run_exec_api_grpc(
|
|
53
63
|
"""Run Exec API (gRPC, request-response)."""
|
54
64
|
executor.set_config(config)
|
55
65
|
|
66
|
+
license_plugin: Optional[LicensePlugin] = get_license_plugin()
|
67
|
+
if license_plugin:
|
68
|
+
license_plugin.get_license_info()
|
69
|
+
if not license_plugin.check_license():
|
70
|
+
flwr_exit(ExitCode.SUPERLINK_LICENSE_INVALID)
|
71
|
+
|
56
72
|
exec_servicer: grpc.Server = ExecServicer(
|
57
73
|
linkstate_factory=state_factory,
|
58
74
|
ffs_factory=ffs_factory,
|
@@ -61,6 +77,8 @@ def run_exec_api_grpc(
|
|
61
77
|
auth_plugin=auth_plugin,
|
62
78
|
)
|
63
79
|
interceptors: list[grpc.ServerInterceptor] = []
|
80
|
+
if license_plugin is not None:
|
81
|
+
interceptors.append(ExecLicenseInterceptor(license_plugin))
|
64
82
|
if auth_plugin is not None and authz_plugin is not None:
|
65
83
|
interceptors.append(ExecUserAuthInterceptor(auth_plugin, authz_plugin))
|
66
84
|
# Event log interceptor must be added after user auth interceptor
|
@@ -0,0 +1,74 @@
|
|
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 Exec API license interceptor."""
|
16
|
+
|
17
|
+
|
18
|
+
from collections.abc import Iterator
|
19
|
+
from typing import Any, Callable, Union
|
20
|
+
|
21
|
+
import grpc
|
22
|
+
from google.protobuf.message import Message as GrpcMessage
|
23
|
+
|
24
|
+
from flwr.supercore.license_plugin import LicensePlugin
|
25
|
+
|
26
|
+
|
27
|
+
class ExecLicenseInterceptor(grpc.ServerInterceptor): # type: ignore
|
28
|
+
"""Exec API interceptor for license checking."""
|
29
|
+
|
30
|
+
def __init__(self, license_plugin: LicensePlugin) -> None:
|
31
|
+
"""Initialize the interceptor with a license plugin."""
|
32
|
+
self.license_plugin = license_plugin
|
33
|
+
|
34
|
+
def intercept_service(
|
35
|
+
self,
|
36
|
+
continuation: Callable[[Any], Any],
|
37
|
+
handler_call_details: grpc.HandlerCallDetails,
|
38
|
+
) -> grpc.RpcMethodHandler:
|
39
|
+
"""Flower server interceptor license logic.
|
40
|
+
|
41
|
+
Intercept all unary-unary/unary-stream calls from users and check the license.
|
42
|
+
Continue RPC call if license check is enabled and passes, else, terminate RPC
|
43
|
+
call by setting context to abort.
|
44
|
+
"""
|
45
|
+
# One of the method handlers in
|
46
|
+
# `flwr.superexec.exec_servicer.ExecServicer`
|
47
|
+
method_handler: grpc.RpcMethodHandler = continuation(handler_call_details)
|
48
|
+
return self._generic_license_unary_method_handler(method_handler)
|
49
|
+
|
50
|
+
def _generic_license_unary_method_handler(
|
51
|
+
self, method_handler: grpc.RpcMethodHandler
|
52
|
+
) -> grpc.RpcMethodHandler:
|
53
|
+
def _generic_method_handler(
|
54
|
+
request: GrpcMessage,
|
55
|
+
context: grpc.ServicerContext,
|
56
|
+
) -> Union[GrpcMessage, Iterator[GrpcMessage]]:
|
57
|
+
"""Handle the method call with license checking."""
|
58
|
+
call = method_handler.unary_unary or method_handler.unary_stream
|
59
|
+
|
60
|
+
if not self.license_plugin.check_license():
|
61
|
+
context.abort(grpc.StatusCode.PERMISSION_DENIED, "License check failed")
|
62
|
+
raise grpc.RpcError()
|
63
|
+
|
64
|
+
return call(request, context) # type: ignore
|
65
|
+
|
66
|
+
if method_handler.unary_unary:
|
67
|
+
message_handler = grpc.unary_unary_rpc_method_handler
|
68
|
+
else:
|
69
|
+
message_handler = grpc.unary_stream_rpc_method_handler
|
70
|
+
return message_handler(
|
71
|
+
_generic_method_handler,
|
72
|
+
request_deserializer=method_handler.request_deserializer,
|
73
|
+
response_serializer=method_handler.response_serializer,
|
74
|
+
)
|
{flwr_nightly-1.20.0.dev20250627.dist-info → flwr_nightly-1.20.0.dev20250701.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: flwr-nightly
|
3
|
-
Version: 1.20.0.
|
3
|
+
Version: 1.20.0.dev20250701
|
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
|
{flwr_nightly-1.20.0.dev20250627.dist-info → flwr_nightly-1.20.0.dev20250701.dist-info}/RECORD
RENAMED
@@ -73,7 +73,7 @@ flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl,sha256=3-gDei-K7zskh5dD
|
|
73
73
|
flwr/cli/run/__init__.py,sha256=RPyB7KbYTFl6YRiilCch6oezxrLQrl1kijV7BMGkLbA,790
|
74
74
|
flwr/cli/run/run.py,sha256=psmr215gkV0e0QtX9NFp7KUwKSA_ZwekdJmoL1zFyfw,8478
|
75
75
|
flwr/cli/stop.py,sha256=l8DcRkA---CESVJgc7iTHLWIBAPGxWIfoem8qSU3lZQ,4972
|
76
|
-
flwr/cli/utils.py,sha256=
|
76
|
+
flwr/cli/utils.py,sha256=X7Jdvwf70bkOpKynFgMGVYPMDxLQiSVG8Y3G1Y9iRjs,12009
|
77
77
|
flwr/client/__init__.py,sha256=boIhKaK6I977zrILmoTutNx94x5jB0e6F1gnAjaRJnI,1250
|
78
78
|
flwr/client/client.py,sha256=3HAchxvknKG9jYbB7swNyDj-e5vUWDuMKoLvbT7jCVM,7895
|
79
79
|
flwr/client/client_app.py,sha256=zVhi-l3chAb06ozFsKwix3hU_RpOLjST13Ha50AVIPE,16918
|
@@ -108,7 +108,7 @@ flwr/common/args.py,sha256=-aX_jVnSaDrJR2KZ8Wq0Y3dQHII4R4MJtJOIXzVUA0c,5417
|
|
108
108
|
flwr/common/auth_plugin/__init__.py,sha256=3rzPkVLn9WyB5n7HLk1XGDw3SLCqRWAU1_CnglcWPfw,970
|
109
109
|
flwr/common/auth_plugin/auth_plugin.py,sha256=kXx5o39vJchaPv28sK9qO6H_UXSWym6zRBbCa7sUwtQ,4825
|
110
110
|
flwr/common/config.py,sha256=glcZDjco-amw1YfQcYTFJ4S1pt9APoexT-mf1QscuHs,13960
|
111
|
-
flwr/common/constant.py,sha256=
|
111
|
+
flwr/common/constant.py,sha256=HMLDvtiWGcGUfHpyyMx1rau34eXdMuBsvn-koRD8-pQ,8234
|
112
112
|
flwr/common/context.py,sha256=Be8obQR_OvEDy1OmshuUKxGRQ7Qx89mf5F4xlhkR10s,2407
|
113
113
|
flwr/common/date.py,sha256=1ZT2cRSpC2DJqprOVTLXYCR_O2_OZR0zXO_brJ3LqWc,1554
|
114
114
|
flwr/common/differential_privacy.py,sha256=FdlpdpPl_H_2HJa8CQM1iCUGBBQ5Dc8CzxmHERM-EoE,6148
|
@@ -118,21 +118,22 @@ flwr/common/event_log_plugin/__init__.py,sha256=ts3VAL3Fk6Grp1EK_1Qg_V-BfOof9F86
|
|
118
118
|
flwr/common/event_log_plugin/event_log_plugin.py,sha256=eK8OaDFagQRwqpb9eV0cJcm2ErtEBpMxFbhxJNx6n5w,2061
|
119
119
|
flwr/common/exit/__init__.py,sha256=-ZOJYLaNnR729a7VzZiFsLiqngzKQh3xc27svYStZ_Q,826
|
120
120
|
flwr/common/exit/exit.py,sha256=mJgbqMlVlwAgYtq-Vedj53wO4VxcDcy_P-GzqGK-1GQ,3452
|
121
|
-
flwr/common/exit/exit_code.py,sha256=
|
121
|
+
flwr/common/exit/exit_code.py,sha256=rvr9ftYL3yp9vJF0epkx8S61R1xcivgPPBJsiS_al9A,3664
|
122
122
|
flwr/common/exit_handlers.py,sha256=IaqJ60fXZuu7McaRYnoYKtlbH9t4Yl9goNExKqtmQbs,4304
|
123
123
|
flwr/common/grpc.py,sha256=manTaHaPiyYngUq1ErZvvV2B2GxlXUUUGRy3jc3TBIQ,9798
|
124
124
|
flwr/common/heartbeat.py,sha256=SyEpNDnmJ0lni0cWO67rcoJVKasCLmkNHm3dKLeNrLU,5749
|
125
125
|
flwr/common/inflatable.py,sha256=GDL9oBKs16_yyVdlH6kBf493O5xll_h9V7XB5Mpx1Hc,9524
|
126
126
|
flwr/common/inflatable_grpc_utils.py,sha256=ZpwtgF1tGD6NwQkCidbhbeBPDBZ1Nx9eGMHQ04eNEE8,3554
|
127
127
|
flwr/common/inflatable_rest_utils.py,sha256=KiZd06XRiXcl_WewOrag0JTvUQt5kZ74UIsQ3FCAXGc,3580
|
128
|
-
flwr/common/inflatable_utils.py,sha256
|
128
|
+
flwr/common/inflatable_utils.py,sha256=XfgkPl8GKuR7tuOpYVZ3zK4n-LbgMZtwoNxMfUbpiCE,12489
|
129
129
|
flwr/common/logger.py,sha256=JbRf6E2vQxXzpDBq1T8IDUJo_usu3gjWEBPQ6uKcmdg,13049
|
130
130
|
flwr/common/message.py,sha256=xAL7iZN5-n-xPQpgoSFvxNrzs8fmiiPfoU0DjNQEhRw,19953
|
131
131
|
flwr/common/object_ref.py,sha256=p3SfTeqo3Aj16SkB-vsnNn01zswOPdGNBitcbRnqmUk,9134
|
132
132
|
flwr/common/parameter.py,sha256=UVw6sOgehEFhFs4uUCMl2kfVq1PD6ncmWgPLMsZPKPE,2095
|
133
133
|
flwr/common/pyproject.py,sha256=2SU6yJW7059SbMXgzjOdK1GZRWO6AixDH7BmdxbMvHI,1386
|
134
134
|
flwr/common/record/__init__.py,sha256=cNGccdDoxttqgnUgyKRIqLWULjW-NaSmOufVxtXq-sw,1197
|
135
|
-
flwr/common/record/array.py,sha256=
|
135
|
+
flwr/common/record/array.py,sha256=oApWRwxh1bY2MivQcAz9YHkrspkYZVvy1OkBsWolMec,14541
|
136
|
+
flwr/common/record/arraychunk.py,sha256=2ubMzsRNZFL4cc-wXNrJkcTSJUD3nL8CeX5PZpEhNSo,2019
|
136
137
|
flwr/common/record/arrayrecord.py,sha256=CpoqYXM6Iv4XEc9SryCMYmw-bIvP8ut6xWJzRwYJzdU,18008
|
137
138
|
flwr/common/record/configrecord.py,sha256=G7U0q39kB0Kyi0zMxFmPxcVemL9NgwVS1qjvI4BRQuU,9763
|
138
139
|
flwr/common/record/conversion_utils.py,sha256=wbNCzy7oAqaA3-arhls_EqRZYXRC4YrWIoE-Gy82fJ0,1191
|
@@ -331,6 +332,8 @@ flwr/supercore/ffs/__init__.py,sha256=U3KXwG_SplEvchat27K0LYPoPHzh-cwwT_NHsGlYMt
|
|
331
332
|
flwr/supercore/ffs/disk_ffs.py,sha256=c5VywSaRnq3XM_zuJptNtsF2HFwsRK0pvBd5-5CNONs,3272
|
332
333
|
flwr/supercore/ffs/ffs.py,sha256=6w7wy71i7tbuJwqEgdeCa49JejXMEof3jujURN_R7Rg,2395
|
333
334
|
flwr/supercore/ffs/ffs_factory.py,sha256=pK-g3LMelvWTV6N9Cd-j-_-FdcGbRFTKNsWaqmlBDSk,1490
|
335
|
+
flwr/supercore/license_plugin/__init__.py,sha256=d8OgHTn2BwjoNSPy8jQQxTC_iT3-ENLwKM8yhHKvCRM,820
|
336
|
+
flwr/supercore/license_plugin/license_plugin.py,sha256=mqr9jn3WxukXembW8EmxsbGJ6kc4ANfc2U9ehmUm5MQ,1147
|
334
337
|
flwr/supercore/object_store/__init__.py,sha256=cdfPAmjINY6iOp8oI_LdcVh2simg469Mkdl4LLV4kHI,911
|
335
338
|
flwr/supercore/object_store/in_memory_object_store.py,sha256=oflJcOuVNgx9A-B2da4VHDb1qj_Jub9wKFOrUBgtz_U,9630
|
336
339
|
flwr/supercore/object_store/object_store.py,sha256=VlZz-yzoWZtITbnYD8vwLZbFosv7vgr1XVNzByObeY0,5853
|
@@ -340,7 +343,8 @@ flwr/superexec/__init__.py,sha256=YFqER0IJc1XEWfsX6AxZ9LSRq0sawPYrNYki-brvTIc,71
|
|
340
343
|
flwr/superexec/app.py,sha256=U2jjOHb2LGWoU7vrl9_czTzre9O2mPxu3CPGUZ86sK4,1465
|
341
344
|
flwr/superexec/deployment.py,sha256=cFxhFom-0zv93HLNjNcUdBy3Sf6JwshRoXPQtcZunF0,6797
|
342
345
|
flwr/superexec/exec_event_log_interceptor.py,sha256=7aBjZ4lkpOIyWut0s394OpMePr16g_Te594s-9aDM9Q,5774
|
343
|
-
flwr/superexec/exec_grpc.py,sha256=
|
346
|
+
flwr/superexec/exec_grpc.py,sha256=xyyxrhPQLGX7tafGadv5DXLUzVoUIkGLd53_raOfNHk,4202
|
347
|
+
flwr/superexec/exec_license_interceptor.py,sha256=-BZPO-ZwtrPYumcDNdEh2QZK4uX-tuYBsZqKuDK0MZ8,3026
|
344
348
|
flwr/superexec/exec_servicer.py,sha256=c0nwdFBiS6CbKrRA7ffOpsgASOLeaRV_ICwxDfxNGAg,12498
|
345
349
|
flwr/superexec/exec_user_auth_interceptor.py,sha256=HpGHTcDKzB7XUiQHXgntNVFYL-VfP9Wj5tEVc04VOOw,5820
|
346
350
|
flwr/superexec/executor.py,sha256=LaErHRJvNggjWV6FI6eajgKfnwOvSv2UqzFH253yDro,3265
|
@@ -360,7 +364,7 @@ flwr/supernode/servicer/__init__.py,sha256=lucTzre5WPK7G1YLCfaqg3rbFWdNSb7ZTt-ca
|
|
360
364
|
flwr/supernode/servicer/clientappio/__init__.py,sha256=7Oy62Y_oijqF7Dxi6tpcUQyOpLc_QpIRZ83NvwmB0Yg,813
|
361
365
|
flwr/supernode/servicer/clientappio/clientappio_servicer.py,sha256=d3GdIabycUoDBDL_eVlt513knGSjQW3-9lG6Cw4QEk4,5719
|
362
366
|
flwr/supernode/start_client_internal.py,sha256=DAXuReZ1FCXt9Y1KbM0p-dI50ROWPEJXzfKrl14OE6k,18233
|
363
|
-
flwr_nightly-1.20.0.
|
364
|
-
flwr_nightly-1.20.0.
|
365
|
-
flwr_nightly-1.20.0.
|
366
|
-
flwr_nightly-1.20.0.
|
367
|
+
flwr_nightly-1.20.0.dev20250701.dist-info/METADATA,sha256=j0r0nY5a-FlldBWbh47eja74PsvI0AW0c6lDYkV4ch0,15910
|
368
|
+
flwr_nightly-1.20.0.dev20250701.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
369
|
+
flwr_nightly-1.20.0.dev20250701.dist-info/entry_points.txt,sha256=jNpDXGBGgs21RqUxelF_jwGaxtqFwm-MQyfz-ZqSjrA,367
|
370
|
+
flwr_nightly-1.20.0.dev20250701.dist-info/RECORD,,
|
{flwr_nightly-1.20.0.dev20250627.dist-info → flwr_nightly-1.20.0.dev20250701.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|