formatting fixes, fix a bug when resetting an existing table

This commit is contained in:
evilchili 2024-02-17 17:05:33 -08:00
parent 6984bfc5e8
commit c3a58696c2
4 changed files with 102 additions and 106 deletions

View File

@ -1,12 +1,13 @@
from collections import defaultdict
from rolltable.types import RollTable
from rolltable import tables
import typer
from enum import Enum
from rich import print
from pathlib import Path
from typing import List
import typer
from rich import print
from rolltable import tables
from rolltable.types import RollTable
app = typer.Typer()
app_state = defaultdict(
@ -16,89 +17,71 @@ app_state = defaultdict(
class OUTPUT_FORMATS(Enum):
text = 'text'
yaml = 'yaml'
markdown = 'markdown'
text = "text"
yaml = "yaml"
markdown = "markdown"
@app.callback()
def main(
frequency: str = typer.Option(
'default',
help='use the specified frequency from the source file'
),
die: int = typer.Option(
20,
help='The size of the die for which to create a table'
),
frequency: str = typer.Option("default", help="use the specified frequency from the source file"),
die: int = typer.Option(20, help="The size of the die for which to create a table"),
hide_rolls: bool = typer.Option(
False,
help='If True, do not show the Roll column.',
),
collapsed: bool = typer.Option(
True,
help='If True, collapse multiple die values with the same option.'
),
width: int = typer.Option(
120,
help='Width of the table.'
help="If True, do not show the Roll column.",
),
collapsed: bool = typer.Option(True, help="If True, collapse multiple die values with the same option."),
width: int = typer.Option(120, help="Width of the table."),
output: OUTPUT_FORMATS = typer.Option(
'text',
help='The output format to use.',
)
"text",
help="The output format to use.",
),
):
app_state['options'] = {
'frequency': frequency,
'die': die,
'hide_rolls': hide_rolls,
app_state["options"] = {
"frequency": frequency,
"die": die,
"hide_rolls": hide_rolls,
}
app_state['collapsed'] = collapsed
app_state['width'] = width
app_state['output'] = output
app_state["collapsed"] = collapsed
app_state["width"] = width
app_state["output"] = output
@app.command("custom")
def custom(
sources: List[Path] = typer.Argument(
...,
help="Path to one or more yaml-formatted source file."),
sources: List[Path] = typer.Argument(..., help="Path to one or more yaml-formatted source file."),
):
"""
Create roll tables from custom sources.
"""
rt = RollTable([Path(s).read_text() for s in sources], **app_state['options'])
rt = RollTable([Path(s).read_text() for s in sources], **app_state["options"])
print_table(rt)
def print_table(table):
if app_state['output'] == OUTPUT_FORMATS.yaml:
if app_state["output"] == OUTPUT_FORMATS.yaml:
print(table.as_yaml())
elif app_state['output'] == OUTPUT_FORMATS.markdown:
elif app_state["output"] == OUTPUT_FORMATS.markdown:
print(table.as_markdown())
else:
print(table.as_table(
width=app_state['width'],
expanded=not app_state['collapsed']
))
print(table.as_table(width=app_state["width"], expanded=not app_state["collapsed"]))
def make_callback(roll_table_instance):
def inner():
roll_table_instance.frequency = app_state['options']['frequency']
roll_table_instance.die = app_state['options']['die']
roll_table_instance.frequency = app_state["options"]["frequency"]
roll_table_instance.die = app_state["options"]["die"]
print_table(roll_table_instance)
return inner
# step through all the predfined tables and create a cli for each
for name, table in tables.index.items():
help_text = name.replace('_', ' ').title()
app.command(name=name, help=f"Create a roll table of {help_text}")(
make_callback(table)
)
help_text = name.replace("_", " ").title()
app.command(name=name, help=f"Create a roll table of {help_text}")(make_callback(table))
if __name__ == '__main__':
if __name__ == "__main__":
app()

View File

@ -1,21 +1,19 @@
from pathlib import Path
from rolltable.types import RollTable
from typing import Any
from rolltable.types import RollTable
def from_sources(names: list[str] = []) -> list:
return RollTable([
(Path(__file__).parent / "sources" / name).read_text()
for name in names
])
return RollTable([(Path(__file__).parent / "sources" / name).read_text() for name in names])
index = dict(
psychadelic_effects=from_sources(['psychadelic_effects.yaml']),
trinkets=from_sources(['trinkets.yaml']),
wild_magic=from_sources(['wild_magic.yaml']),
spells=from_sources(['spells.yaml']),
encounters=from_sources(['encounters.yaml']),
psychadelic_effects=from_sources(["psychadelic_effects.yaml"]),
trinkets=from_sources(["trinkets.yaml"]),
wild_magic=from_sources(["wild_magic.yaml"]),
spells=from_sources(["spells.yaml"]),
encounters=from_sources(["encounters.yaml"]),
)

View File

@ -1,10 +1,10 @@
import yaml
from csv2md.table import Table
from collections.abc import Iterable
from typing import Optional, List, Union
from random_sets.datasources import DataSource
from typing import List, Optional, Union
import rich.table
import yaml
from csv2md.table import Table
from random_sets.datasources import DataSource
class RollTable:
@ -29,10 +29,15 @@ class RollTable:
d2-d4 Bar
"""
def __init__(self, sources: Union[List[str], List[DataSource]], frequency: str = 'default',
die: Optional[int] = 20, hide_rolls: bool = False) -> None:
def __init__(
self,
sources: Union[List[str], List[DataSource]],
frequency: str = "default",
die: Optional[int] = 20,
hide_rolls: bool = False,
) -> None:
self._sources = sources
self._frequency = frequency
self.frequency = frequency
self.die = die
self.hide_rolls = hide_rolls
self.data = None
@ -70,21 +75,19 @@ class RollTable:
]
"""
if not self._generated_values:
self._generated_values = list(zip(*[
t.random_values(self.die) for t in self._data
]))
self._generated_values = list(zip(*[t.random_values(self.die) for t in self._data]))
return self._generated_values
@property
def rows(self) -> List:
def formatted(lastrow, offset, row, i):
thisrow = [f'd{i}' if offset + 1 == i else f'd{offset+1}-d{i}']
thisrow = [f"d{i}" if offset + 1 == i else f"d{offset+1}-d{i}"]
thisrow += self._flatten(lastrow)
return self._column_filter(thisrow)
lastrow = None
offset = 0
self._rows = [self._column_filter(['Roll'] + self.headers)]
self._rows = [self._column_filter(["Roll"] + self.headers)]
for face in range(self.die):
row = self._values[face]
@ -101,14 +104,15 @@ class RollTable:
@property
def expanded_rows(self) -> List:
self._rows = [self._column_filter(['Roll'] + self.headers)]
self._rows = [self._column_filter(["Roll"] + self.headers)]
for face in range(self.die):
row = self._values[face]
self._rows.append(self._column_filter([f'd{face+1}'] + row))
self._rows.append(self._column_filter([f"d{face+1}"] + row))
return self._rows
def reset(self) -> None:
self._generated_values = None
self._config()
def as_markdown(self) -> str:
return Table(self.rows).markdown()
@ -118,9 +122,9 @@ class RollTable:
for row in self.rows[1:]:
struct[row[0]] = {}
# pad rows with empty cols as necessary
cols = row[1:] + [''] * (len(self.headers) - len(row[1:]))
cols = row[1:] + [""] * (len(self.headers) - len(row[1:]))
for idx, col in enumerate(cols):
struct[row[0]][self.headers[idx] if idx < len(self.headers) else '_'] = col
struct[row[0]][self.headers[idx] if idx < len(self.headers) else "_"] = col
return yaml.dump(struct, sort_keys=False)
def as_table(self, width: int = 120, expanded: bool = False) -> str:
@ -151,7 +155,7 @@ class RollTable:
if type(src) is str:
src = [src]
for one_source in src:
ds = DataSource(one_source, frequency=self._frequency)
ds = DataSource(one_source, frequency=self.frequency)
ds.load_source()
self._data.append(ds)
@ -162,9 +166,9 @@ class RollTable:
self.set_headers(*headers)
def _column_filter(self, row):
cols = [col or '' for (pos, col) in enumerate(row) if pos not in self._header_excludes]
cols = [col or "" for (pos, col) in enumerate(row) if pos not in self._header_excludes]
# pad the row with empty columns if there are more headers than columns
cols = cols + [''] * (1 + len(self.headers) - len(row))
cols = cols + [""] * (1 + len(self.headers) - len(row))
# strip the leading column if we're hiding the dice rolls
return cols[1:] if self.hide_rolls else cols
@ -177,5 +181,5 @@ class RollTable:
def __repr__(self) -> str:
rows = list(self.rows)
str_format = '\t'.join(['{:10s}'] * len(rows[0]))
return "\n".join([str_format.format(*[r or '' for r in row]) for row in rows])
str_format = "\t".join(["{:10s}"] * len(rows[0]))
return "\n".join([str_format.format(*[r or "" for r in row]) for row in rows])

View File

@ -3,26 +3,37 @@ import pytest
from rolltable import tables
@pytest.mark.parametrize('table, expected', [
(tables.wild_magic, ['A third eye', 'Advantage on perception checks']),
(tables.trinkets, ['ivory mimic']),
(tables.psychadelic_effects, ['Cosmic', 'mind expands', 'it will become so']),
(tables.encounters, ['None', 'Easy', 'Difficult', 'Dangerous', 'Deadly'])
])
@pytest.mark.parametrize(
"table, expected",
[
(tables.wild_magic, ["A third eye", "Advantage on perception checks"]),
(tables.trinkets, ["ivory mimic"]),
(tables.psychadelic_effects, ["Cosmic", "mind expands", "it will become so"]),
(tables.encounters, ["None", "Easy", "Difficult", "Dangerous", "Deadly"]),
],
)
def test_flat(table, expected):
table.die = 1000
assert 'd1000' in str(table)
assert "d1000" in str(table)
for txt in expected:
assert txt in str(table)
def test_encounter_frequencies():
table = tables.encounters
table.die = 1000
table.frequency = "none"
table.reset()
assert "Deadly" not in str(table)
table.frequency = "deadly"
table.reset()
assert "Deadly" in str(table)
def test_markdown():
tables.trinkets.die = 1
md = tables.trinkets.as_markdown()
assert '| Roll | Trinket ' in md
assert '| ---- |' in md
assert 'd1' in md
assert "| Roll | Trinket " in md
assert "| ---- |" in md
assert "d1" in md