API reference

Everything below is importable from the package root, e.g. from action0.github import GitHubClient.

action0.github.client

The client (GitHubClient): base URL, default headers and auth.

class action0.github.client.GitHubClient(backend, token=None, base_url='https://api.github.com')[source]

The GitHub REST API client: base URL, GitHub’s recommended headers and (optional) token auth baked in. Which execution model runs it is the backend’s choice — see APIClient.

Example (with the test-double backend standing in for a real one):

>>> from action0.client.testing import StubBackend
>>> from action0.req import Response
>>>
>>> backend = StubBackend(Response(200, body="{}"))
>>> client = GitHubClient(backend, token="ghp_secret")
>>> client
GitHubClient(https://api.github.com via StubBackend(0 requests))
Parameters:
  • backend (TypeVar(BackendT_co, bound= Backend[Any], covariant=True))

  • token (str | None, default: None)

  • base_url (str, default: 'https://api.github.com')

  • backend – any sync, async or Twisted backend

  • token – a GitHub token (classic, fine-grained or app installation) sent as Authorization: Bearer; None sends unauthenticated requests (public data only, 60 requests/hour)

  • base_url – the API root — override for GitHub Enterprise Server (https://HOST/api/v3)

action0.github.pagination

Iterating over all pages of a listing.

Pagination itself is execution-model-agnostic data: every listing returns a Page whose next is the ready-to-send operation for the following page. The helpers here are the flattening sugar on top — one per execution model, like action0-client’s retry wrappers, because “loop over pages” is spelled differently in sync, async and Twisted code.

Each helper keeps sending page.next through the client until the last page; one GitHub request per page, so mind the rate limit on large listings (cap via per_page/starting page if needed).

action0.github.pagination.all_items(client, operation)[source]

Iterate over all items of a listing, lazily following the pages (sync backends).

Parameters:
Return type:

Iterator[TypeVar(ItemT)]

Returns:

the items, page by page — each page is fetched only when the iteration reaches it

async action0.github.pagination.all_items_async(client, operation)[source]

Iterate over all items of a listing, lazily following the pages (async backends) — consume with async for.

Parameters:
Return type:

AsyncIterator[TypeVar(ItemT)]

Returns:

the items, page by page — each page is fetched only when the iteration reaches it

action0.github.pagination.all_items_deferred(client, operation)[source]

Collect all items of a listing, following the pages (Twisted backends). Unlike the sync/async helpers this gathers everything into one list — a Deferred cannot stream lazily.

Parameters:
Return type:

Deferred[list[TypeVar(ItemT)]]

Returns:

a Deferred firing with the items of all pages

action0.github.conditional

Conditional requests (ConditionalRequestsHook): GitHub’s recommended way to save rate limit.

GitHub answers most GETs with an ETag (and Last-Modified). Repeat the request with If-None-Match (/ If-Modified-Since) and, if nothing changed, GitHub replies 304 Not Modified — with an empty body, and without counting against the primary rate limit. The hook keeps a store of ETagged responses, attaches the validators on the way out and fills a 304 from the store on the way in.

Because it is a Hook — not a backend wrapper — a single instance drives every execution model: hooks run inside all backend base classes, sync, async and Twisted alike:

hook = ConditionalRequestsHook()
backend = RequestsBackend(hooks=[hook])  # or AsyncHttpxBackend(hooks=[hook]), ...
client = GitHubClient(backend, token="ghp_...")

Layer CachingSyncBackend (or its async/Deferred siblings) around such a backend and hot data is served without any request for the cache’s TTL — after which the request that does go out is a revalidation, and usually free.

action0.github.conditional.GITHUB_CONDITIONAL_POLICY = CachePolicy(ttl=inf, methods=frozenset({'GET', 'HEAD'}), statuses=frozenset({200}), vary_headers=('Accept', 'Authorization'))

The default storage policy: entries never expire (an ETag stays valid until the resource changes; the store’s own eviction bounds memory) and the key varies on Accept and Authorization — a different token or media type is a different cache entry. Keys are sha256 digests, so the token value never appears in a key.

class action0.github.conditional.ConditionalRequestsHook(store=None, policy=CachePolicy(ttl=inf, methods=frozenset({'GET', 'HEAD'}), statuses=frozenset({200}), vary_headers=('Accept', 'Authorization')))[source]

The conditional-requests hook: stores ETagged responses, revalidates with If-None-Match / If-Modified-Since, and turns GitHub’s 304 Not Modified back into the stored full response — transparently to the operations, which only ever see the 200.

The whole revalidation cycle, against a stub backend:

>>> from action0.client.testing import StubBackend
>>> from action0.req import Request, Response
>>>
>>> backend = StubBackend(
...     Response(200, body='{"name": "cpython"}', headers={"ETag": '"abc"'}),
...     Response(304),
...     hooks=[ConditionalRequestsHook()],
... )
>>> request = Request("https://api.github.com/repos/python/cpython")
>>> backend.send(request).body_str()  # stored under its ETag
'{"name": "cpython"}'
>>> backend.send(request.copy()).body_str()  # the 304 is filled from the store
'{"name": "cpython"}'
>>> backend.requests[1].headers["If-None-Match"]
'"abc"'
Parameters:
  • store (CacheStore | None, default: None)

  • policy (CachePolicy, default: CachePolicy(ttl=inf, methods=frozenset({'GET', 'HEAD'}), statuses=frozenset({200}), vary_headers=('Accept', 'Authorization')))

  • store – where the ETagged responses live — any (synchronous) CacheStore; the default is a fresh, thread-safe MemoryCache. Hooks run synchronously even on async backends, so an AsyncCacheStore is not accepted.

  • policy – what to store under which key — GITHUB_CONDITIONAL_POLICY unless told otherwise

on_request(request)[source]

Attach the stored validators to an outgoing GET/HEAD: the stored response’s ETag as If-None-Match (and Last-Modified as If-Modified-Since). A request already carrying its own validators is the caller’s conditional request — left untouched.

Parameters:

request (Request) – the request about to be sent (mutated in place)

Return type:

Request | None

Returns:

None — the given request is the one sent

on_response(request, response, elapsed)[source]

Fill a 304 Not Modified from the store, and store fresh responses that carry validators.

Parameters:
  • request (Request) – the request that was sent

  • response (Response) – the response that arrived

  • elapsed (float) – the seconds the exchange took (unused)

Return type:

Response | None

Returns:

the stored full response for a revalidated 304 (an independent copy tied to the current request), else None to keep the given response

action0.github.retry

GitHub-aware retries (GitHubRetryPolicy).

The mechanics come from action0-client: wrap any backend in the retrying variant of its execution model (RetryingSyncBackend / RetryingAsyncBackend / RetryingDeferredBackend) and hand it this policy:

backend = RetryingSyncBackend(RequestsBackend(), GitHubRetryPolicy())
client = GitHubClient(backend, token="ghp_...")
action0.github.retry.RATE_LIMIT_REMAINING = 'x-ratelimit-remaining'

The response header counting the requests left in the rate window.

action0.github.retry.RATE_LIMIT_RESET = 'x-ratelimit-reset'

The response header naming the rate window’s end (epoch seconds).

class action0.github.retry.GitHubRetryPolicy(attempts=3, backoff=0.5, multiplier=2.0, max_backoff=120.0, retry_statuses=frozenset({408, 429, 500, 502, 503, 504}), retry_errors=(<class 'action0.client.errors.TransportError'>, ), methods=frozenset({'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PUT', 'TRACE'}), jitter=True, respect_retry_after=True, rng=<built-in method random of Random object at 0xcf4b240>, clock=<built-in function time>)[source]

A RetryPolicy tuned to the GitHub API. On top of the base behavior (transient 5xx/429 statuses, Retry-After honored, idempotent methods only — so CreateIssue and friends are never blindly repeated) it knows GitHub’s rate limits:

  • a 403 is retried only when it actually is a rate limit (GitHub also answers plain permission problems with 403): a Retry-After header or x-ratelimit-remaining: 0 must be present,

  • without a Retry-After, an exhausted primary rate limit is waited out until x-ratelimit-reset (GitHub’s documented advice), capped at max_backoff — raise it if you want to sit out whole rate windows.

Example — an exhausted rate window resetting 90 seconds from now:

>>> policy = GitHubRetryPolicy(clock=lambda: 1_000_000.0)
>>> headers = {"x-ratelimit-remaining": "0", "x-ratelimit-reset": "1000090"}
>>> policy.delay_for(1, Response(403, headers=headers))
90.0
Parameters:
  • attempts (int, default: 3)

  • backoff (float, default: 0.5)

  • multiplier (float, default: 2.0)

  • max_backoff (float, default: 120.0)

  • retry_statuses (frozenset[int], default: frozenset({500, 408, 502, 503, 504, 429}))

  • retry_errors (tuple[type[BaseException], ...], default: (<class 'action0.client.errors.TransportError'>,))

  • methods (frozenset[str] | None, default: frozenset({'PUT', 'GET', 'OPTIONS', 'DELETE', 'TRACE', 'HEAD'}))

  • jitter (bool, default: True)

  • respect_retry_after (bool, default: True)

  • rng (Callable[[], float], default: <built-in method random of Random object at 0xcf4b240>)

  • clock (Callable[[], float], default: <built-in function time>)

max_backoff: float = 120.0

The wait cap in seconds — higher than the base default so GitHub’s “wait at least a minute” advice for secondary rate limits fits.

clock()

The epoch-seconds clock x-ratelimit-reset waits are computed against — injectable for tests.

should_retry_response(request, response, attempt)[source]

The base statuses, plus 403 when the response says “rate limited”.

Parameters:
  • request (Request) – the request that was sent

  • response (Response) – the response that arrived

  • attempt (int) – the (1-based) attempt that produced it

Return type:

bool

Returns:

whether to retry

delay_for(attempt, response=None)[source]

The base delays (Retry-After first, else jittered exponential backoff), with one addition: an exhausted primary rate limit without a Retry-After waits until x-ratelimit-reset.

Parameters:
  • attempt (int) – the attempt that just failed

  • response (Response | None, default: None) – the response that triggered the retry, if the attempt produced one

Return type:

float

Returns:

the wait in seconds, capped at max_backoff

action0.github.operations

The GitHub endpoints as typed operation classes — one module per GitHub resource area, one GitHubOperation subclass per endpoint.

action0.github.operations.base

The base classes shared by all GitHub operations (GitHubOperation, PaginatedOperation, NoContentOperation) and the query vocabularies GitHub uses across resource areas (SortDirection).

class action0.github.operations.base.R_co

The parsed result type of a GitHub operation.

alias of TypeVar(‘R_co’, covariant=True)

class action0.github.operations.base.PageT

A page result — Page or a subclass like SearchPage.

alias of TypeVar(‘PageT’, bound=Page[Any])

action0.github.operations.base.attach_next(operation, page, response)[source]

Attach the next-page operation to a freshly parsed page: a copy of the given operation with its page field incremented — exactly when the response’s Link header announces a rel="next" (GitHub’s authoritative end-of-listing signal).

dataclasses.replace keeps the page’s concrete type, so subclasses like SearchPage pass through with their extra fields intact.

Parameters:
  • operation (Any) – the operation that produced the page — any operation dataclass with a page field (typed Any: “has a page field” spans the unrelated PaginatedOperation and SearchOperation hierarchies)

  • page (TypeVar(PageT, bound= Page[Any])) – the parsed page, next not yet set

  • response (Response) – the response it was parsed from

Return type:

TypeVar(PageT, bound= Page[Any])

Returns:

the page, with next attached if there is one

class action0.github.operations.base.SortDirection(*values)[source]

The sort direction of a listing.

class action0.github.operations.base.GitHubOperation[source]

The base class of all GitHub operations: a JsonOperation requesting GitHub’s recommended media type.

accept lives here (not only as a client default header) because as_request() sets the operation’s Accept before the client’s gap-filling defaults run — JsonOperation’s plain application/json would win otherwise.

accept: ClassVar[str | None] = 'application/vnd.github+json'

The Accept header to send, unless one is set explicitly; None sends none. JsonOperation sets application/json.

class action0.github.operations.base.NoContentOperation[source]

The base class of the operations whose success answer is 204 No Content — deletes, locks and the like. There is nothing to parse, so send yields None (wrapped in whatever the execution model wraps results in); errors surface as usual via APIError.

Not a GitHubOperation: JsonOperation’s load treats an empty body as an error, which is exactly the success case here.

accept: ClassVar[str | None] = 'application/vnd.github+json'

The Accept header to send, unless one is set explicitly; None sends none. JsonOperation sets application/json.

load(response)[source]

Nothing to parse — a vetted response is the success.

Parameters:

response (Response) – the response, already vetted

Return type:

None

Returns:

None, always

class action0.github.operations.base.PaginatedOperation(*, per_page=30, page=1)[source]

The base class of the listing operations: GitHub’s page-number pagination as query fields, and the result wrapped as a Page whose next is the ready-to-send operation for the following page — present exactly when the response’s Link header announces a rel="next" (GitHub’s authoritative signal), built as a copy of this operation with page + 1.

Subclasses implement load_item() for a single JSON array item. Being base-class fields, per_page and page come first in every listing’s query string.

Parameters:
  • per_page (int, default: 30)

  • page (int, default: 1)

per_page: int = 30

The page size (GitHub caps it at 100).

page: int = 1

The page number, starting at 1.

abstractmethod load_item(data)[source]

Turn one item of the decoded JSON array into the typed model.

Parameters:

data (Any) – one decoded JSON array item

Return type:

TypeVar(ItemT)

Returns:

the parsed item

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload (an array)

Return type:

Page[TypeVar(ItemT)]

Returns:

the page, without pagination yet (load() adds it — only the response’s Link header knows)

load(response)[source]

Decode the page (via JsonOperation’s JSON handling) and attach the next-page operation if the response’s Link header announces one.

Parameters:

response (Response) – the response, already vetted

Return type:

Page[TypeVar(ItemT)]

Returns:

the page

action0.github.operations.repos

The repository operations (GitHub docs).

class action0.github.operations.repos.GetRepo(*, owner, repo)[source]

GET /repos/{owner}/{repo} — fetch one repository.

>>> GetRepo(owner="python", repo="cpython").as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/cpython'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Repo

Returns:

the repository

class action0.github.operations.repos.GetRepoTopics(*, owner, repo)[source]

GET /repos/{owner}/{repo}/topics — the repository’s topics, as the plain list of names (unwrapped from GitHub’s {names: [...]} envelope).

Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/topics'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload (the envelope)

Return type:

list[str]

Returns:

the topic names

class action0.github.operations.repos.ListContributors(*, per_page=30, page=1, owner, repo)[source]

GET /repos/{owner}/{repo}/contributors — list who contributed, most commits first (each item a Contributor — a user plus their commit count).

Parameters:
  • per_page (int, default: 30)

  • page (int, default: 1)

  • owner (str)

  • repo (str)

method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/contributors'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

Contributor

Returns:

the contributor

class action0.github.operations.repos.ListLanguages(*, owner, repo)[source]

GET /repos/{owner}/{repo}/languages — the repository’s language breakdown, handed through as GitHub sends it: language name → bytes of code, largest first.

>>> operation = ListLanguages(owner="python", repo="cpython")
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/cpython/languages'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/languages'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

dict[str, int]

Returns:

language name → bytes of code

class action0.github.operations.repos.ListOrgRepos(*, per_page=30, page=1, sort=None, direction=None, org, type=None)[source]

GET /orgs/{org}/repos — list an organization’s repositories.

>>> operation = ListOrgRepos(org="python", sort=RepoSort.PUSHED, per_page=5)
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/orgs/python/repos?per_page=5&page=1&sort=pushed'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/orgs/{org}/repos'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

type: OrgRepoType | None = None

The repository-type filter; None uses GitHub’s default (all).

class action0.github.operations.repos.ListRepoTags(*, per_page=30, page=1, owner, repo)[source]

GET /repos/{owner}/{repo}/tags — list a repository’s tags, newest first.

>>> operation = ListRepoTags(owner="python", repo="cpython", per_page=5)
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/cpython/tags?per_page=5&page=1'
Parameters:
  • per_page (int, default: 30)

  • page (int, default: 1)

  • owner (str)

  • repo (str)

method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/tags'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

Tag

Returns:

the tag

class action0.github.operations.repos.ListUserRepos(*, per_page=30, page=1, sort=None, direction=None, username, type=None)[source]

GET /users/{username}/repos — list a user’s repositories.

Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/users/{username}/repos'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

type: UserRepoType | None = None

The repository-type filter; None uses GitHub’s default (owner).

class action0.github.operations.repos.OrgRepoType(*values)[source]

The repository-type filter of ListOrgRepos.

class action0.github.operations.repos.ReplaceRepoTopics(*, owner, repo, names)[source]

PUT /repos/{owner}/{repo}/topics — replace the repository’s topics wholesale (there is no incremental add/remove in GitHub’s API; read-modify-write via GetRepoTopics). Requires a token with write access; [] clears them.

Parameters:
method: ClassVar[str] = 'PUT'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/topics'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

names: list[str]

The complete new topic set (lowercase letters, digits and hyphens — GitHub answers 422 otherwise).

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload (the envelope)

Return type:

list[str]

Returns:

the topic names as stored

class action0.github.operations.repos.RepoSort(*values)[source]

The sort orders of the repository listings.

class action0.github.operations.repos.SortDirection(*values)[source]

The sort direction of a listing.

class action0.github.operations.repos.UserRepoType(*values)[source]

The repository-type filter of ListUserRepos.

action0.github.operations.branches

The branch operations (GitHub docs).

class action0.github.operations.branches.ListBranches(*, per_page=30, page=1, owner, repo, protected=None)[source]

GET /repos/{owner}/{repo}/branches — list a repository’s branches.

The protected filter is the first boolean query parameter — sent web-style as true/false:

>>> operation = ListBranches(owner="python", repo="peps", protected=True)
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/peps/branches?per_page=30&page=1&protected=true'
Parameters:
  • per_page (int, default: 30)

  • page (int, default: 1)

  • owner (str)

  • repo (str)

  • protected (bool | None, default: None)

method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/branches'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

protected: bool | None = None

True for only protected, False for only unprotected branches; None lists all.

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

Branch

Returns:

the branch

class action0.github.operations.branches.GetBranch(*, owner, repo, branch)[source]

GET /repos/{owner}/{repo}/branches/{branch} — fetch one branch, including the full tip commit the listings omit (commit).

>>> operation = GetBranch(owner="python", repo="peps", branch="main")
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/peps/branches/main'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/branches/{branch}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

branch: str

The branch name (slashes in names like feature/x are fine).

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Branch

Returns:

the branch

action0.github.operations.collaborators

The collaborator operations (GitHub docs).

class action0.github.operations.collaborators.CollaboratorAffiliation(*values)[source]

The affiliation filter of ListCollaborators.

class action0.github.operations.collaborators.ListCollaborators(*, per_page=30, page=1, owner, repo, affiliation=None, permission=None)[source]

GET /repos/{owner}/{repo}/collaborators — list who has access to a repository (requires a token with push access itself).

>>> operation = ListCollaborators(
...     owner="octo", repo="demo", affiliation=CollaboratorAffiliation.DIRECT
... )
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/octo/demo/collaborators?per_page=30&page=1&affiliation=direct'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/collaborators'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

affiliation: CollaboratorAffiliation | None = None

Filter by how the access came about — outside collaborators, direct ones, or everyone; None uses GitHub’s default (all).

permission: str | None = None

Only collaborators with (at least) this permission — one of GitHub’s role names ("pull", "triage", "push", "maintain", "admin" or a custom role — an open set, hence no enum); None lists all.

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

SimpleUser

Returns:

the collaborator

class action0.github.operations.collaborators.GetCollaboratorPermission(*, owner, repo, username)[source]

GET /repos/{owner}/{repo}/collaborators/{username}/permission — what one user may do in a repository. The answer is reduced to the permission string itself: "admin", "write", "read" or "none".

Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/collaborators/{username}/permission'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

username: str

The login to look up.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

str

Returns:

the permission level

action0.github.operations.issues

The issue operations (GitHub docs).

class action0.github.operations.issues.IssueStateFilter(*values)[source]

The state filter of ListIssues (unlike IssueState it knows all).

class action0.github.operations.issues.IssueSort(*values)[source]

The sort orders of the issue listing.

class action0.github.operations.issues.IssueStateReason(*values)[source]

The reason attached to an issue’s state by UpdateIssue.

class action0.github.operations.issues.LockReason(*values)[source]

The reason LockIssue attaches to a locked conversation (note "too heated" — GitHub’s value contains a space).

class action0.github.operations.issues.ListIssues(*, per_page=30, page=1, owner, repo, state=None, labels=None, sort=None, direction=None, since=None)[source]

GET /repos/{owner}/{repo}/issues — list a repository’s issues.

GitHub returns pull requests here too (every pull request is an issue); filter them out via is_pull_request.

>>> operation = ListIssues(owner="python", repo="peps", state=IssueStateFilter.CLOSED)
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/peps/issues?per_page=30&page=1&state=closed'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/issues'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

state: IssueStateFilter | None = None

The state filter; None uses GitHub’s default (open).

labels: str | None = None

Label names to filter by, comma-separated ("bug,ui") — GitHub’s own wire format for this parameter.

sort: IssueSort | None = None

The sort order; None uses GitHub’s default (created).

direction: SortDirection | None = None

The sort direction; None uses GitHub’s default (desc).

since: datetime | None = None

Only issues updated at or after this time (serialized to ISO 8601).

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

Issue

Returns:

the issue

class action0.github.operations.issues.GetIssue(*, owner, repo, issue_number)[source]

GET /repos/{owner}/{repo}/issues/{issue_number} — fetch one issue (or pull request — see is_pull_request).

>>> operation = GetIssue(owner="python", repo="peps", issue_number=42)
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/peps/issues/42'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/issues/{issue_number}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Issue

Returns:

the issue

class action0.github.operations.issues.CreateIssue(*, owner, repo, title, body=None, labels=None, assignees=None)[source]

POST /repos/{owner}/{repo}/issues — create an issue.

The non-path fields become the JSON request body; None fields are omitted from it (requires a token with write access to the repository).

Parameters:
method: ClassVar[str] = 'POST'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/issues'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

title: str

The issue title.

body: str | None = None

The description text (GitHub-flavored Markdown).

labels: list[str] | None = None

Label names to attach.

assignees: list[str] | None = None

Logins to assign.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Issue

Returns:

the created issue (with its server-assigned number)

class action0.github.operations.issues.UpdateIssue(*, owner, repo, issue_number, title=None, body=None, state=None, state_reason=None, labels=None, assignees=None)[source]

PATCH /repos/{owner}/{repo}/issues/{issue_number} — update an issue (requires a token with write access to the repository).

PATCH semantics: only the fields you set are changed — a None field is omitted from the JSON body and leaves the issue untouched. (This also means clearing a field by sending JSON null is not expressible here; send an empty string/list instead where GitHub accepts one.) Like every non-idempotent method, a PATCH is never blindly repeated by GitHubRetryPolicy.

Parameters:
method: ClassVar[str] = 'PATCH'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/issues/{issue_number}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

title: str | None = None

The new title.

body: str | None = None

The new description text (GitHub-flavored Markdown).

state: IssueState | None = None

Open or close the issue.

state_reason: IssueStateReason | None = None

The reason to attach to the state change (close as completed/not_planned, reopen as reopened).

labels: list[str] | None = None

The new label names — replaces the whole set ([] clears it).

assignees: list[str] | None = None

The new assignee logins — replaces the whole set ([] clears it).

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Issue

Returns:

the updated issue

class action0.github.operations.issues.ListIssueComments(*, per_page=30, page=1, owner, repo, issue_number, since=None)[source]

GET /repos/{owner}/{repo}/issues/{issue_number}/comments — list an issue’s comments, oldest first (pull request conversation comments live here too — every pull request is an issue).

>>> operation = ListIssueComments(owner="python", repo="peps", issue_number=42)
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/peps/issues/42/comments?per_page=30&page=1'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/issues/{issue_number}/comments'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

since: datetime | None = None

Only comments updated at or after this time (serialized to ISO 8601).

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

IssueComment

Returns:

the comment

class action0.github.operations.issues.CreateIssueComment(*, owner, repo, issue_number, body)[source]

POST /repos/{owner}/{repo}/issues/{issue_number}/comments — comment on an issue or pull request (requires a token with write access to the repository).

Parameters:
method: ClassVar[str] = 'POST'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/issues/{issue_number}/comments'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

body: str

The comment text (GitHub-flavored Markdown).

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

IssueComment

Returns:

the created comment (with its server-assigned id)

class action0.github.operations.issues.UpdateIssueComment(*, owner, repo, comment_id, body)[source]

PATCH /repos/{owner}/{repo}/issues/comments/{comment_id} — edit a comment. Note the address: comment ids are repository-global, so no issue number appears in the path.

Parameters:
method: ClassVar[str] = 'PATCH'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/issues/comments/{comment_id}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

comment_id: int

The comment id (IssueComment.id) — not the issue number.

body: str

The new comment text — replaces the old one entirely.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

IssueComment

Returns:

the updated comment

class action0.github.operations.issues.DeleteIssueComment(*, owner, repo, comment_id)[source]

DELETE /repos/{owner}/{repo}/issues/comments/{comment_id} — delete a comment, for good. The first no-content operation: GitHub answers 204, send yields None.

>>> operation = DeleteIssueComment(owner="octo", repo="demo", comment_id=1)
>>> request = operation.as_request("https://api.github.com")
>>> f"{request.method} {request.url.as_str()}"
'DELETE https://api.github.com/repos/octo/demo/issues/comments/1'
Parameters:
method: ClassVar[str] = 'DELETE'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/issues/comments/{comment_id}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

comment_id: int

The comment id — not the issue number.

class action0.github.operations.issues.LockIssue(*, owner, repo, issue_number, lock_reason=None)[source]

PUT /repos/{owner}/{repo}/issues/{issue_number}/lock — lock an issue’s (or pull request’s) conversation: only collaborators can comment until it is unlocked. Answers 204.

Parameters:
method: ClassVar[str] = 'PUT'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/issues/{issue_number}/lock'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

lock_reason: LockReason | None = None

The reason shown in the timeline; None locks without one.

class action0.github.operations.issues.UnlockIssue(*, owner, repo, issue_number)[source]

DELETE /repos/{owner}/{repo}/issues/{issue_number}/lock — unlock the conversation again. Answers 204.

Parameters:
method: ClassVar[str] = 'DELETE'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/issues/{issue_number}/lock'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

class action0.github.operations.issues.AddAssignees(*, owner, repo, issue_number, assignees)[source]

POST /repos/{owner}/{repo}/issues/{issue_number}/assignees — add assignees to an issue or pull request, keeping the existing ones (unlike UpdateIssue’s assignees, which replaces the whole set). Unassignable logins are silently ignored by GitHub.

Parameters:
method: ClassVar[str] = 'POST'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/issues/{issue_number}/assignees'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

assignees: list[str]

The logins to add (at most 10 assignees in total).

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Issue

Returns:

the issue with its updated assignee set

class action0.github.operations.issues.RemoveAssignees(*, owner, repo, issue_number, assignees)[source]

DELETE /repos/{owner}/{repo}/issues/{issue_number}/assignees — remove assignees from an issue or pull request. A DELETE carrying a JSON body — GitHub’s design, unusual but valid HTTP; the fields serialize exactly like every other body.

Parameters:
method: ClassVar[str] = 'DELETE'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/issues/{issue_number}/assignees'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

assignees: list[str]

The logins to remove (others stay assigned).

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Issue

Returns:

the issue with its updated assignee set

action0.github.operations.labels

The label operations (GitHub docs).

class action0.github.operations.labels.ListRepoLabels(*, per_page=30, page=1, owner, repo)[source]

GET /repos/{owner}/{repo}/labels — list a repository’s labels.

>>> operation = ListRepoLabels(owner="python", repo="peps")
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/peps/labels?per_page=30&page=1'
Parameters:
  • per_page (int, default: 30)

  • page (int, default: 1)

  • owner (str)

  • repo (str)

method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/labels'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

Label

Returns:

the label

class action0.github.operations.labels.AddIssueLabels(*, owner, repo, issue_number, labels)[source]

POST /repos/{owner}/{repo}/issues/{issue_number}/labels — add labels to an issue or pull request, keeping the existing ones (unlike UpdateIssue’s labels, which replaces the whole set). Labels that don’t exist in the repository yet are created on the fly.

Parameters:
method: ClassVar[str] = 'POST'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/issues/{issue_number}/labels'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

labels: list[str]

The label names to add.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload (an array)

Return type:

list[Label]

Returns:

the issue’s complete label set after the addition

class action0.github.operations.labels.RemoveIssueLabel(*, owner, repo, issue_number, name)[source]

DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels/{name} — remove one label from an issue or pull request. Unusually for a DELETE, GitHub answers with a body: the remaining label set.

Parameters:
method: ClassVar[str] = 'DELETE'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/issues/{issue_number}/labels/{name}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

name: str

The label name to remove (spaces and unicode are fine — the path segment is percent-encoded).

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload (an array)

Return type:

list[Label]

Returns:

the issue’s remaining label set

class action0.github.operations.labels.CreateLabel(*, owner, repo, name, color=None, description=None)[source]

POST /repos/{owner}/{repo}/labels — create a repository label (requires a token with write access; 422 if the name is taken).

Parameters:
method: ClassVar[str] = 'POST'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/labels'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

name: str

The label name (emoji and unicode are fine).

color: str | None = None

The 6-character hex color code without the leading #; None lets GitHub pick one.

description: str | None = None

The description shown in the label picker.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Label

Returns:

the created label

class action0.github.operations.labels.UpdateLabel(*, owner, repo, name, new_name=None, color=None, description=None)[source]

PATCH /repos/{owner}/{repo}/labels/{name} — update a label. PATCH semantics; renaming goes through new_name (the current name addresses the label in the path) and cascades to every issue carrying the label.

Parameters:
method: ClassVar[str] = 'PATCH'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/labels/{name}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

name: str

The label’s current name.

new_name: str | None = None

The new name; None keeps the current one.

color: str | None = None

The new hex color code (no leading #); None keeps the current one.

description: str | None = None

The new description; None keeps the current one.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Label

Returns:

the updated label

class action0.github.operations.labels.DeleteLabel(*, owner, repo, name)[source]

DELETE /repos/{owner}/{repo}/labels/{name} — delete a label from the repository (removing it from every issue). Answers 204.

Parameters:
method: ClassVar[str] = 'DELETE'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/labels/{name}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

name: str

The label name to delete.

action0.github.operations.milestones

The milestone operations (GitHub docs).

class action0.github.operations.milestones.MilestoneSort(*values)[source]

The sort orders of the milestone listing.

class action0.github.operations.milestones.ListMilestones(*, per_page=30, page=1, owner, repo, state=None, sort=None, direction=None)[source]

GET /repos/{owner}/{repo}/milestones — list a repository’s milestones. The state filter reuses the issue vocabulary (IssueStateFilter — milestones know the same open/closed/all).

>>> operation = ListMilestones(owner="python", repo="peps", sort=MilestoneSort.DUE_ON)
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/peps/milestones?per_page=30&page=1&sort=due_on'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/milestones'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

state: IssueStateFilter | None = None

The state filter; None uses GitHub’s default (open).

sort: MilestoneSort | None = None

The sort order; None uses GitHub’s default (due_on).

direction: SortDirection | None = None

The sort direction; None uses GitHub’s default (asc).

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

Milestone

Returns:

the milestone

class action0.github.operations.milestones.CreateMilestone(*, owner, repo, title, description=None, due_on=None)[source]

POST /repos/{owner}/{repo}/milestones — create a milestone (requires a token with write access).

Parameters:
method: ClassVar[str] = 'POST'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/milestones'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

title: str

The title, e.g. "v1.0".

description: str | None = None

The description, if any.

due_on: datetime | None = None

The due date (serialized to ISO 8601 in the JSON body).

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Milestone

Returns:

the created milestone (with its server-assigned number)

class action0.github.operations.milestones.UpdateMilestone(*, owner, repo, milestone_number, title=None, state=None, description=None, due_on=None)[source]

PATCH /repos/{owner}/{repo}/milestones/{milestone_number} — update a milestone. PATCH semantics: None fields stay untouched; closing is state=IssueState.CLOSED.

Parameters:
method: ClassVar[str] = 'PATCH'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/milestones/{milestone_number}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

milestone_number: int

The milestone number (Milestone.number — unique per repository, not the global id).

title: str | None = None

The new title; None keeps the current one.

state: IssueState | None = None

Open or close the milestone; None keeps the state.

description: str | None = None

The new description; None keeps the current one.

due_on: datetime | None = None

The new due date; None keeps the current one.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Milestone

Returns:

the updated milestone

class action0.github.operations.milestones.DeleteMilestone(*, owner, repo, milestone_number)[source]

DELETE /repos/{owner}/{repo}/milestones/{milestone_number} — delete a milestone (its issues survive, unassigned). Answers 204.

Parameters:
  • owner (str)

  • repo (str)

  • milestone_number (int)

method: ClassVar[str] = 'DELETE'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/milestones/{milestone_number}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

milestone_number: int

The milestone number (not the global id).

action0.github.operations.pulls

The pull request operations (GitHub docs).

class action0.github.operations.pulls.PullStateFilter(*values)[source]

The state filter of ListPulls (unlike IssueState it knows all).

class action0.github.operations.pulls.PullSort(*values)[source]

The sort orders of the pull request listing.

class action0.github.operations.pulls.MergeMethod(*values)[source]

How MergePull merges.

class action0.github.operations.pulls.ListPulls(*, per_page=30, page=1, owner, repo, state=None, head=None, base=None, sort=None, direction=None)[source]

GET /repos/{owner}/{repo}/pulls — list a repository’s pull requests.

>>> operation = ListPulls(owner="python", repo="peps", state=PullStateFilter.CLOSED)
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/peps/pulls?per_page=30&page=1&state=closed'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/pulls'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

state: PullStateFilter | None = None

The state filter; None uses GitHub’s default (open).

head: str | None = None

Only pull requests from this head, as "owner:branch" (e.g. "octocat:new-topic").

base: str | None = None

Only pull requests targeting this base branch name (e.g. "main").

sort: PullSort | None = None

The sort order; None uses GitHub’s default (created).

direction: SortDirection | None = None

The sort direction; None uses GitHub’s default (desc when sorting by created, asc otherwise).

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

PullRequest

Returns:

the pull request

class action0.github.operations.pulls.GetPull(*, owner, repo, pull_number)[source]

GET /repos/{owner}/{repo}/pulls/{pull_number} — fetch one pull request, including the merge/diff statistics the listings omit (mergeable, commits, …).

>>> operation = GetPull(owner="python", repo="peps", pull_number=42)
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/peps/pulls/42'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/pulls/{pull_number}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

PullRequest

Returns:

the pull request

class action0.github.operations.pulls.CreatePull(*, owner, repo, title, head, base, body=None, draft=None)[source]

POST /repos/{owner}/{repo}/pulls — open a pull request.

The non-path fields become the JSON request body; None fields are omitted from it (requires a token with write access to the repository).

Parameters:
method: ClassVar[str] = 'POST'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/pulls'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

title: str

The pull request title.

head: str

The branch with the changes — a plain branch name, or "owner:branch" for a cross-repository (fork) pull request.

base: str

The branch the changes should be merged into (in the {owner}/{repo} repository), e.g. "main".

body: str | None = None

The description text (GitHub-flavored Markdown).

draft: bool | None = None

Open as a draft pull request; None uses GitHub’s default (False).

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

PullRequest

Returns:

the created pull request (with its server-assigned number)

class action0.github.operations.pulls.UpdatePull(*, owner, repo, pull_number, title=None, body=None, state=None, base=None)[source]

PATCH /repos/{owner}/{repo}/pulls/{pull_number} — update a pull request. PATCH semantics as in UpdateIssue: a None field is omitted from the body and leaves the pull request untouched. Note “merged” is not a state — MergePull merges, state only opens/closes.

Parameters:
method: ClassVar[str] = 'PATCH'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/pulls/{pull_number}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

title: str | None = None

The new title; None leaves it unchanged.

body: str | None = None

The new description text; None leaves it unchanged.

state: IssueState | None = None

Close or reopen the pull request; None leaves the state unchanged.

base: str | None = None

Retarget to this base branch name; None leaves it unchanged.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

PullRequest

Returns:

the updated pull request

class action0.github.operations.pulls.MergePull(*, owner, repo, pull_number, merge_method=None, commit_title=None, commit_message=None, sha=None)[source]

PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge — merge a pull request.

An unmergeable pull request (conflicts, failing required checks, a sha guard mismatch) is answered with 405/409, surfacing as an APIError. Although PUT is nominally idempotent, re-merging an already merged pull request also 405s — the retry policy’s method gate is no license here, so prefer the sha guard for defensive merging.

Parameters:
method: ClassVar[str] = 'PUT'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/pulls/{pull_number}/merge'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

merge_method: MergeMethod | None = None

How to merge; None uses the repository’s default method.

commit_title: str | None = None

The merge commit title; None uses GitHub’s default.

commit_message: str | None = None

The merge commit message body; None uses GitHub’s default.

sha: str | None = None

Only merge if the head is still at this sha — guards against merging commits pushed after the last review.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

MergeResult

Returns:

the merge result

class action0.github.operations.pulls.ListPullFiles(*, per_page=30, page=1, owner, repo, pull_number)[source]

GET /repos/{owner}/{repo}/pulls/{pull_number}/files — list the files a pull request changes (the same per-file diff shape commits use; GitHub caps the listing at 3000 files).

>>> operation = ListPullFiles(owner="python", repo="peps", pull_number=42)
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/peps/pulls/42/files?per_page=30&page=1'
Parameters:
  • per_page (int, default: 30)

  • page (int, default: 1)

  • owner (str)

  • repo (str)

  • pull_number (int)

method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/pulls/{pull_number}/files'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

CommitFile

Returns:

the diff file

class action0.github.operations.pulls.ListPullCommits(*, per_page=30, page=1, owner, repo, pull_number)[source]

GET /repos/{owner}/{repo}/pulls/{pull_number}/commits — list a pull request’s commits, oldest first (capped at 250 by GitHub; for more, use ListCommits on the head branch).

>>> operation = ListPullCommits(owner="python", repo="peps", pull_number=42)
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/peps/pulls/42/commits?per_page=30&page=1'
Parameters:
  • per_page (int, default: 30)

  • page (int, default: 1)

  • owner (str)

  • repo (str)

  • pull_number (int)

method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/pulls/{pull_number}/commits'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

Commit

Returns:

the commit

action0.github.operations.commits

The commit operations (GitHub docs).

class action0.github.operations.commits.ListCommits(*, per_page=30, page=1, owner, repo, sha=None, file_path=None, author=None, committer=None, since=None, until=None)[source]

GET /repos/{owner}/{repo}/commits — list a repository’s commits, newest first.

The file_path filter is called path on the wire — that name would shadow the operation’s own path template attribute, so the field carries a wire-name alias:

>>> operation = ListCommits(owner="python", repo="peps", file_path="pep-0008.txt")
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/peps/commits?per_page=30&page=1&path=pep-0008.txt'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/commits'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

sha: str | None = None

The sha, branch or tag to start listing from; None uses the repository’s default branch.

file_path: str | None = None

Only commits touching this file or directory path (sent as path — GitHub’s parameter name, aliased here because path is the operation’s path template).

author: str | None = None

Only commits by this author — a GitHub login or an email address.

committer: str | None = None

Only commits committed by this account — a GitHub login or an email address.

since: datetime | None = None

Only commits authored at or after this time (serialized to ISO 8601).

until: datetime | None = None

Only commits authored at or before this time (serialized to ISO 8601).

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

Commit

Returns:

the commit

class action0.github.operations.commits.GetCommit(*, owner, repo, ref)[source]

GET /repos/{owner}/{repo}/commits/{ref} — fetch one commit, including the diff statistics and files the listings omit (additions, files, …; GitHub caps files at 300 for very large commits).

>>> operation = GetCommit(owner="octo", repo="demo", ref="6dcb09b5")
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/octo/demo/commits/6dcb09b5'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/commits/{ref}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

ref: str

The commit to fetch — a sha, branch name or tag name.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Commit

Returns:

the commit

class action0.github.operations.commits.CompareCommits(*, owner, repo, base, head)[source]

GET /repos/{owner}/{repo}/compare/{base}...{head} — compare two commits: GitHub’s three-dot comparison, measuring head against the merge base (like git log base...head).

The endpoint’s basehead path segment combines two refs — here they stay two typed fields, joined by the path template (for a cross-fork comparison, prefix the ref with the fork owner, e.g. head="octocat:topic"):

>>> operation = CompareCommits(owner="octo", repo="demo", base="main", head="topic")
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/octo/demo/compare/main...topic'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/compare/{base}...{head}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

base: str

The ref to measure against — a sha, branch or tag name.

head: str

The ref with the changes — a sha, branch or tag name ("owner:ref" for a fork).

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Comparison

Returns:

the comparison

class action0.github.operations.commits.ListPullsForCommit(*, per_page=30, page=1, owner, repo, commit_sha)[source]

GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls — list the pull requests a commit belongs to (open and merged) — the reverse lookup of ListPullCommits.

Parameters:
  • per_page (int, default: 30)

  • page (int, default: 1)

  • owner (str)

  • repo (str)

  • commit_sha (str)

method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/commits/{commit_sha}/pulls'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

commit_sha: str

The full commit sha (unlike GetCommit’s ref, GitHub wants a sha here, not a branch or tag).

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

PullRequest

Returns:

the pull request

action0.github.operations.checks

The check run operations (GitHub docs).

class action0.github.operations.checks.CheckRunStatusFilter(*values)[source]

The status filter of ListCheckRunsForRef.

class action0.github.operations.checks.ListCheckRunsForRef(*, per_page=30, page=1, owner, repo, ref, check_name=None, status=None)[source]

GET /repos/{owner}/{repo}/commits/{ref}/check-runs — list a commit’s check runs (the Checks API — GitHub Actions and modern CI apps report here; the classic statuses live in GetCombinedStatus).

The one listing whose payload is not a bare array: GitHub wraps it in a {total_count, check_runs} envelope, so load_json() unwraps before the usual per-item parsing (pagination still runs on the Link header, like everywhere else).

Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/commits/{ref}/check-runs'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

ref: str

The commit to list checks for — a sha, branch or tag.

check_name: str | None = None

Only runs of the check with this name; None lists all.

status: CheckRunStatusFilter | None = None

Only runs in this lifecycle phase; None lists all.

load_item(data)[source]
Parameters:

data (Any) – one item of the envelope’s check_runs array

Return type:

CheckRun

Returns:

the check run

load_json(data)[source]

Unwrap GitHub’s {total_count, check_runs} envelope into the usual page.

Parameters:

data (Any) – the decoded JSON payload (the envelope)

Return type:

Page[CheckRun]

Returns:

the page, pagination not yet attached

action0.github.operations.statuses

The commit status operations (GitHub docs).

class action0.github.operations.statuses.GetCombinedStatus(*, owner, repo, ref)[source]

GET /repos/{owner}/{repo}/commits/{ref}/status — the rolled-up commit status: one state over all contexts, plus the individual statuses. The classic pre-merge gate — pair it with ListCheckRunsForRef, which covers the newer Checks API (GitHub Actions reports there, not here).

>>> operation = GetCombinedStatus(owner="octo", repo="demo", ref="main")
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/octo/demo/commits/main/status'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/commits/{ref}/status'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

ref: str

The commit to check — a sha, branch or tag.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

CombinedStatus

Returns:

the combined status

action0.github.operations.contents

The repository content operations (GitHub docs).

class action0.github.operations.contents.GetContent(*, owner, repo, file_path, ref=None)[source]

GET /repos/{owner}/{repo}/contents/{file_path} — fetch a file or list a directory.

GitHub answers with an object for a file (base64-encoded content inlined) and an array for a directory — the result type is the union, dispatched on the payload shape:

>>> operation = GetContent(owner="octo", repo="demo", file_path="src/app.py")
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/octo/demo/contents/src/app.py'

(The field is file_path because path is the operation’s own path template attribute; an empty string lists the repository root.)

Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/contents/{file_path}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

file_path: str

The path within the repository — a file for a ContentFile result, a directory (or "" for the root) for a list of DirectoryEntry.

ref: str | None = None

The branch, tag or sha to read from; None uses the repository’s default branch.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload — object or array

Return type:

ContentFile | list[DirectoryEntry]

Returns:

the file, or the directory listing

class action0.github.operations.contents.GetReadme(*, owner, repo, ref=None)[source]

GET /repos/{owner}/{repo}/readme — fetch a repository’s README, whatever it is called (README.md, README.rst, …).

>>> operation = GetReadme(owner="python", repo="peps")
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/peps/readme'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/readme'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

ref: str | None = None

The branch, tag or sha to read from; None uses the repository’s default branch.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

ContentFile

Returns:

the README file

class action0.github.operations.contents.CreateOrUpdateFile(*, owner, repo, file_path, message, content, sha=None, branch=None)[source]

PUT /repos/{owner}/{repo}/contents/{file_path} — create a file, or update one (requires a token with write access; every call is one commit).

Create and update are the same endpoint, told apart by sha: None creates — GitHub answers 422 if the file already exists — and passing the file’s current blob sha updates, answering 409 on a mismatch (someone else wrote in between; both surface as APIError). Pass raw bytes as content — the base64 transport encoding is applied on serialization (a serialize= field hook).

Parameters:
method: ClassVar[str] = 'PUT'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/contents/{file_path}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

file_path: str

The path of the file within the repository.

message: str

The commit message.

content: bytes

The new file content, raw — base64 happens on the wire.

sha: str | None = None

The blob sha the file currently has (sha) when updating; None creates a new file.

branch: str | None = None

The branch to commit to; None uses the repository’s default branch.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

FileCommit

Returns:

the created commit and the written file (whose fresh sha the next update of the same file needs)

class action0.github.operations.contents.DeleteFile(*, owner, repo, file_path, message, sha, branch=None)[source]

DELETE /repos/{owner}/{repo}/contents/{file_path} — delete a file, as one commit. Unusually for a DELETE it carries a JSON body (the commit message and the blob sha) and answers with one — the commit — so this is no NoContentOperation.

Parameters:
method: ClassVar[str] = 'DELETE'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/contents/{file_path}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

file_path: str

The path of the file within the repository.

message: str

The commit message.

sha: str

The blob sha the file currently has — required; GitHub answers 409 on a mismatch.

branch: str | None = None

The branch to commit to; None uses the repository’s default branch.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

FileCommit

Returns:

the deleting commit (content is None)

action0.github.operations.orgs

The organization operations (GitHub docs).

class action0.github.operations.orgs.OrgMemberRole(*values)[source]

The role filter of ListOrgMembers.

class action0.github.operations.orgs.GetOrg(*, org)[source]

GET /orgs/{org} — fetch an organization’s public profile (plus the private counters, if the token is a member’s).

>>> operation = GetOrg(org="python")
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/orgs/python'
Parameters:

org (str)

method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/orgs/{org}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Organization

Returns:

the organization

class action0.github.operations.orgs.ListOrgMembers(*, per_page=30, page=1, org, role=None)[source]

GET /orgs/{org}/members — list an organization’s members (only the public ones, unless the token is a member’s).

>>> operation = ListOrgMembers(org="python", role=OrgMemberRole.ADMIN)
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/orgs/python/members?per_page=30&page=1&role=admin'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/orgs/{org}/members'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

role: OrgMemberRole | None = None

The role filter; None uses GitHub’s default (all).

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

SimpleUser

Returns:

the member

action0.github.operations.reviews

The pull request review operations (GitHub docs).

class action0.github.operations.reviews.ReviewEvent(*values)[source]

The verdict submitted with CreatePullReview — uppercase on the wire, like the review states.

class action0.github.operations.reviews.ReviewSide(*values)[source]

Which side of the diff a review comment anchors to.

class action0.github.operations.reviews.DraftReviewComment(path, body, line, side=None, start_line=None, start_side=None)[source]

One line comment submitted inside a CreatePullReview batch — a plain dataclass that becomes one entry of the review’s comments array (None fields are omitted, as everywhere). For a standalone comment outside a review, use CreateReviewComment.

Parameters:
path: str

The file the comment anchors to.

body: str

The comment text (GitHub-flavored Markdown).

line: int

The line in the diff (the last line, for a multi-line comment).

side: ReviewSide | None = None

Which side of the diff; None uses GitHub’s default (RIGHT — the new code).

start_line: int | None = None

The first line, to span a multi-line range; None comments a single line.

start_side: ReviewSide | None = None

The side of start_line; None uses GitHub’s default.

class action0.github.operations.reviews.ListPullReviews(*, per_page=30, page=1, owner, repo, pull_number)[source]

GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews — list a pull request’s reviews, in chronological order.

>>> operation = ListPullReviews(owner="python", repo="peps", pull_number=42)
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/peps/pulls/42/reviews?per_page=30&page=1'
Parameters:
  • per_page (int, default: 30)

  • page (int, default: 1)

  • owner (str)

  • repo (str)

  • pull_number (int)

method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/pulls/{pull_number}/reviews'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

Review

Returns:

the review

class action0.github.operations.reviews.CreatePullReview(*, owner, repo, pull_number, event, body=None, commit_id=None, comments=None)[source]

POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews — review a pull request: approve it, request changes or leave a summary comment (requires a token with write access; GitHub refuses approving your own pull request).

This is the plain review flow — submitting line comments in a batch is a separate, heavier payload this client does not model.

Parameters:
method: ClassVar[str] = 'POST'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/pulls/{pull_number}/reviews'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

event: ReviewEvent

The verdict. (Omitting it would create a PENDING draft review — this client always submits.)

body: str | None = None

The summary text — required by GitHub for REQUEST_CHANGES and COMMENT, optional for an approval.

commit_id: str | None = None

The commit the review refers to; None uses the pull request’s current head (and risks reviewing code pushed while you were reading).

comments: list[DraftReviewComment] | None = None

Line comments to submit with the review, as DraftReviewComment entries — serialized straight into GitHub’s comments array.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Review

Returns:

the created review

class action0.github.operations.reviews.ListReviewComments(*, per_page=30, page=1, owner, repo, pull_number, since=None)[source]

GET /repos/{owner}/{repo}/pulls/{pull_number}/comments — list a pull request’s review comments (the ones anchored to diff lines). The conversation thread lives on the issue side — that is ListIssueComments.

Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/pulls/{pull_number}/comments'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

since: datetime | None = None

Only comments updated at or after this time (serialized to ISO 8601).

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

ReviewComment

Returns:

the review comment

class action0.github.operations.reviews.CreateReviewComment(*, owner, repo, pull_number, body, commit_id, file_path, line, side=None, start_line=None, start_side=None)[source]

POST /repos/{owner}/{repo}/pulls/{pull_number}/comments — leave one standalone line comment on a pull request’s diff (requires a token with write access). For several at once, batch them into a review via CreatePullReview’s comments.

Parameters:
method: ClassVar[str] = 'POST'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/pulls/{pull_number}/comments'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

body: str

The comment text (GitHub-flavored Markdown).

commit_id: str

The sha the comment refers to — the pull request’s head sha (pull.head.sha), not the merge commit.

file_path: str

The file to anchor to (sent as path — aliased like everywhere the name would shadow the path template).

line: int

The line in the diff (the last line, for a multi-line comment).

side: ReviewSide | None = None

Which side of the diff; None uses GitHub’s default (RIGHT — the new code).

start_line: int | None = None

The first line, to span a multi-line range; None comments a single line.

start_side: ReviewSide | None = None

The side of start_line; None uses GitHub’s default.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

ReviewComment

Returns:

the created comment (with its server-assigned id)

class action0.github.operations.reviews.RequestReviewers(*, owner, repo, pull_number, reviewers=None, team_reviewers=None)[source]

POST /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers — ask users (and/or teams) for a review. GitHub requires at least one of the two lists, refuses the pull request’s own author, and answers 422 for non-collaborators.

Parameters:
method: ClassVar[str] = 'POST'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

reviewers: list[str] | None = None

The logins to request.

team_reviewers: list[str] | None = None

The team slugs to request (organization repositories only).

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

PullRequest

Returns:

the pull request with its updated requested_reviewers

class action0.github.operations.reviews.RemoveRequestedReviewers(*, owner, repo, pull_number, reviewers, team_reviewers=None)[source]

DELETE /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers — withdraw review requests (a DELETE with a JSON body, like RemoveAssignees).

Parameters:
method: ClassVar[str] = 'DELETE'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

reviewers: list[str]

The logins whose request to withdraw.

team_reviewers: list[str] | None = None

The team slugs whose request to withdraw.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

PullRequest

Returns:

the pull request with its updated requested_reviewers

action0.github.operations.releases

The release operations (GitHub docs).

action0.github.operations.releases.GITHUB_UPLOADS_URL = 'https://uploads.github.com'

The base URL of GitHub’s upload host — what a client running UploadReleaseAsset must be pointed at (uploads do not go to api.github.com).

class action0.github.operations.releases.ListReleases(*, per_page=30, page=1, owner, repo)[source]

GET /repos/{owner}/{repo}/releases — list a repository’s releases, most recent first (drafts and prereleases included, as far as the token may see them).

>>> operation = ListReleases(owner="python", repo="cpython", per_page=5)
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/cpython/releases?per_page=5&page=1'
Parameters:
  • per_page (int, default: 30)

  • page (int, default: 1)

  • owner (str)

  • repo (str)

method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/releases'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

Release

Returns:

the release

class action0.github.operations.releases.GetLatestRelease(*, owner, repo)[source]

GET /repos/{owner}/{repo}/releases/latest — fetch the latest release. “Latest” is the most recently published full release: drafts and prereleases never qualify, so this can be older than the first entry of ListReleases.

Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/releases/latest'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Release

Returns:

the release

class action0.github.operations.releases.GetReleaseByTag(*, owner, repo, tag)[source]

GET /repos/{owner}/{repo}/releases/tags/{tag} — fetch the release for a git tag.

>>> operation = GetReleaseByTag(owner="octo", repo="demo", tag="v1.0.0")
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/octo/demo/releases/tags/v1.0.0'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/releases/tags/{tag}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Release

Returns:

the release

class action0.github.operations.releases.CreateRelease(*, owner, repo, tag_name, target_commitish=None, name=None, body=None, draft=None, prerelease=None, generate_release_notes=None)[source]

POST /repos/{owner}/{repo}/releases — create a release (and, unless the tag exists already, the tag itself, once the release is published). Requires a token with write access.

Parameters:
  • owner (str)

  • repo (str)

  • tag_name (str)

  • target_commitish (str | None, default: None)

  • name (str | None, default: None)

  • body (str | None, default: None)

  • draft (bool | None, default: None)

  • prerelease (bool | None, default: None)

  • generate_release_notes (bool | None, default: None)

method: ClassVar[str] = 'POST'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/releases'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

tag_name: str

The git tag the release points at — created from target_commitish if it does not exist yet.

target_commitish: str | None = None

The branch or commit to tag if the tag is new; None uses the repository’s default branch. Ignored if the tag exists.

name: str | None = None

The release title; None leaves it unset.

body: str | None = None

The release notes (GitHub-flavored Markdown).

draft: bool | None = None

Create as an unpublished draft; None uses GitHub’s default (False — published immediately).

prerelease: bool | None = None

Mark as a prerelease; None uses GitHub’s default (False).

generate_release_notes: bool | None = None

Let GitHub generate the notes (appended to body if both are given); None uses GitHub’s default (False). For generating without publishing, see GenerateReleaseNotes.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Release

Returns:

the created release (with its server-assigned id)

class action0.github.operations.releases.UpdateRelease(*, owner, repo, release_id, tag_name=None, name=None, body=None, draft=None, prerelease=None)[source]

PATCH /repos/{owner}/{repo}/releases/{release_id} — update a release. PATCH semantics: a None field is omitted from the body and leaves the release untouched (publishing a draft is draft=False).

Parameters:
method: ClassVar[str] = 'PATCH'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/releases/{release_id}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

release_id: int

The release id (Release.id — not the tag).

tag_name: str | None = None

The new tag; None leaves it unchanged.

name: str | None = None

The new title; None leaves it unchanged.

body: str | None = None

The new release notes; None leaves them unchanged.

draft: bool | None = None

Set the draft flag — False publishes a draft; None leaves it unchanged.

prerelease: bool | None = None

Set the prerelease flag; None leaves it unchanged.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

Release

Returns:

the updated release

class action0.github.operations.releases.DeleteRelease(*, owner, repo, release_id)[source]

DELETE /repos/{owner}/{repo}/releases/{release_id} — delete a release. Answers 204. The tag stays — deleting a release does not delete the git tag it pointed at.

Parameters:
method: ClassVar[str] = 'DELETE'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/releases/{release_id}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

release_id: int

The release id (not the tag).

class action0.github.operations.releases.GenerateReleaseNotes(*, owner, repo, tag_name, target_commitish=None, previous_tag_name=None)[source]

POST /repos/{owner}/{repo}/releases/generate-notes — have GitHub write release notes (the merged-PRs changelog) for a tag, without creating or publishing anything. Feed the result into CreateRelease — or skip this round-trip entirely with its generate_release_notes flag if the text needs no editing.

Parameters:
  • owner (str)

  • repo (str)

  • tag_name (str)

  • target_commitish (str | None, default: None)

  • previous_tag_name (str | None, default: None)

method: ClassVar[str] = 'POST'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/releases/generate-notes'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

tag_name: str

The tag to generate notes for (need not exist yet).

target_commitish: str | None = None

The branch or commit the tag would point at, if it is new; None uses the repository’s default branch.

previous_tag_name: str | None = None

The tag to diff against; None lets GitHub pick the previous release automatically.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

ReleaseNotes

Returns:

the generated notes

class action0.github.operations.releases.UploadReleaseAsset(*, owner, repo, release_id, name, data, content_type, label=None)[source]

POST /repos/{owner}/{repo}/releases/{release_id}/assets — attach a file to a release. This is the one operation that does not go to api.github.com: GitHub takes uploads on a separate host, so send it through a client pointed at GITHUB_UPLOADS_URL (same token; keep it next to your API client):

upload_client = GitHubClient(backend, token=token, base_url=GITHUB_UPLOADS_URL)
asset = upload_client.send(UploadReleaseAsset(...))

The raw bytes are the request body; pass a FileBody (or any BodyProducer) to stream a large file from disk instead of holding it in memory. GitHub answers 422 if an asset of that name exists already.

Parameters:
method: ClassVar[str] = 'POST'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/releases/{release_id}/assets'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

release_id: int

The release id (not the tag).

name: str

The file name the asset gets, e.g. "demo-1.0.0.tar.gz" (unusually for a POST, sent as a query parameter — GitHub’s design, the body being the raw bytes).

data: bytes | BodyProducer

The file content, raw.

content_type: str

The asset’s MIME type, e.g. "application/gzip" — becomes the Content-Type of the upload request and later the content_type served on download.

label: str | None = None

The display label shown instead of the file name; None leaves it unset.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

ReleaseAsset

Returns:

the uploaded asset (with its server-assigned id)

class action0.github.operations.releases.DownloadReleaseAsset(*, owner, repo, asset_id)[source]

GET /repos/{owner}/{repo}/releases/assets/{asset_id} with Accept: application/octet-stream — download an asset’s binary content.

Unlike every other operation this is not a GitHubOperation: the result is not JSON but the raw body, handed out as a BodyProducer. Run it on a backend with stream=True and the body is never held in memory — iterate chunks() (sync) or achunks() (async) and write the chunks out as they arrive. Keep that streaming backend separate from the one running JSON operations (backends are cheap to have two of).

Two GitHub particulars:

  • GitHub answers with a 302 redirect to a short-lived CDN URL, so the backend must follow redirects — requests, aiohttp and urllib do by default, httpx needs follow_redirects=True.

  • The asset id comes from id, not from the browser download URL.

Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/repos/{owner}/{repo}/releases/assets/{asset_id}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

accept: ClassVar[str | None] = 'application/octet-stream'

The Accept header to send, unless one is set explicitly; None sends none. JsonOperation sets application/json.

load(response)[source]

Hand out the response body as a producer — nothing reads it until the caller iterates.

Parameters:

response (Response) – the response, already vetted

Return type:

BodyProducer

Returns:

the body producer (an empty producer for a bodyless response)

action0.github.operations.search

The search operations (GitHub docs).

class action0.github.operations.search.RepoSearchSort(*values)[source]

The sort orders of the repository search (None = best match).

class action0.github.operations.search.IssueSearchSort(*values)[source]

The sort orders of the issue search (None = best match).

class action0.github.operations.search.UserSearchSort(*values)[source]

The sort orders of the user search (None = best match).

class action0.github.operations.search.SearchOperation(*, per_page=30, page=1)[source]

The base class of the search operations: GitHub wraps search results in a {total_count, incomplete_results, items} envelope instead of a bare array, parsed into a SearchPage.

Subclasses implement load_item() for one items entry.

Parameters:
  • per_page (int, default: 30)

  • page (int, default: 1)

per_page: int = 30

The page size (GitHub caps it at 100).

page: int = 1

The page number, starting at 1.

abstractmethod load_item(data)[source]

Turn one entry of the envelope’s items array into the typed model.

Parameters:

data (Any) – one decoded items entry

Return type:

TypeVar(ItemT)

Returns:

the parsed item

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload (the search envelope)

Return type:

SearchPage[TypeVar(ItemT)]

Returns:

the search page, without pagination yet (load() adds it — only the response’s Link header knows)

load(response)[source]

Decode the envelope and attach the next-page operation if the response’s Link header announces one.

Parameters:

response (Response) – the response, already vetted

Return type:

SearchPage[TypeVar(ItemT)]

Returns:

the search page

class action0.github.operations.search.SearchRepos(*, per_page=30, page=1, q, sort=None, order=None)[source]

GET /search/repositories — search repositories with GitHub’s query syntax.

>>> operation = SearchRepos(q="http client language:python", sort=RepoSearchSort.STARS)
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/search/repositories?per_page=30&page=1&q=http+client+language%3Apython&sort=stars'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/search/repositories'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

q: str

The search query, e.g. "http client language:python stars:>100".

sort: RepoSearchSort | None = None

The sort order; None uses GitHub’s default (best match).

order: SortDirection | None = None

The sort direction (GitHub’s parameter name for search); only applied when sort is set, default desc.

load_item(data)[source]
Parameters:

data (Any) – one decoded items entry

Return type:

Repo

Returns:

the repository

class action0.github.operations.search.SearchIssues(*, per_page=30, page=1, q, sort=None, order=None)[source]

GET /search/issues — search issues and pull requests with GitHub’s query syntax.

The hits include pull requests (every pull request is an issue) — filter with is:issue/is:pr in the query, or after the fact via is_pull_request.

>>> operation = SearchIssues(q="repo:python/peps is:open label:bug")
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/search/issues?per_page=30&page=1&q=repo%3Apython%2Fpeps+is%3Aopen+label%3Abug'
Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/search/issues'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

q: str

The search query, e.g. "repo:python/peps is:open label:bug".

sort: IssueSearchSort | None = None

The sort order; None uses GitHub’s default (best match).

order: SortDirection | None = None

The sort direction (GitHub’s parameter name for search); only applied when sort is set, default desc.

load_item(data)[source]
Parameters:

data (Any) – one decoded items entry

Return type:

Issue

Returns:

the issue (or pull request)

class action0.github.operations.search.SearchUsers(*, per_page=30, page=1, q, sort=None, order=None)[source]

GET /search/users — search users and organizations with GitHub’s query syntax.

The hits carry only the embedded-user fields, hence SimpleUser — fetch the full profile with GetUser.

Parameters:
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/search/users'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

q: str

The search query, e.g. "fullname:Guido type:user".

sort: UserSearchSort | None = None

The sort order; None uses GitHub’s default (best match).

order: SortDirection | None = None

The sort direction (GitHub’s parameter name for search); only applied when sort is set, default desc.

load_item(data)[source]
Parameters:

data (Any) – one decoded items entry

Return type:

SimpleUser

Returns:

the user

action0.github.operations.rate_limit

The rate limit operation (GitHub docs).

class action0.github.operations.rate_limit.GetRateLimit[source]

GET /rate_limit — the current rate limit status for the authenticated user (or the IP, without a token).

This call itself does not count against any limit, so it is safe to check before a burst of requests — the proactive complement to GitHubRetryPolicy, which reacts once a limit hits.

>>> GetRateLimit().as_request("https://api.github.com").url.as_str()
'https://api.github.com/rate_limit'
method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/rate_limit'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

RateLimitOverview

Returns:

the overview across all resource categories

action0.github.operations.users

The user operations (GitHub docs).

class action0.github.operations.users.GetUser(*, username)[source]

GET /users/{username} — fetch a user’s public profile.

>>> GetUser(username="gvanrossum").as_request("https://api.github.com").url.as_str()
'https://api.github.com/users/gvanrossum'
Parameters:

username (str)

method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/users/{username}'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

User

Returns:

the user

class action0.github.operations.users.GetAuthenticatedUser[source]

GET /user — fetch the profile behind the client’s token (requires one; the response additionally carries private counts the User model ignores).

method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/user'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_json(data)[source]
Parameters:

data (Any) – the decoded JSON payload

Return type:

User

Returns:

the authenticated user

class action0.github.operations.users.ListFollowers(*, per_page=30, page=1, username)[source]

GET /users/{username}/followers — list who follows a user.

>>> operation = ListFollowers(username="gvanrossum")
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/users/gvanrossum/followers?per_page=30&page=1'
Parameters:
  • per_page (int, default: 30)

  • page (int, default: 1)

  • username (str)

method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/users/{username}/followers'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

SimpleUser

Returns:

the follower

class action0.github.operations.users.ListUserOrgs(*, per_page=30, page=1, username)[source]

GET /users/{username}/orgs — list a user’s public organization memberships. The items are SimpleOrganization — the membership payloads carry no profile fields, so follow up with GetOrg for the full Organization.

Parameters:
  • per_page (int, default: 30)

  • page (int, default: 1)

  • username (str)

method: ClassVar[str] = 'GET'

The HTTP method of the endpoint — fixed per operation class.

path: ClassVar[str] = '/users/{username}/orgs'

The path template of the endpoint, appended to the client’s base URL. {placeholder} names are filled from the operation’s path_param() fields. A leading / is optional — the path is always joined to the base URL with exactly one /.

load_item(data)[source]
Parameters:

data (Any) – one decoded JSON array item

Return type:

SimpleOrganization

Returns:

the organization membership entry

action0.github.models

The result models — plain dataclasses the operations hand to the application, each with a from_json classmethod building it from the decoded API payload. They cover the commonly used fields of the GitHub schemas, not every last one.

action0.github.models.user

The user models: SimpleUser (as GitHub embeds it in other resources), the full User profile and the Contributor variant.

class action0.github.models.user.SimpleUser(login, id, html_url, type)[source]

A user (or organization) as embedded in other GitHub resources, e.g. as the owner of a repository.

This is GitHub’s simple-user schema, reduced to the fields the shipped operations use.

Parameters:
login: str

The login name, e.g. "python".

id: int

The numeric user id.

html_url: str

The profile URL, e.g. "https://github.com/python".

type: str

"User" or "Organization".

classmethod from_json(data)[source]

Build a user from one decoded JSON object.

>>> SimpleUser.from_json(
...     {
...         "login": "python",
...         "id": 1525981,
...         "html_url": "https://github.com/python",
...         "type": "Organization",
...     }
... )
SimpleUser(login='python', id=1525981, html_url='https://github.com/python', type='Organization')
Parameters:

data (Any) – the decoded JSON object

Return type:

SimpleUser

Returns:

the user

class action0.github.models.user.Contributor(login, id, html_url, type, contributions=0)[source]

A repository contributor — a SimpleUser plus their commit count, as ListContributors returns it.

Parameters:
  • login (str)

  • id (int)

  • html_url (str)

  • type (str)

  • contributions (int, default: 0)

contributions: int = 0

The number of commits to the repository.

classmethod from_json(data)[source]

Build a contributor from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

Contributor

Returns:

the contributor

class action0.github.models.user.User(login, id, html_url, type, name=None, company=None, blog=None, location=None, email=None, bio=None, public_repos=0, public_gists=0, followers=0, following=0, created_at=None, updated_at=None)[source]

A full user (or organization) profile, as the user endpoints return it: the SimpleUser core plus the public profile fields.

This is GitHub’s public-user schema, reduced to the commonly used fields (for the authenticated user, GitHub sends additional private fields the model ignores).

Parameters:
  • login (str)

  • id (int)

  • html_url (str)

  • type (str)

  • name (str | None, default: None)

  • company (str | None, default: None)

  • blog (str | None, default: None)

  • location (str | None, default: None)

  • email (str | None, default: None)

  • bio (str | None, default: None)

  • public_repos (int, default: 0)

  • public_gists (int, default: 0)

  • followers (int, default: 0)

  • following (int, default: 0)

  • created_at (datetime | None, default: None)

  • updated_at (datetime | None, default: None)

name: str | None = None

The display name, if set.

company: str | None = None

The company, if set.

blog: str | None = None

The blog / website URL, if set.

location: str | None = None

The location, if set.

email: str | None = None

The public email address, if set.

bio: str | None = None

The profile bio, if set.

public_repos: int = 0

The number of public repositories.

public_gists: int = 0

The number of public gists.

followers: int = 0

The number of followers.

following: int = 0

The number of followed users.

created_at: datetime | None = None

When the account was created.

updated_at: datetime | None = None

When the profile was last updated.

classmethod from_json(data)[source]

Build a full user profile from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

User

Returns:

the user

action0.github.models.repo

The repository model (Repo).

class action0.github.models.repo.Repo(id, name, full_name, owner, private, html_url, default_branch, description=None, language=None, stargazers_count=0, forks_count=0, open_issues_count=0, topics=None, archived=False, created_at=None, updated_at=None, pushed_at=None)[source]

A GitHub repository.

This is GitHub’s full-repository schema, reduced to the commonly used fields (the raw payload has ~100 more).

Parameters:
id: int

The numeric repository id.

name: str

The repository name, e.g. "cpython".

full_name: str

Owner and name, e.g. "python/cpython".

owner: SimpleUser

The owning user or organization.

private: bool

Whether the repository is private.

html_url: str

The web URL, e.g. "https://github.com/python/cpython".

default_branch: str

The default branch, e.g. "main".

description: str | None = None

The description, if set.

language: str | None = None

The dominant programming language, if detected.

stargazers_count: int = 0

The number of stars.

forks_count: int = 0

The number of forks.

open_issues_count: int = 0

The number of open issues (including open pull requests).

topics: list[str] | None = None

The repository topics, if any were requested/set.

archived: bool = False

Whether the repository is archived (read-only).

created_at: datetime | None = None

When the repository was created.

updated_at: datetime | None = None

When the repository was last updated.

pushed_at: datetime | None = None

When the repository was last pushed to (None on empty repos).

classmethod from_json(data)[source]

Build a repository from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

Repo

Returns:

the repository

action0.github.models.label

The label model (Label).

class action0.github.models.label.Label(name, id=None, color=None, description=None, default=False)[source]

An issue label.

Everything but the name is optional: in some payloads (and in older parts of the API) GitHub sends labels as bare name strings instead of objects.

Parameters:
  • name (str)

  • id (int | None, default: None)

  • color (str | None, default: None)

  • description (str | None, default: None)

  • default (bool, default: False)

name: str

The label name, e.g. "bug".

id: int | None = None

The numeric label id.

color: str | None = None

The 6-character hex color code, without the leading #.

description: str | None = None

The description, if set.

default: bool = False

Whether this is one of GitHub’s default labels.

classmethod from_json(data)[source]

Build a label from one decoded JSON item — a full label object or a bare name string.

>>> Label.from_json("bug")
Label(name='bug', id=None, color=None, description=None, default=False)
Parameters:

data (Any) – the decoded JSON item

Return type:

Label

Returns:

the label

action0.github.models.branch

The branch model (Branch).

class action0.github.models.branch.Branch(name, sha, protected=False, commit=None)[source]

A repository branch: a name pinned to a commit.

The listing payloads carry only the tip’s sha; fetching one branch via GetBranch fills commit with the full tip commit.

Parameters:
name: str

The branch name, e.g. "main".

sha: str

The sha of the branch tip.

protected: bool = False

Whether branch protection rules apply.

commit: Commit | None = None

The full tip commit (None in listings — only GetBranch payloads carry it).

classmethod from_json(data)[source]

Build a branch from one decoded JSON object.

The listing sends commit as a bare {sha, url} pair, the single-branch endpoint as a full commit object — told apart by the nested commit key only the full object has.

Parameters:

data (Any) – the decoded JSON object

Return type:

Branch

Returns:

the branch

action0.github.models.check

The check run model (CheckRun).

class action0.github.models.check.CheckRunStatus(*values)[source]

The lifecycle phase of a check run.

class action0.github.models.check.CheckConclusion(*values)[source]

The verdict of a completed check run.

class action0.github.models.check.CheckRun(id, name, status, head_sha, conclusion=None, html_url=None, details_url=None, started_at=None, completed_at=None)[source]

A check run — one entry of a commit’s checks tab (the Checks API, what GitHub Actions and modern CI apps report through; the classic statuses are CommitStatus).

Parameters:
id: int

The numeric check run id (globally unique).

name: str

The check name, e.g. "build (3.12)".

status: CheckRunStatus

The lifecycle phase.

head_sha: str

The commit the check ran against.

conclusion: CheckConclusion | None = None

The verdict — None until the run is COMPLETED.

html_url: str | None = None

The web URL of the run.

details_url: str | None = None

The reporting app’s own results page, if any.

started_at: datetime | None = None

When the run started.

completed_at: datetime | None = None

When the run completed (None while in progress).

classmethod from_json(data)[source]

Build a check run from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

CheckRun

Returns:

the check run

action0.github.models.comment

The issue comment model (IssueComment).

class action0.github.models.comment.IssueComment(id, html_url, body, user=None, created_at=None, updated_at=None)[source]

A comment on an issue.

This is GitHub’s issue-comment schema, reduced to the commonly used fields. Pull request conversation comments are issue comments too (every pull request is an issue) — only review comments, the ones anchored to a diff line, live in a separate API.

Parameters:
id: int

The numeric comment id (globally unique).

html_url: str

The web URL, e.g. "https://github.com/octo/demo/issues/1#issuecomment-1".

body: str

The comment text (GitHub-flavored Markdown).

user: SimpleUser | None = None

The author (None e.g. for deleted accounts).

created_at: datetime | None = None

When the comment was written.

updated_at: datetime | None = None

When the comment was last edited.

classmethod from_json(data)[source]

Build a comment from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

IssueComment

Returns:

the comment

action0.github.models.status

The commit status models (CombinedStatus, CommitStatus).

class action0.github.models.status.StatusState(*values)[source]

The state of a commit status (the combined state never says error — GitHub folds errors into failure there).

class action0.github.models.status.CommitStatus(state, context, description=None, target_url=None, created_at=None, updated_at=None)[source]

One commit status — a single context’s verdict on a commit (the classic statuses API; check runs are the newer sibling).

Parameters:
state: StatusState

The verdict.

context: str

The status name, e.g. "ci/jenkins" — one status per context, newer ones replace older ones.

description: str | None = None

The short explanation, if any.

target_url: str | None = None

The link to the full build output, if any.

created_at: datetime | None = None

When the status was first reported.

updated_at: datetime | None = None

When the status was last updated.

classmethod from_json(data)[source]

Build a status from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

CommitStatus

Returns:

the status

class action0.github.models.status.CombinedStatus(state, sha, total_count, statuses=<factory>)[source]

The combined status of a commit — what GetCombinedStatus returns: one rolled-up state over all contexts, plus the individual statuses.

Parameters:
state: StatusState

The rolled-up verdict: success only when every context succeeded, pending when any is pending (or none exist).

sha: str

The commit the statuses apply to.

total_count: int

The number of contexts.

statuses: list[CommitStatus]

The individual statuses, one per context.

classmethod from_json(data)[source]

Build a combined status from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

CombinedStatus

Returns:

the combined status

action0.github.models.tag

The tag model (Tag).

class action0.github.models.tag.Tag(name, sha, zipball_url=None, tarball_url=None)[source]

A repository tag, as ListRepoTags returns it: a name pinned to a commit, plus GitHub’s on-the-fly source archives.

Parameters:
  • name (str)

  • sha (str)

  • zipball_url (str | None, default: None)

  • tarball_url (str | None, default: None)

name: str

The tag name, e.g. "v1.0.0".

sha: str

The sha of the tagged commit.

zipball_url: str | None = None

The URL of the generated .zip source archive.

tarball_url: str | None = None

The URL of the generated .tar.gz source archive.

classmethod from_json(data)[source]

Build a tag from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

Tag

Returns:

the tag

action0.github.models.content

The repository content models (ContentFile, DirectoryEntry, FileCommit).

class action0.github.models.content.ContentType(*values)[source]

What a repository content entry is.

class action0.github.models.content.ContentFile(name, path, sha, size, type, html_url=None, download_url=None, encoding=None, content=None)[source]

A file fetched through the contents API — the object payload of GetContent and GetReadme.

The bytes arrive base64-encoded in content; use decoded (or text) instead of touching the raw transport encoding.

Parameters:
name: str

The file name, e.g. "README.md".

path: str

The path within the repository.

sha: str

The git blob sha (what update/delete operations would need).

size: int

The file size in bytes.

type: ContentType

What the entry is — requesting a symlink or submodule path yields an object without content.

html_url: str | None = None

The web URL.

download_url: str | None = None

The direct (CDN) download URL — the fallback for files whose content GitHub does not inline.

encoding: str | None = None

The transport encoding of content"base64", or "none" when GitHub declined to inline the bytes (files between 1 and 100 MB; fetch those via download_url).

content: str | None = None

The base64-encoded bytes (use decoded).

property decoded: bytes

The decoded file bytes.

Raises:

ValueError – if the payload carries no inlined content (encoding: "none", or a symlink/submodule entry) — fetch via download_url instead

property text: str

The decoded file content as text (UTF-8).

Raises:
classmethod from_json(data)[source]

Build a content file from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

ContentFile

Returns:

the content file

class action0.github.models.content.DirectoryEntry(name, path, sha, size, type, html_url=None, download_url=None)[source]

One entry of a directory listing — the array items GetContent returns for a directory path. Entries carry no content; fetch a file of interest with its own GetContent(file_path=entry.path).

Parameters:
name: str

The entry name, e.g. "app.py".

path: str

The path within the repository.

sha: str

The git object sha.

size: int

The file size in bytes (0 for directories).

type: ContentType

What the entry is.

html_url: str | None = None

The web URL.

download_url: str | None = None

The direct download URL (None for directories).

classmethod from_json(data)[source]

Build a directory entry from one decoded JSON array item.

Parameters:

data (Any) – the decoded JSON array item

Return type:

DirectoryEntry

Returns:

the entry

class action0.github.models.content.FileCommit(commit, content=None)[source]

The answer of the contents write operations (CreateOrUpdateFile, DeleteFile): the commit GitHub created, plus the resulting file entry.

Parameters:
commit: GitCommit

The commit the write produced.

content: ContentFile | None = None

The written file — its fresh blob sha is what the next update of the same file needs. None after a delete.

classmethod from_json(data)[source]

Build a file commit from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

FileCommit

Returns:

the file commit

action0.github.models.org

The organization models (Organization, SimpleOrganization).

class action0.github.models.org.SimpleOrganization(login, id, description=None)[source]

An organization as GitHub’s membership listings send it (organization-simple — notably without profile fields or even an html_url). Fetch the full Organization via GetOrg when needed.

Parameters:
login: str

The organization’s login name.

id: int

The numeric organization id.

description: str | None = None

The description, if set.

classmethod from_json(data)[source]

Build a membership entry from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

SimpleOrganization

Returns:

the organization entry

class action0.github.models.org.Organization(login, id, html_url, name=None, description=None, blog=None, location=None, public_repos=0, followers=0, created_at=None)[source]

A GitHub organization’s full profile.

This is GitHub’s organization-full schema, reduced to the commonly used fields. Where an organization appears embedded in other payloads (e.g. as a repository owner), GitHub sends a plain user object instead — that stays a SimpleUser.

Parameters:
  • login (str)

  • id (int)

  • html_url (str)

  • name (str | None, default: None)

  • description (str | None, default: None)

  • blog (str | None, default: None)

  • location (str | None, default: None)

  • public_repos (int, default: 0)

  • followers (int, default: 0)

  • created_at (datetime | None, default: None)

login: str

The organization’s login name, e.g. "python".

id: int

The numeric organization id.

html_url: str

The web URL, e.g. "https://github.com/python".

name: str | None = None

The display name, if set.

description: str | None = None

The description, if set.

blog: str | None = None

The website URL, if set (GitHub’s "" for a cleared field is normalized to None).

location: str | None = None

The location, if set.

public_repos: int = 0

The number of public repositories.

followers: int = 0

The number of followers.

created_at: datetime | None = None

When the organization was created.

classmethod from_json(data)[source]

Build an organization from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

Organization

Returns:

the organization

action0.github.models.issue

The issue model (Issue) and its state vocabulary.

class action0.github.models.issue.IssueState(*values)[source]

The state of an issue.

class action0.github.models.issue.Issue(id, number, title, state, html_url, user=None, body=None, labels=<factory>, assignees=<factory>, milestone=None, comments=0, locked=False, is_pull_request=False, created_at=None, updated_at=None, closed_at=None)[source]

A GitHub issue.

This is GitHub’s issue schema, reduced to the commonly used fields. Note that GitHub’s issue endpoints return pull requests too (every pull request is an issue) — is_pull_request tells them apart.

Parameters:
id: int

The numeric issue id (globally unique).

number: int

The issue number (unique per repository), e.g. 1347.

title: str

The title.

state: IssueState

Whether the issue is open or closed.

html_url: str

The web URL, e.g. "https://github.com/python/cpython/issues/1".

user: SimpleUser | None = None

The author (None e.g. for deleted accounts).

body: str | None = None

The description text, if any.

labels: list[Label]

The labels.

assignees: list[SimpleUser]

The assigned users.

milestone: Milestone | None = None

The milestone the issue is assigned to, if any.

comments: int = 0

The number of comments.

locked: bool = False

Whether the conversation is locked.

is_pull_request: bool = False

Whether this “issue” actually is a pull request (GitHub’s issue endpoints return both).

created_at: datetime | None = None

When the issue was created.

updated_at: datetime | None = None

When the issue was last updated.

closed_at: datetime | None = None

When the issue was closed (None while it is open).

classmethod from_json(data)[source]

Build an issue from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

Issue

Returns:

the issue

action0.github.models.milestone

The milestone model (Milestone).

class action0.github.models.milestone.Milestone(id, number, title, state, html_url, description=None, open_issues=0, closed_issues=0, due_on=None, created_at=None)[source]

An issue milestone.

This is GitHub’s milestone schema, reduced to the commonly used fields. A milestone shares the issue open/closed state vocabulary (IssueState).

Parameters:
id: int

The numeric milestone id (globally unique).

number: int

The milestone number (unique per repository) — what issue filters and updates refer to.

title: str

The title, e.g. "v1.0".

state: IssueState

Whether the milestone is open or closed.

html_url: str

The web URL.

description: str | None = None

The description, if set.

open_issues: int = 0

The number of open issues assigned to the milestone.

closed_issues: int = 0

The number of closed issues assigned to the milestone.

due_on: datetime | None = None

The due date, if one was set.

created_at: datetime | None = None

When the milestone was created.

classmethod from_json(data)[source]

Build a milestone from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

Milestone

Returns:

the milestone

action0.github.models.pull

The pull request models (PullRequest, PullRequestRef, MergeResult).

class action0.github.models.pull.PullRequestRef(label, ref, sha, user=None, repo=None)[source]

One side of a pull request — its head (the proposed changes) or base (where they should be merged): a branch pinned to a commit.

Parameters:
label: str

Owner and branch, e.g. "octocat:new-topic".

ref: str

The branch name, e.g. "new-topic".

sha: str

The commit the ref pointed to when GitHub built the payload.

user: SimpleUser | None = None

The owner of the repository the ref lives in (None e.g. for deleted accounts).

repo: Repo | None = None

The repository the ref lives in (None when a fork was deleted after the pull request was opened).

classmethod from_json(data)[source]

Build a ref from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

PullRequestRef

Returns:

the ref

class action0.github.models.pull.MergeResult(sha, merged, message)[source]

What MergePull returns on success. (An unmergeable pull request is not a result but an error — GitHub answers 405/409, which raise APIError.)

Parameters:
sha: str

The sha of the merge commit.

merged: bool

Whether the pull request was merged (always True on the success payload — kept for fidelity with GitHub’s schema).

message: str

GitHub’s human-readable outcome message.

classmethod from_json(data)[source]

Build a merge result from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

MergeResult

Returns:

the merge result

class action0.github.models.pull.PullRequest(id, number, title, state, html_url, head, base, user=None, body=None, labels=<factory>, assignees=<factory>, requested_reviewers=<factory>, draft=False, locked=False, merge_commit_sha=None, mergeable=None, commits=None, additions=None, deletions=None, changed_files=None, created_at=None, updated_at=None, closed_at=None, merged_at=None)[source]

A GitHub pull request.

This is GitHub’s pull-request schema, reduced to the commonly used fields. The listing endpoints send a slimmer variant (pull-request-simple) without the merge/diff statistics — those fields stay None here until the pull request is fetched individually.

Parameters:
id: int

The numeric pull request id (globally unique).

number: int

The pull request number (unique per repository, shared with the issue numbering), e.g. 1347.

title: str

The title.

state: IssueState

Whether the pull request is open or closed (a pull request is an issue, and shares its two-state vocabulary — “merged” is not a state but is_merged, i.e. closed with a merged_at timestamp).

html_url: str

The web URL, e.g. "https://github.com/python/cpython/pull/1".

head: PullRequestRef

The proposed changes: branch and commit they come from.

base: PullRequestRef

Where the changes should be merged into.

user: SimpleUser | None = None

The author (None e.g. for deleted accounts).

body: str | None = None

The description text, if any.

labels: list[Label]

The labels.

assignees: list[SimpleUser]

The assigned users.

requested_reviewers: list[SimpleUser]

The users whose review is (still) requested — GitHub removes a reviewer from this list once they review.

draft: bool = False

Whether the pull request is a draft.

locked: bool = False

Whether the conversation is locked.

merge_commit_sha: str | None = None

The sha of the (test) merge commit, if GitHub computed one.

mergeable: bool | None = None

Whether the branch merges cleanly — None in listings and while GitHub is still computing it (only GetPull payloads carry it).

commits: int | None = None

The number of commits (None in listings — only GetPull payloads carry the diff statistics).

additions: int | None = None

The number of added lines (None in listings).

deletions: int | None = None

The number of deleted lines (None in listings).

changed_files: int | None = None

The number of changed files (None in listings).

created_at: datetime | None = None

When the pull request was opened.

updated_at: datetime | None = None

When the pull request was last updated.

closed_at: datetime | None = None

When the pull request was closed (None while it is open).

merged_at: datetime | None = None

When the pull request was merged (None if it was not).

property is_merged: bool

Whether the pull request was merged — GitHub’s own signal is the presence of merged_at (a merged pull request is always closed, so state cannot tell).

classmethod from_json(data)[source]

Build a pull request from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

PullRequest

Returns:

the pull request

action0.github.models.review

The pull request review models (Review, ReviewComment).

class action0.github.models.review.ReviewState(*values)[source]

The state of a pull request review — uppercase on the wire, unlike every other GitHub state vocabulary.

class action0.github.models.review.Review(id, state, html_url, user=None, body='', commit_id=None, submitted_at=None)[source]

A pull request review — an approval, change request or review comment thread anchor.

Parameters:
id: int

The numeric review id (globally unique).

state: ReviewState

The review verdict.

html_url: str

The web URL of the review.

user: SimpleUser | None = None

The reviewer (None e.g. for deleted accounts).

body: str = ''

The summary text (may be empty, e.g. on a plain approval).

commit_id: str | None = None

The commit the review refers to.

submitted_at: datetime | None = None

When the review was submitted (None while it is PENDING).

classmethod from_json(data)[source]

Build a review from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

Review

Returns:

the review

class action0.github.models.review.ReviewComment(id, path, body, html_url, user=None, line=None, diff_hunk=None, commit_id=None, created_at=None, updated_at=None)[source]

A pull request review comment — a comment anchored to a line of the diff. Not to be confused with the conversation comments (IssueComment — a pull request’s conversation is its issue’s comment thread).

Parameters:
id: int

The numeric comment id (globally unique).

path: str

The file the comment is anchored to.

body: str

The comment text (GitHub-flavored Markdown).

html_url: str

The web URL of the comment.

user: SimpleUser | None = None

The author (None e.g. for deleted accounts).

line: int | None = None

The line in the diff the comment is anchored to (None when the comment is outdated — the code has changed since).

diff_hunk: str | None = None

The diff excerpt the comment was made on.

commit_id: str | None = None

The commit the comment refers to.

created_at: datetime | None = None

When the comment was created.

updated_at: datetime | None = None

When the comment was last edited.

classmethod from_json(data)[source]

Build a review comment from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

ReviewComment

Returns:

the review comment

action0.github.models.commit

The commit models (Commit, GitCommit, GitIdentity, CommitFile).

class action0.github.models.commit.CommitFileStatus(*values)[source]

What happened to a file in a commit (or comparison) diff.

class action0.github.models.commit.GitIdentity(name, email, date=None)[source]

A git-level author or committer identity — the name/email/date triple recorded in the commit object itself, as opposed to the GitHub account GitHub matched to it (a SimpleUser, which may not exist at all).

Parameters:
name: str

The name as recorded in the commit.

email: str

The email address as recorded in the commit.

date: datetime | None = None

When the commit was authored/committed.

classmethod from_json(data)[source]

Build an identity from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

GitIdentity

Returns:

the identity

class action0.github.models.commit.GitCommit(sha, message, html_url=None, author=None, committer=None, parents=<factory>)[source]

A git-level commit object — flat, with message and the identities at the top level. This is what the write endpoints (e.g. CreateOrUpdateFile) return, as opposed to the API-level Commit wrapper the listing/fetch endpoints use (which nests these fields under a commit key).

Parameters:
sha: str

The full commit sha.

message: str

The commit message.

html_url: str | None = None

The web URL of the commit.

author: GitIdentity | None = None

Who wrote the change.

committer: GitIdentity | None = None

Who committed it.

parents: list[str]

The parent commit shas.

classmethod from_json(data)[source]

Build a git commit from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

GitCommit

Returns:

the commit

class action0.github.models.commit.CommitFile(filename, status, additions, deletions, changes, patch=None, previous_filename=None)[source]

One file of a commit (or comparison) diff.

Parameters:
filename: str

The file path within the repository.

status: CommitFileStatus

What happened to the file.

additions: int

The number of added lines.

deletions: int

The number of deleted lines.

changes: int

The number of changed lines (additions + deletions).

patch: str | None = None

The unified diff of the file — None for binary files and oversized diffs.

previous_filename: str | None = None

The path the file was renamed from (only on RENAMED files).

classmethod from_json(data)[source]

Build a diff file from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

CommitFile

Returns:

the diff file

class action0.github.models.commit.Commit(sha, html_url, message, git_author=None, git_committer=None, author=None, committer=None, parents=<factory>, additions=None, deletions=None, files=None)[source]

A commit as GitHub’s API presents it.

This is GitHub’s commit schema, reduced to the commonly used fields and flattened: the nested commit object’s message and git identities live directly on this class. The listing endpoints omit the diff statistics and files — those fields stay None here until the commit is fetched individually via GetCommit.

Parameters:
sha: str

The full commit sha.

html_url: str

The web URL, e.g. "https://github.com/octo/demo/commit/6dcb09b5...".

message: str

The commit message.

git_author: GitIdentity | None = None

Who wrote the change, as recorded in the commit object.

git_committer: GitIdentity | None = None

Who committed it, as recorded in the commit object.

author: SimpleUser | None = None

The GitHub account matched to the author email — None when the email does not map to any account.

committer: SimpleUser | None = None

The GitHub account matched to the committer email (None when unmatched; web commits show as the web-flow bot account).

parents: list[str]

The parent commit shas (more than one on merge commits, none on an initial commit).

additions: int | None = None

The number of added lines (None in listings — only GetCommit payloads carry the diff statistics).

deletions: int | None = None

The number of deleted lines (None in listings).

files: list[CommitFile] | None = None

The diff, file by file (None in listings).

classmethod from_json(data)[source]

Build a commit from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

Commit

Returns:

the commit

action0.github.models.comparison

The commit comparison model (Comparison).

class action0.github.models.comparison.ComparisonStatus(*values)[source]

How head relates to base in a comparison.

class action0.github.models.comparison.Comparison(status, ahead_by, behind_by, total_commits, html_url, merge_base_commit, commits=<factory>, files=<factory>)[source]

The comparison of two commits — what CompareCommits returns: GitHub’s three-dot comparison, i.e. head measured against the merge base (like git log base...head), not against base itself.

Parameters:
status: ComparisonStatus

How head relates to base.

ahead_by: int

How many commits head is ahead of the merge base.

behind_by: int

How many commits base is ahead of the merge base.

total_commits: int

The total number of commits head is ahead by — can exceed len(commits), which GitHub caps at 250.

html_url: str

The web URL of the comparison, e.g. "https://github.com/octo/demo/compare/main...topic".

merge_base_commit: Commit

The merge base — the common ancestor the comparison is measured from (the fork point).

commits: list[Commit]

The commits head is ahead by, oldest first — capped at 250 (total_commits has the real count; list the rest via ListCommits).

files: list[CommitFile]

The combined diff, file by file — capped at 300 files.

classmethod from_json(data)[source]

Build a comparison from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

Comparison

Returns:

the comparison

action0.github.models.release

The release models (Release, ReleaseAsset, ReleaseNotes).

class action0.github.models.release.ReleaseAsset(id, name, content_type, size, download_count, browser_download_url, label=None, uploader=None, created_at=None, updated_at=None)[source]

A file attached to a release.

This is GitHub’s release-asset schema, reduced to the commonly used fields. The id is what DownloadReleaseAsset takes; browser_download_url is the browser-facing link (no API authentication — public repositories only).

Parameters:
id: int

The numeric asset id (globally unique).

name: str

The file name, e.g. "demo-1.0.0-py3-none-any.whl".

content_type: str

The MIME type the asset was uploaded as.

size: int

The file size in bytes.

download_count: int

How often the asset was downloaded.

browser_download_url: str

The browser-facing download URL.

label: str | None = None

The display label, if one was set.

uploader: SimpleUser | None = None

Who uploaded the asset (None e.g. for deleted accounts).

created_at: datetime | None = None

When the asset was uploaded.

updated_at: datetime | None = None

When the asset was last changed.

classmethod from_json(data)[source]

Build an asset from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

ReleaseAsset

Returns:

the asset

class action0.github.models.release.ReleaseNotes(name, body)[source]

Auto-generated release notes — what GenerateReleaseNotes returns. Nothing is published; feed the text into CreateRelease (or let it generate the notes itself via generate_release_notes).

Parameters:
name: str

The suggested release title.

body: str

The generated notes (GitHub-flavored Markdown).

classmethod from_json(data)[source]

Build release notes from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

ReleaseNotes

Returns:

the release notes

class action0.github.models.release.Release(id, tag_name, html_url, draft, prerelease, name=None, body=None, author=None, assets=<factory>, target_commitish=None, created_at=None, published_at=None)[source]

A GitHub release.

This is GitHub’s release schema, reduced to the commonly used fields.

Parameters:
id: int

The numeric release id (globally unique).

tag_name: str

The git tag the release points at, e.g. "v1.0.0".

html_url: str

The web URL, e.g. "https://github.com/octo/demo/releases/tag/v1.0.0".

draft: bool

Whether the release is an unpublished draft.

prerelease: bool

Whether the release is marked as a prerelease.

name: str | None = None

The release title, if one was set.

body: str | None = None

The release notes (GitHub-flavored Markdown), if any.

author: SimpleUser | None = None

Who created the release (None e.g. for deleted accounts).

assets: list[ReleaseAsset]

The attached files (source archives are not assets — GitHub generates those on the fly).

target_commitish: str | None = None

The branch or commit the tag was created from.

created_at: datetime | None = None

When the commit the release points at was created.

published_at: datetime | None = None

When the release was published (None on drafts).

classmethod from_json(data)[source]

Build a release from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

Release

Returns:

the release

action0.github.models.page

One page of a listing result (Page).

class action0.github.models.page.ItemT

The item type of a page — e.g. a repository or an issue.

alias of TypeVar(‘ItemT’)

class action0.github.models.page.Page(items, next=None)[source]

One page of a listing, plus the way to the next one.

A page behaves like the sequence of its items (iteration, len(), indexing, truthiness), so code that treats a listing result as a list keeps working. next carries pagination: the ready-to-send operation for the following page, or None on the last one.

Parameters:
items: list[ItemT]

The items of this page.

next: Operation[Page[ItemT]] | None = None

The operation fetching the next page — send it through the same client (in whatever execution model) — or None if this is the last page.

action0.github.models.search

One page of a search result (SearchPage).

class action0.github.models.search.SearchPage(items, next=None, total_count=0, incomplete_results=False)[source]

One page of a search result: a Page (sequence-like, next carries pagination) plus the envelope fields GitHub wraps search results in.

Note that GitHub caps search results at 1000 items — following next simply ends there, whatever total_count says.

Parameters:
total_count: int = 0

How many results matched in total (across all pages).

incomplete_results: bool = False

Whether GitHub timed out and returned only a partial match set.

action0.github.models.rate_limit

The rate limit models (RateLimitOverview, RateLimit).

class action0.github.models.rate_limit.RateLimit(limit, remaining, used, reset)[source]

One rate limit window (of one resource category).

Parameters:
limit: int

The requests allowed per window.

remaining: int

The requests left in the current window.

used: int

The requests already spent in the current window.

reset: datetime

When the window resets (GitHub sends this as epoch seconds — parsed into an aware UTC datetime).

classmethod from_json(data)[source]

Build one window from one decoded JSON object.

Parameters:

data (Any) – the decoded JSON object

Return type:

RateLimit

Returns:

the window

class action0.github.models.rate_limit.RateLimitOverview(resources)[source]

The rate limit status across all resource categories.

GitHub adds categories over time (graphql, code_search, integration_manifest, …), so everything lives in resources by name; the two everyone needs are also typed properties (core, search).

Parameters:

resources (dict[str, RateLimit])

resources: dict[str, RateLimit]

All resource categories by name.

property core: RateLimit

The core window — everything that is not one of the special categories, i.e. most REST calls.

property search: RateLimit

The search window (much smaller than core).

classmethod from_json(data)[source]

Build the overview from one decoded JSON object.

The payload’s legacy top-level rate key (a copy of resources.core) is ignored — use core.

Parameters:

data (Any) – the decoded JSON object

Return type:

RateLimitOverview

Returns:

the overview

action0.github.models.timestamps

Parsing GitHub’s timestamps, shared by the models.

action0.github.models.timestamps.timestamp(value)[source]

Parse one of GitHub’s ISO 8601 timestamps (2008-06-11T21:19:53Z).

Parameters:

value (str | None) – the timestamp string, or None where GitHub sends null

Return type:

datetime | None

Returns:

the parsed datetime (timezone-aware), or None