# Buggy code
def move_to(
    self,
    destination,
    quiet=False,
    emit_to_obj=None,
    use_destination=True,
    to_none=False,
    move_hooks=True,
):
    """
    Moves this object to a new location.

    Args:
        destination (Object): Reference to the object to move to. This
            can also be an exit object, in which case the
            destination property is used as destination.
        quiet (bool): If true, turn off the calling of the emit hooks
            (announce_move_to/from etc)
        emit_to_obj (Object): object to receive error messages
        use_destination (bool): Default is for objects to use the "destination"
             property of destinations as the target to move to. Turning off this
             keyword allows objects to move "inside" exit objects.
        to_none (bool): Allow destination to be None. Note that no hooks are run when
             moving to a None location. If you want to run hooks, run them manually
             (and make sure they can manage None locations).
        move_hooks (bool): If False, turn off the calling of move-related hooks
            (at_before/after_move etc) with quiet=True, this is as quiet a move
            as can be done.

    Returns:
        result (bool): True/False depending on if there were problems with the move.
                This method may also return various error messages to the
                `emit_to_obj`.

    Notes:
        No access checks are done in this method, these should be handled before
        calling `move_to`.

        The `DefaultObject` hooks called (if `move_hooks=True`) are, in order:

         1. `self.at_before_move(destination)` (if this returns False, move is aborted)
         2. `source_location.at_object_leave(self, destination)`
         3. `self.announce_move_from(destination)`
         4. (move happens here)
         5. `self.announce_move_to(source_location)`
         6. `destination.at_object_receive(self, source_location)`
         7. `self.at_after_move(source_location)`

    """

    def logerr(string=""):
        "Simple log helper method"
        logger.log_trace()
        self.msg(string)

    errtxt = _("Couldn't perform move ('%s'). Contact an admin.")
    if not emit_to_obj:
        emit_to_obj = self

    if not destination:
        if to_none:
            # immediately move to None. There can be no hooks called since
            # there is no destination to call them with.
            self.location = None
            return True
        emit_to_obj.msg(_("The destination doesn't exist."))
        return
    if destination.destination and use_destination:
        # traverse exits
        destination = destination.destination

    # Before the move, call eventual pre-commands.
    if move_hooks:
        try:
            if not self.at_before_move(destination):
                return
        except Exception:
            logerr(errtxt % "at_before_move()")
            return False

    # Save the old location
    source_location = self.location
    if not source_location:
        # there was some error in placing this room.
        # we have to set one or we won't be able to continue
        if self.home:
            source_location = self.home
        else:
            default_home = ObjectDB.objects.get_id(settings.DEFAULT_HOME)
            source_location = default_home

    # Call hook on source location
    if move_hooks:
        try:
            source_location.at_object_leave(self, destination)
        except Exception:
            logerr(errtxt % "at_object_leave()")
            return False

    if not quiet:
        # tell the old room we are leaving
        try:
            self.announce_move_from(destination)
        except Exception:
            logerr(errtxt % "at_announce_move()")
            return False

    # Perform move
    try:
        self.location = destination
    except Exception:
        emit_to_obj.msg(errtxt % "location change")
        logger.log_trace()
        return False

    if not quiet:
        # Tell the new room we are there.
        try:
            self.announce_move_to(source_location)
        except Exception:
            logerr(errtxt % "announce_move_to()")
            return False

    if move_hooks:
        # Perform eventual extra commands on the receiving location
        # (the object has already arrived at this point)
        try:
            destination.at_object_receive(self, source_location)
        except Exception:
            logerr(errtxt % "at_object_receive()")
            return False

    # Execute eventual extra commands on this object after moving it
    # (usually calling 'look')
    if move_hooks:
        try:
            self.at_after_move(source_location)
        except Exception:
            logerr(errtxt % "at_after_move")
            return False
    return True


# Traceback (RuntimeError)
Error: TestSubject.location = TestObject creates a location loop.
Traceback (most recent call last):
File "evennia/evennia/objects/objects.py", line 654, in move_to
self.location = destination
File "/evennia/evennia/objects/models.py", line 249, in __location_set
is_loc_loop(location)
File "/evennia/evennia/objects/models.py", line 247, in is_loc_loop
return is_loc_loop(loc.db_location, depth + 1)
File "/evennia/evennia/objects/models.py", line 244, in is_loc_loop
raise RuntimeError
RuntimeError

