add "fill" action to the CLI, consolidate config generation

This commit is contained in:
2025-12-19 19:45:20 -08:00
parent b56fb396ea
commit 12cf00552b
223 changed files with 10975 additions and 29942 deletions

View File

@@ -10,7 +10,7 @@ def main() -> None:
configure_logging(args.log_level)
if "func" in args:
args.func(args)
args.func(args, parser)
else:
parser.print_help()

View File

@@ -1,7 +1,7 @@
import logging
import argparse
from argparse import ArgumentParser
from monobiome.cli import scheme, palette
from monobiome.cli import fill, scheme, palette
logger: logging.Logger = logging.getLogger(__name__)
@@ -12,8 +12,8 @@ def configure_logging(log_level: int) -> None:
logger.setLevel(log_level)
def create_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
def create_parser() -> ArgumentParser:
parser = ArgumentParser(
description="Accent modeling CLI",
)
parser.add_argument(
@@ -26,7 +26,8 @@ def create_parser() -> argparse.ArgumentParser:
subparsers = parser.add_subparsers(help="subcommand help")
palette.register_parser(subparsers)
fill.register_parser(subparsers)
scheme.register_parser(subparsers)
palette.register_parser(subparsers)
return parser

78
monobiome/cli/fill.py Normal file
View File

@@ -0,0 +1,78 @@
import sys
import tomllib
from pathlib import Path
from argparse import Namespace, ArgumentParser
from symconf.template import Template, TOMLTemplate
from monobiome.util import _SubparserType
from monobiome.palette import generate_palette
def register_parser(subparsers: _SubparserType) -> None:
parser = subparsers.add_parser(
"fill",
help="fill scheme templates for applications"
)
parser.add_argument(
"scheme",
type=str,
help="scheme file path"
)
parser.add_argument(
"template",
nargs="?",
help="template file path (defaults to stdin)"
)
parser.add_argument(
"-p",
"--palette",
type=str,
help="palette file to use for color definitions",
)
parser.add_argument(
"-o",
"--output",
type=str,
help="output file to write filled template",
)
parser.set_defaults(func=handle_fill)
def handle_fill(args: Namespace, parser: ArgumentParser) -> None:
scheme = Path(args.scheme)
output = args.output
if args.template is None:
if sys.stdin.isatty():
parser.error("no template provided (file or stdin)")
return
template_content = sys.stdin.read()
elif args.template == "-":
template_content = sys.stdin.read()
else:
try:
template_content = Path(args.template).read_text()
except OSError as e:
parser.error(f"cannot read template file: {e}")
if args.palette:
try:
palette_toml = Path(args.palette).read_text()
except OSError as e:
parser.error(f"cannot read palette file: {e}")
return
else:
palette_toml = generate_palette("hex", "toml")
palette_dict = tomllib.loads(palette_toml)
concrete_scheme = TOMLTemplate(scheme).fill_dict(palette_dict)
filled_template = Template(template_content).fill(concrete_scheme)
if output is None:
print(filled_template)
else:
with Path(output).open("w") as f:
f.write(filled_template)

View File

@@ -1,5 +1,5 @@
import argparse
from pathlib import Path
from argparse import Namespace, ArgumentParser
from monobiome.util import _SubparserType
from monobiome.palette import generate_palette
@@ -37,7 +37,7 @@ def register_parser(subparsers: _SubparserType) -> None:
parser.set_defaults(func=handle_palette)
def handle_palette(args: argparse.Namespace) -> None:
def handle_palette(args: Namespace, parser: ArgumentParser) -> None:
notation = args.notation
file_format = args.format
output = args.output

View File

@@ -1,5 +1,5 @@
import argparse
from pathlib import Path
from argparse import Namespace, ArgumentParser
from monobiome.util import _SubparserType
from monobiome.scheme import generate_scheme
@@ -90,7 +90,7 @@ def register_parser(subparsers: _SubparserType) -> None:
parser.set_defaults(func=handle_scheme)
def handle_scheme(args: argparse.Namespace) -> None:
def handle_scheme(args: Namespace, parser: ArgumentParser) -> None:
output = args.output
mode = args.mode

View File

@@ -9,8 +9,8 @@ def quad_bezier_rational(
P1: float,
P2: float,
w: float,
t: np.array,
) -> np.array:
t: np.ndarray,
) -> np.ndarray:
"""
Compute the point values of a quadratic rational Bezier curve.
@@ -32,7 +32,7 @@ def bezier_y_at_x(
w: float,
x: float,
n: int = 400,
) -> np.array:
) -> np.ndarray:
"""
For the provided QBR parameters, provide the curve value at the given
input.

