flwr-nightly 1.20.0.dev20250630__py3-none-any.whl → 1.20.0.dev20250701__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 CHANGED
@@ -320,8 +320,7 @@ def flwr_cli_grpc_exc_handler() -> Iterator[None]:
320
320
  raise typer.Exit(code=1) from None
321
321
  if e.code() == grpc.StatusCode.PERMISSION_DENIED:
322
322
  typer.secho(
323
- "❌ Authorization failed. Please contact your administrator"
324
- " to check your permissions.",
323
+ "❌ Permission denied. Please contact the SuperLink administrator.",
325
324
  fg=typer.colors.RED,
326
325
  bold=True,
327
326
  )
@@ -29,6 +29,7 @@ class ExitCode:
29
29
 
30
30
  # SuperLink-specific exit codes (100-199)
31
31
  SUPERLINK_THREAD_CRASH = 100
32
+ SUPERLINK_LICENSE_INVALID = 101
32
33
 
33
34
  # ServerApp-specific exit codes (200-299)
34
35
 
@@ -60,6 +61,10 @@ EXIT_CODE_HELP = {
60
61
  ExitCode.GRACEFUL_EXIT_SIGTERM: "",
61
62
  # SuperLink-specific exit codes (100-199)
62
63
  ExitCode.SUPERLINK_THREAD_CRASH: "An important background thread has crashed.",
64
+ ExitCode.SUPERLINK_LICENSE_INVALID: (
65
+ "The license is invalid or has expired. "
66
+ "Please contact `hello@flower.ai` for assistance."
67
+ ),
63
68
  # ServerApp-specific exit codes (200-299)
64
69
  # SuperNode-specific exit codes (300-399)
65
70
  ExitCode.SUPERNODE_REST_ADDRESS_INVALID: (
@@ -0,0 +1,22 @@
1
+ # Copyright 2025 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 license plugin components."""
16
+
17
+
18
+ from .license_plugin import LicensePlugin as LicensePlugin
19
+
20
+ __all__ = [
21
+ "LicensePlugin",
22
+ ]
@@ -0,0 +1,34 @@
1
+ # Copyright 2025 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
+ """Abstract class for Flower License Plugin."""
16
+
17
+
18
+ from abc import ABC, abstractmethod
19
+
20
+
21
+ class LicensePlugin(ABC):
22
+ """Abstract Flower License Plugin class."""
23
+
24
+ @abstractmethod
25
+ def __init__(self) -> None:
26
+ """Abstract constructor."""
27
+
28
+ @abstractmethod
29
+ def check_license(self) -> bool:
30
+ """Check if the license is valid."""
31
+
32
+ @abstractmethod
33
+ def get_license_info(self) -> None:
34
+ """Get information about the license."""
@@ -23,21 +23,31 @@ import grpc
23
23
  from flwr.common import GRPC_MAX_MESSAGE_LENGTH
24
24
  from flwr.common.auth_plugin import ExecAuthPlugin, ExecAuthzPlugin
25
25
  from flwr.common.event_log_plugin import EventLogWriterPlugin
26
+ from flwr.common.exit import ExitCode, flwr_exit
26
27
  from flwr.common.grpc import generic_create_grpc_server
27
28
  from flwr.common.logger import log
28
29
  from flwr.common.typing import UserConfig
29
30
  from flwr.proto.exec_pb2_grpc import add_ExecServicer_to_server
30
31
  from flwr.server.superlink.linkstate import LinkStateFactory
31
32
  from flwr.supercore.ffs import FfsFactory
33
+ from flwr.supercore.license_plugin import LicensePlugin
32
34
  from flwr.supercore.object_store import ObjectStoreFactory
33
35
  from flwr.superexec.exec_event_log_interceptor import ExecEventLogInterceptor
36
+ from flwr.superexec.exec_license_interceptor import ExecLicenseInterceptor
34
37
  from flwr.superexec.exec_user_auth_interceptor import ExecUserAuthInterceptor
35
38
 
36
39
  from .exec_servicer import ExecServicer
37
40
  from .executor import Executor
38
41
 
42
+ try:
43
+ from flwr.ee import get_license_plugin
44
+ except ImportError:
39
45
 
40
- # pylint: disable-next=too-many-arguments, too-many-positional-arguments
46
+ def get_license_plugin() -> Optional[LicensePlugin]:
47
+ """Return the license plugin."""
48
+
49
+
50
+ # pylint: disable-next=too-many-arguments,too-many-positional-arguments,too-many-locals
41
51
  def run_exec_api_grpc(
42
52
  address: str,
43
53
  executor: Executor,
@@ -53,6 +63,12 @@ def run_exec_api_grpc(
53
63
  """Run Exec API (gRPC, request-response)."""
54
64
  executor.set_config(config)
55
65
 
66
+ license_plugin: Optional[LicensePlugin] = get_license_plugin()
67
+ if license_plugin:
68
+ license_plugin.get_license_info()
69
+ if not license_plugin.check_license():
70
+ flwr_exit(ExitCode.SUPERLINK_LICENSE_INVALID)
71
+
56
72
  exec_servicer: grpc.Server = ExecServicer(
57
73
  linkstate_factory=state_factory,
58
74
  ffs_factory=ffs_factory,
@@ -61,6 +77,8 @@ def run_exec_api_grpc(
61
77
  auth_plugin=auth_plugin,
62
78
  )
63
79
  interceptors: list[grpc.ServerInterceptor] = []
80
+ if license_plugin is not None:
81
+ interceptors.append(ExecLicenseInterceptor(license_plugin))
64
82
  if auth_plugin is not None and authz_plugin is not None:
65
83
  interceptors.append(ExecUserAuthInterceptor(auth_plugin, authz_plugin))
66
84
  # Event log interceptor must be added after user auth interceptor
@@ -0,0 +1,74 @@
1
+ # Copyright 2025 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 Exec API license interceptor."""
16
+
17
+
18
+ from collections.abc import Iterator
19
+ from typing import Any, Callable, Union
20
+
21
+ import grpc
22
+ from google.protobuf.message import Message as GrpcMessage
23
+
24
+ from flwr.supercore.license_plugin import LicensePlugin
25
+
26
+
27
+ class ExecLicenseInterceptor(grpc.ServerInterceptor): # type: ignore
28
+ """Exec API interceptor for license checking."""
29
+
30
+ def __init__(self, license_plugin: LicensePlugin) -> None:
31
+ """Initialize the interceptor with a license plugin."""
32
+ self.license_plugin = license_plugin
33
+
34
+ def intercept_service(
35
+ self,
36
+ continuation: Callable[[Any], Any],
37
+ handler_call_details: grpc.HandlerCallDetails,
38
+ ) -> grpc.RpcMethodHandler:
39
+ """Flower server interceptor license logic.
40
+
41
+ Intercept all unary-unary/unary-stream calls from users and check the license.
42
+ Continue RPC call if license check is enabled and passes, else, terminate RPC
43
+ call by setting context to abort.
44
+ """
45
+ # One of the method handlers in
46
+ # `flwr.superexec.exec_servicer.ExecServicer`
47
+ method_handler: grpc.RpcMethodHandler = continuation(handler_call_details)
48
+ return self._generic_license_unary_method_handler(method_handler)
49
+
50
+ def _generic_license_unary_method_handler(
51
+ self, method_handler: grpc.RpcMethodHandler
52
+ ) -> grpc.RpcMethodHandler:
53
+ def _generic_method_handler(
54
+ request: GrpcMessage,
55
+ context: grpc.ServicerContext,
56
+ ) -> Union[GrpcMessage, Iterator[GrpcMessage]]:
57
+ """Handle the method call with license checking."""
58
+ call = method_handler.unary_unary or method_handler.unary_stream
59
+
60
+ if not self.license_plugin.check_license():
61
+ context.abort(grpc.StatusCode.PERMISSION_DENIED, "License check failed")
62
+ raise grpc.RpcError()
63
+
64
+ return call(request, context) # type: ignore
65
+
66
+ if method_handler.unary_unary:
67
+ message_handler = grpc.unary_unary_rpc_method_handler
68
+ else:
69
+ message_handler = grpc.unary_stream_rpc_method_handler
70
+ return message_handler(
71
+ _generic_method_handler,
72
+ request_deserializer=method_handler.request_deserializer,
73
+ response_serializer=method_handler.response_serializer,
74
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: flwr-nightly
3
- Version: 1.20.0.dev20250630
3
+ Version: 1.20.0.dev20250701
4
4
  Summary: Flower: A Friendly Federated AI Framework
5
5
  License: Apache-2.0
6
6
  Keywords: Artificial Intelligence,Federated AI,Federated Analytics,Federated Evaluation,Federated Learning,Flower,Machine Learning
@@ -73,7 +73,7 @@ flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl,sha256=3-gDei-K7zskh5dD
73
73
  flwr/cli/run/__init__.py,sha256=RPyB7KbYTFl6YRiilCch6oezxrLQrl1kijV7BMGkLbA,790
74
74
  flwr/cli/run/run.py,sha256=psmr215gkV0e0QtX9NFp7KUwKSA_ZwekdJmoL1zFyfw,8478
75
75
  flwr/cli/stop.py,sha256=l8DcRkA---CESVJgc7iTHLWIBAPGxWIfoem8qSU3lZQ,4972
76
- flwr/cli/utils.py,sha256=Vyxpd8LOn2tg5wwId18CHDKq2xaoFDxHMnMW0IlG9Yw,12048
76
+ flwr/cli/utils.py,sha256=X7Jdvwf70bkOpKynFgMGVYPMDxLQiSVG8Y3G1Y9iRjs,12009
77
77
  flwr/client/__init__.py,sha256=boIhKaK6I977zrILmoTutNx94x5jB0e6F1gnAjaRJnI,1250
78
78
  flwr/client/client.py,sha256=3HAchxvknKG9jYbB7swNyDj-e5vUWDuMKoLvbT7jCVM,7895
79
79
  flwr/client/client_app.py,sha256=zVhi-l3chAb06ozFsKwix3hU_RpOLjST13Ha50AVIPE,16918
@@ -118,7 +118,7 @@ flwr/common/event_log_plugin/__init__.py,sha256=ts3VAL3Fk6Grp1EK_1Qg_V-BfOof9F86
118
118
  flwr/common/event_log_plugin/event_log_plugin.py,sha256=eK8OaDFagQRwqpb9eV0cJcm2ErtEBpMxFbhxJNx6n5w,2061
119
119
  flwr/common/exit/__init__.py,sha256=-ZOJYLaNnR729a7VzZiFsLiqngzKQh3xc27svYStZ_Q,826
120
120
  flwr/common/exit/exit.py,sha256=mJgbqMlVlwAgYtq-Vedj53wO4VxcDcy_P-GzqGK-1GQ,3452
121
- flwr/common/exit/exit_code.py,sha256=PNEnCrZfOILjfDAFu5m-2YWEJBrk97xglq4zCUlqV7E,3470
121
+ flwr/common/exit/exit_code.py,sha256=rvr9ftYL3yp9vJF0epkx8S61R1xcivgPPBJsiS_al9A,3664
122
122
  flwr/common/exit_handlers.py,sha256=IaqJ60fXZuu7McaRYnoYKtlbH9t4Yl9goNExKqtmQbs,4304
123
123
  flwr/common/grpc.py,sha256=manTaHaPiyYngUq1ErZvvV2B2GxlXUUUGRy3jc3TBIQ,9798
124
124
  flwr/common/heartbeat.py,sha256=SyEpNDnmJ0lni0cWO67rcoJVKasCLmkNHm3dKLeNrLU,5749
@@ -332,6 +332,8 @@ flwr/supercore/ffs/__init__.py,sha256=U3KXwG_SplEvchat27K0LYPoPHzh-cwwT_NHsGlYMt
332
332
  flwr/supercore/ffs/disk_ffs.py,sha256=c5VywSaRnq3XM_zuJptNtsF2HFwsRK0pvBd5-5CNONs,3272
333
333
  flwr/supercore/ffs/ffs.py,sha256=6w7wy71i7tbuJwqEgdeCa49JejXMEof3jujURN_R7Rg,2395
334
334
  flwr/supercore/ffs/ffs_factory.py,sha256=pK-g3LMelvWTV6N9Cd-j-_-FdcGbRFTKNsWaqmlBDSk,1490
335
+ flwr/supercore/license_plugin/__init__.py,sha256=d8OgHTn2BwjoNSPy8jQQxTC_iT3-ENLwKM8yhHKvCRM,820
336
+ flwr/supercore/license_plugin/license_plugin.py,sha256=mqr9jn3WxukXembW8EmxsbGJ6kc4ANfc2U9ehmUm5MQ,1147
335
337
  flwr/supercore/object_store/__init__.py,sha256=cdfPAmjINY6iOp8oI_LdcVh2simg469Mkdl4LLV4kHI,911
336
338
  flwr/supercore/object_store/in_memory_object_store.py,sha256=oflJcOuVNgx9A-B2da4VHDb1qj_Jub9wKFOrUBgtz_U,9630
337
339
  flwr/supercore/object_store/object_store.py,sha256=VlZz-yzoWZtITbnYD8vwLZbFosv7vgr1XVNzByObeY0,5853
@@ -341,7 +343,8 @@ flwr/superexec/__init__.py,sha256=YFqER0IJc1XEWfsX6AxZ9LSRq0sawPYrNYki-brvTIc,71
341
343
  flwr/superexec/app.py,sha256=U2jjOHb2LGWoU7vrl9_czTzre9O2mPxu3CPGUZ86sK4,1465
342
344
  flwr/superexec/deployment.py,sha256=cFxhFom-0zv93HLNjNcUdBy3Sf6JwshRoXPQtcZunF0,6797
343
345
  flwr/superexec/exec_event_log_interceptor.py,sha256=7aBjZ4lkpOIyWut0s394OpMePr16g_Te594s-9aDM9Q,5774
344
- flwr/superexec/exec_grpc.py,sha256=lpc_rgRjtHHMzcdOzznl12D4vT22JqV5acdy45YDb0k,3498
346
+ flwr/superexec/exec_grpc.py,sha256=xyyxrhPQLGX7tafGadv5DXLUzVoUIkGLd53_raOfNHk,4202
347
+ flwr/superexec/exec_license_interceptor.py,sha256=-BZPO-ZwtrPYumcDNdEh2QZK4uX-tuYBsZqKuDK0MZ8,3026
345
348
  flwr/superexec/exec_servicer.py,sha256=c0nwdFBiS6CbKrRA7ffOpsgASOLeaRV_ICwxDfxNGAg,12498
346
349
  flwr/superexec/exec_user_auth_interceptor.py,sha256=HpGHTcDKzB7XUiQHXgntNVFYL-VfP9Wj5tEVc04VOOw,5820
347
350
  flwr/superexec/executor.py,sha256=LaErHRJvNggjWV6FI6eajgKfnwOvSv2UqzFH253yDro,3265
@@ -361,7 +364,7 @@ flwr/supernode/servicer/__init__.py,sha256=lucTzre5WPK7G1YLCfaqg3rbFWdNSb7ZTt-ca
361
364
  flwr/supernode/servicer/clientappio/__init__.py,sha256=7Oy62Y_oijqF7Dxi6tpcUQyOpLc_QpIRZ83NvwmB0Yg,813
362
365
  flwr/supernode/servicer/clientappio/clientappio_servicer.py,sha256=d3GdIabycUoDBDL_eVlt513knGSjQW3-9lG6Cw4QEk4,5719
363
366
  flwr/supernode/start_client_internal.py,sha256=DAXuReZ1FCXt9Y1KbM0p-dI50ROWPEJXzfKrl14OE6k,18233
364
- flwr_nightly-1.20.0.dev20250630.dist-info/METADATA,sha256=B3mOdd5CdmCCEJsFc4A65ifNMx4_vvr7UHDi-OuIAzY,15910
365
- flwr_nightly-1.20.0.dev20250630.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
366
- flwr_nightly-1.20.0.dev20250630.dist-info/entry_points.txt,sha256=jNpDXGBGgs21RqUxelF_jwGaxtqFwm-MQyfz-ZqSjrA,367
367
- flwr_nightly-1.20.0.dev20250630.dist-info/RECORD,,
367
+ flwr_nightly-1.20.0.dev20250701.dist-info/METADATA,sha256=j0r0nY5a-FlldBWbh47eja74PsvI0AW0c6lDYkV4ch0,15910
368
+ flwr_nightly-1.20.0.dev20250701.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
369
+ flwr_nightly-1.20.0.dev20250701.dist-info/entry_points.txt,sha256=jNpDXGBGgs21RqUxelF_jwGaxtqFwm-MQyfz-ZqSjrA,367
370
+ flwr_nightly-1.20.0.dev20250701.dist-info/RECORD,,