Example #1
0
 def get_objs_with_db_property_value(self,
                                     property_name,
                                     property_value,
                                     candidates=None,
                                     typeclasses=None):
     """
     Returns all objects having a given db field property.
     candidates - list of objects to search
     typeclasses - list of typeclass-path strings to restrict matches with
     """
     if isinstance(property_value, basestring):
         property_value = to_unicode(property_value)
     if isinstance(property_name, basestring):
         if not property_name.startswith('db_'):
             property_name = "db_%s" % property_name
     if hasattr(property_value, 'dbobj'):
         property_value = property_value.dbobj
     querykwargs = {property_name: property_value}
     cand_restriction = candidates != None and Q(
         pk__in=[_GA(obj, "id")
                 for obj in make_iter(candidates) if obj]) or Q()
     type_restriction = typeclasses and Q(
         db_typeclass_path__in=make_iter(typeclasses)) or Q()
     try:
         return list(
             self.filter(cand_restriction & type_restriction
                         & Q(**querykwargs)))
     except exceptions.FieldError:
         return []
     except ValueError:
         from src.utils import logger
         logger.log_errmsg(
             "The property '%s' does not support search criteria of the type %s."
             % (property_name, type(property_value)))
         return []
Example #2
0
    def get_objs_with_attr_value(self, attribute_name, attribute_value, candidates=None, typeclasses=None):
        """
        Returns all objects having the valid attrname set to the given value.

        candidates - list of candidate objects to search
        typeclasses - list of typeclass-path strings to restrict matches with

        This uses the Attribute's PickledField to transparently search the database by matching
        the internal representation. This is reasonably effective but since Attribute values
        cannot be indexed, searching by Attribute key is to be preferred whenever possible.
        """
        cand_restriction = (
            candidates != None and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q()
        )
        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, (basestring, int, float, bool, long)):
            return self.filter(
                cand_restriction
                & type_restriction
                & Q(db_attributes__db_key=attribute_name, db_attributes__db_value=attribute_value)
            )
        else:
            # We have to loop for safety since the referenced lookup gives deepcopy error if attribute value is an object.
            global _ATTR
            if not _ATTR:
                from src.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)
            ]
            return chain(*results)
Example #3
0
    def get_objs_with_db_property_value(self, property_name, property_value, candidates=None, typeclasses=None):
        """
        Returns all objects having a given db field property.
        candidates - list of objects to search
        typeclasses - list of typeclass-path strings to restrict matches with
        """
        if isinstance(property_value, basestring):
            property_value = to_unicode(property_value)
        if isinstance(property_name, basestring):
            if not property_name.startswith("db_"):
                property_name = "db_%s" % property_name
        if hasattr(property_value, "dbobj"):
            property_value = property_value.dbobj
        querykwargs = {property_name: property_value}
        cand_restriction = (
            candidates != None and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q()
        )
        type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q()
        try:
            return list(self.filter(cand_restriction & type_restriction & Q(**querykwargs)))
        except exceptions.FieldError:
            return []
        except ValueError:
            from src.utils import logger

            logger.log_errmsg(
                "The property '%s' does not support search criteria of the type %s."
                % (property_name, type(property_value))
            )
            return []
Example #4
0
 def get_object_with_player(self, ostring, exact=True, candidates=None):
     """
     Search for an object based on its player's name or dbref.
     This search
     is sometimes initiated by appending a * to the beginning of
     the search criterion (e.g. in local_and_global_search).
     search_string:  (string) The name or dbref to search for.
     """
     ostring = to_unicode(ostring).lstrip("*")
     # simplest case - search by dbref
     dbref = self.dbref(ostring)
     if dbref:
         return dbref
     # not a dbref. Search by name.
     cand_restriction = (
         candidates != None and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q()
     )
     if exact:
         return self.filter(cand_restriction & Q(db_player__username__iexact=ostring))
     else:  # fuzzy matching
         ply_cands = self.filter(cand_restriction & Q(playerdb__username__istartswith=ostring)).values_list(
             "db_key", flat=True
         )
         if candidates:
             index_matches = string_partial_matching(ply_cands, ostring, ret_index=True)
             return [obj for ind, obj in enumerate(make_iter(candidates)) if ind in index_matches]
         else:
             return string_partial_matching(ply_cands, ostring, ret_index=False)
Example #5
0
 def __init__(self, senders=None, receivers=None, channels=None, message="", header="", type="", lockstring="", hide_from=None):
     self.senders = senders and make_iter(senders) or []
     self.receivers = receivers and make_iter(receivers) or []
     self.channels = channels and make_iter(channels) or []
     self.type = type
     self.header = header
     self.message = message
     self.lock_storage = lockstring
     self.hide_from = hide_from and make_iter(hide_from) or []
     self.date_sent = datetime.now()
Example #6
0
 def __init__(self, senders=None, receivers=None, channels=None, message="", header="", type="", lockstring="", hide_from=None):
     self.senders = senders and make_iter(senders) or []
     self.receivers = receivers and make_iter(receivers) or []
     self.channels = channels and make_iter(channels) or []
     self.type = type
     self.header = header
     self.message = message
     self.lock_storage = lockstring
     self.locks = LazyLoadHandler(self, "locks", LockHandler)
     self.hide_from = hide_from and make_iter(hide_from) or []
     self.date_sent = datetime.now()
