flwr-nightly 1.14.0.dev20241204__py3-none-any.whl → 1.14.0.dev20241214__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.

Potentially problematic release.


This version of flwr-nightly might be problematic. Click here for more details.

Files changed (100) hide show
  1. flwr/cli/app.py +5 -0
  2. flwr/cli/build.py +1 -0
  3. flwr/cli/cli_user_auth_interceptor.py +86 -0
  4. flwr/cli/config_utils.py +19 -2
  5. flwr/cli/example.py +1 -0
  6. flwr/cli/install.py +1 -0
  7. flwr/cli/log.py +11 -31
  8. flwr/cli/login/__init__.py +22 -0
  9. flwr/cli/login/login.py +83 -0
  10. flwr/cli/ls.py +10 -40
  11. flwr/cli/new/__init__.py +1 -0
  12. flwr/cli/new/new.py +2 -1
  13. flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +2 -2
  14. flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +1 -2
  15. flwr/cli/run/__init__.py +1 -0
  16. flwr/cli/run/run.py +15 -25
  17. flwr/cli/stop.py +91 -0
  18. flwr/cli/utils.py +109 -1
  19. flwr/client/app.py +3 -2
  20. flwr/client/client.py +1 -0
  21. flwr/client/clientapp/app.py +1 -0
  22. flwr/client/clientapp/utils.py +1 -0
  23. flwr/client/grpc_adapter_client/connection.py +1 -1
  24. flwr/client/grpc_client/connection.py +1 -1
  25. flwr/client/grpc_rere_client/connection.py +3 -3
  26. flwr/client/message_handler/message_handler.py +1 -0
  27. flwr/client/mod/comms_mods.py +1 -0
  28. flwr/client/mod/localdp_mod.py +1 -1
  29. flwr/client/nodestate/__init__.py +1 -0
  30. flwr/client/nodestate/nodestate.py +1 -0
  31. flwr/client/nodestate/nodestate_factory.py +1 -0
  32. flwr/client/rest_client/connection.py +3 -3
  33. flwr/client/supernode/app.py +1 -0
  34. flwr/common/address.py +1 -0
  35. flwr/common/args.py +1 -0
  36. flwr/common/auth_plugin/__init__.py +24 -0
  37. flwr/common/auth_plugin/auth_plugin.py +111 -0
  38. flwr/common/config.py +3 -1
  39. flwr/common/constant.py +6 -1
  40. flwr/common/logger.py +1 -0
  41. flwr/common/message.py +1 -0
  42. flwr/common/object_ref.py +57 -54
  43. flwr/common/pyproject.py +1 -0
  44. flwr/common/record/__init__.py +1 -0
  45. flwr/common/record/parametersrecord.py +1 -0
  46. flwr/common/retry_invoker.py +75 -0
  47. flwr/common/secure_aggregation/secaggplus_utils.py +2 -2
  48. flwr/common/telemetry.py +2 -1
  49. flwr/common/typing.py +12 -0
  50. flwr/common/version.py +1 -0
  51. flwr/proto/exec_pb2.py +27 -3
  52. flwr/proto/exec_pb2.pyi +103 -0
  53. flwr/proto/exec_pb2_grpc.py +102 -0
  54. flwr/proto/exec_pb2_grpc.pyi +39 -0
  55. flwr/proto/fab_pb2.py +4 -4
  56. flwr/proto/fab_pb2.pyi +4 -1
  57. flwr/proto/serverappio_pb2.py +18 -18
  58. flwr/proto/serverappio_pb2.pyi +8 -2
  59. flwr/proto/serverappio_pb2_grpc.py +34 -0
  60. flwr/proto/serverappio_pb2_grpc.pyi +13 -0
  61. flwr/proto/simulationio_pb2.py +2 -2
  62. flwr/proto/simulationio_pb2_grpc.py +34 -0
  63. flwr/proto/simulationio_pb2_grpc.pyi +13 -0
  64. flwr/server/app.py +53 -1
  65. flwr/server/compat/app_utils.py +7 -1
  66. flwr/server/driver/grpc_driver.py +11 -63
  67. flwr/server/driver/inmemory_driver.py +5 -1
  68. flwr/server/serverapp/app.py +9 -2
  69. flwr/server/strategy/dpfedavg_fixed.py +1 -0
  70. flwr/server/superlink/driver/serverappio_grpc.py +1 -0
  71. flwr/server/superlink/driver/serverappio_servicer.py +72 -22
  72. flwr/server/superlink/ffs/disk_ffs.py +1 -0
  73. flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +1 -0
  74. flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +1 -0
  75. flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +32 -12
  76. flwr/server/superlink/fleet/message_handler/message_handler.py +31 -2
  77. flwr/server/superlink/fleet/rest_rere/rest_api.py +4 -1
  78. flwr/server/superlink/fleet/vce/__init__.py +1 -0
  79. flwr/server/superlink/fleet/vce/backend/__init__.py +1 -0
  80. flwr/server/superlink/fleet/vce/backend/raybackend.py +1 -0
  81. flwr/server/superlink/linkstate/in_memory_linkstate.py +14 -30
  82. flwr/server/superlink/linkstate/linkstate.py +13 -2
  83. flwr/server/superlink/linkstate/sqlite_linkstate.py +24 -44
  84. flwr/server/superlink/simulation/simulationio_servicer.py +20 -0
  85. flwr/server/superlink/utils.py +65 -0
  86. flwr/simulation/app.py +1 -0
  87. flwr/simulation/ray_transport/ray_actor.py +1 -0
  88. flwr/simulation/ray_transport/utils.py +1 -0
  89. flwr/simulation/run_simulation.py +1 -0
  90. flwr/superexec/app.py +1 -0
  91. flwr/superexec/deployment.py +1 -0
  92. flwr/superexec/exec_grpc.py +19 -1
  93. flwr/superexec/exec_servicer.py +76 -2
  94. flwr/superexec/exec_user_auth_interceptor.py +101 -0
  95. flwr/superexec/executor.py +1 -0
  96. {flwr_nightly-1.14.0.dev20241204.dist-info → flwr_nightly-1.14.0.dev20241214.dist-info}/METADATA +8 -7
  97. {flwr_nightly-1.14.0.dev20241204.dist-info → flwr_nightly-1.14.0.dev20241214.dist-info}/RECORD +100 -92
  98. {flwr_nightly-1.14.0.dev20241204.dist-info → flwr_nightly-1.14.0.dev20241214.dist-info}/LICENSE +0 -0
  99. {flwr_nightly-1.14.0.dev20241204.dist-info → flwr_nightly-1.14.0.dev20241214.dist-info}/WHEEL +0 -0
  100. {flwr_nightly-1.14.0.dev20241204.dist-info → flwr_nightly-1.14.0.dev20241214.dist-info}/entry_points.txt +0 -0
