From 6c9b7eca10686ad64cefd0307090b605e73d4844 Mon Sep 17 00:00:00 2001 From: gurglemurgle5 <95941332+gurglemurgle5@users.noreply.github.com> Date: Thu, 14 Nov 2024 16:43:42 -0600 Subject: [PATCH] Core: Fix Template Yamls for games with colon in name (#4106) * add quotes around strings containing {{ game }} * do the actually correct thing instead of a hack thanks berserker66 for pointing out to me that I was doing this the completly wrong way, so I fixed it up * Clean up filenames to prevent illegal chars * Use %s substitution instead of concatenation * whoops somehow i removed a space from the comment for the regex, so this adds it back * Use pre-existing function in Utils.py * Test: add test for option yaml with colon --------- Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com> --- Options.py | 4 +- data/options.yaml | 6 +-- test/options/test_generate_templates.py | 55 +++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 test/options/test_generate_templates.py diff --git a/Options.py b/Options.py index aa6f175f..992348cb 100644 --- a/Options.py +++ b/Options.py @@ -15,7 +15,7 @@ from dataclasses import dataclass from schema import And, Optional, Or, Schema from typing_extensions import Self -from Utils import get_fuzzy_results, is_iterable_except_str, output_path +from Utils import get_file_safe_name, get_fuzzy_results, is_iterable_except_str, output_path if typing.TYPE_CHECKING: from BaseClasses import MultiWorld, PlandoOptions @@ -1531,7 +1531,7 @@ def generate_yaml_templates(target_folder: typing.Union[str, "pathlib.Path"], ge del file_data - with open(os.path.join(target_folder, game_name + ".yaml"), "w", encoding="utf-8-sig") as f: + with open(os.path.join(target_folder, get_file_safe_name(game_name) + ".yaml"), "w", encoding="utf-8-sig") as f: f.write(res) diff --git a/data/options.yaml b/data/options.yaml index ee886662..09bfcdce 100644 --- a/data/options.yaml +++ b/data/options.yaml @@ -28,9 +28,9 @@ name: Player{number} # Used to describe your yaml. Useful if you have multiple files. -description: Default {{ game }} Template +description: {{ yaml_dump("Default %s Template" % game) }} -game: {{ game }} +game: {{ yaml_dump(game) }} requires: version: {{ __version__ }} # Version of Archipelago required for this yaml to work as expected. @@ -44,7 +44,7 @@ requires: {%- endfor -%} {% endmacro %} -{{ game }}: +{{ yaml_dump(game) }}: {%- for group_name, group_options in option_groups.items() %} # {{ group_name }} diff --git a/test/options/test_generate_templates.py b/test/options/test_generate_templates.py new file mode 100644 index 00000000..cab97c54 --- /dev/null +++ b/test/options/test_generate_templates.py @@ -0,0 +1,55 @@ +import unittest + +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import TYPE_CHECKING, Dict, Type +from Utils import parse_yaml + +if TYPE_CHECKING: + from worlds.AutoWorld import World + + +class TestGenerateYamlTemplates(unittest.TestCase): + old_world_types: Dict[str, Type["World"]] + + def setUp(self) -> None: + import worlds.AutoWorld + + self.old_world_types = worlds.AutoWorld.AutoWorldRegister.world_types + + def tearDown(self) -> None: + import worlds.AutoWorld + + worlds.AutoWorld.AutoWorldRegister.world_types = self.old_world_types + + if "World: with colon" in worlds.AutoWorld.AutoWorldRegister.world_types: + del worlds.AutoWorld.AutoWorldRegister.world_types["World: with colon"] + + def test_name_with_colon(self) -> None: + from Options import generate_yaml_templates + from worlds.AutoWorld import AutoWorldRegister + from worlds.AutoWorld import World + + class WorldWithColon(World): + game = "World: with colon" + item_name_to_id = {} + location_name_to_id = {} + + AutoWorldRegister.world_types = {WorldWithColon.game: WorldWithColon} + with TemporaryDirectory(f"archipelago_{__name__}") as temp_dir: + generate_yaml_templates(temp_dir) + path: Path + for path in Path(temp_dir).iterdir(): + self.assertTrue(path.is_file()) + self.assertTrue(path.suffix == ".yaml") + with path.open(encoding="utf-8") as f: + try: + data = parse_yaml(f) + except: + f.seek(0) + print(f"Error in {path.name}:\n{f.read()}") + raise + self.assertIn("game", data) + self.assertIn(":", data["game"]) + self.assertIn(data["game"], data) + self.assertIsInstance(data[data["game"]], dict)