fix bug where overrides are applied after templates are processed
This commit is contained in:
parent
2dda47f9c4
commit
d13878a7ce
|
@ -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,
|
||||||
|
|
|
@ -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.'
|
||||||
|
|
Loading…
Reference in New Issue
Block a user