Example #1
0
    def __new__(cls, *args, **kwargs):
        """
        When creating a new ANSIString, you may use a custom parser that has
        the same attributes as the standard one, and you may declare the
        string to be handled as already decoded. It is important not to double
        decode strings, as escapes can only be respected once.
        """
        string = args[0]
        if not isinstance(string, basestring):
            string = to_str(string, force_string=True)
        parser = kwargs.get('parser', ANSI_PARSER)
        decoded = kwargs.get('decoded', False) or hasattr(string, '_raw_string')
        if not decoded:
            # Completely new ANSI String
            clean_string = to_unicode(parser.parse_ansi(string, strip_ansi=True))
            string = parser.parse_ansi(string)
        elif hasattr(string, '_clean_string'):
            # It's already an ANSIString
            clean_string = string._clean_string
            string = string._raw_string
        else:
            # It's a string that has been pre-ansi decoded.
            clean_string = parser.strip_raw_codes(string)

        if not isinstance(string, unicode):
            string = string.decode('utf-8')
        else:
            # Do this to prevent recursive ANSIStrings.
            string = unicode(string)
        ansi_string = super(ANSIString, cls).__new__(ANSIString, to_str(clean_string), "utf-8")
        ansi_string._raw_string = string
        ansi_string._clean_string = clean_string
        return ansi_string
Example #2
0
    def reload(self, filename=None, form=None, **kwargs):
        """
        Creates the form from a stored file name
        """
        # clean kwargs (these cannot be overridden)
        kwargs.pop("enforce_size", None)
        kwargs.pop("width", None)
        kwargs.pop("height", None)

        if form or self.input_form_dict:
            datadict = form if form else self.input_form_dict
            self.input_form_dict = datadict
        elif filename or self.filename:
            filename = filename if filename else self.filename
            datadict = all_from_module(filename)
            self.filename = filename
        else:
            datadict = {}

        cellchar = to_str(datadict.get("FORMCHAR", "x"))
        self.cellchar = to_str(cellchar[0] if len(cellchar) > 1 else cellchar)
        tablechar = datadict.get("TABLECHAR", "c")
        self.tablechar = tablechar[0] if len(tablechar) > 1 else tablechar

        # split into a list of list of lines. Form can be indexed with form[iy][ix]
        self.raw_form = to_unicode(datadict.get("FORM", "")).split("\n")
        # strip first line
        self.raw_form = self.raw_form[1:] if self.raw_form else self.raw_form

        self.options.update(kwargs)

        # parse and replace
        self.mapping = self._parse_rectangles(self.cellchar, self.tablechar, self.raw_form, **kwargs)
        self.form = self._populate_form(self.raw_form, self.mapping)
Example #3
0
def connect_to_rss(connection):
    """
    Create the parser instance and connect to RSS feed and channel
    """
    global RSS_READERS
    key = utils.to_str(connection.external_key)
    url, interval = [utils.to_str(conf) for conf in connection.external_config.split('|')]
    # Create reader (this starts the running task and stores a reference in RSS_TASKS)
    RSSReader(key, url, int(interval))
Example #4
0
    def msg_irc(self, msg, senders=None):
        """
        Called by evennia when sending something to mapped IRC channel.

        Note that this cannot simply be called msg() since that's the
        name of of the twisted irc hook as well, this leads to some
        initialization messages to be sent without checks, causing loops.
        """
        self.msg(utils.to_str(self.factory.channel), utils.to_str(msg))
 def forwards(self, orm):
     "Write your forwards methods here."
     for attr in orm.ScriptAttribute.objects.all():
         try:
             # repack attr into new format, and reimport
             val = pickle.loads(to_str(attr.db_value))
             attr.db_value = to_unicode(pickle.dumps(to_str(to_attr(from_attr(attr, val)))))
             attr.save()
         except TypeError, RuntimeError:
             pass
Example #6
0
def connect_to_irc(connection):
    "Create the bot instance and connect to the IRC network and channel."
    # get config
    key = utils.to_str(connection.external_key)
    service_key = build_service_key(key)
    irc_network, irc_port, irc_channel, irc_bot_nick = [utils.to_str(conf) for conf in connection.external_config.split('|')]
    # connect
    bot = internet.TCPClient(irc_network, int(irc_port), IRCbotFactory(key, irc_channel, irc_network, irc_port, irc_bot_nick,
                                                                     connection.channel.key))
    bot.setName(service_key)
    SESSIONS.server.services.addService(bot)
Example #7
0
    def __new__(cls, *args, **kwargs):
        """
        When creating a new ANSIString, you may use a custom parser that has
        the same attributes as the standard one, and you may declare the
        string to be handled as already decoded. It is important not to double
        decode strings, as escapes can only be respected once.

        Internally, ANSIString can also passes itself precached code/character
        indexes and clean strings to avoid doing extra work when combining
        ANSIStrings.
        """
        string = args[0]
        if not isinstance(string, basestring):
            string = to_str(string, force_string=True)
        parser = kwargs.get('parser', ANSI_PARSER)
        decoded = kwargs.get('decoded', False) or hasattr(string, '_raw_string')
        code_indexes = kwargs.pop('code_indexes', None)
        char_indexes = kwargs.pop('char_indexes', None)
        clean_string = kwargs.pop('clean_string', None)
        # All True, or All False, not just one.
        checks = map(lambda x: x is None, [code_indexes, char_indexes, clean_string])
        if not len(set(checks)) == 1:
            raise ValueError("You must specify code_indexes, char_indexes, "
                             "and clean_string together, or not at all.")
        if not all(checks):
            decoded = True
        if not decoded:
            # Completely new ANSI String
            clean_string = to_unicode(parser.parse_ansi(string, strip_ansi=True))
            string = parser.parse_ansi(string)
        elif clean_string is not None:
            # We have an explicit clean string.
            pass
        elif hasattr(string, '_clean_string'):
            # It's already an ANSIString
            clean_string = string._clean_string
            code_indexes = string._code_indexes
            char_indexes = string._char_indexes
            string = string._raw_string
        else:
            # It's a string that has been pre-ansi decoded.
            clean_string = parser.strip_raw_codes(string)

        if not isinstance(string, unicode):
            string = string.decode('utf-8')

        ansi_string = super(ANSIString, cls).__new__(ANSIString, to_str(clean_string), "utf-8")
        ansi_string._raw_string = string
        ansi_string._clean_string = clean_string
        ansi_string._code_indexes = code_indexes
        ansi_string._char_indexes = char_indexes
        return ansi_string
