You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
spiel/spiel/options.py

69 lines
2.0 KiB
Python

from collections.abc import Mapping
from dataclasses import asdict, dataclass, fields
from pathlib import Path
from typing import Any
import tomli
import tomli_w
from rich.align import Align
from rich.console import ConsoleRenderable
from rich.padding import Padding
from rich.table import Column, Table
from spiel.constants import PACKAGE_NAME
from spiel.exceptions import InvalidOptionValue
from spiel.repls import REPLS
@dataclass
class Options:
repl: str = "ipython"
footer_time_format: str = "YYYY-MM-DD hh:mm A"
profiling: bool = False
def __post_init__(self) -> None:
if self.repl not in REPLS:
raise InvalidOptionValue(f"repl must be one of: {set(REPLS.keys())}")
def as_dict(self) -> Mapping[str, Any]:
return asdict(self)
@classmethod
def from_dict(cls, d: Mapping[str, Any]) -> "Options":
fields_by_name = {field.name: field for field in fields(cls)}
only_valid = {k: fields_by_name[k].type(v) for k, v in d.items() if k in fields_by_name}
return cls(**only_valid)
def as_toml(self) -> str:
return tomli_w.dumps({PACKAGE_NAME: self.as_dict()})
@classmethod
def from_toml(cls, t: str) -> "Options":
return cls.from_dict(tomli.loads(t).get(PACKAGE_NAME, {}))
def save(self, path: Path) -> Path:
path.write_text(self.as_toml())
return path
@classmethod
def load(cls, path: Path) -> "Options":
return cls.from_toml(path.read_text())
def __rich__(self) -> ConsoleRenderable:
table = Table(
Column("Option"),
Column("Type", justify="center"),
Column("Value"),
show_lines=True,
)
fields_by_name = {field.name: field for field in fields(self)}
for key, value in self.as_dict().items():
table.add_row(key, fields_by_name[key].type.__name__, str(value))
return Padding(
Align.center(table),
pad=(0, 1),
)