Example #7
0
    def func(self):
        "Implement function"

        caller = self.caller

        # all channels we have available to listen to
        channels = [chan for chan in ChannelDB.objects.get_all_channels() if chan.access(caller, "listen")]
        # print channels
        if not channels:
            self.msg("No channels available.")
            return
        # all channel we are already subscribed to
        subs = ChannelDB.objects.get_subscriptions(caller)
        # print subs

        if self.cmdstring == "comlist":
            # just display the subscribed channels with no extra info
            comtable = prettytable.PrettyTable(["{wchannel", "{wmy aliases", "{wdescription"])
            for chan in subs:
                clower = chan.key.lower()
                nicks = caller.nicks.get(category="channel")
                comtable.add_row(
                    [
                        "%s%s" % (chan.key, chan.aliases.all() and "(%s)" % ",".join(chan.aliases.all()) or ""),
                        "%s".join(nick for nick in make_iter(nicks) if nick and nick.lower() == clower),
                        chan.db.desc,
                    ]
                )
            caller.msg(
                "\n{wChannel subscriptions{n (use {w@channels{n to list all, {waddcom{n/{wdelcom{n to sub/unsub):{n\n%s"
                % comtable
            )
        else:
            # full listing (of channels caller is able to listen to)
            comtable = prettytable.PrettyTable(["{wsub", "{wchannel", "{wmy aliases", "{wlocks", "{wdescription"])
            for chan in channels:
                clower = chan.key.lower()
                nicks = caller.nicks.get(category="channel")
                nicks = nicks or []
                comtable.add_row(
                    [
                        chan in subs and "{gYes{n" or "{rNo{n",
                        "%s%s" % (chan.key, chan.aliases.all() and "(%s)" % ",".join(chan.aliases.all()) or ""),
                        "%s".join(nick for nick in make_iter(nicks) if nick.lower() == clower),
                        str(chan.locks),
                        chan.db.desc,
                    ]
                )
            caller.msg(
                "\n{wAvailable channels{n (use {wcomlist{n,{waddcom{n and {wdelcom{n to manage subscriptions):\n%s"
                % comtable
            )
Example #8
0
 def get_objs_with_key_or_alias(self, ostring, exact=True, candidates=None, typeclasses=None):
     """
     Returns objects based on key or alias match. Will also do fuzzy
     matching based on the utils.string_partial_matching function.
     candidates - list of candidate objects to restrict on
     typeclasses - list of typeclass path strings to restrict on
     """
     if not isinstance(ostring, basestring):
         if hasattr(ostring, "key"):
             ostring = ostring.key
         else:
             return []
     if is_iter(candidates) and not len(candidates):
         # if candidates is an empty iterable there can be no matches
         # Exit early.
         return []
     # build query objects
     candidates_id = [_GA(obj, "id") for obj in make_iter(candidates) if obj]
     cand_restriction = candidates != None and Q(pk__in=make_iter(candidates_id)) or Q()
     type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q()
     if exact:
         # exact match - do direct search
         return self.filter(
             cand_restriction
             & type_restriction
             & (
                 Q(db_key__iexact=ostring)
                 | Q(db_tags__db_key__iexact=ostring) & Q(db_tags__db_category__iexact="objectalias")
             )
         ).distinct()
     elif candidates:
         # fuzzy with candidates
         key_candidates = self.filter(cand_restriction & type_restriction)
     else:
         # fuzzy without supplied candidates - we select our own candidates
         key_candidates = self.filter(
             type_restriction & (Q(db_key__istartswith=ostring) | Q(db_tags__db_key__istartswith=ostring))
         ).distinct()
         candidates_id = [_GA(obj, "id") for obj in key_candidates]
     # fuzzy matching
     key_strings = key_candidates.values_list("db_key", flat=True)
     index_matches = string_partial_matching(key_strings, ostring, ret_index=True)
     if index_matches:
         return [obj for ind, obj in enumerate(key_candidates) if ind in index_matches]
     else:
         alias_candidates = self.filter(id__in=candidates_id, db_tags__db_category__iexact="objectalias")
         # print alias_candidates
         alias_strings = alias_candidates.values_list("db_key", flat=True)
         index_matches = string_partial_matching(alias_strings, ostring, ret_index=True)
         if index_matches:
             return [alias.db_obj for ind, alias in enumerate(alias_candidates) if ind in index_matches]
         return []
    def dataReceived(self, string):
        """
        Method called when data is coming in over
        the websocket connection.

        Type of data is identified by a 3-character
        prefix.
            OOB - This is an Out-of-band instruction. If so,
                  the remaining string should be a json-packed
                  string on the form {oobfuncname: [args, ], ...}
            any other prefix (or lack of prefix) is considered
                  plain text data, to be treated like a game
                  input command.
        """
        if string[:3] == "OOB":
            string = string[3:]
            try:
                oobdata = json.loads(string)
                for (key, args) in oobdata.items():
                    #print "oob data in:", (key, args)
                    self.data_in(text=None, oob=(key, make_iter(args)))
            except Exception:
                log_trace("Websocket malformed OOB request: %s" % string)
        else:
            # plain text input
            self.data_in(text=string)
Example #10
0
    def dataReceived(self, string):
        """
        Method called when data is coming in over
        the websocket connection.

        Type of data is identified by a 3-character
        prefix.
            OOB - This is an Out-of-band instruction. If so,
                  the remaining string should be a json-packed
                  string on the form {oobfuncname: [args, ], ...}
            any other prefix (or lack of prefix) is considered
                  plain text data, to be treated like a game
                  input command.
        """
        if string[:3] == "OOB":
            string = string[3:]
            try:
                oobdata = json.loads(string)
                for (key, args) in oobdata.items():
                    #print "oob data in:", (key, args)
                    self.data_in(text=None, oob=(key, make_iter(args)))
            except Exception:
                log_trace("Websocket malformed OOB request: %s" % string)
        else:
            # plain text input
            self.data_in(text=string)
Example #11
0
 def cmdset_storage_set(self, value):
     """
     Setter. Allows for self.name = value. Stores as a comma-separated
     string.
     """
     _SA(self, "db_cmdset_storage", ",".join(str(val).strip() for val in make_iter(value)))
     _GA(self, "save")()
Example #12
0
 def remove_receiver(self, obj):
     "Remove a sender or a list of senders"
     for o in make_iter(obj):
         try:
             self.senders.remove(o)
         except ValueError:
             pass  # nothing to remove
Example #13
0
 def cmdset_storage_set(self, value):
     """
     Setter. Allows for self.name = value. Stores as a comma-separated
     string.
     """
     _SA(self, "db_cmdset_storage", ",".join(str(val).strip() for val in make_iter(value)))
     _GA(self, "save")()
