Skip to main content

GitHub SDK for Python

Project description

githubkit

license pypi python black pyright ruff pre-commit

✨ The modern, all-batteries-included GitHub SDK for Python ✨

✨ Support both sync and async calls, fully typed

✨ Always up to date, like octokit ✨

Installation

pip install githubkit
# or, use poetry
poetry add githubkit
# or, use pdm
pdm add githubkit

if you want to auth as github app, extra dependencies are required:

pip install githubkit[auth-app]
# or, use poetry
poetry add githubkit[auth-app]
# or, use pdm
pdm add githubkit[auth-app]

if you want to mix sync and async calls in oauth device callback, extra dependencies are required:

pip install githubkit[auth-oauth-device]
# or, use poetry
poetry add githubkit[auth-oauth-device]
# or, use pdm
pdm add githubkit[auth-oauth-device]

githubkit supports both pydantic v1 and v2, but pydantic v2 is recommended. If you have encountered any problems with pydantic v1/v2, please file an issue.

Usage

Authentication

Initialize a github client with no authentication:

from githubkit import GitHub, UnauthAuthStrategy

github = GitHub()
# or, use UnauthAuthStrategy
github = GitHub(UnauthAuthStrategy())

or using PAT (Token):

from githubkit import GitHub, TokenAuthStrategy

github = GitHub("<your_token_here>")
# or, use TokenAuthStrategy
github = GitHub(TokenAuthStrategy("<your_token_here>"))

or using GitHub APP authentication:

from githubkit import GitHub, AppAuthStrategy

github = GitHub(
    AppAuthStrategy(
        "<app_id>", "<private_key>", "<optional_client_id>", "<optional_client_secret>"
    )
)

or using GitHub APP Installation authentication:

from githubkit import GitHub, AppInstallationAuthStrategy

github = GitHub(
    AppInstallationAuthStrategy(
        "<app_id>", "<private_key>", installation_id, "<optional_client_id>", "<optional_client_secret>",
    )
)

or using OAuth APP authentication:

from githubkit import GitHub, OAuthAppAuthStrategy

github = GitHub(OAuthAppAuthStrategy("<client_id_here>", "<client_secret_here>"))

or using GitHub APP / OAuth APP web flow authentication:

from githubkit import GitHub, OAuthWebAuthStrategy

github = GitHub(
    OAuthWebAuthStrategy(
        "<client_id_here>", "<client_secret_here>", "<web_flow_exchange_code_here>"
    )
)

or using GitHub Action authentication:

from githubkit import GitHub, ActionAuthStrategy

github = GitHub(ActionAuthStrategy())

and add env or input to the step:

- name: Some step use githubkit
  with:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Some step use githubkit
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Config

githubkit is highly configurable, you can change the default config by passing config options to GitHub:

from githubkit import GitHub

github = GitHub(
    base_url="https://api.github.com/",
    accept_format="full+json",
    previews=["starfox"],
    user_agent="GitHubKit/Python",
    follow_redirects=True,
    timeout=None,
    http_cache=True
)

The accept_format and previews are used to set the default Accept header, you can find more details in GitHub API docs.

The http_cache option enables the http caching feature powered by Hishel for HTTPX. GitHub API limits the number of requests that you can make within a specific amount of time. This feature is useful to reduce the number of requests to GitHub API and avoid hitting the rate limit.

Calling Rest API

APIs are fully typed. Typing in the following examples is just for reference only.

Simple sync call:

from githubkit import Response
from githubkit.versions.latest.models import FullRepository

resp: Response[FullRepository] = github.rest.repos.get(owner="owner", repo="repo")
repo: FullRepository = resp.parsed_data

Simple async call:

from githubkit import Response
from githubkit.versions.latest.models import FullRepository

resp: Response[FullRepository] = await github.rest.repos.async_get(owner="owner", repo="repo")
repo: FullRepository = resp.parsed_data

Call API with context (reusing client):

from githubkit import Response
from githubkit.versions.latest.models import FullRepository

with GitHub("<your_token_here>") as github:
    resp: Response[FullRepository] = github.rest.repos.get(owner="owner", repo="repo")
    repo: FullRepository = resp.parsed_data
from githubkit import Response
from githubkit.versions.latest.models import FullRepository

async with GitHub("<your_token_here>") as github:
    resp: Response[FullRepository] = await github.rest.repos.async_get(owner="owner", repo="repo")
    repo: FullRepository = resp.parsed_data

Data Validation

As shown above, the response data is parsed and validated by accessing the response.parsed_data property. This ensures that the data type returned by the API is as expected and your code is safe to use it (with static type checking). But sometimes you may want to get the raw data returned by the API, such as when the schema is not correct. You can use the response.text property or response.json() method to get the raw data:

from typing import Any, Dict
from githubkit import Response

resp: Response[FullRepository] = github.rest.repos.get(owner="owner", repo="repo")
repo: Dict[str, Any] = resp.json()

Rest API Versioning

APIs are fully typed. Different versions of APIs are typed separately.

githubkit supports all versions of GitHub API, you can switch between versions as follows:

github.rest("2022-11-28").repos.get(owner="owner", repo="repo")

The models of versions can be imported from githubkit.versions.<version>.models, for example:

from githubkit.versions.v2022_11_28.models import FullRepository

Specially, the latest version is always linked to the latest version of GitHub API:

from githubkit.versions.latest.models import FullRepository

[!NOTE] For backward compatibility, the githubkit.rest module is linked to the models of latest version by default.

from githubkit.rest import FullRepository

