Added some docstring, cleaned to avoid duplication, added relevant tests

This commit is contained in:
ChrisLR 2022-03-22 09:39:35 -04:00
parent 6f6ceb231c
commit 79be6a4689
3 changed files with 85 additions and 23 deletions

View file

@ -56,7 +56,13 @@ class NDBField(NAttributeProperty):
class TagField:
"""
Component Descriptor to add a tag to the host.
Component Tags Descriptor.
Allows you to set Tags related to a component on the class.
The tags are set with a prefixed category, so it can support
multiple tags or enforce a single one.
Default value of a tag is added when the component is registered.
Tags are removed if the component itself is removed.
"""
def __init__(self, default=None, enforce_single=False):
self._category_key = None
@ -65,9 +71,8 @@ class TagField:
def __set_name__(self, owner, name):
"""
Called when descriptor is first assigned to the class. It is called with
the name of the field.
Called when descriptor is first assigned to the class.
It is called with the name of the field.
"""
self._category_key = f"{owner.name}__{name}"
tag_fields = getattr(owner, "_tag_fields", None)
@ -89,7 +94,7 @@ class TagField:
tag_handler.clear(category=self._category_key)
tag_handler.add(
key=self._key,
key=value,
category=self._category_key,
)

View file

@ -64,12 +64,8 @@ class ComponentHandler:
"""
self._set_component(component)
self.db_names.append(component.name)
self.host.tags.add(component.name, category="components")
self._add_component_tags(component)
component.at_added(self.host)
for tag_field_name in component.tag_field_names:
default_tag = type(component).__dict__[tag_field_name]._default
if default_tag:
setattr(component, tag_field_name, default_tag)
def add_default(self, name):
"""
@ -89,8 +85,19 @@ class ComponentHandler:
new_component = component.default_create(self.host)
self._set_component(new_component)
self.db_names.append(name)
self.host.tags.add(name, category="components")
self._add_component_tags(new_component)
new_component.at_added(self.host)
def _add_component_tags(self, component):
"""
Private method that adds the Tags set on a Component via TagFields
It will also add the name of the component so objects can be filtered
by the components the implement.
Args:
component (object): The component instance that is added.
"""
self.host.tags.add(component.name, category="components")
for tag_field_name in component.tag_field_names:
default_tag = type(component).__dict__[tag_field_name]._default
if default_tag:
@ -108,11 +115,9 @@ class ComponentHandler:
"""
component_name = component.name
if component_name in self._loaded_components:
self._remove_component_tags(component)
component.at_removed(self.host)
self.db_names.remove(component_name)
self.host.tags.remove(component_name, category="components")
for tag_field_name in component.tag_field_names:
self.host.tags.remove()
del self._loaded_components[component_name]
else:
message = f"Cannot remove {component_name} from {self.host.name} as it is not registered."
@ -133,11 +138,24 @@ class ComponentHandler:
message = f"Cannot remove {name} from {self.host.name} as it is not registered."
raise ComponentIsNotRegistered(message)
self._remove_component_tags(instance)
instance.at_removed(self.host)
self.db_names.remove(name)
self.host.tags.remove(name, category="components")
del self._loaded_components[name]
def _remove_component_tags(self, component):
"""
Private method that will remove the Tags set on a Component via TagFields
It will also remove the component name tag.
Args:
component (object): The component instance that is removed.
"""
self.host.tags.remove(component.name, category="components")
for tag_field_name in component.tag_field_names:
delattr(component, tag_field_name)
def get(self, name):
"""
Method to retrieve a cached Component instance by its name.
@ -227,10 +245,6 @@ class ComponentHolderMixin(object):
component = component_class.create(self, **values)
component_names.append(component_name)
self.components._loaded_components[component_name] = component
for tag_field_name in component.tag_field_names:
default_tag = type(component).__dict__[tag_field_name]._default
if default_tag:
setattr(component, tag_field_name, default_tag)
self.db.component_names = component_names
@ -239,8 +253,8 @@ class ComponentHolderMixin(object):
Method that add component related tags that were set using ComponentProperty.
"""
super().basetype_posthook_setup()
for component_name in self.db.component_names:
self.tags.add(component_name, category="components")
for component in self.components._loaded_components.values():
self.components._add_component_tags(component)
@property
def components(self) -> ComponentHandler:

View file

@ -1,4 +1,4 @@
from evennia.contrib.base_systems.components import Component, DBField
from evennia.contrib.base_systems.components import Component, DBField, TagField
from evennia.contrib.base_systems.components.holder import ComponentProperty, ComponentHolderMixin
from evennia.objects.objects import DefaultCharacter
from evennia.utils.test_resources import EvenniaTest
@ -14,12 +14,17 @@ class ComponentTestB(Component):
name = "test_b"
my_int = DBField(default=1)
my_list = DBField(default=[])
default_tag = TagField(default="initial_value")
single_tag = TagField(enforce_single=True)
multiple_tags = TagField()
default_single_tag = TagField(default="initial_value", enforce_single=True)
class RuntimeComponentTestC(Component):
name = "test_c"
my_int = DBField(default=6)
my_dict = DBField(default={})
added_tag = TagField(default="added_value")
class CharacterWithComponents(ComponentHolderMixin, DefaultCharacter):
@ -111,7 +116,11 @@ class TestComponents(EvenniaTest):
def test_host_has_class_component_tags(self):
assert self.char1.tags.has(key="test_a", category="components")
assert self.char1.tags.has(key="test_b", category="components")
assert self.char1.tags.has(key="initial_value", category="test_b__default_tag")
assert self.char1.test_b.default_tag == "initial_value"
assert not self.char1.tags.has(key="test_c", category="components")
assert not self.char1.tags.has(category="test_b__single_tag")
assert not self.char1.tags.has(category="test_b__multiple_tags")
def test_host_has_added_component_tags(self):
rct = RuntimeComponentTestC.create(self.char1)
@ -119,12 +128,16 @@ class TestComponents(EvenniaTest):
test_c = self.char1.components.get('test_c')
assert self.char1.tags.has(key="test_c", category="components")
assert self.char1.tags.has(key="added_value", category="test_c__added_tag")
assert test_c.added_tag == "added_value"
def test_host_has_added_default_component_tags(self):
self.char1.components.add_default("test_c")
test_c = self.char1.components.get("test_c")
assert self.char1.tags.has(key="test_c", category="components")
assert self.char1.tags.has(key="added_value", category="test_c__added_tag")
assert test_c.added_tag == "added_value"
def test_host_remove_component_tags(self):
rct = RuntimeComponentTestC.create(self.char1)
@ -134,6 +147,7 @@ class TestComponents(EvenniaTest):
handler.remove(rct)
assert not self.char1.tags.has(key="test_c", category="components")
assert not self.char1.tags.has(key="added_value", category="test_c__added_tag")
def test_host_remove_by_name_component_tags(self):
rct = RuntimeComponentTestC.create(self.char1)
@ -142,4 +156,33 @@ class TestComponents(EvenniaTest):
assert self.char1.tags.has(key="test_c", category="components")
handler.remove_by_name("test_c")
assert not self.char1.tags.has(key="test_c", category="components")
assert not self.char1.tags.has(key="test_c", category="components")
assert not self.char1.tags.has(key="added_value", category="test_c__added_tag")
def test_component_tags_only_hold_one_value_when_enforce_single(self):
test_b = self.char1.components.get('test_b')
test_b.single_tag = "first_value"
test_b.single_tag = "second value"
assert self.char1.tags.has(key="second value", category="test_b__single_tag")
assert test_b.single_tag == "second value"
assert not self.char1.tags.has(key="first_value", category="test_b__single_tag")
def test_component_tags_default_value_is_overridden_when_enforce_single(self):
test_b = self.char1.components.get('test_b')
test_b.default_single_tag = "second value"
assert self.char1.tags.has(key="second value", category="test_b__default_single_tag")
assert test_b.default_single_tag == "second value"
assert not self.char1.tags.has(key="first_value", category="test_b__default_single_tag")
def test_component_tags_support_multiple_values_by_default(self):
test_b = self.char1.components.get('test_b')
test_b.multiple_tags = "first value"
test_b.multiple_tags = "second value"
test_b.multiple_tags = "third value"
assert all(val in test_b.multiple_tags for val in ("first value", "second value", "third value"))
assert self.char1.tags.has(key="first value", category="test_b__multiple_tags")
assert self.char1.tags.has(key="second value", category="test_b__multiple_tags")
assert self.char1.tags.has(key="third value", category="test_b__multiple_tags")