diff --git a/pyproject.toml b/pyproject.toml index aa356835d98..d32b026c400 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,7 +95,7 @@ black = { version = "==24.2.0", extras = ["jupyter"] } taplo = "==0.9.3" docformatter = "==1.7.5" mypy = "==1.8.0" -pylint = "==3.0.3" +pylint = "==3.3.1" flake8 = "==5.0.4" parameterized = "==0.9.0" pytest = "==7.4.4" diff --git a/src/py/flwr/client/clientapp/app.py b/src/py/flwr/client/clientapp/app.py index 69fba16e253..52be2a4b6dc 100644 --- a/src/py/flwr/client/clientapp/app.py +++ b/src/py/flwr/client/clientapp/app.py @@ -132,11 +132,10 @@ def run_clientapp( # pylint: disable=R0914 ) try: - if fab: - # Load ClientApp - client_app: ClientApp = load_client_app_fn( - run.fab_id, run.fab_version, fab.hash_str - ) + # Load ClientApp + client_app: ClientApp = load_client_app_fn( + run.fab_id, run.fab_version, fab.hash_str if fab else "" + ) # Execute ClientApp reply_message = client_app(message=message, context=context) diff --git a/src/py/flwr/client/grpc_adapter_client/connection.py b/src/py/flwr/client/grpc_adapter_client/connection.py index 9b84545eacd..ab823112bbe 100644 --- a/src/py/flwr/client/grpc_adapter_client/connection.py +++ b/src/py/flwr/client/grpc_adapter_client/connection.py @@ -32,7 +32,7 @@ @contextmanager -def grpc_adapter( # pylint: disable=R0913 +def grpc_adapter( # pylint: disable=R0913,too-many-positional-arguments server_address: str, insecure: bool, retry_invoker: RetryInvoker, diff --git a/src/py/flwr/client/grpc_client/connection.py b/src/py/flwr/client/grpc_client/connection.py index 29479cf5479..75d2ebe1502 100644 --- a/src/py/flwr/client/grpc_client/connection.py +++ b/src/py/flwr/client/grpc_client/connection.py @@ -60,7 +60,7 @@ def on_channel_state_change(channel_connectivity: str) -> None: @contextmanager -def grpc_connection( # pylint: disable=R0913, R0915 +def grpc_connection( # pylint: disable=R0913,R0915,too-many-positional-arguments server_address: str, insecure: bool, retry_invoker: RetryInvoker, # pylint: disable=unused-argument diff --git a/src/py/flwr/client/grpc_rere_client/connection.py b/src/py/flwr/client/grpc_rere_client/connection.py index 06701376fac..bfc20eee896 100644 --- a/src/py/flwr/client/grpc_rere_client/connection.py +++ b/src/py/flwr/client/grpc_rere_client/connection.py @@ -71,7 +71,7 @@ def on_channel_state_change(channel_connectivity: str) -> None: @contextmanager -def grpc_request_response( # pylint: disable=R0913, R0914, R0915 +def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917 server_address: str, insecure: bool, retry_invoker: RetryInvoker, diff --git a/src/py/flwr/client/node_state.py b/src/py/flwr/client/node_state.py index e7967dfc8be..843c9890c5d 100644 --- a/src/py/flwr/client/node_state.py +++ b/src/py/flwr/client/node_state.py @@ -48,7 +48,7 @@ def __init__( self.node_config = node_config self.run_infos: dict[int, RunInfo] = {} - # pylint: disable=too-many-arguments + # pylint: disable=too-many-arguments,too-many-positional-arguments def register_context( self, run_id: int, diff --git a/src/py/flwr/client/rest_client/connection.py b/src/py/flwr/client/rest_client/connection.py index 485bbd7a181..f933ae44ad0 100644 --- a/src/py/flwr/client/rest_client/connection.py +++ b/src/py/flwr/client/rest_client/connection.py @@ -82,7 +82,7 @@ @contextmanager -def http_request_response( # pylint: disable=,R0913, R0914, R0915 +def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917 server_address: str, insecure: bool, # pylint: disable=unused-argument retry_invoker: RetryInvoker, diff --git a/src/py/flwr/common/config.py b/src/py/flwr/common/config.py index b1cfaef49e2..24ccada7509 100644 --- a/src/py/flwr/common/config.py +++ b/src/py/flwr/common/config.py @@ -206,6 +206,7 @@ def parse_config_args( # Regular expression to capture key-value pairs with possible quoted values pattern = re.compile(r"(\S+?)=(\'[^\']*\'|\"[^\"]*\"|\S+)") + flat_overrides = {} for config_line in config: if config_line: # .toml files aren't allowed alongside other configs diff --git a/src/py/flwr/common/logger.py b/src/py/flwr/common/logger.py index 303780fc0b5..3a058abac9c 100644 --- a/src/py/flwr/common/logger.py +++ b/src/py/flwr/common/logger.py @@ -111,7 +111,7 @@ def update_console_handler( class CustomHTTPHandler(HTTPHandler): """Custom HTTPHandler which overrides the mapLogRecords method.""" - # pylint: disable=too-many-arguments,bad-option-value,R1725 + # pylint: disable=too-many-arguments,bad-option-value,R1725,R0917 def __init__( self, identifier: str, diff --git a/src/py/flwr/common/message.py b/src/py/flwr/common/message.py index 4e792e8e02a..3bb07ff3961 100644 --- a/src/py/flwr/common/message.py +++ b/src/py/flwr/common/message.py @@ -52,7 +52,7 @@ class Metadata: # pylint: disable=too-many-instance-attributes the receiving end. """ - def __init__( # pylint: disable=too-many-arguments + def __init__( # pylint: disable=too-many-arguments,too-many-positional-arguments self, run_id: int, message_id: str, diff --git a/src/py/flwr/common/record/configsrecord.py b/src/py/flwr/common/record/configsrecord.py index f570e000cc9..e83bca816fc 100644 --- a/src/py/flwr/common/record/configsrecord.py +++ b/src/py/flwr/common/record/configsrecord.py @@ -128,6 +128,7 @@ def count_bytes(self) -> int: def get_var_bytes(value: ConfigsScalar) -> int: """Return Bytes of value passed.""" + var_bytes = 0 if isinstance(value, bool): var_bytes = 1 elif isinstance(value, (int, float)): @@ -136,6 +137,11 @@ def get_var_bytes(value: ConfigsScalar) -> int: ) if isinstance(value, (str, bytes)): var_bytes = len(value) + if var_bytes == 0: + raise ValueError( + "Config values must be either `bool`, `int`, `float`, " + "`str`, or `bytes`" + ) return var_bytes num_bytes = 0 diff --git a/src/py/flwr/server/app.py b/src/py/flwr/server/app.py index d156edaa3c9..047fdf8700a 100644 --- a/src/py/flwr/server/app.py +++ b/src/py/flwr/server/app.py @@ -542,6 +542,7 @@ def _run_fleet_api_grpc_adapter( # pylint: disable=import-outside-toplevel,too-many-arguments +# pylint: disable=too-many-positional-arguments def _run_fleet_api_rest( host: str, port: int, diff --git a/src/py/flwr/server/compat/driver_client_proxy_test.py b/src/py/flwr/server/compat/driver_client_proxy_test.py index 335f47cc773..5bad0b56c4c 100644 --- a/src/py/flwr/server/compat/driver_client_proxy_test.py +++ b/src/py/flwr/server/compat/driver_client_proxy_test.py @@ -200,7 +200,7 @@ def test_evaluate_and_fail(self) -> None: ) self._common_assertions(ins) - def _create_message_dummy( # pylint: disable=R0913 + def _create_message_dummy( # pylint: disable=R0913,too-many-positional-arguments self, content: RecordSet, message_type: str, @@ -237,9 +237,9 @@ def _exec_send_and_receive( def generate_replies(messages: Iterable[Message]) -> Iterable[Message]: msg = list(messages)[0] + recordset = None if error_reply: - recordset = None - ret = msg.create_error_reply(ERROR_REPLY) + pass elif isinstance(res, GetParametersRes): recordset = compat.getparametersres_to_recordset(res, True) elif isinstance(res, GetPropertiesRes): @@ -248,10 +248,11 @@ def generate_replies(messages: Iterable[Message]) -> Iterable[Message]: recordset = compat.fitres_to_recordset(res, True) elif isinstance(res, EvaluateRes): recordset = compat.evaluateres_to_recordset(res) - else: - raise ValueError(f"Unsupported type: {type(res)}") + if recordset is not None: ret = msg.create_reply(recordset) + else: + ret = msg.create_error_reply(ERROR_REPLY) # Reply messages given the push message return [ret] diff --git a/src/py/flwr/server/driver/driver.py b/src/py/flwr/server/driver/driver.py index e8429e865db..5a6ee691f3a 100644 --- a/src/py/flwr/server/driver/driver.py +++ b/src/py/flwr/server/driver/driver.py @@ -32,7 +32,7 @@ def run(self) -> Run: """Run information.""" @abstractmethod - def create_message( # pylint: disable=too-many-arguments + def create_message( # pylint: disable=too-many-arguments,R0917 self, content: RecordSet, message_type: str, diff --git a/src/py/flwr/server/driver/grpc_driver.py b/src/py/flwr/server/driver/grpc_driver.py index 421dfd30ecb..13c1c4152da 100644 --- a/src/py/flwr/server/driver/grpc_driver.py +++ b/src/py/flwr/server/driver/grpc_driver.py @@ -158,7 +158,7 @@ def _check_message(self, message: Message) -> None: ): raise ValueError(f"Invalid message: {message}") - def create_message( # pylint: disable=too-many-arguments + def create_message( # pylint: disable=too-many-arguments,R0917 self, content: RecordSet, message_type: str, diff --git a/src/py/flwr/server/driver/inmemory_driver.py b/src/py/flwr/server/driver/inmemory_driver.py index 61788477f2e..130562c6def 100644 --- a/src/py/flwr/server/driver/inmemory_driver.py +++ b/src/py/flwr/server/driver/inmemory_driver.py @@ -82,7 +82,7 @@ def run(self) -> Run: self._init_run() return Run(**vars(cast(Run, self._run))) - def create_message( # pylint: disable=too-many-arguments + def create_message( # pylint: disable=too-many-arguments,R0917 self, content: RecordSet, message_type: str, diff --git a/src/py/flwr/server/server_app.py b/src/py/flwr/server/server_app.py index e9cb4ddcaf0..9d91be88e94 100644 --- a/src/py/flwr/server/server_app.py +++ b/src/py/flwr/server/server_app.py @@ -71,7 +71,7 @@ class ServerApp: >>> print("ServerApp running") """ - # pylint: disable=too-many-arguments + # pylint: disable=too-many-arguments,too-many-positional-arguments def __init__( self, server: Optional[Server] = None, diff --git a/src/py/flwr/server/strategy/bulyan_test.py b/src/py/flwr/server/strategy/bulyan_test.py index c0b87c82a03..f5b7282fed2 100644 --- a/src/py/flwr/server/strategy/bulyan_test.py +++ b/src/py/flwr/server/strategy/bulyan_test.py @@ -124,7 +124,7 @@ def test_aggregate_fit() -> None: actual_aggregated, _ = strategy.aggregate_fit( server_round=1, results=results, failures=[] ) - if actual_aggregated: - actual_list = parameters_to_ndarrays(actual_aggregated) - actual = actual_list[0] + assert actual_aggregated + actual_list = parameters_to_ndarrays(actual_aggregated) + actual = actual_list[0] assert (actual == expected[0]).all() diff --git a/src/py/flwr/server/strategy/dp_adaptive_clipping.py b/src/py/flwr/server/strategy/dp_adaptive_clipping.py index 77e70bb9af0..c64091091c5 100644 --- a/src/py/flwr/server/strategy/dp_adaptive_clipping.py +++ b/src/py/flwr/server/strategy/dp_adaptive_clipping.py @@ -88,7 +88,7 @@ class DifferentialPrivacyServerSideAdaptiveClipping(Strategy): >>> ) """ - # pylint: disable=too-many-arguments,too-many-instance-attributes + # pylint: disable=too-many-arguments,too-many-instance-attributes,too-many-positional-arguments def __init__( self, strategy: Strategy, @@ -307,7 +307,7 @@ class DifferentialPrivacyClientSideAdaptiveClipping(Strategy): >>> ) """ - # pylint: disable=too-many-arguments,too-many-instance-attributes + # pylint: disable=too-many-arguments,too-many-instance-attributes,too-many-positional-arguments def __init__( self, strategy: Strategy, diff --git a/src/py/flwr/server/strategy/dpfedavg_adaptive.py b/src/py/flwr/server/strategy/dpfedavg_adaptive.py index ab513aba226..170c9d619a7 100644 --- a/src/py/flwr/server/strategy/dpfedavg_adaptive.py +++ b/src/py/flwr/server/strategy/dpfedavg_adaptive.py @@ -39,7 +39,7 @@ class DPFedAvgAdaptive(DPFedAvgFixed): This class is deprecated and will be removed in a future release. """ - # pylint: disable=too-many-arguments,too-many-instance-attributes + # pylint: disable=too-many-arguments,too-many-instance-attributes,too-many-positional-arguments def __init__( self, strategy: Strategy, diff --git a/src/py/flwr/server/strategy/dpfedavg_fixed.py b/src/py/flwr/server/strategy/dpfedavg_fixed.py index 4ea84db30cd..60f8c16f8e6 100644 --- a/src/py/flwr/server/strategy/dpfedavg_fixed.py +++ b/src/py/flwr/server/strategy/dpfedavg_fixed.py @@ -36,7 +36,7 @@ class DPFedAvgFixed(Strategy): This class is deprecated and will be removed in a future release. """ - # pylint: disable=too-many-arguments,too-many-instance-attributes + # pylint: disable=too-many-arguments,too-many-instance-attributes,too-many-positional-arguments def __init__( self, strategy: Strategy, diff --git a/src/py/flwr/server/strategy/fedadagrad_test.py b/src/py/flwr/server/strategy/fedadagrad_test.py index 96d98fe750f..6ac217b021b 100644 --- a/src/py/flwr/server/strategy/fedadagrad_test.py +++ b/src/py/flwr/server/strategy/fedadagrad_test.py @@ -79,7 +79,7 @@ def test_aggregate_fit() -> None: actual_aggregated, _ = strategy.aggregate_fit( server_round=1, results=results, failures=[] ) - if actual_aggregated: - actual_list = parameters_to_ndarrays(actual_aggregated) - actual = actual_list[0] + assert actual_aggregated + actual_list = parameters_to_ndarrays(actual_aggregated) + actual = actual_list[0] assert (actual == expected[0]).all() diff --git a/src/py/flwr/server/strategy/fedmedian_test.py b/src/py/flwr/server/strategy/fedmedian_test.py index 2c988163531..bbce69c19ac 100644 --- a/src/py/flwr/server/strategy/fedmedian_test.py +++ b/src/py/flwr/server/strategy/fedmedian_test.py @@ -193,7 +193,7 @@ def test_aggregate_fit() -> None: actual_aggregated, _ = strategy.aggregate_fit( server_round=1, results=results, failures=[] ) - if actual_aggregated: - actual_list = parameters_to_ndarrays(actual_aggregated) - actual = actual_list[0] + assert actual_aggregated + actual_list = parameters_to_ndarrays(actual_aggregated) + actual = actual_list[0] assert (actual == expected[0]).all() diff --git a/src/py/flwr/server/strategy/krum_test.py b/src/py/flwr/server/strategy/krum_test.py index dc996b48063..ac068a8e6ba 100644 --- a/src/py/flwr/server/strategy/krum_test.py +++ b/src/py/flwr/server/strategy/krum_test.py @@ -194,7 +194,7 @@ def test_aggregate_fit() -> None: actual_aggregated, _ = strategy.aggregate_fit( server_round=1, results=results, failures=[] ) - if actual_aggregated: - actual_list = parameters_to_ndarrays(actual_aggregated) - actual = actual_list[0] + assert actual_aggregated + actual_list = parameters_to_ndarrays(actual_aggregated) + actual = actual_list[0] assert (actual == expected[0]).all() diff --git a/src/py/flwr/server/strategy/multikrum_test.py b/src/py/flwr/server/strategy/multikrum_test.py index 90607e2c0ed..d9c73fb4eb8 100644 --- a/src/py/flwr/server/strategy/multikrum_test.py +++ b/src/py/flwr/server/strategy/multikrum_test.py @@ -93,7 +93,7 @@ def test_aggregate_fit() -> None: actual_aggregated, _ = strategy.aggregate_fit( server_round=1, results=results, failures=[] ) - if actual_aggregated: - actual_list = parameters_to_ndarrays(actual_aggregated) - actual = actual_list[0] + assert actual_aggregated + actual_list = parameters_to_ndarrays(actual_aggregated) + actual = actual_list[0] assert (actual == expected[0]).all() diff --git a/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py b/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py index 70283c0e129..9d2e13d5b10 100644 --- a/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +++ b/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py @@ -60,7 +60,7 @@ def valid_certificates(certificates: tuple[bytes, bytes, bytes]) -> bool: return is_valid -def start_grpc_server( # pylint: disable=too-many-arguments +def start_grpc_server( # pylint: disable=too-many-arguments,R0917 client_manager: ClientManager, server_address: str, max_concurrent_workers: int = 1000, @@ -156,7 +156,7 @@ def start_grpc_server( # pylint: disable=too-many-arguments return server -def generic_create_grpc_server( # pylint: disable=too-many-arguments +def generic_create_grpc_server( # pylint: disable=too-many-arguments,R0917 servicer_and_add_fn: Union[ tuple[FleetServicer, AddServicerToServerFn], tuple[GrpcAdapterServicer, AddServicerToServerFn], diff --git a/src/py/flwr/server/superlink/fleet/vce/vce_api.py b/src/py/flwr/server/superlink/fleet/vce/vce_api.py index 9bdfaec979a..78539053400 100644 --- a/src/py/flwr/server/superlink/fleet/vce/vce_api.py +++ b/src/py/flwr/server/superlink/fleet/vce/vce_api.py @@ -172,6 +172,7 @@ def put_taskres_into_state( pass +# pylint: disable=too-many-positional-arguments def run_api( app_fn: Callable[[], ClientApp], backend_fn: Callable[[], Backend], @@ -251,7 +252,7 @@ def run_api( # pylint: disable=too-many-arguments,unused-argument,too-many-locals,too-many-branches -# pylint: disable=too-many-statements +# pylint: disable=too-many-statements,too-many-positional-arguments def start_vce( backend_name: str, backend_config_json_stream: str, @@ -267,6 +268,8 @@ def start_vce( existing_nodes_mapping: Optional[NodeToPartitionMapping] = None, ) -> None: """Start Fleet API with the Simulation Engine.""" + nodes_mapping = {} + if client_app_attr is not None and client_app is not None: raise ValueError( "Both `client_app_attr` and `client_app` are provided, " @@ -340,17 +343,17 @@ def backend_fn() -> Backend: # Load ClientApp if needed def _load() -> ClientApp: + if client_app: + return client_app if client_app_attr: - app = get_load_client_app_fn( + return get_load_client_app_fn( default_app_ref=client_app_attr, app_path=app_dir, flwr_dir=flwr_dir, multi_app=False, )(run.fab_id, run.fab_version, run.fab_hash) - if client_app: - app = client_app - return app + raise ValueError("Either `client_app_attr` or `client_app` must be provided") app_fn = _load diff --git a/src/py/flwr/server/superlink/fleet/vce/vce_api_test.py b/src/py/flwr/server/superlink/fleet/vce/vce_api_test.py index ece8321dd18..bc34b825c33 100644 --- a/src/py/flwr/server/superlink/fleet/vce/vce_api_test.py +++ b/src/py/flwr/server/superlink/fleet/vce/vce_api_test.py @@ -170,7 +170,7 @@ def _autoresolve_app_dir(rel_client_app_dir: str = "backend") -> str: return str(rel_app_dir.parent / rel_client_app_dir) -# pylint: disable=too-many-arguments +# pylint: disable=too-many-arguments,too-many-positional-arguments def start_and_shutdown( backend: str = "ray", client_app_attr: Optional[str] = None, diff --git a/src/py/flwr/server/superlink/state/state_test.py b/src/py/flwr/server/superlink/state/state_test.py index 62f3c204b78..a4663f80f63 100644 --- a/src/py/flwr/server/superlink/state/state_test.py +++ b/src/py/flwr/server/superlink/state/state_test.py @@ -316,8 +316,8 @@ def test_task_res_store_and_retrieve_by_task_ins_id(self) -> None: # Execute task_res_uuid = state.store_task_res(task_res) - if task_ins_id is not None: - task_res_list = state.get_task_res(task_ids={task_ins_id}) + assert task_ins_id + task_res_list = state.get_task_res(task_ids={task_ins_id}) # Assert retrieved_task_res = task_res_list[0] @@ -811,8 +811,8 @@ def test_get_task_res_not_return_expired(self) -> None: with patch("time.time", side_effect=lambda: task_ins.task.created_at + 6.1): # Execute - if task_id is not None: - task_res_list = state.get_task_res(task_ids={task_id}) + assert task_id is not None + task_res_list = state.get_task_res(task_ids={task_id}) # Assert assert len(task_res_list) == 0 @@ -865,8 +865,8 @@ def test_get_task_res_return_if_not_expired(self) -> None: with patch("time.time", side_effect=lambda: task_ins.task.created_at + 6.1): # Execute - if task_id is not None: - task_res_list = state.get_task_res(task_ids={task_id}) + assert task_id is not None + task_res_list = state.get_task_res(task_ids={task_id}) # Assert assert len(task_res_list) != 0 diff --git a/src/py/flwr/simulation/ray_transport/ray_client_proxy.py b/src/py/flwr/simulation/ray_transport/ray_client_proxy.py index 90e932aa801..ad9be6bd1fc 100644 --- a/src/py/flwr/simulation/ray_transport/ray_client_proxy.py +++ b/src/py/flwr/simulation/ray_transport/ray_client_proxy.py @@ -48,7 +48,7 @@ class RayActorClientProxy(ClientProxy): """Flower client proxy which delegates work using Ray.""" - def __init__( # pylint: disable=too-many-arguments + def __init__( # pylint: disable=too-many-arguments,too-many-positional-arguments self, client_fn: ClientFnExt, node_id: int, diff --git a/src/py/flwr/simulation/run_simulation.py b/src/py/flwr/simulation/run_simulation.py index 2d29629c4f0..8c4e42c3474 100644 --- a/src/py/flwr/simulation/run_simulation.py +++ b/src/py/flwr/simulation/run_simulation.py @@ -225,7 +225,7 @@ def run_simulation_from_cli() -> None: # Entry point from Python session (script or notebook) -# pylint: disable=too-many-arguments +# pylint: disable=too-many-arguments,too-many-positional-arguments def run_simulation( server_app: ServerApp, client_app: ClientApp, @@ -300,7 +300,7 @@ def run_simulation( ) -# pylint: disable=too-many-arguments +# pylint: disable=too-many-arguments,too-many-positional-arguments def run_serverapp_th( server_app_attr: Optional[str], server_app: Optional[ServerApp], @@ -369,7 +369,7 @@ def server_th_with_start_checks( return serverapp_th -# pylint: disable=too-many-locals +# pylint: disable=too-many-locals,too-many-positional-arguments def _main_loop( num_supernodes: int, backend_name: str, @@ -455,7 +455,7 @@ def _main_loop( log(DEBUG, "Stopping Simulation Engine now.") -# pylint: disable=too-many-arguments,too-many-locals +# pylint: disable=too-many-arguments,too-many-locals,too-many-positional-arguments def _run_simulation( num_supernodes: int, exit_event: EventType,