# Buggy code
def msg(self, text=None, from_obj=None, session=None, options=None, **kwargs):
    """
    Evennia -> User
    This is the main route for sending data back to the user from the
    server.

    Args:
        text (str, optional): text data to send
        from_obj (Object or Player, optional): Object sending. If given,
            its at_msg_send() hook will be called.
        session (Session or list, optional): Session object or a list of
            Sessions to receive this send. If given, overrules the
            default send behavior for the current
            MULTISESSION_MODE.
        options (list): Protocol-specific options. Passed on to the protocol.
    Kwargs:
        any (dict): All other keywords are passed on to the protocol.

    """
    if from_obj:
        # call hook
        try:
            from_obj.at_msg_send(text=text, to_obj=self, **kwargs)
        except Exception:
            pass
    try:
        if not self.at_msg_receive(text=text, **kwargs):
            # abort message to this player
            return
    except Exception:
        pass

    kwargs["options"] = options

    # session relay
    sessions = make_iter(session) if session else self.sessions.all()
    for session in sessions:
        session.data_out(text=text, **kwargs)


# Traceback (AttributeError)
Traceback (most recent call last):
File "/evennia/evennia/commands/cmdhandler.py", line 464, in _run_command
ret = yield cmd.func()
File "/evennia/evennia/commands/default/building.py", line 1807, in func
caller.msg(obj.locks)
File "/evennia/evennia/objects/objects.py", line 509, in msg
session.data_out(text=text, **kwargs)
File "/evennia/evennia/server/serversession.py", line 362, in data_out
self.sessionhandler.data_out(self, **kwargs)
File "/evennia/evennia/server/sessionhandler.py", line 621, in data_out
**kwargs)
File "/evennia/evennia/server/amp.py", line 467, in send_MsgServer2Portal
return self.send_data(MsgServer2Portal, session.sessid, **kwargs)
File "/evennia/evennia/server/amp.py", line 406, in send_data
packed_data=dumps((sessid, kwargs))
File "/evennia/evennia/server/amp.py", line 319, in <lambda>
dumps = lambda data: to_str(pickle.dumps(to_str(data), pickle.HIGHEST_PROTOCOL))
File "/pyenv/local/lib/python2.7/site-packages/twisted/persisted/styles.py", line 119, in _pickleFunction
tuple([".".join([f.__module__, f.__qualname__])]))
AttributeError: 'function' object has no attribute '__qualname__'

# Fixed code
def msg(self, text=None, from_obj=None, session=None, options=None, **kwargs):
    """
    Evennia -> User
    This is the main route for sending data back to the user from the
    server.

    Args:
        text (str, optional): text data to send
        from_obj (Object or Player, optional): Object sending. If given,
            its at_msg_send() hook will be called.
        session (Session or list, optional): Session object or a list of
            Sessions to receive this send. If given, overrules the
            default send behavior for the current
            MULTISESSION_MODE.
        options (list): Protocol-specific options. Passed on to the protocol.
    Kwargs:
        any (dict): All other keywords are passed on to the protocol.

    """
    if from_obj:
        # call hook
        try:
            from_obj.at_msg_send(text=text, to_obj=self, **kwargs)
        except Exception:
            pass
    try:
        if not self.at_msg_receive(text=text, **kwargs):
            # abort message to this player
            return
    except Exception:
        pass

    text = None if text is None else str(text)
    kwargs["options"] = options

    # session relay
    sessions = make_iter(session) if session else self.sessions.all()
    for session in sessions:
        session.data_out(text=text, **kwargs)