diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index 159f253883..ca8800b3d8 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -2375,9 +2375,10 @@ class CmdExamine(ObjManipCommand): value (any): Attribute value. Returns: """ + if attr is None: + return "No such attribute was found." + value = utils.to_str(value) if crop: - if not isinstance(value, str): - value = utils.to_str(value) value = utils.crop(value) value = inlinefunc_raw(ansi_raw(value)) if category: @@ -2391,19 +2392,24 @@ class CmdExamine(ObjManipCommand): non-persistent data stored on object """ - if attrname: - db_attr = [(attrname, obj.attributes.get(attrname), None)] + if obj.attributes.has(attrname): + db_attr = [(attrname, obj.attributes.get(attrname), None)] + else: + db_attr = None try: ndb_attr = [(attrname, object.__getattribute__(obj.ndb, attrname))] except Exception: ndb_attr = None + if not (db_attr or ndb_attr): + return {"Attribue(s)": f"\n No Attribute '{attrname}' found on {obj.name}"} else: db_attr = [(attr.key, attr.value, attr.category) for attr in obj.db_attributes.all()] try: ndb_attr = obj.nattributes.all(return_tuples=True) except Exception: - ndb_attr = None + ndb_attr = (None, None, None) + output = {} if db_attr and db_attr[0]: output["Persistent attribute(s)"] = "\n " + "\n ".join( diff --git a/evennia/objects/manager.py b/evennia/objects/manager.py index 3e609991ff..a3db831149 100644 --- a/evennia/objects/manager.py +++ b/evennia/objects/manager.py @@ -154,7 +154,7 @@ class ObjectDBManager(TypedObjectManager): Args: attribute_name (str): Attribute key to search for. - attribute_value (str): Attribute value to search for. + attribute_value (any): Attribute value to search for. This can also be database objects. candidates (list, optional): Candidate objects to limit search to. typeclasses (list, optional): Python pats to restrict matches with. @@ -175,31 +175,16 @@ class ObjectDBManager(TypedObjectManager): ) type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q() - # This doesn't work if attribute_value is an object. Workaround below - - if isinstance(attribute_value, (str, int, float, bool)): - return self.filter( + results = ( + self + .filter( cand_restriction & type_restriction - & Q(db_attributes__db_key=attribute_name, db_attributes__db_value=attribute_value) - ).order_by("id") - else: - # We must loop for safety since the referenced lookup gives deepcopy error if attribute value is an object. - global _ATTR - if not _ATTR: - from evennia.typeclasses.models import Attribute as _ATTR - cands = list( - self.filter( - cand_restriction & type_restriction & Q(db_attributes__db_key=attribute_name) - ) - ) - results = [ - attr.objectdb_set.all() - for attr in _ATTR.objects.filter( - objectdb__in=cands, db_value=attribute_value - ).order_by("id") - ] - return chain(*results) + & Q(db_attributes__db_key=attribute_name) + & Q(db_attributes__db_value=attribute_value)) + .order_by("id") + ) + return results def get_objs_with_db_property(self, property_name, candidates=None): """ diff --git a/evennia/utils/picklefield.py b/evennia/utils/picklefield.py index a86f0099ca..e76825086c 100644 --- a/evennia/utils/picklefield.py +++ b/evennia/utils/picklefield.py @@ -31,7 +31,7 @@ Modified for Evennia by Griatch and the Evennia community. from ast import literal_eval from datetime import datetime -from copy import deepcopy +from copy import deepcopy, Error as CopyError from base64 import b64encode, b64decode from zlib import compress, decompress @@ -44,6 +44,7 @@ from django.forms.widgets import Textarea from pickle import loads, dumps from django.utils.encoding import force_str +from evennia.utils.dbserialize import pack_dbobj DEFAULT_PROTOCOL = 4 @@ -92,7 +93,16 @@ def dbsafe_encode(value, compress_object=False, pickle_protocol=DEFAULT_PROTOCOL # The reason this is important is because we do all of our lookups as # simple string matches, thus the character streams must be the same # for the lookups to work properly. See tests.py for more information. - value = dumps(deepcopy(value), protocol=pickle_protocol) + try: + value = deepcopy(value) + except CopyError: + # this can happen on a manager query where the search query string is a + # database model. + value = pack_dbobj(value) + + value = dumps(value, protocol=pickle_protocol) + + if compress_object: value = compress(value) value = b64encode(value).decode() # decode bytes to str