Example #14
0
    def create_tag(self,
                   key=None,
                   category=None,
                   data=None,
                   model="objects.objectdb",
                   tagtype=None):
        """
        Create a tag. This makes sure the create case-insensitive tags.
        Note that if the exact same tag configuration (key+category+model+tagtype)
        exists, it will be re-used. A data keyword will overwrite existing
        data on a tag (it is not part of what makes the tag unique).

        """
        data = str(data) if data is not None else None

        tag = self.get_tag(key=key,
                           category=category,
                           model=model,
                           tagtype=tagtype)
        if tag and data is not None:
            tag.db_data = data
            tag.save()
        elif not tag:
            tag = self.create(
                db_key=key.lower().strip() if key is not None else None,
                db_category=category.lower().strip()
                if category and key is not None else None,
                db_data=str(data) if data is not None else None,
                db_model=model,
                db_tagtype=tagtype)
            tag.save()
        return make_iter(tag)[0]
Example #15
0
 def get_objs_with_key_or_alias(self, ostring, exact=True, candidates=None):
     """
     Returns objects based on key or alias match. Will also do fuzzy matching based on
     the utils.string_partial_matching function.
     """
     # build query objects
     candidates_id = [_GA(obj, "id") for obj in make_iter(candidates) if obj]
     cand_restriction = candidates and Q(pk__in=candidates_id) or Q()
     if exact:
         # exact match - do direct search
         return self.filter(cand_restriction & (Q(db_key__iexact=ostring) | Q(alias__db_key__iexact=ostring))).distinct()
     elif candidates:
         # fuzzy with candidates
         key_candidates = self.filter(cand_restriction)
     else:
         # fuzzy without supplied candidates - we select our own candidates
         key_candidates = self.filter(Q(db_key__istartswith=ostring) | Q(alias__db_key__istartswith=ostring)).distinct()
         candidates_id = [_GA(obj, "id") for obj in key_candidates]
     # fuzzy matching
     key_strings = key_candidates.values_list("db_key", flat=True)
     index_matches = string_partial_matching(key_strings, ostring, ret_index=True)
     if index_matches:
         return [obj for ind, obj in enumerate(key_candidates) if ind in index_matches]
     else:
         alias_candidates = self.model.alias_set.related.model.objects.filter(db_obj__pk__in=candidates_id)
         alias_strings = alias_candidates.values_list("db_key", flat=True)
         index_matches = string_partial_matching(alias_strings, ostring, ret_index=True)
         if index_matches:
             return [alias.db_obj for ind, alias in enumerate(alias_candidates) if ind in index_matches]
         return []
Example #16
0
 def remove_receiver(self, obj):
     "Remove a sender or a list of senders"
     for o in make_iter(obj):
         try:
             self.senders.remove(o)
         except ValueError:
             pass  # nothing to remove
Example #17
0
 def create_tag(self, key=None, category=None, data=None, tagtype=None):
     """
     Create a new Tag of the base type associated with this typedobject.
     This makes sure to create case-insensitive tags. If the exact same
     tag configuration (key+category+tagtype) exists on the model, a
     new tag will not be created, but an old one returned.  A data
     keyword is not part of the uniqueness of the tag and setting one
     on an existing tag will overwrite the old data field.
     """
     data = str(data) if data is not None else None
     # try to get old tag
     tag = self.get_tag(key=key, category=category, tagtype=tagtype)
     if tag and data is not None:
         # overload data on tag
         tag.db_data = data
         tag.save()
     elif not tag:
         # create a new tag
         global _Tag
         if not _Tag:
             from src.typeclasses.models import Tag as _Tag
         tag = _Tag.objects.create(
             db_key=key.strip().lower() if key is not None else None,
             db_category=category.strip().lower() if category and key is not None else None,
             db_data=data,
             db_tagtype=tagtype.strip().lower() if tagtype is not None else None)
         tag.save()
     return make_iter(tag)[0]
Example #18
0
 def get_objs_with_key_and_typeclass(self, oname, otypeclass_path, candidates=None):
     """
     Returns objects based on simultaneous key and typeclass match.
     """
     cand_restriction = (
         candidates != None and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q()
     )
     return self.filter(cand_restriction & Q(db_key__iexact=oname, db_typeclass_path__exact=otypeclass_path))
Example #19
0
 def func(self, *args, **kwargs):
     "decorator. Returns result or None."
     self.__doc__ = method.__doc__
     matches = method(self, *args, **kwargs)
     dbobj = matches and make_iter(matches)[0] or None
     if dbobj:
         return (hasattr(dbobj, "typeclass") and dbobj.typeclass) or dbobj
     return None
Example #20
0
    def no_look_target(self):
        "Hook method for default look without a specified target"
        # caller is always a player at this point.
        player = self.player
        sessid = self.sessid
        # get all our characters and sessions
        characters = player.db._playable_characters
        if None in characters:
            # clean up list if character object was deleted in between
            characters = [character for character in characters if character]
            player.db._playable_characters = characters

        sessions = player.get_all_sessions()
        is_su = player.is_superuser

        # text shown when looking in the ooc area
        string = "Account {g%s{n (you are Out-of-Character)" % (player.key)

        nsess = len(sessions)
        string += nsess == 1 and "\n\n{wConnected session:{n" or "\n\n{wConnected sessions (%i):{n" % nsess
        for isess, sess in enumerate(sessions):
            csessid = sess.sessid
            addr = "%s (%s)" % (sess.protocol_key, isinstance(sess.address, tuple) and str(sess.address[0]) or str(sess.address))
            string += "\n %s %s" % (sessid == csessid and "{w%s{n" % (isess + 1) or (isess + 1), addr)
        string += "\n\n {whelp{n - more commands"
        string += "\n {wooc <Text>{n - talk on public channel"

        if is_su or len(characters) < MAX_NR_CHARACTERS:
            if not characters:
                string += "\n\n You don't have any characters yet. See {whelp @charcreate{n for creating one."
            else:
                string += "\n {w@charcreate <name> [=description]{n - create new character"

        if characters:
            string_s_ending = len(characters) > 1 and "s" or ""
            string += "\n {w@ic <character>{n - enter the game ({w@ooc{n to get back here)"
            if is_su:
                string += "\n\nAvailable character%s (%i/unlimited):" % (string_s_ending, len(characters))
            else:
                string += "\n\nAvailable character%s%s:"  % (string_s_ending,
                         MAX_NR_CHARACTERS > 1 and " (%i/%i)" % (len(characters), MAX_NR_CHARACTERS) or "")

            for char in characters:
                csessid = char.sessid.get()
                if csessid:
                    # character is already puppeted
                    sessi = player.get_session(csessid)
                    for sess in utils.make_iter(sessi):
                        sid = sess in sessions and sessions.index(sess) + 1
                        if sess and sid:
                            string += "\n - {G%s{n [%s] (played by you in session %i)" % (char.key, ", ".join(char.permissions.all()), sid)
                        else:
                            string += "\n - {R%s{n [%s] (played by someone else)" % (char.key, ", ".join(char.permissions.all()))
                else:
                    # character is "free to puppet"
                    string += "\n - %s [%s]" % (char.key, ", ".join(char.permissions.all()))
        string = ("-" * 68) + "\n" + string + "\n" + ("-" * 68)
        self.msg(string)
