flwr-nightly 1.19.0.dev20250528__py3-none-any.whl → 1.19.0.dev20250530__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flwr/cli/utils.py +11 -3
- flwr/client/mod/comms_mods.py +36 -17
- flwr/common/auth_plugin/auth_plugin.py +9 -3
- flwr/common/exit_handlers.py +30 -0
- flwr/common/inflatable_grpc_utils.py +27 -13
- flwr/common/message.py +11 -0
- flwr/common/record/array.py +10 -21
- flwr/common/record/arrayrecord.py +1 -1
- flwr/common/recorddict_compat.py +2 -2
- flwr/common/serde.py +1 -1
- flwr/proto/fleet_pb2.py +16 -16
- flwr/proto/fleet_pb2.pyi +5 -5
- flwr/proto/message_pb2.py +10 -10
- flwr/proto/message_pb2.pyi +4 -4
- flwr/proto/serverappio_pb2.py +26 -26
- flwr/proto/serverappio_pb2.pyi +5 -5
- flwr/server/app.py +45 -57
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +2 -0
- flwr/server/superlink/fleet/message_handler/message_handler.py +34 -7
- flwr/server/superlink/fleet/rest_rere/rest_api.py +5 -2
- flwr/server/superlink/linkstate/utils.py +8 -5
- flwr/server/superlink/serverappio/serverappio_servicer.py +45 -5
- flwr/server/superlink/utils.py +29 -0
- flwr/supercore/object_store/__init__.py +2 -1
- flwr/supercore/object_store/in_memory_object_store.py +9 -2
- flwr/supercore/object_store/object_store.py +12 -0
- flwr/superexec/exec_grpc.py +4 -3
- flwr/superexec/exec_user_auth_interceptor.py +33 -4
- flwr/supernode/start_client_internal.py +144 -170
- {flwr_nightly-1.19.0.dev20250528.dist-info → flwr_nightly-1.19.0.dev20250530.dist-info}/METADATA +1 -1
- {flwr_nightly-1.19.0.dev20250528.dist-info → flwr_nightly-1.19.0.dev20250530.dist-info}/RECORD +33 -33
- {flwr_nightly-1.19.0.dev20250528.dist-info → flwr_nightly-1.19.0.dev20250530.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.19.0.dev20250528.dist-info → flwr_nightly-1.19.0.dev20250530.dist-info}/entry_points.txt +0 -0
flwr/cli/utils.py
CHANGED
@@ -291,9 +291,9 @@ def init_channel(
|
|
291
291
|
def flwr_cli_grpc_exc_handler() -> Iterator[None]:
|
292
292
|
"""Context manager to handle specific gRPC errors.
|
293
293
|
|
294
|
-
It catches grpc.RpcError exceptions with UNAUTHENTICATED
|
295
|
-
informs the user, and exits the application. All other
|
296
|
-
escape.
|
294
|
+
It catches grpc.RpcError exceptions with UNAUTHENTICATED, UNIMPLEMENTED, and
|
295
|
+
PERMISSION_DENIED statuses, informs the user, and exits the application. All other
|
296
|
+
exceptions will be allowed to escape.
|
297
297
|
"""
|
298
298
|
try:
|
299
299
|
yield
|
@@ -313,4 +313,12 @@ def flwr_cli_grpc_exc_handler() -> Iterator[None]:
|
|
313
313
|
bold=True,
|
314
314
|
)
|
315
315
|
raise typer.Exit(code=1) from None
|
316
|
+
if e.code() == grpc.StatusCode.PERMISSION_DENIED:
|
317
|
+
typer.secho(
|
318
|
+
"❌ Authorization failed. Please contact your administrator"
|
319
|
+
" to check your permissions.",
|
320
|
+
fg=typer.colors.RED,
|
321
|
+
bold=True,
|
322
|
+
)
|
323
|
+
raise typer.Exit(code=1) from None
|
316
324
|
raise
|
flwr/client/mod/comms_mods.py
CHANGED
@@ -32,14 +32,17 @@ def message_size_mod(
|
|
32
32
|
|
33
33
|
This mod logs the size in bytes of the message being transmited.
|
34
34
|
"""
|
35
|
-
|
35
|
+
# Log the size of the incoming message in bytes
|
36
|
+
total_bytes = sum(record.count_bytes() for record in msg.content.values())
|
37
|
+
log(INFO, "Incoming message size: %i bytes", total_bytes)
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
+
# Call the next layer
|
40
|
+
msg = call_next(msg, ctxt)
|
39
41
|
|
40
|
-
|
41
|
-
|
42
|
-
|
42
|
+
# Log the size of the outgoing message in bytes
|
43
|
+
total_bytes = sum(record.count_bytes() for record in msg.content.values())
|
44
|
+
log(INFO, "Outgoing message size: %i bytes", total_bytes)
|
45
|
+
return msg
|
43
46
|
|
44
47
|
|
45
48
|
def arrays_size_mod(
|
@@ -50,25 +53,41 @@ def arrays_size_mod(
|
|
50
53
|
This mod logs the number of array elements transmitted in ``ArrayRecord`` objects
|
51
54
|
of the message as well as their sizes in bytes.
|
52
55
|
"""
|
53
|
-
|
54
|
-
|
56
|
+
# Log the ArrayRecord size statistics and the total size in the incoming message
|
57
|
+
array_record_size_stats = _get_array_record_size_stats(msg)
|
58
|
+
total_bytes = sum(stat["bytes"] for stat in array_record_size_stats.values())
|
59
|
+
if array_record_size_stats:
|
60
|
+
log(INFO, "Incoming `ArrayRecord` size statistics:")
|
61
|
+
log(INFO, array_record_size_stats)
|
62
|
+
log(INFO, "Total array elements received: %i bytes", total_bytes)
|
63
|
+
|
64
|
+
msg = call_next(msg, ctxt)
|
65
|
+
|
66
|
+
# Log the ArrayRecord size statistics and the total size in the outgoing message
|
67
|
+
array_record_size_stats = _get_array_record_size_stats(msg)
|
68
|
+
total_bytes = sum(stat["bytes"] for stat in array_record_size_stats.values())
|
69
|
+
if array_record_size_stats:
|
70
|
+
log(INFO, "Outgoing `ArrayRecord` size statistics:")
|
71
|
+
log(INFO, array_record_size_stats)
|
72
|
+
log(INFO, "Total array elements sent: %i bytes", total_bytes)
|
73
|
+
return msg
|
74
|
+
|
75
|
+
|
76
|
+
def _get_array_record_size_stats(
|
77
|
+
msg: Message,
|
78
|
+
) -> dict[str, dict[str, int]]:
|
79
|
+
"""Get `ArrayRecord` size statistics from the message."""
|
80
|
+
array_record_size_stats = {}
|
55
81
|
for record_name, arr_record in msg.content.array_records.items():
|
56
82
|
arr_record_bytes = arr_record.count_bytes()
|
57
|
-
arrays_size_in_bytes += arr_record_bytes
|
58
83
|
element_count = 0
|
59
84
|
for array in arr_record.values():
|
60
85
|
element_count += (
|
61
86
|
int(np.prod(array.shape)) if array.shape else array.numpy().size
|
62
87
|
)
|
63
88
|
|
64
|
-
|
89
|
+
array_record_size_stats[record_name] = {
|
65
90
|
"elements": element_count,
|
66
91
|
"bytes": arr_record_bytes,
|
67
92
|
}
|
68
|
-
|
69
|
-
if model_size_stats:
|
70
|
-
log(INFO, model_size_stats)
|
71
|
-
|
72
|
-
log(INFO, "Total array elements transmitted: %i bytes", arrays_size_in_bytes)
|
73
|
-
|
74
|
-
return call_next(msg, ctxt)
|
93
|
+
return array_record_size_stats
|
@@ -33,6 +33,9 @@ class ExecAuthPlugin(ABC):
|
|
33
33
|
----------
|
34
34
|
user_auth_config_path : Path
|
35
35
|
Path to the YAML file containing the authentication configuration.
|
36
|
+
verify_tls_cert : bool
|
37
|
+
Boolean indicating whether to verify the TLS certificate
|
38
|
+
when making requests to the server.
|
36
39
|
"""
|
37
40
|
|
38
41
|
@abstractmethod
|
@@ -60,7 +63,7 @@ class ExecAuthPlugin(ABC):
|
|
60
63
|
@abstractmethod
|
61
64
|
def refresh_tokens(
|
62
65
|
self, metadata: Sequence[tuple[str, Union[str, bytes]]]
|
63
|
-
) -> Optional[Sequence[tuple[str, Union[str, bytes]]]]:
|
66
|
+
) -> tuple[Optional[Sequence[tuple[str, Union[str, bytes]]]], Optional[UserInfo]]:
|
64
67
|
"""Refresh authentication tokens in the provided metadata."""
|
65
68
|
|
66
69
|
|
@@ -69,12 +72,15 @@ class ExecAuthzPlugin(ABC): # pylint: disable=too-few-public-methods
|
|
69
72
|
|
70
73
|
Parameters
|
71
74
|
----------
|
72
|
-
|
75
|
+
user_auth_config_path : Path
|
73
76
|
Path to the YAML file containing the authorization configuration.
|
77
|
+
verify_tls_cert : bool
|
78
|
+
Boolean indicating whether to verify the TLS certificate
|
79
|
+
when making requests to the server.
|
74
80
|
"""
|
75
81
|
|
76
82
|
@abstractmethod
|
77
|
-
def __init__(self,
|
83
|
+
def __init__(self, user_auth_config_path: Path, verify_tls_cert: bool):
|
78
84
|
"""Abstract constructor."""
|
79
85
|
|
80
86
|
@abstractmethod
|
flwr/common/exit_handlers.py
CHANGED
@@ -30,6 +30,7 @@ SIGNAL_TO_EXIT_CODE: dict[int, int] = {
|
|
30
30
|
signal.SIGINT: ExitCode.GRACEFUL_EXIT_SIGINT,
|
31
31
|
signal.SIGTERM: ExitCode.GRACEFUL_EXIT_SIGTERM,
|
32
32
|
}
|
33
|
+
registered_exit_handlers: list[Callable[[], None]] = []
|
33
34
|
|
34
35
|
# SIGQUIT is not available on Windows
|
35
36
|
if hasattr(signal, "SIGQUIT"):
|
@@ -41,6 +42,7 @@ def register_exit_handlers(
|
|
41
42
|
exit_message: Optional[str] = None,
|
42
43
|
grpc_servers: Optional[list[Server]] = None,
|
43
44
|
bckg_threads: Optional[list[Thread]] = None,
|
45
|
+
exit_handlers: Optional[list[Callable[[], None]]] = None,
|
44
46
|
) -> None:
|
45
47
|
"""Register exit handlers for `SIGINT`, `SIGTERM` and `SIGQUIT` signals.
|
46
48
|
|
@@ -56,8 +58,12 @@ def register_exit_handlers(
|
|
56
58
|
bckg_threads: Optional[List[Thread]] (default: None)
|
57
59
|
An optional list of threads that need to be gracefully
|
58
60
|
terminated before exiting.
|
61
|
+
exit_handlers: Optional[List[Callable[[], None]]] (default: None)
|
62
|
+
An optional list of exit handlers to be called before exiting.
|
63
|
+
Additional exit handlers can be added using `add_exit_handler`.
|
59
64
|
"""
|
60
65
|
default_handlers: dict[int, Callable[[int, FrameType], None]] = {}
|
66
|
+
registered_exit_handlers.extend(exit_handlers or [])
|
61
67
|
|
62
68
|
def graceful_exit_handler(signalnum: int, _frame: FrameType) -> None:
|
63
69
|
"""Exit handler to be registered with `signal.signal`.
|
@@ -68,6 +74,9 @@ def register_exit_handlers(
|
|
68
74
|
# Reset to default handler
|
69
75
|
signal.signal(signalnum, default_handlers[signalnum]) # type: ignore
|
70
76
|
|
77
|
+
for handler in registered_exit_handlers:
|
78
|
+
handler()
|
79
|
+
|
71
80
|
if grpc_servers is not None:
|
72
81
|
for grpc_server in grpc_servers:
|
73
82
|
grpc_server.stop(grace=1)
|
@@ -87,3 +96,24 @@ def register_exit_handlers(
|
|
87
96
|
for sig in SIGNAL_TO_EXIT_CODE:
|
88
97
|
default_handler = signal.signal(sig, graceful_exit_handler) # type: ignore
|
89
98
|
default_handlers[sig] = default_handler # type: ignore
|
99
|
+
|
100
|
+
|
101
|
+
def add_exit_handler(exit_handler: Callable[[], None]) -> None:
|
102
|
+
"""Add an exit handler to be called on graceful exit.
|
103
|
+
|
104
|
+
This function allows you to register additional exit handlers
|
105
|
+
that will be executed when the application exits gracefully,
|
106
|
+
if `register_exit_handlers` was called.
|
107
|
+
|
108
|
+
Parameters
|
109
|
+
----------
|
110
|
+
exit_handler : Callable[[], None]
|
111
|
+
A callable that takes no arguments and performs cleanup or
|
112
|
+
other actions before the application exits.
|
113
|
+
|
114
|
+
Notes
|
115
|
+
-----
|
116
|
+
This method is not thread-safe, and it allows you to add the
|
117
|
+
same exit handler multiple times.
|
118
|
+
"""
|
119
|
+
registered_exit_handlers.append(exit_handler)
|
@@ -15,7 +15,7 @@
|
|
15
15
|
"""InflatableObject utils."""
|
16
16
|
|
17
17
|
|
18
|
-
from typing import Union
|
18
|
+
from typing import Optional, Union
|
19
19
|
|
20
20
|
from flwr.proto.fleet_pb2_grpc import FleetStub # pylint: disable=E0611
|
21
21
|
from flwr.proto.message_pb2 import ( # pylint: disable=E0611
|
@@ -24,6 +24,7 @@ from flwr.proto.message_pb2 import ( # pylint: disable=E0611
|
|
24
24
|
PushObjectRequest,
|
25
25
|
PushObjectResponse,
|
26
26
|
)
|
27
|
+
from flwr.proto.node_pb2 import Node # pylint: disable=E0611
|
27
28
|
from flwr.proto.serverappio_pb2_grpc import ServerAppIoStub # pylint: disable=E0611
|
28
29
|
|
29
30
|
from .inflatable import (
|
@@ -46,40 +47,51 @@ inflatable_class_registry: dict[str, type[InflatableObject]] = {
|
|
46
47
|
|
47
48
|
|
48
49
|
def push_object_to_servicer(
|
49
|
-
obj: InflatableObject,
|
50
|
+
obj: InflatableObject,
|
51
|
+
stub: Union[FleetStub, ServerAppIoStub],
|
52
|
+
node: Node,
|
53
|
+
object_ids_to_push: Optional[set[str]] = None,
|
50
54
|
) -> set[str]:
|
51
55
|
"""Recursively deflate an object and push it to the servicer.
|
52
56
|
|
53
|
-
Objects with the same ID are not pushed twice.
|
57
|
+
Objects with the same ID are not pushed twice. If `object_ids_to_push` is set,
|
58
|
+
only objects with those IDs are pushed. It returns the set of pushed object
|
54
59
|
IDs.
|
55
60
|
"""
|
56
61
|
pushed_object_ids: set[str] = set()
|
57
62
|
# Push children if it has any
|
58
63
|
if children := obj.children:
|
59
64
|
for child in children.values():
|
60
|
-
pushed_object_ids |= push_object_to_servicer(
|
65
|
+
pushed_object_ids |= push_object_to_servicer(
|
66
|
+
child, stub, node, object_ids_to_push
|
67
|
+
)
|
61
68
|
|
62
69
|
# Deflate object and push
|
63
70
|
object_content = obj.deflate()
|
64
71
|
object_id = get_object_id(object_content)
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
72
|
+
# Push always if no object set is specified, or if the object is in the set
|
73
|
+
if object_ids_to_push is None or object_id in object_ids_to_push:
|
74
|
+
_: PushObjectResponse = stub.PushObject(
|
75
|
+
PushObjectRequest(
|
76
|
+
node=node,
|
77
|
+
object_id=object_id,
|
78
|
+
object_content=object_content,
|
79
|
+
)
|
69
80
|
)
|
70
|
-
|
71
|
-
pushed_object_ids.add(object_id)
|
81
|
+
pushed_object_ids.add(object_id)
|
72
82
|
|
73
83
|
return pushed_object_ids
|
74
84
|
|
75
85
|
|
76
86
|
def pull_object_from_servicer(
|
77
|
-
object_id: str,
|
87
|
+
object_id: str,
|
88
|
+
stub: Union[FleetStub, ServerAppIoStub],
|
89
|
+
node: Node,
|
78
90
|
) -> InflatableObject:
|
79
91
|
"""Recursively inflate an object by pulling it from the servicer."""
|
80
92
|
# Pull object
|
81
93
|
object_proto: PullObjectResponse = stub.PullObject(
|
82
|
-
PullObjectRequest(object_id=object_id)
|
94
|
+
PullObjectRequest(node=node, object_id=object_id)
|
83
95
|
)
|
84
96
|
object_content = object_proto.object_content
|
85
97
|
|
@@ -93,7 +105,9 @@ def pull_object_from_servicer(
|
|
93
105
|
# Pull all children objects
|
94
106
|
children: dict[str, InflatableObject] = {}
|
95
107
|
for child_object_id in children_obj_ids:
|
96
|
-
children[child_object_id] = pull_object_from_servicer(
|
108
|
+
children[child_object_id] = pull_object_from_servicer(
|
109
|
+
child_object_id, stub, node
|
110
|
+
)
|
97
111
|
|
98
112
|
# Inflate object passing its children
|
99
113
|
return cls_type.inflate(object_content, children=children)
|
flwr/common/message.py
CHANGED
@@ -24,6 +24,7 @@ from flwr.common.date import now
|
|
24
24
|
from flwr.common.logger import warn_deprecated_feature
|
25
25
|
from flwr.proto.message_pb2 import Message as ProtoMessage # pylint: disable=E0611
|
26
26
|
from flwr.proto.message_pb2 import Metadata as ProtoMetadata # pylint: disable=E0611
|
27
|
+
from flwr.proto.message_pb2 import ObjectIDs # pylint: disable=E0611
|
27
28
|
|
28
29
|
from ..app.error import Error
|
29
30
|
from ..app.metadata import Metadata
|
@@ -31,6 +32,7 @@ from .constant import MESSAGE_TTL_TOLERANCE
|
|
31
32
|
from .inflatable import (
|
32
33
|
InflatableObject,
|
33
34
|
add_header_to_object_body,
|
35
|
+
get_desdendant_object_ids,
|
34
36
|
get_object_body,
|
35
37
|
get_object_children_ids_from_object_content,
|
36
38
|
)
|
@@ -505,3 +507,12 @@ def _check_arg_types( # pylint: disable=too-many-arguments, R0917
|
|
505
507
|
):
|
506
508
|
return
|
507
509
|
raise MessageInitializationError()
|
510
|
+
|
511
|
+
|
512
|
+
def get_message_to_descendant_id_mapping(message: Message) -> dict[str, ObjectIDs]:
|
513
|
+
"""Construct a mapping between message object_id and that of its descendants."""
|
514
|
+
return {
|
515
|
+
message.object_id: ObjectIDs(
|
516
|
+
object_ids=list(get_desdendant_object_ids(message))
|
517
|
+
)
|
518
|
+
}
|
flwr/common/record/array.py
CHANGED
@@ -62,8 +62,8 @@ class Array(InflatableObject):
|
|
62
62
|
A string representing the data type of the serialized object (e.g. `"float32"`).
|
63
63
|
Only required if you are not passing in a ndarray or a tensor.
|
64
64
|
|
65
|
-
shape : Optional[
|
66
|
-
A
|
65
|
+
shape : Optional[tuple[int, ...]] (default: None)
|
66
|
+
A tuple representing the shape of the unserialized array-like object. Only
|
67
67
|
required if you are not passing in a ndarray or a tensor.
|
68
68
|
|
69
69
|
stype : Optional[str] (default: None)
|
@@ -107,24 +107,13 @@ class Array(InflatableObject):
|
|
107
107
|
"""
|
108
108
|
|
109
109
|
dtype: str
|
110
|
+
shape: tuple[int, ...]
|
110
111
|
stype: str
|
111
112
|
data: bytes
|
112
113
|
|
113
|
-
@property
|
114
|
-
def shape(self) -> list[int]:
|
115
|
-
"""Get the shape of the array."""
|
116
|
-
self.is_dirty = True # Mark as dirty when shape is accessed
|
117
|
-
return cast(list[int], self.__dict__["_shape"])
|
118
|
-
|
119
|
-
@shape.setter
|
120
|
-
def shape(self, value: list[int]) -> None:
|
121
|
-
"""Set the shape of the array."""
|
122
|
-
self.is_dirty = True # Mark as dirty when shape is set
|
123
|
-
self.__dict__["_shape"] = value
|
124
|
-
|
125
114
|
@overload
|
126
115
|
def __init__( # noqa: E704
|
127
|
-
self, dtype: str, shape:
|
116
|
+
self, dtype: str, shape: tuple[int, ...], stype: str, data: bytes
|
128
117
|
) -> None: ...
|
129
118
|
|
130
119
|
@overload
|
@@ -137,7 +126,7 @@ class Array(InflatableObject):
|
|
137
126
|
self,
|
138
127
|
*args: Any,
|
139
128
|
dtype: str | None = None,
|
140
|
-
shape:
|
129
|
+
shape: tuple[int, ...] | None = None,
|
141
130
|
stype: str | None = None,
|
142
131
|
data: bytes | None = None,
|
143
132
|
ndarray: NDArray | None = None,
|
@@ -145,7 +134,7 @@ class Array(InflatableObject):
|
|
145
134
|
) -> None:
|
146
135
|
# Determine the initialization method and validate input arguments.
|
147
136
|
# Support three initialization formats:
|
148
|
-
# 1. Array(dtype: str, shape:
|
137
|
+
# 1. Array(dtype: str, shape: tuple[int, ...], stype: str, data: bytes)
|
149
138
|
# 2. Array(ndarray: NDArray)
|
150
139
|
# 3. Array(torch_tensor: torch.Tensor)
|
151
140
|
|
@@ -192,7 +181,7 @@ class Array(InflatableObject):
|
|
192
181
|
if (
|
193
182
|
len(all_args) == 4 # pylint: disable=too-many-boolean-expressions
|
194
183
|
and isinstance(all_args[0], str)
|
195
|
-
and isinstance(all_args[1],
|
184
|
+
and isinstance(all_args[1], tuple)
|
196
185
|
and all(isinstance(i, int) for i in all_args[1])
|
197
186
|
and isinstance(all_args[2], str)
|
198
187
|
and isinstance(all_args[3], bytes)
|
@@ -232,7 +221,7 @@ class Array(InflatableObject):
|
|
232
221
|
data = buffer.getvalue()
|
233
222
|
return Array(
|
234
223
|
dtype=str(ndarray.dtype),
|
235
|
-
shape=
|
224
|
+
shape=tuple(ndarray.shape),
|
236
225
|
stype=SType.NUMPY,
|
237
226
|
data=data,
|
238
227
|
)
|
@@ -302,7 +291,7 @@ class Array(InflatableObject):
|
|
302
291
|
proto_array = ArrayProto.FromString(obj_body)
|
303
292
|
return cls(
|
304
293
|
dtype=proto_array.dtype,
|
305
|
-
shape=
|
294
|
+
shape=tuple(proto_array.shape),
|
306
295
|
stype=proto_array.stype,
|
307
296
|
data=proto_array.data,
|
308
297
|
)
|
@@ -328,7 +317,7 @@ class Array(InflatableObject):
|
|
328
317
|
|
329
318
|
def __setattr__(self, name: str, value: Any) -> None:
|
330
319
|
"""Set attribute with special handling for dirty state."""
|
331
|
-
if name in ("dtype", "stype", "data"):
|
320
|
+
if name in ("dtype", "shape", "stype", "data"):
|
332
321
|
# Mark as dirty if any of the main attributes are set
|
333
322
|
self.is_dirty = True
|
334
323
|
super().__setattr__(name, value)
|
@@ -252,7 +252,7 @@ class ArrayRecord(TypedDict[str, Array], InflatableObject):
|
|
252
252
|
record = ArrayRecord()
|
253
253
|
for k, v in array_dict.items():
|
254
254
|
record[k] = Array(
|
255
|
-
dtype=v.dtype, shape=
|
255
|
+
dtype=v.dtype, shape=tuple(v.shape), stype=v.stype, data=v.data
|
256
256
|
)
|
257
257
|
if not keep_input:
|
258
258
|
array_dict.clear()
|
flwr/common/recorddict_compat.py
CHANGED
@@ -111,12 +111,12 @@ def parameters_to_arrayrecord(parameters: Parameters, keep_input: bool) -> Array
|
|
111
111
|
else:
|
112
112
|
tensor = parameters.tensors.pop(0)
|
113
113
|
ordered_dict[str(idx)] = Array(
|
114
|
-
data=tensor, dtype="", stype=tensor_type, shape=
|
114
|
+
data=tensor, dtype="", stype=tensor_type, shape=()
|
115
115
|
)
|
116
116
|
|
117
117
|
if num_arrays == 0:
|
118
118
|
ordered_dict[EMPTY_TENSOR_KEY] = Array(
|
119
|
-
data=b"", dtype="", stype=tensor_type, shape=
|
119
|
+
data=b"", dtype="", stype=tensor_type, shape=()
|
120
120
|
)
|
121
121
|
return ArrayRecord(ordered_dict, keep_input=keep_input)
|
122
122
|
|
flwr/common/serde.py
CHANGED
@@ -390,7 +390,7 @@ def array_from_proto(array_proto: ProtoArray) -> Array:
|
|
390
390
|
"""Deserialize Array from ProtoBuf."""
|
391
391
|
return Array(
|
392
392
|
dtype=array_proto.dtype,
|
393
|
-
shape=
|
393
|
+
shape=tuple(array_proto.shape),
|
394
394
|
stype=array_proto.stype,
|
395
395
|
data=array_proto.data,
|
396
396
|
)
|
flwr/proto/fleet_pb2.py
CHANGED
@@ -19,7 +19,7 @@ from flwr.proto import fab_pb2 as flwr_dot_proto_dot_fab__pb2
|
|
19
19
|
from flwr.proto import message_pb2 as flwr_dot_proto_dot_message__pb2
|
20
20
|
|
21
21
|
|
22
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16\x66lwr/proto/fleet.proto\x12\nflwr.proto\x1a\x1a\x66lwr/proto/heartbeat.proto\x1a\x15\x66lwr/proto/node.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x18\x66lwr/proto/message.proto\"/\n\x11\x43reateNodeRequest\x12\x1a\n\x12heartbeat_interval\x18\x01 \x01(\x01\"4\n\x12\x43reateNodeResponse\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"3\n\x11\x44\x65leteNodeRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"\x14\n\x12\x44\x65leteNodeResponse\"J\n\x13PullMessagesRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x13\n\x0bmessage_ids\x18\x02 \x03(\t\"\x87\x02\n\x14PullMessagesResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12*\n\rmessages_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.Message\x12L\n\x0fobjects_to_pull\x18\x03 \x03(\x0b\x32\x33.flwr.proto.PullMessagesResponse.ObjectsToPullEntry\x1aK\n\x12ObjectsToPullEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12$\n\x05value\x18\x02 \x01(\x0b\x32\x15.flwr.proto.ObjectIDs:\x02\x38\x01\"\
|
22
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16\x66lwr/proto/fleet.proto\x12\nflwr.proto\x1a\x1a\x66lwr/proto/heartbeat.proto\x1a\x15\x66lwr/proto/node.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x18\x66lwr/proto/message.proto\"/\n\x11\x43reateNodeRequest\x12\x1a\n\x12heartbeat_interval\x18\x01 \x01(\x01\"4\n\x12\x43reateNodeResponse\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"3\n\x11\x44\x65leteNodeRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"\x14\n\x12\x44\x65leteNodeResponse\"J\n\x13PullMessagesRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x13\n\x0bmessage_ids\x18\x02 \x03(\t\"\x87\x02\n\x14PullMessagesResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12*\n\rmessages_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.Message\x12L\n\x0fobjects_to_pull\x18\x03 \x03(\x0b\x32\x33.flwr.proto.PullMessagesResponse.ObjectsToPullEntry\x1aK\n\x12ObjectsToPullEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12$\n\x05value\x18\x02 \x01(\x0b\x32\x15.flwr.proto.ObjectIDs:\x02\x38\x01\"\x97\x02\n\x13PushMessagesRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12*\n\rmessages_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.Message\x12^\n\x19msg_to_descendant_mapping\x18\x03 \x03(\x0b\x32;.flwr.proto.PushMessagesRequest.MsgToDescendantMappingEntry\x1aT\n\x1bMsgToDescendantMappingEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12$\n\x05value\x18\x02 \x01(\x0b\x32\x15.flwr.proto.ObjectIDs:\x02\x38\x01\"\xcb\x02\n\x14PushMessagesResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12>\n\x07results\x18\x02 \x03(\x0b\x32-.flwr.proto.PushMessagesResponse.ResultsEntry\x12L\n\x0fobjects_to_push\x18\x03 \x03(\x0b\x32\x33.flwr.proto.PushMessagesResponse.ObjectsToPushEntry\x1a.\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\r:\x02\x38\x01\x1aK\n\x12ObjectsToPushEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12$\n\x05value\x18\x02 \x01(\x0b\x32\x15.flwr.proto.ObjectIDs:\x02\x38\x01\"\x1e\n\tReconnect\x12\x11\n\treconnect\x18\x01 \x01(\x04\x32\xd7\x05\n\x05\x46leet\x12M\n\nCreateNode\x12\x1d.flwr.proto.CreateNodeRequest\x1a\x1e.flwr.proto.CreateNodeResponse\"\x00\x12M\n\nDeleteNode\x12\x1d.flwr.proto.DeleteNodeRequest\x1a\x1e.flwr.proto.DeleteNodeResponse\"\x00\x12\x62\n\x11SendNodeHeartbeat\x12$.flwr.proto.SendNodeHeartbeatRequest\x1a%.flwr.proto.SendNodeHeartbeatResponse\"\x00\x12S\n\x0cPullMessages\x12\x1f.flwr.proto.PullMessagesRequest\x1a .flwr.proto.PullMessagesResponse\"\x00\x12S\n\x0cPushMessages\x12\x1f.flwr.proto.PushMessagesRequest\x1a .flwr.proto.PushMessagesResponse\"\x00\x12\x41\n\x06GetRun\x12\x19.flwr.proto.GetRunRequest\x1a\x1a.flwr.proto.GetRunResponse\"\x00\x12\x41\n\x06GetFab\x12\x19.flwr.proto.GetFabRequest\x1a\x1a.flwr.proto.GetFabResponse\"\x00\x12M\n\nPushObject\x12\x1d.flwr.proto.PushObjectRequest\x1a\x1e.flwr.proto.PushObjectResponse\"\x00\x12M\n\nPullObject\x12\x1d.flwr.proto.PullObjectRequest\x1a\x1e.flwr.proto.PullObjectResponse\"\x00\x62\x06proto3')
|
23
23
|
|
24
24
|
_globals = globals()
|
25
25
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
@@ -28,8 +28,8 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
28
28
|
DESCRIPTOR._options = None
|
29
29
|
_globals['_PULLMESSAGESRESPONSE_OBJECTSTOPULLENTRY']._options = None
|
30
30
|
_globals['_PULLMESSAGESRESPONSE_OBJECTSTOPULLENTRY']._serialized_options = b'8\001'
|
31
|
-
_globals['
|
32
|
-
_globals['
|
31
|
+
_globals['_PUSHMESSAGESREQUEST_MSGTODESCENDANTMAPPINGENTRY']._options = None
|
32
|
+
_globals['_PUSHMESSAGESREQUEST_MSGTODESCENDANTMAPPINGENTRY']._serialized_options = b'8\001'
|
33
33
|
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._options = None
|
34
34
|
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_options = b'8\001'
|
35
35
|
_globals['_PUSHMESSAGESRESPONSE_OBJECTSTOPUSHENTRY']._options = None
|
@@ -49,17 +49,17 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
49
49
|
_globals['_PULLMESSAGESRESPONSE_OBJECTSTOPULLENTRY']._serialized_start=602
|
50
50
|
_globals['_PULLMESSAGESRESPONSE_OBJECTSTOPULLENTRY']._serialized_end=677
|
51
51
|
_globals['_PUSHMESSAGESREQUEST']._serialized_start=680
|
52
|
-
_globals['_PUSHMESSAGESREQUEST']._serialized_end=
|
53
|
-
_globals['
|
54
|
-
_globals['
|
55
|
-
_globals['_PUSHMESSAGESRESPONSE']._serialized_start=
|
56
|
-
_globals['_PUSHMESSAGESRESPONSE']._serialized_end=
|
57
|
-
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_start=
|
58
|
-
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_end=
|
59
|
-
_globals['_PUSHMESSAGESRESPONSE_OBJECTSTOPUSHENTRY']._serialized_start=
|
60
|
-
_globals['_PUSHMESSAGESRESPONSE_OBJECTSTOPUSHENTRY']._serialized_end=
|
61
|
-
_globals['_RECONNECT']._serialized_start=
|
62
|
-
_globals['_RECONNECT']._serialized_end=
|
63
|
-
_globals['_FLEET']._serialized_start=
|
64
|
-
_globals['_FLEET']._serialized_end=
|
52
|
+
_globals['_PUSHMESSAGESREQUEST']._serialized_end=959
|
53
|
+
_globals['_PUSHMESSAGESREQUEST_MSGTODESCENDANTMAPPINGENTRY']._serialized_start=875
|
54
|
+
_globals['_PUSHMESSAGESREQUEST_MSGTODESCENDANTMAPPINGENTRY']._serialized_end=959
|
55
|
+
_globals['_PUSHMESSAGESRESPONSE']._serialized_start=962
|
56
|
+
_globals['_PUSHMESSAGESRESPONSE']._serialized_end=1293
|
57
|
+
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_start=1170
|
58
|
+
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_end=1216
|
59
|
+
_globals['_PUSHMESSAGESRESPONSE_OBJECTSTOPUSHENTRY']._serialized_start=1218
|
60
|
+
_globals['_PUSHMESSAGESRESPONSE_OBJECTSTOPUSHENTRY']._serialized_end=1293
|
61
|
+
_globals['_RECONNECT']._serialized_start=1295
|
62
|
+
_globals['_RECONNECT']._serialized_end=1325
|
63
|
+
_globals['_FLEET']._serialized_start=1328
|
64
|
+
_globals['_FLEET']._serialized_end=2055
|
65
65
|
# @@protoc_insertion_point(module_scope)
|
flwr/proto/fleet_pb2.pyi
CHANGED
@@ -115,7 +115,7 @@ global___PullMessagesResponse = PullMessagesResponse
|
|
115
115
|
class PushMessagesRequest(google.protobuf.message.Message):
|
116
116
|
"""PushMessages messages"""
|
117
117
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
118
|
-
class
|
118
|
+
class MsgToDescendantMappingEntry(google.protobuf.message.Message):
|
119
119
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
120
120
|
KEY_FIELD_NUMBER: builtins.int
|
121
121
|
VALUE_FIELD_NUMBER: builtins.int
|
@@ -132,21 +132,21 @@ class PushMessagesRequest(google.protobuf.message.Message):
|
|
132
132
|
|
133
133
|
NODE_FIELD_NUMBER: builtins.int
|
134
134
|
MESSAGES_LIST_FIELD_NUMBER: builtins.int
|
135
|
-
|
135
|
+
MSG_TO_DESCENDANT_MAPPING_FIELD_NUMBER: builtins.int
|
136
136
|
@property
|
137
137
|
def node(self) -> flwr.proto.node_pb2.Node: ...
|
138
138
|
@property
|
139
139
|
def messages_list(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[flwr.proto.message_pb2.Message]: ...
|
140
140
|
@property
|
141
|
-
def
|
141
|
+
def msg_to_descendant_mapping(self) -> google.protobuf.internal.containers.MessageMap[typing.Text, flwr.proto.message_pb2.ObjectIDs]: ...
|
142
142
|
def __init__(self,
|
143
143
|
*,
|
144
144
|
node: typing.Optional[flwr.proto.node_pb2.Node] = ...,
|
145
145
|
messages_list: typing.Optional[typing.Iterable[flwr.proto.message_pb2.Message]] = ...,
|
146
|
-
|
146
|
+
msg_to_descendant_mapping: typing.Optional[typing.Mapping[typing.Text, flwr.proto.message_pb2.ObjectIDs]] = ...,
|
147
147
|
) -> None: ...
|
148
148
|
def HasField(self, field_name: typing_extensions.Literal["node",b"node"]) -> builtins.bool: ...
|
149
|
-
def ClearField(self, field_name: typing_extensions.Literal["messages_list",b"messages_list","
|
149
|
+
def ClearField(self, field_name: typing_extensions.Literal["messages_list",b"messages_list","msg_to_descendant_mapping",b"msg_to_descendant_mapping","node",b"node"]) -> None: ...
|
150
150
|
global___PushMessagesRequest = PushMessagesRequest
|
151
151
|
|
152
152
|
class PushMessagesResponse(google.protobuf.message.Message):
|
flwr/proto/message_pb2.py
CHANGED
@@ -18,7 +18,7 @@ from flwr.proto import transport_pb2 as flwr_dot_proto_dot_transport__pb2
|
|
18
18
|
from flwr.proto import node_pb2 as flwr_dot_proto_dot_node__pb2
|
19
19
|
|
20
20
|
|
21
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18\x66lwr/proto/message.proto\x12\nflwr.proto\x1a\x16\x66lwr/proto/error.proto\x1a\x1b\x66lwr/proto/recorddict.proto\x1a\x1a\x66lwr/proto/transport.proto\x1a\x15\x66lwr/proto/node.proto\"|\n\x07Message\x12&\n\x08metadata\x18\x01 \x01(\x0b\x32\x14.flwr.proto.Metadata\x12\'\n\x07\x63ontent\x18\x02 \x01(\x0b\x32\x16.flwr.proto.RecordDict\x12 \n\x05\x65rror\x18\x03 \x01(\x0b\x32\x11.flwr.proto.Error\"\xd0\x02\n\x07\x43ontext\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x0f\n\x07node_id\x18\x02 \x01(\x04\x12\x38\n\x0bnode_config\x18\x03 \x03(\x0b\x32#.flwr.proto.Context.NodeConfigEntry\x12%\n\x05state\x18\x04 \x01(\x0b\x32\x16.flwr.proto.RecordDict\x12\x36\n\nrun_config\x18\x05 \x03(\x0b\x32\".flwr.proto.Context.RunConfigEntry\x1a\x45\n\x0fNodeConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\x1a\x44\n\x0eRunConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\"\xbe\x01\n\x08Metadata\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x12\n\nmessage_id\x18\x02 \x01(\t\x12\x13\n\x0bsrc_node_id\x18\x03 \x01(\x04\x12\x13\n\x0b\x64st_node_id\x18\x04 \x01(\x04\x12\x1b\n\x13reply_to_message_id\x18\x05 \x01(\t\x12\x10\n\x08group_id\x18\x06 \x01(\t\x12\x0b\n\x03ttl\x18\x07 \x01(\x01\x12\x14\n\x0cmessage_type\x18\x08 \x01(\t\x12\x12\n\ncreated_at\x18\t \x01(\x01\"\
|
21
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18\x66lwr/proto/message.proto\x12\nflwr.proto\x1a\x16\x66lwr/proto/error.proto\x1a\x1b\x66lwr/proto/recorddict.proto\x1a\x1a\x66lwr/proto/transport.proto\x1a\x15\x66lwr/proto/node.proto\"|\n\x07Message\x12&\n\x08metadata\x18\x01 \x01(\x0b\x32\x14.flwr.proto.Metadata\x12\'\n\x07\x63ontent\x18\x02 \x01(\x0b\x32\x16.flwr.proto.RecordDict\x12 \n\x05\x65rror\x18\x03 \x01(\x0b\x32\x11.flwr.proto.Error\"\xd0\x02\n\x07\x43ontext\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x0f\n\x07node_id\x18\x02 \x01(\x04\x12\x38\n\x0bnode_config\x18\x03 \x03(\x0b\x32#.flwr.proto.Context.NodeConfigEntry\x12%\n\x05state\x18\x04 \x01(\x0b\x32\x16.flwr.proto.RecordDict\x12\x36\n\nrun_config\x18\x05 \x03(\x0b\x32\".flwr.proto.Context.RunConfigEntry\x1a\x45\n\x0fNodeConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\x1a\x44\n\x0eRunConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\"\xbe\x01\n\x08Metadata\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x12\n\nmessage_id\x18\x02 \x01(\t\x12\x13\n\x0bsrc_node_id\x18\x03 \x01(\x04\x12\x13\n\x0b\x64st_node_id\x18\x04 \x01(\x04\x12\x1b\n\x13reply_to_message_id\x18\x05 \x01(\t\x12\x10\n\x08group_id\x18\x06 \x01(\t\x12\x0b\n\x03ttl\x18\x07 \x01(\x01\x12\x14\n\x0cmessage_type\x18\x08 \x01(\t\x12\x12\n\ncreated_at\x18\t \x01(\x01\"\x1f\n\tObjectIDs\x12\x12\n\nobject_ids\x18\x01 \x03(\t\"^\n\x11PushObjectRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x11\n\tobject_id\x18\x02 \x01(\t\x12\x16\n\x0eobject_content\x18\x03 \x01(\x0c\"\x14\n\x12PushObjectResponse\"F\n\x11PullObjectRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x11\n\tobject_id\x18\x02 \x01(\t\",\n\x12PullObjectResponse\x12\x16\n\x0eobject_content\x18\x01 \x01(\x0c\x62\x06proto3')
|
22
22
|
|
23
23
|
_globals = globals()
|
24
24
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
@@ -40,13 +40,13 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
40
40
|
_globals['_METADATA']._serialized_start=610
|
41
41
|
_globals['_METADATA']._serialized_end=800
|
42
42
|
_globals['_OBJECTIDS']._serialized_start=802
|
43
|
-
_globals['_OBJECTIDS']._serialized_end=
|
44
|
-
_globals['_PUSHOBJECTREQUEST']._serialized_start=
|
45
|
-
_globals['_PUSHOBJECTREQUEST']._serialized_end=
|
46
|
-
_globals['_PUSHOBJECTRESPONSE']._serialized_start=
|
47
|
-
_globals['_PUSHOBJECTRESPONSE']._serialized_end=
|
48
|
-
_globals['_PULLOBJECTREQUEST']._serialized_start=
|
49
|
-
_globals['_PULLOBJECTREQUEST']._serialized_end=
|
50
|
-
_globals['_PULLOBJECTRESPONSE']._serialized_start=
|
51
|
-
_globals['_PULLOBJECTRESPONSE']._serialized_end=
|
43
|
+
_globals['_OBJECTIDS']._serialized_end=833
|
44
|
+
_globals['_PUSHOBJECTREQUEST']._serialized_start=835
|
45
|
+
_globals['_PUSHOBJECTREQUEST']._serialized_end=929
|
46
|
+
_globals['_PUSHOBJECTRESPONSE']._serialized_start=931
|
47
|
+
_globals['_PUSHOBJECTRESPONSE']._serialized_end=951
|
48
|
+
_globals['_PULLOBJECTREQUEST']._serialized_start=953
|
49
|
+
_globals['_PULLOBJECTREQUEST']._serialized_end=1023
|
50
|
+
_globals['_PULLOBJECTRESPONSE']._serialized_start=1025
|
51
|
+
_globals['_PULLOBJECTRESPONSE']._serialized_end=1069
|
52
52
|
# @@protoc_insertion_point(module_scope)
|
flwr/proto/message_pb2.pyi
CHANGED
@@ -130,14 +130,14 @@ global___Metadata = Metadata
|
|
130
130
|
|
131
131
|
class ObjectIDs(google.protobuf.message.Message):
|
132
132
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
133
|
-
|
133
|
+
OBJECT_IDS_FIELD_NUMBER: builtins.int
|
134
134
|
@property
|
135
|
-
def
|
135
|
+
def object_ids(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[typing.Text]: ...
|
136
136
|
def __init__(self,
|
137
137
|
*,
|
138
|
-
|
138
|
+
object_ids: typing.Optional[typing.Iterable[typing.Text]] = ...,
|
139
139
|
) -> None: ...
|
140
|
-
def ClearField(self, field_name: typing_extensions.Literal["
|
140
|
+
def ClearField(self, field_name: typing_extensions.Literal["object_ids",b"object_ids"]) -> None: ...
|
141
141
|
global___ObjectIDs = ObjectIDs
|
142
142
|
|
143
143
|
class PushObjectRequest(google.protobuf.message.Message):
|