From 036579607cb7c38894bc1b3674957eac602ffc78 Mon Sep 17 00:00:00 2001 From: object-Object Date: Wed, 23 Aug 2023 08:34:06 -0400 Subject: [PATCH] Add stricter pattern page validation --- .../hexcasting/lang/en_us.flatten.json5 | 8 ++- .../great_spells/greater_sentinel.json | 1 + .../en_us/entries/patterns/lists.json | 12 ++--- .../hexcasting/page/abstract_hex_pages.py | 2 +- doc/src/hexdoc/hexcasting/page/hex_pages.py | 8 ++- doc/src/hexdoc/hexdoc.py | 19 ++++--- doc/src/hexdoc/utils/resource_loader.py | 6 ++- doc/test/__snapshots__/test_snapshots.ambr | 54 ++++++++++++------- 8 files changed, 71 insertions(+), 39 deletions(-) diff --git a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 index c3f58087..66d5da40 100644 --- a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 +++ b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 @@ -599,9 +599,7 @@ append: "Integration Distillation", unappend: "Derivation Distillation", - concat: "Combination Distillation", index: "Selection Distillation", - list_size: "Abacus Purification", singleton: "Single's Purification", empty_list: "Vacant Reflection", reverse: "Retrograde Purification", @@ -1604,7 +1602,7 @@ numlist: "Set operations are odd, in that some of them can accept two numbers or two lists, but not a combination thereof. Such arguments will be written as \"(num, num)|(list, list)\".$(br2)When numbers are used in those operations, they are being used as so-called binary \"bitsets\", lists of 1 and 0, true and false, \"on\" and \"off\".", "or.1": "Unifies two sets.", - "or.2": "As such:$(li)With two numbers at the top of the stack, combines them into a bitset containing every \"on\" bit in either bitset.$(li)With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to $(l:patterns/lists#hexcasting:concat)$(action)Combination Distillation/$.", + "or.2": "As such:$(li)With two numbers at the top of the stack, combines them into a bitset containing every \"on\" bit in either bitset.$(li)With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to $(l:patterns/lists#hexcasting:add)$(action)Combination Distillation/$.", "and.1": "Takes the intersection of two sets.", "and.2": "As such:$(li)With two numbers at the top of the stack, combines them into a bitset containing every \"on\" bit present in $(italics)both/$ bitsets.$(li)With two lists, this creates a list of every element from the first list that is also in the second list.", @@ -1709,10 +1707,10 @@ slice: "Remove the two numbers at the top of the stack, then take a sublist of the list at the top of the stack between those indices, lower bound inclusive, upper bound exclusive. For example, the 0, 2 sublist of [0, 1, 2, 3, 4] would be [0, 1].", append: "Remove the top of the stack, then add it to the end of the list at the top of the stack.", unappend: "Remove the iota on the end of the list at the top of the stack, and add it to the top of the stack.", - concat: "Remove the list at the top of the stack, then add all its elements to the end of the list at the top of the stack.", + add: "Remove the list at the top of the stack, then add all its elements to the end of the list at the top of the stack.", empty_list: "Push an empty list to the top of the stack.", singleton: "Remove the top of the stack, then push a list containing only that element.", - list_size: "Remove the list at the top of the stack, then push the number of elements in the list to the stack.", + abs: "Remove the list at the top of the stack, then push the number of elements in the list to the stack.", reverse: "Reverse the list at the top of the stack.", index_of: "Remove the iota at the top of the stack, then replace the list at the top with the first index of that iota within the list (starting from 0). Replaces the list with -1 if the iota doesn't exist in the list.", remove_from: "Remove the number at the top of the stack, then remove the nth element of the list at the top of the stack (where n is the number you removed).", diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/great_spells/greater_sentinel.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/great_spells/greater_sentinel.json index 0e26650f..e436b44e 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/great_spells/greater_sentinel.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/great_spells/greater_sentinel.json @@ -9,6 +9,7 @@ { "type": "hexcasting:pattern", "op_id": "hexcasting:sentinel/create/great", + "anchor": "hexcasting:sentinel/create/great", "text": "hexcasting.page.greater_sentinel.1", "input": "vector", "output": "" diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/lists.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/lists.json index 267a1a40..8dfe25a2 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/lists.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/lists.json @@ -40,12 +40,12 @@ }, { "type": "hexcasting:pattern", - "header": "hexcasting.action.hexcasting:concat", + "header": "hexcasting.action.hexcasting:add", "op_id": "hexcasting:add", - "anchor": "hexcasting:concat", + "anchor": "hexcasting:add", "input": "list, list", "output": "list", - "text": "hexcasting.page.lists.concat" + "text": "hexcasting.page.lists.add" }, { "type": "hexcasting:pattern", @@ -65,12 +65,12 @@ }, { "type": "hexcasting:pattern", - "header": "hexcasting.action.hexcasting:list_size", + "header": "hexcasting.action.hexcasting:abs", "op_id": "hexcasting:abs", - "anchor": "hexcasting:list_size", + "anchor": "hexcasting:abs", "input": "list", "output": "num", - "text": "hexcasting.page.lists.list_size" + "text": "hexcasting.page.lists.abs" }, { "type": "hexcasting:pattern", diff --git a/doc/src/hexdoc/hexcasting/page/abstract_hex_pages.py b/doc/src/hexdoc/hexcasting/page/abstract_hex_pages.py index 93cc949d..1d910c0f 100644 --- a/doc/src/hexdoc/hexcasting/page/abstract_hex_pages.py +++ b/doc/src/hexdoc/hexcasting/page/abstract_hex_pages.py @@ -12,7 +12,6 @@ from hexdoc.utils.deserialize import cast_or_raise from ..pattern import RawPatternInfo -# TODO: make anchor required (breaks because of Greater Sentinel) class PageWithPattern(PageWithText, type=None): header: LocalizedStr patterns: list[RawPatternInfo] @@ -44,6 +43,7 @@ class PageWithPattern(PageWithText, type=None): class PageWithOpPattern(PageWithPattern, type=None): op_id: ResourceLocation + anchor: str @model_validator(mode="before") def _pre_root_header(cls, values: Any, info: ValidationInfo): diff --git a/doc/src/hexdoc/hexcasting/page/hex_pages.py b/doc/src/hexdoc/hexcasting/page/hex_pages.py index bdb173b5..b7e1f924 100644 --- a/doc/src/hexdoc/hexcasting/page/hex_pages.py +++ b/doc/src/hexdoc/hexcasting/page/hex_pages.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, Self from pydantic import ValidationInfo, model_validator @@ -32,6 +32,12 @@ class LookupPatternPage(PageWithOpPattern, type="hexcasting:pattern"): case _: return values + @model_validator(mode="after") + def _check_anchor(self) -> Self: + if str(self.op_id) != self.anchor: + raise ValueError(f"op_id={self.op_id} does not equal anchor={self.anchor}") + return self + class ManualOpPatternPage( PageWithOpPattern, diff --git a/doc/src/hexdoc/hexdoc.py b/doc/src/hexdoc/hexdoc.py index 97e6eea0..8190b198 100644 --- a/doc/src/hexdoc/hexdoc.py +++ b/doc/src/hexdoc/hexdoc.py @@ -32,7 +32,7 @@ class Args: properties_file: Path output_file: Path | None - verbose: bool + verbose: int ci: bool @classmethod @@ -41,7 +41,7 @@ class Args: parser.add_argument("properties_file", type=Path) parser.add_argument("--output_file", "-o", type=Path) - parser.add_argument("--verbose", "-v", action="store_true") + parser.add_argument("--verbose", "-v", action="count", default=0) parser.add_argument("--ci", action="store_true") return cls(**vars(parser.parse_args(args))) @@ -55,6 +55,16 @@ class Args: if self.ci and os.getenv("RUNNER_DEBUG") == "1": self.verbose = True + @property + def log_level(self) -> int: + match self.verbose: + case 0: + return logging.WARNING + case 1: + return logging.INFO + case _: + return logging.DEBUG + def main(args: Args | None = None) -> None: # allow passing Args for test cases, but parse by default @@ -72,11 +82,8 @@ def main(args: Args | None = None) -> None: logging.basicConfig( style="{", format="\033[1m[{relativeCreated:.02f} | {levelname} | {name}]\033[0m {message}", + level=args.log_level, ) - logger = logging.getLogger(__name__) - if args.verbose: - logging.getLogger().setLevel(logging.DEBUG) - logger.debug("Log level set to DEBUG") # load the book props = Properties.load(args.properties_file) diff --git a/doc/src/hexdoc/utils/resource_loader.py b/doc/src/hexdoc/utils/resource_loader.py index a350ceba..983f3722 100644 --- a/doc/src/hexdoc/utils/resource_loader.py +++ b/doc/src/hexdoc/utils/resource_loader.py @@ -202,7 +202,9 @@ class ModResourceLoader: if not path.is_file(): raise FileNotFoundError(path) - logging.getLogger(__name__).debug(f"Loading {path}") + logger = logging.getLogger(__name__) + logger.info(f"Loading {path}") + data = path.read_text("utf-8") value = decode(data) @@ -210,7 +212,7 @@ class ModResourceLoader: out_path = self.props.export_dir / path.relative_to(resource_dir.path) out_path.parent.mkdir(parents=True, exist_ok=True) - logging.getLogger(__name__).debug(f"Exporting {path} to {out_path}") + logger.debug(f"Exporting {path} to {out_path}") match export: case None: out_data = data diff --git a/doc/test/__snapshots__/test_snapshots.ambr b/doc/test/__snapshots__/test_snapshots.ambr index 7bc58928..1d0930e4 100644 --- a/doc/test/__snapshots__/test_snapshots.ambr +++ b/doc/test/__snapshots__/test_snapshots.ambr @@ -3762,9 +3762,9 @@

Remove the iota on the end of the list at the top of the stack, and add it to the top of the stack.


-
+

Additive Distillation (list, list → list)

@@ -3822,9 +3822,9 @@

Remove the top of the stack, then push a list containing only that element.


-
+

Length Purification (list → num)

@@ -4530,7 +4530,7 @@

Unifies two sets.


-

As such:

With two numbers at the top of the stack, combines them into a bitset containing every "on" bit in either bitset.

With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to Combination Distillation.

+

As such:

With two numbers at the top of the stack, combines them into a bitset containing every "on" bit in either bitset.

With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to Combination Distillation.


Conjunction Distillation ((num, num)|(list, list) → num|list)

-

Summon Greater Sentinel (vector →)

+
+

Summon Greater Sentinel (vector →)

Your browser does not support visualizing patterns. Pattern code: waeawaeqqqwqwqqwq

Summon a greater version of my Sentinel. Costs about two Amethyst Dust.

+

The stronger sentinel acts like the normal one I can summon without the use of a Great Spell, if a little more visually interesting. However, the range in which my spells can work is extended to a small region around my greater sentinel, about 16 blocks. In other words, no matter where in the world I am, I can interact with things around my sentinel (the mysterious forces of chunkloading notwithstanding).


@@ -9794,9 +9800,9 @@

Remove the iota on the end of the list at the top of the stack, and add it to the top of the stack.


-
+

Additive Distillation (list, list → list)

@@ -9854,9 +9860,9 @@

Remove the top of the stack, then push a list containing only that element.


-
+

Length Purification (list → num)

@@ -10562,7 +10568,7 @@

Unifies two sets.


-

As such:

With two numbers at the top of the stack, combines them into a bitset containing every "on" bit in either bitset.

With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to Combination Distillation.

+

As such:

With two numbers at the top of the stack, combines them into a bitset containing every "on" bit in either bitset.

With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to Combination Distillation.


Conjunction Distillation ((num, num)|(list, list) → num|list)

-

Summon Greater Sentinel (vector →)

+
+

Summon Greater Sentinel (vector →)

Your browser does not support visualizing patterns. Pattern code: waeawaeqqqwqwqqwq

Summon a greater version of my Sentinel. Costs about two Amethyst Dust.

+

The stronger sentinel acts like the normal one I can summon without the use of a Great Spell, if a little more visually interesting. However, the range in which my spells can work is extended to a small region around my greater sentinel, about 16 blocks. In other words, no matter where in the world I am, I can interact with things around my sentinel (the mysterious forces of chunkloading notwithstanding).


@@ -15828,9 +15840,9 @@

Remove the iota on the end of the list at the top of the stack, and add it to the top of the stack.


-
+

Additive Distillation (list, list → list)

@@ -15888,9 +15900,9 @@

Remove the top of the stack, then push a list containing only that element.


-
+

Length Purification (list → num)

@@ -16596,7 +16608,7 @@

Unifies two sets.


-

As such:

With two numbers at the top of the stack, combines them into a bitset containing every "on" bit in either bitset.

With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to Combination Distillation.

+

As such:

With two numbers at the top of the stack, combines them into a bitset containing every "on" bit in either bitset.

With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to Combination Distillation.


Conjunction Distillation ((num, num)|(list, list) → num|list)

-

Summon Greater Sentinel (vector →)

+
+

Summon Greater Sentinel (vector →)

Your browser does not support visualizing patterns. Pattern code: waeawaeqqqwqwqqwq

Summon a greater version of my Sentinel. Costs about two Amethyst Dust.

+

The stronger sentinel acts like the normal one I can summon without the use of a Great Spell, if a little more visually interesting. However, the range in which my spells can work is extended to a small region around my greater sentinel, about 16 blocks. In other words, no matter where in the world I am, I can interact with things around my sentinel (the mysterious forces of chunkloading notwithstanding).