Example #21
0
def create_message(senderobj,
                   message,
                   channels=None,
                   receivers=None,
                   locks=None,
                   header=None):
    """
    Create a new communication message. Msgs are used for all
    player-to-player communication, both between individual players
    and over channels.
    senderobj - the player sending the message. This must be the actual object.
    message - text with the message. Eventual headers, titles etc
              should all be included in this text string. Formatting
              will be retained.
    channels - a channel or a list of channels to send to. The channels
             may be actual channel objects or their unique key strings.
    receivers - a player to send to, or a list of them. May be Player objects
               or playernames.
    locks - lock definition string
    header - mime-type or other optional information for the message

    The Comm system is created very open-ended, so it's fully possible
    to let a message both go to several channels and to several receivers
    at the same time, it's up to the command definitions to limit this as
    desired.
    """
    global _Msg
    if not _Msg:
        from src.comms.models import Msg as _Msg
    if not message:
        # we don't allow empty messages.
        return
    new_message = _Msg(db_message=message)
    new_message.save()
    for sender in make_iter(senderobj):
        new_message.senders = sender
    new_message.header = header
    for channel in make_iter(channels):
        new_message.channels = channel
    for receiver in make_iter(receivers):
        new_message.receivers = receiver
    if locks:
        new_message.locks.add(locks)
    new_message.save()
    return new_message
Example #22
0
    def get_contents(self, location, excludeobj=None):
        """
        Get all objects that has a location
        set to this one.

        excludeobj - one or more object keys to exclude from the match
        """
        exclude_restriction = Q(pk__in=[_GA(obj, "id") for obj in make_iter(excludeobj)]) if excludeobj else Q()
        return self.filter(db_location=location).exclude(exclude_restriction)
Example #23
0
    def msg(self, msgobj, header=None, senders=None, sender_strings=None,
            persistent=False, online=False, emit=False, external=False):
        """
        Send the given message to all players connected to channel. Note that
        no permission-checking is done here; it is assumed to have been
        done before calling this method. The optional keywords are not used if
        persistent is False.

        msgobj - a Msg/TempMsg instance or a message string. If one of the
                 former, the remaining keywords will be ignored. If a string,
                 this will either be sent as-is (if persistent=False) or it
                 will be used together with header and senders keywords to
                 create a Msg instance on the fly.
        senders - an object, player or a list of objects or players.
                 Optional if persistent=False.
        sender_strings - Name strings of senders. Used for external
                connections where the sender is not a player or object. When
                this is defined, external will be assumed.
        external - Treat this message agnostic of its sender.
        persistent (default False) - ignored if msgobj is a Msg or TempMsg.
                If True, a Msg will be created, using header and senders
                keywords. If False, other keywords will be ignored.
        online (bool) - If this is set true, only messages people who are
                online. Otherwise, messages all players connected. This can
                make things faster, but may not trigger listeners on players
                that are offline.
        emit (bool) - Signals to the message formatter that this message is
                not to be directly associated with a name.
        """
        if senders:
            senders = make_iter(senders)
        else:
            senders = []
        if isinstance(msgobj, basestring):
            # given msgobj is a string
            msg = msgobj
            if persistent and self.db.keep_log:
                msgobj = Msg()
                msgobj.save()
            else:
                # Use TempMsg, so this message is not stored.
                msgobj = TempMsg()
            msgobj.header = header
            msgobj.message = msg
            msgobj.channels = [self.dbobj]  # add this channel

        if not msgobj.senders:
            msgobj.senders = senders
        msgobj = self.pre_send_message(msgobj)
        if not msgobj:
            return False
        msgobj = self.message_transform(msgobj, emit=emit,
                                        sender_strings=sender_strings,
                                        external=external)
        self.distribute_message(msgobj, online=online)
        self.post_send_message(msgobj)
        return True
Example #24
0
    def func(self):
        "Create the nickname"

        caller = self.caller
        switches = self.switches
        nicks = caller.nicks.get(return_obj=True)

        if 'list' in switches:
            table = prettytable.PrettyTable(
                ["{wNickType", "{wNickname", "{wTranslates-to"])
            for nick in utils.make_iter(nicks):
                table.add_row(
                    [nick.db_category, nick.db_key, nick.db_strvalue])
            string = "{wDefined Nicks:{n\n%s" % table
            caller.msg(string)
            return
        if 'clearall' in switches:
            caller.nicks.clear()
            caller.msg("Cleared all aliases.")
            return
        if not self.args or not self.lhs:
            caller.msg("Usage: nick[/switches] nickname = [realname]")
            return
        nick = self.lhs
        real = self.rhs

        if real == nick:
            caller.msg(
                "No point in setting nick same as the string to replace...")
            return

        # check so we have a suitable nick type
        if not any(True for switch in switches
                   if switch in ("object", "player", "inputline")):
            switches = ["inputline"]
        string = ""
        for switch in switches:
            oldnick = caller.nicks.get(key=nick, category=switch)
            #oldnick = Nick.objects.filter(db_obj=caller.dbobj, db_nick__iexact=nick, db_type__iexact=switch)
            if not real:
                # removal of nick
                if oldnick:
                    # clear the alias
                    string += "\nNick '%s' (= '%s') was cleared." % (nick,
                                                                     oldnick)
                    caller.nicks.delete(nick, category=switch)
                else:
                    string += "\nNo nick '%s' found, so it could not be removed." % nick
            else:
                # creating new nick
                if oldnick:
                    string += "\nNick %s changed from '%s' to '%s'." % (
                        nick, oldnick, real)
                else:
                    string += "\nNick set: '%s' = '%s'." % (nick, real)
                caller.nicks.add(nick, real, category=switch)
        caller.msg(string)
