Prepared package for adding GM sheets.

- Improved test coverage in ``make_sheets.py``.
- Refactor file loading to make it more flexible.
- Added a stub ``gm.py`` example.
This commit is contained in:
Mark Wolfman
2021-06-01 22:51:10 -05:00
parent bb3a40ed0e
commit 3b8dbc0566
7 changed files with 116 additions and 19 deletions
+21 -5
View File
@@ -4,7 +4,7 @@ import re
import warnings
import math
from types import ModuleType
from typing import Sequence, Union
from typing import Sequence, Union, MutableMapping
import jinja2
@@ -22,7 +22,7 @@ from dungeonsheets import (
)
from dungeonsheets.stats import findattr
from dungeonsheets.weapons import Weapon
from dungeonsheets.readers import read_character_file
from dungeonsheets.readers import read_sheet_file
from dungeonsheets.entity import Entity
@@ -884,9 +884,25 @@ class Character(Entity):
return ()
@classmethod
def load(Cls, character_file):
# Create a character from the character definition
char_props = read_character_file(character_file)
def load(Cls, char_props: MutableMapping):
"""Factory Creates a character from the character definition.
Parameters
==========
char_props
Keys and values holding all the attributes of the
character. E.g. ``char_props['strength'] = 16``
Returns
=======
char
The initialized ``Character`` object with associated
parameters.
"""
# Parse the sheet type
char_props.pop('sheet_type', "")
# Load classes
classes = char_props.get("classes", [])
# backwards compatability
if (len(classes) == 0) and ("character_class" in char_props):
+3 -3
View File
@@ -12,8 +12,7 @@ from itertools import product
from jinja2 import Environment, PackageLoader
from dungeonsheets import character as _char
from dungeonsheets import exceptions, readers, latex
from dungeonsheets import character as _char, exceptions, readers, latex
from dungeonsheets.stats import mod_str
from dungeonsheets.fill_pdf_template import (
create_character_pdf_template,
@@ -132,7 +131,8 @@ def make_sheet(
"""
if character is None:
character = _char.Character.load(character_file)
char_props = readers.read_sheet_file(character_file)
character = _char.Character.load(char_props)
# Set the fields in the FDF
char_base = os.path.splitext(character_file)[0] + "_char"
+1 -1
View File
@@ -12,7 +12,7 @@ from dungeonsheets import exceptions
log = logging.getLogger(__file__)
def read_character_file(filename: str):
def read_sheet_file(filename: str):
"""Create a character object from the given definition file.
The definition file should be an importable python file or a JSON
+10
View File
@@ -0,0 +1,10 @@
"""This file describes game-manager notes.
It's used for creating notes for the GM to keep track of various
monsters, etc.
"""
dungeonsheets_version = "0.14.0"
sheet_type = "gm"
+5
View File
@@ -235,6 +235,11 @@ class TestCharacter(TestCase):
char.race = None
self.assertEqual(char.speed, "30")
def test_load_char(self):
char = Character.load({"name": "Dave", "sheet_type": "character"})
self.assertFalse(hasattr(char, "sheet_type"),
"'sheet_type' not stripped from char props")
class DruidTestCase(TestCase):
def test_learned_spells(self):
+56 -3
View File
@@ -1,9 +1,8 @@
import unittest
import os
from pathlib import Path
from dungeonsheets import make_sheets, character
from dungeonsheets.fill_pdf_template import create_character_pdf_template, create_spells_pdf_template
from dungeonsheets.classes import monk
EG_DIR = os.path.abspath(os.path.join(os.path.split(__file__)[0], "../examples/"))
@@ -25,5 +24,59 @@ class PdfOutputTestCase(unittest.TestCase):
# self.assertFalse(os.path.exists(pdf_name), f'{pdf_name} already exists.')
char = character.Character(name="Clara")
char.saving_throw_proficiencies = ["strength"]
make_sheets.create_character_pdf_template(character=char, basename=self.basename)
make_sheets.create_character_pdf_template(
character=char, basename=self.basename
)
self.assertTrue(os.path.exists(pdf_name), f"{pdf_name} not created.")
class TexCreatorTestCase(unittest.TestCase):
"""Test various helper functions for creating TeX from a character."""
def new_character(self):
char = character.Character(
classes=["Monk", "Druid", "Artificer"],
levels=[1, 1, 1],
subclasses=["way of the open hand", None, None],
magic_items=["cloak of protection"],
spells=["invisibility"],
wild_shapes=["crocodile"],
infusions=["boots of the winding path"]
)
return char
def test_create_subclasses_tex(self):
char = self.new_character()
tex = make_sheets.create_subclasses_tex(character=char)
self.assertIn(r"\section*{Subclasses}", tex)
self.assertIn(r"\subsection*{Way of the Open Hand}", tex)
def test_create_features_tex(self):
char = self.new_character()
tex = make_sheets.create_features_tex(character=char)
self.assertIn(r"\section*{Features}", tex)
self.assertIn(r"\subsection*{Martial Arts}", tex)
def test_create_magic_items_tex(self):
char = self.new_character()
tex = make_sheets.create_magic_items_tex(character=char)
self.assertIn(r"\section*{Magic Items}", tex)
self.assertIn(r"\subsection*{Cloak of Protection}", tex)
def test_create_spellbook_tex(self):
char = self.new_character()
tex = make_sheets.create_spellbook_tex(character=char)
self.assertIn(r"\section*{Spells}", tex)
self.assertIn(r"\section*{Invisibility}", tex)
def test_create_infusions_tex(self):
char = self.new_character()
tex = make_sheets.create_infusions_tex(character=char)
self.assertIn(r"\section*{Infusions}", tex)
self.assertIn(r"\subsection*{Boots of the Winding Path}", tex)
def test_create_druid_shapes_tex(self):
char = self.new_character()
tex = make_sheets.create_druid_shapes_tex(character=char)
self.assertIn(r"\section*{Known Beasts}", tex)
self.assertIn(r"\section*{Crocodile}", tex)
+20 -7
View File
@@ -3,27 +3,40 @@ from pathlib import Path
import unittest
import types
from dungeonsheets.readers import read_character_file
from dungeonsheets import exceptions
from dungeonsheets.readers import read_sheet_file
EG_DIR = (Path(__file__).parent.parent / "examples").resolve()
CHAR_PYTHON_FILE = EG_DIR / "rogue1.py"
GM_PYTHON_FILE = EG_DIR / "gm.py"
ROLL20_JSON_FILE = EG_DIR / "barbarian3.json"
FOUNDRY_JSON_FILE = EG_DIR / "bard3_foundry.json"
SPELLCASTER_JSON_FILE = EG_DIR / "artificer2.json"
class PythonReaderTests(unittest.TestCase):
def test_load_python_file(self):
def test_load_python_gm_sheet(self):
gmfile = GM_PYTHON_FILE
result = read_sheet_file(gmfile)
self.assertEqual(result["sheet_type"], "gm")
def test_load_python_character(self):
charfile = CHAR_PYTHON_FILE
result = read_character_file(charfile)
result = read_sheet_file(charfile)
self.assertEqual(result["strength"], 10)
def test_load_bad_file(self):
"""This file is not a valid character, so should fail."""
this_file = __file__
with self.assertRaises(exceptions.CharacterFileFormatError):
read_sheet_file(this_file)
class Roll20ReaderTests(unittest.TestCase):
def test_load_json_file(self):
charfile = ROLL20_JSON_FILE
with warnings.catch_warnings(record=True):
result = read_character_file(charfile)
result = read_sheet_file(charfile)
expected_data = dict(
name="Ulthar Jenkins",
classes=["Barbarian"],
@@ -88,7 +101,7 @@ class Roll20ReaderTests(unittest.TestCase):
def test_load_json_spells(self):
charfile = SPELLCASTER_JSON_FILE
with warnings.catch_warnings(record=True):
result = read_character_file(charfile)
result = read_sheet_file(charfile)
expected_data = dict(
spells_prepared=[
"cure wounds",
@@ -127,7 +140,7 @@ class FoundryReaderTests(unittest.TestCase):
def test_load_json_file(self):
charfile = FOUNDRY_JSON_FILE
with warnings.catch_warnings(record=True):
result = read_character_file(charfile)
result = read_sheet_file(charfile)
expected_data = dict(
name="Sam Lloyd",
classes=["Bard"],
@@ -207,7 +220,7 @@ class FoundryReaderTests(unittest.TestCase):
def test_load_json_spells(self):
charfile = SPELLCASTER_JSON_FILE
with warnings.catch_warnings(record=True):
result = read_character_file(charfile)
result = read_sheet_file(charfile)
expected_data = dict(
spells_prepared=[
"cure wounds",