You can also get the latest version name of GitHub API and all versions mapping of GitHub API:

from githubkit.versions import LATEST_VERSION, VERSIONS

Pagination

Pagination type checking is also supported:

Typing is tested with Pylance (Pyright).

from githubkit.versions.latest.models import Issue

for issue in github.paginate(
    github.rest.issues.list_for_repo, owner="owner", repo="repo", state="open"
):
    issue: Issue
    print(issue.number)
from githubkit.versions.latest.models import Issue

async for issue in github.paginate(
    github.rest.issues.async_list_for_repo, owner="owner", repo="repo", state="open"
):
    issue: Issue
    print(issue.number)

complex pagination with custom map function (some api returns data in a nested field):

async for accessible_repo in github.paginate(
    github.rest.apps.async_list_installation_repos_for_authenticated_user,
    map_func=lambda r: r.parsed_data.repositories,
    installation_id=1,
):
    accessible_repo: Repository
    print(accessible_repo.full_name)

Calling GraphQL API

Simple sync call:

data: Dict[str, Any] = github.graphql(query, variables={"foo": "bar"})

Simple async call:

data: Dict[str, Any] = await github.async_graphql(query, variables={"foo": "bar"})

Webhook Verification

githubkit.webhooks module contains some shortcut functions to help you verify and parse webhook payload.

Simple webhook payload verification:

from githubkit.webhooks import verify

valid: bool = verify(secret, request.body, request.headers["X-Hub-Signature-256"])

Sign the webhook payload manually:

from githubkit.webhooks import sign

signature: str = sign(secret, payload, method="sha256")

Webhook Parsing

githubkit.webhooks module contains some shortcut functions to help you verify and parse webhook payload.

Parse the payload with event name:

from githubkit.webhooks import parse

event = parse(request.headers["X-GitHub-Event"], request.body)

(NOT RECOMMENDED) Parse the payload without event name (may cost longer time and more memory):

from githubkit.webhooks import parse_without_name

event = parse_without_name(request.body)

[!WARNING] The parse_without_name function will try to parse the payload with all supported event names.
The behavior of this function is not the same between pydantic v1 and v2.
When using pydantic v1, the function will return the first valid event model (known as left-to-right mode).
When using pydantic v2, the function will return the highest scored valid event model (known as smart mode).
See: Union Modes.

Parse dict like payload:

from githubkit.webhooks import parse_obj, parse_obj_without_name

event = parse_obj(request.headers["X-GitHub-Event"], request.json())
event = parse_obj_without_name(request.json())  # NOT RECOMMENDED

The parse and parse_obj function supports type overload, if you provide static value for the event_name parameter, the return type will be inferred automatically.

Webhook also supports versioning, you can switch between versions as follows:

from githubkit import GitHub

event = GitHub.webhooks("2022-11-28").parse(request.headers["X-GitHub-Event"], request.body)

Switch between AuthStrategy

You can change the auth strategy and get a new client simplely using with_auth.

Change from AppAuthStrategy to AppInstallationAuthStrategy:

from githubkit import GitHub, AppAuthStrategy

github = GitHub(AppAuthStrategy("<app_id>", "<private_key>"))
installation_github = github.with_auth(
    github.auth.as_installation(installation_id)
)

Change from OAuthAppAuthStrategy to OAuthWebAuthStrategy:

from githubkit import GitHub, OAuthAppAuthStrategy

github = GitHub(OAuthAppAuthStrategy("<client_id>", "<client_secret>"))
user_github = github.with_auth(github.auth.as_web_user("<code>"))

Development

Open in Codespaces (Dev Container):

Open in GitHub Codespaces

Generate latest models and apis:

[!WARNING] This may use about 400M memory and take a long time.

./scripts/run-codegen.sh

Run tests in dev env:

./scripts/run-tests.sh

Run tests in test envs, for example:

cd ./envs/pydantic-v2/
poetry run bash ../../scripts/run-tests.sh

Contributors

Thanks to the following people who have contributed to this project:

contributors

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

githubkit-0.11.0a4.tar.gz (1.1 MB view details)

Uploaded Source

Built Distribution

githubkit-0.11.0a4-py3-none-any.whl (2.8 MB view details)

Uploaded Python 3

File details

Details for the file githubkit-0.11.0a4.tar.gz.

File metadata

  • Download URL: githubkit-0.11.0a4.tar.gz
  • Upload date:
  • Size: 1.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/4.0.2 CPython/3.11.7

File hashes

Hashes for githubkit-0.11.0a4.tar.gz
Algorithm Hash digest
SHA256 8263ed628bb89b23458fe0eb9688708b04142d58d037d93b6d411878d8da62ca
MD5 32027dd1196b3261fec0f16367c4618c
BLAKE2b-256 4aab8707d07ad8466ddc8616d5304493fa0f99ea9e6f13a2307f2314fd6df4be

See more details on using hashes here.

File details

Details for the file githubkit-0.11.0a4-py3-none-any.whl.

File metadata

  • Download URL: githubkit-0.11.0a4-py3-none-any.whl
  • Upload date:
  • Size: 2.8 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/4.0.2 CPython/3.11.7

File hashes

Hashes for githubkit-0.11.0a4-py3-none-any.whl
Algorithm Hash digest
SHA256 50891e52acb9ea9f436fea97d53d5ca605c0524aeab9034a4a0ce300056b7d87
MD5 3f1a26186d44ff66dbf5604004191ca5
BLAKE2b-256 1040f71d478ae4a488b60311d7f2c72ec9eb84a3559a17a2f412be56c7fd8edf

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page