The following code implements a loop-check for objects in roundup (not just issues) that refer to the same type of object via a link or multilink property. The code is intended to be called by an auditor. The first parameter is a gettext method for localisation of the error message in Reject. The other paramerts are cl: roundup class, id: id of the current item (can be None for a new item), prop: the name of the link or multilink property of the class for which no loop should occur, and attr: the contents of the prop attribute of the current item. The parameter ids is only used for recursive calls of the function:

 from   roundup.hyperdb    import String, Link, Multilink
 def check_loop (_, cl, id, prop, attr, ids = []) :
     is_multi = isinstance (cl.properties [prop], Multilink)
     assert (is_multi or isinstance (cl.properties [prop], Link))
     label = cl.labelprop ()
     if id :
         ids.append (id)
     if attr :
         if not is_multi :
             attr = [attr]
         for a in attr :
             if a in ids :
                 raise Reject, _ ("%s loop: %s") % \
                     (_ (prop), ','.join ([cl.get (i, label) for i in ids]))
             check_loop (_, cl, a, prop, cl.get (a, prop), ids)
             ids.pop ()
 # end def check_loop

Usage example: Say, we have a supervisor attribute in the user class. Now we want to check that there is no supervisor-loop (one person being supervised by him or herself recursively). We'd call the following in an auditor for the user class:

    if 'supervisor' in new_values :
        check_loop (_, cl, nodeid, 'supervisor', new_values ['supervisor'])