code: def user_groups(self, ldap_user, group_search):
          
          group_info_map = {}  # Maps group_dn to group_info of groups we've found
          member_dn_set = {ldap_user.dn}  # Member DNs to search with next
          handled_dn_set = set()  # Member DNs that we've already searched with
  
          while len(member_dn_set) > 0:
              group_infos = self.find_groups_with_any_member(
                  member_dn_set, group_search, ldap_user.connection
              )
              new_group_info_map = {info[0]: info for info in group_infos}
              group_info_map.update(new_group_info_map)
              handled_dn_set.update(member_dn_set)
  
              # Get ready for the next iteration. To avoid cycles, we make sure
              # never to search with the same member DN twice.
              member_dn_set = set(new_group_info_map.keys()) - handled_dn_set
  
          return group_info_map.values()
docs: This searches for all of a user's groups from the bottom up. In other
          words, it returns the groups that the user belongs to, the groups that
          those groups belong to, etc. Circular references will be detected and
          pruned.