Example #25
0
 def delete_script(self, dbref):
     """
     This stops and deletes a specific script directly
     from the script database. This might be
     needed for global scripts not tied to
     a specific game object.
     """
     scripts = self.get_id(dbref)
     for script in make_iter(scripts):
         script.stop()
Example #26
0
 def delete_script(self, dbref):
     """
     This stops and deletes a specific script directly
     from the script database. This might be
     needed for global scripts not tied to
     a specific game object.
     """
     scripts = self.get_id(dbref)
     for script in make_iter(scripts):
         script.stop()
Example #27
0
 def get_objs_with_attr(self, attribute_name, candidates=None):
     """
     Returns all objects having the given attribute_name defined at all.
     Location should be a valid location object.
     """
     cand_restriction = (
         candidates != None
         and Q(db_attributes__db_obj__pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj])
         or Q()
     )
     return list(self.filter(cand_restriction & Q(db_attributes__db_key=attribute_name)))
Example #28
0
    def get_contents(self, location, excludeobj=None):
        """
        Get all objects that has a location
        set to this one.

        excludeobj - one or more object keys to exclude from the match
        """
        exclude_restriction = Q(
            pk__in=[_GA(obj, "id")
                    for obj in make_iter(excludeobj)]) if excludeobj else Q()
        return self.filter(db_location=location).exclude(exclude_restriction)
Example #29
0
def create_message(senderobj, message, channels=None,
                   receivers=None, locks=None, header=None):
    """
    Create a new communication message. Msgs are used for all
    player-to-player communication, both between individual players
    and over channels.
    senderobj - the player sending the message. This must be the actual object.
    message - text with the message. Eventual headers, titles etc
              should all be included in this text string. Formatting
              will be retained.
    channels - a channel or a list of channels to send to. The channels
             may be actual channel objects or their unique key strings.
    receivers - a player to send to, or a list of them. May be Player objects
               or playernames.
    locks - lock definition string
    header - mime-type or other optional information for the message

    The Comm system is created very open-ended, so it's fully possible
    to let a message both go to several channels and to several receivers
    at the same time, it's up to the command definitions to limit this as
    desired.
    """
    global _Msg
    if not _Msg:
        from src.comms.models import Msg as _Msg
    if not message:
        # we don't allow empty messages.
        return
    new_message = _Msg(db_message=message)
    new_message.save()
    for sender in make_iter(senderobj):
        new_message.senders = sender
    new_message.header = header
    for channel in make_iter(channels):
        new_message.channels = channel
    for receiver in make_iter(receivers):
        new_message.receivers = receiver
    if locks:
        new_message.locks.add(locks)
    new_message.save()
    return new_message
Example #30
0
    def get_objs_with_attr_value(self,
                                 attribute_name,
                                 attribute_value,
                                 candidates=None,
                                 typeclasses=None):
        """
        Returns all objects having the valid attrname set to the given value.

        candidates - list of candidate objects to search
        typeclasses - list of typeclass-path strings to restrict matches with

        This uses the Attribute's PickledField to transparently search the database by matching
        the internal representation. This is reasonably effective but since Attribute values
        cannot be indexed, searching by Attribute key is to be preferred whenever possible.
        """
        cand_restriction = candidates != None and Q(
            pk__in=[_GA(obj, "id")
                    for obj in make_iter(candidates) if obj]) or Q()
        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, (basestring, int, float, bool, long)):
            return self.filter(cand_restriction & type_restriction
                               & Q(db_attributes__db_key=attribute_name,
                                   db_attributes__db_value=attribute_value))
        else:
            # We have to loop for safety since the referenced lookup gives deepcopy error if attribute value is an object.
            global _ATTR
            if not _ATTR:
                from src.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)
            ]
            return chain(*results)
Example #31
0
    def contents_get(self, exclude=None):
        """
        Returns the contents of this object, i.e. all
        objects that has this object set as its location.
        This should be publically available.

        exclude is one or more objects to not return
        """
        if exclude:
            exclude = [obj.dbobj for obj in make_iter(exclude)]
            return ObjectDB.objects.get_contents(self, excludeobj=exclude)
        return ObjectDB.objects.get_contents(self)
Example #32
0
 def get_objs_with_attr(self, attribute_name, candidates=None):
     """
     Returns all objects having the given attribute_name defined at all.
     Location should be a valid location object.
     """
     cand_restriction = candidates != None and Q(
         db_attributes__db_obj__pk__in=[
             _GA(obj, "id") for obj in make_iter(candidates) if obj
         ]) or Q()
     return list(
         self.filter(cand_restriction
                     & Q(db_attributes__db_key=attribute_name)))
Example #33
0
 def get_objs_with_key_and_typeclass(self,
                                     oname,
                                     otypeclass_path,
                                     candidates=None):
     """
     Returns objects based on simultaneous key and typeclass match.
     """
     cand_restriction = candidates != None and Q(
         pk__in=[_GA(obj, "id")
                 for obj in make_iter(candidates) if obj]) or Q()
     return self.filter(cand_restriction & Q(
         db_key__iexact=oname, db_typeclass_path__exact=otypeclass_path))
Example #34
0
 def get_objs_with_db_property_value(self, property_name, property_value, candidates=None):
     """
     Returns all objects having a given db field property
     """
     if isinstance(property_value, basestring):
         property_value = to_unicode(property_value)
     property_name = "db_%s" % property_name.lstrip('db_')
     cand_restriction = candidates and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q()
     try:
         return self.filter(cand_restriction & Q(property_name=property_value))
     except exceptions.FieldError:
         return []
