pip install asyncPyGithubgit clone https://github.com/sudoDeVinci/asyncPyGithub.git
cd asyncPyGithub
pip install -r requirements.txtCreate a .env file:
GITHUB_TOKEN=your_token_here
The library uses a shared httpx.AsyncClient under the hood. You have two options for managing it:
The client starts automatically on first request. Just remember to close it when done:
import asyncio
from asyncPyGithub import GitHubPortal, GitHubUserPortal
async def main():
# Client starts automatically on first request
status, user = await GitHubPortal.authenticate("your_token")
if status != 200:
print(f"Auth failed: {user.message}")
return
print(f"Logged in as {user.login}")
# Do stuff...
status, other = await GitHubUserPortal.get_by_username("torvalds")
if status == 200:
print(f"Found: {other.login}")
# Clean up when done
await GitHubPortal.close()
asyncio.run(main())For scoped usage where you want automatic cleanup:
import asyncio
from asyncPyGithub import GitHubPortal, GitHubUserPortal
async def main():
async with GitHubPortal.scoped_client():
status, user = await GitHubPortal.authenticate("your_token")
if status != 200:
return
status, other = await GitHubUserPortal.get_by_username("torvalds")
# Client closes automatically when exiting the context
asyncio.run(main())The client uses connection pooling, so concurrent requests share connections efficiently:
import asyncio
from asyncPyGithub import GitHubPortal, GitHubUserPortal, GitHubRepositoryPortal
async def main():
status, user = await GitHubPortal.authenticate("your_token")
if status != 200:
return
# All requests run concurrently over the shared client
results = await asyncio.gather(
GitHubUserPortal.get_by_id(user.id),
GitHubUserPortal.get_by_username(user.login),
GitHubUserPortal.all(since=0, per_page=5),
GitHubRepositoryPortal.get_organization_repos("LEGO", per_page=5),
)
for status, data in results:
if status == 200:
print(f"OK: {type(data).__name__}")
else:
print(f"Error: {data.message}")
await GitHubPortal.close()
asyncio.run(main())Every method returns tuple[int, Result | ErrorMessage]. Check the status code first.
| Method | What it does |
|---|---|
authenticate(token) |
Auth and get your user info. Starts client if needed. |
start() |
Manually start the HTTP client |
close() |
Close the HTTP client |
scoped_client() |
Context manager that auto-closes on exit |
| Method | What it does |
|---|---|
update(changes) |
Update your profile |
get_by_id(uid) |
Get user by ID |
get_by_username(username) |
Get user by username |
all(since, per_page) |
List users |
get_hovercard(username) |
Get hovercard info |
| Method | What it does |
|---|---|
get_organization_repos(org, ...) |
List org repos |
create_organization_repo(org, name, ...) |
Create repo in org |
get_user_repo(owner, repo) |
Get a specific repo |
update_repository(owner, repo, ...) |
Update repo settings |
delete_repository(owner, repo) |
Delete a repo |
list_contributors(owner, repo) |
List contributors |
list_repository_languages(owner, repo) |
Get language breakdown |
list_repository_tags(owner, repo) |
List tags |
get_repository_topics(owner, repo) |
Get topics |
list_commits(owner, repo, sha, ...) |
List commits, newest first (supports since/until date filters) |
get_commit(owner, repo, ref) |
Get a single commit |
get_latest_commit(owner, repo, sha) |
Get the most recent commit (optionally of a branch/SHA) |
compare_commits(owner, repo, base, head) |
Compare two commits/refs |
check_for_updates(owner, repo, local_sha, branch) |
Check if the remote has new commits |
To see whether a new version has been pushed to a repository, pass your
locally known commit SHA to check_for_updates. If branch is omitted the
repository's default branch is used:
import asyncio
from asyncPyGithub import GitHubPortal, GitHubRepositoryPortal
async def main():
status, user = await GitHubPortal.authenticate("your_token")
if status != 200:
return
# The commit SHA you have locally (e.g. your deployed version)
local_sha = "6dcb09b5b57875f334f61aebed695e2e4193db5e"
status, update = await GitHubRepositoryPortal.check_for_updates(
owner="octocat", repo="Hello-World", local_sha=local_sha
)
if status != 200:
print(f"Error {update.code}: {update.message}")
return
if update.up_to_date:
print(f"No new commits. Latest is {update.latest_commit_sha}")
else:
print(f"{update.ahead_by} new commit(s) pushed!")
for commit in update.new_commits:
print(f" {commit.sha[:7]} {commit.commit.message.splitlines()[0]}")
await GitHubPortal.close()
asyncio.run(main())You can also use list_commits (newest first, so commits[0] is the latest)
and compare_commits directly if you need finer control over refs or pagination.
To discover the current head commit SHA of a branch:
status, latest = await GitHubRepositoryPortal.get_latest_commit(
owner="octocat", repo="Hello-World", sha="main"
)
if status == 200:
print(latest.sha) # newest commit on mainstatus, result = await GitHubUserPortal.get_by_username("doesnt-exist")
if status == 200:
print(result.login)
else:
# result is an ErrorMessage
print(f"Error {result.code}: {result.message}")GitHubPortal # Base - auth, client management
├── GitHubUserPortal # /user and /users endpoints
└── GitHubRepositoryPortal # /repos and /orgs/.../repos endpoints
All responses are Pydantic models (PrivateUser, SimpleUser, MinimalRepository, etc.).
pip install -r requirements-dev.txt
pytest- No rate limit handling
- No pagination helpers
- No webhooks