The great refactoring (move to hexdoc package and add reexports)
This commit is contained in:
parent
2960568e91
commit
03e7683ae1
53 changed files with 475 additions and 404 deletions
36
.vscode/settings.json
vendored
36
.vscode/settings.json
vendored
|
@ -1,36 +0,0 @@
|
|||
{
|
||||
"[python]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true,
|
||||
},
|
||||
"editor.rulers": [88],
|
||||
},
|
||||
"[html][jinja-html]": {
|
||||
"editor.rulers": [120],
|
||||
},
|
||||
"python.formatting.provider": "black",
|
||||
"python.analysis.typeCheckingMode": "strict", // god save us
|
||||
"python.analysis.diagnosticSeverityOverrides": {
|
||||
"reportMissingParameterType": "error",
|
||||
"reportUnknownParameterType": "error",
|
||||
"reportUnknownArgumentType": "warning",
|
||||
"reportUnknownLambdaType": "warning",
|
||||
"reportUnknownVariableType": "none",
|
||||
"reportUnknownMemberType": "warning",
|
||||
"reportUnnecessaryComparison": "warning",
|
||||
"reportMissingTypeArgument": "warning",
|
||||
"reportUnusedImport": "information",
|
||||
"reportPrivateUsage": "warning",
|
||||
"reportUnnecessaryIsInstance": "information",
|
||||
},
|
||||
"python.analysis.diagnosticMode": "workspace",
|
||||
"python.languageServer": "Pylance",
|
||||
"python.testing.cwd": "${workspaceFolder}/doc",
|
||||
"python.testing.unittestEnabled": false,
|
||||
"python.testing.pytestEnabled": true,
|
||||
"python.analysis.extraPaths": ["${workspaceFolder}/doc/src", "${workspaceFolder}/doc/test"],
|
||||
"isort.args": [
|
||||
"--settings", "doc/pyproject.toml"
|
||||
]
|
||||
}
|
11
doc/.vscode/extensions.json
vendored
Normal file
11
doc/.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
"ms-python.vscode-pylance",
|
||||
"ms-python.isort",
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": [
|
||||
"ms-python.black-formatter",
|
||||
]
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
"type": "python",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}/doc",
|
||||
"module": "hexcasting.scripts.main",
|
||||
"module": "hexdoc",
|
||||
"args": [
|
||||
"properties.toml",
|
||||
],
|
18
doc/.vscode/settings.json
vendored
Normal file
18
doc/.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"[python]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true,
|
||||
},
|
||||
"editor.rulers": [88],
|
||||
},
|
||||
"python.formatting.provider": "black",
|
||||
"isort.importStrategy": "fromEnvironment",
|
||||
"python.languageServer": "Pylance",
|
||||
"python.analysis.diagnosticMode": "workspace",
|
||||
"python.testing.unittestEnabled": false,
|
||||
"python.testing.pytestEnabled": true,
|
||||
"[html][jinja-html]": {
|
||||
"editor.rulers": [120],
|
||||
},
|
||||
}
|
|
@ -51,12 +51,8 @@ package = "{src}/main/java/at/petrak/hexcasting"
|
|||
resources = "{src}/main/resources"
|
||||
generated = "{src}/generated/resources"
|
||||
pattern_stubs = [
|
||||
# these are tables so we have the option to add extra per-stub configs (eg. regex)
|
||||
# NOTE: each ^ is like ../ in a file path (^key and ^.key are both valid)
|
||||
# the parent of an item in an array is the table containing the array, not the array
|
||||
# so in this case, {^.package} is common.package
|
||||
{ file = "{^.package}/common/casting/RegisterPatterns.java" },
|
||||
{ file = "{^.package}/interop/pehkui/PehkuiInterop.java" },
|
||||
"{package}/common/casting/RegisterPatterns.java",
|
||||
"{package}/interop/pehkui/PehkuiInterop.java",
|
||||
]
|
||||
|
||||
[fabric]
|
||||
|
@ -65,7 +61,7 @@ package = "{src}/main/java/at/petrak/hexcasting/fabric"
|
|||
resources = "{src}/main/resources"
|
||||
generated = "{src}/generated/resources"
|
||||
pattern_stubs = [
|
||||
{ file = "{^.package}/interop/gravity/GravityApiInterop.java" },
|
||||
"{package}/interop/gravity/GravityApiInterop.java",
|
||||
]
|
||||
|
||||
[forge]
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
# project metadata
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
|
||||
[project]
|
||||
name = "HexDoc" # TODO: i'm pretty sure i had funnier ideas than this
|
||||
name = "HexDoc"
|
||||
version = "0.1.0"
|
||||
authors = [
|
||||
{ name="Alwinfy" },
|
||||
|
@ -16,45 +15,108 @@ requires-python = ">=3.11"
|
|||
dependencies = [
|
||||
"typing_extensions~=4.7.0",
|
||||
"typed-argument-parser~=1.8.0",
|
||||
"pydantic==2.0",
|
||||
"pydantic~=2.0",
|
||||
"Jinja2~=3.1.2",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"black==23.7.0",
|
||||
"isort==5.12.0",
|
||||
"pytest==7.3.1",
|
||||
"syrupy==4.0.2",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
hexdoc = "hexdoc.scripts.hexdoc:main"
|
||||
|
||||
[project.entry-points."hexdoc.Page"]
|
||||
hexdoc-patchouli = "patchouli.page.pages"
|
||||
hexdoc-hexcasting = "hexcasting.hex_pages"
|
||||
hexdoc-abstract-hexcasting = "hexcasting.abstract_hex_pages"
|
||||
hexdoc-patchouli = "hexdoc.patchouli.page.pages"
|
||||
hexdoc-hexcasting = "hexdoc.hexcasting.page.hex_pages"
|
||||
|
||||
[project.entry-points."hexdoc.Recipe"]
|
||||
hexdoc-minecraft = "minecraft.recipe.recipes"
|
||||
hexdoc-hexcasting = "hexcasting.hex_recipes"
|
||||
hexdoc-minecraft = "hexdoc.minecraft.recipe.recipes"
|
||||
hexdoc-hexcasting = "hexdoc.hexcasting.hex_recipes"
|
||||
|
||||
[project.entry-points."hexdoc.ItemIngredient"]
|
||||
hexdoc-minecraft = "minecraft.recipe.ingredients"
|
||||
hexdoc-hexcasting = "hexcasting.hex_recipes"
|
||||
hexdoc-minecraft = "hexdoc.minecraft.recipe.ingredients"
|
||||
hexdoc-hexcasting = "hexdoc.hexcasting.hex_recipes"
|
||||
|
||||
# Hatch settings (the build backend)
|
||||
|
||||
[tool.hatch.metadata]
|
||||
allow-direct-references = true # TODO: remove when we switch to Pydantic
|
||||
|
||||
[tool.hatch.build]
|
||||
packages = ["src/common", "src/hexcasting", "src/minecraft", "src/patchouli"]
|
||||
packages = ["src/hexdoc"]
|
||||
|
||||
# tests, formatting, and (TODO:) type checking
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
addopts = [
|
||||
"--import-mode=importlib"
|
||||
]
|
||||
addopts = ["--import-mode=importlib"]
|
||||
markers = [
|
||||
"filename: name of file for fixtures to create",
|
||||
"file_contents: data for fixtures to write to files",
|
||||
"fixture_data: other misc data",
|
||||
]
|
||||
|
||||
|
||||
[tool.coverage.report]
|
||||
include_namespace_packages = true
|
||||
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
combine_as_imports = true
|
||||
|
||||
|
||||
[tool.pyright]
|
||||
pythonVersion = "3.11"
|
||||
pythonPlatform = "All"
|
||||
|
||||
# mostly we use strict mode
|
||||
# but pyright doesn't allow decreasing error severity in strict mode
|
||||
# so we need to manually specify all of the strict mode overrides so we can do that :/
|
||||
typeCheckingMode = "basic"
|
||||
|
||||
strictDictionaryInference = true
|
||||
strictListInference = true
|
||||
strictSetInference = true
|
||||
|
||||
reportAssertAlwaysTrue = "error"
|
||||
reportConstantRedefinition = "error"
|
||||
reportDeprecated = "error"
|
||||
reportDuplicateImport = "error"
|
||||
reportFunctionMemberAccess = "error"
|
||||
reportIncompatibleMethodOverride = "error"
|
||||
reportIncompatibleVariableOverride = "error"
|
||||
reportIncompleteStub = "error"
|
||||
reportInconsistentConstructor = "error"
|
||||
reportInvalidStringEscapeSequence = "error"
|
||||
reportInvalidStubStatement = "error"
|
||||
reportInvalidTypeVarUse = "error"
|
||||
reportMatchNotExhaustive = "error"
|
||||
reportMissingParameterType = "error"
|
||||
reportMissingTypeStubs = "error"
|
||||
reportOverlappingOverload = "error"
|
||||
reportSelfClsParameterName = "error"
|
||||
reportTypeCommentUsage = "error"
|
||||
reportUnknownParameterType = "error"
|
||||
reportUnnecessaryCast = "error"
|
||||
reportUnnecessaryContains = "error"
|
||||
reportUnsupportedDunderAll = "error"
|
||||
reportUntypedBaseClass = "error"
|
||||
reportUntypedClassDecorator = "error"
|
||||
reportUntypedFunctionDecorator = "error"
|
||||
reportUntypedNamedTuple = "error"
|
||||
reportUnusedClass = "error"
|
||||
reportUnusedExpression = "error"
|
||||
reportUnusedFunction = "error"
|
||||
reportUnusedVariable = "error"
|
||||
reportWildcardImportFromLibrary = "error"
|
||||
|
||||
reportMissingTypeArgument = "warning"
|
||||
reportPrivateUsage = "warning"
|
||||
reportUnknownArgumentType = "warning"
|
||||
reportUnknownLambdaType = "warning"
|
||||
reportUnknownMemberType = "warning"
|
||||
reportUnnecessaryComparison = "warning"
|
||||
reportUnnecessaryIsInstance = "warning"
|
||||
reportUnusedImport = "warning"
|
||||
|
||||
reportUnknownVariableType = "none"
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
-e . # install package locally as editable
|
||||
black==22.10.0 # formatting
|
||||
isort==5.12.0 # formatting 2
|
||||
pytest==7.3.1 # testing framework
|
||||
syrupy==4.0.2 # snapshot tests
|
||||
beautifulsoup4==4.12.2 # html pretty print so the snapshot diffs are actually usable
|
|
@ -1,9 +0,0 @@
|
|||
__all__ = [
|
||||
"HexBook",
|
||||
"HexContext",
|
||||
"AnyHexContext",
|
||||
"HexBookModel",
|
||||
]
|
||||
|
||||
|
||||
from .hex_book import AnyHexContext, HexBook, HexBookModel, HexContext
|
|
@ -1,68 +0,0 @@
|
|||
import re
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import Annotated, Any, Generator
|
||||
|
||||
from pydantic import BeforeValidator
|
||||
|
||||
from common.model import HexDocModel
|
||||
from minecraft.resource import ResourceLocation
|
||||
|
||||
|
||||
class Direction(Enum):
|
||||
NORTH_EAST = 0
|
||||
EAST = 1
|
||||
SOUTH_EAST = 2
|
||||
SOUTH_WEST = 3
|
||||
WEST = 4
|
||||
NORTH_WEST = 5
|
||||
|
||||
@classmethod
|
||||
def validate(cls, value: str | int | Any):
|
||||
match value:
|
||||
case str():
|
||||
return cls[value]
|
||||
case int():
|
||||
return cls(value)
|
||||
case _:
|
||||
return value
|
||||
|
||||
|
||||
DirectionField = Annotated[Direction, BeforeValidator(Direction.validate)]
|
||||
|
||||
|
||||
class RawPatternInfo(HexDocModel[Any]):
|
||||
startdir: DirectionField
|
||||
signature: str
|
||||
is_per_world: bool = False
|
||||
q: int | None = None
|
||||
r: int | None = None
|
||||
|
||||
|
||||
class PatternInfo(RawPatternInfo):
|
||||
id: ResourceLocation
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.id.path
|
||||
|
||||
|
||||
class PatternStubFile(HexDocModel[Any]):
|
||||
file: Path
|
||||
|
||||
def load_patterns(
|
||||
self,
|
||||
modid: str,
|
||||
pattern_re: re.Pattern[str],
|
||||
) -> Generator[PatternInfo, None, None]:
|
||||
# TODO: add Gradle task to generate json with this data. this is dumb and fragile.
|
||||
|
||||
pattern_data = self.file.read_text("utf-8")
|
||||
for match in pattern_re.finditer(pattern_data):
|
||||
signature, startdir, name, is_per_world = match.groups()
|
||||
yield PatternInfo(
|
||||
startdir=Direction[startdir],
|
||||
signature=signature,
|
||||
is_per_world=bool(is_per_world),
|
||||
id=ResourceLocation(modid, name),
|
||||
)
|
13
doc/src/hexdoc/hexcasting/__init__.py
Normal file
13
doc/src/hexdoc/hexcasting/__init__.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
__all__ = [
|
||||
"AnyHexContext",
|
||||
"HexBook",
|
||||
"HexBookType",
|
||||
"HexContext",
|
||||
"Direction",
|
||||
"PatternInfo",
|
||||
"RawPatternInfo",
|
||||
]
|
||||
|
||||
|
||||
from .hex_book import AnyHexContext, HexBook, HexBookType, HexContext
|
||||
from .pattern import Direction, PatternInfo, RawPatternInfo
|
|
@ -1,11 +1,12 @@
|
|||
from pathlib import Path
|
||||
from typing import Any, Generic, TypeVar
|
||||
|
||||
from common.model import AnyContext
|
||||
from common.properties import Properties
|
||||
from hexcasting.pattern import PatternInfo
|
||||
from minecraft.resource import ResourceLocation
|
||||
from patchouli.book import Book
|
||||
from patchouli.context import AnyBookContext, BookContext
|
||||
from hexdoc.patchouli import AnyBookContext, Book, BookContext
|
||||
from hexdoc.properties import Properties
|
||||
from hexdoc.resource import ResourceLocation
|
||||
from hexdoc.utils import AnyContext
|
||||
|
||||
from .pattern import Direction, PatternInfo
|
||||
|
||||
|
||||
class HexContext(BookContext):
|
||||
|
@ -15,7 +16,7 @@ class HexContext(BookContext):
|
|||
AnyHexContext = TypeVar("AnyHexContext", bound=HexContext)
|
||||
|
||||
|
||||
class HexBookModel(
|
||||
class HexBookType(
|
||||
Generic[AnyContext, AnyBookContext, AnyHexContext],
|
||||
Book[AnyHexContext, AnyHexContext],
|
||||
):
|
||||
|
@ -28,7 +29,7 @@ class HexBookModel(
|
|||
signatures = dict[str, PatternInfo]() # just for duplicate checking
|
||||
for stub in props.pattern_stubs:
|
||||
# for each stub, load all the patterns in the file
|
||||
for pattern in stub.load_patterns(props.modid, props.pattern_regex):
|
||||
for pattern in cls.load_patterns(stub, props):
|
||||
# check for duplicates, because why not
|
||||
if duplicate := (
|
||||
patterns.get(pattern.id) or signatures.get(pattern.signature)
|
||||
|
@ -45,5 +46,19 @@ class HexBookModel(
|
|||
"patterns": patterns,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def load_patterns(cls, path: Path, props: Properties):
|
||||
# TODO: add Gradle task to generate json with this data. this is dumb and fragile.
|
||||
stub_text = path.read_text("utf-8")
|
||||
for match in props.pattern_regex.finditer(stub_text):
|
||||
signature, startdir, name, is_per_world = match.groups()
|
||||
yield PatternInfo(
|
||||
startdir=Direction[startdir],
|
||||
signature=signature,
|
||||
is_per_world=bool(is_per_world),
|
||||
id=ResourceLocation(props.modid, name),
|
||||
)
|
||||
|
||||
HexBook = HexBookModel[HexContext, HexContext, HexContext]
|
||||
|
||||
# type alias for convenience
|
||||
HexBook = HexBookType[HexContext, HexContext, HexContext]
|
|
@ -1,15 +1,15 @@
|
|||
from typing import Any, Literal
|
||||
|
||||
from common.model import HexDocModel
|
||||
from hexcasting.hex_book import HexContext
|
||||
from minecraft.i18n import LocalizedItem
|
||||
from minecraft.recipe import (
|
||||
from hexdoc.minecraft import LocalizedItem, Recipe
|
||||
from hexdoc.minecraft.recipe import (
|
||||
ItemIngredient,
|
||||
MinecraftItemIdIngredient,
|
||||
MinecraftItemTagIngredient,
|
||||
Recipe,
|
||||
)
|
||||
from minecraft.resource import ResourceLocation
|
||||
from hexdoc.resource import ResourceLocation
|
||||
from hexdoc.utils import HexDocModel
|
||||
|
||||
from .hex_book import HexContext
|
||||
|
||||
# ingredients
|
||||
|
20
doc/src/hexdoc/hexcasting/page/__init__.py
Normal file
20
doc/src/hexdoc/hexcasting/page/__init__.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
__all__ = [
|
||||
"PageWithOpPattern",
|
||||
"PageWithPattern",
|
||||
"BrainsweepPage",
|
||||
"CraftingMultiPage",
|
||||
"LookupPatternPage",
|
||||
"ManualOpPatternPage",
|
||||
"ManualPatternNosigPage",
|
||||
"ManualRawPatternPage",
|
||||
]
|
||||
|
||||
from .abstract_hex_pages import PageWithOpPattern, PageWithPattern
|
||||
from .hex_pages import (
|
||||
BrainsweepPage,
|
||||
CraftingMultiPage,
|
||||
LookupPatternPage,
|
||||
ManualOpPatternPage,
|
||||
ManualPatternNosigPage,
|
||||
ManualRawPatternPage,
|
||||
)
|
|
@ -3,12 +3,12 @@ from typing import Any, cast
|
|||
|
||||
from pydantic import ValidationInfo, model_validator
|
||||
|
||||
from hexcasting.pattern import RawPatternInfo
|
||||
from minecraft.i18n import LocalizedStr
|
||||
from minecraft.resource import ResourceLocation
|
||||
from patchouli.page import PageWithText
|
||||
from hexdoc.minecraft import LocalizedStr
|
||||
from hexdoc.patchouli.page import PageWithText
|
||||
from hexdoc.resource import ResourceLocation
|
||||
|
||||
from .hex_book import AnyHexContext, HexContext
|
||||
from ..hex_book import AnyHexContext, HexContext
|
||||
from ..pattern import RawPatternInfo
|
||||
|
||||
|
||||
# TODO: make anchor required (breaks because of Greater Sentinel)
|
|
@ -2,15 +2,14 @@ from typing import Any, cast
|
|||
|
||||
from pydantic import ValidationInfo, model_validator
|
||||
|
||||
from minecraft.i18n import LocalizedStr
|
||||
from minecraft.recipe import CraftingRecipe
|
||||
from minecraft.resource import ResourceLocation
|
||||
from patchouli.page import PageWithText
|
||||
from patchouli.page.abstract_pages import PageWithTitle
|
||||
from hexdoc.minecraft import LocalizedStr
|
||||
from hexdoc.minecraft.recipe import CraftingRecipe
|
||||
from hexdoc.patchouli.page import PageWithText, PageWithTitle
|
||||
from hexdoc.resource import ResourceLocation
|
||||
|
||||
from ..hex_book import HexContext
|
||||
from ..hex_recipes import BrainsweepRecipe
|
||||
from .abstract_hex_pages import PageWithOpPattern, PageWithPattern
|
||||
from .hex_book import HexContext
|
||||
from .hex_recipes import BrainsweepRecipe
|
||||
|
||||
|
||||
class LookupPatternPage(
|
45
doc/src/hexdoc/hexcasting/pattern.py
Normal file
45
doc/src/hexdoc/hexcasting/pattern.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
from enum import Enum
|
||||
from typing import Annotated, Any
|
||||
|
||||
from pydantic import BeforeValidator
|
||||
|
||||
from hexdoc.resource import ResourceLocation
|
||||
from hexdoc.utils import HexDocModel
|
||||
|
||||
|
||||
class Direction(Enum):
|
||||
NORTH_EAST = 0
|
||||
EAST = 1
|
||||
SOUTH_EAST = 2
|
||||
SOUTH_WEST = 3
|
||||
WEST = 4
|
||||
NORTH_WEST = 5
|
||||
|
||||
@classmethod
|
||||
def validate(cls, value: str | int | Any):
|
||||
match value:
|
||||
case str():
|
||||
return cls[value]
|
||||
case int():
|
||||
return cls(value)
|
||||
case _:
|
||||
return value
|
||||
|
||||
|
||||
DirectionField = Annotated[Direction, BeforeValidator(Direction.validate)]
|
||||
|
||||
|
||||
class RawPatternInfo(HexDocModel[Any]):
|
||||
startdir: DirectionField
|
||||
signature: str
|
||||
is_per_world: bool = False
|
||||
q: int | None = None
|
||||
r: int | None = None
|
||||
|
||||
|
||||
class PatternInfo(RawPatternInfo):
|
||||
id: ResourceLocation
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.id.path
|
9
doc/src/hexdoc/minecraft/__init__.py
Normal file
9
doc/src/hexdoc/minecraft/__init__.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
__all__ = [
|
||||
"I18n",
|
||||
"LocalizedItem",
|
||||
"LocalizedStr",
|
||||
"Recipe",
|
||||
]
|
||||
|
||||
from .i18n import I18n, LocalizedItem, LocalizedStr
|
||||
from .recipe import Recipe
|
|
@ -1,7 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dataclasses import InitVar
|
||||
from functools import total_ordering
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Self, cast
|
||||
|
||||
from pydantic import ValidationInfo, model_validator
|
||||
|
@ -9,10 +9,10 @@ from pydantic.dataclasses import dataclass
|
|||
from pydantic.functional_validators import ModelWrapValidatorHandler
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
from common.deserialize import isinstance_or_raise, load_json
|
||||
from common.model import DEFAULT_CONFIG, HexDocModel
|
||||
from common.properties import Properties
|
||||
from minecraft.resource import ItemStack, ResourceLocation
|
||||
from hexdoc.properties import Properties
|
||||
from hexdoc.resource import ItemStack, ResourceLocation
|
||||
from hexdoc.utils import DEFAULT_CONFIG, HexDocModel
|
||||
from hexdoc.utils.deserialize import isinstance_or_raise, load_json
|
||||
|
||||
|
||||
class I18nContext(TypedDict):
|
||||
|
@ -94,12 +94,12 @@ class LocalizedItem(LocalizedStr):
|
|||
class I18n:
|
||||
"""Handles localization of strings."""
|
||||
|
||||
props: Properties
|
||||
props: InitVar[Properties]
|
||||
enabled: bool
|
||||
|
||||
lookup: dict[str, LocalizedStr] | None = None
|
||||
|
||||
def __post_init__(self):
|
||||
def __post_init__(self, props: Properties):
|
||||
# skip loading the files if we don't need to
|
||||
self.lookup = None
|
||||
if not self.enabled:
|
||||
|
@ -109,8 +109,9 @@ class I18n:
|
|||
# TODO: load ALL of the i18n files, return dict[str, _Lookup] | None
|
||||
# or maybe dict[(str, str), LocalizedStr]
|
||||
# we could also use that to ensure all i18n files have the same set of keys
|
||||
path = self.dir / self.props.i18n.filename
|
||||
raw_lookup = load_json(path) | (self.props.i18n.extra or {})
|
||||
lang_dir = props.resources_dir / "assets" / props.modid / "lang"
|
||||
path = lang_dir / props.i18n.filename
|
||||
raw_lookup = load_json(path) | (props.i18n.extra or {})
|
||||
|
||||
# validate and insert
|
||||
self.lookup = {}
|
||||
|
@ -121,11 +122,6 @@ class I18n:
|
|||
value=raw_value.replace("%%", "%"),
|
||||
)
|
||||
|
||||
@property
|
||||
def dir(self) -> Path:
|
||||
"""eg. `resources/assets/hexcasting/lang`"""
|
||||
return self.props.resources_dir / "assets" / self.props.modid / "lang"
|
||||
|
||||
def localize(
|
||||
self,
|
||||
*keys: str,
|
|
@ -1,19 +1,19 @@
|
|||
__all__ = [
|
||||
"CraftingRecipe",
|
||||
"ItemIngredient",
|
||||
"MinecraftItemTagIngredient",
|
||||
"MinecraftItemIdIngredient",
|
||||
"ItemResult",
|
||||
"Recipe",
|
||||
"recipes",
|
||||
"ItemIngredient",
|
||||
"ItemIngredientOrList",
|
||||
"MinecraftItemIdIngredient",
|
||||
"MinecraftItemTagIngredient",
|
||||
"CraftingRecipe",
|
||||
"CraftingShapedRecipe",
|
||||
"CraftingShapelessRecipe",
|
||||
"ItemResult",
|
||||
]
|
||||
|
||||
from .abstract_recipes import Recipe
|
||||
from .ingredients import (
|
||||
ItemIngredient,
|
||||
ItemIngredientOrList,
|
||||
MinecraftItemIdIngredient,
|
||||
MinecraftItemTagIngredient,
|
||||
)
|
|
@ -2,13 +2,12 @@ from typing import Any, Self, cast
|
|||
|
||||
from pydantic import ValidationInfo, model_validator
|
||||
|
||||
from common.deserialize import load_json
|
||||
from common.tagged_union import TypeTaggedUnion
|
||||
from minecraft.resource import ResourceLocation
|
||||
from patchouli.context import AnyBookContext
|
||||
from hexdoc.properties import AnyPropsContext
|
||||
from hexdoc.resource import ResourceLocation, TypeTaggedUnion
|
||||
from hexdoc.utils.deserialize import load_json
|
||||
|
||||
|
||||
class Recipe(TypeTaggedUnion[AnyBookContext], group="hexdoc.Recipe", type=None):
|
||||
class Recipe(TypeTaggedUnion[AnyPropsContext], group="hexdoc.Recipe", type=None):
|
||||
id: ResourceLocation
|
||||
|
||||
group: str | None = None
|
||||
|
@ -31,7 +30,7 @@ class Recipe(TypeTaggedUnion[AnyBookContext], group="hexdoc.Recipe", type=None):
|
|||
id = values
|
||||
|
||||
# load the recipe
|
||||
context = cast(AnyBookContext, info.context)
|
||||
context = cast(AnyPropsContext, info.context)
|
||||
for recipe_dir in context["props"].recipe_dirs:
|
||||
# TODO: should this use id.namespace somewhere?
|
||||
path = recipe_dir / f"{id.path}.json"
|
23
doc/src/hexdoc/minecraft/recipe/ingredients.py
Normal file
23
doc/src/hexdoc/minecraft/recipe/ingredients.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
from typing import Any
|
||||
|
||||
from hexdoc.resource import ResourceLocation, TypeTaggedUnion
|
||||
from hexdoc.utils import AnyContext, NoValue
|
||||
|
||||
|
||||
class ItemIngredient(
|
||||
TypeTaggedUnion[AnyContext],
|
||||
group="hexdoc.ItemIngredient",
|
||||
type=None,
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
ItemIngredientOrList = ItemIngredient[AnyContext] | list[ItemIngredient[AnyContext]]
|
||||
|
||||
|
||||
class MinecraftItemIdIngredient(ItemIngredient[Any], type=NoValue):
|
||||
item: ResourceLocation
|
||||
|
||||
|
||||
class MinecraftItemTagIngredient(ItemIngredient[Any], type=NoValue):
|
||||
tag: ResourceLocation
|
|
@ -1,30 +1,31 @@
|
|||
from common.model import HexDocModel
|
||||
from minecraft.i18n import LocalizedItem
|
||||
from patchouli.context import BookContext
|
||||
from typing import Any
|
||||
|
||||
from hexdoc.utils import HexDocModel
|
||||
|
||||
from ..i18n import LocalizedItem
|
||||
from .abstract_recipes import Recipe
|
||||
from .ingredients import ItemIngredientOrList
|
||||
|
||||
|
||||
class ItemResult(HexDocModel[BookContext]):
|
||||
class ItemResult(HexDocModel[Any]):
|
||||
item: LocalizedItem
|
||||
count: int | None = None
|
||||
|
||||
|
||||
class CraftingShapedRecipe(
|
||||
Recipe[BookContext],
|
||||
Recipe[Any],
|
||||
type="minecraft:crafting_shaped",
|
||||
):
|
||||
pattern: list[str]
|
||||
key: dict[str, ItemIngredientOrList[BookContext]]
|
||||
key: dict[str, ItemIngredientOrList[Any]]
|
||||
result: ItemResult
|
||||
|
||||
|
||||
class CraftingShapelessRecipe(
|
||||
Recipe[BookContext],
|
||||
Recipe[Any],
|
||||
type="minecraft:crafting_shapeless",
|
||||
):
|
||||
ingredients: list[ItemIngredientOrList[BookContext]]
|
||||
ingredients: list[ItemIngredientOrList[Any]]
|
||||
result: ItemResult
|
||||
|
||||
|
16
doc/src/hexdoc/patchouli/__init__.py
Normal file
16
doc/src/hexdoc/patchouli/__init__.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
__all__ = [
|
||||
"Book",
|
||||
"Category",
|
||||
"Entry",
|
||||
"Page",
|
||||
"FormatTree",
|
||||
"AnyBookContext",
|
||||
"BookContext",
|
||||
]
|
||||
|
||||
from .book import Book
|
||||
from .category import Category
|
||||
from .entry import Entry
|
||||
from .model import AnyBookContext, BookContext
|
||||
from .page import Page
|
||||
from .text import FormatTree
|
|
@ -2,16 +2,15 @@ from typing import Any, Generic, Literal, Self, cast
|
|||
|
||||
from pydantic import Field, ValidationInfo, model_validator
|
||||
|
||||
from common.deserialize import isinstance_or_raise, load_json
|
||||
from common.model import AnyContext, HexDocModel
|
||||
from common.properties import Properties
|
||||
from common.types import Color
|
||||
from minecraft.i18n import I18n, LocalizedStr
|
||||
from minecraft.resource import ItemStack, ResLoc, ResourceLocation
|
||||
from hexdoc.minecraft import I18n, LocalizedStr
|
||||
from hexdoc.properties import Properties
|
||||
from hexdoc.resource import ItemStack, ResLoc, ResourceLocation
|
||||
from hexdoc.utils import AnyContext, Color, HexDocModel
|
||||
from hexdoc.utils.deserialize import isinstance_or_raise, load_json
|
||||
|
||||
from .category import Category
|
||||
from .context import AnyBookContext, BookContext
|
||||
from .entry import Entry
|
||||
from .model import AnyBookContext, BookContext
|
||||
from .text import DEFAULT_MACROS, FormatTree
|
||||
|
||||
|
|
@ -3,17 +3,17 @@ from typing import Self
|
|||
|
||||
from pydantic import Field
|
||||
|
||||
from common.properties import Properties
|
||||
from common.types import Sortable, sorted_dict
|
||||
from minecraft.i18n import LocalizedStr
|
||||
from minecraft.resource import ItemStack, ResourceLocation
|
||||
from hexdoc.minecraft import LocalizedStr
|
||||
from hexdoc.properties import Properties
|
||||
from hexdoc.resource import ItemStack, ResourceLocation
|
||||
from hexdoc.utils.types import Sortable, sorted_dict
|
||||
|
||||
from .context import BookContext, BookModelFile
|
||||
from .entry import Entry
|
||||
from .model import BookContext, BookFileModel
|
||||
from .text import FormatTree
|
||||
|
||||
|
||||
class Category(BookModelFile[BookContext, BookContext], Sortable):
|
||||
class Category(BookFileModel[BookContext, BookContext], Sortable):
|
||||
"""Category with pages and localizations.
|
||||
|
||||
See: https://vazkiimods.github.io/Patchouli/docs/reference/category-json
|
|
@ -3,16 +3,17 @@ from typing import cast
|
|||
|
||||
from pydantic import Field, ValidationInfo, model_validator
|
||||
|
||||
from common.properties import Properties
|
||||
from common.types import Color, Sortable
|
||||
from minecraft.i18n import LocalizedStr
|
||||
from minecraft.resource import ItemStack, ResourceLocation
|
||||
from hexdoc.minecraft import LocalizedStr
|
||||
from hexdoc.properties import Properties
|
||||
from hexdoc.resource import ItemStack, ResourceLocation
|
||||
from hexdoc.utils import Color
|
||||
from hexdoc.utils.types import Sortable
|
||||
|
||||
from .context import BookContext, BookModelFile
|
||||
from .page import Page
|
||||
from .model import BookContext, BookFileModel
|
||||
from .page.pages import Page
|
||||
|
||||
|
||||
class Entry(BookModelFile[BookContext, BookContext], Sortable):
|
||||
class Entry(BookFileModel[BookContext, BookContext], Sortable):
|
||||
"""Entry json file, with pages and localizations.
|
||||
|
||||
See: https://vazkiimods.github.io/Patchouli/docs/reference/entry-json
|
|
@ -4,10 +4,11 @@ from typing import Any, Generic, TypeVar, cast, dataclass_transform
|
|||
|
||||
from pydantic import ValidationInfo, model_validator
|
||||
|
||||
from common.model import AnyContext, HexDocModelFile
|
||||
from common.properties import Properties
|
||||
from minecraft.resource import ResourceLocation
|
||||
from patchouli.text import FormatContext
|
||||
from hexdoc.properties import Properties
|
||||
from hexdoc.resource import ResourceLocation
|
||||
from hexdoc.utils import AnyContext, HexDocFileModel
|
||||
|
||||
from .text.formatting import FormatContext
|
||||
|
||||
|
||||
class BookContext(FormatContext):
|
||||
|
@ -18,9 +19,9 @@ AnyBookContext = TypeVar("AnyBookContext", bound=BookContext)
|
|||
|
||||
|
||||
@dataclass_transform()
|
||||
class BookModelFile(
|
||||
class BookFileModel(
|
||||
Generic[AnyContext, AnyBookContext],
|
||||
HexDocModelFile[AnyBookContext],
|
||||
HexDocFileModel[AnyBookContext],
|
||||
ABC,
|
||||
):
|
||||
id: ResourceLocation
|
|
@ -2,17 +2,17 @@ __all__ = [
|
|||
"Page",
|
||||
"PageWithText",
|
||||
"PageWithTitle",
|
||||
"CraftingPage",
|
||||
"EmptyPage",
|
||||
"EntityPage",
|
||||
"ImagePage",
|
||||
"LinkPage",
|
||||
"MultiblockPage",
|
||||
"QuestPage",
|
||||
"RelationsPage",
|
||||
"SmeltingPage",
|
||||
"SpotlightPage",
|
||||
"TextPage",
|
||||
"ImagePage",
|
||||
"CraftingPage",
|
||||
"SmeltingPage",
|
||||
"MultiblockPage",
|
||||
"EntityPage",
|
||||
"SpotlightPage",
|
||||
"LinkPage",
|
||||
"RelationsPage",
|
||||
"QuestPage",
|
||||
"EmptyPage",
|
||||
]
|
||||
|
||||
from .abstract_pages import Page, PageWithText, PageWithTitle
|
|
@ -3,11 +3,11 @@ from typing import Any, ClassVar, Self
|
|||
from pydantic import model_validator
|
||||
from pydantic.functional_validators import ModelWrapValidatorHandler
|
||||
|
||||
from common.tagged_union import TagValue, TypeTaggedUnion
|
||||
from minecraft.i18n import LocalizedStr
|
||||
from minecraft.resource import ResourceLocation
|
||||
from hexdoc.minecraft import LocalizedStr
|
||||
from hexdoc.resource import ResourceLocation, TypeTaggedUnion
|
||||
from hexdoc.utils import TagValue
|
||||
|
||||
from ..context import AnyBookContext
|
||||
from ..model import AnyBookContext
|
||||
from ..text import FormatTree
|
||||
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
from typing import Any
|
||||
|
||||
from minecraft.i18n import LocalizedItem, LocalizedStr
|
||||
from minecraft.recipe import CraftingRecipe
|
||||
from minecraft.resource import Entity, ItemStack, ResourceLocation
|
||||
from patchouli.context import BookContext
|
||||
from hexdoc.minecraft import LocalizedItem, LocalizedStr
|
||||
from hexdoc.minecraft.recipe import CraftingRecipe
|
||||
from hexdoc.resource import Entity, ItemStack, ResourceLocation
|
||||
|
||||
from ..model import BookContext
|
||||
from ..text import FormatTree
|
||||
from .abstract_pages import Page, PageWithText, PageWithTitle
|
||||
|
9
doc/src/hexdoc/patchouli/text/__init__.py
Normal file
9
doc/src/hexdoc/patchouli/text/__init__.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
__all__ = [
|
||||
"FormatTree",
|
||||
"HTMLElement",
|
||||
"HTMLStream",
|
||||
"DEFAULT_MACROS",
|
||||
]
|
||||
|
||||
from .formatting import DEFAULT_MACROS, FormatTree
|
||||
from .html import HTMLElement, HTMLStream
|
|
@ -12,10 +12,11 @@ from pydantic import ValidationInfo, model_validator
|
|||
from pydantic.dataclasses import dataclass
|
||||
from pydantic.functional_validators import ModelWrapValidatorHandler
|
||||
|
||||
from common.model import DEFAULT_CONFIG, HexDocModel
|
||||
from common.properties import Properties
|
||||
from common.types import TryGetEnum
|
||||
from minecraft.i18n import I18nContext, LocalizedStr
|
||||
from hexdoc.minecraft import LocalizedStr
|
||||
from hexdoc.minecraft.i18n import I18nContext
|
||||
from hexdoc.properties import PropsContext
|
||||
from hexdoc.utils import DEFAULT_CONFIG, HexDocModel
|
||||
from hexdoc.utils.types import TryGetEnum
|
||||
|
||||
from .html import HTMLElement, HTMLStream
|
||||
|
||||
|
@ -251,9 +252,8 @@ class _CloseTag(HexDocModel[Any], frozen=True):
|
|||
_FORMAT_RE = re.compile(r"\$\(([^)]*)\)")
|
||||
|
||||
|
||||
class FormatContext(I18nContext):
|
||||
class FormatContext(I18nContext, PropsContext):
|
||||
macros: dict[str, str]
|
||||
props: Properties
|
||||
|
||||
|
||||
@dataclass(config=DEFAULT_CONFIG)
|
|
@ -5,7 +5,7 @@ from dataclasses import dataclass
|
|||
from html import escape
|
||||
from typing import IO, Any
|
||||
|
||||
from minecraft.i18n import LocalizedStr
|
||||
from hexdoc.minecraft import LocalizedStr
|
||||
|
||||
|
||||
def attributes_to_str(attributes: dict[str, Any]):
|
|
@ -1,6 +1,8 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Annotated, Any, Self
|
||||
from typing import Annotated, Any, Self, TypeVar
|
||||
|
||||
from pydantic import (
|
||||
AfterValidator,
|
||||
|
@ -9,11 +11,11 @@ from pydantic import (
|
|||
HttpUrl,
|
||||
field_validator,
|
||||
)
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
from common.model import HexDocModel
|
||||
from common.toml_placeholders import load_toml
|
||||
from hexcasting.pattern import PatternStubFile
|
||||
from minecraft.resource import ResourceLocation
|
||||
from hexdoc.resource import ResourceLocation
|
||||
from hexdoc.utils.model import HexDocModel
|
||||
from hexdoc.utils.toml_placeholders import load_toml
|
||||
|
||||
NoTrailingSlashHttpUrl = Annotated[
|
||||
str,
|
||||
|
@ -27,7 +29,7 @@ class PlatformProps(HexDocModel[Any]):
|
|||
generated: Path
|
||||
src: Path
|
||||
package: Path
|
||||
pattern_stubs: list[PatternStubFile] | None = None
|
||||
pattern_stubs: list[Path] | None = None
|
||||
|
||||
|
||||
class I18nProps(HexDocModel[Any]):
|
||||
|
@ -112,7 +114,7 @@ class Properties(HexDocModel[Any]):
|
|||
return platforms
|
||||
|
||||
@property
|
||||
def pattern_stubs(self) -> list[PatternStubFile]:
|
||||
def pattern_stubs(self) -> list[Path]:
|
||||
return [
|
||||
stub
|
||||
for platform in self.platforms
|
||||
|
@ -132,3 +134,10 @@ class Properties(HexDocModel[Any]):
|
|||
f"default_recipe_dir must be a valid index of recipe_dirs (expected <={num_dirs - 1}, got {value})"
|
||||
)
|
||||
return value
|
||||
|
||||
|
||||
class PropsContext(TypedDict):
|
||||
props: Properties
|
||||
|
||||
|
||||
AnyPropsContext = TypeVar("AnyPropsContext", bound=PropsContext)
|
|
@ -1,5 +1,9 @@
|
|||
# pyright: reportPrivateUsage=false
|
||||
|
||||
# this file is used by basically everything
|
||||
# so if it's in literally any namespace, everything fucking dies from circular deps
|
||||
# basically, just leave it here
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any, ClassVar, Self
|
||||
|
@ -8,7 +12,13 @@ from pydantic import field_validator, model_serializer, model_validator
|
|||
from pydantic.dataclasses import dataclass
|
||||
from pydantic.functional_validators import ModelWrapValidatorHandler
|
||||
|
||||
from common.model import DEFAULT_CONFIG
|
||||
from hexdoc.utils import (
|
||||
DEFAULT_CONFIG,
|
||||
AnyContext,
|
||||
InternallyTaggedUnion,
|
||||
NoValueType,
|
||||
TagValue,
|
||||
)
|
||||
|
||||
|
||||
def _make_regex(count: bool = False, nbt: bool = False) -> re.Pattern[str]:
|
||||
|
@ -118,3 +128,22 @@ class Entity(BaseResourceLocation, regex=_make_regex(nbt=True)):
|
|||
if self.nbt is not None:
|
||||
s += self.nbt
|
||||
return s
|
||||
|
||||
|
||||
class TypeTaggedUnion(InternallyTaggedUnion[AnyContext], key="type", value=None):
|
||||
type: ResourceLocation | None
|
||||
|
||||
def __init_subclass__(
|
||||
cls,
|
||||
*,
|
||||
group: str | None = None,
|
||||
type: TagValue | None,
|
||||
) -> None:
|
||||
super().__init_subclass__(group=group, value=type)
|
||||
match type:
|
||||
case str():
|
||||
cls.type = ResourceLocation.from_str(type)
|
||||
case NoValueType():
|
||||
cls.type = None
|
||||
case None:
|
||||
pass
|
|
@ -1,7 +1,6 @@
|
|||
# because Tap.add_argument isn't typed, for some reason
|
||||
# pyright: reportUnknownMemberType=false
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from jinja2 import Environment, FileSystemLoader, StrictUndefined
|
||||
|
@ -9,12 +8,9 @@ from jinja2 import Environment, FileSystemLoader, StrictUndefined
|
|||
# from jinja2.sandbox import SandboxedEnvironment
|
||||
from tap import Tap
|
||||
|
||||
from common.jinja_extensions import IncludeRawExtension, hexdoc_block, hexdoc_wrap
|
||||
from common.properties import Properties
|
||||
from hexcasting.hex_book import HexBook
|
||||
|
||||
if sys.version_info < (3, 11):
|
||||
raise RuntimeError("Minimum Python version: 3.11")
|
||||
from hexdoc.hexcasting import HexBook
|
||||
from hexdoc.properties import Properties
|
||||
from hexdoc.utils.jinja_extensions import IncludeRawExtension, hexdoc_block, hexdoc_wrap
|
||||
|
||||
|
||||
def strip_empty_lines(text: str) -> str:
|
||||
|
@ -33,7 +29,11 @@ class Args(Tap):
|
|||
self.add_argument("-o", "--output_file", required=False)
|
||||
|
||||
|
||||
def main(args: Args) -> None:
|
||||
def main(args: Args | None = None) -> None:
|
||||
# allow passing Args for test cases, but parse by default
|
||||
if args is None:
|
||||
args = Args().parse_args()
|
||||
|
||||
# load the properties and book
|
||||
props = Properties.load(args.properties_file)
|
||||
book = HexBook.load(*HexBook.prepare(props))
|
||||
|
@ -74,4 +74,4 @@ def main(args: Args) -> None:
|
|||
|
||||
# entry point: just read the CLI args and pass them to the actual logic
|
||||
if __name__ == "__main__":
|
||||
main(Args().parse_args())
|
||||
main()
|
22
doc/src/hexdoc/utils/__init__.py
Normal file
22
doc/src/hexdoc/utils/__init__.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
__all__ = [
|
||||
"HexDocModel",
|
||||
"FrozenHexDocModel",
|
||||
"HexDocFileModel",
|
||||
"InternallyTaggedUnion",
|
||||
"Color",
|
||||
"AnyContext",
|
||||
"DEFAULT_CONFIG",
|
||||
"NoValue",
|
||||
"NoValueType",
|
||||
"TagValue",
|
||||
]
|
||||
|
||||
from .model import (
|
||||
DEFAULT_CONFIG,
|
||||
AnyContext,
|
||||
FrozenHexDocModel,
|
||||
HexDocFileModel,
|
||||
HexDocModel,
|
||||
)
|
||||
from .tagged_union import InternallyTaggedUnion, NoValue, NoValueType, TagValue
|
||||
from .types import Color
|
|
@ -6,6 +6,7 @@ _T = TypeVar("_T")
|
|||
|
||||
_DEFAULT_MESSAGE = "Expected any of {expected}, got {actual}: {value}"
|
||||
|
||||
|
||||
# there may well be a better way to do this but i don't know what it is
|
||||
def isinstance_or_raise(
|
||||
val: Any,
|
|
@ -5,9 +5,9 @@ from jinja2.ext import Extension
|
|||
from jinja2.parser import Parser
|
||||
from markupsafe import Markup
|
||||
|
||||
from minecraft.i18n import LocalizedStr
|
||||
from patchouli.text.formatting import FormatTree
|
||||
from patchouli.text.html import HTMLStream
|
||||
from hexdoc.minecraft import LocalizedStr
|
||||
from hexdoc.patchouli import FormatTree
|
||||
from hexdoc.patchouli.text import HTMLStream
|
||||
|
||||
|
||||
# https://stackoverflow.com/a/64392515
|
|
@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Any, Generic, Self, TypeVar, dataclass_transfo
|
|||
from pydantic import BaseModel, ConfigDict
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
from common.deserialize import load_json
|
||||
from .deserialize import load_json
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pydantic.root_model import Model
|
||||
|
@ -53,7 +53,7 @@ class FrozenHexDocModel(Generic[AnyContext], HexDocModel[AnyContext]):
|
|||
|
||||
|
||||
@dataclass_transform()
|
||||
class HexDocModelFile(HexDocModel[AnyContext]):
|
||||
class HexDocFileModel(HexDocModel[AnyContext]):
|
||||
@classmethod
|
||||
def load(cls, path: Path, context: AnyContext) -> Self:
|
||||
data = load_json(path) | {"__path": path}
|
|
@ -10,10 +10,11 @@ from pkg_resources import iter_entry_points
|
|||
from pydantic import ValidationInfo, model_validator
|
||||
from pydantic.functional_validators import ModelWrapValidatorHandler
|
||||
|
||||
from minecraft.resource import ResourceLocation
|
||||
|
||||
from .model import AnyContext, HexDocModel
|
||||
|
||||
# from hexdoc.minecraft import ResourceLocation
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pydantic.root_model import Model
|
||||
|
||||
|
@ -154,13 +155,13 @@ class InternallyTaggedUnion(HexDocModel[AnyContext]):
|
|||
context: AnyContext | None = None,
|
||||
) -> Model:
|
||||
# resolve forward references, because apparently we need to do this
|
||||
if cls not in _rebuilt_models:
|
||||
_rebuilt_models.add(cls)
|
||||
cls.model_rebuild(
|
||||
_types_namespace={
|
||||
"ResourceLocation": ResourceLocation,
|
||||
}
|
||||
)
|
||||
# if cls not in _rebuilt_models:
|
||||
# _rebuilt_models.add(cls)
|
||||
# cls.model_rebuild(
|
||||
# _types_namespace={
|
||||
# "ResourceLocation": ResourceLocation,
|
||||
# }
|
||||
# )
|
||||
|
||||
return super().model_validate(
|
||||
obj,
|
||||
|
@ -232,22 +233,3 @@ class InternallyTaggedUnion(HexDocModel[AnyContext]):
|
|||
f"Failed to match {cls} with {cls._tag_key}={tag_value} to any of {tag_types}: {data}",
|
||||
exceptions,
|
||||
)
|
||||
|
||||
|
||||
class TypeTaggedUnion(InternallyTaggedUnion[AnyContext], key="type", value=None):
|
||||
type: ResourceLocation | None
|
||||
|
||||
def __init_subclass__(
|
||||
cls,
|
||||
*,
|
||||
group: str | None = None,
|
||||
type: TagValue | None,
|
||||
) -> None:
|
||||
super().__init_subclass__(group=group, value=type)
|
||||
match type:
|
||||
case str():
|
||||
cls.type = ResourceLocation.from_str(type)
|
||||
case NoValueType():
|
||||
cls.type = None
|
||||
case None:
|
||||
pass
|
|
@ -1,11 +1,10 @@
|
|||
import datetime
|
||||
import re
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
from typing import Callable, TypeVar
|
||||
|
||||
import tomllib
|
||||
|
||||
from common.deserialize import isinstance_or_raise
|
||||
from .deserialize import isinstance_or_raise
|
||||
|
||||
# TODO: there's (figuratively) literally no comments in this file
|
||||
|
|
@ -6,7 +6,7 @@ from typing import Any, Mapping, Protocol, TypeVar
|
|||
from pydantic import field_validator, model_validator
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
from common.model import DEFAULT_CONFIG
|
||||
from .model import DEFAULT_CONFIG
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
from common.tagged_union import NoValue, TypeTaggedUnion
|
||||
from minecraft.resource import ResourceLocation
|
||||
from patchouli.context import AnyBookContext, BookContext
|
||||
|
||||
|
||||
class ItemIngredient(
|
||||
TypeTaggedUnion[AnyBookContext],
|
||||
group="hexdoc.ItemIngredient",
|
||||
type=None,
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
ItemIngredientOrList = (
|
||||
ItemIngredient[AnyBookContext] | list[ItemIngredient[AnyBookContext]]
|
||||
)
|
||||
|
||||
|
||||
class MinecraftItemIdIngredient(ItemIngredient[BookContext], type=NoValue):
|
||||
item: ResourceLocation
|
||||
|
||||
|
||||
class MinecraftItemTagIngredient(ItemIngredient[BookContext], type=NoValue):
|
||||
tag: ResourceLocation
|
|
@ -1,7 +0,0 @@
|
|||
__all__ = ["Book", "Category", "Entry", "Page", "Style", "FormatTree"]
|
||||
|
||||
from .book import Book
|
||||
from .category import Category
|
||||
from .entry import Entry
|
||||
from .page import Page
|
||||
from .text import FormatTree, Style
|
|
@ -1,8 +0,0 @@
|
|||
__all__ = [
|
||||
"FormatTree",
|
||||
"Style",
|
||||
"DEFAULT_MACROS",
|
||||
"FormatContext",
|
||||
]
|
||||
|
||||
from .formatting import DEFAULT_MACROS, FormatContext, FormatTree, Style
|
|
@ -1,6 +1,6 @@
|
|||
import pytest
|
||||
|
||||
from minecraft.resource import ItemStack, ResLoc, ResourceLocation
|
||||
from hexdoc.resource import ItemStack, ResLoc, ResourceLocation
|
||||
|
||||
resource_locations: list[tuple[str, ResourceLocation, str]] = [
|
||||
(
|
||||
|
|
|
@ -1,34 +1,13 @@
|
|||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Iterator
|
||||
|
||||
import pytest
|
||||
from bs4 import BeautifulSoup as bs
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from syrupy.extensions.amber import AmberSnapshotExtension
|
||||
from syrupy.types import SerializedData
|
||||
|
||||
from hexcasting.scripts.main import Args, main
|
||||
from hexdoc.scripts.hexdoc import Args, main
|
||||
|
||||
|
||||
def prettify(data: SerializedData) -> str:
|
||||
return bs(data, features="html.parser").prettify()
|
||||
|
||||
|
||||
class NoDiffSnapshotEx(AmberSnapshotExtension):
|
||||
def diff_snapshots(
|
||||
self, serialized_data: SerializedData, snapshot_data: SerializedData
|
||||
) -> SerializedData:
|
||||
return "no diff"
|
||||
|
||||
def diff_lines(
|
||||
self, serialized_data: SerializedData, snapshot_data: SerializedData
|
||||
) -> Iterator[str]:
|
||||
yield from ["no diff"]
|
||||
|
||||
|
||||
_RUN = [sys.executable, "-m" "hexcasting.scripts.main"]
|
||||
_RUN = ["hexdoc"]
|
||||
_ARGV = ["properties.toml", "-o"]
|
||||
|
||||
|
||||
|
@ -53,28 +32,3 @@ def test_cmd(tmp_path: Path, snapshot: SnapshotAssertion):
|
|||
def test_stdout(capsys: pytest.CaptureFixture[str], snapshot: SnapshotAssertion):
|
||||
main(Args().parse_args(["properties.toml"]))
|
||||
assert capsys.readouterr() == snapshot
|
||||
|
||||
|
||||
# def test_book_text(snapshot: SnapshotAssertion):
|
||||
# def test_field(data_class: Any, field: Field[Any]):
|
||||
# value = getattr(data_class, field.name, None)
|
||||
# if isinstance(value, (LocalizedStr, FormatTree)):
|
||||
# assert value == snapshot
|
||||
|
||||
# props = Properties.load(Path("properties.toml"))
|
||||
# book = HexBook.load(HexBookState(props))
|
||||
|
||||
# for field in fields(book):
|
||||
# test_field(book, field)
|
||||
|
||||
# for category in book.categories.values():
|
||||
# for field in fields(category):
|
||||
# test_field(category, field)
|
||||
|
||||
# for entry in category.entries:
|
||||
# for field in fields(entry):
|
||||
# test_field(entry, field)
|
||||
|
||||
# for page in entry.pages:
|
||||
# for field in fields(page):
|
||||
# test_field(page, field)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import pytest
|
||||
|
||||
from common.types import Color
|
||||
from hexdoc.utils.types import Color
|
||||
|
||||
colors: list[str] = [
|
||||
"#0099FF",
|
|
@ -1,6 +1,6 @@
|
|||
# pyright: reportPrivateUsage=false
|
||||
from patchouli.text import DEFAULT_MACROS, FormatTree
|
||||
from patchouli.text.formatting import (
|
||||
from hexdoc.patchouli.text import DEFAULT_MACROS, FormatTree
|
||||
from hexdoc.patchouli.text.formatting import (
|
||||
CommandStyle,
|
||||
FunctionStyle,
|
||||
FunctionStyleType,
|
Loading…
Reference in a new issue