Example #35
0
    def func(self):
        "Create the nickname"

        caller = self.caller
        switches = self.switches
        nicks = caller.nicks.get(return_obj=True)

        if 'list' in switches:
            table = prettytable.PrettyTable(["{wNickType",
                                             "{wNickname",
                                             "{wTranslates-to"])
            for nick in utils.make_iter(nicks):
                table.add_row([nick.db_category, nick.db_key, nick.db_strvalue])
            string = "{wDefined Nicks:{n\n%s" % table
            caller.msg(string)
            return
        if 'clearall' in switches:
            caller.nicks.clear()
            caller.msg("Cleared all aliases.")
            return
        if not self.args or not self.lhs:
            caller.msg("Usage: nick[/switches] nickname = [realname]")
            return
        nick = self.lhs
        real = self.rhs

        if real == nick:
            caller.msg("No point in setting nick same as the string to replace...")
            return

        # check so we have a suitable nick type
        if not any(True for switch in switches if switch in ("object", "player", "inputline")):
            switches = ["inputline"]
        string = ""
        for switch in switches:
            oldnick = caller.nicks.get(key=nick, category=switch)
            #oldnick = Nick.objects.filter(db_obj=caller.dbobj, db_nick__iexact=nick, db_type__iexact=switch)
            if not real:
                # removal of nick
                if oldnick:
                    # clear the alias
                    string += "\nNick '%s' (= '%s') was cleared." % (nick, oldnick)
                    caller.nicks.delete(nick, category=switch)
                else:
                    string += "\nNo nick '%s' found, so it could not be removed." % nick
            else:
                # creating new nick
                if oldnick:
                    string += "\nNick %s changed from '%s' to '%s'." % (nick, oldnick, real)
                else:
                    string += "\nNick set: '%s' = '%s'." % (nick, real)
                caller.nicks.add(nick, real, category=switch)
        caller.msg(string)
Example #36
0
 def get_objs_with_db_property(self, property_name, candidates=None):
     """
     Returns all objects having a given db field property.
     property_name = search string
     candidates - list of candidate objects to search
     """
     property_name = "db_%s" % property_name.lstrip('db_')
     cand_restriction = candidates and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q()
     try:
         return self.filter(cand_restriction).exclude(Q(property_name=None))
     except exceptions.FieldError:
         return []
Example #37
0
 def __receivers_set(self, value):
     "Setter. Allows for self.receivers = value. This appends a new receiver to the message."
     for val in (v for v in make_iter(value) if v):
         obj, typ = identify_object(val)
         if typ == 'player':
             self.db_receivers_players.add(obj)
         elif typ == 'object':
             self.db_receivers_objects.add(obj)
         elif not obj:
             return
         else:
             raise ValueError
         self.save()
Example #38
0
    def msg_contents(self, message, exclude=None, from_obj=None, **kwargs):
        """
        Emits something to all objects inside an object.

        exclude is a list of objects not to send to. See self.msg() for
                more info.
        """
        contents = _GA(self, "contents")
        if exclude:
            exclude = make_iter(exclude)
            contents = [obj for obj in contents if obj not in exclude]
        for obj in contents:
            obj.msg(message, from_obj=from_obj, **kwargs)
Example #39
0
 def remove_sender(self, value):
     "Remove a single sender or a list of senders"
     for val in make_iter(value):
         obj, typ = identify_object(val)
         if typ == 'player':
             self.db_sender_players.remove(obj)
         elif typ == 'object':
             self.db_sender_objects.remove(obj)
         elif isinstance(obj, basestring):
             self.db_sender_external = obj
         else:
             raise ValueError(obj)
         self.save()
Example #40
0
    def contents_get(self, exclude=None):
        """
        Returns the contents of this object, i.e. all
        objects that has this object set as its location.
        This should be publically available.

        exclude is one or more objects to not return
        """
        cont = get_prop_cache(self, "_contents")
        exclude = make_iter(exclude)
        if cont == None:
            cont = _GA(self, "contents_update")()
        return [obj for obj in cont if obj not in exclude]
Example #41
0
    def msg_contents(self, message, exclude=None, from_obj=None, **kwargs):
        """
        Emits something to all objects inside an object.

        exclude is a list of objects not to send to. See self.msg() for
                more info.
        """
        contents = _GA(self, "contents")
        if exclude:
            exclude = make_iter(exclude)
            contents = [obj for obj in contents if obj not in exclude]
        for obj in contents:
            obj.msg(message, from_obj=from_obj, **kwargs)
Example #42
0
 def remove_sender(self, value):
     "Remove a single sender or a list of senders"
     for val in make_iter(value):
         obj, typ = identify_object(val)
         if typ == 'player':
             self.db_sender_players.remove(obj)
         elif typ == 'object':
             self.db_sender_objects.remove(obj)
         elif isinstance(obj, basestring):
             self.db_sender_external = obj
         else:
             raise ValueError(obj)
         self.save()
Example #43
0
    def msg(self, text=None, from_obj=None, sessid=0, **kwargs):
        """
        Emits something to a session attached to the object.

        message (str): The message to send
        from_obj (obj): object that is sending.
        data (object): an optional data object that may or may not
                       be used by the protocol.
        sessid (int): sessid to relay to, if any.
                      If set to 0 (default), use either from_obj.sessid (if set) or self.sessid automatically
                      If None, echo to all connected sessions

        When this message is called, from_obj.at_msg_send and self.at_msg_receive are called.

        """
        global _SESSIONS
        if not _SESSIONS:
            from src.server.sessionhandler import SESSIONS as _SESSIONS

        text = to_str(text, force_string=True) if text else ""

        if "data" in kwargs:
            # deprecation warning
            logger.log_depmsg(
                "ObjectDB.msg(): 'data'-dict keyword is deprecated. Use **kwargs instead."
            )
            data = kwargs.pop("data")
            if isinstance(data, dict):
                kwargs.update(data)

        if from_obj:
            # call hook
            try:
                _GA(from_obj, "at_msg_send")(text=text,
                                             to_obj=_GA(self, "typeclass"),
                                             **kwargs)
            except Exception:
                logger.log_trace()
        try:
            if not _GA(_GA(self, "typeclass"), "at_msg_receive")(text=text,
                                                                 **kwargs):
                # if at_msg_receive returns false, we abort message to this object
                return
        except Exception:
            logger.log_trace()

        sessions = _SESSIONS.session_from_sessid(
            [sessid] if sessid else make_iter(_GA(self, "sessid").get()))
        for session in sessions:
            session.msg(text=text, **kwargs)
