diff --git a/CHANGELOG.md b/CHANGELOG.md index f92cdab5ee..59c1ca5d91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,11 @@ - [Feature][pull3470]: New `exit_order` kwarg to `DefaultObject.get_display_exits` to easier customize the order in which standard exits are displayed in a room (chiizujin) +- [Fix][pull3495]: Fix rate in Trait contribs not updating after reload + (jaborsh) [pull3470]: https://github.com/evennia/evennia/pull/3470 +[pull3495]: https://github.com/evennia/evennia/pull/3495 ## Evennia 4.1.1 diff --git a/evennia/contrib/base_systems/components/dbfield.py b/evennia/contrib/base_systems/components/dbfield.py index 67f812b484..4b9c6d4fa8 100644 --- a/evennia/contrib/base_systems/components/dbfield.py +++ b/evennia/contrib/base_systems/components/dbfield.py @@ -6,8 +6,7 @@ This file contains the Descriptors used to set Fields in Components import typing -from evennia.typeclasses.attributes import (AttributeProperty, - NAttributeProperty) +from evennia.typeclasses.attributes import AttributeProperty, NAttributeProperty if typing.TYPE_CHECKING: from .components import Component diff --git a/evennia/contrib/rpg/traits/traits.py b/evennia/contrib/rpg/traits/traits.py index 911da85b02..59daf7d70f 100644 --- a/evennia/contrib/rpg/traits/traits.py +++ b/evennia/contrib/rpg/traits/traits.py @@ -571,16 +571,12 @@ class TraitHandler: # initialize any # Note that .trait_data retains the connection to the database, meaning every # update we do to .trait_data automatically syncs with database. - self.trait_data = obj.attributes.get( - db_attribute_key, category=db_attribute_category - ) + self.trait_data = obj.attributes.get(db_attribute_key, category=db_attribute_category) if self.trait_data is None: # no existing storage; initialize it, we then have to fetch it again # to retain the db connection obj.attributes.add(db_attribute_key, {}, category=db_attribute_category) - self.trait_data = obj.attributes.get( - db_attribute_key, category=db_attribute_category - ) + self.trait_data = obj.attributes.get(db_attribute_key, category=db_attribute_category) self._cache = {} def __len__(self): @@ -599,9 +595,7 @@ class TraitHandler: _SA(self, trait_key, value) else: trait_cls = self._get_trait_class(trait_key=trait_key) - valid_keys = list_to_string( - list(trait_cls.default_keys.keys()), endsep="or" - ) + valid_keys = list_to_string(list(trait_cls.default_keys.keys()), endsep="or") raise TraitException( f"Trait object not settable directly. Assign to {trait_key}.{valid_keys}." ) @@ -633,9 +627,7 @@ class TraitHandler: try: trait_type = self.trait_data[trait_key]["trait_type"] except KeyError: - raise TraitException( - f"Trait class for Trait {trait_key} could not be found." - ) + raise TraitException(f"Trait class for Trait {trait_key} could not be found.") try: return _TRAIT_CLASSES[trait_type] except KeyError: @@ -665,9 +657,7 @@ class TraitHandler: if trait is None and trait_key in self.trait_data: trait_type = self.trait_data[trait_key]["trait_type"] trait_cls = self._get_trait_class(trait_type) - trait = self._cache[trait_key] = trait_cls( - _GA(self, "trait_data")[trait_key] - ) + trait = self._cache[trait_key] = trait_cls(_GA(self, "trait_data")[trait_key]) return trait def add( @@ -763,9 +753,7 @@ class TraitProperty: """ - def __init__( - self, name=None, trait_type=DEFAULT_TRAIT_TYPE, force=True, **trait_properties - ): + def __init__(self, name=None, trait_type=DEFAULT_TRAIT_TYPE, force=True, **trait_properties): """ Initialize a TraitField. Mimics TraitHandler.add input except no `trait_key`. @@ -784,9 +772,7 @@ class TraitProperty: """ self._traithandler_name = trait_properties.pop("traithandler_name", "traits") - trait_properties.update( - {"name": name, "trait_type": trait_type, "force": force} - ) + trait_properties.update({"name": name, "trait_type": trait_type, "force": force}) self._trait_properties = trait_properties self._cache = {} @@ -826,9 +812,7 @@ class TraitProperty: if trait is None: # initialize the trait traithandler.add(self._trait_key, **self._trait_properties) - trait = traithandler.get( - self._trait_key - ) # caches it in the traithandler + trait = traithandler.get(self._trait_key) # caches it in the traithandler self._cache[instance] = trait return self._cache[instance] @@ -936,21 +920,13 @@ class Trait: if MandatoryTraitKey in unset_defaults.values(): # we have one or more unset keys that was mandatory - _raise_err( - [ - key - for key, value in unset_defaults.items() - if value == MandatoryTraitKey - ] - ) + _raise_err([key for key, value in unset_defaults.items() if value == MandatoryTraitKey]) # apply the default values trait_data.update(unset_defaults) if not cls.allow_extra_properties: # don't allow any extra properties - remove the extra data - for key in ( - key for key in inp.difference(req) if key not in ("name", "trait_type") - ): + for key in (key for key in inp.difference(req) if key not in ("name", "trait_type")): del trait_data[key] return trait_data @@ -1344,8 +1320,7 @@ class CounterTrait(Trait): """Check if we passed the ratetarget in either direction.""" ratetarget = self._data["ratetarget"] return ratetarget is not None and ( - (self.rate < 0 and value <= ratetarget) - or (self.rate > 0 and value >= ratetarget) + (self.rate < 0 and value <= ratetarget) or (self.rate > 0 and value >= ratetarget) ) def _stop_timer(self): @@ -1470,9 +1445,7 @@ class CounterTrait(Trait): @current.setter def current(self, value): if type(value) in (int, float): - self._data["current"] = self._check_and_start_timer( - self._enforce_boundaries(value) - ) + self._data["current"] = self._check_and_start_timer(self._enforce_boundaries(value)) @current.deleter def current(self): @@ -1695,17 +1668,13 @@ class GaugeTrait(CounterTrait): def current(self): """The `current` value of the gauge.""" return self._update_current( - self._enforce_boundaries( - self._data.get("current", (self.base + self.mod) * self.mult) - ) + self._enforce_boundaries(self._data.get("current", (self.base + self.mod) * self.mult)) ) @current.setter def current(self, value): if type(value) in (int, float): - self._data["current"] = self._check_and_start_timer( - self._enforce_boundaries(value) - ) + self._data["current"] = self._check_and_start_timer(self._enforce_boundaries(value)) @current.deleter def current(self): diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 150c95f5d1..dcf9b49f90 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -1588,6 +1588,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase): obj.get_display_name(looker, exit_order=('north', 'south')) -> "Exits: north, south, out, and portal." (markup not shown here) """ + def _sort_exit_names(names): exit_order = kwargs.get("exit_order") if not exit_order: @@ -1595,7 +1596,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase): sort_index = {name: key for key, name in enumerate(exit_order)} names = sorted(names) end_pos = len(names) + 1 - names.sort(key=lambda name:sort_index.get(name, end_pos)) + names.sort(key=lambda name: sort_index.get(name, end_pos)) return names exits = self.filter_visible(self.contents_get(content_type="exit"), looker, **kwargs) diff --git a/evennia/objects/tests.py b/evennia/objects/tests.py index 5c300865dc..df00189d50 100644 --- a/evennia/objects/tests.py +++ b/evennia/objects/tests.py @@ -3,8 +3,12 @@ from unittest import skip from evennia import DefaultCharacter, DefaultExit, DefaultObject, DefaultRoom from evennia.objects.models import ObjectDB from evennia.typeclasses.attributes import AttributeProperty -from evennia.typeclasses.tags import (AliasProperty, PermissionProperty, - TagCategoryProperty, TagProperty) +from evennia.typeclasses.tags import ( + AliasProperty, + PermissionProperty, + TagCategoryProperty, + TagProperty, +) from evennia.utils import create, search from evennia.utils.ansi import strip_ansi from evennia.utils.test_resources import BaseEvenniaTest, EvenniaTestCase @@ -102,7 +106,7 @@ class DefaultObjectTest(BaseEvenniaTest): self.assertEqual(exits, "Exits: out, south, portal, north, and aperture") # in specified order with unspecified exits alpbabetically on the end - exit_order = ('north', 'south', 'out') + exit_order = ("north", "south", "out") exits = strip_ansi(self.room1.get_display_exits(self.char1, exit_order=exit_order)) self.assertEqual(exits, "Exits: north, south, out, aperture, and portal") @@ -589,7 +593,6 @@ class TestProperties(EvenniaTestCase): # check cross-instance sharing self.assertEqual(obj2.attr5, [], "cross-instance sharing detected") - def test_mutable_defaults__autocreate_false(self): """ Test https://github.com/evennia/evennia/issues/3488, where a mutable default value (like a @@ -631,7 +634,6 @@ class TestProperties(EvenniaTestCase): # check cross-instance sharing self.assertEqual(obj2.attr7, []) - def test_mutable_defaults__autocreate_true(self): """ Test mutable defaults with autocreate=True. @@ -652,4 +654,3 @@ class TestProperties(EvenniaTestCase): obj1.delete() obj2.delete() - diff --git a/evennia/typeclasses/attributes.py b/evennia/typeclasses/attributes.py index bdef3bdc33..03929dac43 100644 --- a/evennia/typeclasses/attributes.py +++ b/evennia/typeclasses/attributes.py @@ -17,6 +17,7 @@ from copy import copy from django.conf import settings from django.db import models from django.utils.encoding import smart_str + from evennia.locks.lockhandler import LockHandler from evennia.utils.dbserialize import from_pickle, to_pickle from evennia.utils.idmapper.models import SharedMemoryModel