@@ -14,6 +14,7 @@
14
14
  # ==============================================================================
15
15
  """SimulationIo API servicer."""
16
16
 
17
+
17
18
  import threading
18
19
  from logging import DEBUG, INFO
19
20
 
@@ -28,6 +29,7 @@ from flwr.common.serde import (
28
29
  context_to_proto,
29
30
  fab_to_proto,
30
31
  run_status_from_proto,
32
+ run_status_to_proto,
31
33
  run_to_proto,
32
34
  )
33
35
  from flwr.common.typing import Fab, RunStatus
@@ -39,6 +41,8 @@ from flwr.proto.log_pb2 import ( # pylint: disable=E0611
39
41
  from flwr.proto.run_pb2 import ( # pylint: disable=E0611
40
42
  GetFederationOptionsRequest,
41
43
  GetFederationOptionsResponse,
44
+ GetRunStatusRequest,
45
+ GetRunStatusResponse,
42
46
  UpdateRunStatusRequest,
43
47
  UpdateRunStatusResponse,
44
48
  )
@@ -122,6 +126,22 @@ class SimulationIoServicer(simulationio_pb2_grpc.SimulationIoServicer):
122
126
  )
123
127
  return UpdateRunStatusResponse()
124
128
 
129
+ def GetRunStatus(
130
+ self, request: GetRunStatusRequest, context: ServicerContext
131
+ ) -> GetRunStatusResponse:
132
+ """Get status of requested runs."""
133
+ log(DEBUG, "SimultionIoServicer.GetRunStatus")
134
+ state = self.state_factory.state()
135
+
136
+ statuses = state.get_run_status(set(request.run_ids))
137
+
138
+ return GetRunStatusResponse(
139
+ run_status_dict={
140
+ run_id: run_status_to_proto(status)
141
+ for run_id, status in statuses.items()
142
+ }
143
+ )
144
+
125
145
  def PushLogs(
126
146
  self, request: PushLogsRequest, context: grpc.ServicerContext
127
147
  ) -> PushLogsResponse:
