flwr-nightly 1.14.0.dev20241216__py3-none-any.whl → 1.15.0.dev20250112__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.
Files changed (60) hide show
  1. flwr/cli/cli_user_auth_interceptor.py +6 -2
  2. flwr/cli/log.py +8 -6
  3. flwr/cli/login/login.py +11 -4
  4. flwr/cli/ls.py +7 -4
  5. flwr/cli/new/templates/app/.gitignore.tpl +3 -0
  6. flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +1 -1
  7. flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +1 -1
  8. flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +1 -1
  9. flwr/cli/new/templates/app/pyproject.jax.toml.tpl +1 -1
  10. flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +1 -1
  11. flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +1 -1
  12. flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +3 -3
  13. flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +1 -1
  14. flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +1 -1
  15. flwr/cli/run/run.py +7 -2
  16. flwr/cli/stop.py +3 -2
  17. flwr/cli/utils.py +83 -14
  18. flwr/client/app.py +17 -9
  19. flwr/client/client.py +0 -32
  20. flwr/client/grpc_rere_client/client_interceptor.py +6 -0
  21. flwr/client/grpc_rere_client/grpc_adapter.py +16 -0
  22. flwr/client/message_handler/message_handler.py +0 -2
  23. flwr/client/numpy_client.py +0 -44
  24. flwr/client/supernode/app.py +1 -2
  25. flwr/common/auth_plugin/auth_plugin.py +33 -23
  26. flwr/common/constant.py +2 -0
  27. flwr/common/grpc.py +154 -3
  28. flwr/common/record/recordset.py +1 -1
  29. flwr/common/secure_aggregation/crypto/symmetric_encryption.py +45 -0
  30. flwr/common/telemetry.py +13 -3
  31. flwr/common/typing.py +20 -0
  32. flwr/proto/exec_pb2.py +12 -24
  33. flwr/proto/exec_pb2.pyi +27 -54
  34. flwr/proto/fleet_pb2.py +40 -27
  35. flwr/proto/fleet_pb2.pyi +84 -0
  36. flwr/proto/fleet_pb2_grpc.py +66 -0
  37. flwr/proto/fleet_pb2_grpc.pyi +20 -0
  38. flwr/server/app.py +54 -33
  39. flwr/server/run_serverapp.py +8 -9
  40. flwr/server/serverapp/app.py +17 -2
  41. flwr/server/superlink/driver/serverappio_grpc.py +1 -1
  42. flwr/server/superlink/driver/serverappio_servicer.py +29 -6
  43. flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +2 -165
  44. flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +16 -0
  45. flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +2 -1
  46. flwr/server/superlink/fleet/vce/vce_api.py +2 -2
  47. flwr/server/superlink/linkstate/in_memory_linkstate.py +36 -24
  48. flwr/server/superlink/linkstate/linkstate.py +14 -4
  49. flwr/server/superlink/linkstate/sqlite_linkstate.py +56 -31
  50. flwr/server/superlink/simulation/simulationio_grpc.py +1 -1
  51. flwr/server/superlink/simulation/simulationio_servicer.py +13 -0
  52. flwr/simulation/app.py +15 -4
  53. flwr/simulation/run_simulation.py +35 -7
  54. flwr/superexec/exec_grpc.py +1 -1
  55. flwr/superexec/exec_servicer.py +23 -2
  56. {flwr_nightly-1.14.0.dev20241216.dist-info → flwr_nightly-1.15.0.dev20250112.dist-info}/METADATA +5 -5
  57. {flwr_nightly-1.14.0.dev20241216.dist-info → flwr_nightly-1.15.0.dev20250112.dist-info}/RECORD +60 -60
  58. {flwr_nightly-1.14.0.dev20241216.dist-info → flwr_nightly-1.15.0.dev20250112.dist-info}/LICENSE +0 -0
  59. {flwr_nightly-1.14.0.dev20241216.dist-info → flwr_nightly-1.15.0.dev20250112.dist-info}/WHEEL +0 -0
  60. {flwr_nightly-1.14.0.dev20241216.dist-info → flwr_nightly-1.15.0.dev20250112.dist-info}/entry_points.txt +0 -0
