Of course! The GitHub API is a powerful way to interact with GitHub repositories, users, organizations, and more. Using it with Python is a common and practical task.

Here’s a comprehensive guide covering the essentials, from basic setup to advanced topics.
Prerequisites: What You Need
- Python 3: Make sure you have Python 3 installed.
- A GitHub Account: You'll need an account to create an API token.
- A GitHub Personal Access Token (PAT): This is your password for the API. For most tasks, you should use a "fine-grained" token.
- Go to Settings > Developer settings > Personal access tokens > Tokens (classic) or Fine-grained tokens.
- Click "Generate new token".
- Give it a descriptive name (e.g., "My Python Script").
- Set an expiration date.
- Crucially, select the scopes (permissions) your token needs. For public repository data,
public_repois enough. For private repos or writing data, you'll need more permissions likerepoorworkflow. - Copy the token immediately! You won't be able to see it again.
The Key Python Library: PyGithub
While you can use Python's built-in requests library to interact with the GitHub API, the PyGithub library is fantastic because it abstracts away the HTTP requests and JSON parsing, making your code much cleaner and more Pythonic.
Installation:
pip install PyGithub
Authentication: The Right Way
You should always authenticate your requests. Authenticated requests have higher rate limits (5,000 requests/hour vs. 60/hour for unauthenticated).

There are two main ways to do this with PyGithub:
Method 1: Using a Personal Access Token (Recommended)
This is the most common method. You can pass the token directly to the Github constructor.
from github import Github
# Replace with your actual token
GITHUB_TOKEN = "ghp_YourVeryLongAndSecureTokenHere"
# Create a Github instance
g = Github(GITHUB_TOKEN)
# Now you can make authenticated requests
# The rate limit will be high
print(f"Rate Limit: {g.get_rate_limit().core}")
Method 2: Using Environment Variables (Best Practice for Security)
Never hardcode your token in your script. Use environment variables.
- Set the environment variable in your terminal:
- Linux/macOS:
export GITHUB_TOKEN="ghp_YourToken" - Windows (Command Prompt):
set GITHUB_TOKEN=ghp_YourToken
- Linux/macOS:
- Modify your Python script to read from the environment.
import os
from github import Github
# Get the token from an environment variable
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
if not GITHUB_TOKEN:
raise ValueError("GITHUB_TOKEN environment variable not set!")
g = Github(GITHUB_TOKEN)
Common API Operations with PyGithub
Let's explore some of the most common tasks.

