From 614a9ab0486ca36860ac9540f7d1e58e3beff0bd Mon Sep 17 00:00:00 2001 From: Tegiminis Date: Sun, 10 Jul 2022 02:32:05 -0700 Subject: [PATCH 1/6] makes attributeproperty "object-aware" --- evennia/typeclasses/attributes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evennia/typeclasses/attributes.py b/evennia/typeclasses/attributes.py index 7c5a537c19..1165c59ebf 100644 --- a/evennia/typeclasses/attributes.py +++ b/evennia/typeclasses/attributes.py @@ -224,7 +224,7 @@ class AttributeProperty: category=self._category, strattr=self._strattr, raise_exception=self._autocreate, - )) + ), instance) except AttributeError: if self._autocreate: # attribute didn't exist and autocreate is set @@ -274,7 +274,7 @@ class AttributeProperty: """ return value - def at_get(self, value): + def at_get(self, value, obj): """ The value returned from the Attribute is passed through this method. It can be used to react to the retrieval or modify the result in some way. From 6fca198a70dac42e6283332e0b295e6a4d3c9fe1 Mon Sep 17 00:00:00 2001 From: Tegiminis Date: Sun, 10 Jul 2022 03:20:16 -0700 Subject: [PATCH 2/6] makes attributeproperties object-aware, part 2 --- evennia/typeclasses/attributes.py | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/evennia/typeclasses/attributes.py b/evennia/typeclasses/attributes.py index 9917b351b8..2e801b5bce 100644 --- a/evennia/typeclasses/attributes.py +++ b/evennia/typeclasses/attributes.py @@ -218,7 +218,6 @@ class AttributeProperty: """ value = self._default try: -<<<<<<< HEAD value = self.at_get(getattr(instance, self.attrhandler_name).get( key=self._key, default=self._default, @@ -226,17 +225,6 @@ class AttributeProperty: strattr=self._strattr, raise_exception=self._autocreate, ), instance) -======= - value = self.at_get( - getattr(instance, self.attrhandler_name).get( - key=self._key, - default=self._default, - category=self._category, - strattr=self._strattr, - raise_exception=self._autocreate, - ) - ) ->>>>>>> ce3992f999a164881462d8f878d71a47a8f946cc except AttributeError: if self._autocreate: # attribute didn't exist and autocreate is set @@ -253,7 +241,7 @@ class AttributeProperty: ( getattr(instance, self.attrhandler_name).add( self._key, - self.at_set(value), + self.at_set(value, instance), category=self._category, lockstring=self._lockstring, strattr=self._strattr, @@ -269,7 +257,7 @@ class AttributeProperty: """ getattr(instance, self.attrhandler_name).remove(key=self._key, category=self._category) - def at_set(self, value): + def at_set(self, value, obj): """ The value to set is passed through the method. It can be used to customize/validate the input in a custom child class. From 248df1a19b3dd91fe3eee0fd571078f4d1de97d7 Mon Sep 17 00:00:00 2001 From: Tegiminis Date: Sun, 10 Jul 2022 03:25:56 -0700 Subject: [PATCH 3/6] docstring fix --- evennia/typeclasses/attributes.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/evennia/typeclasses/attributes.py b/evennia/typeclasses/attributes.py index 2e801b5bce..b8c68bb7ac 100644 --- a/evennia/typeclasses/attributes.py +++ b/evennia/typeclasses/attributes.py @@ -264,6 +264,7 @@ class AttributeProperty: Args: value (any): The value about to the stored in this Attribute. + obj (object): Object the attribute is attached to Returns: any: The value to store. @@ -281,6 +282,7 @@ class AttributeProperty: Args: value (any): Value returned from the Attribute. + obj (object): Object the attribute is attached to Returns: any: The value to return to the caller. From 296c966ae6b574294ad96691aca235dcfa3cc4f5 Mon Sep 17 00:00:00 2001 From: Tegiminis Date: Sun, 10 Jul 2022 03:48:54 -0700 Subject: [PATCH 4/6] remove unused argument --- evennia/typeclasses/attributes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evennia/typeclasses/attributes.py b/evennia/typeclasses/attributes.py index b8c68bb7ac..f714753b99 100644 --- a/evennia/typeclasses/attributes.py +++ b/evennia/typeclasses/attributes.py @@ -211,7 +211,7 @@ class AttributeProperty: """ self._key = name - def __get__(self, instance, owner): + def __get__(self, instance): """ Called when the attrkey is retrieved from the instance. From 38606f4edbbe117332c1521a0520d39ca0b4e04c Mon Sep 17 00:00:00 2001 From: Tegiminis Date: Sun, 10 Jul 2022 03:55:52 -0700 Subject: [PATCH 5/6] Revert "remove unused argument" This reverts commit 296c966ae6b574294ad96691aca235dcfa3cc4f5. --- evennia/typeclasses/attributes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evennia/typeclasses/attributes.py b/evennia/typeclasses/attributes.py index f714753b99..b8c68bb7ac 100644 --- a/evennia/typeclasses/attributes.py +++ b/evennia/typeclasses/attributes.py @@ -211,7 +211,7 @@ class AttributeProperty: """ self._key = name - def __get__(self, instance): + def __get__(self, instance, owner): """ Called when the attrkey is retrieved from the instance. From 8a9ccb4bbe90df975927c887524ba3d0ce12d7d7 Mon Sep 17 00:00:00 2001 From: Tegiminis Date: Mon, 11 Jul 2022 02:16:25 -0700 Subject: [PATCH 6/6] unit tests for customized attributeproperty getter/setter --- evennia/objects/tests.py | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/evennia/objects/tests.py b/evennia/objects/tests.py index a718d9b01b..b447eed09f 100644 --- a/evennia/objects/tests.py +++ b/evennia/objects/tests.py @@ -239,23 +239,32 @@ class SubAttributeProperty(AttributeProperty): class SubTagProperty(TagProperty): pass +class CustomizedProperty(AttributeProperty): + def at_set(self, value, obj): + obj.settest = value + return value + + def at_get(self, value, obj): + return value + obj.awaretest class TestObjectPropertiesClass(DefaultObject): attr1 = AttributeProperty(default="attr1") attr2 = AttributeProperty(default="attr2", category="attrcategory") attr3 = AttributeProperty(default="attr3", autocreate=False) attr4 = SubAttributeProperty(default="attr4") + cusattr = CustomizedProperty(default=5) tag1 = TagProperty() tag2 = TagProperty(category="tagcategory") tag3 = SubTagProperty() testalias = AliasProperty() testperm = PermissionProperty() + awaretest = 5 + settest = 0 @property def base_property(self): self.property_initialized = True - class TestProperties(EvenniaTestCase): """ Test Properties. @@ -263,7 +272,7 @@ class TestProperties(EvenniaTestCase): """ def setUp(self): - self.obj = create.create_object(TestObjectPropertiesClass, key="testobj") + self.obj: TestObjectPropertiesClass = create.create_object(TestObjectPropertiesClass, key="testobj") def tearDown(self): self.obj.delete() @@ -305,3 +314,30 @@ class TestProperties(EvenniaTestCase): # Verify that regular properties do not get fetched in init_evennia_properties, # only Attribute or TagProperties. self.assertFalse(hasattr(obj, "property_initialized")) + + def test_object_awareness(self): + '''Test the "object-awareness" of customized AttributeProperty getter/setters''' + obj = self.obj + + # attribute properties receive on obj ref in the getter/setter that can customize return + self.assertEqual(obj.cusattr, 10) + self.assertEqual(obj.settest, 5) + obj.awaretest = 10 + self.assertEqual(obj.cusattr, 15) + obj.cusattr = 10 + self.assertEqual(obj.cusattr, 20) + self.assertEqual(obj.settest, 10) + + # attribute value mutates if you do += or similar (combined get-set) + obj.cusattr += 10 + self.assertEqual(obj.attributes.get("cusattr"), 30) + self.assertEqual(obj.settest, 30) + self.assertEqual(obj.cusattr, 40) + obj.awaretest = 0 + obj.cusattr += 20 + self.assertEqual(obj.attributes.get("cusattr"), 50) + self.assertEqual(obj.settest, 50) + self.assertEqual(obj.cusattr, 50) + del obj.cusattr + self.assertEqual(obj.cusattr, 5) + self.assertEqual(obj.settest, 5)