@@ -21,13 +21,11 @@ from typing import Callable
21
21
  from flwr.client.client import Client
22
22
  from flwr.common import (
23
23
  Config,
24
- Context,
25
24
  NDArrays,
26
25
  Scalar,
27
26
  ndarrays_to_parameters,
28
27
  parameters_to_ndarrays,
29
28
  )
30
- from flwr.common.logger import warn_deprecated_feature_with_example
31
29
  from flwr.common.typing import (
32
30
  Code,
33
31
  EvaluateIns,
@@ -71,8 +69,6 @@ Example
71
69
  class NumPyClient(ABC):
72
70
  """Abstract base class for Flower clients using NumPy."""
73
71
 
74
- _context: Context
75
-
76
72
  def get_properties(self, config: Config) -> dict[str, Scalar]:
77
73
  """Return a client's set of properties.
78
74
 
@@ -175,34 +171,6 @@ class NumPyClient(ABC):
175
171
  _ = (self, parameters, config)
176
172
  return 0.0, 0, {}
177
173
 
178
- @property
179
- def context(self) -> Context:
180
- """Getter for `Context` client attribute."""
181
- warn_deprecated_feature_with_example(
182
- "Accessing the context via the client's attribute is deprecated.",
183
- example_message="Instead, pass it to the client's "
184
- "constructor in your `client_fn()` which already "
185
- "receives a context object.",
186
- code_example="def client_fn(context: Context) -> Client:\n\n"
187
- "\t\t# Your existing client_fn\n\n"
188
- "\t\t# Pass `context` to the constructor\n"
189
- "\t\treturn FlowerClient(context).to_client()",
190
- )
191
- return self._context
192
-
193
- @context.setter
194
- def context(self, context: Context) -> None:
195
- """Setter for `Context` client attribute."""
196
- self._context = context
197
-
198
- def get_context(self) -> Context:
199
- """Get the run context from this client."""
200
- return self.context
201
-
202
- def set_context(self, context: Context) -> None:
203
- """Apply a run context to this client."""
204
- self.context = context
205
-
206
174
  def to_client(self) -> Client:
207
175
  """Convert to object to Client type and return it."""
208
176
  return _wrap_numpy_client(client=self)
@@ -299,21 +267,9 @@ def _evaluate(self: Client, ins: EvaluateIns) -> EvaluateRes:
299
267
  )
300
268
 
301
269
 
302
- def _get_context(self: Client) -> Context:
303
- """Return context of underlying NumPyClient."""
304
- return self.numpy_client.get_context() # type: ignore
305
-
306
-
307
- def _set_context(self: Client, context: Context) -> None:
308
- """Apply context to underlying NumPyClient."""
309
- self.numpy_client.set_context(context) # type: ignore
310
-
311
-
312
270
  def _wrap_numpy_client(client: NumPyClient) -> Client:
313
271
  member_dict: dict[str, Callable] = { # type: ignore
314
272
  "__init__": _constructor,
315
- "get_context": _get_context,
316
- "set_context": _set_context,
317
273
  }
318
274
 
319
275
  # Add wrapper type methods (if overridden)
@@ -114,9 +114,8 @@ def run_client_app() -> None:
114
114
  event(EventType.RUN_CLIENT_APP_ENTER)
115
115
  log(
116
116
  ERROR,
117
- "The command `flower-client-app` has been replaced by `flower-supernode`.",
117
+ "The command `flower-client-app` has been replaced by `flwr run`.",
118
118
  )
119
- log(INFO, "Execute `flower-supernode --help` to learn how to use it.")
120
119
  register_exit_handlers(event_type=EventType.RUN_CLIENT_APP_LEAVE)
121
120
 
122
121
 
@@ -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 Any, Optional, Union
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
- config : dict[str, Any]
32
- The authentication configuration loaded from a YAML file.
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__(self, config: dict[str, Any]):
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) -> dict[str, str]:
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, auth_details: dict[str, str]) -> dict[str, str]:
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
- user_auth_config_path : Path
66
- The path to the user's authentication configuration file.
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: dict[str, str],
77
+ login_details: UserAuthLoginDetails,
73
78
  exec_stub: ExecStub,
74
- ) -> dict[str, Any]:
75
- """Authenticate the user with the SuperLink.
79
+ ) -> UserAuthCredentials:
80
+ """Authenticate the user and retrieve authentication credentials.
76
81
 
77
82
  Parameters
78
83
  ----------
79
- login_details : dict[str, str]
80
- A dictionary containing the user's login details.
84
+ login_details : UserAuthLoginDetails
85
+ An object containing the user's login details.
81
86
  exec_stub : ExecStub
82
- An instance of `ExecStub` used for communication with the SuperLink.
87
+ A stub for executing RPC calls to the server.
83
88
 
84
89
  Returns
85
90
  -------
86
- user_auth_config : dict[str, Any]
87
- A dictionary containing the user's authentication configuration
88
- in JSON format.
91
+ UserAuthCredentials
92
+ The authentication credentials obtained after login.
89
93
  """
