flwr 1.13.1__py3-none-any.whl → 1.15.0__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 (158) hide show
  1. flwr/cli/app.py +5 -0
  2. flwr/cli/auth_plugin/__init__.py +31 -0
  3. flwr/cli/auth_plugin/oidc_cli_plugin.py +150 -0
  4. flwr/cli/build.py +1 -0
  5. flwr/cli/cli_user_auth_interceptor.py +90 -0
  6. flwr/cli/config_utils.py +43 -149
  7. flwr/cli/constant.py +27 -0
  8. flwr/cli/example.py +1 -0
  9. flwr/cli/install.py +2 -1
  10. flwr/cli/log.py +34 -37
  11. flwr/cli/login/__init__.py +22 -0
  12. flwr/cli/login/login.py +116 -0
  13. flwr/cli/ls.py +214 -106
  14. flwr/cli/new/__init__.py +1 -0
  15. flwr/cli/new/new.py +2 -1
  16. flwr/cli/new/templates/app/.gitignore.tpl +3 -0
  17. flwr/cli/new/templates/app/README.md.tpl +3 -2
  18. flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +4 -4
  19. flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +4 -4
  20. flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +4 -4
  21. flwr/cli/new/templates/app/pyproject.jax.toml.tpl +2 -2
  22. flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +3 -4
  23. flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +2 -2
  24. flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +4 -4
  25. flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +3 -3
  26. flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +2 -2
  27. flwr/cli/run/__init__.py +1 -0
  28. flwr/cli/run/run.py +103 -43
  29. flwr/cli/stop.py +139 -0
  30. flwr/cli/utils.py +186 -8
  31. flwr/client/app.py +49 -50
  32. flwr/client/client.py +1 -32
  33. flwr/client/clientapp/app.py +23 -26
  34. flwr/client/clientapp/utils.py +2 -1
  35. flwr/client/grpc_adapter_client/connection.py +1 -1
  36. flwr/client/grpc_client/connection.py +2 -13
  37. flwr/client/grpc_rere_client/client_interceptor.py +19 -119
  38. flwr/client/grpc_rere_client/connection.py +59 -43
  39. flwr/client/grpc_rere_client/grpc_adapter.py +12 -12
  40. flwr/client/message_handler/message_handler.py +1 -2
  41. flwr/client/message_handler/task_handler.py +0 -17
  42. flwr/client/mod/comms_mods.py +1 -0
  43. flwr/client/mod/localdp_mod.py +1 -1
  44. flwr/client/nodestate/__init__.py +1 -0
  45. flwr/client/nodestate/nodestate.py +1 -0
  46. flwr/client/nodestate/nodestate_factory.py +1 -0
  47. flwr/client/numpy_client.py +0 -44
  48. flwr/client/rest_client/connection.py +37 -29
  49. flwr/client/supernode/app.py +20 -74
  50. flwr/common/address.py +1 -0
  51. flwr/common/args.py +26 -47
  52. flwr/common/auth_plugin/__init__.py +24 -0
  53. flwr/common/auth_plugin/auth_plugin.py +122 -0
  54. flwr/common/config.py +169 -17
  55. flwr/common/constant.py +38 -9
  56. flwr/common/differential_privacy.py +2 -1
  57. flwr/common/exit/__init__.py +24 -0
  58. flwr/common/exit/exit.py +99 -0
  59. flwr/common/exit/exit_code.py +93 -0
  60. flwr/common/exit_handlers.py +24 -10
  61. flwr/common/grpc.py +167 -4
  62. flwr/common/logger.py +66 -7
  63. flwr/common/message.py +1 -0
  64. flwr/common/object_ref.py +57 -54
  65. flwr/common/pyproject.py +1 -0
  66. flwr/common/record/__init__.py +1 -0
  67. flwr/common/record/parametersrecord.py +1 -0
  68. flwr/common/record/recordset.py +1 -1
  69. flwr/common/retry_invoker.py +77 -0
  70. flwr/common/secure_aggregation/crypto/symmetric_encryption.py +45 -0
  71. flwr/common/secure_aggregation/secaggplus_utils.py +2 -2
  72. flwr/common/serde.py +6 -4
  73. flwr/common/telemetry.py +15 -4
  74. flwr/common/typing.py +32 -0
  75. flwr/common/version.py +1 -0
  76. flwr/proto/clientappio_pb2.py +1 -1
  77. flwr/proto/error_pb2.py +1 -1
  78. flwr/proto/exec_pb2.py +27 -15
  79. flwr/proto/exec_pb2.pyi +80 -2
  80. flwr/proto/exec_pb2_grpc.py +102 -0
  81. flwr/proto/exec_pb2_grpc.pyi +39 -0
  82. flwr/proto/fab_pb2.py +5 -5
  83. flwr/proto/fab_pb2.pyi +4 -1
  84. flwr/proto/fleet_pb2.py +31 -31
  85. flwr/proto/fleet_pb2.pyi +23 -23
  86. flwr/proto/fleet_pb2_grpc.py +30 -30
  87. flwr/proto/fleet_pb2_grpc.pyi +20 -20
  88. flwr/proto/grpcadapter_pb2.py +1 -1
  89. flwr/proto/log_pb2.py +1 -1
  90. flwr/proto/message_pb2.py +1 -1
  91. flwr/proto/node_pb2.py +3 -3
  92. flwr/proto/node_pb2.pyi +1 -4
  93. flwr/proto/recordset_pb2.py +1 -1
  94. flwr/proto/run_pb2.py +1 -1
  95. flwr/proto/serverappio_pb2.py +24 -25
  96. flwr/proto/serverappio_pb2.pyi +32 -32
  97. flwr/proto/serverappio_pb2_grpc.py +62 -28
  98. flwr/proto/serverappio_pb2_grpc.pyi +29 -16
  99. flwr/proto/simulationio_pb2.py +3 -3
  100. flwr/proto/simulationio_pb2_grpc.py +34 -0
  101. flwr/proto/simulationio_pb2_grpc.pyi +13 -0
  102. flwr/proto/task_pb2.py +1 -1
  103. flwr/proto/transport_pb2.py +1 -1
  104. flwr/server/app.py +152 -112
  105. flwr/server/compat/app_utils.py +7 -2
  106. flwr/server/compat/driver_client_proxy.py +1 -2
  107. flwr/server/driver/grpc_driver.py +38 -85
  108. flwr/server/driver/inmemory_driver.py +7 -2
  109. flwr/server/run_serverapp.py +8 -9
  110. flwr/server/serverapp/app.py +37 -13
  111. flwr/server/strategy/dpfedavg_fixed.py +1 -0
  112. flwr/server/superlink/driver/serverappio_grpc.py +2 -1
  113. flwr/server/superlink/driver/serverappio_servicer.py +148 -63
  114. flwr/server/superlink/ffs/disk_ffs.py +1 -0
  115. flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +20 -87
  116. flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +1 -0
  117. flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +2 -165
  118. flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +56 -35
  119. flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +99 -169
  120. flwr/server/superlink/fleet/message_handler/message_handler.py +69 -29
  121. flwr/server/superlink/fleet/rest_rere/rest_api.py +20 -19
  122. flwr/server/superlink/fleet/vce/__init__.py +1 -0
  123. flwr/server/superlink/fleet/vce/backend/__init__.py +1 -0
  124. flwr/server/superlink/fleet/vce/backend/raybackend.py +1 -0
  125. flwr/server/superlink/fleet/vce/vce_api.py +2 -2
  126. flwr/server/superlink/linkstate/in_memory_linkstate.py +60 -99
  127. flwr/server/superlink/linkstate/linkstate.py +30 -36
  128. flwr/server/superlink/linkstate/sqlite_linkstate.py +105 -188
  129. flwr/server/superlink/linkstate/utils.py +18 -8
  130. flwr/server/superlink/simulation/simulationio_grpc.py +1 -1
  131. flwr/server/superlink/simulation/simulationio_servicer.py +33 -0
  132. flwr/server/superlink/utils.py +65 -0
  133. flwr/server/utils/validator.py +9 -34
  134. flwr/simulation/app.py +20 -10
  135. flwr/simulation/legacy_app.py +4 -2
  136. flwr/simulation/ray_transport/ray_actor.py +1 -0
  137. flwr/simulation/ray_transport/utils.py +1 -0
  138. flwr/simulation/run_simulation.py +36 -22
  139. flwr/simulation/simulationio_connection.py +5 -1
  140. flwr/superexec/app.py +1 -0
  141. flwr/superexec/deployment.py +1 -0
  142. flwr/superexec/exec_grpc.py +20 -2
  143. flwr/superexec/exec_servicer.py +97 -2
  144. flwr/superexec/exec_user_auth_interceptor.py +101 -0
  145. flwr/superexec/executor.py +1 -0
  146. {flwr-1.13.1.dist-info → flwr-1.15.0.dist-info}/METADATA +14 -13
  147. {flwr-1.13.1.dist-info → flwr-1.15.0.dist-info}/RECORD +150 -144
  148. flwr/proto/common_pb2.py +0 -36
  149. flwr/proto/common_pb2.pyi +0 -121
  150. flwr/proto/common_pb2_grpc.py +0 -4
  151. flwr/proto/common_pb2_grpc.pyi +0 -4
  152. flwr/proto/control_pb2.py +0 -27
  153. flwr/proto/control_pb2.pyi +0 -7
  154. flwr/proto/control_pb2_grpc.py +0 -135
  155. flwr/proto/control_pb2_grpc.pyi +0 -53
  156. {flwr-1.13.1.dist-info → flwr-1.15.0.dist-info}/LICENSE +0 -0
  157. {flwr-1.13.1.dist-info → flwr-1.15.0.dist-info}/WHEEL +0 -0
  158. {flwr-1.13.1.dist-info → flwr-1.15.0.dist-info}/entry_points.txt +0 -0
