Python-Gitlab - Reset iterator on RestobjectList

Hello,

I am iterating over a branch list multiple times and it seems that the pointer needs to be reset.

Python-gitlab v3.12.0

e.g.
branchlist = self.project.branches.list(iterator=True)
m_branchlist = [i for i in branchlist if (i.merged==True)]
p_branchlist = [i for i in branchlist if (i.protected==True)]

p_branchlist will be empty as it seems the pointer is at end of list.

Is there a way to reset pointer?

1 Like
branchlist = self.project.branches.list(iterator=True)

will return a list that is iterated through until the end. Depending on the lazy setting, you either get a full object in each loop cycle, or a lazy-loaded object that needs to get the real object first to do more. Getting the object includes a REST API call in the background.

A boring solution can be to re-initialize the branchlist again after processing all items. For said reasons above, I’d advocate against it to save API calls and CPU time. Instead, collect all required data into a temporary array, and use Python’s .items() to iterate a dictionary, or loop directory through a list of collected object.

Something like this:

#!/usr/bin/env python

# Description: Fetch all branches from a given project ID, and showcase different merge state filters.
# Requirements: python-gitlab Python libraries. GitLab API read access, and maintainer access to all configured groups/projects.
# Author: Michael Friedrich <mfriedrich@gitlab.com>
# License: MIT, (c) 2023-present GitLab B.V.

import gitlab
import os
import sys

GITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com')
# https://gitlab.com/dnsmichi/opsindev.news
PROJECT_ID = os.environ.get('GL_PROJECT_ID', 33298437)
GITLAB_TOKEN = os.environ.get('GL_TOKEN')

if not GITLAB_TOKEN:
    print("Please set the GL_TOKEN env variable.")
    sys.exit(1)

gl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN)

# Main
project = gl.projects.get(PROJECT_ID, lazy=False, pagination="keyset", order_by="updated_at", per_page=100)

# Get all branches
real_branches = []
for branch in project.branches.list():
    real_branches.append(branch)
    # print(branch) # debug

print("All branches")
for rb in real_branches:
    print("Branch: {b}".format(b=rb.name))

# Get all merged branches
merged_branches_names = []
for branch in real_branches:
    if branch.default:
        continue # ignore the default branch for merge status

    if branch.merged:
        merged_branches_names.append(branch.name)

print("Branches merged: {b}".format(b=", ".join(merged_branches_names)))

# Get un-merged branches
not_merged_branches_names = []
for branch in real_branches:
    if branch.default:
        continue # ignore the default branch for merge status

    if not branch.merged:
        not_merged_branches_names.append(branch.name)

print("Branches not merged: {b}".format(b=", ".join(not_merged_branches_names)))

resulting in

GL_TOKEN=$GITLAB_TOKEN python3 get_branches_by_state.py                            ─╯
All branches
Branch: main
Branch: test-branch
Branches merged:
Branches not merged: test-branch

Script will be living in get_branches_by_state.py · main · Developer Evangelism at GitLab / use-cases / GitLab API / GitLab API with Python · GitLab and soon in an blog post that I am writing.

This also helps answer Python-gitlab - project.branch.list filter - #2 by dnsmichi about how to filter branch lists.

2 Likes