From c8f7ffb2964a9c28099323fd54ba0638240c1dd4 Mon Sep 17 00:00:00 2001 From: Yang An Date: Mon, 11 May 2026 09:26:05 +1000 Subject: [PATCH 1/6] [pylint4] Fix all style errors for pylint 4.x compatibility (logging, duplicate functions, codecs.open migration) --- src/azure-cli-core/azure/cli/core/util.py | 3 +- .../azure/cli/command_modules/apim/custom.py | 2 +- .../cli/command_modules/appservice/custom.py | 1 - .../command_modules/batch/_command_type.py | 5 +-- .../cli/command_modules/botservice/custom.py | 7 ++-- .../command_modules/containerapp/_utils.py | 17 --------- .../cli/command_modules/cosmosdb/custom.py | 7 ---- .../operations/sqlpoolblobauditingpolicy.py | 35 ------------------- 8 files changed, 9 insertions(+), 68 deletions(-) diff --git a/src/azure-cli-core/azure/cli/core/util.py b/src/azure-cli-core/azure/cli/core/util.py index b693ee00518..bc572f3efe6 100644 --- a/src/azure-cli-core/azure/cli/core/util.py +++ b/src/azure-cli-core/azure/cli/core/util.py @@ -576,11 +576,10 @@ def get_file_yaml(file_path, throw_on_empty=True): def read_file_content(file_path, allow_binary=False): - from codecs import open as codecs_open # Note, always put 'utf-8-sig' first, so that BOM in WinOS won't cause trouble. for encoding in ['utf-8-sig', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be']: try: - with codecs_open(file_path, encoding=encoding) as f: + with open(file_path, mode='r', encoding=encoding) as f: logger.debug("attempting to read file %s as %s", file_path, encoding) return f.read() except (UnicodeError, UnicodeDecodeError): diff --git a/src/azure-cli/azure/cli/command_modules/apim/custom.py b/src/azure-cli/azure/cli/command_modules/apim/custom.py index f78112b86fc..86612521c70 100644 --- a/src/azure-cli/azure/cli/command_modules/apim/custom.py +++ b/src/azure-cli/azure/cli/command_modules/apim/custom.py @@ -580,7 +580,7 @@ def apim_api_export(client, resource_group_name, service_name, api_id, export_fo try: exportedResults = requests.get(link, timeout=30) if not exportedResults.ok: - logger.warning("Got bad status from APIManagement during API Export:%s, {exportedResults.status_code}") + logger.warning("Got bad status from APIManagement during API Export: %s", exportedResults.status_code) except requests.exceptions.ReadTimeout: logger.warning("Timed out while exporting api from APIManagement.") diff --git a/src/azure-cli/azure/cli/command_modules/appservice/custom.py b/src/azure-cli/azure/cli/command_modules/appservice/custom.py index 5da17f08f94..6eac25c36ab 100644 --- a/src/azure-cli/azure/cli/command_modules/appservice/custom.py +++ b/src/azure-cli/azure/cli/command_modules/appservice/custom.py @@ -66,7 +66,6 @@ retryable_method, raise_missing_token_suggestion, _get_location_from_resource_group, - _list_app, is_functionapp, is_linux_webapp, _rename_server_farm_props, diff --git a/src/azure-cli/azure/cli/command_modules/batch/_command_type.py b/src/azure-cli/azure/cli/command_modules/batch/_command_type.py index f50d6e803be..7817f6691aa 100644 --- a/src/azure-cli/azure/cli/command_modules/batch/_command_type.py +++ b/src/azure-cli/azure/cli/command_modules/batch/_command_type.py @@ -756,10 +756,11 @@ def get_track1_rest_names(self, cls): def _resolve_track1_type_hint(self, type_hint): """Resolve type hints to the legacy track1 type string format.""" args = get_args(type_hint) + none_type = None.__class__ # Optional[T] / Union[..., None] -> select the best non-None candidate. - if type(None) in args: - non_none_args = [arg for arg in args if arg is not type(None)] + if none_type in args: + non_none_args = [arg for arg in args if arg is not none_type] preferred_args = [arg for arg in non_none_args if arg != str] or non_none_args selected = preferred_args[0] if preferred_args else type_hint return self.convert_to_track1_type(str(selected)) diff --git a/src/azure-cli/azure/cli/command_modules/botservice/custom.py b/src/azure-cli/azure/cli/command_modules/botservice/custom.py index b1f507f554d..3e2d6549096 100644 --- a/src/azure-cli/azure/cli/command_modules/botservice/custom.py +++ b/src/azure-cli/azure/cli/command_modules/botservice/custom.py @@ -59,7 +59,7 @@ def __prepare_configuration_file(cmd, resource_group_name, kudu_client, folder_p if setting['name'] not in ignorable_settings} existing = None if not os.path.exists(app_settings_path): - logger.info('App settings not found at %s, defaulting app settings to {}.', app_settings_path) + logger.info('App settings not found at %s, defaulting app settings to empty object.', app_settings_path) existing = {} else: with open(app_settings_path, 'r') as f: @@ -271,7 +271,8 @@ def download_app(cmd, client, resource_group_name, resource_name, file_save_path if (os.path.exists(os.path.join(folder_path, 'PostDeployScripts', 'deploy.cmd.template')) and os.path.exists(os.path.join(folder_path, 'deploy.cmd'))): - logger.info('Post deployment scripts and deploy.cmd found in source under folder %s. Copying deploy.cmd.') + logger.info('Post deployment scripts and deploy.cmd found in source under folder %s. Copying deploy.cmd.', + folder_path) shutil.copyfile(os.path.join(folder_path, 'deploy.cmd'), os.path.join(folder_path, 'PostDeployScripts', 'deploy.cmd.template')) @@ -318,7 +319,7 @@ def download_app(cmd, client, resource_group_name, resource_name, file_save_path existing = None if not os.path.exists(app_settings_path): - logger.info('App settings not found at %s, defaulting app settings to {}.', app_settings_path) + logger.info('App settings not found at %s, defaulting app settings to empty object.', app_settings_path) existing = '{}' else: with open(app_settings_path, 'r') as f: diff --git a/src/azure-cli/azure/cli/command_modules/containerapp/_utils.py b/src/azure-cli/azure/cli/command_modules/containerapp/_utils.py index 4d03c999853..4c2cce48b0d 100644 --- a/src/azure-cli/azure/cli/command_modules/containerapp/_utils.py +++ b/src/azure-cli/azure/cli/command_modules/containerapp/_utils.py @@ -895,23 +895,6 @@ def _remove_env_vars(existing_env_vars, remove_env_vars): logger.warning("Environment variable {} does not exist.".format(old_env_var)) # pylint: disable=logging-format-interpolation -def _remove_env_vars(existing_env_vars, remove_env_vars): - for old_env_var in remove_env_vars: - - # Check if updating existing env var - is_existing = False - for index, value in enumerate(existing_env_vars): - existing_env_var = value - if existing_env_var["name"].lower() == old_env_var.lower(): - is_existing = True - existing_env_vars.pop(index) - break - - # If not updating existing env var, add it as a new env var - if not is_existing: - logger.warning("Environment variable {} does not exist.".format(old_env_var)) # pylint: disable=logging-format-interpolation - - def _add_or_update_tags(containerapp_def, tags): if 'tags' not in containerapp_def: if tags: diff --git a/src/azure-cli/azure/cli/command_modules/cosmosdb/custom.py b/src/azure-cli/azure/cli/command_modules/cosmosdb/custom.py index 52a78f33496..b7ba9a7a1cf 100644 --- a/src/azure-cli/azure/cli/command_modules/cosmosdb/custom.py +++ b/src/azure-cli/azure/cli/command_modules/cosmosdb/custom.py @@ -2773,13 +2773,6 @@ def cli_cosmosdb_managed_cassandra_datacenter_update(client, return client.begin_create_update(resource_group_name, cluster_name, data_center_name, data_center_resource) -def _handle_exists_exception(http_response_error): - - if http_response_error.status_code == 404: - return False - raise http_response_error - - def process_restorable_databases(restorable_databases, database_name): latest_database_delete_time = datetime.datetime.utcfromtimestamp(0) diff --git a/src/azure-cli/azure/cli/command_modules/synapse/manual/operations/sqlpoolblobauditingpolicy.py b/src/azure-cli/azure/cli/command_modules/synapse/manual/operations/sqlpoolblobauditingpolicy.py index 3ff73e8960e..9f4f36ac78f 100644 --- a/src/azure-cli/azure/cli/command_modules/synapse/manual/operations/sqlpoolblobauditingpolicy.py +++ b/src/azure-cli/azure/cli/command_modules/synapse/manual/operations/sqlpoolblobauditingpolicy.py @@ -861,41 +861,6 @@ def _audit_policy_validate_arguments( raise CLIError('event-hub-authorization-rule-id must be specified if event-hub-target-state is enabled') -def _get_diagnostic_settings_url( - cmd, - resource_group_name, - workspace_name, - sql_pool_name=None): - - from azure.cli.core.commands.client_factory import get_subscription_id - - diag_settings = '/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Synapse/workspaces/{}'.format( - get_subscription_id(cmd.cli_ctx), - resource_group_name, workspace_name) - - if sql_pool_name is not None: - diag_settings = diag_settings + '/sqlpools/{}'.format(sql_pool_name) - - return diag_settings - - -def _get_diagnostic_settings( - cmd, - resource_group_name, - workspace_name, - sql_pool_name=None): - ''' - Common code to get server or database diagnostic settings - ''' - - diagnostic_settings_url = _get_diagnostic_settings_url( - cmd=cmd, resource_group_name=resource_group_name, - workspace_name=workspace_name, sql_pool_name=sql_pool_name) - azure_monitor_client = cf_monitor(cmd.cli_ctx) - - return list(azure_monitor_client.diagnostic_settings.list(diagnostic_settings_url)) - - def workspace_audit_policy_show( cmd, client, From 61ba0f783813d3a1453ca30e28c7ca161d5a2629 Mon Sep 17 00:00:00 2001 From: Yang An Date: Mon, 11 May 2026 11:31:07 +1000 Subject: [PATCH 2/6] Fix flake8 E128 indentation in botservice custom logger call --- .../azure/cli/command_modules/botservice/custom.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/botservice/custom.py b/src/azure-cli/azure/cli/command_modules/botservice/custom.py index 3e2d6549096..b9da23393a2 100644 --- a/src/azure-cli/azure/cli/command_modules/botservice/custom.py +++ b/src/azure-cli/azure/cli/command_modules/botservice/custom.py @@ -271,8 +271,10 @@ def download_app(cmd, client, resource_group_name, resource_name, file_save_path if (os.path.exists(os.path.join(folder_path, 'PostDeployScripts', 'deploy.cmd.template')) and os.path.exists(os.path.join(folder_path, 'deploy.cmd'))): - logger.info('Post deployment scripts and deploy.cmd found in source under folder %s. Copying deploy.cmd.', - folder_path) + logger.info( + 'Post deployment scripts and deploy.cmd found in source under folder %s. Copying deploy.cmd.', + folder_path + ) shutil.copyfile(os.path.join(folder_path, 'deploy.cmd'), os.path.join(folder_path, 'PostDeployScripts', 'deploy.cmd.template')) From f2b9bcaa41f5c546c5f4e97c89d54e29555762d0 Mon Sep 17 00:00:00 2001 From: Yang An Date: Mon, 11 May 2026 14:23:14 +1000 Subject: [PATCH 3/6] Guard APIM export flow on missing link and timeout --- src/azure-cli/azure/cli/command_modules/apim/custom.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/azure-cli/azure/cli/command_modules/apim/custom.py b/src/azure-cli/azure/cli/command_modules/apim/custom.py index 86612521c70..945a15992df 100644 --- a/src/azure-cli/azure/cli/command_modules/apim/custom.py +++ b/src/azure-cli/azure/cli/command_modules/apim/custom.py @@ -555,11 +555,13 @@ def apim_api_export(client, resource_group_name, service_name, api_id, export_fo # Obtain link from the response response_dict = api_export_result_to_dict(response) + link = None try: # Extract the link from the response where results are stored link = response_dict['additional_properties']['properties']['value']['link'] except KeyError: logger.warning("Error exporting api from APIManagement. The expected link is not present in the response.") + return # Determine the file extension based on the mappedFormat if mappedFormat in ['swagger-link', 'openapi+json-link']: @@ -577,12 +579,15 @@ def apim_api_export(client, resource_group_name, service_name, api_id, export_fo full_path = os.path.join(file_path, file_name) # Get the results from the link where the API Export Results are stored + exportedResults = None try: exportedResults = requests.get(link, timeout=30) if not exportedResults.ok: logger.warning("Got bad status from APIManagement during API Export: %s", exportedResults.status_code) + return except requests.exceptions.ReadTimeout: logger.warning("Timed out while exporting api from APIManagement.") + return try: # Try to parse as JSON From c781e2a4be2c50b87a5dd1ebffe87a0d7bae23e1 Mon Sep 17 00:00:00 2001 From: YangAn-microsoft Date: Tue, 12 May 2026 13:15:16 +1000 Subject: [PATCH 4/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/azure-cli/azure/cli/command_modules/apim/custom.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/apim/custom.py b/src/azure-cli/azure/cli/command_modules/apim/custom.py index 945a15992df..f18362a8505 100644 --- a/src/azure-cli/azure/cli/command_modules/apim/custom.py +++ b/src/azure-cli/azure/cli/command_modules/apim/custom.py @@ -584,10 +584,12 @@ def apim_api_export(client, resource_group_name, service_name, api_id, export_fo exportedResults = requests.get(link, timeout=30) if not exportedResults.ok: logger.warning("Got bad status from APIManagement during API Export: %s", exportedResults.status_code) - return - except requests.exceptions.ReadTimeout: + raise RuntimeError( + f"API export failed with status code {exportedResults.status_code}." + ) + except requests.exceptions.ReadTimeout as ex: logger.warning("Timed out while exporting api from APIManagement.") - return + raise RuntimeError("Timed out while exporting api from APIManagement.") from ex try: # Try to parse as JSON From 94a67e3ed99e3e6be04f5f23326fc6b4540a2dc6 Mon Sep 17 00:00:00 2001 From: Yang An Date: Tue, 12 May 2026 13:22:22 +1000 Subject: [PATCH 5/6] fix(apim): raise CLIError on export failures instead of silently returning - Replace silent return statements with CLIError exceptions in apim_api_export - Raises CLIError when response link is missing (KeyError) - Raises CLIError when API export request returns non-OK status - Raises CLIError when API export request times out - This ensures proper error signaling in automation/CI pipelines (exit code non-zero on failure) - Addresses review feedback: guard clauses must not mask failures --- src/azure-cli/azure/cli/command_modules/apim/custom.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/apim/custom.py b/src/azure-cli/azure/cli/command_modules/apim/custom.py index 945a15992df..d629dfd672d 100644 --- a/src/azure-cli/azure/cli/command_modules/apim/custom.py +++ b/src/azure-cli/azure/cli/command_modules/apim/custom.py @@ -27,7 +27,7 @@ from azure.cli.core.util import sdk_no_wait from azure.cli.core.util import get_logger from azure.cli.core.azclierror import (RequiredArgumentMissingError, MutuallyExclusiveArgumentError, - InvalidArgumentValueError) + InvalidArgumentValueError, CLIError) from azure.mgmt.apimanagement.models import (ApiManagementServiceResource, ApiManagementServiceIdentity, ApiManagementServiceSkuProperties, ApiManagementServiceBackupRestoreParameters, @@ -561,7 +561,7 @@ def apim_api_export(client, resource_group_name, service_name, api_id, export_fo link = response_dict['additional_properties']['properties']['value']['link'] except KeyError: logger.warning("Error exporting api from APIManagement. The expected link is not present in the response.") - return + raise CLIError("Failed to export API: link not found in response") # Determine the file extension based on the mappedFormat if mappedFormat in ['swagger-link', 'openapi+json-link']: @@ -584,10 +584,10 @@ def apim_api_export(client, resource_group_name, service_name, api_id, export_fo exportedResults = requests.get(link, timeout=30) if not exportedResults.ok: logger.warning("Got bad status from APIManagement during API Export: %s", exportedResults.status_code) - return + raise CLIError(f"Failed to export API: Got status code {exportedResults.status_code}") except requests.exceptions.ReadTimeout: logger.warning("Timed out while exporting api from APIManagement.") - return + raise CLIError("Failed to export API: Request timed out") try: # Try to parse as JSON From 792bf6f9cea934358a14b53c9ce4cbe5364db478 Mon Sep 17 00:00:00 2001 From: YangAn-microsoft Date: Tue, 12 May 2026 13:38:56 +1000 Subject: [PATCH 6/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/azure-cli/azure/cli/command_modules/botservice/custom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/azure-cli/azure/cli/command_modules/botservice/custom.py b/src/azure-cli/azure/cli/command_modules/botservice/custom.py index b9da23393a2..02335f42489 100644 --- a/src/azure-cli/azure/cli/command_modules/botservice/custom.py +++ b/src/azure-cli/azure/cli/command_modules/botservice/custom.py @@ -322,7 +322,7 @@ def download_app(cmd, client, resource_group_name, resource_name, file_save_path if not os.path.exists(app_settings_path): logger.info('App settings not found at %s, defaulting app settings to empty object.', app_settings_path) - existing = '{}' + existing = {} else: with open(app_settings_path, 'r') as f: existing = json.load(f)