From 7ec11cbbbc18bb8995794025371ba1f712edbeac Mon Sep 17 00:00:00 2001 From: anibalinn Date: Fri, 22 Nov 2024 17:45:50 -0300 Subject: [PATCH] Renaming try_operate_descriptor by retry_file_operation --- .pre-commit-config.yaml | 2 +- behavex/outputs/report_html.py | 6 +++--- behavex/outputs/report_json.py | 4 ++-- behavex/outputs/report_utils.py | 24 ++++++++++++++++++++---- behavex/outputs/report_xml.py | 6 +++--- behavex/runner.py | 19 ++++++++++++------- behavex/utils.py | 20 ++++++++++---------- 7 files changed, 51 insertions(+), 30 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index eb46272..baf41a9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: hooks: - id: bandit exclude: tests - args: [--skip, "B322"] # ignore assert_used + args: [--skip, "B322,B110"] # ignore assert_used and B110 - repo: https://github.com/pre-commit/mirrors-isort rev: v5.6.4 diff --git a/behavex/outputs/report_html.py b/behavex/outputs/report_html.py index 8acac91..7eb87b2 100644 --- a/behavex/outputs/report_html.py +++ b/behavex/outputs/report_html.py @@ -19,7 +19,7 @@ from behavex.outputs.report_utils import (gather_steps_with_definition, get_environment_details, get_save_function, - try_operate_descriptor) + retry_file_operation) def generate_report(output, joined=None, report=None): @@ -47,7 +47,7 @@ def _create_manifest(relative, page): os.makedirs(folder) file_manifest = os.path.join(folder, page.replace('html', 'manifest')) - try_operate_descriptor( + retry_file_operation( file_manifest, execution=get_save_function(file_manifest, output_text) ) @@ -80,7 +80,7 @@ def _create_files_report(content_to_file): # pylint: disable= W0703 except Exception as ex: print(ex) - try_operate_descriptor(path_file, get_save_function(path_file, content)) + retry_file_operation(path_file, get_save_function(path_file, content)) def get_metrics_variables(scenarios): diff --git a/behavex/outputs/report_json.py b/behavex/outputs/report_json.py index b50c974..6e9f2bb 100644 --- a/behavex/outputs/report_json.py +++ b/behavex/outputs/report_json.py @@ -28,7 +28,7 @@ get_error_message, match_for_execution, text) from behavex.utils import (generate_hash, generate_uuid, get_scenario_tags, - try_operate_descriptor) + retry_file_operation) def add_step_info(step, parent_node): @@ -105,7 +105,7 @@ def generate_json_report(feature_list): def write_json(): file_info.write(json.dumps(output)) - try_operate_descriptor(path_info, execution=write_json) + retry_file_operation(path_info, execution=write_json) if multiprocessing.current_process().name != 'MainProcess': return output except IOError: diff --git a/behavex/outputs/report_utils.py b/behavex/outputs/report_utils.py index 234b276..a482d63 100644 --- a/behavex/outputs/report_utils.py +++ b/behavex/outputs/report_utils.py @@ -190,7 +190,23 @@ def resolving_type(step, scenario, background=True): return step['step_type'].title() -def try_operate_descriptor(dest_path, execution, return_value=False): +def retry_file_operation(dest_path, execution, return_value=False): + """Executes a file operation with retry logic for handling file access conflicts. + + This function attempts to execute a file operation (like copy, delete, etc.) and + provides an interactive retry mechanism if the files are locked by another process. + + Args: + dest_path (str): The file system path where the operation will be performed + operation (callable): A function containing the file operation to execute + return_value (bool, optional): Whether to return the result of the operation. Defaults to False. + + Returns: + Any: The result of the operation if return_value is True, otherwise None + + Example: + >>> retry_file_operation('/path/to/dir', lambda: shutil.rmtree('/path/to/dir')) + """ passed = False following = True retry_number = 1 @@ -290,8 +306,8 @@ def copy_bootstrap_html_generator(output): bootstrap_path = ['outputs', 'bootstrap'] bootstrap_path = os.path.join(global_vars.execution_path, *bootstrap_path) if os.path.exists(dest_path): - try_operate_descriptor(dest_path, lambda: shutil.rmtree(dest_path)) - try_operate_descriptor( + retry_file_operation(dest_path, lambda: shutil.rmtree(dest_path)) + retry_file_operation( dest_path, lambda: shutil.copytree(bootstrap_path, dest_path) ) @@ -451,5 +467,5 @@ def get_environment_details(): environment_details = environment_details_raw_data.split(',') if environment_details_raw_data else [] return environment_details -def strip_ansi_codes(from_str: str): +def strip_ansi_codes(from_str: str): return re.sub(r'\x1B\[[0-?9;]*[mGJK]', '', from_str) diff --git a/behavex/outputs/report_xml.py b/behavex/outputs/report_xml.py index df095f8..4ca51c5 100644 --- a/behavex/outputs/report_xml.py +++ b/behavex/outputs/report_xml.py @@ -16,8 +16,8 @@ from behavex.global_vars import global_vars from behavex.outputs.jinja_mgr import TemplateHandler from behavex.outputs.report_utils import (get_save_function, - match_for_execution, text, - try_operate_descriptor) + match_for_execution, + retry_file_operation, text) from behavex.utils import get_scenario_tags @@ -101,7 +101,7 @@ def get_status(scenario_): junit_path = os.path.join(get_env('OUTPUT'), 'behave') path_output = os.path.join(junit_path, u'TESTS-' + name + u'.xml') - try_operate_descriptor( + retry_file_operation( path_output + '.xml', get_save_function(path_output, output_text) ) diff --git a/behavex/runner.py b/behavex/runner.py index 7dce3b3..4684389 100644 --- a/behavex/runner.py +++ b/behavex/runner.py @@ -44,8 +44,8 @@ from behavex.outputs.report_json import generate_execution_info from behavex.outputs.report_utils import (get_overall_status, match_for_execution, - pretty_print_time, text, - try_operate_descriptor) + pretty_print_time, + retry_file_operation, text) from behavex.progress_bar import ProgressBar from behavex.utils import (IncludeNameMatch, IncludePathsMatch, MatchInclude, cleanup_folders, configure_logging, @@ -752,11 +752,16 @@ def _merge_and_remove(): with open(os.path.join(get_env('OUTPUT'), 'merged_behave_outputs.log'), 'a+') as behave_log_file: with open(stdout_file, 'r') as source_file: behave_log_file.write(source_file.read()) - os.close(source_file.fileno()) - os.remove(stdout_file) - + # nosec B110 + try: + if not source_file.closed: + os.close(source_file.fileno()) + if os.path.exists(stdout_file): + os.remove(stdout_file) + except: + pass try: - try_operate_descriptor(stdout_file, _merge_and_remove) + retry_file_operation(stdout_file, _merge_and_remove) except Exception as remove_ex: logging.warning(f"Could not remove stdout file {stdout_file}: {remove_ex}") # Don't fail the execution if we can't remove the file @@ -1184,7 +1189,7 @@ def _load_json(): json_output = {'environment': [], 'features': [], 'steps_definition': []} if os.path.exists(path_info): - json_output = try_operate_descriptor(path_info, _load_json, return_value=True) + json_output = retry_file_operation(path_info, _load_json, return_value=True) return json_output diff --git a/behavex/utils.py b/behavex/utils.py index b0c21c1..1115395 100644 --- a/behavex/utils.py +++ b/behavex/utils.py @@ -33,7 +33,7 @@ from behavex.outputs.output_strings import TEXTS from behavex.outputs.report_utils import (get_save_function, get_string_hash, match_for_execution, - try_operate_descriptor) + retry_file_operation) LOGGING_CFG = ConfigObj(os.path.join(global_vars.execution_path, 'conf_logging.cfg')) LOGGING_LEVELS = { @@ -250,10 +250,10 @@ def copy_bootstrap_html_generator(): bootstrap_path = ['outputs', 'bootstrap'] bootstrap_path = os.path.join(global_vars.execution_path, *bootstrap_path) if os.path.exists(destination_path): - try_operate_descriptor( + retry_file_operation( destination_path, lambda: shutil.rmtree(destination_path) ) - try_operate_descriptor( + retry_file_operation( destination_path, lambda: shutil.copytree(bootstrap_path, destination_path) ) @@ -265,18 +265,18 @@ def cleanup_folders(): def execution(): return shutil.rmtree(output_folder, ignore_errors=True) - try_operate_descriptor(output_folder, execution) + retry_file_operation(output_folder, execution) if not os.path.exists(output_folder): - try_operate_descriptor(output_folder, lambda: os.makedirs(output_folder)) + retry_file_operation(output_folder, lambda: os.makedirs(output_folder)) # temp folder temp_folder = get_env('temp') def execution(): return shutil.rmtree(temp_folder, ignore_errors=True) - try_operate_descriptor(temp_folder, execution) + retry_file_operation(temp_folder, execution) if not os.path.exists(temp_folder): - try_operate_descriptor(temp_folder, lambda: os.makedirs(temp_folder)) + retry_file_operation(temp_folder, lambda: os.makedirs(temp_folder)) # behave folder behave_folder = os.path.join(get_env('OUTPUT'), 'behave') @@ -284,9 +284,9 @@ def execution(): def execution(): return shutil.rmtree(behave_folder, ignore_errors=True) - try_operate_descriptor(behave_folder, execution) + retry_file_operation(behave_folder, execution) if not os.path.exists(behave_folder): - try_operate_descriptor(behave_folder, lambda: os.makedirs(behave_folder)) + retry_file_operation(behave_folder, lambda: os.makedirs(behave_folder)) def set_env_variable(key, value): @@ -422,7 +422,7 @@ def set_behave_tags(): tags_line = ' '.join(tags) tags_line = tags_line.replace('~', 'not ') tags_line = tags_line.replace(',', ' or ') - try_operate_descriptor( + retry_file_operation( behave_tags, execution=get_save_function(behave_tags, tags_line) )