@@ -0,0 +1,65 @@
1
+ # Copyright 2024 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
+ """SuperLink utilities."""
16
+
17
+
18
+ from typing import Union
19
+
20
+ import grpc
21
+
22
+ from flwr.common.constant import Status, SubStatus
23
+ from flwr.common.typing import RunStatus
24
+ from flwr.server.superlink.linkstate import LinkState
25
+
26
+ _STATUS_TO_MSG = {
27
+ Status.PENDING: "Run is pending.",
28
+ Status.STARTING: "Run is starting.",
29
+ Status.RUNNING: "Run is running.",
30
+ Status.FINISHED: "Run is finished.",
31
+ }
32
+
33
+
34
+ def check_abort(
35
+ run_id: int,
36
+ abort_status_list: list[str],
37
+ state: LinkState,
38
+ ) -> Union[str, None]:
39
+ """Check if the status of the provided `run_id` is in `abort_status_list`."""
40
+ run_status: RunStatus = state.get_run_status({run_id})[run_id]
41
+
42
+ if run_status.status in abort_status_list:
43
+ msg = _STATUS_TO_MSG[run_status.status]
44
+ if run_status.sub_status == SubStatus.STOPPED:
45
+ msg += " Stopped by user."
46
+ return msg
47
+
48
+ return None
49
+
50
+
51
+ def abort_grpc_context(msg: Union[str, None], context: grpc.ServicerContext) -> None:
52
+ """Abort context with statuscode PERMISSION_DENIED if `msg` is not None."""
53
+ if msg is not None:
54
+ context.abort(grpc.StatusCode.PERMISSION_DENIED, msg)
55
+
56
+
57
+ def abort_if(
58
+ run_id: int,
59
+ abort_status_list: list[str],
60
+ state: LinkState,
61
+ context: grpc.ServicerContext,
62
+ ) -> None:
63
+ """Abort context if status of the provided `run_id` is in `abort_status_list`."""
64
+ msg = check_abort(run_id, abort_status_list, state)
65
+ abort_grpc_context(msg, context)
flwr/simulation/app.py CHANGED
@@ -14,6 +14,7 @@
14
14
  # ==============================================================================
15
15
  """Flower Simulation process."""
16
16
 
17
+
17
18
  import argparse
18
19
  import sys
19
20
  from logging import DEBUG, ERROR, INFO
@@ -14,6 +14,7 @@
14
14
  # ==============================================================================
15
15
  """Ray-based Flower Actor and ActorPool implementation."""
16
16
 
17
+
17
18
  import threading
18
19
  from abc import ABC
19
20
  from logging import DEBUG, ERROR, WARNING
@@ -14,6 +14,7 @@
14
14
  # ==============================================================================
15
15
  """Utilities for Actors in the Virtual Client Engine."""
16
16
 
17
+
17
18
  import traceback
18
19
  import warnings
19
20
  from logging import ERROR
@@ -14,6 +14,7 @@
14
14
  # ==============================================================================
15
15
  """Flower Simulation."""
16
16
 
17
+
17
18
  import argparse
18
19
  import asyncio
19
20
  import json
flwr/superexec/app.py CHANGED
@@ -14,6 +14,7 @@
14
14
  # ==============================================================================
