From f4753208b3d62cca3c653af92743904e93a4b34c Mon Sep 17 00:00:00 2001 From: Mateusz Masiarz Date: Sun, 24 Sep 2023 18:37:15 +0200 Subject: [PATCH] Remove version changes, catch errors while validating expected scores --- src/sinol_make/__init__.py | 1 - src/sinol_make/commands/run/__init__.py | 24 ++++++- src/sinol_make/structs/status_structs.py | 1 + src/sinol_make/util.py | 79 ++++++++++++------------ 4 files changed, 61 insertions(+), 44 deletions(-) diff --git a/src/sinol_make/__init__.py b/src/sinol_make/__init__.py index e7d33398..b58096b3 100644 --- a/src/sinol_make/__init__.py +++ b/src/sinol_make/__init__.py @@ -61,7 +61,6 @@ def main_exn(): except Exception as err: util.exit_with_error('`oiejq` could not be installed.\n' + err) - util.make_version_changes() command.run(args) exit(0) diff --git a/src/sinol_make/commands/run/__init__.py b/src/sinol_make/commands/run/__init__.py index 8e3de681..4ece0801 100644 --- a/src/sinol_make/commands/run/__init__.py +++ b/src/sinol_make/commands/run/__init__.py @@ -827,6 +827,7 @@ def validate_expected_scores(self, results): added_groups = set() removed_groups = set() changes = [] + unknown_change = False for type, field, change in list(expected_scores_diff): if type == "add": @@ -877,6 +878,9 @@ def validate_expected_scores(self, results): old_result=change[0], result=change[1] )) + else: + unknown_change = True + return ValidationResult( added_solutions, @@ -885,7 +889,8 @@ def validate_expected_scores(self, results): removed_groups, changes, expected_scores, - new_expected_scores + new_expected_scores, + unknown_change, ) @@ -893,6 +898,10 @@ def print_expected_scores_diff(self, validation_results: ValidationResult): diff = validation_results config_expected_scores = self.config.get("sinol_expected_scores", {}) + if diff.unknown_change: + print(util.error("There was an unknown change in expected scores. " + "You should apply the suggested changes to avoid errors.")) + def warn_if_not_empty(set, message): if len(set) > 0: print(util.warning(message + ": "), end='') @@ -917,7 +926,7 @@ def print_points_change(solution, group, new_points, old_points): elif isinstance(change, PointsChange): print_points_change(change.solution, change.group, change.new_points, change.old_points) - if diff.expected_scores == diff.new_expected_scores: + if diff.expected_scores == diff.new_expected_scores and not diff.unknown_change: print(util.info("Expected scores are correct!")) else: def delete_group(solution, group): @@ -1157,6 +1166,15 @@ def run(self, args): results, all_results = self.compile_and_run(solutions) self.check_errors(all_results) - validation_results = self.validate_expected_scores(results) + try: + validation_results = self.validate_expected_scores(results) + except: + self.config = util.try_fix_config(self.config) + try: + validation_results = self.validate_expected_scores(results) + except: + util.exit_with_error("Validating expected scores failed. " + "This probably means that `sinol_expected_scores` is broken. " + "Delete it and run `sinol-make run --apply-suggestions` again.") self.print_expected_scores_diff(validation_results) self.exit() diff --git a/src/sinol_make/structs/status_structs.py b/src/sinol_make/structs/status_structs.py index 41b6f254..dd2317f4 100644 --- a/src/sinol_make/structs/status_structs.py +++ b/src/sinol_make/structs/status_structs.py @@ -67,6 +67,7 @@ class ValidationResult: changes: List[ResultChange] expected_scores: dict new_expected_scores: dict + unknown_change: bool @dataclass diff --git a/src/sinol_make/util.py b/src/sinol_make/util.py index ec0b59cd..0ad9120b 100644 --- a/src/sinol_make/util.py +++ b/src/sinol_make/util.py @@ -89,11 +89,9 @@ def save_config(config): "key": "sinol_expected_scores", "default_flow_style": None }, - "sinol_make_version", ] config = config.copy() - config["sinol_make_version"] = sinol_make.__version__ with open("config.yml", "w") as config_file: for field in order: if isinstance(field, dict): # If the field is a dict, it means that it has a custom property (for example default_flow_style). @@ -296,44 +294,45 @@ def get_file_md5(path): return hashlib.md5(f.read()).hexdigest() -def make_version_changes(): - if find_and_chdir_package(): - with open("config.yml", "r") as config_file: - config = yaml.load(config_file, Loader=yaml.FullLoader) - if "sinol_make_version" not in config: - config["sinol_make_version"] = "1.5.9" - if compare_versions(config["sinol_make_version"], "1.5.10") == -1: - # If the version is less than 1.5.10, we change the format of `sinol_expected_scores` field. - try: - new_expected_scores = {} - expected_scores = config["sinol_expected_scores"] - contest = get_contest_type() - groups = [] - for solution, results in expected_scores.items(): - for group in results["expected"].keys(): - if group not in groups: - groups.append(int(group)) - - scores = contest.assign_scores(groups) - for solution, results in expected_scores.items(): - new_expected_scores[solution] = {"expected": {}, "points": results["points"]} - for group, result in results["expected"].items(): - if result in Status.possible_statuses(): - new_expected_scores[solution]["expected"][group] = {"status": result} - if result == "OK": - new_expected_scores[solution]["expected"][group]["points"] = scores[group] - else: - new_expected_scores[solution]["expected"][group]["points"] = 0 - else: - # This means that the result is probably valid. - new_expected_scores[solution]["expected"][group] = result - config["sinol_expected_scores"] = new_expected_scores - save_config(config) - except: - # If there is an error, we just delete the field. - if "sinol_expected_scores" in config: - del config["sinol_expected_scores"] - save_config(config) +def try_fix_config(config): + """ + Function to try to fix the config.yml file. + Tries to: + - reformat `sinol_expected_scores` field + :param config: config.yml file as a dict + :return: config.yml file as a dict + """ + try: + new_expected_scores = {} + expected_scores = config["sinol_expected_scores"] + contest = get_contest_type() + groups = [] + for solution, results in expected_scores.items(): + for group in results["expected"].keys(): + if group not in groups: + groups.append(int(group)) + + scores = contest.assign_scores(groups) + for solution, results in expected_scores.items(): + new_expected_scores[solution] = {"expected": {}, "points": results["points"]} + for group, result in results["expected"].items(): + if result in Status.possible_statuses(): + new_expected_scores[solution]["expected"][group] = {"status": result} + if result == "OK": + new_expected_scores[solution]["expected"][group]["points"] = scores[group] + else: + new_expected_scores[solution]["expected"][group]["points"] = 0 + else: + # This means that the result is probably valid. + new_expected_scores[solution]["expected"][group] = result + config["sinol_expected_scores"] = new_expected_scores + save_config(config) + except: + # If there is an error, we just delete the field. + if "sinol_expected_scores" in config: + del config["sinol_expected_scores"] + save_config(config) + return config def color_red(text): return "\033[91m{}\033[00m".format(text)