Example #44
0
    def msdp_cmd_send(self, arg):
        """
        Request the server to send a particular variable
        to the client.

        arg - this is a list of variables the client wants.
        """
        ret = []
        for var in make_iter(arg):
            try:
                ret.append(MSDP_REPORTABLE[arg](send=True))
            except Exception:
                logger.log_trace()
        return ret
Example #45
0
def _get_prototype(dic, prot, protparents):
    """
    Recursively traverse a prototype dictionary,
    including multiple inheritance. Use _validate_prototype
    before this, we don't check for infinite recursion here.
    """
    if "prototype" in dic:
        # move backwards through the inheritance
        for prototype in make_iter(dic["prototype"]):
            # Build the prot dictionary in reverse order, overloading
            new_prot = _get_prototype(protparents.get(prototype, {}), prot, protparents)
            prot.update(new_prot)
    prot.update(dic)
    prot.pop("prototype", None) # we don't need this anymore
    return prot
Example #46
0
 def get_object_with_player(self, ostring, exact=True, candidates=None):
     """
     Search for an object based on its player's name or dbref.
     This search
     is sometimes initiated by appending a * to the beginning of
     the search criterion (e.g. in local_and_global_search).
     search_string:  (string) The name or dbref to search for.
     """
     ostring = to_unicode(ostring).lstrip('*')
     # simplest case - search by dbref
     dbref = self.dbref(ostring)
     if dbref:
         return dbref
     # not a dbref. Search by name.
     cand_restriction = candidates != None and Q(
         pk__in=[_GA(obj, "id")
                 for obj in make_iter(candidates) if obj]) or Q()
     if exact:
         return self.filter(cand_restriction
                            & Q(db_player__username__iexact=ostring))
     else:  # fuzzy matching
         ply_cands = self.filter(cand_restriction & Q(
             playerdb__username__istartswith=ostring)).values_list(
                 "db_key", flat=True)
         if candidates:
             index_matches = string_partial_matching(ply_cands,
                                                     ostring,
                                                     ret_index=True)
             return [
                 obj for ind, obj in enumerate(make_iter(candidates))
                 if ind in index_matches
             ]
         else:
             return string_partial_matching(ply_cands,
                                            ostring,
                                            ret_index=False)
Example #47
0
 def __senders_set(self, value):
     "Setter. Allows for self.sender = value"
     for val in (v for v in make_iter(value) if v):
         obj, typ = identify_object(val)
         if typ == 'player':
             self.db_sender_players.add(obj)
         elif typ == 'object':
             self.db_sender_objects.add(obj)
         elif isinstance(typ, basestring):
             self.db_sender_external = obj
         elif not obj:
             return
         else:
             raise ValueError(obj)
         self.save()
Example #48
0
def _validate_prototype(key, prototype, protparents, visited):
    "Run validation on a prototype, checking for inifinite regress"
    assert isinstance(prototype, dict)
    if id(prototype) in visited:
        raise RuntimeError("%s has infinite nesting of prototypes." % key or prototype)
    visited.append(id(prototype))
    protstrings = prototype.get("prototype")
    if protstrings:
        for protstring in make_iter(protstrings):
            if key is not None and protstring == key:
                raise RuntimeError("%s tries to prototype itself." % key or prototype)
            protparent = protparents.get(protstring)
            if not protparent:
                raise RuntimeError("%s's prototype '%s' was not found." % (key or prototype, protstring))
            _validate_prototype(protstring, protparent, protparents, visited)
Example #49
0
 def __senders_set(self, value):
     "Setter. Allows for self.sender = value"
     for val in (v for v in make_iter(value) if v):
         obj, typ = identify_object(val)
         if typ == 'player':
             self.db_sender_players.add(obj)
         elif typ == 'object':
             self.db_sender_objects.add(obj)
         elif isinstance(typ, basestring):
             self.db_sender_external = obj
         elif not obj:
             return
         else:
             raise ValueError(obj)
         self.save()
Example #50
0
 def __receivers_set(self, value):
     """
     Setter. Allows for self.receivers = value.
     This appends a new receiver to the message.
     """
     for val in (v for v in make_iter(value) if v):
         obj, typ = identify_object(val)
         if typ == 'player':
             self.db_receivers_players.add(obj)
         elif typ == 'object':
             self.db_receivers_objects.add(obj)
         elif not obj:
             return
         else:
             raise ValueError
         self.save()
Example #51
0
 def get_objs_with_db_property(self, property_name, candidates=None):
     """
     Returns all objects having a given db field property.
     property_name = search string
     candidates - list of candidate objects to search
     """
     property_name = "db_%s" % property_name.lstrip('db_')
     cand_restriction = candidates != None and Q(
         pk__in=[_GA(obj, "id")
                 for obj in make_iter(candidates) if obj]) or Q()
     querykwargs = {property_name: None}
     try:
         return list(
             self.filter(cand_restriction).exclude(Q(**querykwargs)))
     except exceptions.FieldError:
         return []
Example #52
0
    def msg(self, text=None, from_obj=None, sessid=None, **kwargs):
        """
        Evennia -> User
        This is the main route for sending data back to the user from the
        server.

        outgoing_string (string) - text data to send
        from_obj (Object/Player) - source object of message to send. Its
                 at_msg_send() hook will be called.
        sessid - the session id of the session to send to. If not given, return
                 to all sessions connected to this player. This is usually only
                 relevant when using msg() directly from a player-command (from
                 a command on a Character, the character automatically stores
                 and handles the sessid). Can also be a list of sessids.
        kwargs (dict) - All other keywords are parsed as extra data.
        """
        if "data" in kwargs:
            # deprecation warning
            logger.log_depmsg(
                "PlayerDB:msg() 'data'-dict keyword is deprecated. Use **kwargs instead."
            )
            data = kwargs.pop("data")
            if isinstance(data, dict):
                kwargs.update(data)

        text = to_str(text, force_string=True) if text else ""
        if from_obj:
            # call hook
            try:
                _GA(from_obj, "at_msg_send")(text=text,
                                             to_obj=_GA(self, "typeclass"),
                                             **kwargs)
            except Exception:
                pass
        sessions = _MULTISESSION_MODE > 1 and sessid and _GA(
            self, "get_session")(sessid) or None
        if sessions:
            for session in make_iter(sessions):
                obj = session.puppet
                if obj and not obj.at_msg_receive(text=text, **kwargs):
                    # if hook returns false, cancel send
                    continue
                session.msg(text=text, **kwargs)
        else:
            # if no session was specified, send to them all
            for sess in _GA(self, 'get_all_sessions')():
                sess.msg(text=text, **kwargs)
