Python client for the GitLab API
Project description
qodev-gitlab-api
A lightweight, typed Python client for the GitLab REST API. Built on httpx with automatic pagination, structured error handling, and .env support, it provides a clean interface for common GitLab operations without the weight of a full-featured SDK.
Why this library?
- Lightweight -- just
httpx, no heavy ORM-like abstractions - Typed -- ships with
py.typedfor full mypy/pyright support - Agent-friendly -- simple method signatures, dict returns, auto-pagination
- Built for tools -- designed for MCP servers and CLIs, not full application frameworks
- Focused --
python-gitlabis comprehensive but heavy; this library covers the operations AI agents and developer tools actually need
Installation
pip install qodev-gitlab-api
Quick Start
from qodev_gitlab_api import GitLabClient
# Reads GITLAB_TOKEN and GITLAB_URL from environment or .env file
client = GitLabClient()
# Or pass credentials explicitly
client = GitLabClient(token="glpat-xxxxxxxxxxxx", base_url="https://gitlab.example.com")
# Skip connection validation for faster startup
client = GitLabClient(validate=False)
# List open merge requests
mrs = client.get_merge_requests("mygroup/myproject", state="opened")
for mr in mrs:
print(f"!{mr['iid']} {mr['title']}")
# Create a merge request
client.create_merge_request("mygroup/myproject", "feature-branch", "main", "Add new feature")
# Get pipeline status
pipelines = client.get_pipelines("mygroup/myproject")
Features
- Merge requests -- create, update, merge, close, and review with inline diff comments
- Pipelines and jobs -- list, inspect, wait for completion, retry, and download artifacts
- Issues -- create, update, close, and comment
- Releases -- create, update, delete, and list with asset links
- CI/CD variables -- get, list, create, update, and upsert (set) project variables
- File operations -- read repository files at any ref, upload files for markdown embedding
- Automatic pagination -- all list endpoints handle multi-page results transparently
- Typed exceptions --
AuthenticationError,NotFoundError,APIError,ConfigurationError
Configuration
The client reads configuration from environment variables, with .env file support via python-dotenv:
| Variable | Description | Default |
|---|---|---|
GITLAB_TOKEN |
GitLab personal access token (required) | -- |
GITLAB_URL |
GitLab instance base URL | https://gitlab.com |
You can also use GITLAB_BASE_URL as an alias for GITLAB_URL.
Create a .env file in your project root:
GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx
GITLAB_URL=https://gitlab.example.com
API Reference
Projects
projects = client.get_projects(owned=True)
project = client.get_project("my-group/my-project")
Merge Requests
# List and inspect
mrs = client.get_merge_requests("my-group/my-project", state="opened")
mr = client.get_merge_request("my-group/my-project", mr_iid=42)
changes = client.get_mr_changes("my-group/my-project", mr_iid=42)
commits = client.get_mr_commits("my-group/my-project", mr_iid=42)
approvals = client.get_mr_approvals("my-group/my-project", mr_iid=42)
# Create
mr = client.create_merge_request(
"my-group/my-project",
source_branch="feature/foo",
target_branch="main",
title="Add foo feature",
description="Implements the foo feature.",
assignee_ids=[123],
reviewer_ids=[456],
labels="enhancement",
)
# Update, merge, close
client.update_mr("my-group/my-project", mr_iid=42, title="Updated title")
client.merge_mr("my-group/my-project", mr_iid=42, squash=True)
client.close_mr("my-group/my-project", mr_iid=42)
# Discussions and comments
discussions = client.get_mr_discussions("my-group/my-project", mr_iid=42)
client.create_mr_note("my-group/my-project", mr_iid=42, body="Looks good!")
client.reply_to_discussion("my-group/my-project", mr_iid=42, discussion_id="abc123", body="Fixed.")
client.resolve_discussion("my-group/my-project", mr_iid=42, discussion_id="abc123", resolved=True)
# Inline diff comment
from qodev_gitlab_api import DiffPosition
client.create_mr_discussion(
"my-group/my-project",
mr_iid=42,
body="Consider renaming this variable.",
position=DiffPosition(file_path="src/main.py", new_line=15),
)
Pipelines and Jobs
pipelines = client.get_pipelines("my-group/my-project", ref="main")
pipeline = client.get_pipeline("my-group/my-project", pipeline_id=1001)
jobs = client.get_pipeline_jobs("my-group/my-project", pipeline_id=1001)
# Job details, logs, and artifacts
job = client.get_job("my-group/my-project", job_id=5001)
log = client.get_job_log("my-group/my-project", job_id=5001)
artifact = client.get_job_artifact("my-group/my-project", job_id=5001, artifact_path="report.xml")
# Retry a failed job
client.retry_job("my-group/my-project", job_id=5001)
# Wait for pipeline completion (blocks until done or timeout)
result = client.wait_for_pipeline("my-group/my-project", pipeline_id=1001, timeout_seconds=600)
print(result["final_status"]) # "success", "failed", "canceled", "skipped", or "timeout"
Issues
issues = client.get_issues("my-group/my-project", state="opened", labels="bug")
issue = client.get_issue("my-group/my-project", issue_iid=10)
issue = client.create_issue(
"my-group/my-project",
title="Fix login bug",
description="Users cannot log in with SSO.",
labels="bug,urgent",
assignee_ids=[123],
)
client.update_issue("my-group/my-project", issue_iid=10, labels="bug,resolved")
client.close_issue("my-group/my-project", issue_iid=10)
# Comments
notes = client.get_issue_notes("my-group/my-project", issue_iid=10)
client.create_issue_note("my-group/my-project", issue_iid=10, body="Investigating this now.")
Releases
releases = client.get_releases("my-group/my-project")
release = client.get_release("my-group/my-project", tag_name="v1.0.0")
release = client.create_release(
"my-group/my-project",
tag_name="v1.1.0",
name="Version 1.1.0",
description="## What's new\n- Feature A\n- Bug fix B",
ref="main",
)
client.update_release("my-group/my-project", tag_name="v1.1.0", description="Updated notes.")
client.delete_release("my-group/my-project", tag_name="v1.1.0")
CI/CD Variables
variables = client.list_project_variables("my-group/my-project")
var = client.get_project_variable("my-group/my-project", key="API_KEY")
# Create or update (upsert)
var, action = client.set_project_variable(
"my-group/my-project",
key="API_KEY",
value="secret-value",
masked=True,
protected=True,
)
print(action) # "created" or "updated"
File Operations
# Read a file from the repository
content = client.get_file_content("my-group/my-project", file_path="README.md", ref="main")
# Upload a file (for embedding in issues/MRs)
from qodev_gitlab_api import FileFromPath
result = client.upload_file("my-group/my-project", source=FileFromPath(path="/tmp/screenshot.png"))
Error Handling
All API errors raise typed exceptions that inherit from GitLabError:
from qodev_gitlab_api import GitLabClient, AuthenticationError, NotFoundError, APIError, ConfigurationError
try:
client = GitLabClient()
mr = client.get_merge_request("my-group/my-project", mr_iid=999)
except ConfigurationError:
print("Missing or invalid GITLAB_TOKEN / GITLAB_URL")
except AuthenticationError:
print("Token is invalid or expired")
except NotFoundError:
print("Merge request not found")
except APIError as e:
print(f"API error {e.status_code}: {e.response_body}")
Requirements
- Python 3.11+
- httpx >= 0.28.1
- python-dotenv >= 1.1.0
License
MIT -- see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file qodev_gitlab_api-0.2.2.tar.gz.
File metadata
- Download URL: qodev_gitlab_api-0.2.2.tar.gz
- Upload date:
- Size: 14.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c5e017c1888f95980f89c2cdec0f21f16bb2ec773c688667d7539646d51d3d5
|
|
| MD5 |
cd33cdf6766d523ac2e863f7030c39cf
|
|
| BLAKE2b-256 |
b69812f3516d52e1878d580b944a8a5e8f394f839075e0a322b8c6c630bc6f04
|
Provenance
The following attestation bundles were made for qodev_gitlab_api-0.2.2.tar.gz:
Publisher:
publish.yml on qodevai/gitlab-api
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
qodev_gitlab_api-0.2.2.tar.gz -
Subject digest:
5c5e017c1888f95980f89c2cdec0f21f16bb2ec773c688667d7539646d51d3d5 - Sigstore transparency entry: 973315224
- Sigstore integration time:
-
Permalink:
qodevai/gitlab-api@6279ce4bf2820b1abcd674b338ce09d32180fb13 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/qodevai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6279ce4bf2820b1abcd674b338ce09d32180fb13 -
Trigger Event:
push
-
Statement type:
File details
Details for the file qodev_gitlab_api-0.2.2-py3-none-any.whl.
File metadata
- Download URL: qodev_gitlab_api-0.2.2-py3-none-any.whl
- Upload date:
- Size: 16.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c893573f2d27d90f7563076c5b421f025a8726f5fe37029b67c804e63e04bfea
|
|
| MD5 |
03bfdb9206bea43c1594737c838d072f
|
|
| BLAKE2b-256 |
fbb5f0057a167270a441027da611b1725b9b41db0cfafadd95c187f55f45ad7b
|
Provenance
The following attestation bundles were made for qodev_gitlab_api-0.2.2-py3-none-any.whl:
Publisher:
publish.yml on qodevai/gitlab-api
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
qodev_gitlab_api-0.2.2-py3-none-any.whl -
Subject digest:
c893573f2d27d90f7563076c5b421f025a8726f5fe37029b67c804e63e04bfea - Sigstore transparency entry: 973315231
- Sigstore integration time:
-
Permalink:
qodevai/gitlab-api@6279ce4bf2820b1abcd674b338ce09d32180fb13 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/qodevai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6279ce4bf2820b1abcd674b338ce09d32180fb13 -
Trigger Event:
push
-
Statement type: