From c3a58696c211241a0a8c73024b49eace12eadc72 Mon Sep 17 00:00:00 2001 From: evilchili Date: Sat, 17 Feb 2024 17:05:33 -0800 Subject: [PATCH] formatting fixes, fix a bug when resetting an existing table --- rolltable/cli.py | 85 ++++++++++++++++++-------------------------- rolltable/tables.py | 18 +++++----- rolltable/types.py | 74 ++++++++++++++++++++------------------ tests/test_tables.py | 31 ++++++++++------ 4 files changed, 102 insertions(+), 106 deletions(-) diff --git a/rolltable/cli.py b/rolltable/cli.py index a0b95d0..c91a1cc 100644 --- a/rolltable/cli.py +++ b/rolltable/cli.py @@ -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() diff --git a/rolltable/tables.py b/rolltable/tables.py index 15047e2..07152b7 100644 --- a/rolltable/tables.py +++ b/rolltable/tables.py @@ -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"]), ) diff --git a/rolltable/types.py b/rolltable/types.py index 260f45e..1efb4ff 100644 --- a/rolltable/types.py +++ b/rolltable/types.py @@ -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 @@ -53,38 +58,36 @@ class RollTable: @property def _values(self) -> List: """ - For each data source, select N random values, where N is the size of the die. - we then zip those random values so that each member of the generated list - contains one value from each data source. So if _data is: + For each data source, select N random values, where N is the size of the die. + we then zip those random values so that each member of the generated list + contains one value from each data source. So if _data is: - [ - ['axe', 'shortsword', 'dagger'], - ['fire', 'ice', 'poison'], - ] + [ + ['axe', 'shortsword', 'dagger'], + ['fire', 'ice', 'poison'], + ] - and the die is 2, the resulting generated values might be: + and the die is 2, the resulting generated values might be: - [ - ['axe', 'fire'], - ['dagger', 'ice'], - ] + [ + ['axe', 'fire'], + ['dagger', 'ice'], + ] """ 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] @@ -96,19 +99,20 @@ class RollTable: self._rows.append(formatted(lastrow, offset, row, face)) lastrow = row offset = face - self._rows.append(formatted(lastrow, offset, row, face+1)) + self._rows.append(formatted(lastrow, offset, row, face + 1)) return self._rows @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: @@ -138,7 +142,7 @@ class RollTable: self._header_excludes = [] for i in range(len(self._headers)): if self.headers[i] is None: - self._header_excludes.append(i+1) + self._header_excludes.append(i + 1) def _config(self): """ @@ -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]) diff --git a/tests/test_tables.py b/tests/test_tables.py index 616e1b8..7e46a17 100644 --- a/tests/test_tables.py +++ b/tests/test_tables.py @@ -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