flwr/cli/log.py CHANGED
@@ -14,6 +14,7 @@
14
14
  # ==============================================================================
15
15
  """Flower command line interface `log` command."""
16
16
 
17
+
17
18
  import time
18
19
  from logging import DEBUG, ERROR, INFO
19
20
  from pathlib import Path
@@ -23,17 +24,19 @@ import grpc
23
24
  import typer
24
25
 
25
26
  from flwr.cli.config_utils import (
27
+ exit_if_no_address,
26
28
  load_and_validate,
27
- validate_certificate_in_federation_config,
29
+ process_loaded_project_config,
28
30
  validate_federation_in_project_config,
29
- validate_project_config,
30
31
  )
32
+ from flwr.cli.constant import FEDERATION_CONFIG_HELP_MESSAGE
31
33
  from flwr.common.constant import CONN_RECONNECT_INTERVAL, CONN_REFRESH_PERIOD
32
- from flwr.common.grpc import GRPC_MAX_MESSAGE_LENGTH, create_channel
33
34
  from flwr.common.logger import log as logger
34
35
  from flwr.proto.exec_pb2 import StreamLogsRequest # pylint: disable=E0611
35
36
  from flwr.proto.exec_pb2_grpc import ExecStub
36
37
 
38
+ from .utils import init_channel, try_obtain_cli_auth_plugin, unauthenticated_exc_handler
39
+
37
40
 
