Merge branch 'evennia:main' into hex_colors

This commit is contained in:
Michael Faith 2024-04-07 14:27:50 -07:00 committed by GitHub
commit aa9ed83a26
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 55 additions and 31 deletions

View file

@ -5,8 +5,14 @@
- [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)
- [Fix][pull3491]: Fix traceback in EvEditor when searching with malformed regex (chiizujin)
- [Docs]: Doc fixes (Griatch, chiizujin)
[pull3470]: https://github.com/evennia/evennia/pull/3470
[pull3495]: https://github.com/evennia/evennia/pull/3495
[pull3491]: https://github.com/evennia/evennia/pull/3491
## Evennia 4.1.1

View file

@ -135,7 +135,7 @@ ABILITY_REVERSE_MAP = {
Above, the `Ability` class holds some basic properties of a character sheet.
The `ABILITY_REVERSE_MAP` is a convenient map to go the other way &mdas; if in some command we were to enter the string 'cha', we could use this mapping to directly convert your input to the correct `Ability`. For example:
The `ABILITY_REVERSE_MAP` is a convenient map to go the other way — if in some command we were to enter the string 'cha', we could use this mapping to directly convert your input to the correct `Ability`. For example:
ability = ABILITY_REVERSE_MAP.get(your_input)

View file

@ -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

View file

@ -268,7 +268,7 @@ class TestComponents(EvenniaTest):
def test_mutables_are_not_shared_when_autocreate(self):
self.char1.test_a.my_list.append(1)
self.assertNotEqual(id(self.char1.test_a.my_list), id(self.char2.test_a.my_list))
self.assertIsNot(self.char1.test_a.my_list, self.char2.test_a.my_list)
def test_replacing_class_component_slot_with_runtime_component(self):
self.char1.components.add_default("replacement_inherited_test_a")

View file

@ -661,7 +661,12 @@ class TraitHandler:
return trait
def add(
self, trait_key, name=None, trait_type=DEFAULT_TRAIT_TYPE, force=True, **trait_properties
self,
trait_key,
name=None,
trait_type=DEFAULT_TRAIT_TYPE,
force=True,
**trait_properties,
):
"""
Create a new Trait and add it to the handler.
@ -945,7 +950,12 @@ class Trait:
def __getattr__(self, key):
"""Access extra parameters as attributes."""
if key in ("default_keys", "data_default", "trait_type", "allow_extra_properties"):
if key in (
"default_keys",
"data_default",
"trait_type",
"allow_extra_properties",
):
return _GA(self, key)
try:
return self._data[key]
@ -1276,7 +1286,7 @@ class CounterTrait(Trait):
)
# set up rate
if trait_data["rate"] != 0:
trait_data["last_update"] = time()
trait_data["last_update"] = trait_data.get("last_update", time())
else:
trait_data["last_update"] = None
return trait_data
@ -1552,6 +1562,7 @@ class GaugeTrait(CounterTrait):
rate = self.rate
if rate != 0 and self._data["last_update"] is not None:
now = time()
tdiff = now - self._data["last_update"]
current += rate * tdiff
value = current

View file

@ -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)

View file

@ -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()

View file

@ -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

View file

@ -654,29 +654,34 @@ class CmdEditorGroup(CmdEditorBase):
if not self.linerange:
lstart = 0
lend = self.cline + 1
caller.msg(
_("Search-replaced {arg1} -> {arg2} for lines {l1}-{l2}.").format(
arg1=self.arg1, arg2=self.arg2, l1=lstart + 1, l2=lend
)
)
else:
caller.msg(
_("Search-replaced {arg1} -> {arg2} for {line}.").format(
arg1=self.arg1, arg2=self.arg2, line=self.lstr
)
)
sarea = "\n".join(linebuffer[lstart:lend])
regex = r"%s|^%s(?=\s)|(?<=\s)%s(?=\s)|^%s$|(?<=\s)%s$"
regarg = self.arg1.strip("'").strip('"')
if " " in regarg:
regarg = regarg.replace(" ", " +")
sarea = re.sub(
regex % (regarg, regarg, regarg, regarg, regarg),
self.arg2.strip("'").strip('"'),
sarea,
re.MULTILINE,
)
try:
sarea = re.sub(
regex % (regarg, regarg, regarg, regarg, regarg),
self.arg2.strip("'").strip('"'),
sarea,
re.MULTILINE,
)
except re.error as e:
caller.msg(_("Invalid regular expression."))
else:
if not self.linerange:
caller.msg(
_("Search-replaced {arg1} -> {arg2} for lines {l1}-{l2}.").format(
arg1=self.arg1, arg2=self.arg2, l1=lstart + 1, l2=lend
)
)
else:
caller.msg(
_("Search-replaced {arg1} -> {arg2} for {line}.").format(
arg1=self.arg1, arg2=self.arg2, line=self.lstr
)
)
buf = linebuffer[:lstart] + sarea.split("\n") + linebuffer[lend:]
editor.update_buffer(buf)
elif cmd == ":f":