Load Entries in Book instead of Category

This commit is contained in:
object-Object 2023-06-20 22:54:28 -04:00
parent d282ff8ffb
commit e52bbc37be
3 changed files with 51 additions and 43 deletions

View file

@ -153,17 +153,19 @@ class Book:
self.__post_init_pre_categories__(*args, **kwargs)
# categories
self.categories: dict[ResourceLocation, patchouli.Category] = {}
for path in self.categories_dir.rglob("*.json"):
category = patchouli.Category.load(path, self)
self.categories[category.id] = category
self.categories = patchouli.Category.load_all(self)
# NOTE: category sorting requires book.categories to already contain all of the
# categories, because category sorting depends on its parent, and categories get
# their parent from the book. it's mildly scuffed, but it works
self.categories = sorted_dict(self.categories)
# entries
# must be after categories, since Entry uses book.categories to get the parent
for path in self.entries_dir.rglob("*.json"):
# i used the entry to insert the entry
# pretty sure thanos said that
entry = patchouli.Entry.load(path, self)
entry.category.entries.append(entry)
# TODO: entries
# we inserted a bunch of entries in no particular order, so sort each category
for category in self.categories.values():
category.entries.sort()
def __post_init_pre_categories__(self) -> None:
"""Subclasses may override this method to run code just before categories are
@ -172,17 +174,21 @@ class Book:
Type hooks are initialized before this, so you can add more here if needed.
"""
@property
def _dir_with_lang(self) -> Path:
return self.props.book_dir / self.props.i18n.lang
@property
def categories_dir(self) -> Path:
return self.props.book_dir / self.props.i18n.lang / "categories"
return self._dir_with_lang / "categories"
@property
def entries_dir(self) -> Path:
return self.props.book_dir / self.props.i18n.lang / "entries"
return self._dir_with_lang / "entries"
@property
def templates_dir(self) -> Path:
return self.props.book_dir / self.props.i18n.lang / "templates"
return self._dir_with_lang / "templates"
def format(
self,

View file

@ -7,7 +7,7 @@ from typing import Self
import patchouli
from common.deserialize import from_dict_checked, load_json_data, rename
from common.formatting import FormatTree
from common.types import LocalizedStr, Sortable
from common.types import LocalizedStr, Sortable, sorted_dict
from minecraft.resource import ItemStack, ResourceLocation
@ -28,23 +28,37 @@ class Category(Sortable, patchouli.BookHelpers):
icon: ItemStack
# optional (category.json)
parent_id: ResourceLocation | None = field(default=None, metadata=rename("parent"))
_parent_id: ResourceLocation | None = field(default=None, metadata=rename("parent"))
parent: Category | None = field(default=None, init=False)
flag: str | None = None
sortnum: int = 0
secret: bool = False
def __post_init__(self):
self.entries: list[patchouli.Entry] = []
@classmethod
def load(cls, path: Path, book: patchouli.Book) -> Self:
def _load(cls, path: Path, book: patchouli.Book) -> Self:
# load the raw data from json, and add our extra fields
data = load_json_data(cls, path, {"path": path, "book": book})
return from_dict_checked(cls, data, book.config(), path)
def __post_init__(self):
# load entries
entry_dir = self.book.entries_dir / self.id.path
self.entries: list[patchouli.Entry] = sorted(
patchouli.Entry.load(path, self) for path in entry_dir.glob("*.json")
)
@classmethod
def load_all(cls, book: patchouli.Book):
categories: dict[ResourceLocation, Self] = {}
# load
for path in book.categories_dir.rglob("*.json"):
category = cls._load(path, book)
categories[category.id] = category
# late-init parent
for category in categories.values():
if category._parent_id is not None:
category.parent = categories[category._parent_id]
# return sorted by sortnum, which requires parent to be initialized
return sorted_dict(categories)
@property
def id(self) -> ResourceLocation:
@ -54,16 +68,9 @@ class Category(Sortable, patchouli.BookHelpers):
self.path,
)
def parent(self) -> Category | None:
"""Get this category's parent from the book. Must not be called until the book
is fully initialized."""
if self.parent_id is None:
return None
return self.book.categories[self.parent_id]
@property
def _cmp_key(self) -> tuple[int, ...]:
# implement Sortable
if parent := self.parent():
if parent := self.parent:
return parent._cmp_key + (self.sortnum,)
return (self.sortnum,)

View file

@ -19,11 +19,11 @@ class Entry(Sortable, patchouli.BookHelpers):
# non-json fields
path: Path
category: patchouli.Category
category: patchouli.Category = field(init=False)
# required (entry.json)
name: LocalizedStr
category_id: ResourceLocation = field(metadata=rename("category"))
_category_id: ResourceLocation = field(metadata=rename("category"))
icon: ItemStack
pages: list[patchouli.Page]
@ -39,19 +39,14 @@ class Entry(Sortable, patchouli.BookHelpers):
entry_color: Color | None = None # this is undocumented lmao
@classmethod
def load(cls, path: Path, category: patchouli.Category) -> Self:
# load the raw data from json, and add our extra fields
data = load_json_data(cls, path, {"path": path, "category": category})
config = category.book.config()
return from_dict_checked(cls, data, config, path)
def load(cls, path: Path, book: patchouli.Book) -> Self:
# load and convert the raw data from json
data = load_json_data(cls, path, {"path": path})
entry = from_dict_checked(cls, data, book.config(), path)
def __post_init__(self):
# check the category id, just for fun
# note the _ and . on the left and right respectively
if self.category_id != self.category.id:
raise ValueError(
f"Entry {self.name} has category {self.category_id} but was initialized by {self.category.id}"
)
# now that it's been type hooked, use the id to get the category
entry.category = book.categories[entry._category_id]
return entry
@property
def book(self) -> patchouli.Book: