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))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;Nonesends 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).
- 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.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
AcceptandAuthorization— 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’s304 Not Modifiedback 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-safeMemoryCache. Hooks run synchronously even on async backends, so anAsyncCacheStoreis not accepted.policy – what to store under which key —
GITHUB_CONDITIONAL_POLICYunless told otherwise
- on_request(request)[source]¶
Attach the stored validators to an outgoing GET/HEAD: the stored response’s
ETagasIf-None-Match(andLast-ModifiedasIf-Modified-Since). A request already carrying its own validators is the caller’s conditional request — left untouched.
- on_response(request, response, elapsed)[source]¶
Fill a
304 Not Modifiedfrom the store, and store fresh responses that carry validators.- Parameters:
- Return type:
- Returns:
the stored full response for a revalidated 304 (an independent copy tied to the current request), else
Noneto 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
RetryPolicytuned to the GitHub API. On top of the base behavior (transient 5xx/429 statuses,Retry-Afterhonored, idempotent methods only — soCreateIssueand 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-Afterheader orx-ratelimit-remaining: 0must be present,without a
Retry-After, an exhausted primary rate limit is waited out untilx-ratelimit-reset(GitHub’s documented advice), capped atmax_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-resetwaits are computed against — injectable for tests.
- should_retry_response(request, response, attempt)[source]¶
The base statuses, plus 403 when the response says “rate limited”.
- delay_for(attempt, response=None)[source]¶
The base delays (
Retry-Afterfirst, else jittered exponential backoff), with one addition: an exhausted primary rate limit without aRetry-Afterwaits untilx-ratelimit-reset.- Parameters:
- Return type:
- 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 —
Pageor a subclass likeSearchPage.
- 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
pagefield incremented — exactly when the response’sLinkheader announces arel="next"(GitHub’s authoritative end-of-listing signal).dataclasses.replacekeeps the page’s concrete type, so subclasses likeSearchPagepass through with their extra fields intact.- Parameters:
operation (
Any) – the operation that produced the page — any operation dataclass with apagefield (typedAny: “has a page field” spans the unrelatedPaginatedOperationandSearchOperationhierarchies)page (
TypeVar(PageT, bound=Page[Any])) – the parsed page,nextnot yet setresponse (
Response) – the response it was parsed from
- Return type:
- Returns:
the page, with
nextattached 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
JsonOperationrequesting GitHub’s recommended media type.acceptlives here (not only as a client default header) becauseas_request()sets the operation’sAcceptbefore the client’s gap-filling defaults run —JsonOperation’s plainapplication/jsonwould win otherwise.
- 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, sosendyieldsNone(wrapped in whatever the execution model wraps results in); errors surface as usual viaAPIError.Not a
GitHubOperation:JsonOperation’sloadtreats an empty body as an error, which is exactly the success case here.
- 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
Pagewhosenextis the ready-to-send operation for the following page — present exactly when the response’sLinkheader announces arel="next"(GitHub’s authoritative signal), built as a copy of this operation withpage+ 1.Subclasses implement
load_item()for a single JSON array item. Being base-class fields,per_pageandpagecome first in every listing’s query string.- abstractmethod load_item(data)[source]¶
Turn one item of the decoded JSON array into the typed model.
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'
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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).- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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 aContributor— a user plus their commit count).- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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'
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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:
per_page (
int, default:30)page (
int, default:1)direction (
SortDirection|None, default:None)org (
str)type (
OrgRepoType|None, default:None)
- 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’spath_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;
Noneuses 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'
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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:
per_page (
int, default:30)page (
int, default:1)direction (
SortDirection|None, default:None)username (
str)type (
UserRepoType|None, default:None)
- 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’spath_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;
Noneuses 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 viaGetRepoTopics). Requires a token with write access;[]clears them.- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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
protectedfilter is the first boolean query parameter — sent web-style astrue/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:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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'
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
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:
- 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’spath_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;
Noneuses 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);Nonelists all.
- 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".- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
action0.github.operations.issues¶
The issue operations (GitHub docs).
- class action0.github.operations.issues.IssueStateFilter(*values)[source]¶
The state filter of
ListIssues(unlikeIssueStateit knowsall).
- 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
LockIssueattaches 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:
- 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’spath_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;
Noneuses 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.
- direction: SortDirection | None = None¶
The sort direction;
Noneuses GitHub’s default (desc).
- class action0.github.operations.issues.GetIssue(*, owner, repo, issue_number)[source]¶
GET /repos/{owner}/{repo}/issues/{issue_number}— fetch one issue (or pull request — seeis_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'
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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;
Nonefields are omitted from it (requires a token with write access to the repository).- Parameters:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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
Nonefield is omitted from the JSON body and leaves the issue untouched. (This also means clearing a field by sending JSONnullis not expressible here; send an empty string/list instead where GitHub accepts one.) Like every non-idempotent method, a PATCH is never blindly repeated byGitHubRetryPolicy.- Parameters:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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 asreopened).
- 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:
- 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’spath_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).
- 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).- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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.- 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’spath_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.
- 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 answers204,sendyieldsNone.>>> 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'
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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. Answers204.- Parameters:
owner (
str)repo (
str)issue_number (
int)lock_reason (
LockReason|None, default:None)
- 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’spath_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;
Nonelocks 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. Answers204.- 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’spath_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 (unlikeUpdateIssue’sassignees, which replaces the whole set). Unassignable logins are silently ignored by GitHub.- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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.- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
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'
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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 (unlikeUpdateIssue’slabels, which replaces the whole set). Labels that don’t exist in the repository yet are created on the fly.- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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.- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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 throughnew_name(the current name addresses the label in the path) and cascades to every issue carrying the label.- Parameters:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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). Answers204.- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
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 sameopen/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:
per_page (
int, default:30)page (
int, default:1)owner (
str)repo (
str)state (
IssueStateFilter|None, default:None)sort (
MilestoneSort|None, default:None)direction (
SortDirection|None, default:None)
- 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’spath_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;
Noneuses GitHub’s default (open).
- sort: MilestoneSort | None = None¶
The sort order;
Noneuses GitHub’s default (due_on).
- direction: SortDirection | None = None¶
The sort direction;
Noneuses GitHub’s default (asc).
- 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:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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:Nonefields stay untouched; closing isstate=IssueState.CLOSED.- Parameters:
- 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’spath_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).
- state: IssueState | None = None¶
Open or close the milestone;
Nonekeeps the state.
- 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). Answers204.- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
action0.github.operations.pulls¶
The pull request operations (GitHub docs).
- class action0.github.operations.pulls.PullStateFilter(*values)[source]¶
The state filter of
ListPulls(unlikeIssueStateit knowsall).
- class action0.github.operations.pulls.PullSort(*values)[source]¶
The sort orders of the pull request listing.
- 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:
- 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’spath_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;
Noneuses GitHub’s default (open).
- head: str | None = None¶
Only pull requests from this head, as
"owner:branch"(e.g."octocat:new-topic").
- direction: SortDirection | None = None¶
The sort direction;
Noneuses GitHub’s default (descwhen sorting bycreated,ascotherwise).
- 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'
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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;
Nonefields are omitted from it (requires a token with write access to the repository).- Parameters:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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".
- 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 inUpdateIssue: aNonefield is omitted from the body and leaves the pull request untouched. Note “merged” is not a state —MergePullmerges,stateonly opens/closes.- Parameters:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- state: IssueState | None = None¶
Close or reopen the pull request;
Noneleaves the state unchanged.
- 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
shaguard mismatch) is answered with 405/409, surfacing as anAPIError. 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 theshaguard for defensive merging.- Parameters:
- 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’spath_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;
Noneuses the repository’s default method.
- sha: str | None = None¶
Only merge if the head is still at this sha — guards against merging commits pushed after the last review.
- 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:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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, useListCommitson 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:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
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_pathfilter is calledpathon 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:
- 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’spath_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;
Noneuses 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 becausepathis the operation’s path template).
- 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).
- 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 capsfilesat 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'
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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, measuringheadagainst the merge base (likegit log base...head).The endpoint’s
baseheadpath 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'
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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 ofListPullCommits.- Parameters:
- 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’spath_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’sref, GitHub wants a sha here, not a branch or tag).
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 inGetCombinedStatus).The one listing whose payload is not a bare array: GitHub wraps it in a
{total_count, check_runs}envelope, soload_json()unwraps before the usual per-item parsing (pagination still runs on theLinkheader, like everywhere else).- Parameters:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- status: CheckRunStatusFilter | None = None¶
Only runs in this lifecycle phase;
Nonelists all.
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 withListCheckRunsForRef, 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'
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
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_pathbecausepathis the operation’s own path template attribute; an empty string lists the repository root.)- 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’spath_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
ContentFileresult, a directory (or""for the root) for a list ofDirectoryEntry.
- ref: str | None = None¶
The branch, tag or sha to read from;
Noneuses the repository’s default branch.
- 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'
- 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’spath_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;
Noneuses the repository’s default branch.
- 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:Nonecreates — 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 asAPIError). Pass raw bytes ascontent— the base64 transport encoding is applied on serialization (aserialize=field hook).- Parameters:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- sha: str | None = None¶
The blob sha the file currently has (
sha) when updating;Nonecreates a new file.
- 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 noNoContentOperation.- Parameters:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
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)
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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:
per_page (
int, default:30)page (
int, default:1)org (
str)role (
OrgMemberRole|None, default:None)
- 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’spath_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;
Noneuses GitHub’s default (all).
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
CreatePullReviewbatch — a plain dataclass that becomes one entry of the review’scommentsarray (Nonefields are omitted, as everywhere). For a standalone comment outside a review, useCreateReviewComment.- Parameters:
path (
str)body (
str)line (
int)side (
ReviewSide|None, default:None)start_side (
ReviewSide|None, default:None)
- side: ReviewSide | None = None¶
Which side of the diff;
Noneuses GitHub’s default (RIGHT— the new code).
- start_line: int | None = None¶
The first line, to span a multi-line range;
Nonecomments a single line.
- start_side: ReviewSide | None = None¶
The side of
start_line;Noneuses 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:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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:
- 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’spath_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
PENDINGdraft review — this client always submits.)
- body: str | None = None¶
The summary text — required by GitHub for
REQUEST_CHANGESandCOMMENT, optional for an approval.
- commit_id: str | None = None¶
The commit the review refers to;
Noneuses 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
DraftReviewCommententries — serialized straight into GitHub’scommentsarray.
- 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 isListIssueComments.- Parameters:
- 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’spath_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).
- 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 viaCreatePullReview’scomments.- Parameters:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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).
- side: ReviewSide | None = None¶
Which side of the diff;
Noneuses GitHub’s default (RIGHT— the new code).
- start_line: int | None = None¶
The first line, to span a multi-line range;
Nonecomments a single line.
- start_side: ReviewSide | None = None¶
The side of
start_line;Noneuses GitHub’s default.
- 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:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- team_reviewers: list[str] | None = None¶
The team slugs to request (organization repositories only).
- 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, likeRemoveAssignees).- Parameters:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
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
UploadReleaseAssetmust be pointed at (uploads do not go toapi.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'
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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 ofListReleases.- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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'
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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:
- 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’spath_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_commitishif it does not exist yet.
- target_commitish: str | None = None¶
The branch or commit to tag if the tag is new;
Noneuses the repository’s default branch. Ignored if the tag exists.
- draft: bool | None = None¶
Create as an unpublished draft;
Noneuses GitHub’s default (False— published immediately).
- generate_release_notes: bool | None = None¶
Let GitHub generate the notes (appended to
bodyif both are given);Noneuses GitHub’s default (False). For generating without publishing, seeGenerateReleaseNotes.
- 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: aNonefield is omitted from the body and leaves the release untouched (publishing a draft isdraft=False).- Parameters:
- 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’spath_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).
- class action0.github.operations.releases.DeleteRelease(*, owner, repo, release_id)[source]¶
DELETE /repos/{owner}/{repo}/releases/{release_id}— delete a release. Answers204. The tag stays — deleting a release does not delete the git tag it pointed at.- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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 intoCreateRelease— or skip this round-trip entirely with itsgenerate_release_notesflag if the text needs no editing.- Parameters:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- target_commitish: str | None = None¶
The branch or commit the tag would point at, if it is new;
Noneuses the repository’s default branch.
- previous_tag_name: str | None = None¶
The tag to diff against;
Nonelets GitHub pick the previous release automatically.
- 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 toapi.github.com: GitHub takes uploads on a separate host, so send it through a client pointed atGITHUB_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 anyBodyProducer) 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:
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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 theContent-Typeof the upload request and later thecontent_typeserved on download.
- class action0.github.operations.releases.DownloadReleaseAsset(*, owner, repo, asset_id)[source]¶
GET /repos/{owner}/{repo}/releases/assets/{asset_id}withAccept: 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 aBodyProducer. Run it on a backend withstream=Trueand the body is never held in memory — iteratechunks()(sync) orachunks()(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.
- 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’spath_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
Acceptheader to send, unless one is set explicitly;Nonesends none.JsonOperationsetsapplication/json.
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 aSearchPage.Subclasses implement
load_item()for oneitemsentry.- abstractmethod load_item(data)[source]¶
Turn one entry of the envelope’s
itemsarray into the typed model.
- 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’sLinkheader knows)
- load(response)[source]¶
Decode the envelope and attach the next-page operation if the response’s
Linkheader 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:
per_page (
int, default:30)page (
int, default:1)q (
str)sort (
RepoSearchSort|None, default:None)order (
SortDirection|None, default:None)
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- sort: RepoSearchSort | None = None¶
The sort order;
Noneuses GitHub’s default (best match).
- order: SortDirection | None = None¶
The sort direction (GitHub’s parameter name for search); only applied when
sortis set, defaultdesc.
- 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:prin the query, or after the fact viais_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:
per_page (
int, default:30)page (
int, default:1)q (
str)sort (
IssueSearchSort|None, default:None)order (
SortDirection|None, default:None)
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- sort: IssueSearchSort | None = None¶
The sort order;
Noneuses GitHub’s default (best match).
- order: SortDirection | None = None¶
The sort direction (GitHub’s parameter name for search); only applied when
sortis set, defaultdesc.
- 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 withGetUser.- Parameters:
per_page (
int, default:30)page (
int, default:1)q (
str)sort (
UserSearchSort|None, default:None)order (
SortDirection|None, default:None)
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- sort: UserSearchSort | None = None¶
The sort order;
Noneuses GitHub’s default (best match).
- order: SortDirection | None = None¶
The sort direction (GitHub’s parameter name for search); only applied when
sortis set, defaultdesc.
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'
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
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)
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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 theUsermodel ignores).- path: ClassVar[str] = '/user'¶
The path template of the endpoint, appended to the client’s base URL.
{placeholder}names are filled from the operation’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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'
- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
- 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 areSimpleOrganization— the membership payloads carry no profile fields, so follow up withGetOrgfor the fullOrganization.- 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’spath_param()fields. A leading/is optional — the path is always joined to the base URL with exactly one/.
action0.github.operations.links¶
Reading the Link response header (RFC 8288, as GitHub sends it).
- action0.github.operations.links.links(response)[source]¶
Extract the link relations of a response’s
Linkheader(s).>>> header = ( ... '<https://api.github.com/repositories/1/issues?page=2>; rel="next", ' ... '<https://api.github.com/repositories/1/issues?page=5>; rel="last"' ... ) >>> links(Response(200, headers={"Link": header}))["next"] 'https://api.github.com/repositories/1/issues?page=2' >>> links(Response(200)) {}
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
ownerof a repository.This is GitHub’s
simple-userschema, reduced to the fields the shipped operations use.- 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:
- Returns:
the user
- class action0.github.models.user.Contributor(login, id, html_url, type, contributions=0)[source]¶
A repository contributor — a
SimpleUserplus their commit count, asListContributorsreturns it.
- 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
SimpleUsercore plus the public profile fields.This is GitHub’s
public-userschema, reduced to the commonly used fields (for the authenticated user, GitHub sends additional private fields the model ignores).
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-repositoryschema, reduced to the commonly used fields (the raw payload has ~100 more).- Parameters:
- owner: SimpleUser¶
The owning user or organization.
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:
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
GetBranchfillscommitwith the full tip commit.- Parameters:
- commit: Commit | None = None¶
The full tip commit (
Nonein listings — onlyGetBranchpayloads carry it).
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:
- status: CheckRunStatus¶
The lifecycle phase.
- conclusion: CheckConclusion | None = None¶
The verdict —
Noneuntil the run isCOMPLETED.
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-commentschema, 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:
- user: SimpleUser | None = None¶
The author (
Nonee.g. for deleted accounts).
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 intofailurethere).
- 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.
- class action0.github.models.status.CombinedStatus(state, sha, total_count, statuses=<factory>)[source]¶
The combined status of a commit — what
GetCombinedStatusreturns: one rolled-up state over all contexts, plus the individual statuses.- Parameters:
state (
StatusState)sha (
str)total_count (
int)statuses (
list[CommitStatus], default:<factory>)
- state: StatusState¶
The rolled-up verdict:
successonly when every context succeeded,pendingwhen any is pending (or none exist).
- statuses: list[CommitStatus]¶
The individual statuses, one per context.
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
ListRepoTagsreturns it: a name pinned to a commit, plus GitHub’s on-the-fly source archives.- Parameters:
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
GetContentandGetReadme.The bytes arrive base64-encoded in
content; usedecoded(ortext) instead of touching the raw transport encoding.- Parameters:
- type: ContentType¶
What the entry is — requesting a symlink or submodule path yields an object without content.
- 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 viadownload_url).
- property decoded: bytes¶
The decoded file bytes.
- Raises:
ValueError – if the payload carries no inlined content (
encoding: "none", or a symlink/submodule entry) — fetch viadownload_urlinstead
- property text: str¶
The decoded file content as text (UTF-8).
- Raises:
ValueError – if the payload carries no inlined content
UnicodeDecodeError – if the bytes are not valid UTF-8
- 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
GetContentreturns for a directory path. Entries carry no content; fetch a file of interest with its ownGetContent(file_path=entry.path).- Parameters:
- type: ContentType¶
What the entry is.
- 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)content (
ContentFile|None, default:None)
- content: ContentFile | None = None¶
The written file — its fresh blob
shais what the next update of the same file needs.Noneafter a delete.
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 anhtml_url). Fetch the fullOrganizationviaGetOrgwhen needed.
- 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-fullschema, 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 aSimpleUser.- Parameters:
- blog: str | None = None¶
The website URL, if set (GitHub’s
""for a cleared field is normalized toNone).
action0.github.models.issue¶
The issue model (Issue) and its state vocabulary.
- 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
issueschema, reduced to the commonly used fields. Note that GitHub’s issue endpoints return pull requests too (every pull request is an issue) —is_pull_requesttells them apart.- Parameters:
id (
int)number (
int)title (
str)state (
IssueState)html_url (
str)user (
SimpleUser|None, default:None)assignees (
list[SimpleUser], default:<factory>)comments (
int, default:0)locked (
bool, default:False)is_pull_request (
bool, default:False)
- state: IssueState¶
Whether the issue is open or closed.
- user: SimpleUser | None = None¶
The author (
Nonee.g. for deleted accounts).
- assignees: list[SimpleUser]¶
The assigned users.
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
milestoneschema, reduced to the commonly used fields. A milestone shares the issue open/closed state vocabulary (IssueState).- Parameters:
- number: int¶
The milestone number (unique per repository) — what issue filters and updates refer to.
- state: IssueState¶
Whether the milestone is open or closed.
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) orbase(where they should be merged): a branch pinned to a commit.- Parameters:
- user: SimpleUser | None = None¶
The owner of the repository the ref lives in (
Nonee.g. for deleted accounts).
- repo: Repo | None = None¶
The repository the ref lives in (
Nonewhen a fork was deleted after the pull request was opened).
- class action0.github.models.pull.MergeResult(sha, merged, message)[source]¶
What
MergePullreturns on success. (An unmergeable pull request is not a result but an error — GitHub answers 405/409, which raiseAPIError.)- merged: bool¶
Whether the pull request was merged (always
Trueon the success payload — kept for fidelity with GitHub’s schema).
- 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-requestschema, reduced to the commonly used fields. The listing endpoints send a slimmer variant (pull-request-simple) without the merge/diff statistics — those fields stayNonehere until the pull request is fetched individually.- Parameters:
id (
int)number (
int)title (
str)state (
IssueState)html_url (
str)head (
PullRequestRef)base (
PullRequestRef)user (
SimpleUser|None, default:None)assignees (
list[SimpleUser], default:<factory>)requested_reviewers (
list[SimpleUser], default:<factory>)draft (
bool, default:False)locked (
bool, default:False)
- number: int¶
The pull request number (unique per repository, shared with the issue numbering), e.g.
1347.
- 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 amerged_attimestamp).
- 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 (
Nonee.g. for deleted accounts).
- 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.
- mergeable: bool | None = None¶
Whether the branch merges cleanly —
Nonein listings and while GitHub is still computing it (onlyGetPullpayloads carry it).
- commits: int | None = None¶
The number of commits (
Nonein listings — onlyGetPullpayloads carry the diff statistics).
- 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 alwaysclosed, sostatecannot tell).
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)state (
ReviewState)html_url (
str)user (
SimpleUser|None, default:None)body (
str, default:'')
- state: ReviewState¶
The review verdict.
- user: SimpleUser | None = None¶
The reviewer (
Nonee.g. for deleted accounts).
- 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:
- user: SimpleUser | None = None¶
The author (
Nonee.g. for deleted accounts).
- line: int | None = None¶
The line in the diff the comment is anchored to (
Nonewhen the comment is outdated — the code has changed since).
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).
- 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
messageand the identities at the top level. This is what the write endpoints (e.g.CreateOrUpdateFile) return, as opposed to the API-levelCommitwrapper the listing/fetch endpoints use (which nests these fields under acommitkey).- Parameters:
sha (
str)message (
str)author (
GitIdentity|None, default:None)committer (
GitIdentity|None, default:None)
- author: GitIdentity | None = None¶
Who wrote the change.
- committer: GitIdentity | None = None¶
Who committed it.
- 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:
- status: CommitFileStatus¶
What happened to the 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
commitschema, reduced to the commonly used fields and flattened: the nestedcommitobject’s message and git identities live directly on this class. The listing endpoints omit the diff statistics and files — those fields stayNonehere until the commit is fetched individually viaGetCommit.- Parameters:
sha (
str)html_url (
str)message (
str)git_author (
GitIdentity|None, default:None)git_committer (
GitIdentity|None, default:None)author (
SimpleUser|None, default:None)committer (
SimpleUser|None, default:None)files (
list[CommitFile] |None, default:None)
- 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 —
Nonewhen the email does not map to any account.
- committer: SimpleUser | None = None¶
The GitHub account matched to the committer email (
Nonewhen unmatched; web commits show as theweb-flowbot 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 (
Nonein listings — onlyGetCommitpayloads carry the diff statistics).
- files: list[CommitFile] | None = None¶
The diff, file by file (
Nonein listings).
action0.github.models.comparison¶
The commit comparison model (Comparison).
- class action0.github.models.comparison.ComparisonStatus(*values)[source]¶
How
headrelates tobasein 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
CompareCommitsreturns: GitHub’s three-dot comparison, i.e.headmeasured against the merge base (likegit log base...head), not againstbaseitself.- Parameters:
status (
ComparisonStatus)ahead_by (
int)behind_by (
int)total_commits (
int)html_url (
str)merge_base_commit (
Commit)files (
list[CommitFile], default:<factory>)
- status: ComparisonStatus¶
How
headrelates tobase.
- total_commits: int¶
The total number of commits
headis ahead by — can exceedlen(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
headis ahead by, oldest first — capped at 250 (total_commitshas the real count; list the rest viaListCommits).
- files: list[CommitFile]¶
The combined diff, file by file — capped at 300 files.
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-assetschema, reduced to the commonly used fields. Theidis whatDownloadReleaseAssettakes;browser_download_urlis the browser-facing link (no API authentication — public repositories only).- Parameters:
- uploader: SimpleUser | None = None¶
Who uploaded the asset (
Nonee.g. for deleted accounts).
- class action0.github.models.release.ReleaseNotes(name, body)[source]¶
Auto-generated release notes — what
GenerateReleaseNotesreturns. Nothing is published; feed the text intoCreateRelease(or let it generate the notes itself viagenerate_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
releaseschema, reduced to the commonly used fields.- Parameters:
id (
int)tag_name (
str)html_url (
str)draft (
bool)prerelease (
bool)author (
SimpleUser|None, default:None)assets (
list[ReleaseAsset], default:<factory>)
- author: SimpleUser | None = None¶
Who created the release (
Nonee.g. for deleted accounts).
- assets: list[ReleaseAsset]¶
The attached files (source archives are not assets — GitHub generates those on the fly).
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.nextcarries pagination: the ready-to-send operation for the following page, orNoneon the last one.- Parameters:
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,nextcarries pagination) plus the envelope fields GitHub wraps search results in.Note that GitHub caps search results at 1000 items — following
nextsimply ends there, whatevertotal_countsays.- Parameters:
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).
- 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 inresourcesby name; the two everyone needs are also typed properties (core,search).- property core: RateLimit¶
The core window — everything that is not one of the special categories, i.e. most REST calls.
action0.github.models.timestamps¶
Parsing GitHub’s timestamps, shared by the models.