Example #8
0
 def __set_obj(self, value):
     """
     Set player or obj to their right database field. If
     a dbref is given, assume ObjectDB.
     """
     try:
         value = _GA(value, "dbobj")
     except AttributeError:
         pass
     if isinstance(value, (basestring, int)):
         from src.objects.models import ObjectDB
         value = to_str(value, force_string=True)
         if (value.isdigit() or value.startswith("#")):
             dbid = dbref(value, reqhash=False)
             if dbid:
                 try:
                     value = ObjectDB.objects.get(id=dbid)
                 except ObjectDoesNotExist:
                     # maybe it is just a name that happens to look like a dbid
                     pass
     if value.__class__.__name__ == "PlayerDB":
         fname = "db_player"
         _SA(self, fname, value)
     else:
         fname = "db_obj"
         _SA(self, fname, value)
     # saving the field
     _GA(self, "save")(update_fields=[fname])
Example #9
0
 def _send_packet(self, packet):
     "Helper function to send packets across the wire"
     packet.imc2_protocol = self
     packet_str = utils.to_str(
         packet.assemble(self.factory.mudname, self.factory.client_pwd,
                         self.factory.server_pwd))
     self.sendLine(packet_str)
Example #10
0
  def run_diagnostics(self):
    print('Running diagnostics...')
    # diagnostic runs on validation set
    validation_images   = self.dataHandler.validation_images
    validation_labels   = self.dataHandler.validation_labels
    y                   = self.graphHelper.y
    predict             = self.graphHelper.predict

    val_labels  = np.zeros(validation_images.shape[0])
    val_y       = np.zeros((validation_images.shape[0], 10))

    for i in range(0,validation_images.shape[0]//BATCH_SIZE):
        b1 = i*BATCH_SIZE
        b2 = (i+1)*BATCH_SIZE
        fd = self._get_eval_dict('other', dataset = validation_images[b1:b2])
        val_labels[b1:b2], val_y[b1:b2] = self.sess.run([predict, y], feed_dict=fd)

    # dump diagnostics to file
    to_file = []
    bad_img = []
    bad_lbs = []
    for i in range(0, len(val_labels)):
        val_label_dense     = np.argmax(validation_labels[i])
        if val_labels[i] != val_label_dense:
            bad_img.append(validation_images[i])
            bad_lbs.append(validation_labels[i])
            to_file.append('index: '+ str(i)+
                           ', predicted: '+str(val_labels[i])+
                           ', target: '+str(val_label_dense)+
                           ', probs: '+utils.to_str(val_y[i]))

    utils.save_diagnostics(to_file)
Example #11
0
 def _set_foreign(cls, fname, value):
     "Setter only used on foreign key relations, allows setting with #dbref"
     try:
         value = _GA(value, "dbobj")
     except AttributeError:
         pass
     if isinstance(value, (basestring, int)):
         value = to_str(value, force_string=True)
         if (value.isdigit() or value.startswith("#")):
             # we also allow setting using dbrefs, if so we try to load the matching object.
             # (we assume the object is of the same type as the class holding the field, if
             # not a custom handler must be used for that field)
             dbid = dbref(value, reqhash=False)
             if dbid:
                 model = _GA(cls, "_meta").get_field(fname).model
                 try:
                     value = model._default_manager.get(id=dbid)
                 except ObjectDoesNotExist:
                     # maybe it is just a name that happens to look like a dbid
                     pass
     _SA(cls, fname, value)
     # only use explicit update_fields in save if we actually have a
     # primary key assigned already (won't be set when first creating object)
     update_fields = [fname] if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None else None
     _GA(cls, "save")(update_fields=update_fields)
Example #12
0
 def _set_foreign(cls, fname, value):
     "Setter only used on foreign key relations, allows setting with #dbref"
     try:
         value = _GA(value, "dbobj")
     except AttributeError:
         pass
     if isinstance(value, (basestring, int)):
         value = to_str(value, force_string=True)
         if (value.isdigit() or value.startswith("#")):
             # we also allow setting using dbrefs, if so we try to load the matching object.
             # (we assume the object is of the same type as the class holding the field, if
             # not a custom handler must be used for that field)
             dbid = dbref(value, reqhash=False)
             if dbid:
                 model = _GA(cls, "_meta").get_field(fname).model
                 try:
                     value = model._default_manager.get(id=dbid)
                 except ObjectDoesNotExist:
                     # maybe it is just a name that happens to look like a dbid
                     pass
     _SA(cls, fname, value)
     # only use explicit update_fields in save if we actually have a
     # primary key assigned already (won't be set when first creating object)
     update_fields = [fname] if _GA(cls, "_get_pk_val")(_GA(
         cls, "_meta")) is not None else None
     _GA(cls, "save")(update_fields=update_fields)
Example #13
0
 def send_split_msg(self, sessid, msg, data, command):
     """
     This helper method splits the sending of a msg into multiple parts
     with a maxlength of MAXLEN. This is to avoid repetition in the two
     msg-sending commands. When calling this, the maximum length has
     already been exceeded.
     Inputs:
         msg - string
         data - data dictionary
         command - one of MsgPortal2Server or MsgServer2Portal commands
     """
     # split the strings into acceptable chunks
     datastr = dumps(data)
     nmsg, ndata = len(msg), len(datastr)
     if nmsg > MAXLEN or ndata > MAXLEN:
         msglist = [msg[i:i+MAXLEN] for i in range(0, len(msg), MAXLEN)]
         datalist = [datastr[i:i+MAXLEN] for i in range(0, len(datastr), MAXLEN)]
     nmsglist, ndatalist = len(msglist), len(datalist)
     if ndatalist < nmsglist:
         datalist.extend("" for i in range(nmsglist-ndatalist))
     if nmsglist < ndatalist:
         msglist.extend("" for i in range(ndatalist-nmsglist))
     # we have split the msg/data into right-size chunks. Now we send it in sequence
     return [self.callRemote(command,
                     sessid=sessid,
                     msg=to_str(msg),
                     ipart=icall,
                     nparts=nmsglist,
                     data=dumps(data)).addErrback(self.errback, "OOBServer2Portal")
             for icall, (msg, data) in enumerate(zip(msglist, datalist))]
Example #14
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
        """
        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=self, **kwargs)
            except Exception:
                pass

        session = _SESSIONS.session_from_sessid(sessid if sessid else _GA(self, "sessid"))
        if session:
            session.msg(text=text, **kwargs)
Example #15
0
 def forwards(self, orm):
     "Write your forwards methods here."
     for attr in orm['players.PlayerAttribute'].objects.all():
         try:
             # repack attr into new format, and reimport
             val = pickle.loads(to_str(attr.db_value))
             if hasattr(val, '__iter__'):
                 val = ("iter", val)
             elif type(val) == PackedDBobject:
                 val = ("dbobj", val)
             else:
                 val = ("simple", val)
             attr.db_value = to_unicode(pickle.dumps(to_str(to_attr(from_attr(attr, val)))))
             attr.save()
         except TypeError, RuntimeError:
             pass
Example #16
0
    def data_out(self, string='', data=None):
        """
        Data Evennia -> Player access hook.

        data argument may be used depending on
        the client-server implementation.
        """

        if data:
            # treat data?
            pass

        # string handling is similar to telnet
        try:
            string = utils.to_str(string, encoding=self.encoding)

            nomarkup = False
            raw = False
            if type(data) == dict:
                # check if we want escape codes to go through unparsed.
                raw = data.get("raw", False)
                # check if we want to remove all markup
                nomarkup = data.get("nomarkup", False)
            if raw:
                self.client.lineSend(self.suid, string)
            else:
                self.client.lineSend(self.suid, parse_html(string, strip_ansi=nomarkup))
            return
        except Exception, e:
            logger.log_trace()
 def forwards(self, orm):
     "Write your forwards methods here."
     for attr in orm.PlayerAttribute.objects.all():
         try:
             # repack attr into new format, and reimport
             val = pickle.loads(to_str(attr.db_value))
             if hasattr(val, '__iter__'):
                 val = ("iter", val)
             elif type(val) == PackedDBobject:
                 val = ("dbobj", val)
             else:
                 val = ("simple", val)
             attr.db_value = to_unicode(pickle.dumps(to_str(to_attr(from_attr(attr, val)))))
             attr.save()
         except TypeError, RuntimeError:
             pass
Example #18
0
    def msg(self, outgoing_string, from_obj=None, data=None, sessid=None):
        """
        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
        data (dict) - arbitrary data object containing eventual protocol-specific options
        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).
        """
        if from_obj:
            # call hook
            try:
                _GA(from_obj, "at_msg_send")(outgoing_string, to_obj=self, data=data)
            except Exception:
                pass
        outgoing_string = utils.to_str(outgoing_string, force_string=True)

        session = _MULTISESSION_MODE == 2 and sessid and _GA(self, "get_session")(sessid) or None
        if session:
            obj = session.puppet
            if obj and not obj.at_msg_receive(outgoing_string, from_obj=from_obj, data=data):
                # if hook returns false, cancel send
                return
            session.msg(outgoing_string, data)
        else:
            # if no session was specified, send to them all
            for sess in _GA(self, "get_all_sessions")():
                sess.msg(outgoing_string, data)
Example #19
0
    def data_out(self, text=None, **kwargs):
        """
        Data Evennia -> Player.
        generic hook method for engine to call in order to send data
        through the telnet connection.

        valid telnet kwargs:
            oob=<string> - supply an Out-of-Band instruction.
            xterm256=True/False - enforce xterm256 setting. If not
                                  given, ttype result is used. If
                                  client does not suport xterm256, the
                                  ansi fallback will be used
            ansi=True/False - enforce ansi setting. If not given,
                              ttype result is used.
            nomarkup=True - strip all ansi markup (this is the same as
                            xterm256=False, ansi=False)
            raw=True - pass string through without any ansi
                       processing (i.e. include Evennia ansi markers but do
                       not convert them into ansi tokens)

        The telnet ttype negotiation flags, if any, are used if no kwargs
        are given.
        """
        try:
            text = utils.to_str(text if text else "", encoding=self.encoding)
        except Exception, e:
            self.sendLine(str(e))
            return
Example #20
0
 def __set_obj(self, value):
     """
     Set player or obj to their right database field. If
     a dbref is given, assume ObjectDB.
     """
     try:
         value = _GA(value, "dbobj")
     except AttributeError:
         pass
     if isinstance(value, (basestring, int)):
         from src.objects.models import ObjectDB
         value = to_str(value, force_string=True)
         if (value.isdigit() or value.startswith("#")):
             dbid = dbref(value, reqhash=False)
             if dbid:
                 try:
                     value = ObjectDB.objects.get(id=dbid)
                 except ObjectDoesNotExist:
                     # maybe it is just a name that happens to look like a dbid
                     pass
     if value.__class__.__name__ == "PlayerDB":
         fname = "db_player"
         _SA(self, fname, value)
     else:
         fname = "db_obj"
         _SA(self, fname, value)
     # saving the field
     _GA(self, "save")(update_fields=[fname])
Example #21
0
    def data_out(self, text=None, **kwargs):
        """
        Data Evennia -> Player.
        generic hook method for engine to call in order to send data
        through the telnet connection.

        valid telnet kwargs:
            oob=<string> - supply an Out-of-Band instruction.
            xterm256=True/False - enforce xterm256 setting. If not
                                  given, ttype result is used. If
                                  client does not suport xterm256, the
                                  ansi fallback will be used
            ansi=True/False - enforce ansi setting. If not given,
                              ttype result is used.
            nomarkup=True - strip all ansi markup (this is the same as
                            xterm256=False, ansi=False)
            raw=True - pass string through without any ansi
                       processing (i.e. include Evennia ansi markers but do
                       not convert them into ansi tokens)

        The telnet ttype negotiation flags, if any, are used if no kwargs
        are given.
        """
        try:
            text = utils.to_str(text if text else "", encoding=self.encoding)
        except Exception, e:
            self.sendLine(str(e))
            return
Example #22
0
    def parse_ansi(self, string, strip_ansi=False, xterm256=False):
        """
        Parses a string, subbing color codes according to
        the stored mapping.

        strip_ansi flag instead removes all ansi markup.

        """
        if hasattr(string, 'raw_string'):
            if strip_ansi:
                return string.clean_string
            else:
                return string.raw_string
        if not string:
            return ''
        self.do_xterm256 = xterm256
        string = utils.to_str(string)

        # go through all available mappings and translate them
        parts = self.ansi_escapes.split(string) + [" "]
        string = ""
        for part, sep in zip(parts[::2], parts[1::2]):
            for sub in self.ansi_sub:
                part = sub[0].sub(sub_meth(self, sub[1]), part)
            string += "%s%s" % (part, sep[0].strip())
        if strip_ansi:
            # remove all ansi codes (including those manually
            # inserted in string)
            string = self.ansi_regex.sub("", string)
        return string
Example #23
0
 def call_remote_MsgPortal2Server(self, sessid, msg, data=""):
     """
     Access method called by the Portal and executed on the Portal.
     """
     #print "msg portal->server (portal side):", sessid, msg, data
     return self.safe_send(MsgPortal2Server, sessid,
                           msg=to_str(msg) if msg is not None else "",
                           data=dumps(data))
Example #24
0
 def update(self, new_value, *args, **kwargs):
     "Called by cache when attribute's db_value field updates"
     try:
         new_value = new_value.dbobj
     except AttributeError:
         new_value = to_str(new_value, force_string=True)
     # this is a wrapper call for sending oob data back to session
     self.oobhandler.msg(self.sessid, "report", self.attrname, new_value, *args, **kwargs)
Example #25
0
 def call_remote_MsgServer2Portal(self, sessid, msg, data=""):
     """
     Access method called by the Server and executed on the Server.
     """
     #print "msg server->portal (server side):", sessid, msg, data
     return self.safe_send(MsgServer2Portal, sessid,
                           msg=to_str(msg) if msg is not None else "",
                           data=dumps(data))
Example #26
0
    def __init__(self,
                 filename=None,
                 cells=None,
                 tables=None,
                 form=None,
                 **kwargs):
        """
        Initiate the form

        keywords:
            filename - path to template file
            form - dictionary of {"CELLCHAR":char,
                                  "TABLECHAR":char,
                                  "FORM":templatestring}
                    if this is given, filename is not read.
            cells - a dictionary mapping of {id:text}
            tables -  dictionary mapping of {id:EvTable}

        other kwargs are fed as options to the Cells and EvTables
        (see evtablet.Cell and evtable.EvTable for more info).

        """
        self.filename = filename
        self.input_form_dict = form

        self.cells_mapping = dict(
            (to_str(key, force_string=True), value)
            for key, value in cells.items()) if cells else {}
        self.tables_mapping = dict(
            (to_str(key, force_string=True), value)
            for key, value in tables.items()) if tables else {}

        self.cellchar = "x"
        self.tablechar = "c"

        self.raw_form = []
        self.form = []

        # clean kwargs (these cannot be overridden)
        kwargs.pop("enforce_size", None)
        kwargs.pop("width", None)
        kwargs.pop("height", None)
        # table/cell options
        self.options = kwargs

        self.reload()
Example #27
0
 def call_remote_MsgServer2Portal(self, sessid, msg, data=""):
     """
     Access method called by the Server and executed on the Server.
     """
     #print "msg server->portal (server side):", sessid, msg, data
     return self.safe_send(MsgServer2Portal, sessid,
                           msg=to_str(msg) if msg is not None else "",
                           data=dumps(data))
Example #28
0
 def data_out(self, session, text="", **kwargs):
     """
     Sending data Server -> Portal
     """
     text = text and to_str(to_unicode(text), encoding=session.encoding)
     self.server.amp_protocol.call_remote_MsgServer2Portal(sessid=session.sessid,
                                                           msg=text,
                                                           data=kwargs)
Example #29
0
 def call_remote_MsgPortal2Server(self, sessid, msg, data=""):
     """
     Access method called by the Portal and executed on the Portal.
     """
     #print "msg portal->server (portal side):", sessid, msg, data
     return self.safe_send(MsgPortal2Server, sessid,
                           msg=to_str(msg) if msg is not None else "",
                           data=dumps(data))
Example #30
0
 def update(self, new_value, *args, **kwargs):
     "Called by cache when attribute's db_value field updates"
     try:
         new_value = new_value.dbobj
     except AttributeError:
         new_value = to_str(new_value, force_string=True)
     # this is a wrapper call for sending oob data back to session
     self.oobhandler.msg(self.sessid, "report", self.attrname, new_value,
                         *args, **kwargs)
Example #31
0
 def data_out(self, string, data=None):
     """
     Data Evennia -> Player access hook. 'data' argument is a dict parsed for string settings.
     """
     try:
         string = utils.to_str(string, encoding=self.encoding)
     except Exception, e:
         self.lineSend(str(e))
         return
Example #32
0
 def look_target(self):
     "Hook method for when an argument is given."
     player = self.caller
     key = self.args.lower()
     chars = dict((utils.to_str(char.key.lower()), char) for char in player.db._playable_characters)
     looktarget = chars.get(key)
     if looktarget:
         self.msg(looktarget.return_appearance(player))
     else:
         self.msg("No such character.")
     return
Example #33
0
 def update(self, new_value, *args, **kwargs):
     "Called by cache when updating the tracked entitiy"
     # use oobhandler to relay data
     try:
         # we must never relay objects across the amp, only text data.
         new_value = new_value.key
     except AttributeError:
         new_value = to_str(new_value, force_string=True)
     # this is a wrapper call for sending oob data back to session
     self.oobhandler.msg(self.sessid, "report", self.fieldname, new_value,
                         *args, **kwargs)
Example #34
0
 def update(self, new_value, *args, **kwargs):
     "Called by cache when updating the tracked entitiy"
     # use oobhandler to relay data
     try:
         # we must never relay objects across the amp, only text data.
         new_value = new_value.key
     except AttributeError:
         new_value = to_str(new_value, force_string=True)
     kwargs[self.fieldname] = new_value
     # this is a wrapper call for sending oob data back to session
     self.oobhandler.msg(self.sessid, "report", *args, **kwargs)
Example #35
0
 def look_target(self):
     "Hook method for when an argument is given."
     player = self.player
     key = self.args.lower()
     chars = dict((utils.to_str(char.key.lower()), char)
                  for char in player.db._playable_characters)
     looktarget = chars.get(key)
     if looktarget:
         self.msg(looktarget.return_appearance(player))
     else:
         self.msg("No such character.")
     return
Example #36
0
 def data_out(self, string, data=None):
     """
     generic hook method for engine to call in order to send data
     through the telnet connection.
     Data Evennia -> Player.
     data argument may contain a dict with output flags.
     """
     try:
         string = utils.to_str(string, encoding=self.encoding)
     except Exception, e:
         self.sendLine(str(e))
         return
Example #37
0
    def map(self, cells=None, tables=None, **kwargs):
        """
        Add mapping for form.

        cells - a dictionary of {identifier:celltext}
        tables - a dictionary of {identifier:table}

        kwargs will be forwarded to tables/cells. See
        evtable.EvCell and evtable.EvTable for info.

        """
        # clean kwargs (these cannot be overridden)
        kwargs.pop("enforce_size", None)
        kwargs.pop("width", None)
        kwargs.pop("height", None)

        new_cells =  dict((to_str(key, force_string=True), value) for key, value in cells.items()) if cells  else {}
        new_tables = dict((to_str(key, force_string=True), value) for key, value in tables.items()) if tables else {}

        self.cells_mapping.update(new_cells)
        self.tables_mapping.update(new_tables)
        self.reload()
Example #38
0
    def map(self, cells=None, tables=None, **kwargs):
        """
        Add mapping for form.

        cells - a dictionary of {identifier:celltext}
        tables - a dictionary of {identifier:table}

        kwargs will be forwarded to tables/cells. See
        evtable.Cell and evtable.EvTable for info.

        """
        # clean kwargs (these cannot be overridden)
        kwargs.pop("enforce_size", None)
        kwargs.pop("width", None)
        kwargs.pop("height", None)

        new_cells =  dict((to_str(key), value) for key, value in cells.items()) if cells  else {}
        new_tables = dict((to_str(key), value) for key, value in tables.items()) if tables else {}

        self.cells_mapping.update(new_cells)
        self.tables_mapping.update(new_tables)
        self.reload()
Example #39
0
    def parse_ansi(self, string, strip_ansi=False, xterm256=False, mxp=False):
        """
        Parses a string, subbing color codes according to
        the stored mapping.

        strip_ansi flag instead removes all ansi markup.

        """
        if hasattr(string, '_raw_string'):
            if strip_ansi:
                return string.clean()
            else:
                return string.raw()

        if not string:
            return ''

        # check cached parsings
        global _PARSE_CACHE
        cachekey = "%s-%s-%s" % (string, strip_ansi, xterm256)
        if cachekey in _PARSE_CACHE:
            return _PARSE_CACHE[cachekey]

        self.do_xterm256 = xterm256
        self.do_mxp = mxp
        in_string = utils.to_str(string)

        # do string replacement
        parsed_string =  ""
        parts = self.ansi_escapes.split(in_string) + [" "]
        for part, sep in zip(parts[::2], parts[1::2]):
            pstring = self.xterm256_sub.sub(self.sub_xterm256, part)
            pstring = self.ansi_sub.sub(self.sub_ansi, pstring)
            parsed_string += "%s%s" % (pstring, sep[0].strip())

        if strip_ansi:
            # remove all ansi codes (including those manually
            # inserted in string)
            parsed_string = self.strip_mxp(parsed_string)
            return self.strip_raw_codes(parsed_string)

        if not mxp:
            parsed_string = self.strip_mxp(parsed_string)

         # cache and crop old cache
        _PARSE_CACHE[cachekey] = parsed_string
        if len(_PARSE_CACHE) > _PARSE_CACHE_SIZE:
           _PARSE_CACHE.popitem(last=False)

        return parsed_string
Example #40
0
    def parse_ansi(self, string, strip_ansi=False, xterm256=False, mxp=False):
        """
        Parses a string, subbing color codes according to
        the stored mapping.

        strip_ansi flag instead removes all ansi markup.

        """
        if hasattr(string, '_raw_string'):
            if strip_ansi:
                return string.clean()
            else:
                return string.raw()

        if not string:
            return ''

        # check cached parsings
        global _PARSE_CACHE
        cachekey = "%s-%s-%s" % (string, strip_ansi, xterm256)
        if cachekey in _PARSE_CACHE:
            return _PARSE_CACHE[cachekey]

        self.do_xterm256 = xterm256
        self.do_mxp = mxp
        in_string = utils.to_str(string)

        # do string replacement
        parsed_string = ""
        parts = self.ansi_escapes.split(in_string) + [" "]
        for part, sep in zip(parts[::2], parts[1::2]):
            pstring = self.xterm256_sub.sub(self.sub_xterm256, part)
            pstring = self.ansi_sub.sub(self.sub_ansi, pstring)
            parsed_string += "%s%s" % (pstring, sep[0].strip())

        if strip_ansi:
            # remove all ansi codes (including those manually
            # inserted in string)
            parsed_string = self.strip_mxp(parsed_string)
            return self.strip_raw_codes(parsed_string)

        if not mxp:
            parsed_string = self.strip_mxp(parsed_string)

        # cache and crop old cache
        _PARSE_CACHE[cachekey] = parsed_string
        if len(_PARSE_CACHE) > _PARSE_CACHE_SIZE:
            _PARSE_CACHE.popitem(last=False)

        return parsed_string
Example #41
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 #42
0
    def __init__(self, filename=None, cells=None, tables=None, form=None, **kwargs):
        """
        Initiate the form

        keywords:
            filename - path to template file
            form - dictionary of {"CELLCHAR":char,
                                  "TABLECHAR":char,
                                  "FORM":templatestring}
                    if this is given, filename is not read.
            cells - a dictionary mapping of {id:text}
            tables -  dictionary mapping of {id:EvTable}

        other kwargs are fed as options to the EvCells and EvTables
        (see evtablet.EvCell and evtable.EvTable for more info).

        """
        self.filename = filename
        self.input_form_dict = form

        self.cells_mapping =  dict((to_str(key, force_string=True), value) for key, value in cells.items()) if cells  else {}
        self.tables_mapping = dict((to_str(key, force_string=True), value) for key, value in tables.items()) if tables else {}

        self.cellchar = "x"
        self.tablechar = "c"

        self.raw_form = []
        self.form = []

        # clean kwargs (these cannot be overridden)
        kwargs.pop("enforce_size", None)
        kwargs.pop("width", None)
        kwargs.pop("height", None)
        # table/cell options
        self.options = kwargs

        self.reload()
Example #43
0
    def __new__(cls, *args, **kwargs):
        """
        When creating a new ANSIString, you may use a custom parser that has
        the same attributes as the standard one, and you may declare the
        string to be handled as already decoded. It is important not to double
        decode strings, as escapes can only be respected once.
        """
        string = args[0]
        if not isinstance(string, basestring):
            string = to_str(string, force_string=True)
        parser = kwargs.get('parser', ANSI_PARSER)
        decoded = kwargs.get('decoded', False) or hasattr(
            string, '_raw_string')
        if not decoded:
            # Completely new ANSI String
            clean_string = to_unicode(
                parser.parse_ansi(string, strip_ansi=True))
            string = parser.parse_ansi(string)
        elif hasattr(string, '_clean_string'):
            # It's already an ANSIString
            clean_string = string._clean_string
            string = string._raw_string
        else:
            # It's a string that has been pre-ansi decoded.
            clean_string = parser.strip_raw_codes(string)

        if not isinstance(string, unicode):
            string = string.decode('utf-8')
        else:
            # Do this to prevent recursive ANSIStrings.
            string = unicode(string)
        ansi_string = super(ANSIString, cls).__new__(ANSIString,
                                                     to_str(clean_string),
                                                     "utf-8")
        ansi_string._raw_string = string
        ansi_string._clean_string = clean_string
        return ansi_string
Example #44
0
    def data_out(self, text=None, **kwargs):
        """
        Data Evennia -> Player access hook. 'data' argument is a dict
        parsed for string settings.

        ssh flags:
            raw=True - leave all ansi markup and tokens unparsed
            nomarkup=True - remove all ansi markup

        """
        try:
            text = utils.to_str(text if text else "", encoding=self.encoding)
        except Exception, e:
            self.lineSend(str(e))
            return
Example #45
0
    def reload(self, filename=None, form=None, **kwargs):
        """
        Creates the form from a stored file name
        """
        # clean kwargs (these cannot be overridden)
        kwargs.pop("enforce_size", None)
        kwargs.pop("width", None)
        kwargs.pop("height", None)

        if form or self.input_form_dict:
            datadict = form if form else self.input_form_dict
            self.input_form_dict = datadict
        elif filename or self.filename:
            filename = filename if filename else self.filename
            datadict = all_from_module(filename)
            self.filename = filename
        else:
            datadict = {}

        cellchar = to_str(datadict.get("FORMCHAR", "x"))
        self.cellchar = to_str(cellchar[0] if len(cellchar) > 1 else cellchar)
        tablechar = datadict.get("TABLECHAR", "c")
        self.tablechar = tablechar[0] if len(tablechar) > 1 else tablechar

        # split into a list of list of lines. Form can be indexed with form[iy][ix]
        self.raw_form = _to_ansi(
            to_unicode(datadict.get("FORM", "")).split("\n"))
        # strip first line
        self.raw_form = self.raw_form[1:] if self.raw_form else self.raw_form

        self.options.update(kwargs)

        # parse and replace
        self.mapping = self._parse_rectangles(self.cellchar, self.tablechar,
                                              self.raw_form, **kwargs)
        self.form = self._populate_form(self.raw_form, self.mapping)
Example #46
0
    def data_out(self, text=None, **kwargs):
        """
        Data Evennia -> Player.
        generic hook method for engine to call in order to send data
        through the websocket connection.

        valid webclient kwargs:
            oob=<string> - supply an Out-of-Band instruction.
            raw=True - no parsing at all (leave ansi-to-html markers unparsed)
            nomarkup=True - clean out all ansi/html markers and tokens
        """
        try:
            text = to_str(text if text else "", encoding=self.encoding)
        except Exception, e:
            self.sendLine(str(e))
Example #47
0
 def call_remote_MsgServer2Portal(self, sessid, msg, data=""):
     """
     Access method called by the Server and executed on the Server.
     """
     #print "msg server->portal (server side):", sessid, msg, data
     try:
         return self.callRemote(MsgServer2Portal,
                         sessid=sessid,
                         msg=to_str(msg),
                         ipart=0,
                         nparts=1,
                         data=dumps(data)).addErrback(self.errback, "OOBServer2Portal")
     except amp.TooLong:
         # the msg (or data) was too long for AMP to send. We need to send in blocks.
         return self.send_split_msg(sessid, msg, data, MsgServer2Portal)
Example #48
0
    def data_out(self, text=None, **kwargs):
        """
        Data Evennia -> Player.
        generic hook method for engine to call in order to send data
        through the websocket connection.

        valid webclient kwargs:
            oob=<string> - supply an Out-of-Band instruction.
            raw=True - no parsing at all (leave ansi-to-html markers unparsed)
            nomarkup=True - clean out all ansi/html markers and tokens
        """
        try:
            text = to_str(text if text else "", encoding=self.encoding)
        except Exception, e:
            self.sendLine(str(e))
Example #49
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 #50
0
def hashid(obj, suffix=""):
    """
    Returns a per-class unique hash that combines the object's
    class name with its idnum and creation time. This makes this id unique also
    between different typeclassed entities such as scripts and
    objects (which may still have the same id).
    """
    if not obj:
        return obj
    try:
        hid = _GA(obj, "_hashid")
    except AttributeError:
        try:
            date, idnum = _GA(obj,
                              "db_date_created").strftime(_DATESTRING), _GA(
                                  obj, "id")
        except AttributeError:
            try:
                # maybe a typeclass, try to go to dbobj
                obj = _GA(obj, "dbobj")
                date, idnum = _GA(
                    obj,
                    "db_date_created").strftime(_DATESTRING), _GA(obj, "id")
            except AttributeError:
                # this happens if hashing something like ndb. We have to
                # rely on memory adressing in this case.
                date, idnum = "InMemory", id(obj)
        if not idnum or not date:
            # this will happen if setting properties on an object which
            # is not yet saved
            return None
        # we have to remove the class-name's space, for eventual use
        # of memcached
        hid = "%s-%s-#%s" % (_GA(obj, "__class__"), date, idnum)
        hid = hid.replace(" ", "")
        # we cache the object part of the hashid to avoid too many
        # object lookups
        _SA(obj, "_hashid", hid)
    # build the complete hashid
    hid = "%s%s" % (hid, suffix)
    return to_str(hid)
Example #51
0
    def data_out(self, text=None, **kwargs):
        """
        Data Evennia -> Player access hook.

        webclient flags checked are
        raw=True - no parsing at all (leave ansi-to-html markers unparsed)
        nomarkup=True - clean out all ansi/html markers and tokens

        """
        # string handling is similar to telnet
        try:
            text = utils.to_str(text if text else "", encoding=self.encoding)
            raw = kwargs.get("raw", False)
            nomarkup = kwargs.get("nomarkup", False)
            if raw:
                self.client.lineSend(self.suid, text)
            else:
                self.client.lineSend(self.suid,
                                     parse_html(text, strip_ansi=nomarkup))
            return
        except Exception:
            logger.log_trace()
Example #52
0
    def forwards(self, orm):
        "Write your forwards methods here."

        # Note: Remember to use orm['appname.ModelName'] rather than "from appname.models..."

        # modified for migration - converts to plain python properties
        def from_attr(datatuple):
            """
            Retrieve data from a previously stored attribute. This
            is always a dict with keys type and data.

            datatuple comes from the database storage and has
            the following format:
               (simple|dbobj|iter, <data>)
            where
                simple - a single non-db object, like a string. is returned as-is.
                dbobj - a single dbobj-id. This id is retrieved back from the database.
                iter - an iterable. This is traversed iteratively, converting all found
                       dbobj-ids back to objects. Also, all lists and dictionaries are
                       returned as their PackedList/PackedDict counterparts in order to
                       allow in-place assignment such as obj.db.mylist[3] = val. Mylist
                       is then a PackedList that saves the data on the fly.
            """

            # nested functions
            def id2db(data):
                """
                Convert db-stored dbref back to object
                """
                mclass = CTYPEGET(model=data.db_model).model_class()
                try:
                    return mclass.objects.get(id=data.id)

                except AttributeError:
                    try:
                        return mclass.objects.get(id=data.id)
                    except mclass.DoesNotExist:  # could happen if object was deleted in the interim.
                        return None

            def iter_id2db(item):
                """
                Recursively looping through stored iterables, replacing ids with actual objects.
                We return PackedDict and PackedLists instead of normal lists; this is needed in order for
                the user to do dynamic saving of nested in-place, such as obj.db.attrlist[2]=3. What is
                stored in the database are however always normal python primitives.
                """
                dtype = type(item)
                if dtype in (
                        basestring, int, float, long,
                        bool):  # check the most common types first, for speed
                    return item
                elif dtype == PackedDBobject or hasattr(
                        item, '__class__'
                ) and item.__class__.__name__ == "PackedDBobject":
                    return id2db(item)
                elif dtype == tuple:
                    return tuple([iter_id2db(val) for val in item])
                elif dtype in (dict, PackedDict):
                    return dict(
                        zip([key for key in item.keys()],
                            [iter_id2db(val) for val in item.values()]))
                elif hasattr(item, '__iter__'):
                    return list(iter_id2db(val) for val in item)
                else:
                    return item

            typ, data = datatuple

            if typ == 'simple':
                # single non-db objects
                return data
            elif typ == 'dbobj':
                # a single stored dbobj
                return id2db(data)
            elif typ == 'iter':
                # all types of iterables
                return iter_id2db(data)

        if not db.dry_run:
            for attr in orm['players.PlayerAttribute'].objects.all():
                # repack attr into new format and reimport
                datatuple = loads(to_str(attr.db_value))
                python_data = from_attr(datatuple)
                new_data = to_pickle(python_data)
                attr.db_value2 = new_data  # new pickleObjectField
                attr.save()

        def backwards(self, orm):
            "Write your backwards methods here."
            raise RuntimeError("This migration cannot be reversed.")
Example #53
0
def jsonify(obj):
    return utils.to_str(json.dumps(obj, ensure_ascii=False, cls=LazyEncoder))
Example #54
0
from src.utils.utils import to_str

# MSDP-relevant telnet cmd/opt-codes
MSDP = chr(69)
MSDP_VAR = chr(1)
MSDP_VAL = chr(2)
MSDP_TABLE_OPEN = chr(3)
MSDP_TABLE_CLOSE = chr(4)
MSDP_ARRAY_OPEN = chr(5)
MSDP_ARRAY_CLOSE = chr(6)

IAC = chr(255)
SB = chr(250)
SE = chr(240)

force_str = lambda inp: to_str(inp, force_string=True)

# pre-compiled regexes
# returns 2-tuple
regex_array = re.compile(
    r"%s(.*?)%s%s(.*?)%s" %
    (MSDP_VAR, MSDP_VAL, MSDP_ARRAY_OPEN, MSDP_ARRAY_CLOSE))
# returns 2-tuple (may be nested)
regex_table = re.compile(
    r"%s(.*?)%s%s(.*?)%s" %
    (MSDP_VAR, MSDP_VAL, MSDP_TABLE_OPEN, MSDP_TABLE_CLOSE))
regex_var = re.compile(MSDP_VAR)
regex_val = re.compile(MSDP_VAL)

# Msdp object handler
Example #55
0
    Sent when either process needs to call an
    arbitrary function in the other.
    """
    key = "FunctionCall"
    arguments = [('module', amp.String()),
                 ('function', amp.String()),
                 ('args', amp.String()),
                 ('kwargs', amp.String())]
    errors = [(Exception, 'EXCEPTION')]
    response = [('result', amp.String())]