90
94
 
91
95
  @abstractmethod
92
- def __init__(self, user_auth_config_path: Path):
96
+ def __init__(self, credentials_path: Path):
93
97
  """Abstract constructor."""
94
98
 
95
99
  @abstractmethod
96
- def store_tokens(self, user_auth_config: dict[str, Any]) -> None:
97
- """Store authentication tokens from the provided user_auth_config.
100
+ def store_tokens(self, credentials: UserAuthCredentials) -> None:
101
+ """Store authentication tokens to the `credentials_path`.
98
102
 
99
- The configuration, including tokens, will be saved as a JSON file
100
- at `user_auth_config_path`.
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 user_auth_config_path."""
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/grpc.py CHANGED
@@ -15,16 +15,26 @@
15
15
  """Utility functions for gRPC."""
16
16
 
17
17
 
18
+ import concurrent.futures
19
+ import sys
18
20
  from collections.abc import Sequence
19
- from logging import DEBUG
20
- from typing import Optional
21
+ from logging import DEBUG, ERROR
22
+ from typing import Any, Callable, Optional
21
23
 
22
24
  import grpc
23
25
 
24
- from flwr.common.logger import log
26
+ from .address import is_port_in_use
27
+ from .logger import log
25
28
 
26
29
  GRPC_MAX_MESSAGE_LENGTH: int = 536_870_912 # == 512 * 1024 * 1024
27
30
 
31
+ INVALID_CERTIFICATES_ERR_MSG = """
32
+ When setting any of root_certificate, certificate, or private_key,
33
+ all of them need to be set.
34
+ """
35
+
36
+ AddServicerToServerFn = Callable[..., Any]
37
+
28
38
 
29
39
  def create_channel(
30
40
  server_address: str,
@@ -66,3 +76,144 @@ def create_channel(
66
76
  channel = grpc.intercept_channel(channel, interceptors)
67
77
 
68
78
  return channel
79
+
80
+
81
+ def valid_certificates(certificates: tuple[bytes, bytes, bytes]) -> bool:
82
+ """Validate certificates tuple."""
83
+ is_valid = (
84
+ all(isinstance(certificate, bytes) for certificate in certificates)
85
+ and len(certificates) == 3
86
+ )
87
+
88
+ if not is_valid:
89
+ log(ERROR, INVALID_CERTIFICATES_ERR_MSG)
90
+
91
+ return is_valid
92
+
93
+
94
+ def generic_create_grpc_server( # pylint: disable=too-many-arguments,R0917
95
+ servicer_and_add_fn: tuple[Any, AddServicerToServerFn],
96
+ server_address: str,
97
+ max_concurrent_workers: int = 1000,
98
+ max_message_length: int = GRPC_MAX_MESSAGE_LENGTH,
99
+ keepalive_time_ms: int = 210000,
100
+ certificates: Optional[tuple[bytes, bytes, bytes]] = None,
101
+ interceptors: Optional[Sequence[grpc.ServerInterceptor]] = None,
102
+ ) -> grpc.Server:
103
+ """Create a gRPC server with a single servicer.
104
+
105
+ Parameters
106
+ ----------
107
+ servicer_and_add_fn : tuple
108
+ A tuple holding a servicer implementation and a matching
109
+ add_Servicer_to_server function.
110
+ server_address : str
111
+ Server address in the form of HOST:PORT e.g. "[::]:8080"
112
+ max_concurrent_workers : int
113
+ Maximum number of clients the server can process before returning
114
+ RESOURCE_EXHAUSTED status (default: 1000)
115
+ max_message_length : int
116
+ Maximum message length that the server can send or receive.
117
+ Int valued in bytes. -1 means unlimited. (default: GRPC_MAX_MESSAGE_LENGTH)
118
+ keepalive_time_ms : int
119
+ Flower uses a default gRPC keepalive time of 210000ms (3 minutes 30 seconds)
120
+ because some cloud providers (for example, Azure) agressively clean up idle
121
+ TCP connections by terminating them after some time (4 minutes in the case
122
+ of Azure). Flower does not use application-level keepalive signals and relies
123
+ on the assumption that the transport layer will fail in cases where the
124
+ connection is no longer active. `keepalive_time_ms` can be used to customize
125
+ the keepalive interval for specific environments. The default Flower gRPC
126
+ keepalive of 210000 ms (3 minutes 30 seconds) ensures that Flower can keep
127
+ the long running streaming connection alive in most environments. The actual
128
+ gRPC default of this setting is 7200000 (2 hours), which results in dropped
129
+ connections in some cloud environments.
130
+
131
+ These settings are related to the issue described here:
132
+ - https://github.com/grpc/proposal/blob/master/A8-client-side-keepalive.md
133
+ - https://github.com/grpc/grpc/blob/master/doc/keepalive.md
134
+ - https://grpc.io/docs/guides/performance/
135
+
136
+ Mobile Flower clients may choose to increase this value if their server
137
+ environment allows long-running idle TCP connections.
138
+ (default: 210000)
139
+ certificates : Tuple[bytes, bytes, bytes] (default: None)
140
+ Tuple containing root certificate, server certificate, and private key to
141
+ start a secure SSL-enabled server. The tuple is expected to have three bytes
142
+ elements in the following order:
143
+
144
+ * CA certificate.
145
+ * server certificate.
146
+ * server private key.
147
+ interceptors : Optional[Sequence[grpc.ServerInterceptor]] (default: None)
148
+ A list of gRPC interceptors.
149
+
150
+ Returns
151
+ -------
152
+ server : grpc.Server
153
+ A non-running instance of a gRPC server.
154
+ """
155
+ # Check if port is in use
156
+ if is_port_in_use(server_address):
157
+ sys.exit(f"Port in server address {server_address} is already in use.")
158
+
159
+ # Deconstruct tuple into servicer and function
160
+ servicer, add_servicer_to_server_fn = servicer_and_add_fn
161
+
162
+ # Possible options:
163
+ # https://github.com/grpc/grpc/blob/v1.43.x/include/grpc/impl/codegen/grpc_types.h
164
+ options = [
165
+ # Maximum number of concurrent incoming streams to allow on a http2
166
+ # connection. Int valued.
167
+ ("grpc.max_concurrent_streams", max(100, max_concurrent_workers)),
168
+ # Maximum message length that the channel can send.
169
+ # Int valued, bytes. -1 means unlimited.
170
+ ("grpc.max_send_message_length", max_message_length),
171
+ # Maximum message length that the channel can receive.
172
+ # Int valued, bytes. -1 means unlimited.
173
+ ("grpc.max_receive_message_length", max_message_length),
174
+ # The gRPC default for this setting is 7200000 (2 hours). Flower uses a
175
+ # customized default of 210000 (3 minutes and 30 seconds) to improve
176
+ # compatibility with popular cloud providers. Mobile Flower clients may
177
+ # choose to increase this value if their server environment allows
178
+ # long-running idle TCP connections.
179
+ ("grpc.keepalive_time_ms", keepalive_time_ms),
180
+ # Setting this to zero will allow sending unlimited keepalive pings in between
181
+ # sending actual data frames.
182
+ ("grpc.http2.max_pings_without_data", 0),
183
+ # Is it permissible to send keepalive pings from the client without
184
+ # any outstanding streams. More explanation here:
185
+ # https://github.com/adap/flower/pull/2197
186
+ ("grpc.keepalive_permit_without_calls", 0),
187
+ ]
188
+
189
+ server = grpc.server(
190
+ concurrent.futures.ThreadPoolExecutor(max_workers=max_concurrent_workers),
191
+ # Set the maximum number of concurrent RPCs this server will service before
192
+ # returning RESOURCE_EXHAUSTED status, or None to indicate no limit.
193
+ maximum_concurrent_rpcs=max_concurrent_workers,
194
+ options=options,
195
+ interceptors=interceptors,
196
+ )
197
+ add_servicer_to_server_fn(servicer, server)
198
+
199
+ if certificates is not None:
200
+ if not valid_certificates(certificates):
201
+ sys.exit(1)
202
+
203
+ root_certificate_b, certificate_b, private_key_b = certificates
204
+
205
+ server_credentials = grpc.ssl_server_credentials(
206
+ ((private_key_b, certificate_b),),
207
+ root_certificates=root_certificate_b,
208
+ # A boolean indicating whether or not to require clients to be
209
+ # authenticated. May only be True if root_certificates is not None.
210
+ # We are explicitly setting the current gRPC default to document
211
+ # the option. For further reference see:
212
+ # https://grpc.github.io/grpc/python/grpc.html#create-server-credentials
213
+ require_client_auth=False,
214
+ )
215
+ server.add_secure_port(server_address, server_credentials)
216
+ else:
217
+ server.add_insecure_port(server_address)
218
+
219
+ return server
@@ -151,7 +151,7 @@ class RecordSet:
151
151
  >>> p_record = ParametersRecord({"my_array": arr})
152
152
  >>>
153
153
  >>> # Adding it to the record_set would look like this
154
- >>> my_recordset.configs_records["my_config"] = c_record
154
+ >>> my_recordset.parameters_records["my_parameters"] = p_record
155
155
 
156
156
  For additional examples on how to construct each of the records types shown
157
157
  above, please refer to the documentation for :code:`ConfigsRecord`,
@@ -117,3 +117,48 @@ def verify_hmac(key: bytes, message: bytes, hmac_value: bytes) -> bool:
117
117
  return True
118
118
  except InvalidSignature:
119
119
  return False
120
+
121
+
122
+ def sign_message(private_key: ec.EllipticCurvePrivateKey, message: bytes) -> bytes:
123
+ """Sign a message using the provided EC private key.
124
+
125
+ Parameters
126
+ ----------
127
+ private_key : ec.EllipticCurvePrivateKey
128
+ The EC private key to sign the message with.
129
+ message : bytes
130
+ The message to be signed.
131
+
132
+ Returns
133
+ -------
134
+ bytes
135
+ The signature of the message.
136
+ """
137
+ signature = private_key.sign(message, ec.ECDSA(hashes.SHA256()))
138
+ return signature
139
+
140
+
141
+ def verify_signature(
142
+ public_key: ec.EllipticCurvePublicKey, message: bytes, signature: bytes
143
+ ) -> bool:
144
+ """Verify a signature against a message using the provided EC public key.
145
+
146
+ Parameters
147
+ ----------
148
+ public_key : ec.EllipticCurvePublicKey
149
+ The EC public key to verify the signature.
150
+ message : bytes
151
+ The original message.
152
+ signature : bytes
153
+ The signature to verify.
154
+
155
+ Returns
156
+ -------
157
+ bool
158
+ True if the signature is valid, False otherwise.
159
+ """
160
+ try:
161
+ public_key.verify(signature, message, ec.ECDSA(hashes.SHA256()))
162
+ return True
163
+ except InvalidSignature:
164
+ return False
flwr/common/telemetry.py CHANGED
@@ -151,6 +151,16 @@ class EventType(str, Enum):
151
151
 
152
152
  # Not yet implemented
153
153
 
154
+ # --- `flwr-*` commands ------------------------------------------------------------
155
+
156
+ # CLI: flwr-simulation
157
+ FLWR_SIMULATION_RUN_ENTER = auto()
158
+ FLWR_SIMULATION_RUN_LEAVE = auto()
159
+
160
+ # CLI: flwr-serverapp
161
+ FLWR_SERVERAPP_RUN_ENTER = auto()
162
+ FLWR_SERVERAPP_RUN_LEAVE = auto()
163
+
154
164
  # --- Simulation Engine ------------------------------------------------------------
155
165
 
156
166
  # CLI: flower-simulation
@@ -171,12 +181,12 @@ class EventType(str, Enum):
171
181
  RUN_SUPERNODE_ENTER = auto()
172
182
  RUN_SUPERNODE_LEAVE = auto()
173
183
 
174
- # CLI: `flower-server-app`
184
+ # --- DEPRECATED -------------------------------------------------------------------
185
+
186
+ # [DEPRECATED] CLI: `flower-server-app`
175
187
  RUN_SERVER_APP_ENTER = auto()
176
188
  RUN_SERVER_APP_LEAVE = auto()
177
189
 
178
- # --- DEPRECATED -------------------------------------------------------------------
179
-
180
190
  # [DEPRECATED] CLI: `flower-client-app`
181
191
  RUN_CLIENT_APP_ENTER = auto()
182
192
  RUN_CLIENT_APP_LEAVE = auto()
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\"\x9c\x01\n\x17GetLoginDetailsResponse\x12L\n\rlogin_details\x18\x01 \x03(\x0b\x32\x35.flwr.proto.GetLoginDetailsResponse.LoginDetailsEntry\x1a\x33\n\x11LoginDetailsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x93\x01\n\x14GetAuthTokensRequest\x12G\n\x0c\x61uth_details\x18\x01 \x03(\x0b\x32\x31.flwr.proto.GetAuthTokensRequest.AuthDetailsEntry\x1a\x32\n\x10\x41uthDetailsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x92\x01\n\x15GetAuthTokensResponse\x12\x46\n\x0b\x61uth_tokens\x18\x01 \x03(\x0b\x32\x31.flwr.proto.GetAuthTokensResponse.AuthTokensEntry\x1a\x31\n\x0f\x41uthTokensEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\" \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')
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=967
58
- _globals['_GETLOGINDETAILSRESPONSE_LOGINDETAILSENTRY']._serialized_start=916
59
- _globals['_GETLOGINDETAILSRESPONSE_LOGINDETAILSENTRY']._serialized_end=967
60
- _globals['_GETAUTHTOKENSREQUEST']._serialized_start=970
61
- _globals['_GETAUTHTOKENSREQUEST']._serialized_end=1117
62
- _globals['_GETAUTHTOKENSREQUEST_AUTHDETAILSENTRY']._serialized_start=1067
63
- _globals['_GETAUTHTOKENSREQUEST_AUTHDETAILSENTRY']._serialized_end=1117
64
- _globals['_GETAUTHTOKENSRESPONSE']._serialized_start=1120
65
- _globals['_GETAUTHTOKENSRESPONSE']._serialized_end=1266
66
- _globals['_GETAUTHTOKENSRESPONSE_AUTHTOKENSENTRY']._serialized_start=1217
67
- _globals['_GETAUTHTOKENSRESPONSE_AUTHTOKENSENTRY']._serialized_end=1266
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)