15
15
  """Flower SuperExec app."""
16
16
 
17
+
17
18
  import argparse
18
19
  import sys
19
20
  from logging import INFO
@@ -14,6 +14,7 @@
14
14
  # ==============================================================================
15
15
  """Deployment engine executor."""
16
16
 
17
+
17
18
  import hashlib
18
19
  from logging import ERROR, INFO
19
20
  from pathlib import Path
@@ -14,18 +14,22 @@
14
14
  # ==============================================================================
15
15
  """SuperExec gRPC API."""
16
16
 
17
+
18
+ from collections.abc import Sequence
17
19
  from logging import INFO
18
20
  from typing import Optional
19
21
 
20
22
  import grpc
21
23
 
22
24
  from flwr.common import GRPC_MAX_MESSAGE_LENGTH
25
+ from flwr.common.auth_plugin import ExecAuthPlugin
23
26
  from flwr.common.logger import log
24
27
  from flwr.common.typing import UserConfig
25
28
  from flwr.proto.exec_pb2_grpc import add_ExecServicer_to_server
26
29
  from flwr.server.superlink.ffs.ffs_factory import FfsFactory
27
30
  from flwr.server.superlink.fleet.grpc_bidi.grpc_server import generic_create_grpc_server
28
31
  from flwr.server.superlink.linkstate import LinkStateFactory
32
+ from flwr.superexec.exec_user_auth_interceptor import ExecUserAuthInterceptor
29
33
 
30
34
  from .exec_servicer import ExecServicer
31
35
  from .executor import Executor
@@ -39,6 +43,7 @@ def run_exec_api_grpc(
39
43
  ffs_factory: FfsFactory,
40
44
  certificates: Optional[tuple[bytes, bytes, bytes]],
41
45
  config: UserConfig,
46
+ auth_plugin: Optional[ExecAuthPlugin] = None,
42
47
  ) -> grpc.Server:
43
48
  """Run Exec API (gRPC, request-response)."""
44
49
  executor.set_config(config)
@@ -47,16 +52,29 @@ def run_exec_api_grpc(
47
52
  linkstate_factory=state_factory,
48
53
  ffs_factory=ffs_factory,
49
54
  executor=executor,
55
+ auth_plugin=auth_plugin,
50
56
  )
57
+ interceptors: Optional[Sequence[grpc.ServerInterceptor]] = None
58
+ if auth_plugin is not None:
59
+ interceptors = [ExecUserAuthInterceptor(auth_plugin)]
51
60
  exec_add_servicer_to_server_fn = add_ExecServicer_to_server
52
61
  exec_grpc_server = generic_create_grpc_server(
53
62
  servicer_and_add_fn=(exec_servicer, exec_add_servicer_to_server_fn),
54
63
  server_address=address,
55
64
  max_message_length=GRPC_MAX_MESSAGE_LENGTH,
56
65
  certificates=certificates,
66
+ interceptors=interceptors,
57
67
  )
58
68
 
59
- log(INFO, "Flower Deployment Engine: Starting Exec API on %s", address)
69
+ if auth_plugin is None:
70
+ log(INFO, "Flower Deployment Engine: Starting Exec API on %s", address)
71
+ else:
72
+ log(
73
+ INFO,
74
+ "Flower Deployment Engine: Starting Exec API with user "
75
+ "authentication on %s",
76
+ address,
77
+ )
60
78
  exec_grpc_server.start()
61
79
 
62
80
  return exec_grpc_server
@@ -18,24 +18,33 @@
18
18
  import time
19
19
  from collections.abc import Generator
20
20
  from logging import ERROR, INFO
21
- from typing import Any
21
+ from typing import Any, Optional
22
+ from uuid import UUID
22
23
 
23
24
  import grpc
24
25
 
25
26
  from flwr.common import now
26
- from flwr.common.constant import LOG_STREAM_INTERVAL, Status
27
+ from flwr.common.auth_plugin import ExecAuthPlugin
28
+ from flwr.common.constant import LOG_STREAM_INTERVAL, Status, SubStatus
27
29
  from flwr.common.logger import log