38
41
  def start_stream(
39
42
  run_id: int, channel: grpc.Channel, refresh_period: int = CONN_REFRESH_PERIOD
@@ -55,6 +58,8 @@ def start_stream(
55
58
  logger(ERROR, "Invalid run_id `%s`, exiting", run_id)
56
59
  if e.code() == grpc.StatusCode.CANCELLED:
57
60
  pass
61
+ else:
62
+ raise e
58
63
  finally:
59
64
  channel.close()
60
65
 
@@ -86,8 +91,9 @@ def stream_logs(
86
91
  latest_timestamp = 0.0
87
92
  res = None
88
93
  try:
89
- for res in stub.StreamLogs(req, timeout=duration):
90
- print(res.log_output, end="")
94
+ with unauthenticated_exc_handler():
95
+ for res in stub.StreamLogs(req, timeout=duration):
96
+ print(res.log_output, end="")
91
97
  except grpc.RpcError as e:
92
98
  # pylint: disable=E1101
93
99
  if e.code() != grpc.StatusCode.DEADLINE_EXCEEDED:
@@ -107,9 +113,10 @@ def print_logs(run_id: int, channel: grpc.Channel, timeout: int) -> None:
107
113
  try:
108
114
  while True:
109
115
  try:
110
- # Enforce timeout for graceful exit
111
- for res in stub.StreamLogs(req, timeout=timeout):
112
- print(res.log_output)
116
+ with unauthenticated_exc_handler():
117
+ # Enforce timeout for graceful exit
118
+ for res in stub.StreamLogs(req, timeout=timeout):
119
+ print(res.log_output)
113
120
  except grpc.RpcError as e:
114
121
  # pylint: disable=E1101
115
122
  if e.code() == grpc.StatusCode.DEADLINE_EXCEEDED:
@@ -119,6 +126,7 @@ def print_logs(run_id: int, channel: grpc.Channel, timeout: int) -> None:
119
126
  break
120
127
  if e.code() == grpc.StatusCode.CANCELLED:
121
128
  break
129
+ raise e
122
130
  except KeyboardInterrupt:
123
131
  logger(DEBUG, "Stream interrupted by user")
124
132
  finally:
@@ -126,11 +134,6 @@ def print_logs(run_id: int, channel: grpc.Channel, timeout: int) -> None:
126
134
  logger(DEBUG, "Channel closed")
127
135
 
128
136
 
129
- def on_channel_state_change(channel_connectivity: str) -> None:
130
- """Log channel connectivity."""
131
- logger(DEBUG, channel_connectivity)
132
-
133
-
134
137
  def log(
135
138
  run_id: Annotated[
136
139
  int,
@@ -144,6 +147,13 @@ def log(
144
147
  Optional[str],
145
148
  typer.Argument(help="Name of the federation to run the app on"),
146
149
  ] = None,
150
+ federation_config_overrides: Annotated[
151
+ Optional[list[str]],
152
+ typer.Option(
153
+ "--federation-config",
154
+ help=FEDERATION_CONFIG_HELP_MESSAGE,
155
+ ),
156
+ ] = None,
147
157
  stream: Annotated[
148
158
  bool,
149
159
  typer.Option(
@@ -157,41 +167,28 @@ def log(
157
167
 
158
168
  pyproject_path = app / "pyproject.toml" if app else None
159
169
  config, errors, warnings = load_and_validate(path=pyproject_path)
160
- config = validate_project_config(config, errors, warnings)
170
+ config = process_loaded_project_config(config, errors, warnings)
161
171
  federation, federation_config = validate_federation_in_project_config(
162
- federation, config
172
+ federation, config, federation_config_overrides
163
173
  )
174
+ exit_if_no_address(federation_config, "log")
164
175
 
165
- if "address" not in federation_config:
166
- typer.secho(
167
- "❌ `flwr log` currently works with Exec API. Ensure that the correct"
168
- "Exec API address is provided in the `pyproject.toml`.",
169
- fg=typer.colors.RED,
170
- bold=True,
171
- )
172
- raise typer.Exit(code=1)
173
-
174
- _log_with_exec_api(app, federation_config, run_id, stream)
176
+ try:
177
+ _log_with_exec_api(app, federation, federation_config, run_id, stream)
178
+ except Exception as err: # pylint: disable=broad-except
179
+ typer.secho(str(err), fg=typer.colors.RED, bold=True)
180
+ raise typer.Exit(code=1) from None
175
181
 
176
182
 
177
183
  def _log_with_exec_api(
178
184
  app: Path,
185
+ federation: str,
179
186
  federation_config: dict[str, Any],
180
187
  run_id: int,
181
188
  stream: bool,
182
189
  ) -> None:
183
-
184
- insecure, root_certificates_bytes = validate_certificate_in_federation_config(
185
- app, federation_config
186
- )
187
- channel = create_channel(
188
- server_address=federation_config["address"],
189
- insecure=insecure,
190
- root_certificates=root_certificates_bytes,
191
- max_message_length=GRPC_MAX_MESSAGE_LENGTH,
192
- interceptors=None,
193
- )
194
- channel.subscribe(on_channel_state_change)
190
+ auth_plugin = try_obtain_cli_auth_plugin(app, federation, federation_config)
191
+ channel = init_channel(app, federation_config, auth_plugin)
195
192
 
196
193
  if stream:
197
194
  start_stream(run_id, channel, CONN_REFRESH_PERIOD)
@@ -0,0 +1,22 @@
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 command line interface `login` command."""
16
+
17
+
18
+ from .login import login as login
19
+
20
+ __all__ = [
21
+ "login",
22
+ ]
@@ -0,0 +1,116 @@
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 command line interface `login` command."""
16
+
17
+
18
+ from pathlib import Path
19
+ from typing import Annotated, Optional
20
+
21
+ import typer
22
+
23
+ from flwr.cli.config_utils import (
24
+ exit_if_no_address,
25
+ load_and_validate,
26
+ process_loaded_project_config,
27
+ validate_federation_in_project_config,
28
+ )
29
+ from flwr.cli.constant import FEDERATION_CONFIG_HELP_MESSAGE
30
+ from flwr.common.typing import UserAuthLoginDetails
31
+ from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
32
+ GetLoginDetailsRequest,
33
+ GetLoginDetailsResponse,
34
+ )
35
+ from flwr.proto.exec_pb2_grpc import ExecStub
36
+
37
+ from ..utils import (
38
+ init_channel,
39
+ try_obtain_cli_auth_plugin,
40
+ unauthenticated_exc_handler,
41
+ )
42
+
43
+
44
+ def login( # pylint: disable=R0914
45
+ app: Annotated[
46
+ Path,
47
+ typer.Argument(help="Path of the Flower App to run."),
48
+ ] = Path("."),
49
+ federation: Annotated[
50
+ Optional[str],
51
+ typer.Argument(help="Name of the federation to login into."),
52
+ ] = None,
53
+ federation_config_overrides: Annotated[
54
+ Optional[list[str]],
55
+ typer.Option(
56
+ "--federation-config",
57
+ help=FEDERATION_CONFIG_HELP_MESSAGE,
58
+ ),
59
+ ] = None,
60
+ ) -> None:
61
+ """Login to Flower SuperLink."""
62
+ typer.secho("Loading project configuration... ", fg=typer.colors.BLUE)
63
+
64
+ pyproject_path = app / "pyproject.toml" if app else None
65
+ config, errors, warnings = load_and_validate(path=pyproject_path)
66
+
67
+ config = process_loaded_project_config(config, errors, warnings)
68
+ federation, federation_config = validate_federation_in_project_config(
69
+ federation, config, federation_config_overrides
70
+ )
71
+ exit_if_no_address(federation_config, "login")
72
+
73
+ # Check if `enable-user-auth` is set to `true`
74
+ if not federation_config.get("enable-user-auth", False):
75
+ typer.secho(
76
+ f"❌ User authentication is not enabled for the federation '{federation}'. "
77
+ "To enable it, set `enable-user-auth = true` in the federation "
78
+ "configuration.",
79
+ fg=typer.colors.RED,
80
+ bold=True,
81
+ )
82
+ raise typer.Exit(code=1)
83
+
84
+ channel = init_channel(app, federation_config, None)
85
+ stub = ExecStub(channel)
86
+
87
+ login_request = GetLoginDetailsRequest()
88
+ with unauthenticated_exc_handler():
89
+ login_response: GetLoginDetailsResponse = stub.GetLoginDetails(login_request)
90
+
91
+ # Get the auth plugin
92
+ auth_type = login_response.auth_type
93
+ auth_plugin = try_obtain_cli_auth_plugin(
94
+ app, federation, federation_config, auth_type
95
+ )
96
+ if auth_plugin is None:
97
+ typer.secho(
98
+ f'❌ Authentication type "{auth_type}" not found',
99
+ fg=typer.colors.RED,
100
+ bold=True,
101
+ )
102
+ raise typer.Exit(code=1)
103
+
104
+ # Login
105
+ details = UserAuthLoginDetails(
106
+ auth_type=login_response.auth_type,
107
+ device_code=login_response.device_code,
108
+ verification_uri_complete=login_response.verification_uri_complete,
109
+ expires_in=login_response.expires_in,
110
+ interval=login_response.interval,
111
+ )
112
+ with unauthenticated_exc_handler():
113
+ credentials = auth_plugin.login(details, stub)
114
+
115
+ # Store the tokens
116
+ auth_plugin.store_tokens(credentials)