From a0133e42861a2cdfa53df800384dbf257404d5c2 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 25 Feb 2023 20:23:29 +0100 Subject: [PATCH] Explain in docs why AttributePropety.at_get/set are not called if accessing attribute from AttributeHandler. Resolve #3034. --- docs/source/Components/Attributes.md | 9 +++++++++ evennia/typeclasses/attributes.py | 14 +++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/source/Components/Attributes.md b/docs/source/Components/Attributes.md index 41a4b26b66..e971b18b4b 100644 --- a/docs/source/Components/Attributes.md +++ b/docs/source/Components/Attributes.md @@ -192,6 +192,15 @@ You can e.g. `del char.strength` to set the value back to the default (the value See the [AttributeProperty API](evennia.typeclasses.attributes.AttributeProperty) for more details on how to create it with special options, like giving access-restrictions. +```{warning} +While the `AttributeProperty` uses the `AttributeHandler` (`.attributes`) under the hood, the reverse is _not_ true. The `AttributeProperty` has helper methods, like `at_get` and `at_set`. These will _only_ be called if you access the Attribute using the property. + +That is, if you do `obj.yourattribute = 1`, the `AttributeProperty.at_set` will be called. But while doing `obj.db.yourattribute = 1`, will lead to the same Attribute being saved, this is 'bypassing' the `AttributeProperty` and using the `AttributeHandler` directly. So in this case the `AttributeProperty.at_set` will _not_ be called. If you added some special functionality in `at_get` this may be confusing. + +To avoid confusion, you should aim to be consistent in how you access your Attributes - if you use a `AttributeProperty` to define it, use that also to access and modify the Attribute later. +``` + + ### Properties of Attributes An `Attribute` object is stored in the database. It has the following properties: diff --git a/evennia/typeclasses/attributes.py b/evennia/typeclasses/attributes.py index 2fc7a5533e..9f3dc8a124 100644 --- a/evennia/typeclasses/attributes.py +++ b/evennia/typeclasses/attributes.py @@ -162,7 +162,9 @@ class AttributeProperty: Attribute property descriptor. Allows for specifying Attributes as Django-like 'fields' on the class level. Note that while one can set a lock on the Attribute, there is no way to *check* said lock when accessing via the property - use - the full AttributeHandler if you need to do access checks. + the full `AttributeHandler` if you need to do access checks. Note however that if you use the + full `AttributeHandler` to access this Attribute, the `at_get/at_set` methods on this class will + _not_ fire (because you are bypassing the `AttributeProperty` entirely in that case). Example: :: @@ -288,6 +290,11 @@ class AttributeProperty: Raises: AttributeError: If the value is invalid to store. + Notes: + This is will only fire if you actually set the Attribute via this `AttributeProperty`. + That is, if you instead set it via the `AttributeHandler` (or via `.db`), you are + bypassing this `AttributeProperty` entirely and this method is never reached. + """ return value @@ -303,6 +310,11 @@ class AttributeProperty: Returns: any: The value to return to the caller. + Notes: + This is will only fire if you actually get the Attribute via this `AttributeProperty`. + That is, if you instead get it via the `AttributeHandler` (or via `.db`), you are + bypassing this `AttributeProperty` entirely and this method is never reached. + """ return value