diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a2cedc899..c6bba0033a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -95,6 +95,9 @@ Up requirements to Django 3.2+, Twisted 21+ - Add validation question to default account creation. - Add `LOCALECHO` client option to add server-side echo for clients that does not support this (useful for getting a complete log). +- Make `@lazy_property` decorator create read/delete-protected properties. This is + because it's used for handlers, and e.g. self.locks=[] is a common beginner mistake. + ### Evennia 0.9.5 (2019-2020) diff --git a/evennia/utils/utils.py b/evennia/utils/utils.py index 63ec8f4bf3..8c29fef433 100644 --- a/evennia/utils/utils.py +++ b/evennia/utils/utils.py @@ -2064,7 +2064,8 @@ class lazy_property: ``` Once initialized, the `AttributeHandler` will be available as a - property "attributes" on the object. + property "attributes" on the object. This is read-only since + this functionality is pretty much exclusively used by handlers. """ @@ -2085,6 +2086,24 @@ class lazy_property: obj.__dict__[self.__name__] = value return value + def __set__(self, obj, value): + """Protect against setting""" + handlername = self.__name__ + raise AttributeError( + _("{obj}.{handlername} is a handler and can't be set directly. " + "To add values, use `{obj}.{handlername}.add()` instead.").format( + obj=obj, handlername=handlername) + ) + + def __delete__(self, obj): + """Protect against deleting""" + handlername = self.__name__ + raise AttributeError( + _("{obj}.{handlername} is a handler and can't be deleted directly. " + "To remove values, use `{obj}.{handlername}.remove()` instead.").format( + obj=obj, handlername=handlername) + ) + _STRIP_ANSI = None _RE_CONTROL_CHAR = re.compile(