fix bug where overrides are applied after templates are processed

This commit is contained in:
evilchili 2023-12-31 10:15:15 -08:00
parent 2dda47f9c4
commit d13878a7ce
2 changed files with 51 additions and 11 deletions

View File

@ -156,7 +156,7 @@ class Item(AttributeMap):
? length=10, ? length=10,
? properties=dict( ? properties=dict(
? 'broken'=dict( ? 'broken'=dict(
? description="The end of this {length}ft. pole has been snapped off.", ? description="The end of this 10ft. pole has been snapped off.",
? override_length=7 ? override_length=7
? ), ? ),
? ) ? )
@ -199,10 +199,6 @@ class Item(AttributeMap):
converted to Item objects; everything else is passed as-is. converted to Item objects; everything else is passed as-is.
""" """
# delay processing the 'properties' attribute until after the other
# attributes, because they may contain references to those attributes.
properties = attrs.pop("properties", None)
attributes = dict() attributes = dict()
# recursively locate and populate template strings # recursively locate and populate template strings
@ -233,19 +229,25 @@ class Item(AttributeMap):
# Any type other than dict, list, and string is returned unaltered. # Any type other than dict, list, and string is returned unaltered.
return obj return obj
properties = attrs.pop("properties", {})
# apply property overrides overrides before anything else
for prop in properties.values():
overrides = [k for k in prop.keys() if k.startswith("override_")]
for o in overrides:
if prop[o]:
attrs[o.replace("override_", "")] = prop[o]
# step through the supplied attributes and format each member. # step through the supplied attributes and format each member.
for k, v in sorted(attrs.items(), key=lambda i: '{' in f"{i[0]}{i[1]}"): for k, v in sorted(attrs.items(), key=lambda i: '{' in f"{i[0]}{i[1]}"):
if type(v) is dict: if type(v) is dict:
attributes[k] = AttributeMap.from_dict(_format(v)) attributes[k] = AttributeMap.from_dict(_format(v))
else: else:
attributes[k] = _format(v) attributes[k] = _format(v)
# process properties now that we have preprocessed everything else
if properties: if properties:
attributes["properties"] = AttributeMap.from_dict(_format(properties)) attributes["properties"] = AttributeMap.from_dict(_format(properties))
for prop in attributes["properties"].values():
overrides = [k for k in prop.attributes.keys() if k.startswith("override_")]
for o in overrides:
if prop.attributes[o]:
attributes[o.replace("override_", "")] = prop.attributes[o]
# store the item name as the _name attribute; it is accessable directly, or # store the item name as the _name attribute; it is accessable directly, or
# via the name property. This makes overriding the name convenient for subclassers, # via the name property. This makes overriding the name convenient for subclassers,

View File

@ -1,6 +1,28 @@
from dnd_item import types from dnd_item import types
def test_AttributeMap():
assert types.AttributeMap(attributes={'foo': True, 'bar': False}).foo is True
def test_AttributeMap_nested():
nested_dict = {'foo': {'bar': {'baz': True}, 'boz': False}}
amap = types.AttributeMap.from_dict(nested_dict)
assert amap.foo.bar.baz is True
assert amap.foo.boz is False
def test_AttributeMap_list():
amap = types.AttributeMap(attributes={'foo': True, 'bar': False})
assert list(amap.attributes.keys()) == ['foo', 'bar']
def test_AttributeMap_mapping():
amap = types.AttributeMap(attributes={'foo': True, 'bar': False})
assert 'foo' in amap
assert '{foo}, {bar}'.format(**amap) == 'True, False'
def test_Item_attributes(): def test_Item_attributes():
assert types.Item.from_dict(dict( assert types.Item.from_dict(dict(
name='{length}ft. Pole', name='{length}ft. Pole',
@ -10,7 +32,7 @@ def test_Item_attributes():
)).name == '10ft. Pole' )).name == '10ft. Pole'
def test_item_nested_attributes(): def test_Item_nested_attributes():
assert types.Item.from_dict(dict( assert types.Item.from_dict(dict(
name='{length}ft. Pole', name='{length}ft. Pole',
length=10, length=10,
@ -23,3 +45,19 @@ def test_item_nested_attributes():
owner='Jules Ultardottir', owner='Jules Ultardottir',
) )
)).description == 'Engraved. "Property of Jules Ultardottir!"' )).description == 'Engraved. "Property of Jules Ultardottir!"'
def test_Item_overrides():
attrs = dict(
name='{length}ft. Pole',
length=10,
properties=dict(
broken=dict(
description="The end of this 10ft. pole has been snapped off.",
override_length=7
),
)
)
ten_foot_pole = types.Item.from_dict(attrs)
assert ten_foot_pole.name == '7ft. Pole'
assert ten_foot_pole.description == 'Broken. The end of this 10ft. pole has been snapped off.'