mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-05-18 20:23:27 +02:00
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:
@@ -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):
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
@@ -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):
|
||||
|
||||
@@ -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
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user