mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-05-18 20:23:27 +02:00
_resolve_mechanic no longer accepts a *module* argument since it uses the content registry.
This commit is contained in:
+17
-15
@@ -69,32 +69,39 @@ multiclass_spellslots_by_level = {
|
||||
}
|
||||
|
||||
|
||||
def _resolve_mechanic(mechanic, module, SuperClass, warning_message=None):
|
||||
def _resolve_mechanic(mechanic, SuperClass, warning_message=None):
|
||||
"""Take a raw entry in a character sheet and turn it into a usable object.
|
||||
|
||||
Eg: spells can be defined in many ways. This function accepts all
|
||||
of those options and returns an actual *Spell* class that can be
|
||||
used by a character::
|
||||
|
||||
>>> _resolve_mechanic("mage_hand", SuperClass=spells.Spell)
|
||||
|
||||
>>> _resolve_mechanic("mage_hand", SuperClass=None)
|
||||
|
||||
>>> from dungeonsheets import spells
|
||||
>>> _resolve_mechanic("mage_hand", spells, None)
|
||||
>>> class MySpell(spells.Spell): pass
|
||||
>>> _resolve_mechanic(MySpell, None, spells.Spell)
|
||||
>>> _resolve_mechanic("hocus pocus", spells, None)
|
||||
>>> _resolve_mechanic(MySpell, SuperClass=spells.Spell)
|
||||
|
||||
>>> _resolve_mechanic("hocus pocus", SuperClass=spells.Spell)
|
||||
|
||||
The acceptable entries for *mechanic*, in priority order, are:
|
||||
1. A subclass of *SuperClass*
|
||||
2. A string with the name of a defined spell in *module*
|
||||
2. A string with the name of defined content
|
||||
3. The name of an unknown spell (creates generic object using *factory*)
|
||||
|
||||
*SuperClass* can be ``None`` to match any class, however this will
|
||||
raise an exception if more than one content type has this
|
||||
name. For example, "shield" can refer to both the armor or the
|
||||
spell, so ``_resolve_mechanic("shield")`` will raise an exception.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
mechanic : str, type
|
||||
The thing to be resolved, either a string with the name of the
|
||||
mechanic, or a subclass of *ParentClass* describing the
|
||||
mechanic.
|
||||
module : module
|
||||
A python module in which to look for the defined string in *name*.
|
||||
SuperClass : type
|
||||
Class to determine whether *mechanic* should just be allowed
|
||||
through as is.
|
||||
@@ -120,7 +127,8 @@ def _resolve_mechanic(mechanic, module, SuperClass, warning_message=None):
|
||||
else:
|
||||
try:
|
||||
# Retrieve pre-defined mechanic
|
||||
Mechanic = find_content(mechanic, valid_classes=[SuperClass])
|
||||
valid_classes = [SuperClass] if SuperClass is not None else []
|
||||
Mechanic = find_content(mechanic, valid_classes=valid_classes)
|
||||
except AttributeError:
|
||||
# No pre-defined mechanic available
|
||||
if warning_message is not None:
|
||||
@@ -618,7 +626,6 @@ class Character(Entity):
|
||||
)
|
||||
ThisMagicItem = _resolve_mechanic(
|
||||
mechanic=mitem,
|
||||
module=magic_items,
|
||||
SuperClass=magic_items.MagicItem,
|
||||
warning_message=msg,
|
||||
)
|
||||
@@ -627,7 +634,7 @@ class Character(Entity):
|
||||
self.other_weapon_proficiencies = ()
|
||||
msg = 'Magic Item "{}" not defined. Please add it to ``weapons.py``'
|
||||
wps = set(
|
||||
[_resolve_mechanic(w, weapons, weapons.Weapon, msg) for w in val]
|
||||
[_resolve_mechanic(w, SuperClass=weapons.Weapon, warning_message=msg) for w in val]
|
||||
)
|
||||
wps -= set(self.weapon_proficiencies)
|
||||
self.other_weapon_proficiencies = list(wps)
|
||||
@@ -646,7 +653,6 @@ class Character(Entity):
|
||||
msg = 'Feature "{}" not defined. Please add it to ``features.py``'
|
||||
ThisFeature = _resolve_mechanic(
|
||||
mechanic=f,
|
||||
module=features,
|
||||
SuperClass=features.Feature,
|
||||
warning_message=msg,
|
||||
)
|
||||
@@ -659,7 +665,6 @@ class Character(Entity):
|
||||
msg = 'Spell "{}" not defined. Please add it to ``spells.py``'
|
||||
ThisSpell = _resolve_mechanic(
|
||||
mechanic=spell_name,
|
||||
module=spells,
|
||||
SuperClass=spells.Spell,
|
||||
warning_message=msg,
|
||||
)
|
||||
@@ -683,7 +688,6 @@ class Character(Entity):
|
||||
)
|
||||
ThisInfusion = _resolve_mechanic(
|
||||
mechanic=infusion_name,
|
||||
module=infusions,
|
||||
SuperClass=infusions.Infusion,
|
||||
warning_message=msg,
|
||||
)
|
||||
@@ -793,7 +797,6 @@ class Character(Entity):
|
||||
msg = 'Unnown armor "{}". Please add it to ``armor.py``.'
|
||||
NewArmor = _resolve_mechanic(
|
||||
mechanic=new_armor,
|
||||
module=armor,
|
||||
SuperClass=armor.Armor,
|
||||
warning_message=msg,
|
||||
)
|
||||
@@ -834,7 +837,6 @@ class Character(Entity):
|
||||
msg = 'Unknown weapon "{}". Please add it to ``weapons.py``.'
|
||||
ThisWeapon = _resolve_mechanic(
|
||||
mechanic=weapon,
|
||||
module=weapons,
|
||||
SuperClass=weapons.Weapon,
|
||||
warning_message=msg,
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@ from functools import lru_cache
|
||||
import importlib.util
|
||||
from typing import Union, List, Optional
|
||||
|
||||
from dungeonsheets import weapons, monsters, race, background, armor, spells, infusions, magic_items
|
||||
from dungeonsheets import weapons, monsters, race, background, armor, spells, infusions, magic_items, features
|
||||
|
||||
|
||||
class ContentRegistry():
|
||||
@@ -80,6 +80,7 @@ default_content_registry.add_module(armor)
|
||||
default_content_registry.add_module(spells)
|
||||
default_content_registry.add_module(infusions)
|
||||
default_content_registry.add_module(magic_items)
|
||||
default_content_registry.add_module(features)
|
||||
|
||||
|
||||
def find_content(name: str, valid_classes: Optional[List]):
|
||||
@@ -100,7 +101,7 @@ def find_content(name: str, valid_classes: Optional[List]):
|
||||
return default_content_registry.findattr(name, valid_classes=valid_classes)
|
||||
|
||||
|
||||
@lru_cache
|
||||
@lru_cache()
|
||||
def import_homebrew(filepath: Union[str, Path]):
|
||||
"""Import a module file containing homebrew content.
|
||||
|
||||
|
||||
@@ -79,24 +79,23 @@ class TestCharacter(TestCase):
|
||||
self.assertIsInstance(char.infusions[0], infusions.Infusion)
|
||||
self.assertEqual(char.infusions[0].name, "Spam Infusion")
|
||||
|
||||
@expectedFailure
|
||||
def test_resolve_mechanic(self):
|
||||
# Test a well defined mechanic
|
||||
NewSpell = _resolve_mechanic("mage_hand", spells, None)
|
||||
NewSpell = _resolve_mechanic("mage_hand", None)
|
||||
self.assertTrue(issubclass(NewSpell, spells.Spell))
|
||||
|
||||
# Test an unknown mechanic
|
||||
def new_spell(**params):
|
||||
return spells.Spell
|
||||
|
||||
NewSpell = _resolve_mechanic("hocus_pocus", spells, spells.Spell)
|
||||
NewSpell = _resolve_mechanic("hocus_pocus", spells.Spell)
|
||||
self.assertTrue(issubclass(NewSpell, spells.Spell))
|
||||
|
||||
# Test direct resolution of a proper subclass
|
||||
class MySpell(spells.Spell):
|
||||
pass
|
||||
|
||||
NewSpell = _resolve_mechanic(MySpell, spells, spells.Spell)
|
||||
NewSpell = _resolve_mechanic(MySpell, spells.Spell)
|
||||
|
||||
def test_wield_weapon(self):
|
||||
char = Character()
|
||||
|
||||
Reference in New Issue
Block a user