# Fixed code
def move_to(
    self,
    destination,
    quiet=False,
    emit_to_obj=None,
    use_destination=True,
    to_none=False,
    move_hooks=True,
):
    """
    Moves this object to a new location.

    Args:
        destination (Object): Reference to the object to move to. This
            can also be an exit object, in which case the
            destination property is used as destination.
        quiet (bool): If true, turn off the calling of the emit hooks
            (announce_move_to/from etc)
        emit_to_obj (Object): object to receive error messages
        use_destination (bool): Default is for objects to use the "destination"
             property of destinations as the target to move to. Turning off this
             keyword allows objects to move "inside" exit objects.
        to_none (bool): Allow destination to be None. Note that no hooks are run when
             moving to a None location. If you want to run hooks, run them manually
             (and make sure they can manage None locations).
        move_hooks (bool): If False, turn off the calling of move-related hooks
            (at_before/after_move etc) with quiet=True, this is as quiet a move
            as can be done.

    Returns:
        result (bool): True/False depending on if there were problems with the move.
                This method may also return various error messages to the
                `emit_to_obj`.

    Notes:
        No access checks are done in this method, these should be handled before
        calling `move_to`.

        The `DefaultObject` hooks called (if `move_hooks=True`) are, in order:

         1. `self.at_before_move(destination)` (if this returns False, move is aborted)
         2. `source_location.at_object_leave(self, destination)`
         3. `self.announce_move_from(destination)`
         4. (move happens here)
         5. `self.announce_move_to(source_location)`
         6. `destination.at_object_receive(self, source_location)`
         7. `self.at_after_move(source_location)`

    """

    def logerr(string="", err=None):
        "Simple log helper method"
        logger.log_trace()
        self.msg("%s%s" % (string, "" if err is None else " (%s)" % err))

    errtxt = _("Couldn't perform move ('%s'). Contact an admin.")
    if not emit_to_obj:
        emit_to_obj = self

    if not destination:
        if to_none:
            # immediately move to None. There can be no hooks called since
            # there is no destination to call them with.
            self.location = None
            return True
        emit_to_obj.msg(_("The destination doesn't exist."))
        return
    if destination.destination and use_destination:
        # traverse exits
        destination = destination.destination

    # Before the move, call eventual pre-commands.
    if move_hooks:
        try:
            if not self.at_before_move(destination):
                return
        except Exception as err:
            logerr(errtxt % "at_before_move()", err)
            return False

    # Save the old location
    source_location = self.location
    if not source_location:
        # there was some error in placing this room.
        # we have to set one or we won't be able to continue
        if self.home:
            source_location = self.home
        else:
            default_home = ObjectDB.objects.get_id(settings.DEFAULT_HOME)
            source_location = default_home

    # Call hook on source location
    if move_hooks:
        try:
            source_location.at_object_leave(self, destination)
        except Exception as err:
            logerr(errtxt % "at_object_leave()", err)
            return False

    if not quiet:
        # tell the old room we are leaving
        try:
            self.announce_move_from(destination)
        except Exception as err:
            logerr(errtxt % "at_announce_move()", err)
            return False

    # Perform move
    try:
        self.location = destination
    except Exception as err:
        logerr(errtxt % "location change", err)
        return False

    if not quiet:
        # Tell the new room we are there.
        try:
            self.announce_move_to(source_location)
        except Exception as err:
            logerr(errtxt % "announce_move_to()", err)
            return False

    if move_hooks:
        # Perform eventual extra commands on the receiving location
        # (the object has already arrived at this point)
        try:
            destination.at_object_receive(self, source_location)
        except Exception as err:
            logerr(errtxt % "at_object_receive()", err)
            return False

    # Execute eventual extra commands on this object after moving it
    # (usually calling 'look')
    if move_hooks:
        try:
            self.at_after_move(source_location)
        except Exception as err:
            logerr(errtxt % "at_after_move", err)
            return False
    return True