28
30
  from flwr.common.serde import (
29
31
  configs_record_from_proto,
30
32
  run_to_proto,
31
33
  user_config_from_proto,
32
34
  )
35
+ from flwr.common.typing import RunStatus
33
36
  from flwr.proto import exec_pb2_grpc # pylint: disable=E0611
34
37
  from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
38
+ GetAuthTokensRequest,
39
+ GetAuthTokensResponse,
40
+ GetLoginDetailsRequest,
41
+ GetLoginDetailsResponse,
35
42
  ListRunsRequest,
36
43
  ListRunsResponse,
37
44
  StartRunRequest,
38
45
  StartRunResponse,
46
+ StopRunRequest,
47
+ StopRunResponse,
39
48
  StreamLogsRequest,
40
49
  StreamLogsResponse,
41
50
  )
@@ -53,11 +62,13 @@ class ExecServicer(exec_pb2_grpc.ExecServicer):
53
62
  linkstate_factory: LinkStateFactory,
54
63
  ffs_factory: FfsFactory,
55
64
  executor: Executor,
65
+ auth_plugin: Optional[ExecAuthPlugin] = None,
56
66
  ) -> None:
57
67
  self.linkstate_factory = linkstate_factory
58
68
  self.ffs_factory = ffs_factory
59
69
  self.executor = executor
60
70
  self.executor.initialize(linkstate_factory, ffs_factory)
71
+ self.auth_plugin = auth_plugin
61
72
 