Example #53
0
    def func(self):
        "Implementing the command. "

        caller = self.caller
        player = caller

        if not self.args:
            self.msg("Usage: delcom <alias or channel>")
            return
        ostring = self.args.lower()

        channel = find_channel(caller, ostring, silent=True, noaliases=True)
        if channel:
            # we have given a channel name - unsubscribe
            if not channel.has_connection(player):
                self.msg("You are not listening to that channel.")
                return
            chkey = channel.key.lower()
            # find all nicks linked to this channel and delete them
            for nick in [
                    nick for nick in make_iter(
                        caller.nicks.get(category="channel", return_obj=True))
                    if nick and nick.strvalue.lower() == chkey
            ]:
                nick.delete()
            disconnect = channel.disconnect(player)
            if disconnect:
                self.msg(
                    "You stop listening to channel '%s'. Eventual aliases were removed."
                    % channel.key)
            return
        else:
            # we are removing a channel nick
            channame = caller.nicks.get(key=ostring, category="channel")
            channel = find_channel(caller, channame, silent=True)
            if not channel:
                self.msg("No channel with alias '%s' was found." % ostring)
            else:
                if caller.nicks.get(ostring, category="channel"):
                    caller.nicks.remove(ostring, category="channel")
                    self.msg("Your alias '%s' for channel %s was cleared." %
                             (ostring, channel.key))
                else:
                    self.msg("You had no such alias defined for this channel.")
Example #54
0
def _get_prototype(dic, prot, protparents, visited):
    """
    Recursively traverse a prototype dictionary,
    including multiple inheritance and self-reference
    detection
    """
    visited.append(id(dic))
    if "prototype" in dic:
        # move backwards through the inheritance
        for prototype in make_iter(dic["prototype"]):
            if id(prototype) in visited:
                # a loop was detected. Don't self-reference.
                continue
            # Build the prot dictionary in reverse order, overloading
            new_prot = _get_prototype(protparents.get(prototype, {}), prot,
                                      protparents, visited)
            prot.update(new_prot)
    prot.update(dic)
    prot.pop("prototype", None)  # we don't need this anymore
    return prot
Example #55
0
 def func(self, *args, **kwargs):
     "decorator. Returns a list."
     self.__doc__ = method.__doc__
     matches = make_iter(method(self, *args, **kwargs))
     return [(hasattr(dbobj, "typeclass") and dbobj.typeclass) or dbobj
                                            for dbobj in make_iter(matches)]
Example #56
0
    def search(
            self,
            searchdata,
            global_search=False,
            use_nicks=True,  # should this default to off?
            typeclass=None,
            location=None,
            attribute_name=None,
            quiet=False,
            exact=False):
        """
        Returns the typeclass of an Object matching a search string/condition

        Perform a standard object search in the database, handling
        multiple results and lack thereof gracefully. By default, only
        objects in self's current location or inventory is searched.
        Note: to find Players, use eg. ev.player_search.

        Inputs:

        searchdata (str or obj): Primary search criterion. Will be matched
                    against object.key (with object.aliases second) unless
                    the keyword attribute_name specifies otherwise.
                    Special strings:
                        #<num> - search by unique dbref. This is always
                                 a global search.
                        me,self - self-reference to this object
                        <num>-<string> - can be used to differentiate
                                         between multiple same-named matches
        global_search (bool): Search all objects globally. This is overruled
                              by "location" keyword.
        use_nicks (bool): Use nickname-replace (nicktype "object") on the
                          search string
        typeclass (str or Typeclass, or list of either): Limit search only
                   to Objects with this typeclass. May be a list of typeclasses
                   for a broader search.
        location (Object): Specify a location to search, if different from the
                     self's given location plus its contents. This can also
                     be a list of locations.
        attribute_name (str): Define which property to search. If set, no
                      key+alias search will be performed. This can be used to
                      search database fields (db_ will be automatically
                      appended), and if that fails, it will try to return
                      objects having Attributes with this name and value
                      equal to searchdata. A special use is to search for
                      "key" here if you want to do a key-search without
                      including aliases.
        quiet (bool) - don't display default error messages - return multiple
                      matches as a list and no matches as None. If not
                      set (default), will echo error messages and return None.
        exact (bool) - if unset (default) - prefers to match to beginning of
                      string rather than not matching at all. If set, requires
                      exact mathing of entire string.

        Returns:
            quiet=False (default):
                no match or multimatch:
                auto-echoes errors to self.msg, then returns None
                    (results are handled by settings.SEARCH_AT_RESULT
                               and settings.SEARCH_AT_MULTIMATCH_INPUT)
                match:
                    a unique object match
            quiet=True:
                no match or multimatch:
                    returns None or list of multi-matches
                match:
                    a unique object match

        """
        is_string = isinstance(searchdata, basestring)

        if use_nicks:
            # do nick-replacement on search
            searchdata = self.nicks.nickreplace(searchdata,
                                                categories=("object",
                                                            "player"),
                                                include_player=True)

        candidates = None
        if (global_search
                or (is_string and searchdata.startswith("#")
                    and len(searchdata) > 1 and searchdata[1:].isdigit())):
            # only allow exact matching if searching the entire database
            # or unique #dbrefs
            exact = True
        elif location:
            # location(s) were given
            candidates = []
            for obj in make_iter(location):
                candidates.extend([o.dbobj for o in obj.contents])
        else:
            # local search. Candidates are self.contents, self.location
            # and self.location.contents
            location = self.location
            candidates = self.contents
            if location:
                candidates = candidates + [location] + location.contents
            else:
                # normally we are included in location.contents
                candidates.append(self)
            # db manager expects database objects
            candidates = [obj.dbobj for obj in candidates]

        results = ObjectDB.objects.object_search(searchdata,
                                                 attribute_name=attribute_name,
                                                 typeclass=typeclass,
                                                 candidates=candidates,
                                                 exact=exact)
        if quiet:
            return results
        return _AT_SEARCH_RESULT(self, searchdata, results, global_search)