From 1299d3f0c576ff3070f15180f3334dc04de0548a Mon Sep 17 00:00:00 2001 From: ym1906 Date: Wed, 13 Nov 2024 17:40:31 +0000 Subject: [PATCH 1/5] added command to update obsolete variables in IN.DAT --- process/main.py | 109 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 75 insertions(+), 34 deletions(-) diff --git a/process/main.py b/process/main.py index ddf5acac..0291d196 100644 --- a/process/main.py +++ b/process/main.py @@ -197,6 +197,11 @@ def parse_args(self, args): action="store_true", help="Print the version of PROCESS to the terminal", ) + parser.add_argument( + "--update_obsolete", + action="store_true", + help="Automatically update obsolete variables in the IN.DAT file", + ) # If args is not None, then parse the supplied arguments. This is likely # to come from the test suite when testing command-line arguments; the @@ -215,7 +220,9 @@ def run_mode(self): if self.args.varyiterparams: self.run = VaryRun(self.args.varyiterparamsconfig, self.args.solver) else: - self.run = SingleRun(self.args.input, self.args.solver) + self.run = SingleRun( + self.args.input, self.args.update_obsolete, self.args.solver + ) self.run.run() def post_process(self): @@ -355,7 +362,7 @@ def run(self): class SingleRun: """Perform a single run of PROCESS.""" - def __init__(self, input_file, solver="vmcon"): + def __init__(self, input_file, update_obsolete, solver="vmcon"): """Read input file and initialise variables. :param input_file: input file named IN.DAT @@ -365,7 +372,7 @@ def __init__(self, input_file, solver="vmcon"): """ self.input_file = input_file - self.validate_input() + self.validate_input(update_obsolete) self.init_module_vars() self.set_filenames() self.initialise() @@ -524,49 +531,83 @@ def append_input(self): mfile_file.write("***********************************************") mfile_file.writelines(input_lines) - def validate_input(self): - """Checks the input IN.DAT file for any obsolete variables in the OBS_VARS dict contained - within obsolete_variables.py. - Then will print out what the used obsolete variables are (if any) before continuing the proces run. + def validate_input(self, replace_obsolete=False): + """ + Checks the input IN.DAT file for any obsolete variables in the OBS_VARS dict contained + within obsolete_variables.py. If obsolete variables are found, and if `replace_obsolete` + is set to True, they are either removed or replaced by their updated names as specified + in the OBS_VARS dictionary. + + Parameters: + replace_obsolete (bool): If True, modifies the IN.DAT file to replace or comment out + obsolete variables. If False, only reports obsolete variables. """ obsolete_variables = ov.OBS_VARS obsolete_vars_help_message = ov.OBS_VARS_HELP filename = self.input_file - variables_in_in_dat = [] + modified_lines = [] + with open(filename, "r") as file: for line in file: - if line[0] == "*" or "=" not in line: + # Skip comment lines or lines without an assignment + if line.startswith("*") or "=" not in line: + modified_lines.append(line) continue + # Extract the variable name before the separator + variable_name = line.strip().split(" ", 1)[0] + variables_in_in_dat.append(variable_name) + + # Check if the variable is obsolete and needs replacing + if variable_name in obsolete_variables: + replacement = obsolete_variables.get(variable_name) + + if replace_obsolete: + # Prepare replacement or removal + if replacement is None: + # If no replacement is defined, comment out the line + modified_lines.append(f"* Obsolete: {line}") + else: + # Replace obsolete variable with updated variable + modified_line = line.replace(variable_name, replacement, 1) + modified_lines.append( + f"* Replaced '{variable_name}' with '{replacement}'\n{modified_line}" + ) + else: + # If replacement is False, add the line as-is + modified_lines.append(line) else: - sep = " " - variables = line.strip().split(sep, 1)[0] - variables_in_in_dat.append(variables) - - obs_vars_in_in_dat = [] - replace_hints = {} - for var in variables_in_in_dat: - if var in obsolete_variables: - obs_vars_in_in_dat.append(var) - replace_hints[var] = obsolete_variables.get(var) - - if len(obs_vars_in_in_dat) > 0: - message = ( - "The IN.DAT file contains obsolete variables from the OBS_VARS dictionary. The obsolete variables in your IN.DAT file are: " - f"{obs_vars_in_in_dat}. " - "Either remove these or replace them with their updated variable names. " - ) - for obs_var in obs_vars_in_in_dat: - if replace_hints[obs_var] is None: - message += f"\n\n {obs_var} is an obsolete variable and needs to be removed. " - else: - message += f"\n \n {obs_var} is an obsolete variable and needs to be replaced by {str(replace_hints[obs_var])}. " - message += f"{obsolete_vars_help_message.get(obs_var, '')}" - - raise ValueError(message) + modified_lines.append(line) + + obs_vars_in_in_dat = [ + var for var in variables_in_in_dat if var in obsolete_variables + ] + if obs_vars_in_in_dat: + if replace_obsolete: + # If replace_obsolete is True, write the modified content to the file + with open(filename, "w") as file: + file.writelines(modified_lines) + print( + "The IN.DAT file has been updated to replace or comment out obsolete variables." + ) + else: + # Only print the report if replace_obsolete is False + message = ( + "The IN.DAT file contains obsolete variables from the OBS_VARS dictionary. " + f"The obsolete variables in your IN.DAT file are: {obs_vars_in_in_dat}. " + "Either remove these or replace them with their updated variable names. " + ) + for obs_var in obs_vars_in_in_dat: + replacement = obsolete_variables.get(obs_var) + if replacement is None: + message += f"\n\n{obs_var} is an obsolete variable and needs to be removed." + else: + message += f"\n\n{obs_var} is an obsolete variable and needs to be replaced by {replacement}." + message += f" {obsolete_vars_help_message.get(obs_var, '')}" + raise ValueError(message) else: print("The IN.DAT file does not contain any obsolete variables.") From 7675db11b1cb01f06642e452cb34160afa08c331 Mon Sep 17 00:00:00 2001 From: ym1906 Date: Thu, 14 Nov 2024 09:16:29 +0000 Subject: [PATCH 2/5] Updated with default for update_obsolete --- process/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/process/main.py b/process/main.py index 0291d196..92834695 100644 --- a/process/main.py +++ b/process/main.py @@ -362,7 +362,7 @@ def run(self): class SingleRun: """Perform a single run of PROCESS.""" - def __init__(self, input_file, update_obsolete, solver="vmcon"): + def __init__(self, input_file, update_obsolete=False, solver="vmcon"): """Read input file and initialise variables. :param input_file: input file named IN.DAT From feaf3ac84fe80d22017cef154692c3176ce1cd4c Mon Sep 17 00:00:00 2001 From: ym1906 Date: Thu, 14 Nov 2024 09:27:13 +0000 Subject: [PATCH 3/5] Updated to print out the changes in the terminal --- process/main.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/process/main.py b/process/main.py index 92834695..34f35626 100644 --- a/process/main.py +++ b/process/main.py @@ -549,6 +549,7 @@ def validate_input(self, replace_obsolete=False): filename = self.input_file variables_in_in_dat = [] modified_lines = [] + changes_made = [] # To store details of the changes with open(filename, "r") as file: for line in file: @@ -570,12 +571,18 @@ def validate_input(self, replace_obsolete=False): if replacement is None: # If no replacement is defined, comment out the line modified_lines.append(f"* Obsolete: {line}") + changes_made.append( + f"Commented out obsolete variable: {variable_name}" + ) else: # Replace obsolete variable with updated variable modified_line = line.replace(variable_name, replacement, 1) modified_lines.append( f"* Replaced '{variable_name}' with '{replacement}'\n{modified_line}" ) + changes_made.append( + f"Replaced '{variable_name}' with '{replacement}'" + ) else: # If replacement is False, add the line as-is modified_lines.append(line) @@ -593,6 +600,9 @@ def validate_input(self, replace_obsolete=False): print( "The IN.DAT file has been updated to replace or comment out obsolete variables." ) + print("Summary of changes made:") + for change in changes_made: + print(f" - {change}") else: # Only print the report if replace_obsolete is False message = ( From d0f236a74b5b876e73f319087643b8913b95ac00 Mon Sep 17 00:00:00 2001 From: ym1906 Date: Thu, 14 Nov 2024 10:14:01 +0000 Subject: [PATCH 4/5] added update_obsolete to namespace --- tests/unit/test_main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/test_main.py b/tests/unit/test_main.py index 858886cf..b348d580 100644 --- a/tests/unit/test_main.py +++ b/tests/unit/test_main.py @@ -102,6 +102,8 @@ def test_run_mode(process_obj, monkeypatch): monkeypatch.setattr(process_obj, "args", argparse.Namespace(), raising=False) monkeypatch.setattr(process_obj.args, "varyiterparams", True, raising=False) monkeypatch.setattr(process_obj.args, "version", False, raising=False) + monkeypatch.setattr(process_obj.args, "update_obsolete", False, raising=False) + monkeypatch.setattr( process_obj.args, "varyiterparamsconfig", "file.conf", raising=False ) From b9791614ca693a39745a3a57b39ebd0b91efee66 Mon Sep 17 00:00:00 2001 From: ym1906 Date: Fri, 22 Nov 2024 15:40:34 +0000 Subject: [PATCH 5/5] Updated argument name. Updated init for singlerun to use keyword argument. Modified parsing to find variables with spacing around equals. Added error for when there is a list of replacements --- process/main.py | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/process/main.py b/process/main.py index 34f35626..be7052a4 100644 --- a/process/main.py +++ b/process/main.py @@ -198,7 +198,7 @@ def parse_args(self, args): help="Print the version of PROCESS to the terminal", ) parser.add_argument( - "--update_obsolete", + "--update-obsolete", action="store_true", help="Automatically update obsolete variables in the IN.DAT file", ) @@ -221,7 +221,9 @@ def run_mode(self): self.run = VaryRun(self.args.varyiterparamsconfig, self.args.solver) else: self.run = SingleRun( - self.args.input, self.args.update_obsolete, self.args.solver + self.args.input, + self.args.solver, + update_obsolete=self.args.update_obsolete, ) self.run.run() @@ -362,9 +364,8 @@ def run(self): class SingleRun: """Perform a single run of PROCESS.""" - def __init__(self, input_file, update_obsolete=False, solver="vmcon"): + def __init__(self, input_file, solver="vmcon", *, update_obsolete=False): """Read input file and initialise variables. - :param input_file: input file named IN.DAT :type input_file: str :param solver: which solver to use, as specified in solver.py @@ -559,7 +560,7 @@ def validate_input(self, replace_obsolete=False): continue # Extract the variable name before the separator - variable_name = line.strip().split(" ", 1)[0] + variable_name = line.split("=", 1)[0].strip() variables_in_in_dat.append(variable_name) # Check if the variable is obsolete and needs replacing @@ -575,14 +576,24 @@ def validate_input(self, replace_obsolete=False): f"Commented out obsolete variable: {variable_name}" ) else: - # Replace obsolete variable with updated variable - modified_line = line.replace(variable_name, replacement, 1) - modified_lines.append( - f"* Replaced '{variable_name}' with '{replacement}'\n{modified_line}" - ) - changes_made.append( - f"Replaced '{variable_name}' with '{replacement}'" - ) + if isinstance(replacement, list): + # Raise an error if replacement is a list + replacement_str = ", ".join(replacement) + raise ValueError( + f"The variable '{variable_name}' is obsolete and should be replaced by the following variables: {replacement_str}. " + "Please set their values accordingly." + ) + else: + # Replace obsolete variable with updated variable + modified_line = line.replace( + variable_name, replacement, 1 + ) + modified_lines.append( + f"* Replaced '{variable_name}' with '{replacement}'\n{modified_line}" + ) + changes_made.append( + f"Replaced '{variable_name}' with '{replacement}'" + ) else: # If replacement is False, add the line as-is modified_lines.append(line)