62
73
  def StartRun(
63
74
  self, request: StartRunRequest, context: grpc.ServicerContext
@@ -126,6 +137,69 @@ class ExecServicer(exec_pb2_grpc.ExecServicer):
126
137
  # Handle `flwr ls --run-id <run_id>`
127
138
  return _create_list_runs_response({request.run_id}, state)
128
139
 
140
+ def StopRun(
141
+ self, request: StopRunRequest, context: grpc.ServicerContext
142
+ ) -> StopRunResponse:
143
+ """Stop a given run ID."""
144
+ log(INFO, "ExecServicer.StopRun")
145
+ state = self.linkstate_factory.state()
146
+
147
+ # Exit if `run_id` not found
148
+ if not state.get_run(request.run_id):
149
+ context.abort(
150
+ grpc.StatusCode.NOT_FOUND, f"Run ID {request.run_id} not found"
151
+ )
152
+
153
+ run_status = state.get_run_status({request.run_id})[request.run_id]
154
+ if run_status.status == Status.FINISHED:
155
+ context.abort(
156
+ grpc.StatusCode.FAILED_PRECONDITION,
157
+ f"Run ID {request.run_id} is already finished",
158
+ )
159
+
160
+ update_success = state.update_run_status(
161
+ run_id=request.run_id,
162
+ new_status=RunStatus(Status.FINISHED, SubStatus.STOPPED, ""),
163
+ )
164
+
165
+ if update_success:
166
+ task_ids: set[UUID] = state.get_task_ids_from_run_id(request.run_id)
167
+
168
+ # Delete TaskIns and TaskRes for the `run_id`
169
+ state.delete_tasks(task_ids)
170
+
171
+ return StopRunResponse(success=update_success)
172
+
173
+ def GetLoginDetails(
174
+ self, request: GetLoginDetailsRequest, context: grpc.ServicerContext
175
+ ) -> GetLoginDetailsResponse:
176
+ """Start login."""
177
+ log(INFO, "ExecServicer.GetLoginDetails")
178
+ if self.auth_plugin is None:
179
+ context.abort(
180
+ grpc.StatusCode.UNIMPLEMENTED,
181
+ "ExecServicer initialized without user authentication",
182
+ )
183
+ raise grpc.RpcError() # This line is unreachable
184
+ return GetLoginDetailsResponse(
185
+ login_details=self.auth_plugin.get_login_details()
186
+ )
187
+
188
+ def GetAuthTokens(
189
+ self, request: GetAuthTokensRequest, context: grpc.ServicerContext
190
+ ) -> GetAuthTokensResponse:
191
+ """Get auth token."""
192
+ log(INFO, "ExecServicer.GetAuthTokens")
193
+ if self.auth_plugin is None:
194
+ context.abort(
195
+ grpc.StatusCode.UNIMPLEMENTED,
196
+ "ExecServicer initialized without user authentication",
197
+ )
198
+ raise grpc.RpcError() # This line is unreachable
199
+ return GetAuthTokensResponse(
200
+ auth_tokens=self.auth_plugin.get_auth_tokens(dict(request.auth_details))
201
+ )
202
+
129
203
 
130
204
  def _create_list_runs_response(run_ids: set[int], state: LinkState) -> ListRunsResponse:
131
205
  """Create response for `flwr ls --runs` and `flwr ls --run-id <run_id>`."""
@@ -0,0 +1,101 @@
1
+ # Copyright 2024 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 interceptor."""
16
+
17
+
18
+ from typing import Any, Callable, Union
19
+
20
+ import grpc
21
+
22
+ from flwr.common.auth_plugin import ExecAuthPlugin
23
+ from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
24
+ GetAuthTokensRequest,
25
+ GetAuthTokensResponse,
26
+ GetLoginDetailsRequest,
27
+ GetLoginDetailsResponse,
28
+ StartRunRequest,
29
+ StartRunResponse,
30
+ StreamLogsRequest,
31
+ StreamLogsResponse,
32
+ )
33
+
34
+ Request = Union[
35
+ StartRunRequest,
36
+ StreamLogsRequest,
37
+ GetLoginDetailsRequest,
38
+ GetAuthTokensRequest,
39
+ ]
40
+
41
+ Response = Union[
42
+ StartRunResponse, StreamLogsResponse, GetLoginDetailsResponse, GetAuthTokensResponse
43
+ ]
44
+
45
+
46
+ class ExecUserAuthInterceptor(grpc.ServerInterceptor): # type: ignore
47
+ """Exec API interceptor for user authentication."""
48
+
49
+ def __init__(
50
+ self,
51
+ auth_plugin: ExecAuthPlugin,
52
+ ):
53
+ self.auth_plugin = auth_plugin
54
+
55
+ def intercept_service(
56
+ self,
57
+ continuation: Callable[[Any], Any],
58
+ handler_call_details: grpc.HandlerCallDetails,
59
+ ) -> grpc.RpcMethodHandler:
60
+ """Flower server interceptor authentication logic.
61
+
62
+ Intercept all unary-unary/unary-stream calls from users and authenticate users
63
+ by validating auth metadata sent by the user. Continue RPC call if user is
64
+ authenticated, else, terminate RPC call by setting context to abort.
65
+ """
66
+ # One of the method handlers in
67
+ # `flwr.superexec.exec_servicer.ExecServicer`
68
+ method_handler: grpc.RpcMethodHandler = continuation(handler_call_details)
69
+ return self._generic_auth_unary_method_handler(method_handler)
70
+
71
+ def _generic_auth_unary_method_handler(
72
+ self, method_handler: grpc.RpcMethodHandler
73
+ ) -> grpc.RpcMethodHandler:
74
+ def _generic_method_handler(
75
+ request: Request,
76
+ context: grpc.ServicerContext,
77
+ ) -> Response:
78
+ call = method_handler.unary_unary or method_handler.unary_stream
79
+ metadata = context.invocation_metadata()
80
+ if isinstance(
81
+ request, (GetLoginDetailsRequest, GetAuthTokensRequest)
82
+ ) or self.auth_plugin.validate_tokens_in_metadata(metadata):
83
+ return call(request, context) # type: ignore
84
+
85
+ tokens = self.auth_plugin.refresh_tokens(context.invocation_metadata())
86
+ if tokens is not None:
87
+ context.send_initial_metadata(tokens)
88
+ return call(request, context) # type: ignore
89
+
90
+ context.abort(grpc.StatusCode.UNAUTHENTICATED, "Access denied")
91
+ raise grpc.RpcError() # This line is unreachable
92
+
93
+ if method_handler.unary_unary:
94
+ message_handler = grpc.unary_unary_rpc_method_handler
95
+ else:
96
+ message_handler = grpc.unary_stream_rpc_method_handler
97
+ return message_handler(
98
+ _generic_method_handler,
99
+ request_deserializer=method_handler.request_deserializer,
100
+ response_serializer=method_handler.response_serializer,
101
+ )
@@ -14,6 +14,7 @@
14
14
  # ==============================================================================