# Helper functions

dumps = lambda data: to_str(pickle.dumps(data, pickle.HIGHEST_PROTOCOL))
loads = lambda data: pickle.loads(to_str(data))

# multipart message store



#------------------------------------------------------------
# Core AMP protocol for communication Server <-> Portal
#------------------------------------------------------------

class AMPProtocol(amp.AMP):
    """
    This is the protocol that the MUD server and the proxy server
    communicate to each other with. AMP is a bi-directional protocol, so
    both the proxy and the MUD use the same commands and protocol.
Example #56
0
def do_pickle(data):
    "Perform pickle to string"
    return to_str(dumps(data, protocol=PICKLE_PROTOCOL))
Example #57
0
def do_unpickle(data):
    "Retrieve pickle from pickled string"
    return loads(to_str(data))
Example #58
0
def run_async(to_execute, *args, **kwargs):
    """
    Runs a function or executes a code snippet asynchronously.

    Inputs:
    to_execute (callable) - if this is a callable, it will
            be executed with *args and non-reserver *kwargs as
            arguments.
            The callable will be executed using ProcPool, or in
            a thread if ProcPool is not available.
    to_execute (string) - this is only available is ProcPool is
            running. If a string, to_execute this will be treated as a code
            snippet to execute asynchronously. *args are then not used
            and non-reserverd *kwargs are used to define the execution
            environment made available to the code.

    reserved kwargs:
        'use_thread' (bool) - this only works with callables (not code).
                     It forces the code to run in a thread instead
                     of using the Process Pool, even if the latter
                     is available. This could be useful if you want
                     to make sure to not get out of sync with the
                     main process (such as accessing in-memory global
                     properties)
        'proc_timeout' (int) - only used if ProcPool is available. Sets a
                     max time for execution. This alters the value set
                     by settings.PROCPOOL_TIMEOUT
        'at_return' -should point to a callable with one argument.
                    It will be called with the return value from
                    to_execute.
        'at_return_kwargs' - this dictionary which be used as keyword
                             arguments to the at_return callback.
        'at_err' - this will be called with a Failure instance if
                       there is an error in to_execute.
        'at_err_kwargs' - this dictionary will be used as keyword
                          arguments to the at_err errback.
        'procpool_name' - the Service name of the procpool to use.
                          Default is PythonProcPool.

    *args   - if to_execute is a callable, these args will be used
              as arguments for that function. If to_execute is a string
              *args are not used.
    *kwargs - if to_execute is a callable, these kwargs will be used
              as keyword arguments in that function. If a string, they
              instead are used to define the executable environment
              that should be available to execute the code in to_execute.

    run_async will either relay the code to a thread or to a processPool
    depending on input and what is available in the system. To activate
    Process pooling, settings.PROCPOOL_ENABLE must be set.

    to_execute in string form should handle all imports needed. kwargs
    can be used to send objects and properties. Such properties will
    be pickled, except Database Objects which will be sent across
    on a special format and re-loaded on the other side.

    To get a return value from your code snippet, Use the _return()
    function: Every call to this function from your snippet will
    append the argument to an internal list of returns. This return value
    (or a list) will be the first argument to the at_return callback.

    Use this function with restrain and only for features/commands
    that you know has no influence on the cause-and-effect order of your
    game (commands given after the async function might be executed before
    it has finished). Accessing the same property from different
    threads/processes can lead to unpredicted behaviour if you are not
    careful (this is called a "race condition").

    Also note that some databases, notably sqlite3, don't support access from
    multiple threads simultaneously, so if you do heavy database access from
    your to_execute under sqlite3 you will probably run very slow or even get
    tracebacks.

    """
    # handle all global imports.
    global _PPOOL, _SESSIONS

    # get the procpool name, if set in kwargs
    procpool_name = kwargs.get("procpool_name", "PythonProcPool")

    if _PPOOL is None:
        # Try to load process Pool
        from src.server.sessionhandler import SESSIONS as _SESSIONS
        try:
            _PPOOL = _SESSIONS.server.services.namedServices.get(
                procpool_name).pool
        except AttributeError:
            _PPOOL = False

    use_timeout = kwargs.pop("proc_timeout", _PPOOL.timeout)

    # helper converters for callbacks/errbacks
    def convert_return(f):
        def func(ret, *args, **kwargs):
            rval = ret["response"] and from_pickle(do_unpickle(
                ret["response"]))
            reca = ret["recached"] and from_pickle(do_unpickle(
                ret["recached"]))
            # recache all indicated objects
            [clean_object_caches(obj) for obj in reca]
            if f:
                return f(rval, *args, **kwargs)
            else:
                return rval

        return func

    def convert_err(f):
        def func(err, *args, **kwargs):
            err.trap(Exception)
            err = err.getErrorMessage()
            if use_timeout and err == _PROC_ERR:
                err = "Process took longer than %ss and timed out." % use_timeout
            if f:
                return f(err, *args, **kwargs)
            else:
                err = "Error reported from subprocess: '%s'" % err
                logger.log_errmsg(err)

        return func

    # handle special reserved input kwargs
    use_thread = kwargs.pop("use_thread", False)
    callback = convert_return(kwargs.pop("at_return", None))
    errback = convert_err(kwargs.pop("at_err", None))
    callback_kwargs = kwargs.pop("at_return_kwargs", {})
    errback_kwargs = kwargs.pop("at_err_kwargs", {})

    if _PPOOL and not use_thread:
        # process pool is running
        if isinstance(to_execute, basestring):
            # run source code in process pool
            cmdargs = {"_timeout": use_timeout}
            cmdargs["source"] = to_str(to_execute)
            if kwargs:
                cmdargs["environment"] = do_pickle(to_pickle(kwargs))
            else:
                cmdargs["environment"] = ""
            # defer to process pool
            deferred = _PPOOL.doWork(ExecuteCode, **cmdargs)
        elif callable(to_execute):
            # execute callable in process
            callname = to_execute.__name__
            cmdargs = {"_timeout": use_timeout}
            cmdargs["source"] = "_return(%s(*args,**kwargs))" % callname
            cmdargs["environment"] = do_pickle(
                to_pickle({
                    callname: to_execute,
                    "args": args,
                    "kwargs": kwargs
                }))
            deferred = _PPOOL.doWork(ExecuteCode, **cmdargs)
        else:
            raise RuntimeError(
                "'%s' could not be handled by the process pool" % to_execute)
    elif callable(to_execute):
        # no process pool available, fall back to old deferToThread mechanism.
        deferred = threads.deferToThread(to_execute, *args, **kwargs)
    else:
        # no appropriate input for this server setup
        raise RuntimeError(
            "'%s' could not be handled by run_async - no valid input or no process pool."
            % to_execute)

    # attach callbacks
    if callback:
        deferred.addCallback(callback, **callback_kwargs)
    deferred.addErrback(errback, **errback_kwargs)