flwr-nightly 1.10.0.dev20240614__py3-none-any.whl → 1.10.0.dev20240617__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.

flwr/cli/run/run.py CHANGED
@@ -41,7 +41,7 @@ class Engine(str, Enum):
41
41
  def run(
42
42
  engine: Annotated[
43
43
  Optional[Engine],
44
- typer.Option(case_sensitive=False, help="The ML framework to use"),
44
+ typer.Option(case_sensitive=False, help="The execution engine to run the app"),
45
45
  ] = None,
46
46
  use_superexec: Annotated[
47
47
  bool,
@@ -20,7 +20,6 @@ from logging import DEBUG, INFO, WARN
20
20
  from pathlib import Path
21
21
  from typing import Callable, Optional, Tuple
22
22
 
23
- import tomli
24
23
  from cryptography.exceptions import UnsupportedAlgorithm
25
24
  from cryptography.hazmat.primitives.asymmetric import ec
26
25
  from cryptography.hazmat.primitives.serialization import (
@@ -28,10 +27,9 @@ from cryptography.hazmat.primitives.serialization import (
28
27
  load_ssh_public_key,
29
28
  )
30
29
 
31
- from flwr.cli.config_utils import validate_fields
32
30
  from flwr.client.client_app import ClientApp, LoadClientAppError
33
31
  from flwr.common import EventType, event
34
- from flwr.common.config import get_flwr_dir
32
+ from flwr.common.config import get_flwr_dir, get_project_config, get_project_dir
35
33
  from flwr.common.exit_handlers import register_exit_handlers
36
34
  from flwr.common.logger import log, warn_deprecated_feature
37
35
  from flwr.common.object_ref import load_app, validate
@@ -56,7 +54,7 @@ def run_supernode() -> None:
56
54
  authentication_keys = _try_setup_client_authentication(args)
57
55
 
58
56
  _start_client_internal(
59
- server_address=args.server,
57
+ server_address=args.superlink,
60
58
  load_client_app_fn=load_fn,
61
59
  transport="rest" if args.rest else "grpc-rere",
62
60
  root_certificates=root_certificates,
@@ -172,9 +170,9 @@ def _get_load_client_app_fn(
172
170
  if args.flwr_dir is None:
173
171
  flwr_dir = get_flwr_dir()
174
172
  else:
175
- flwr_dir = Path(args.flwr_dir)
173
+ flwr_dir = Path(args.flwr_dir).absolute()
176
174
 
177
- sys.path.insert(0, str(flwr_dir))
175
+ sys.path.insert(0, str(flwr_dir.absolute()))
178
176
 
179
177
  default_app_ref: str = getattr(args, "client-app")
180
178
 
@@ -191,8 +189,8 @@ def _get_load_client_app_fn(
191
189
  def _load(fab_id: str, fab_version: str) -> ClientApp:
192
190
  # If multi-app feature is disabled
193
191
  if not multi_app:
194
- # Set sys.path
195
- sys.path[0] = args.dir
192
+ # Get sys path to be inserted
193
+ sys_path = Path(args.dir).absolute()
196
194
 
197
195
  # Set app reference
198
196
  client_app_ref = default_app_ref
@@ -204,52 +202,28 @@ def _get_load_client_app_fn(
204
202
  ) from None
205
203
 
206
204
  log(WARN, "FAB ID is not provided; the default ClientApp will be loaded.")
207
- # Set sys.path
208
- sys.path[0] = args.dir
205
+ # Get sys path to be inserted
206
+ sys_path = Path(args.dir).absolute()
209
207
 
210
208
  # Set app reference
211
209
  client_app_ref = default_app_ref
212
210
  # If multi-app feature is enabled
213
211
  else:
214
- # Check the fab_id
215
- if fab_id.count("/") != 1:
216
- raise LoadClientAppError(
217
- f"Invalid FAB ID: {fab_id}",
218
- ) from None
219
- username, project_name = fab_id.split("/")
220
-
221
- # Locate the directory
222
- project_dir = flwr_dir / "apps" / username / project_name / fab_version
223
-
224
- # Check if the directory exists
225
- if not project_dir.exists():
226
- raise LoadClientAppError(
227
- f"Invalid Flower App directory: {project_dir}",
228
- ) from None
212
+ try:
213
+ project_dir = get_project_dir(fab_id, fab_version, flwr_dir)
214
+ config = get_project_config(project_dir)
215
+ except Exception as e:
216
+ raise LoadClientAppError("Failed to load ClientApp") from e
229
217
 
230
- # Load pyproject.toml file
231
- toml_path = project_dir / "pyproject.toml"
232
- if not toml_path.is_file():
233
- raise LoadClientAppError(
234
- f"Cannot find pyproject.toml in {project_dir}",
235
- ) from None
236
- with open(toml_path, encoding="utf-8") as toml_file:
237
- config = tomli.loads(toml_file.read())
238
-
239
- # Validate pyproject.toml fields
240
- is_valid, errors, _ = validate_fields(config)
241
- if not is_valid:
242
- error_msg = "\n".join([f" - {error}" for error in errors])
243
- raise LoadClientAppError(
244
- f"Invalid pyproject.toml:\n{error_msg}",
245
- ) from None
246
-
247
- # Set sys.path
248
- sys.path[0] = str(project_dir)
218
+ # Get sys path to be inserted
219
+ sys_path = Path(project_dir).absolute()
249
220
 
250
221
  # Set app reference
251
222
  client_app_ref = config["flower"]["components"]["clientapp"]
252
223
 
224
+ # Set sys.path
225
+ sys.path.insert(0, str(sys_path))
226
+
253
227
  # Load ClientApp
254
228
  log(
255
229
  DEBUG,
flwr/common/config.py CHANGED
@@ -16,13 +16,56 @@
16
16
 
17
17
  import os
18
18
  from pathlib import Path
19
+ from typing import Any, Dict, Optional, Union
20
+
21
+ import tomli
22
+
23
+ from flwr.cli.config_utils import validate_fields
24
+ from flwr.common.constant import APP_DIR, FAB_CONFIG_FILE, FLWR_HOME
19
25
 
20
26
 
21
27
  def get_flwr_dir() -> Path:
22
28
  """Return the Flower home directory based on env variables."""
23
29
  return Path(
24
30
  os.getenv(
25
- "FLWR_HOME",
31
+ FLWR_HOME,
26
32
  f"{os.getenv('XDG_DATA_HOME', os.getenv('HOME'))}/.flwr",
27
33
  )
28
34
  )
35
+
36
+
37
+ def get_project_dir(
38
+ fab_id: str, fab_version: str, flwr_dir: Optional[Union[str, Path]] = None
39
+ ) -> Path:
40
+ """Return the project directory based on the given fab_id and fab_version."""
41
+ # Check the fab_id
42
+ if fab_id.count("/") != 1:
43
+ raise ValueError(
44
+ f"Invalid FAB ID: {fab_id}",
45
+ )
46
+ publisher, project_name = fab_id.split("/")
47
+ if flwr_dir is None:
48
+ flwr_dir = get_flwr_dir()
49
+ return Path(flwr_dir) / APP_DIR / publisher / project_name / fab_version
50
+
51
+
52
+ def get_project_config(project_dir: Union[str, Path]) -> Dict[str, Any]:
53
+ """Return pyproject.toml in the given project directory."""
54
+ # Load pyproject.toml file
55
+ toml_path = Path(project_dir) / FAB_CONFIG_FILE
56
+ if not toml_path.is_file():
57
+ raise FileNotFoundError(
58
+ f"Cannot find {FAB_CONFIG_FILE} in {project_dir}",
59
+ )
60
+ with toml_path.open(encoding="utf-8") as toml_file:
61
+ config = tomli.loads(toml_file.read())
62
+
63
+ # Validate pyproject.toml fields
64
+ is_valid, errors, _ = validate_fields(config)
65
+ if not is_valid:
66
+ error_msg = "\n".join([f" - {error}" for error in errors])
67
+ raise ValueError(
68
+ f"Invalid {FAB_CONFIG_FILE}:\n{error_msg}",
69
+ )
70
+
71
+ return config
flwr/common/constant.py CHANGED
@@ -45,6 +45,11 @@ PING_BASE_MULTIPLIER = 0.8
45
45
  PING_RANDOM_RANGE = (-0.1, 0.1)
46
46
  PING_MAX_INTERVAL = 1e300
47
47
 
48
+ # Constants for FAB
49
+ APP_DIR = "apps"
50
+ FAB_CONFIG_FILE = "pyproject.toml"
51
+ FLWR_HOME = "FLWR_HOME"
52
+
48
53
 
49
54
  class MessageType:
50
55
  """Message type."""
flwr/proto/exec_pb2.py CHANGED
@@ -14,7 +14,7 @@ _sym_db = _symbol_database.Default()
14
14
 
15
15
 
16
16
 
17
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x66lwr/proto/exec.proto\x12\nflwr.proto\"#\n\x0fStartRunRequest\x12\x10\n\x08\x66\x61\x62_file\x18\x01 \x01(\x0c\"\"\n\x10StartRunResponse\x12\x0e\n\x06run_id\x18\x01 \x01(\x12\x32O\n\x04\x45xec\x12G\n\x08StartRun\x12\x1b.flwr.proto.StartRunRequest\x1a\x1c.flwr.proto.StartRunResponse\"\x00\x62\x06proto3')
17
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x66lwr/proto/exec.proto\x12\nflwr.proto\"#\n\x0fStartRunRequest\x12\x10\n\x08\x66\x61\x62_file\x18\x01 \x01(\x0c\"\"\n\x10StartRunResponse\x12\x0e\n\x06run_id\x18\x01 \x01(\x12\"#\n\x11StreamLogsRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x12\"(\n\x12StreamLogsResponse\x12\x12\n\nlog_output\x18\x01 \x01(\t2\xa0\x01\n\x04\x45xec\x12G\n\x08StartRun\x12\x1b.flwr.proto.StartRunRequest\x1a\x1c.flwr.proto.StartRunResponse\"\x00\x12O\n\nStreamLogs\x12\x1d.flwr.proto.StreamLogsRequest\x1a\x1e.flwr.proto.StreamLogsResponse\"\x00\x30\x01\x62\x06proto3')
18
18
 
19
19
  _globals = globals()
20
20
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -25,6 +25,10 @@ if _descriptor._USE_C_DESCRIPTORS == False:
25
25
  _globals['_STARTRUNREQUEST']._serialized_end=72
26
26
  _globals['_STARTRUNRESPONSE']._serialized_start=74
27
27
  _globals['_STARTRUNRESPONSE']._serialized_end=108
28
- _globals['_EXEC']._serialized_start=110
29
- _globals['_EXEC']._serialized_end=189
28
+ _globals['_STREAMLOGSREQUEST']._serialized_start=110
29
+ _globals['_STREAMLOGSREQUEST']._serialized_end=145
30
+ _globals['_STREAMLOGSRESPONSE']._serialized_start=147
31
+ _globals['_STREAMLOGSRESPONSE']._serialized_end=187
32
+ _globals['_EXEC']._serialized_start=190
33
+ _globals['_EXEC']._serialized_end=350
30
34
  # @@protoc_insertion_point(module_scope)
flwr/proto/exec_pb2.pyi CHANGED
@@ -5,6 +5,7 @@ isort:skip_file
5
5
  import builtins
6
6
  import google.protobuf.descriptor
7
7
  import google.protobuf.message
8
+ import typing
8
9
  import typing_extensions
9
10
 
10
11
  DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
@@ -30,3 +31,25 @@ class StartRunResponse(google.protobuf.message.Message):
30
31
  ) -> None: ...
31
32
  def ClearField(self, field_name: typing_extensions.Literal["run_id",b"run_id"]) -> None: ...
32
33
  global___StartRunResponse = StartRunResponse
34
+
35
+ class StreamLogsRequest(google.protobuf.message.Message):
36
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
37
+ RUN_ID_FIELD_NUMBER: builtins.int
38
+ run_id: builtins.int
39
+ def __init__(self,
40
+ *,
41
+ run_id: builtins.int = ...,
42
+ ) -> None: ...
43
+ def ClearField(self, field_name: typing_extensions.Literal["run_id",b"run_id"]) -> None: ...
44
+ global___StreamLogsRequest = StreamLogsRequest
45
+
46
+ class StreamLogsResponse(google.protobuf.message.Message):
47
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
48
+ LOG_OUTPUT_FIELD_NUMBER: builtins.int
49
+ log_output: typing.Text
50
+ def __init__(self,
51
+ *,
52
+ log_output: typing.Text = ...,
53
+ ) -> None: ...
54
+ def ClearField(self, field_name: typing_extensions.Literal["log_output",b"log_output"]) -> None: ...
55
+ global___StreamLogsResponse = StreamLogsResponse
@@ -19,6 +19,11 @@ class ExecStub(object):
19
19
  request_serializer=flwr_dot_proto_dot_exec__pb2.StartRunRequest.SerializeToString,
20
20
  response_deserializer=flwr_dot_proto_dot_exec__pb2.StartRunResponse.FromString,
21
21
  )
22
+ self.StreamLogs = channel.unary_stream(
23
+ '/flwr.proto.Exec/StreamLogs',
24
+ request_serializer=flwr_dot_proto_dot_exec__pb2.StreamLogsRequest.SerializeToString,
25
+ response_deserializer=flwr_dot_proto_dot_exec__pb2.StreamLogsResponse.FromString,
26
+ )
22
27
 
23
28
 
24
29
  class ExecServicer(object):
@@ -31,6 +36,13 @@ class ExecServicer(object):
31
36
  context.set_details('Method not implemented!')
32
37
  raise NotImplementedError('Method not implemented!')
33
38
 
39
+ def StreamLogs(self, request, context):
40
+ """Start log stream upon request
41
+ """
42
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
43
+ context.set_details('Method not implemented!')
44
+ raise NotImplementedError('Method not implemented!')
45
+
34
46
 
35
47
  def add_ExecServicer_to_server(servicer, server):
36
48
  rpc_method_handlers = {
@@ -39,6 +51,11 @@ def add_ExecServicer_to_server(servicer, server):
39
51
  request_deserializer=flwr_dot_proto_dot_exec__pb2.StartRunRequest.FromString,
40
52
  response_serializer=flwr_dot_proto_dot_exec__pb2.StartRunResponse.SerializeToString,
41
53
  ),
54
+ 'StreamLogs': grpc.unary_stream_rpc_method_handler(
55
+ servicer.StreamLogs,
56
+ request_deserializer=flwr_dot_proto_dot_exec__pb2.StreamLogsRequest.FromString,
57
+ response_serializer=flwr_dot_proto_dot_exec__pb2.StreamLogsResponse.SerializeToString,
58
+ ),
42
59
  }
43
60
  generic_handler = grpc.method_handlers_generic_handler(
44
61
  'flwr.proto.Exec', rpc_method_handlers)
@@ -65,3 +82,20 @@ class Exec(object):
65
82
  flwr_dot_proto_dot_exec__pb2.StartRunResponse.FromString,
66
83
  options, channel_credentials,
67
84
  insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
85
+
86
+ @staticmethod
87
+ def StreamLogs(request,
88
+ target,
89
+ options=(),
90
+ channel_credentials=None,
91
+ call_credentials=None,
92
+ insecure=False,
93
+ compression=None,
94
+ wait_for_ready=None,
95
+ timeout=None,
96
+ metadata=None):
97
+ return grpc.experimental.unary_stream(request, target, '/flwr.proto.Exec/StreamLogs',
98
+ flwr_dot_proto_dot_exec__pb2.StreamLogsRequest.SerializeToString,
99
+ flwr_dot_proto_dot_exec__pb2.StreamLogsResponse.FromString,
100
+ options, channel_credentials,
101
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@@ -5,6 +5,7 @@ isort:skip_file
5
5
  import abc
6
6
  import flwr.proto.exec_pb2
7
7
  import grpc
8
+ import typing
8
9
 
9
10
  class ExecStub:
10
11
  def __init__(self, channel: grpc.Channel) -> None: ...
@@ -13,6 +14,11 @@ class ExecStub:
13
14
  flwr.proto.exec_pb2.StartRunResponse]
14
15
  """Start run upon request"""
15
16
 
17
+ StreamLogs: grpc.UnaryStreamMultiCallable[
18
+ flwr.proto.exec_pb2.StreamLogsRequest,
19
+ flwr.proto.exec_pb2.StreamLogsResponse]
20
+ """Start log stream upon request"""
21
+
16
22
 
17
23
  class ExecServicer(metaclass=abc.ABCMeta):
18
24
  @abc.abstractmethod
@@ -23,5 +29,13 @@ class ExecServicer(metaclass=abc.ABCMeta):
23
29
  """Start run upon request"""
24
30
  pass
25
31
 
32
+ @abc.abstractmethod
33
+ def StreamLogs(self,
34
+ request: flwr.proto.exec_pb2.StreamLogsRequest,
35
+ context: grpc.ServicerContext,
36
+ ) -> typing.Iterator[flwr.proto.exec_pb2.StreamLogsResponse]:
37
+ """Start log stream upon request"""
38
+ pass
39
+
26
40
 
27
41
  def add_ExecServicer_to_server(servicer: ExecServicer, server: grpc.Server) -> None: ...
flwr/proto/fab_pb2.py ADDED
@@ -0,0 +1,30 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: flwr/proto/fab.proto
4
+ # Protobuf Python Version: 4.25.0
5
+ """Generated protocol buffer code."""
6
+ from google.protobuf import descriptor as _descriptor
7
+ from google.protobuf import descriptor_pool as _descriptor_pool
8
+ from google.protobuf import symbol_database as _symbol_database
9
+ from google.protobuf.internal import builder as _builder
10
+ # @@protoc_insertion_point(imports)
11
+
12
+ _sym_db = _symbol_database.Default()
13
+
14
+
15
+
16
+
17
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14\x66lwr/proto/fab.proto\x12\nflwr.proto\"$\n\x03\x46\x61\x62\x12\x0c\n\x04hash\x18\x01 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x02 \x01(\x0c\"\x1d\n\rGetFabRequest\x12\x0c\n\x04hash\x18\x01 \x01(\t\".\n\x0eGetFabResponse\x12\x1c\n\x03\x66\x61\x62\x18\x01 \x01(\x0b\x32\x0f.flwr.proto.Fabb\x06proto3')
18
+
19
+ _globals = globals()
20
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
21
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flwr.proto.fab_pb2', _globals)
22
+ if _descriptor._USE_C_DESCRIPTORS == False:
23
+ DESCRIPTOR._options = None
24
+ _globals['_FAB']._serialized_start=36
25
+ _globals['_FAB']._serialized_end=72
26
+ _globals['_GETFABREQUEST']._serialized_start=74
27
+ _globals['_GETFABREQUEST']._serialized_end=103
28
+ _globals['_GETFABRESPONSE']._serialized_start=105
29
+ _globals['_GETFABRESPONSE']._serialized_end=151
30
+ # @@protoc_insertion_point(module_scope)
flwr/proto/fab_pb2.pyi ADDED
@@ -0,0 +1,56 @@
1
+ """
2
+ @generated by mypy-protobuf. Do not edit manually!
3
+ isort:skip_file
4
+ """
5
+ import builtins
6
+ import google.protobuf.descriptor
7
+ import google.protobuf.message
8
+ import typing
9
+ import typing_extensions
10
+
11
+ DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
12
+
13
+ class Fab(google.protobuf.message.Message):
14
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
15
+ HASH_FIELD_NUMBER: builtins.int
16
+ CONTENT_FIELD_NUMBER: builtins.int
17
+ hash: typing.Text
18
+ """This field is the hash of the data field. It is used to identify the data.
19
+ The hash is calculated using the SHA-256 algorithm and is represented as a
20
+ hex string (sha256hex).
21
+ """
22
+
23
+ content: builtins.bytes
24
+ """This field contains the fab file contents a one bytes blob."""
25
+
26
+ def __init__(self,
27
+ *,
28
+ hash: typing.Text = ...,
29
+ content: builtins.bytes = ...,
30
+ ) -> None: ...
31
+ def ClearField(self, field_name: typing_extensions.Literal["content",b"content","hash",b"hash"]) -> None: ...
32
+ global___Fab = Fab
33
+
34
+ class GetFabRequest(google.protobuf.message.Message):
35
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
36
+ HASH_FIELD_NUMBER: builtins.int
37
+ hash: typing.Text
38
+ def __init__(self,
39
+ *,
40
+ hash: typing.Text = ...,
41
+ ) -> None: ...
42
+ def ClearField(self, field_name: typing_extensions.Literal["hash",b"hash"]) -> None: ...
43
+ global___GetFabRequest = GetFabRequest
44
+
45
+ class GetFabResponse(google.protobuf.message.Message):
46
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
47
+ FAB_FIELD_NUMBER: builtins.int
48
+ @property
49
+ def fab(self) -> global___Fab: ...
50
+ def __init__(self,
51
+ *,
52
+ fab: typing.Optional[global___Fab] = ...,
53
+ ) -> None: ...
54
+ def HasField(self, field_name: typing_extensions.Literal["fab",b"fab"]) -> builtins.bool: ...
55
+ def ClearField(self, field_name: typing_extensions.Literal["fab",b"fab"]) -> None: ...
56
+ global___GetFabResponse = GetFabResponse
@@ -0,0 +1,4 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+
@@ -0,0 +1,4 @@
1
+ """
2
+ @generated by mypy-protobuf. Do not edit manually!
3
+ isort:skip_file
4
+ """
@@ -45,7 +45,7 @@ def run(
45
45
  )
46
46
 
47
47
  if server_app_dir is not None:
48
- sys.path.insert(0, server_app_dir)
48
+ sys.path.insert(0, str(Path(server_app_dir).absolute()))
49
49
 
50
50
  # Load ServerApp if needed
51
51
  def _load() -> ServerApp:
@@ -20,6 +20,7 @@ import sys
20
20
  import time
21
21
  import traceback
22
22
  from logging import DEBUG, ERROR, INFO, WARN
23
+ from pathlib import Path
23
24
  from typing import Callable, Dict, List, Optional
24
25
 
25
26
  from flwr.client.client_app import ClientApp, ClientAppException, LoadClientAppError
@@ -274,6 +275,7 @@ def start_vce(
274
275
  # Use mapping constructed externally. This also means nodes
275
276
  # have previously being registered.
276
277
  nodes_mapping = existing_nodes_mapping
278
+ app_dir = str(Path(app_dir).absolute())
277
279
 
278
280
  if not state_factory:
279
281
  log(INFO, "A StateFactory was not supplied to the SimulationEngine.")
@@ -16,7 +16,7 @@
16
16
 
17
17
 
18
18
  from logging import ERROR, INFO
19
- from typing import Dict
19
+ from typing import Any, Dict, Generator
20
20
 
21
21
  import grpc
22
22
 
@@ -25,6 +25,8 @@ from flwr.proto import exec_pb2_grpc # pylint: disable=E0611
25
25
  from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
26
26
  StartRunRequest,
27
27
  StartRunResponse,
28
+ StreamLogsRequest,
29
+ StreamLogsResponse,
28
30
  )
29
31
 
30
32
  from .executor import Executor, RunTracker
@@ -52,3 +54,12 @@ class ExecServicer(exec_pb2_grpc.ExecServicer):
52
54
  self.runs[run.run_id] = run
53
55
 
54
56
  return StartRunResponse(run_id=run.run_id)
57
+
58
+ def StreamLogs(
59
+ self, request: StreamLogsRequest, context: grpc.ServicerContext
60
+ ) -> Generator[StreamLogsResponse, Any, None]:
61
+ """Get logs."""
62
+ logs = ["a", "b", "c"]
63
+ while context.is_active():
64
+ for i in range(len(logs)): # pylint: disable=C0200
65
+ yield StreamLogsResponse(log_output=logs[i])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr-nightly
3
- Version: 1.10.0.dev20240614
3
+ Version: 1.10.0.dev20240617
4
4
  Summary: Flower: A Friendly Federated Learning Framework
5
5
  Home-page: https://flower.ai
6
6
  License: Apache-2.0
@@ -40,7 +40,7 @@ flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl,sha256=wxN6I8uvWZ4MErvTbQJ
40
40
  flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl,sha256=wFeJuhqnBPQtKCBvnE3ySBpxmbeNdxcsq2Eb_RmSDIg,655
41
41
  flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl,sha256=zkxLTQRvujF76sIlzNNGPVU7Y9nVCwNBxAx82AOBaJY,654
42
42
  flwr/cli/run/__init__.py,sha256=oCd6HmQDx-sqver1gecgx-uMA38BLTSiiKpl7RGNceg,789
43
- flwr/cli/run/run.py,sha256=cByaU8y04NMqlvRb5ap1WXP-xNY07LVl23J6V4w0jaw,3830
43
+ flwr/cli/run/run.py,sha256=boAv5Ib9PdscieetxCR2MJ3MPjt5YRMjUZ8cR75P424,3842
44
44
  flwr/cli/utils.py,sha256=l65Ul0YsSBPuypk0uorAtEDmLEYiUrzpCXi6zCg9mJ4,4506
45
45
  flwr/client/__init__.py,sha256=tcgMyAW8brnmAIk4NmXkonVjYV3lafQJD4vfZ3OJ6kA,1279
46
46
  flwr/client/app.py,sha256=GhL-eR_Y2H8e2XhUnq5AUGQWQya51b5iVr4I6RDW7Hc,24189
@@ -70,12 +70,12 @@ flwr/client/numpy_client.py,sha256=u76GWAdHmJM88Agm2EgLQSvO8Jnk225mJTk-_TmPjFE,1
70
70
  flwr/client/rest_client/__init__.py,sha256=ThwOnkMdzxo_UuyTI47Q7y9oSpuTgNT2OuFvJCfuDiw,735
71
71
  flwr/client/rest_client/connection.py,sha256=GvDPX2BdPwhBQGH6LQE50AzUxQvC7bisWK1pk_OR7eE,11567
72
72
  flwr/client/supernode/__init__.py,sha256=SUhWOzcgXRNXk1V9UgB5-FaWukqqrOEajVUHEcPkwyQ,865
73
- flwr/client/supernode/app.py,sha256=sxRSLPkuKrihEjYMTPg9H1WbHtVl_izcg2se2fXvKR4,14701
73
+ flwr/client/supernode/app.py,sha256=9mwrPfgzNOsrpw2ToXmBRabrXHAn8yINsXBHw457IJs,13789
74
74
  flwr/client/typing.py,sha256=c9EvjlEjasxn1Wqx6bGl6Xg6vM1gMFfmXht-E2i5J-k,1006
75
75
  flwr/common/__init__.py,sha256=dHOptgKxna78CEQLD5Yu0QIsoSgpIIw5AhIUZCHDWAU,3721
76
76
  flwr/common/address.py,sha256=iTAN9jtmIGMrWFnx9XZQl45ZEtQJVZZLYPRBSNVARGI,1882
77
- flwr/common/config.py,sha256=WEPvVsGPrJKVppNlEGK23p33vKbOuMqSvi8DVtyW_dU,1022
78
- flwr/common/constant.py,sha256=k3QmlqQL4rfgjsO4xqTJ1QiGBHyJ5rTRE01FDEiNFCQ,2468
77
+ flwr/common/config.py,sha256=iXcpC7Eg1YK6C5apOIoWCI-mV92djyvVfcrMraOfDLM,2461
78
+ flwr/common/constant.py,sha256=yyTVQRkuhsRJE1wgaqP37OweNbOpBxungEglKvQblVA,2565
79
79
  flwr/common/context.py,sha256=ounF-mWPPtXGwtae3sg5EhF58ScviOa3MVqxRpGVu-8,1313
80
80
  flwr/common/date.py,sha256=UWhBZj49yX9LD4BmatS_ZFZu_-kweGh0KQJ1djyWWH4,891
81
81
  flwr/common/differential_privacy.py,sha256=WZWrL7C9XaB9l9NDkLDI5PvM7jwcoTTFu08ZVG8-M5Q,6113
@@ -118,10 +118,14 @@ flwr/proto/error_pb2.py,sha256=LarjKL90LbwkXKlhzNrDssgl4DXcvIPve8NVCXHpsKA,1084
118
118
  flwr/proto/error_pb2.pyi,sha256=ZNH4HhJTU_KfMXlyCeg8FwU-fcUYxTqEmoJPtWtHikc,734
119
119
  flwr/proto/error_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
120
120
  flwr/proto/error_pb2_grpc.pyi,sha256=ff2TSiLVnG6IVQcTGzb2DIH3XRSoAvAo_RMcvbMFyc0,76
121
- flwr/proto/exec_pb2.py,sha256=fwuyyK6WEwx-RngMZm6z5dqDeYcMKKxBBhwh9MJfvMA,1450
122
- flwr/proto/exec_pb2.pyi,sha256=IMUD1GlhK0mizORQ-lkiU-JbpAefmo9GLpDNfAib2GM,1068
123
- flwr/proto/exec_pb2_grpc.py,sha256=7yyi_J1Sri8LXzj5_MjhI7_hoxUMcjIAQcaE-Ghnvco,2480
124
- flwr/proto/exec_pb2_grpc.pyi,sha256=w721aoQ_ggktlIbR973bFRhwbIlEhfNMjOH4hnwgQE0,743
121
+ flwr/proto/exec_pb2.py,sha256=eA1VsoMtSAtBI8uWhEiM_xO_5bY9H-TZkrwFbDgzM-8,1909
122
+ flwr/proto/exec_pb2.pyi,sha256=eQ262F1-bvE60BthMh4rQOWKCRw_E4J4FEnHXtabIlc,1929
123
+ flwr/proto/exec_pb2_grpc.py,sha256=faAN19XEMP8GTKrcIU6jvlWkN44n2KiUsZh_OG0sYcg,4072
124
+ flwr/proto/exec_pb2_grpc.pyi,sha256=VrFhT1Um3Nb8UC2YqnR9GIiM-Yyx0FqaxVOWljh-G_w,1208
125
+ flwr/proto/fab_pb2.py,sha256=k1L3z4L3pJGRIUmgt609xUe-UAtSKFwT0C7wXnb12IY,1427
126
+ flwr/proto/fab_pb2.pyi,sha256=G2eHjgIAeVAf4TchXg3XPdeUk-h5-OMJnAv7CLyxdGs,1930
127
+ flwr/proto/fab_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
128
+ flwr/proto/fab_pb2_grpc.pyi,sha256=ff2TSiLVnG6IVQcTGzb2DIH3XRSoAvAo_RMcvbMFyc0,76
125
129
  flwr/proto/fleet_pb2.py,sha256=sASthuSb5R0v1NH2g6vRDC4BeJUFPAso8bjcihAflo0,4543
126
130
  flwr/proto/fleet_pb2.pyi,sha256=45kQ9YINv3VG0nxWSjCN4SppdepjKW8rRBlxKxz7ud4,7571
127
131
  flwr/proto/fleet_pb2_grpc.py,sha256=4eP1jkEVuckzSxo16yNaOBrHPzxHqQfj2MaNtPql4Wk,10655
@@ -166,7 +170,7 @@ flwr/server/driver/driver.py,sha256=t9SSSDlo9wT_y2Nl7waGYMTm2VlkvK3_bOb7ggPPlho,
166
170
  flwr/server/driver/grpc_driver.py,sha256=rdjkcAmtRWKeqJw4xDFqULuwVf0G2nLhfbOTrNUvPeY,11832
167
171
  flwr/server/driver/inmemory_driver.py,sha256=XfdLV3mVorTWBfthBkErJDLm8jXZ834IHF3139lTS5o,6490
168
172
  flwr/server/history.py,sha256=bBOHKyX1eQONIsUx4EUU-UnAk1i0EbEl8ioyMq_UWQ8,5063
169
- flwr/server/run_serverapp.py,sha256=nKrA9Vhs3OKeY_T4-kFL-41Qhsp5dszW98yfycOCD6c,6887
173
+ flwr/server/run_serverapp.py,sha256=svfVK-4tS2j9qYoXsLQAziJht_XiClQiSsM7OUPA6II,6909
170
174
  flwr/server/server.py,sha256=wsXsxMZ9SQ0B42nBnUlcV83NJPycgrgg5bFwcQ4BYBE,17821
171
175
  flwr/server/server_app.py,sha256=Re5Y9ftXlBRJXYHY_8TrNWsjyOUCPC5F_93H0xiZDhI,4400
172
176
  flwr/server/server_config.py,sha256=CZaHVAsMvGLjpWVcLPkiYxgJN4xfIyAiUrCI3fETKY4,1349
@@ -215,7 +219,7 @@ flwr/server/superlink/fleet/vce/__init__.py,sha256=36MHKiefnJeyjwMQzVUK4m06Ojon3
215
219
  flwr/server/superlink/fleet/vce/backend/__init__.py,sha256=oBIzmnrSSRvH_H0vRGEGWhWzQQwqe3zn6e13RsNwlIY,1466
216
220
  flwr/server/superlink/fleet/vce/backend/backend.py,sha256=LJsKl7oixVvptcG98Rd9ejJycNWcEVB0ODvSreLGp-A,2260
217
221
  flwr/server/superlink/fleet/vce/backend/raybackend.py,sha256=KCzV-n-czXxIKPwNfuD-JEVCl4-xAJaHe4taGmw9cTQ,6722
218
- flwr/server/superlink/fleet/vce/vce_api.py,sha256=aH-1h1EhTPCxdiqgH0_t8oDPiXX8VNNLV_BiDvu6kRk,12456
222
+ flwr/server/superlink/fleet/vce/vce_api.py,sha256=DQtEZ6VsL5fK1gpki0FxaJ33MUGPPXC6OEZ6oKCnZs0,12525
219
223
  flwr/server/superlink/state/__init__.py,sha256=ij-7Ms-hyordQdRmGQxY1-nVa4OhixJ0jr7_YDkys0s,1003
220
224
  flwr/server/superlink/state/in_memory_state.py,sha256=WoIOwgayuCu1DLRkkV6KgBsc28SKzSDxtXwO2a9Phuw,12750
221
225
  flwr/server/superlink/state/sqlite_state.py,sha256=8xvJgufEbl_ZRAz9VWXykKP3viUZjQNVS7yDY5dildw,28528
@@ -242,10 +246,10 @@ flwr/simulation/run_simulation.py,sha256=nTw8VG_agsxVyKmlOw-0umVuXJflcdAGqkKOL-Z
242
246
  flwr/superexec/__init__.py,sha256=9h94ogLxi6eJ3bUuJYq3E3pApThSabTPiSmPAGlTkHE,800
243
247
  flwr/superexec/app.py,sha256=8qW72a4LZRGMfNxsY6PPv-ClsKrk_ai9l0GrLI4vvTw,6078
244
248
  flwr/superexec/exec_grpc.py,sha256=u-rztpOleqSGqgvNE-ZLw1HchNsBHU1-eB3m52GZ0pQ,1852
245
- flwr/superexec/exec_servicer.py,sha256=KosYdHNwShkGdmJH1bxnZpJbMt5rz5N4I4c-ouimF6Y,1698
249
+ flwr/superexec/exec_servicer.py,sha256=qf8CT4RLXnY8omOy75kwfsWmMnfTD42B4ENTh5S-BCY,2120
246
250
  flwr/superexec/executor.py,sha256=GouXCY2LiZ-ffsOoZ_z-fh4JwbzMmhTl-gwpWFgGWTY,1688
247
- flwr_nightly-1.10.0.dev20240614.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
248
- flwr_nightly-1.10.0.dev20240614.dist-info/METADATA,sha256=or-QIXojYrlw7Qn7dsSErzGjpCvZQsgHOmkDX_p-vsw,15518
249
- flwr_nightly-1.10.0.dev20240614.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
250
- flwr_nightly-1.10.0.dev20240614.dist-info/entry_points.txt,sha256=7qBQcA-bDGDxnJmLd9FYqglFQubjCNqyg9M8a-lukps,336
251
- flwr_nightly-1.10.0.dev20240614.dist-info/RECORD,,
251
+ flwr_nightly-1.10.0.dev20240617.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
252
+ flwr_nightly-1.10.0.dev20240617.dist-info/METADATA,sha256=ZSK8BEeRBiFbBnZAN8qgOc3j664Obwmtv85LvcCqBJs,15518
253
+ flwr_nightly-1.10.0.dev20240617.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
254
+ flwr_nightly-1.10.0.dev20240617.dist-info/entry_points.txt,sha256=7qBQcA-bDGDxnJmLd9FYqglFQubjCNqyg9M8a-lukps,336
255
+ flwr_nightly-1.10.0.dev20240617.dist-info/RECORD,,