Source code for action0.github.models.pull

"""The pull request models (:py:class:`PullRequest`, :py:class:`PullRequestRef`,
:py:class:`MergeResult`)."""

from __future__ import annotations

from dataclasses import dataclass
from dataclasses import field
from datetime import datetime
from typing import Any

from .issue import IssueState
from .label import Label
from .repo import Repo
from .timestamps import timestamp
from .user import SimpleUser


[docs] @dataclass class PullRequestRef: """ One side of a pull request — its ``head`` (the proposed changes) or ``base`` (where they should be merged): a branch pinned to a commit. """ label: str """Owner and branch, e.g. ``"octocat:new-topic"``.""" ref: str """The branch name, e.g. ``"new-topic"``.""" sha: str """The commit the ref pointed to when GitHub built the payload.""" user: SimpleUser | None = None """The owner of the repository the ref lives in (``None`` e.g. for deleted accounts).""" repo: Repo | None = None """The repository the ref lives in (``None`` when a fork was deleted after the pull request was opened)."""
[docs] @classmethod def from_json(cls, data: Any) -> PullRequestRef: """ Build a ref from one decoded JSON object. :param data: the decoded JSON object :return: the ref """ user = data.get("user") repo = data.get("repo") return cls( label=data["label"], ref=data["ref"], sha=data["sha"], user=SimpleUser.from_json(user) if user is not None else None, repo=Repo.from_json(repo) if repo is not None else None, )
[docs] @dataclass class MergeResult: """ What :py:class:`~action0.github.operations.pulls.MergePull` returns on success. (An unmergeable pull request is not a result but an error — GitHub answers 405/409, which raise :py:class:`~action0.client.errors.APIError`.) """ sha: str """The sha of the merge commit.""" merged: bool """Whether the pull request was merged (always ``True`` on the success payload — kept for fidelity with GitHub's schema).""" message: str """GitHub's human-readable outcome message."""
[docs] @classmethod def from_json(cls, data: Any) -> MergeResult: """ Build a merge result from one decoded JSON object. :param data: the decoded JSON object :return: the merge result """ return cls(sha=data["sha"], merged=data["merged"], message=data["message"])
[docs] @dataclass class PullRequest: """ A GitHub pull request. This is GitHub's ``pull-request`` schema, reduced to the commonly used fields. The listing endpoints send a slimmer variant (``pull-request-simple``) without the merge/diff statistics — those fields stay ``None`` here until the pull request is fetched individually. """ id: int """The numeric pull request id (globally unique).""" number: int """The pull request number (unique per repository, shared with the issue numbering), e.g. ``1347``.""" title: str """The title.""" state: IssueState """Whether the pull request is open or closed (a pull request *is* an issue, and shares its two-state vocabulary — "merged" is not a state but :py:attr:`is_merged`, i.e. closed with a :py:attr:`merged_at` timestamp).""" html_url: str """The web URL, e.g. ``"https://github.com/python/cpython/pull/1"``.""" head: PullRequestRef """The proposed changes: branch and commit they come from.""" base: PullRequestRef """Where the changes should be merged into.""" user: SimpleUser | None = None """The author (``None`` e.g. for deleted accounts).""" body: str | None = None """The description text, if any.""" labels: list[Label] = field(default_factory=list) """The labels.""" assignees: list[SimpleUser] = field(default_factory=list) """The assigned users.""" requested_reviewers: list[SimpleUser] = field(default_factory=list) """The users whose review is (still) requested — GitHub removes a reviewer from this list once they review.""" draft: bool = False """Whether the pull request is a draft.""" locked: bool = False """Whether the conversation is locked.""" merge_commit_sha: str | None = None """The sha of the (test) merge commit, if GitHub computed one.""" mergeable: bool | None = None """Whether the branch merges cleanly — ``None`` in listings and while GitHub is still computing it (only :py:class:`GetPull <action0.github.operations.pulls.GetPull>` payloads carry it).""" commits: int | None = None """The number of commits (``None`` in listings — only :py:class:`~action0.github.operations.pulls.GetPull` payloads carry the diff statistics).""" additions: int | None = None """The number of added lines (``None`` in listings).""" deletions: int | None = None """The number of deleted lines (``None`` in listings).""" changed_files: int | None = None """The number of changed files (``None`` in listings).""" created_at: datetime | None = None """When the pull request was opened.""" updated_at: datetime | None = None """When the pull request was last updated.""" closed_at: datetime | None = None """When the pull request was closed (``None`` while it is open).""" merged_at: datetime | None = None """When the pull request was merged (``None`` if it was not).""" @property def is_merged(self) -> bool: """Whether the pull request was merged — GitHub's own signal is the presence of :py:attr:`merged_at` (a merged pull request is always ``closed``, so :py:attr:`state` cannot tell).""" return self.merged_at is not None
[docs] @classmethod def from_json(cls, data: Any) -> PullRequest: """ Build a pull request from one decoded JSON object. :param data: the decoded JSON object :return: the pull request """ user = data.get("user") return cls( id=data["id"], number=data["number"], title=data["title"], state=IssueState(data["state"]), html_url=data["html_url"], head=PullRequestRef.from_json(data["head"]), base=PullRequestRef.from_json(data["base"]), user=SimpleUser.from_json(user) if user is not None else None, body=data.get("body"), labels=[Label.from_json(item) for item in data.get("labels", [])], assignees=[SimpleUser.from_json(item) for item in data.get("assignees", [])], requested_reviewers=[ SimpleUser.from_json(item) for item in data.get("requested_reviewers", []) ], draft=data.get("draft", False), locked=data.get("locked", False), merge_commit_sha=data.get("merge_commit_sha"), mergeable=data.get("mergeable"), commits=data.get("commits"), additions=data.get("additions"), deletions=data.get("deletions"), changed_files=data.get("changed_files"), created_at=timestamp(data.get("created_at")), updated_at=timestamp(data.get("updated_at")), closed_at=timestamp(data.get("closed_at")), merged_at=timestamp(data.get("merged_at")), )