A. Getting Information about a Repository
# Assuming 'g' is your authenticated Github instance from above
# Format is "owner/repository_name"
repo_name = "psf/requests"
try:
repo = g.get_repo(repo_name)
# Get repository details
print(f"Repository Name: {repo.name}")
print(f"Full Name: {repo.full_name}")
print(f"Description: {repo.description}")
print(f"Clone URL: {repo.clone_url}")
print(f"Default Branch: {repo.default_branch}")
print(f"Stars: {repo.stargazers_count}")
print(f"Language: {repo.language}")
except Exception as e:
print(f"Error: {e}")
B. Listing and Creating Issues
Issues are used for tracking bugs and features.
# Using the same 'repo' object from the previous example
# --- Listing Issues ---
# Get open issues, sorted by most recently updated
issues = repo.get_issues(state='open')
print("\n--- Open Issues ---")
for issue in issues[:5]: # Print the first 5 issues
print(f"#{issue.number}: {issue.title} (by {issue.user.login})")
# --- Creating an Issue ---
print("\n--- Creating a New Issue ---")
try:
# The 'create_issue' method returns the created issue object
new_issue = repo.create_issue(
title="Found a bug with PyGithub",
body="I'm having trouble with the XYZ method. It's not working as expected.",
assignee="your-github-username", # Optional
labels="bug" # Can be a single string or a list of strings
)
print(f"Successfully created issue #{new_issue.number}: {new_issue.title}")
except Exception as e:
print(f"Error creating issue: {e}")
C. Working with Pull Requests (PRs)
PRs are for proposing code changes.
# Using the same 'repo' object
# --- Listing Pull Requests ---
# Get open PRs
prs = repo.get_pulls(state='open', sort='created', direction='desc')
print("\n--- Open Pull Requests ---")
for pr in prs[:5]:
print(f"PR #{pr.number}: {pr.title} (by {pr.user.login})")
print(f" - Target Branch: {pr.base.ref}, Head Branch: {pr.head.ref}")
print(f" - State: {pr.state}")
print("-" * 20)
# --- Getting a Specific PR ---
# PRs are a special kind of issue, so you can get them by number
pr_number = 123 # Replace with an actual PR number
try:
specific_pr = repo.get_pull(pr_number)
print(f"\nDetails for PR #{specific_pr.number}:")
print(f"Title: {specific_pr.title}")
print(f"Body:\n{specific_pr.body}")
except Exception as e:
print(f"Error fetching PR #{pr_number}: {e}")
D. Listing and Creating Releases
Releases are used to ship new versions of your project.
# Using the same 'repo' object
# --- Listing Releases ---
releases = repo.get_releases()
print("\n--- Releases ---")
for release in releases[:5]:
print(f"Tag: {release.tag_name}, Name: {release.title}, Published: {release.published_at}")
# --- Creating a Release ---
print("\n--- Creating a New Release ---")
try:
# You need to create a tag on your repository first (e.g., via git)
# 'generate_release_notes=True' will auto-generate notes from PRs and issues
new_release = repo.create_git_release(
tag="v1.2.3",
name="Version 1.2.3",
message="This is a great new feature release!",
draft=False, # Set to True to keep it as a draft
prerelease=False,
generate_release_notes=True
)
print(f"Successfully created release: {new_release.tag_name}")
except Exception as e:
print(f"Error creating release: {e}")
Advanced Topics
A. Handling Rate Limits
The GitHub API has rate limits. If you exceed them, you'll get a 403 Forbidden error. PyGithub makes it easy to check your remaining quota.
from github import Github, GithubException
g = Github("your_token")
try:
# Check the current rate limit status
rate_limit = g.get_rate_limit()
core_limit = rate_limit.core
print(f"Remaining Core Limit: {core_limit.remaining}")
print(f"Core Limit Reset Time: {core_limit.reset}")
# If you are close to the limit, you might want to wait
if core_limit.remaining < 10:
print("Approaching rate limit. Waiting for reset...")
# You would implement a sleep here until the reset time
# import time
# time.sleep((core_limit.reset - datetime.datetime.now()).total_seconds())
# Now make your API calls
# ...
except GithubException as e:
if e.status == 403:
print("Rate limit exceeded!")
else:
print(f"An API error occurred: {e}")
B. Using the requests Library Directly
If you need more control or want to avoid dependencies, you can use requests. You have to manually handle authentication and JSON parsing.
import requests
import json
# The API endpoint for a single repository
url = "https://api.github.com/repos/psf/requests"
# Headers are crucial for authentication and specifying the response format
headers = {
"Accept": "application/vnd.github.v3+json",
"Authorization": "token YOUR_GITHUB_TOKEN" # Replace with your token
}
try:
response = requests.get(url, headers=headers)
# Raise an exception for bad status codes (4xx or 5xx)
response.raise_for_status()
# Parse the JSON response
repo_data = response.json()
# Now you can work with the data as a Python dictionary
print(f"Repository Name: {repo_data['name']}")
print(f"Stars: {repo_data['stargazers_count']}")
except requests.exceptions.HTTPError as err:
print(f"HTTP Error: {err}")
except requests.exceptions.RequestException as err:
print(f"Request Error: {err}")
Official Documentation
- GitHub REST API Documentation: https://docs.github.com/en/rest (This is the ultimate source for all available endpoints).
- PyGithub Documentation: https://pygithub.readthedocs.io/ (Excellent for understanding the
PyGithublibrary's methods and objects).
