flwr 1.18.0__py3-none-any.whl → 1.19.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.
- flwr/app/__init__.py +15 -0
- flwr/app/error.py +68 -0
- flwr/app/metadata.py +223 -0
- flwr/cli/build.py +82 -57
- flwr/cli/log.py +3 -3
- flwr/cli/login/login.py +3 -7
- flwr/cli/ls.py +15 -36
- flwr/cli/new/templates/app/code/client.baseline.py.tpl +1 -1
- flwr/cli/new/templates/app/code/model.baseline.py.tpl +1 -1
- flwr/cli/new/templates/app/code/server.baseline.py.tpl +2 -3
- flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +14 -17
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.jax.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +1 -1
- flwr/cli/run/run.py +10 -18
- flwr/cli/stop.py +2 -2
- flwr/cli/utils.py +31 -5
- flwr/client/__init__.py +2 -2
- flwr/client/client_app.py +1 -1
- flwr/client/clientapp/__init__.py +0 -7
- flwr/client/grpc_adapter_client/connection.py +4 -4
- flwr/client/grpc_rere_client/connection.py +130 -60
- flwr/client/grpc_rere_client/grpc_adapter.py +34 -6
- flwr/client/message_handler/message_handler.py +1 -1
- flwr/client/mod/comms_mods.py +36 -17
- flwr/client/rest_client/connection.py +173 -67
- flwr/clientapp/__init__.py +15 -0
- flwr/common/__init__.py +2 -2
- flwr/common/auth_plugin/__init__.py +2 -0
- flwr/common/auth_plugin/auth_plugin.py +29 -3
- flwr/common/constant.py +36 -7
- flwr/common/event_log_plugin/event_log_plugin.py +3 -3
- flwr/common/exit_handlers.py +30 -0
- flwr/common/heartbeat.py +165 -0
- flwr/common/inflatable.py +290 -0
- flwr/common/inflatable_grpc_utils.py +99 -0
- flwr/common/inflatable_rest_utils.py +99 -0
- flwr/common/inflatable_utils.py +341 -0
- flwr/common/message.py +110 -242
- flwr/common/record/__init__.py +2 -1
- flwr/common/record/array.py +323 -0
- flwr/common/record/arrayrecord.py +103 -225
- flwr/common/record/configrecord.py +59 -4
- flwr/common/record/conversion_utils.py +1 -1
- flwr/common/record/metricrecord.py +55 -4
- flwr/common/record/recorddict.py +69 -1
- flwr/common/recorddict_compat.py +2 -2
- flwr/common/retry_invoker.py +5 -1
- flwr/common/serde.py +59 -183
- flwr/common/serde_utils.py +175 -0
- flwr/common/typing.py +5 -3
- flwr/compat/__init__.py +15 -0
- flwr/compat/client/__init__.py +15 -0
- flwr/{client → compat/client}/app.py +19 -159
- flwr/compat/common/__init__.py +15 -0
- flwr/compat/server/__init__.py +15 -0
- flwr/compat/server/app.py +174 -0
- flwr/compat/simulation/__init__.py +15 -0
- flwr/proto/fleet_pb2.py +32 -27
- flwr/proto/fleet_pb2.pyi +49 -35
- flwr/proto/fleet_pb2_grpc.py +117 -13
- flwr/proto/fleet_pb2_grpc.pyi +47 -6
- flwr/proto/heartbeat_pb2.py +33 -0
- flwr/proto/heartbeat_pb2.pyi +66 -0
- flwr/proto/heartbeat_pb2_grpc.py +4 -0
- flwr/proto/heartbeat_pb2_grpc.pyi +4 -0
- flwr/proto/message_pb2.py +28 -11
- flwr/proto/message_pb2.pyi +125 -0
- flwr/proto/recorddict_pb2.py +16 -28
- flwr/proto/recorddict_pb2.pyi +46 -64
- flwr/proto/run_pb2.py +24 -32
- flwr/proto/run_pb2.pyi +4 -52
- flwr/proto/serverappio_pb2.py +32 -23
- flwr/proto/serverappio_pb2.pyi +45 -3
- flwr/proto/serverappio_pb2_grpc.py +138 -34
- flwr/proto/serverappio_pb2_grpc.pyi +54 -13
- flwr/proto/simulationio_pb2.py +12 -11
- flwr/proto/simulationio_pb2_grpc.py +35 -0
- flwr/proto/simulationio_pb2_grpc.pyi +14 -0
- flwr/server/__init__.py +1 -1
- flwr/server/app.py +68 -186
- flwr/server/compat/app_utils.py +50 -28
- flwr/server/fleet_event_log_interceptor.py +2 -2
- flwr/server/grid/grpc_grid.py +104 -34
- flwr/server/grid/inmemory_grid.py +5 -4
- flwr/server/serverapp/app.py +18 -0
- flwr/server/superlink/ffs/__init__.py +2 -0
- flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +13 -3
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +101 -7
- flwr/server/superlink/fleet/message_handler/message_handler.py +135 -18
- flwr/server/superlink/fleet/rest_rere/rest_api.py +72 -11
- flwr/server/superlink/fleet/vce/vce_api.py +6 -3
- flwr/server/superlink/linkstate/in_memory_linkstate.py +138 -43
- flwr/server/superlink/linkstate/linkstate.py +53 -20
- flwr/server/superlink/linkstate/sqlite_linkstate.py +149 -55
- flwr/server/superlink/linkstate/utils.py +33 -29
- flwr/server/superlink/serverappio/serverappio_grpc.py +3 -0
- flwr/server/superlink/serverappio/serverappio_servicer.py +211 -57
- flwr/server/superlink/simulation/simulationio_servicer.py +25 -1
- flwr/server/superlink/utils.py +44 -2
- flwr/server/utils/validator.py +2 -2
- flwr/serverapp/__init__.py +15 -0
- flwr/simulation/app.py +17 -0
- flwr/supercore/__init__.py +15 -0
- flwr/supercore/object_store/__init__.py +24 -0
- flwr/supercore/object_store/in_memory_object_store.py +229 -0
- flwr/supercore/object_store/object_store.py +192 -0
- flwr/supercore/object_store/object_store_factory.py +44 -0
- flwr/superexec/deployment.py +6 -2
- flwr/superexec/exec_event_log_interceptor.py +4 -4
- flwr/superexec/exec_grpc.py +7 -3
- flwr/superexec/exec_servicer.py +125 -23
- flwr/superexec/exec_user_auth_interceptor.py +37 -8
- flwr/superexec/executor.py +4 -0
- flwr/superexec/simulation.py +7 -1
- flwr/superlink/__init__.py +15 -0
- flwr/{client/supernode → supernode}/__init__.py +0 -7
- flwr/{client/nodestate/nodestate.py → supernode/cli/__init__.py} +7 -14
- flwr/{client/supernode/app.py → supernode/cli/flower_supernode.py} +3 -12
- flwr/supernode/cli/flwr_clientapp.py +81 -0
- flwr/supernode/nodestate/in_memory_nodestate.py +190 -0
- flwr/supernode/nodestate/nodestate.py +212 -0
- flwr/supernode/runtime/__init__.py +15 -0
- flwr/{client/clientapp/app.py → supernode/runtime/run_clientapp.py} +25 -56
- flwr/supernode/servicer/__init__.py +15 -0
- flwr/supernode/servicer/clientappio/__init__.py +24 -0
- flwr/supernode/start_client_internal.py +491 -0
- {flwr-1.18.0.dist-info → flwr-1.19.0.dist-info}/METADATA +5 -4
- {flwr-1.18.0.dist-info → flwr-1.19.0.dist-info}/RECORD +141 -108
- {flwr-1.18.0.dist-info → flwr-1.19.0.dist-info}/WHEEL +1 -1
- {flwr-1.18.0.dist-info → flwr-1.19.0.dist-info}/entry_points.txt +2 -2
- flwr/client/heartbeat.py +0 -74
- flwr/client/nodestate/in_memory_nodestate.py +0 -38
- /flwr/{client → compat/client}/grpc_client/__init__.py +0 -0
- /flwr/{client → compat/client}/grpc_client/connection.py +0 -0
- /flwr/{client → supernode}/nodestate/__init__.py +0 -0
- /flwr/{client → supernode}/nodestate/nodestate_factory.py +0 -0
- /flwr/{client/clientapp → supernode/servicer/clientappio}/clientappio_servicer.py +0 -0
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
"""$project_name: A Flower Baseline."""
|
|
2
2
|
|
|
3
|
-
from typing import List, Tuple
|
|
4
|
-
|
|
5
3
|
from flwr.common import Context, Metrics, ndarrays_to_parameters
|
|
6
4
|
from flwr.server import ServerApp, ServerAppComponents, ServerConfig
|
|
7
5
|
from flwr.server.strategy import FedAvg
|
|
6
|
+
|
|
8
7
|
from $import_name.model import Net, get_weights
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
# Define metric aggregation function
|
|
12
|
-
def weighted_average(metrics:
|
|
11
|
+
def weighted_average(metrics: list[tuple[int, Metrics]]) -> Metrics:
|
|
13
12
|
"""Do weighted average of accuracy metric."""
|
|
14
13
|
# Multiply accuracy of each client by number of examples used
|
|
15
14
|
accuracies = [num_examples * float(m["accuracy"]) for num_examples, m in metrics]
|
|
@@ -8,10 +8,10 @@ version = "1.0.0"
|
|
|
8
8
|
description = ""
|
|
9
9
|
license = "Apache-2.0"
|
|
10
10
|
dependencies = [
|
|
11
|
-
"flwr[simulation]>=1.
|
|
11
|
+
"flwr[simulation]>=1.19.0",
|
|
12
12
|
"flwr-datasets[vision]>=0.5.0",
|
|
13
|
-
"torch==2.
|
|
14
|
-
"torchvision==0.
|
|
13
|
+
"torch==2.6.0",
|
|
14
|
+
"torchvision==0.21.0",
|
|
15
15
|
]
|
|
16
16
|
|
|
17
17
|
[tool.hatch.metadata]
|
|
@@ -23,28 +23,23 @@ dev = [
|
|
|
23
23
|
"black==24.2.0",
|
|
24
24
|
"docformatter==1.7.5",
|
|
25
25
|
"mypy==1.8.0",
|
|
26
|
-
"pylint==3.
|
|
27
|
-
"
|
|
28
|
-
"pytest==6.2.4",
|
|
26
|
+
"pylint==3.3.1",
|
|
27
|
+
"pytest==7.4.4",
|
|
29
28
|
"pytest-watch==4.2.0",
|
|
30
|
-
"ruff==0.
|
|
29
|
+
"ruff==0.4.5",
|
|
31
30
|
"types-requests==2.31.0.20240125",
|
|
32
31
|
]
|
|
33
32
|
|
|
34
33
|
[tool.isort]
|
|
35
34
|
profile = "black"
|
|
36
|
-
known_first_party = ["flwr"]
|
|
37
35
|
|
|
38
36
|
[tool.black]
|
|
39
37
|
line-length = 88
|
|
40
|
-
target-version = ["
|
|
38
|
+
target-version = ["py310", "py311", "py312"]
|
|
41
39
|
|
|
42
40
|
[tool.pytest.ini_options]
|
|
43
41
|
minversion = "6.2"
|
|
44
42
|
addopts = "-qq"
|
|
45
|
-
testpaths = [
|
|
46
|
-
"flwr_baselines",
|
|
47
|
-
]
|
|
48
43
|
|
|
49
44
|
[tool.mypy]
|
|
50
45
|
ignore_missing_imports = true
|
|
@@ -82,11 +77,8 @@ wrap-summaries = 88
|
|
|
82
77
|
wrap-descriptions = 88
|
|
83
78
|
|
|
84
79
|
[tool.ruff]
|
|
85
|
-
target-version = "
|
|
80
|
+
target-version = "py310"
|
|
86
81
|
line-length = 88
|
|
87
|
-
select = ["D", "E", "F", "W", "B", "ISC", "C4"]
|
|
88
|
-
fixable = ["D", "E", "F", "W", "B", "ISC", "C4"]
|
|
89
|
-
ignore = ["B024", "B027"]
|
|
90
82
|
exclude = [
|
|
91
83
|
".bzr",
|
|
92
84
|
".direnv",
|
|
@@ -111,7 +103,12 @@ exclude = [
|
|
|
111
103
|
"proto",
|
|
112
104
|
]
|
|
113
105
|
|
|
114
|
-
[tool.ruff.
|
|
106
|
+
[tool.ruff.lint]
|
|
107
|
+
select = ["D", "E", "F", "W", "B", "ISC", "C4", "UP"]
|
|
108
|
+
fixable = ["D", "E", "F", "W", "B", "ISC", "C4", "UP"]
|
|
109
|
+
ignore = ["B024", "B027", "D205", "D209"]
|
|
110
|
+
|
|
111
|
+
[tool.ruff.lint.pydocstyle]
|
|
115
112
|
convention = "numpy"
|
|
116
113
|
|
|
117
114
|
[tool.hatch.build.targets.wheel]
|
flwr/cli/run/run.py
CHANGED
|
@@ -24,9 +24,8 @@ from typing import Annotated, Any, Optional
|
|
|
24
24
|
import typer
|
|
25
25
|
from rich.console import Console
|
|
26
26
|
|
|
27
|
-
from flwr.cli.build import
|
|
27
|
+
from flwr.cli.build import build_fab, get_fab_filename
|
|
28
28
|
from flwr.cli.config_utils import (
|
|
29
|
-
get_fab_metadata,
|
|
30
29
|
load_and_validate,
|
|
31
30
|
process_loaded_project_config,
|
|
32
31
|
validate_federation_in_project_config,
|
|
@@ -34,6 +33,7 @@ from flwr.cli.config_utils import (
|
|
|
34
33
|
from flwr.cli.constant import FEDERATION_CONFIG_HELP_MESSAGE
|
|
35
34
|
from flwr.common.config import (
|
|
36
35
|
flatten_dict,
|
|
36
|
+
get_metadata_from_config,
|
|
37
37
|
parse_config_args,
|
|
38
38
|
user_config_to_configrecord,
|
|
39
39
|
)
|
|
@@ -45,11 +45,7 @@ from flwr.proto.exec_pb2 import StartRunRequest # pylint: disable=E0611
|
|
|
45
45
|
from flwr.proto.exec_pb2_grpc import ExecStub
|
|
46
46
|
|
|
47
47
|
from ..log import start_stream
|
|
48
|
-
from ..utils import
|
|
49
|
-
init_channel,
|
|
50
|
-
try_obtain_cli_auth_plugin,
|
|
51
|
-
unauthenticated_exc_handler,
|
|
52
|
-
)
|
|
48
|
+
from ..utils import flwr_cli_grpc_exc_handler, init_channel, try_obtain_cli_auth_plugin
|
|
53
49
|
|
|
54
50
|
CONN_REFRESH_PERIOD = 60 # Connection refresh period for log streaming (seconds)
|
|
55
51
|
|
|
@@ -158,25 +154,21 @@ def _run_with_exec_api(
|
|
|
158
154
|
channel = init_channel(app, federation_config, auth_plugin)
|
|
159
155
|
stub = ExecStub(channel)
|
|
160
156
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
fab_id, fab_version = get_fab_metadata(Path(fab_path))
|
|
164
|
-
|
|
165
|
-
# Delete FAB file once the bytes is computed
|
|
166
|
-
Path(fab_path).unlink()
|
|
157
|
+
fab_bytes, fab_hash, config = build_fab(app)
|
|
158
|
+
fab_id, fab_version = get_metadata_from_config(config)
|
|
167
159
|
|
|
168
|
-
fab = Fab(fab_hash,
|
|
160
|
+
fab = Fab(fab_hash, fab_bytes)
|
|
169
161
|
|
|
170
162
|
# Construct a `ConfigRecord` out of a flattened `UserConfig`
|
|
171
|
-
|
|
172
|
-
c_record = user_config_to_configrecord(
|
|
163
|
+
fed_config = flatten_dict(federation_config.get("options", {}))
|
|
164
|
+
c_record = user_config_to_configrecord(fed_config)
|
|
173
165
|
|
|
174
166
|
req = StartRunRequest(
|
|
175
167
|
fab=fab_to_proto(fab),
|
|
176
168
|
override_config=user_config_to_proto(parse_config_args(config_overrides)),
|
|
177
169
|
federation_options=config_record_to_proto(c_record),
|
|
178
170
|
)
|
|
179
|
-
with
|
|
171
|
+
with flwr_cli_grpc_exc_handler():
|
|
180
172
|
res = stub.StartRun(req)
|
|
181
173
|
|
|
182
174
|
if res.HasField("run_id"):
|
|
@@ -194,7 +186,7 @@ def _run_with_exec_api(
|
|
|
194
186
|
"fab-name": fab_id.rsplit("/", maxsplit=1)[-1],
|
|
195
187
|
"fab-version": fab_version,
|
|
196
188
|
"fab-hash": fab_hash[:8],
|
|
197
|
-
"fab-filename":
|
|
189
|
+
"fab-filename": get_fab_filename(config, fab_hash),
|
|
198
190
|
}
|
|
199
191
|
)
|
|
200
192
|
restore_output()
|
flwr/cli/stop.py
CHANGED
|
@@ -35,7 +35,7 @@ from flwr.common.logger import print_json_error, redirect_output, restore_output
|
|
|
35
35
|
from flwr.proto.exec_pb2 import StopRunRequest, StopRunResponse # pylint: disable=E0611
|
|
36
36
|
from flwr.proto.exec_pb2_grpc import ExecStub
|
|
37
37
|
|
|
38
|
-
from .utils import init_channel, try_obtain_cli_auth_plugin
|
|
38
|
+
from .utils import flwr_cli_grpc_exc_handler, init_channel, try_obtain_cli_auth_plugin
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
def stop( # pylint: disable=R0914
|
|
@@ -122,7 +122,7 @@ def stop( # pylint: disable=R0914
|
|
|
122
122
|
|
|
123
123
|
def _stop_run(stub: ExecStub, run_id: int, output_format: str) -> None:
|
|
124
124
|
"""Stop a run."""
|
|
125
|
-
with
|
|
125
|
+
with flwr_cli_grpc_exc_handler():
|
|
126
126
|
response: StopRunResponse = stub.StopRun(request=StopRunRequest(run_id=run_id))
|
|
127
127
|
if response.success:
|
|
128
128
|
typer.secho(f"✅ Run {run_id} successfully stopped.", fg=typer.colors.GREEN)
|
flwr/cli/utils.py
CHANGED
|
@@ -28,7 +28,12 @@ import typer
|
|
|
28
28
|
|
|
29
29
|
from flwr.cli.cli_user_auth_interceptor import CliUserAuthInterceptor
|
|
30
30
|
from flwr.common.auth_plugin import CliAuthPlugin
|
|
31
|
-
from flwr.common.constant import
|
|
31
|
+
from flwr.common.constant import (
|
|
32
|
+
AUTH_TYPE_JSON_KEY,
|
|
33
|
+
CREDENTIALS_DIR,
|
|
34
|
+
FLWR_DIR,
|
|
35
|
+
RUN_ID_NOT_FOUND_MESSAGE,
|
|
36
|
+
)
|
|
32
37
|
from flwr.common.grpc import (
|
|
33
38
|
GRPC_MAX_MESSAGE_LENGTH,
|
|
34
39
|
create_channel,
|
|
@@ -288,11 +293,12 @@ def init_channel(
|
|
|
288
293
|
|
|
289
294
|
|
|
290
295
|
@contextmanager
|
|
291
|
-
def
|
|
292
|
-
"""Context manager to handle gRPC
|
|
296
|
+
def flwr_cli_grpc_exc_handler() -> Iterator[None]:
|
|
297
|
+
"""Context manager to handle specific gRPC errors.
|
|
293
298
|
|
|
294
|
-
It catches grpc.RpcError exceptions with UNAUTHENTICATED
|
|
295
|
-
and exits the application. All other
|
|
299
|
+
It catches grpc.RpcError exceptions with UNAUTHENTICATED, UNIMPLEMENTED, and
|
|
300
|
+
PERMISSION_DENIED statuses, informs the user, and exits the application. All other
|
|
301
|
+
exceptions will be allowed to escape.
|
|
296
302
|
"""
|
|
297
303
|
try:
|
|
298
304
|
yield
|
|
@@ -312,4 +318,24 @@ def unauthenticated_exc_handler() -> Iterator[None]:
|
|
|
312
318
|
bold=True,
|
|
313
319
|
)
|
|
314
320
|
raise typer.Exit(code=1) from None
|
|
321
|
+
if e.code() == grpc.StatusCode.PERMISSION_DENIED:
|
|
322
|
+
typer.secho(
|
|
323
|
+
"❌ Authorization failed. Please contact your administrator"
|
|
324
|
+
" to check your permissions.",
|
|
325
|
+
fg=typer.colors.RED,
|
|
326
|
+
bold=True,
|
|
327
|
+
)
|
|
328
|
+
# pylint: disable=E1101
|
|
329
|
+
typer.secho(e.details(), fg=typer.colors.RED, bold=True)
|
|
330
|
+
raise typer.Exit(code=1) from None
|
|
331
|
+
if (
|
|
332
|
+
e.code() == grpc.StatusCode.NOT_FOUND
|
|
333
|
+
and e.details() == RUN_ID_NOT_FOUND_MESSAGE
|
|
334
|
+
):
|
|
335
|
+
typer.secho(
|
|
336
|
+
"❌ Run ID not found.",
|
|
337
|
+
fg=typer.colors.RED,
|
|
338
|
+
bold=True,
|
|
339
|
+
)
|
|
340
|
+
raise typer.Exit(code=1) from None
|
|
315
341
|
raise
|
flwr/client/__init__.py
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"""Flower client."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
from .app import start_client as start_client
|
|
19
|
-
from .app import start_numpy_client as start_numpy_client
|
|
18
|
+
from ..compat.client.app import start_client as start_client # Deprecated
|
|
19
|
+
from ..compat.client.app import start_numpy_client as start_numpy_client # Deprecated
|
|
20
20
|
from .client import Client as Client
|
|
21
21
|
from .client_app import ClientApp as ClientApp
|
|
22
22
|
from .numpy_client import NumPyClient as NumPyClient
|
flwr/client/client_app.py
CHANGED
|
@@ -20,6 +20,7 @@ from collections.abc import Iterator
|
|
|
20
20
|
from contextlib import contextmanager
|
|
21
21
|
from typing import Callable, Optional
|
|
22
22
|
|
|
23
|
+
from flwr.app.metadata import validate_message_type
|
|
23
24
|
from flwr.client.client import Client
|
|
24
25
|
from flwr.client.message_handler.message_handler import (
|
|
25
26
|
handle_legacy_message_from_msgtype,
|
|
@@ -28,7 +29,6 @@ from flwr.client.mod.utils import make_ffn
|
|
|
28
29
|
from flwr.client.typing import ClientFnExt, Mod
|
|
29
30
|
from flwr.common import Context, Message, MessageType
|
|
30
31
|
from flwr.common.logger import warn_deprecated_feature
|
|
31
|
-
from flwr.common.message import validate_message_type
|
|
32
32
|
|
|
33
33
|
from .typing import ClientAppCallable
|
|
34
34
|
|
|
@@ -45,10 +45,10 @@ def grpc_adapter( # pylint: disable=R0913,too-many-positional-arguments
|
|
|
45
45
|
tuple[
|
|
46
46
|
Callable[[], Optional[Message]],
|
|
47
47
|
Callable[[Message], None],
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
Callable[[], Optional[int]],
|
|
49
|
+
Callable[[], None],
|
|
50
|
+
Callable[[int], Run],
|
|
51
|
+
Callable[[str, int], Fab],
|
|
52
52
|
]
|
|
53
53
|
]:
|
|
54
54
|
"""Primitives for request/response-based interaction with a server via GrpcAdapter.
|