15
15
  """Execute and monitor a Flower run."""
16
16
 
17
+
17
18
  from abc import ABC, abstractmethod
18
19
  from dataclasses import dataclass, field
19
20
  from subprocess import Popen
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr-nightly
3
- Version: 1.14.0.dev20241204
3
+ Version: 1.14.0.dev20241214
4
4
  Summary: Flower: A Friendly Federated AI Framework
5
5
  Home-page: https://flower.ai
6
6
  License: Apache-2.0
@@ -39,8 +39,9 @@ Requires-Dist: numpy (>=1.26.0,<3.0.0)
39
39
  Requires-Dist: pathspec (>=0.12.1,<0.13.0)
40
40
  Requires-Dist: protobuf (>=4.25.2,<5.0.0)
41
41
  Requires-Dist: pycryptodome (>=3.18.0,<4.0.0)
42
+ Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
42
43
  Requires-Dist: ray (==2.10.0) ; (python_version >= "3.9" and python_version < "3.12") and (extra == "simulation")
43
- Requires-Dist: requests (>=2.31.0,<3.0.0) ; extra == "rest"
44
+ Requires-Dist: requests (>=2.31.0,<3.0.0)
44
45
  Requires-Dist: rich (>=13.5.0,<14.0.0)
45
46
  Requires-Dist: starlette (>=0.31.0,<0.32.0) ; extra == "rest"
46
47
  Requires-Dist: tomli (>=2.0.1,<3.0.0)
@@ -101,23 +102,23 @@ Flower's goal is to make federated learning accessible to everyone. This series
101
102
 
102
103
  0. **What is Federated Learning?**
103
104
 
104
- [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/doc/source/tutorial-series-what-is-federated-learning.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/doc/source/tutorial-series-what-is-federated-learning.ipynb))
105
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-what-is-federated-learning.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-what-is-federated-learning.ipynb))
105
106
 
106
107
  1. **An Introduction to Federated Learning**
107
108
 
108
- [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/doc/source/tutorial-series-get-started-with-flower-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/doc/source/tutorial-series-get-started-with-flower-pytorch.ipynb))
109
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-get-started-with-flower-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-get-started-with-flower-pytorch.ipynb))
109
110
 
110
111
  2. **Using Strategies in Federated Learning**
111
112
 
112
- [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/doc/source/tutorial-series-use-a-federated-learning-strategy-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/doc/source/tutorial-series-use-a-federated-learning-strategy-pytorch.ipynb))
113
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-use-a-federated-learning-strategy-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-use-a-federated-learning-strategy-pytorch.ipynb))
113
114
 
114
115
  3. **Building Strategies for Federated Learning**
115
116
 
116
- [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/doc/source/tutorial-series-build-a-strategy-from-scratch-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/doc/source/tutorial-series-build-a-strategy-from-scratch-pytorch.ipynb))
117
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-build-a-strategy-from-scratch-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-build-a-strategy-from-scratch-pytorch.ipynb))
117
118
 
118
119
  4. **Custom Clients for Federated Learning**
119
120
 
120
- [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/doc/source/tutorial-series-customize-the-client-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/doc/source/tutorial-series-customize-the-client-pytorch.ipynb))
121
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/doc/source/tutorial-series-customize-the-client-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-customize-the-client-pytorch.ipynb))
121
122
 
122
123
  Stay tuned, more tutorials are coming soon. Topics include **Privacy and Security in Federated Learning**, and **Scaling Federated Learning**.
123
124