flwr-nightly 1.15.0.dev20250107__py3-none-any.whl → 1.15.0.dev20250108__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/cli_user_auth_interceptor.py +6 -2
- flwr/cli/login/login.py +11 -4
- flwr/cli/utils.py +4 -4
- flwr/common/auth_plugin/auth_plugin.py +33 -23
- flwr/common/constant.py +2 -0
- flwr/common/typing.py +20 -0
- flwr/proto/exec_pb2.py +12 -24
- flwr/proto/exec_pb2.pyi +27 -54
- flwr/server/app.py +11 -13
- flwr/server/superlink/linkstate/sqlite_linkstate.py +8 -9
- flwr/superexec/exec_servicer.py +23 -2
- {flwr_nightly-1.15.0.dev20250107.dist-info → flwr_nightly-1.15.0.dev20250108.dist-info}/METADATA +3 -3
- {flwr_nightly-1.15.0.dev20250107.dist-info → flwr_nightly-1.15.0.dev20250108.dist-info}/RECORD +16 -16
- {flwr_nightly-1.15.0.dev20250107.dist-info → flwr_nightly-1.15.0.dev20250108.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.15.0.dev20250107.dist-info → flwr_nightly-1.15.0.dev20250108.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.15.0.dev20250107.dist-info → flwr_nightly-1.15.0.dev20250108.dist-info}/entry_points.txt +0 -0
@@ -54,8 +54,12 @@ class CliUserAuthInterceptor(
|
|
54
54
|
|
55
55
|
response = continuation(details, request)
|
56
56
|
if response.initial_metadata():
|
57
|
-
|
58
|
-
|
57
|
+
credentials = self.auth_plugin.read_tokens_from_metadata(
|
58
|
+
response.initial_metadata()
|
59
|
+
)
|
60
|
+
# The metadata contains tokens only if they have been refreshed
|
61
|
+
if credentials is not None:
|
62
|
+
self.auth_plugin.store_tokens(credentials)
|
59
63
|
|
60
64
|
return response
|
61
65
|
|
flwr/cli/login/login.py
CHANGED
@@ -26,7 +26,7 @@ from flwr.cli.config_utils import (
|
|
26
26
|
process_loaded_project_config,
|
27
27
|
validate_federation_in_project_config,
|
28
28
|
)
|
29
|
-
from flwr.common.
|
29
|
+
from flwr.common.typing import UserAuthLoginDetails
|
30
30
|
from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
|
31
31
|
GetLoginDetailsRequest,
|
32
32
|
GetLoginDetailsResponse,
|
@@ -64,7 +64,7 @@ def login( # pylint: disable=R0914
|
|
64
64
|
login_response: GetLoginDetailsResponse = stub.GetLoginDetails(login_request)
|
65
65
|
|
66
66
|
# Get the auth plugin
|
67
|
-
auth_type = login_response.
|
67
|
+
auth_type = login_response.auth_type
|
68
68
|
auth_plugin = try_obtain_cli_auth_plugin(app, federation, auth_type)
|
69
69
|
if auth_plugin is None:
|
70
70
|
typer.secho(
|
@@ -75,7 +75,14 @@ def login( # pylint: disable=R0914
|
|
75
75
|
raise typer.Exit(code=1)
|
76
76
|
|
77
77
|
# Login
|
78
|
-
|
78
|
+
details = UserAuthLoginDetails(
|
79
|
+
auth_type=login_response.auth_type,
|
80
|
+
device_code=login_response.device_code,
|
81
|
+
verification_uri_complete=login_response.verification_uri_complete,
|
82
|
+
expires_in=login_response.expires_in,
|
83
|
+
interval=login_response.interval,
|
84
|
+
)
|
85
|
+
credentials = auth_plugin.login(details, stub)
|
79
86
|
|
80
87
|
# Store the tokens
|
81
|
-
auth_plugin.store_tokens(
|
88
|
+
auth_plugin.store_tokens(credentials)
|
flwr/cli/utils.py
CHANGED
@@ -223,19 +223,19 @@ def try_obtain_cli_auth_plugin(
|
|
223
223
|
config_path = get_user_auth_config_path(root_dir, federation)
|
224
224
|
|
225
225
|
# Load the config file if it exists
|
226
|
-
|
226
|
+
json_file: dict[str, Any] = {}
|
227
227
|
if config_path.exists():
|
228
228
|
with config_path.open("r", encoding="utf-8") as file:
|
229
|
-
|
229
|
+
json_file = json.load(file)
|
230
230
|
# This is the case when the user auth is not enabled
|
231
231
|
elif auth_type is None:
|
232
232
|
return None
|
233
233
|
|
234
234
|
# Get the auth type from the config if not provided
|
235
235
|
if auth_type is None:
|
236
|
-
if AUTH_TYPE not in
|
236
|
+
if AUTH_TYPE not in json_file:
|
237
237
|
return None
|
238
|
-
auth_type =
|
238
|
+
auth_type = json_file[AUTH_TYPE]
|
239
239
|
|
240
240
|
# Retrieve auth plugin class and instantiate it
|
241
241
|
try:
|
@@ -18,26 +18,31 @@
|
|
18
18
|
from abc import ABC, abstractmethod
|
19
19
|
from collections.abc import Sequence
|
20
20
|
from pathlib import Path
|
21
|
-
from typing import
|
21
|
+
from typing import Optional, Union
|
22
22
|
|
23
23
|
from flwr.proto.exec_pb2_grpc import ExecStub
|
24
24
|
|
25
|
+
from ..typing import UserAuthCredentials, UserAuthLoginDetails
|
26
|
+
|
25
27
|
|
26
28
|
class ExecAuthPlugin(ABC):
|
27
29
|
"""Abstract Flower Auth Plugin class for ExecServicer.
|
28
30
|
|
29
31
|
Parameters
|
30
32
|
----------
|
31
|
-
|
32
|
-
|
33
|
+
user_auth_config_path : Path
|
34
|
+
Path to the YAML file containing the authentication configuration.
|
33
35
|
"""
|
34
36
|
|
35
37
|
@abstractmethod
|
36
|
-
def __init__(
|
38
|
+
def __init__(
|
39
|
+
self,
|
40
|
+
user_auth_config_path: Path,
|
41
|
+
):
|
37
42
|
"""Abstract constructor."""
|
38
43
|
|
39
44
|
@abstractmethod
|
40
|
-
def get_login_details(self) ->
|
45
|
+
def get_login_details(self) -> Optional[UserAuthLoginDetails]:
|
41
46
|
"""Get the login details."""
|
42
47
|
|
43
48
|
@abstractmethod
|
@@ -47,7 +52,7 @@ class ExecAuthPlugin(ABC):
|
|
47
52
|
"""Validate authentication tokens in the provided metadata."""
|
48
53
|
|
49
54
|
@abstractmethod
|
50
|
-
def get_auth_tokens(self,
|
55
|
+
def get_auth_tokens(self, device_code: str) -> Optional[UserAuthCredentials]:
|
51
56
|
"""Get authentication tokens."""
|
52
57
|
|
53
58
|
@abstractmethod
|
@@ -62,50 +67,55 @@ class CliAuthPlugin(ABC):
|
|
62
67
|
|
63
68
|
Parameters
|
64
69
|
----------
|
65
|
-
|
66
|
-
|
70
|
+
credentials_path : Path
|
71
|
+
Path to the user's authentication credentials file.
|
67
72
|
"""
|
68
73
|
|
69
74
|
@staticmethod
|
70
75
|
@abstractmethod
|
71
76
|
def login(
|
72
|
-
login_details:
|
77
|
+
login_details: UserAuthLoginDetails,
|
73
78
|
exec_stub: ExecStub,
|
74
|
-
) ->
|
75
|
-
"""Authenticate the user
|
79
|
+
) -> UserAuthCredentials:
|
80
|
+
"""Authenticate the user and retrieve authentication credentials.
|
76
81
|
|
77
82
|
Parameters
|
78
83
|
----------
|
79
|
-
login_details :
|
80
|
-
|
84
|
+
login_details : UserAuthLoginDetails
|
85
|
+
An object containing the user's login details.
|
81
86
|
exec_stub : ExecStub
|
82
|
-
|
87
|
+
A stub for executing RPC calls to the server.
|
83
88
|
|
84
89
|
Returns
|
85
90
|
-------
|
86
|
-
|
87
|
-
|
88
|
-
in JSON format.
|
91
|
+
UserAuthCredentials
|
92
|
+
The authentication credentials obtained after login.
|
89
93
|
"""
|
90
94
|
|
91
95
|
@abstractmethod
|
92
|
-
def __init__(self,
|
96
|
+
def __init__(self, credentials_path: Path):
|
93
97
|
"""Abstract constructor."""
|
94
98
|
|
95
99
|
@abstractmethod
|
96
|
-
def store_tokens(self,
|
97
|
-
"""Store authentication tokens
|
100
|
+
def store_tokens(self, credentials: UserAuthCredentials) -> None:
|
101
|
+
"""Store authentication tokens to the `credentials_path`.
|
98
102
|
|
99
|
-
The
|
100
|
-
at `
|
103
|
+
The credentials, including tokens, will be saved as a JSON file
|
104
|
+
at `credentials_path`.
|
101
105
|
"""
|
102
106
|
|
103
107
|
@abstractmethod
|
104
108
|
def load_tokens(self) -> None:
|
105
|
-
"""Load authentication tokens from the
|
109
|
+
"""Load authentication tokens from the `credentials_path`."""
|
106
110
|
|
107
111
|
@abstractmethod
|
108
112
|
def write_tokens_to_metadata(
|
109
113
|
self, metadata: Sequence[tuple[str, Union[str, bytes]]]
|
110
114
|
) -> Sequence[tuple[str, Union[str, bytes]]]:
|
111
115
|
"""Write authentication tokens to the provided metadata."""
|
116
|
+
|
117
|
+
@abstractmethod
|
118
|
+
def read_tokens_from_metadata(
|
119
|
+
self, metadata: Sequence[tuple[str, Union[str, bytes]]]
|
120
|
+
) -> Optional[UserAuthCredentials]:
|
121
|
+
"""Read authentication tokens from the provided metadata."""
|
flwr/common/constant.py
CHANGED
@@ -114,6 +114,8 @@ MAX_RETRY_DELAY = 20 # Maximum delay duration between two consecutive retries.
|
|
114
114
|
# Constants for user authentication
|
115
115
|
CREDENTIALS_DIR = ".credentials"
|
116
116
|
AUTH_TYPE = "auth_type"
|
117
|
+
ACCESS_TOKEN_KEY = "access_token"
|
118
|
+
REFRESH_TOKEN_KEY = "refresh_token"
|
117
119
|
|
118
120
|
|
119
121
|
class MessageType:
|
flwr/common/typing.py
CHANGED
@@ -266,3 +266,23 @@ class InvalidRunStatusException(BaseException):
|
|
266
266
|
def __init__(self, message: str) -> None:
|
267
267
|
super().__init__(message)
|
268
268
|
self.message = message
|
269
|
+
|
270
|
+
|
271
|
+
# OIDC user authentication types
|
272
|
+
@dataclass
|
273
|
+
class UserAuthLoginDetails:
|
274
|
+
"""User authentication login details."""
|
275
|
+
|
276
|
+
auth_type: str
|
277
|
+
device_code: str
|
278
|
+
verification_uri_complete: str
|
279
|
+
expires_in: int
|
280
|
+
interval: int
|
281
|
+
|
282
|
+
|
283
|
+
@dataclass
|
284
|
+
class UserAuthCredentials:
|
285
|
+
"""User authentication tokens."""
|
286
|
+
|
287
|
+
access_token: str
|
288
|
+
refresh_token: str
|
flwr/proto/exec_pb2.py
CHANGED
@@ -18,7 +18,7 @@ from flwr.proto import recordset_pb2 as flwr_dot_proto_dot_recordset__pb2
|
|
18
18
|
from flwr.proto import run_pb2 as flwr_dot_proto_dot_run__pb2
|
19
19
|
|
20
20
|
|
21
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x66lwr/proto/exec.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x1a\x66lwr/proto/transport.proto\x1a\x1a\x66lwr/proto/recordset.proto\x1a\x14\x66lwr/proto/run.proto\"\xfb\x01\n\x0fStartRunRequest\x12\x1c\n\x03\x66\x61\x62\x18\x01 \x01(\x0b\x32\x0f.flwr.proto.Fab\x12H\n\x0foverride_config\x18\x02 \x03(\x0b\x32/.flwr.proto.StartRunRequest.OverrideConfigEntry\x12\x35\n\x12\x66\x65\x64\x65ration_options\x18\x03 \x01(\x0b\x32\x19.flwr.proto.ConfigsRecord\x1aI\n\x13OverrideConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\"2\n\x10StartRunResponse\x12\x13\n\x06run_id\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\t\n\x07_run_id\"<\n\x11StreamLogsRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x17\n\x0f\x61\x66ter_timestamp\x18\x02 \x01(\x01\"B\n\x12StreamLogsResponse\x12\x12\n\nlog_output\x18\x01 \x01(\t\x12\x18\n\x10latest_timestamp\x18\x02 \x01(\x01\"1\n\x0fListRunsRequest\x12\x13\n\x06run_id\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\t\n\x07_run_id\"\x9d\x01\n\x10ListRunsResponse\x12;\n\x08run_dict\x18\x01 \x03(\x0b\x32).flwr.proto.ListRunsResponse.RunDictEntry\x12\x0b\n\x03now\x18\x02 \x01(\t\x1a?\n\x0cRunDictEntry\x12\x0b\n\x03key\x18\x01 \x01(\x04\x12\x1e\n\x05value\x18\x02 \x01(\x0b\x32\x0f.flwr.proto.Run:\x02\x38\x01\"\x18\n\x16GetLoginDetailsRequest\"\
|
21
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x66lwr/proto/exec.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x1a\x66lwr/proto/transport.proto\x1a\x1a\x66lwr/proto/recordset.proto\x1a\x14\x66lwr/proto/run.proto\"\xfb\x01\n\x0fStartRunRequest\x12\x1c\n\x03\x66\x61\x62\x18\x01 \x01(\x0b\x32\x0f.flwr.proto.Fab\x12H\n\x0foverride_config\x18\x02 \x03(\x0b\x32/.flwr.proto.StartRunRequest.OverrideConfigEntry\x12\x35\n\x12\x66\x65\x64\x65ration_options\x18\x03 \x01(\x0b\x32\x19.flwr.proto.ConfigsRecord\x1aI\n\x13OverrideConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\"2\n\x10StartRunResponse\x12\x13\n\x06run_id\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\t\n\x07_run_id\"<\n\x11StreamLogsRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x17\n\x0f\x61\x66ter_timestamp\x18\x02 \x01(\x01\"B\n\x12StreamLogsResponse\x12\x12\n\nlog_output\x18\x01 \x01(\t\x12\x18\n\x10latest_timestamp\x18\x02 \x01(\x01\"1\n\x0fListRunsRequest\x12\x13\n\x06run_id\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\t\n\x07_run_id\"\x9d\x01\n\x10ListRunsResponse\x12;\n\x08run_dict\x18\x01 \x03(\x0b\x32).flwr.proto.ListRunsResponse.RunDictEntry\x12\x0b\n\x03now\x18\x02 \x01(\t\x1a?\n\x0cRunDictEntry\x12\x0b\n\x03key\x18\x01 \x01(\x04\x12\x1e\n\x05value\x18\x02 \x01(\x0b\x32\x0f.flwr.proto.Run:\x02\x38\x01\"\x18\n\x16GetLoginDetailsRequest\"\x8a\x01\n\x17GetLoginDetailsResponse\x12\x11\n\tauth_type\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65vice_code\x18\x02 \x01(\t\x12!\n\x19verification_uri_complete\x18\x03 \x01(\t\x12\x12\n\nexpires_in\x18\x04 \x01(\x03\x12\x10\n\x08interval\x18\x05 \x01(\x03\"+\n\x14GetAuthTokensRequest\x12\x13\n\x0b\x64\x65vice_code\x18\x01 \x01(\t\"D\n\x15GetAuthTokensResponse\x12\x14\n\x0c\x61\x63\x63\x65ss_token\x18\x01 \x01(\t\x12\x15\n\rrefresh_token\x18\x02 \x01(\t\" \n\x0eStopRunRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\"\"\n\x0fStopRunResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x32\xe5\x03\n\x04\x45xec\x12G\n\x08StartRun\x12\x1b.flwr.proto.StartRunRequest\x1a\x1c.flwr.proto.StartRunResponse\"\x00\x12\x44\n\x07StopRun\x12\x1a.flwr.proto.StopRunRequest\x1a\x1b.flwr.proto.StopRunResponse\"\x00\x12O\n\nStreamLogs\x12\x1d.flwr.proto.StreamLogsRequest\x1a\x1e.flwr.proto.StreamLogsResponse\"\x00\x30\x01\x12G\n\x08ListRuns\x12\x1b.flwr.proto.ListRunsRequest\x1a\x1c.flwr.proto.ListRunsResponse\"\x00\x12\\\n\x0fGetLoginDetails\x12\".flwr.proto.GetLoginDetailsRequest\x1a#.flwr.proto.GetLoginDetailsResponse\"\x00\x12V\n\rGetAuthTokens\x12 .flwr.proto.GetAuthTokensRequest\x1a!.flwr.proto.GetAuthTokensResponse\"\x00\x62\x06proto3')
|
22
22
|
|
23
23
|
_globals = globals()
|
24
24
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
@@ -29,12 +29,6 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
29
29
|
_globals['_STARTRUNREQUEST_OVERRIDECONFIGENTRY']._serialized_options = b'8\001'
|
30
30
|
_globals['_LISTRUNSRESPONSE_RUNDICTENTRY']._options = None
|
31
31
|
_globals['_LISTRUNSRESPONSE_RUNDICTENTRY']._serialized_options = b'8\001'
|
32
|
-
_globals['_GETLOGINDETAILSRESPONSE_LOGINDETAILSENTRY']._options = None
|
33
|
-
_globals['_GETLOGINDETAILSRESPONSE_LOGINDETAILSENTRY']._serialized_options = b'8\001'
|
34
|
-
_globals['_GETAUTHTOKENSREQUEST_AUTHDETAILSENTRY']._options = None
|
35
|
-
_globals['_GETAUTHTOKENSREQUEST_AUTHDETAILSENTRY']._serialized_options = b'8\001'
|
36
|
-
_globals['_GETAUTHTOKENSRESPONSE_AUTHTOKENSENTRY']._options = None
|
37
|
-
_globals['_GETAUTHTOKENSRESPONSE_AUTHTOKENSENTRY']._serialized_options = b'8\001'
|
38
32
|
_globals['_STARTRUNREQUEST']._serialized_start=138
|
39
33
|
_globals['_STARTRUNREQUEST']._serialized_end=389
|
40
34
|
_globals['_STARTRUNREQUEST_OVERRIDECONFIGENTRY']._serialized_start=316
|
@@ -54,21 +48,15 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
54
48
|
_globals['_GETLOGINDETAILSREQUEST']._serialized_start=784
|
55
49
|
_globals['_GETLOGINDETAILSREQUEST']._serialized_end=808
|
56
50
|
_globals['_GETLOGINDETAILSRESPONSE']._serialized_start=811
|
57
|
-
_globals['_GETLOGINDETAILSRESPONSE']._serialized_end=
|
58
|
-
_globals['
|
59
|
-
_globals['
|
60
|
-
_globals['
|
61
|
-
_globals['
|
62
|
-
_globals['
|
63
|
-
_globals['
|
64
|
-
_globals['
|
65
|
-
_globals['
|
66
|
-
_globals['
|
67
|
-
_globals['
|
68
|
-
_globals['_STOPRUNREQUEST']._serialized_start=1268
|
69
|
-
_globals['_STOPRUNREQUEST']._serialized_end=1300
|
70
|
-
_globals['_STOPRUNRESPONSE']._serialized_start=1302
|
71
|
-
_globals['_STOPRUNRESPONSE']._serialized_end=1336
|
72
|
-
_globals['_EXEC']._serialized_start=1339
|
73
|
-
_globals['_EXEC']._serialized_end=1824
|
51
|
+
_globals['_GETLOGINDETAILSRESPONSE']._serialized_end=949
|
52
|
+
_globals['_GETAUTHTOKENSREQUEST']._serialized_start=951
|
53
|
+
_globals['_GETAUTHTOKENSREQUEST']._serialized_end=994
|
54
|
+
_globals['_GETAUTHTOKENSRESPONSE']._serialized_start=996
|
55
|
+
_globals['_GETAUTHTOKENSRESPONSE']._serialized_end=1064
|
56
|
+
_globals['_STOPRUNREQUEST']._serialized_start=1066
|
57
|
+
_globals['_STOPRUNREQUEST']._serialized_end=1098
|
58
|
+
_globals['_STOPRUNRESPONSE']._serialized_start=1100
|
59
|
+
_globals['_STOPRUNRESPONSE']._serialized_end=1134
|
60
|
+
_globals['_EXEC']._serialized_start=1137
|
61
|
+
_globals['_EXEC']._serialized_end=1622
|
74
62
|
# @@protoc_insertion_point(module_scope)
|
flwr/proto/exec_pb2.pyi
CHANGED
@@ -143,77 +143,50 @@ global___GetLoginDetailsRequest = GetLoginDetailsRequest
|
|
143
143
|
|
144
144
|
class GetLoginDetailsResponse(google.protobuf.message.Message):
|
145
145
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
) -> None: ...
|
157
|
-
def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ...
|
158
|
-
|
159
|
-
LOGIN_DETAILS_FIELD_NUMBER: builtins.int
|
160
|
-
@property
|
161
|
-
def login_details(self) -> google.protobuf.internal.containers.ScalarMap[typing.Text, typing.Text]: ...
|
146
|
+
AUTH_TYPE_FIELD_NUMBER: builtins.int
|
147
|
+
DEVICE_CODE_FIELD_NUMBER: builtins.int
|
148
|
+
VERIFICATION_URI_COMPLETE_FIELD_NUMBER: builtins.int
|
149
|
+
EXPIRES_IN_FIELD_NUMBER: builtins.int
|
150
|
+
INTERVAL_FIELD_NUMBER: builtins.int
|
151
|
+
auth_type: typing.Text
|
152
|
+
device_code: typing.Text
|
153
|
+
verification_uri_complete: typing.Text
|
154
|
+
expires_in: builtins.int
|
155
|
+
interval: builtins.int
|
162
156
|
def __init__(self,
|
163
157
|
*,
|
164
|
-
|
158
|
+
auth_type: typing.Text = ...,
|
159
|
+
device_code: typing.Text = ...,
|
160
|
+
verification_uri_complete: typing.Text = ...,
|
161
|
+
expires_in: builtins.int = ...,
|
162
|
+
interval: builtins.int = ...,
|
165
163
|
) -> None: ...
|
166
|
-
def ClearField(self, field_name: typing_extensions.Literal["
|
164
|
+
def ClearField(self, field_name: typing_extensions.Literal["auth_type",b"auth_type","device_code",b"device_code","expires_in",b"expires_in","interval",b"interval","verification_uri_complete",b"verification_uri_complete"]) -> None: ...
|
167
165
|
global___GetLoginDetailsResponse = GetLoginDetailsResponse
|
168
166
|
|
169
167
|
class GetAuthTokensRequest(google.protobuf.message.Message):
|
170
168
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
171
|
-
|
172
|
-
|
173
|
-
KEY_FIELD_NUMBER: builtins.int
|
174
|
-
VALUE_FIELD_NUMBER: builtins.int
|
175
|
-
key: typing.Text
|
176
|
-
value: typing.Text
|
177
|
-
def __init__(self,
|
178
|
-
*,
|
179
|
-
key: typing.Text = ...,
|
180
|
-
value: typing.Text = ...,
|
181
|
-
) -> None: ...
|
182
|
-
def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ...
|
183
|
-
|
184
|
-
AUTH_DETAILS_FIELD_NUMBER: builtins.int
|
185
|
-
@property
|
186
|
-
def auth_details(self) -> google.protobuf.internal.containers.ScalarMap[typing.Text, typing.Text]: ...
|
169
|
+
DEVICE_CODE_FIELD_NUMBER: builtins.int
|
170
|
+
device_code: typing.Text
|
187
171
|
def __init__(self,
|
188
172
|
*,
|
189
|
-
|
173
|
+
device_code: typing.Text = ...,
|
190
174
|
) -> None: ...
|
191
|
-
def ClearField(self, field_name: typing_extensions.Literal["
|
175
|
+
def ClearField(self, field_name: typing_extensions.Literal["device_code",b"device_code"]) -> None: ...
|
192
176
|
global___GetAuthTokensRequest = GetAuthTokensRequest
|
193
177
|
|
194
178
|
class GetAuthTokensResponse(google.protobuf.message.Message):
|
195
179
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
key: typing.Text
|
201
|
-
value: typing.Text
|
202
|
-
def __init__(self,
|
203
|
-
*,
|
204
|
-
key: typing.Text = ...,
|
205
|
-
value: typing.Text = ...,
|
206
|
-
) -> None: ...
|
207
|
-
def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ...
|
208
|
-
|
209
|
-
AUTH_TOKENS_FIELD_NUMBER: builtins.int
|
210
|
-
@property
|
211
|
-
def auth_tokens(self) -> google.protobuf.internal.containers.ScalarMap[typing.Text, typing.Text]: ...
|
180
|
+
ACCESS_TOKEN_FIELD_NUMBER: builtins.int
|
181
|
+
REFRESH_TOKEN_FIELD_NUMBER: builtins.int
|
182
|
+
access_token: typing.Text
|
183
|
+
refresh_token: typing.Text
|
212
184
|
def __init__(self,
|
213
185
|
*,
|
214
|
-
|
186
|
+
access_token: typing.Text = ...,
|
187
|
+
refresh_token: typing.Text = ...,
|
215
188
|
) -> None: ...
|
216
|
-
def ClearField(self, field_name: typing_extensions.Literal["
|
189
|
+
def ClearField(self, field_name: typing_extensions.Literal["access_token",b"access_token","refresh_token",b"refresh_token"]) -> None: ...
|
217
190
|
global___GetAuthTokensResponse = GetAuthTokensResponse
|
218
191
|
|
219
192
|
class StopRunRequest(google.protobuf.message.Message):
|
flwr/server/app.py
CHANGED
@@ -263,11 +263,10 @@ def run_superlink() -> None:
|
|
263
263
|
# Obtain certificates
|
264
264
|
certificates = try_obtain_server_certificates(args, args.fleet_api_type)
|
265
265
|
|
266
|
-
user_auth_config = _try_obtain_user_auth_config(args)
|
267
266
|
auth_plugin: Optional[ExecAuthPlugin] = None
|
268
|
-
#
|
269
|
-
if
|
270
|
-
auth_plugin = _try_obtain_exec_auth_plugin(
|
267
|
+
# Load the auth plugin if the args.user_auth_config is provided
|
268
|
+
if cfg_path := getattr(args, "user_auth_config", None):
|
269
|
+
auth_plugin = _try_obtain_exec_auth_plugin(Path(cfg_path))
|
271
270
|
|
272
271
|
# Initialize StateFactory
|
273
272
|
state_factory = LinkStateFactory(args.database)
|
@@ -584,21 +583,20 @@ def _try_setup_node_authentication(
|
|
584
583
|
)
|
585
584
|
|
586
585
|
|
587
|
-
def
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
return config
|
592
|
-
return None
|
586
|
+
def _try_obtain_exec_auth_plugin(config_path: Path) -> Optional[ExecAuthPlugin]:
|
587
|
+
# Load YAML file
|
588
|
+
with config_path.open("r", encoding="utf-8") as file:
|
589
|
+
config: dict[str, Any] = yaml.safe_load(file)
|
593
590
|
|
594
|
-
|
595
|
-
def _try_obtain_exec_auth_plugin(config: dict[str, Any]) -> Optional[ExecAuthPlugin]:
|
591
|
+
# Load authentication configuration
|
596
592
|
auth_config: dict[str, Any] = config.get("authentication", {})
|
597
593
|
auth_type: str = auth_config.get(AUTH_TYPE, "")
|
594
|
+
|
595
|
+
# Load authentication plugin
|
598
596
|
try:
|
599
597
|
all_plugins: dict[str, type[ExecAuthPlugin]] = get_exec_auth_plugins()
|
600
598
|
auth_plugin_class = all_plugins[auth_type]
|
601
|
-
return auth_plugin_class(
|
599
|
+
return auth_plugin_class(user_auth_config_path=config_path)
|
602
600
|
except KeyError:
|
603
601
|
if auth_type != "":
|
604
602
|
sys.exit(
|
@@ -982,17 +982,16 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
982
982
|
"""Acknowledge a ping received from a node, serving as a heartbeat."""
|
983
983
|
sint64_node_id = convert_uint64_to_sint64(node_id)
|
984
984
|
|
985
|
-
#
|
986
|
-
query = "
|
987
|
-
|
988
|
-
self.query(
|
989
|
-
query, (time.time() + ping_interval, ping_interval, sint64_node_id)
|
990
|
-
)
|
991
|
-
return True
|
992
|
-
except sqlite3.IntegrityError:
|
993
|
-
log(ERROR, "`node_id` does not exist.")
|
985
|
+
# Check if the node exists in the `node` table
|
986
|
+
query = "SELECT 1 FROM node WHERE node_id = ?"
|
987
|
+
if not self.query(query, (sint64_node_id,)):
|
994
988
|
return False
|
995
989
|
|
990
|
+
# Update `online_until` and `ping_interval` for the given `node_id`
|
991
|
+
query = "UPDATE node SET online_until = ?, ping_interval = ? WHERE node_id = ?"
|
992
|
+
self.query(query, (time.time() + ping_interval, ping_interval, sint64_node_id))
|
993
|
+
return True
|
994
|
+
|
996
995
|
def get_serverapp_context(self, run_id: int) -> Optional[Context]:
|
997
996
|
"""Get the context for the specified `run_id`."""
|
998
997
|
# Retrieve context if any
|
flwr/superexec/exec_servicer.py
CHANGED
@@ -181,8 +181,20 @@ class ExecServicer(exec_pb2_grpc.ExecServicer):
|
|
181
181
|
"ExecServicer initialized without user authentication",
|
182
182
|
)
|
183
183
|
raise grpc.RpcError() # This line is unreachable
|
184
|
+
|
185
|
+
# Get login details
|
186
|
+
details = self.auth_plugin.get_login_details()
|
187
|
+
|
188
|
+
# Return empty response if details is None
|
189
|
+
if details is None:
|
190
|
+
return GetLoginDetailsResponse()
|
191
|
+
|
184
192
|
return GetLoginDetailsResponse(
|
185
|
-
|
193
|
+
auth_type=details.auth_type,
|
194
|
+
device_code=details.device_code,
|
195
|
+
verification_uri_complete=details.verification_uri_complete,
|
196
|
+
expires_in=details.expires_in,
|
197
|
+
interval=details.interval,
|
186
198
|
)
|
187
199
|
|
188
200
|
def GetAuthTokens(
|
@@ -196,8 +208,17 @@ class ExecServicer(exec_pb2_grpc.ExecServicer):
|
|
196
208
|
"ExecServicer initialized without user authentication",
|
197
209
|
)
|
198
210
|
raise grpc.RpcError() # This line is unreachable
|
211
|
+
|
212
|
+
# Get auth tokens
|
213
|
+
credentials = self.auth_plugin.get_auth_tokens(request.device_code)
|
214
|
+
|
215
|
+
# Return empty response if credentials is None
|
216
|
+
if credentials is None:
|
217
|
+
return GetAuthTokensResponse()
|
218
|
+
|
199
219
|
return GetAuthTokensResponse(
|
200
|
-
|
220
|
+
access_token=credentials.access_token,
|
221
|
+
refresh_token=credentials.refresh_token,
|
201
222
|
)
|
202
223
|
|
203
224
|
|
{flwr_nightly-1.15.0.dev20250107.dist-info → flwr_nightly-1.15.0.dev20250108.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: flwr-nightly
|
3
|
-
Version: 1.15.0.
|
3
|
+
Version: 1.15.0.dev20250108
|
4
4
|
Summary: Flower: A Friendly Federated AI Framework
|
5
5
|
Home-page: https://flower.ai
|
6
6
|
License: Apache-2.0
|
@@ -43,11 +43,11 @@ Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
|
|
43
43
|
Requires-Dist: ray (==2.10.0) ; (python_version >= "3.9" and python_version < "3.12") and (extra == "simulation")
|
44
44
|
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
45
45
|
Requires-Dist: rich (>=13.5.0,<14.0.0)
|
46
|
-
Requires-Dist: starlette (>=0.
|
46
|
+
Requires-Dist: starlette (>=0.45.2,<0.46.0) ; extra == "rest"
|
47
47
|
Requires-Dist: tomli (>=2.0.1,<3.0.0)
|
48
48
|
Requires-Dist: tomli-w (>=1.0.0,<2.0.0)
|
49
49
|
Requires-Dist: typer (>=0.12.5,<0.13.0)
|
50
|
-
Requires-Dist: uvicorn[standard] (>=0.
|
50
|
+
Requires-Dist: uvicorn[standard] (>=0.34.0,<0.35.0) ; extra == "rest"
|
51
51
|
Project-URL: Documentation, https://flower.ai
|
52
52
|
Project-URL: Repository, https://github.com/adap/flower
|
53
53
|
Description-Content-Type: text/markdown
|
{flwr_nightly-1.15.0.dev20250107.dist-info → flwr_nightly-1.15.0.dev20250108.dist-info}/RECORD
RENAMED
@@ -2,13 +2,13 @@ flwr/__init__.py,sha256=VmBWedrCxqmt4QvUHBLqyVEH6p7zaFMD_oCHerXHSVw,937
|
|
2
2
|
flwr/cli/__init__.py,sha256=cZJVgozlkC6Ni2Hd_FAIrqefrkCGOV18fikToq-6iLw,720
|
3
3
|
flwr/cli/app.py,sha256=UeXrW5gxrUnFViDjAMIxGNZZKwu3a1oAj83v53IWIWM,1382
|
4
4
|
flwr/cli/build.py,sha256=4P70i_FnUs0P21aTwjTXtFQSAfY-C04hUDF-2npfJdo,6345
|
5
|
-
flwr/cli/cli_user_auth_interceptor.py,sha256=
|
5
|
+
flwr/cli/cli_user_auth_interceptor.py,sha256=aZepPA298s-HjGmkJGMvI_uZe72O5aLC3jri-ilG53o,3126
|
6
6
|
flwr/cli/config_utils.py,sha256=I4_EMv2f68mfrL_QuOYoAG--yDfKisE7tGiIg09G2YQ,12079
|
7
7
|
flwr/cli/example.py,sha256=uk5CoD0ZITgpY_ffsTbEKf8XOOCSUzByjHPcMSPqV18,2216
|
8
8
|
flwr/cli/install.py,sha256=0AD0qJD79SKgBnWOQlphcubfr4zHk8jTpFgwZbJBI_g,8180
|
9
9
|
flwr/cli/log.py,sha256=O7MBpsJp114PIZb-7Cru-KM6fqyneFQkqoQbQsqQmZU,6121
|
10
10
|
flwr/cli/login/__init__.py,sha256=6_9zOzbPOAH72K2wX3-9dXTAbS7Mjpa5sEn2lA6eHHI,800
|
11
|
-
flwr/cli/login/login.py,sha256=
|
11
|
+
flwr/cli/login/login.py,sha256=VaBPQBdLYmSfxXEJWVyu8U5dXztQgIv6rfTJkvz3zV8,3025
|
12
12
|
flwr/cli/ls.py,sha256=K_3Bt2RfETw4V7J4qgo8_Wx-Y_bWZqttuO879Ppxo5Y,11056
|
13
13
|
flwr/cli/new/__init__.py,sha256=pOQtPT9W4kCIttcKne5m-FtJbvTqdjTVJxzQ9AUYK8I,790
|
14
14
|
flwr/cli/new/new.py,sha256=scyyKt8mzkc3El1bypgkHjKwVQEc2-q4I50PxriPFdI,9922
|
@@ -67,7 +67,7 @@ flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl,sha256=r0SZnvoR5a5mEWKJ
|
|
67
67
|
flwr/cli/run/__init__.py,sha256=cCsKVB0SFzh2b3QmGba6BHckB85xlhjh3mh4pBpACtY,790
|
68
68
|
flwr/cli/run/run.py,sha256=BvpjYyUvDhVMvO5cG711ihtdeSbls9p8zVAuFGETLA8,7893
|
69
69
|
flwr/cli/stop.py,sha256=1T9RNRCH8dxjmBT38hFtKAWY9Gb7RMCMCML7kex9WzE,4613
|
70
|
-
flwr/cli/utils.py,sha256=
|
70
|
+
flwr/cli/utils.py,sha256=RXozds-T7HN8yH0mMj67q-0YktdNNm83N9Ptu_pdhsc,10604
|
71
71
|
flwr/client/__init__.py,sha256=DGDoO0AEAfz-0CUFmLdyUUweAS64-07AOnmDfWUefK4,1192
|
72
72
|
flwr/client/app.py,sha256=XJWu-kPswM52oLYXaOLKr0gj87KPNRI7M0Na9oBsDK4,34784
|
73
73
|
flwr/client/client.py,sha256=8o58nd9o6ZFcMIaVYPGcV4MSjBG4H0oFgWiv8ZEO3oA,7895
|
@@ -112,9 +112,9 @@ flwr/common/__init__.py,sha256=TVaoFEJE158aui1TPZQiJCDZX4RNHRyI8I55VC80HhI,3901
|
|
112
112
|
flwr/common/address.py,sha256=9KNYE69WW_QVcyumsux3Qn1wmn4J7f13Y9nHASpvzbA,3018
|
113
113
|
flwr/common/args.py,sha256=bCvtG0hhh_hVjl9NoWsY_g7kLMIN3jCN7B883HvZ7hg,6223
|
114
114
|
flwr/common/auth_plugin/__init__.py,sha256=1Y8Oj3iB49IHDu9tvDih1J74Ygu7k85V9s2A4WORPyA,887
|
115
|
-
flwr/common/auth_plugin/auth_plugin.py,sha256=
|
115
|
+
flwr/common/auth_plugin/auth_plugin.py,sha256=p_3oDuKiHtMMLLCyEe_fuRi_g5GwRKb4HJCnBkVK74I,3840
|
116
116
|
flwr/common/config.py,sha256=vmPwtRu7JIoGCke03pJlsyrA6zTlN43flzQx-4AX1mE,8099
|
117
|
-
flwr/common/constant.py,sha256=
|
117
|
+
flwr/common/constant.py,sha256=0H9SBSnQ78ZK4KPIKCIxTQZps2jU_pea8KMX8Hw22bQ,6066
|
118
118
|
flwr/common/context.py,sha256=uJ-mnoC_8y_udEb3kAX-r8CPphNTWM72z1AlsvQEu54,2403
|
119
119
|
flwr/common/date.py,sha256=NHHpESce5wYqEwoDXf09gp9U9l_5Bmlh2BsOcwS-kDM,1554
|
120
120
|
flwr/common/differential_privacy.py,sha256=XwcJ3rWr8S8BZUocc76vLSJAXIf6OHnWkBV6-xlIRuw,6106
|
@@ -146,7 +146,7 @@ flwr/common/secure_aggregation/secaggplus_constants.py,sha256=9MF-oQh62uD7rt9VeN
|
|
146
146
|
flwr/common/secure_aggregation/secaggplus_utils.py,sha256=OgYd68YBRaHQYLc-YdExj9CSpwL58bVTaPrdHoAj2AE,3214
|
147
147
|
flwr/common/serde.py,sha256=K9ExsqcTPETESkt2HMaNtIQAIAfwmuwtJFlG-59I7Sw,31046
|
148
148
|
flwr/common/telemetry.py,sha256=APKVubU_zJNrE-M_rip6S6Fsu41DxY3tAjFWNOgTmC0,9086
|
149
|
-
flwr/common/typing.py,sha256=
|
149
|
+
flwr/common/typing.py,sha256=IMgs_7nDJWn8Eb7y16Hl4HC3imQV7_Hdla1IFs3B5u8,6382
|
150
150
|
flwr/common/version.py,sha256=aNSxLL49RKeLz8sPcZrsTEWtrAeQ0uxu6tjmfba4O60,1325
|
151
151
|
flwr/proto/__init__.py,sha256=hbY7JYakwZwCkYgCNlmHdc8rtvfoJbAZLalMdc--CGc,683
|
152
152
|
flwr/proto/clientappio_pb2.py,sha256=Y3PMv-JMaBGehpslgbvGY6l2u5vNpfCTFWu-fmAmBJ4,3703
|
@@ -157,8 +157,8 @@ flwr/proto/error_pb2.py,sha256=LarjKL90LbwkXKlhzNrDssgl4DXcvIPve8NVCXHpsKA,1084
|
|
157
157
|
flwr/proto/error_pb2.pyi,sha256=ZNH4HhJTU_KfMXlyCeg8FwU-fcUYxTqEmoJPtWtHikc,734
|
158
158
|
flwr/proto/error_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
|
159
159
|
flwr/proto/error_pb2_grpc.pyi,sha256=ff2TSiLVnG6IVQcTGzb2DIH3XRSoAvAo_RMcvbMFyc0,76
|
160
|
-
flwr/proto/exec_pb2.py,sha256=
|
161
|
-
flwr/proto/exec_pb2.pyi,sha256=
|
160
|
+
flwr/proto/exec_pb2.py,sha256=1a8nh4RyDpRLY2gC6vMSAEe6-ksj7hLonAr-pZAejqc,5664
|
161
|
+
flwr/proto/exec_pb2.pyi,sha256=2vbzq2OOYM5GI-Tug4eVM5J6xvNvSFtR8m3MsP-i-Q4,9477
|
162
162
|
flwr/proto/exec_pb2_grpc.py,sha256=-bdLqjsqQxK9R8LIiZaKlLKH2NmjR50EaGKTPPTwFhI,10445
|
163
163
|
flwr/proto/exec_pb2_grpc.pyi,sha256=M5k-FzeLWxal7zt28LJfzMWWRxmNknTC2BzHRRMa1sQ,2914
|
164
164
|
flwr/proto/fab_pb2.py,sha256=-gfW_ePYHx1vDGHfimwn91qEhmmY_gslaOHwqqZnVdU,1627
|
@@ -211,7 +211,7 @@ flwr/proto/transport_pb2_grpc.py,sha256=vLN3EHtx2aEEMCO4f1Upu-l27BPzd3-5pV-u8wPc
|
|
211
211
|
flwr/proto/transport_pb2_grpc.pyi,sha256=AGXf8RiIiW2J5IKMlm_3qT3AzcDa4F3P5IqUjve_esA,766
|
212
212
|
flwr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
213
213
|
flwr/server/__init__.py,sha256=cEg1oecBu4cKB69iJCqWEylC8b5XW47bl7rQiJsdTvM,1528
|
214
|
-
flwr/server/app.py,sha256=
|
214
|
+
flwr/server/app.py,sha256=xXiRsHXypzMW0EI1ewiiGE0dk6296I9d95ae1d0MKYU,30860
|
215
215
|
flwr/server/client_manager.py,sha256=7Ese0tgrH-i-ms363feYZJKwB8gWnXSmg_hYF2Bju4U,6227
|
216
216
|
flwr/server/client_proxy.py,sha256=4G-oTwhb45sfWLx2uZdcXD98IZwdTS6F88xe3akCdUg,2399
|
217
217
|
flwr/server/compat/__init__.py,sha256=VxnJtJyOjNFQXMNi9hIuzNlZM5n0Hj1p3aq_Pm2udw4,892
|
@@ -288,7 +288,7 @@ flwr/server/superlink/linkstate/__init__.py,sha256=v-2JyJlCB3qyhMNwMjmcNVOq4rkoo
|
|
288
288
|
flwr/server/superlink/linkstate/in_memory_linkstate.py,sha256=SR6a0wb-xFVQmPEsNseT91jmBeN0Lh1m_lZ6nY6aNS0,21984
|
289
289
|
flwr/server/superlink/linkstate/linkstate.py,sha256=ayQY5eb-2InSldQUnVcx5ABjPU4QhQRV2lEVPVM_818,13114
|
290
290
|
flwr/server/superlink/linkstate/linkstate_factory.py,sha256=ISSMjDlwuN7swxjOeYlTNpI_kuZ8PGkMcJnf1dbhUSE,2069
|
291
|
-
flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=
|
291
|
+
flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=yellTrzUics7A8Y5YKRVVLRMDMMGhudeE-s4dM1ONkY,42900
|
292
292
|
flwr/server/superlink/linkstate/utils.py,sha256=d5uqqIOCKfd54X8CFNfUr3AWqPLpgmzsC_RagRwFugM,13321
|
293
293
|
flwr/server/superlink/simulation/__init__.py,sha256=mg-oapC9dkzEfjXPQFior5lpWj4g9kwbLovptyYM_g0,718
|
294
294
|
flwr/server/superlink/simulation/simulationio_grpc.py,sha256=5wflYW_TS0mjmPG6OYuHMJwXD2_cYmUNhFkdOU0jMWQ,2237
|
@@ -317,12 +317,12 @@ flwr/superexec/__init__.py,sha256=fcj366jh4RFby_vDwLroU4kepzqbnJgseZD_jUr_Mko,71
|
|
317
317
|
flwr/superexec/app.py,sha256=Z6kYHWd62YL0Q4YKyCAbt_BcefNfbKH6V-jCC-1NkZM,1842
|
318
318
|
flwr/superexec/deployment.py,sha256=wZ9G42gGS91knfplswh95MnQ83Fzu-rs6wcuNgDmmvY,6735
|
319
319
|
flwr/superexec/exec_grpc.py,sha256=XD94kqzigQ9tLB3hU-jVgMAS_BmlK80Z5rQ_9M6b7aY,2897
|
320
|
-
flwr/superexec/exec_servicer.py,sha256=
|
320
|
+
flwr/superexec/exec_servicer.py,sha256=X10ILT-AoGMrB3IgI2mBe9i-QcIVUAl9bucuqVOPYkU,8341
|
321
321
|
flwr/superexec/exec_user_auth_interceptor.py,sha256=K06OU-l4LnYhTDg071hGJuOaQWEJbZsYi5qxUmmtiG0,3704
|
322
322
|
flwr/superexec/executor.py,sha256=_B55WW2TD1fBINpabSSDRenVHXYmvlfhv-k8hJKU4lQ,3115
|
323
323
|
flwr/superexec/simulation.py,sha256=WQDon15oqpMopAZnwRZoTICYCfHqtkvFSqiTQ2hLD_g,4088
|
324
|
-
flwr_nightly-1.15.0.
|
325
|
-
flwr_nightly-1.15.0.
|
326
|
-
flwr_nightly-1.15.0.
|
327
|
-
flwr_nightly-1.15.0.
|
328
|
-
flwr_nightly-1.15.0.
|
324
|
+
flwr_nightly-1.15.0.dev20250108.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
325
|
+
flwr_nightly-1.15.0.dev20250108.dist-info/METADATA,sha256=N34sl2KG1HTyopOraXZOl5iqeqjVlL_eOFOMfJGjWu4,15810
|
326
|
+
flwr_nightly-1.15.0.dev20250108.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
327
|
+
flwr_nightly-1.15.0.dev20250108.dist-info/entry_points.txt,sha256=JlNxX3qhaV18_2yj5a3kJW1ESxm31cal9iS_N_pf1Rk,538
|
328
|
+
flwr_nightly-1.15.0.dev20250108.dist-info/RECORD,,
|
{flwr_nightly-1.15.0.dev20250107.dist-info → flwr_nightly-1.15.0.dev20250108.dist-info}/LICENSE
RENAMED
File without changes
|
{flwr_nightly-1.15.0.dev20250107.dist-info → flwr_nightly-1.15.0.dev20250108.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|