View File

@@ -1,4 +1,5 @@
import json
from typing import Any
from functools import cache
from importlib.metadata import version
@@ -12,7 +13,7 @@ from monobiome.constants import (
@cache
def compute_hlc_map(notation: str) -> dict[str, dict[int, str]]:
def compute_hlc_map(notation: str) -> dict[str, Any]:
hlc_map = {}
for h_str, Lpoints_Cstar in Lpoints_Cstar_Hmap.items():
@@ -44,7 +45,7 @@ def generate_palette(
hlc_map["version"] = mb_version
return json.dumps(hlc_map, indent=4)
else:
toml_lines = [f"version = {mb_version}", ""]
toml_lines = [f"version = \"{mb_version}\"", ""]
for _h, _lc_map in hlc_map.items():
toml_lines.append(f"[{_h}]")
for _l, _c in _lc_map.items():

View File

@@ -99,7 +99,7 @@ def palette_image(
palette: dict[str, dict[int, str]],
cell_size: int = 40,
keys: list[str] | None = None
) -> None:
) -> tuple[np.ndarray, list[str], list[list[int]], int, int]:
names = list(palette.keys()) if keys is None else keys
row_count = len(names)
@@ -114,9 +114,9 @@ def palette_image(
for r, name in enumerate(names):
shades = palette[name]
keys = sorted(shades.keys())
lightness_keys_per_row.append(keys)
for c, k in enumerate(keys):
lkeys = sorted(shades.keys())
lightness_keys_per_row.append(lkeys)
for c, k in enumerate(lkeys):
col = Color(shades[k]).convert("srgb").fit(method="clip")
rgb = [col["r"], col["g"], col["b"]]
r0, r1 = r * cell_size, (r + 1) * cell_size
@@ -129,26 +129,45 @@ def palette_image(
def show_palette(
palette: dict[str, dict[int, str]],
cell_size: int = 40,
keys: list[str] | None = None
) -> None:
keys: list[str] | None = None,
show_labels: bool = True,
dpi: int = 100,
) -> tuple[plt.Figure, plt.Axes]:
img, names, keys, cell_size, max_cols = palette_image(
palette, cell_size, keys=keys
)
fig_w = img.shape[1] / 100
fig_h = img.shape[0] / 100
fig, ax = plt.subplots(figsize=(fig_w, fig_h))
ax.imshow(img, interpolation="none", origin="upper")
ax.set_xticks([])
if show_labels:
fig, ax = plt.subplots(figsize=(fig_w, fig_h), dpi=dpi)
ytick_pos = [(i + 0.5) * cell_size for i in range(len(names))]
ax.set_yticks(ytick_pos)
ax.set_yticklabels(names)
ax.set_ylim(img.shape[0], 0) # ensures rows render w/o half-cells
ax.imshow(img, interpolation="none", origin="upper")
ax.set_xticks([])
plt.show()
ytick_pos = [(i + 0.5) * cell_size for i in range(len(names))]
ax.set_yticks(ytick_pos)
ax.set_yticklabels(names)
ax.set_ylim(img.shape[0], 0) # ensures rows render w/o half-cells
return fig, ax
fig = plt.figure(figsize=(fig_w, fig_h), dpi=dpi, frameon=False)
ax = fig.add_axes((0, 0, 1, 1), frame_on=False)
ax.imshow(
img,
interpolation="nearest",
origin="upper",
extent=(0, img.shape[1], img.shape[0], 0),
aspect="auto",
)
ax.set_xlim(0, img.shape[1])
ax.set_ylim(img.shape[0], 0)
ax.axis("off")
fig.subplots_adjust(0, 0, 1, 1, hspace=0, wspace=0)
return fig, ax
if __name__ == "__main__":
keys = [