from __future__ import annotations
import uuid
from functools import partial
from pathlib import Path
from pharaoh.assetlib.finder import asset_groupby
[docs]
def raise_helper(msg):
"""
Raises an Exception with a certain message. The actual name of the Jinja global function is ``raise``.
"""
raise Exception(msg)
[docs]
def heading(text: str, level: int) -> str:
"""
Renders a heading for a certain level.
Shortcuts for this function are automatically generated with names h1...h7.
Examples::
{{ heading("Page Title", 1) }}
{{ h2("Sub-Title") }}
:param text: The heading
:param level: The heading level. From 1 (top-level) to 7.
"""
default = {1: "#", 2: "*", 3: "=", 4: "-", 5: "^", 6: '"', 7: "~"}
if isinstance(level, (float, int)):
if int(level) not in default:
msg = "Default heading characters only available from index 1 to 7!"
raise LookupError(msg)
character = default[level]
else:
character = str(level)
if character not in default.values():
raise ValueError("character must be an integer from 1-7 or one of " + ",".join(default.values()))
text = text.strip().replace("\r", "").replace("\n", "")
if len(text) < 2:
msg = "Heading text must be at least 2 characters"
raise ValueError(msg)
return f"{text}\n{character * len(text)}"
[docs]
def rand_id(chars: int | None = None) -> str:
"""
Returns a unique id for usage in HTML as it is made sure it starts with no number
"""
id = "i" + uuid.uuid4().hex
return id[:chars]
[docs]
def read_text(file) -> str:
"""
Reads a file content using utf-8 encoding.
"""
file = Path(file)
return file.read_text("utf-8")
[docs]
def hrule():
"""
Renders a 1px gray horizontal rule using a raw html directive.
"""
return '.. raw:: html\n\n <hr style="height:1px;border-width:0;color:gray;background-color:gray">\n\n'
[docs]
def fglob(pattern: str, root: str = ".") -> list[Path]:
"""
Returns a list of relative paths of all files relative to a root directory that match a certain pattern.
Examples::
{% set index_files1 = fglob("index_*.rst") %}
{% set index_files2 = fglob("subdir/index_*.rst") %}
:param pattern: A glob pattern to match files.
:param root: The root directory for discovering files and anchor for relative paths.
Default is the current working directory (the parent directory of the currently rendered file).
"""
rootpath = Path(root).absolute()
matches = rootpath.glob(pattern)
return [file.relative_to(rootpath) for file in matches]
[docs]
def assert_true(statement: bool, message: str = ""):
"""
Wrapper for Python's assert builtin.
:param statement: A boolean statement
:param message: The message for the AssertionError, if statement is False.
"""
if message:
assert statement, message
else:
assert statement
env_globals = {
"assert_true": assert_true,
"fglob": fglob,
"hrule": hrule,
"raise": raise_helper,
"heading": heading,
"rand_id": rand_id,
"read_text": read_text,
"agroupby": asset_groupby,
"asset_groupby": asset_groupby,
}
# Shortcuts for headings
for i in range(1, 8):
env_globals[f"h{i}"] = partial(heading, level=i) # type: ignore[assignment]
# Only document the functions defined in here
to_document = {
k: func for k, func in env_globals.items() if hasattr(func, "__module__") and func.__module__ == __name__
}