| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- """
- Data structures to interact with Discussions and Pull Requests on the Hub.
- See [the Discussions and Pull Requests guide](https://huggingface.co/docs/hub/repositories-pull-requests-discussions)
- for more information on Pull Requests, Discussions, and the community tab.
- """
- from dataclasses import dataclass
- from datetime import datetime
- from typing import Literal, TypedDict
- from . import constants
- from .utils import parse_datetime
- DiscussionStatus = Literal["open", "closed", "merged", "draft"]
- @dataclass
- class Discussion:
- """
- A Discussion or Pull Request on the Hub.
- This dataclass is not intended to be instantiated directly.
- Attributes:
- title (`str`):
- The title of the Discussion / Pull Request
- status (`str`):
- The status of the Discussion / Pull Request.
- It must be one of:
- * `"open"`
- * `"closed"`
- * `"merged"` (only for Pull Requests )
- * `"draft"` (only for Pull Requests )
- num (`int`):
- The number of the Discussion / Pull Request.
- repo_id (`str`):
- The id (`"{namespace}/{repo_name}"`) of the repo on which
- the Discussion / Pull Request was open.
- repo_type (`str`):
- The type of the repo on which the Discussion / Pull Request was open.
- Possible values are: `"model"`, `"dataset"`, `"space"`.
- author (`str`):
- The username of the Discussion / Pull Request author.
- Can be `"deleted"` if the user has been deleted since.
- is_pull_request (`bool`):
- Whether or not this is a Pull Request.
- created_at (`datetime`):
- The `datetime` of creation of the Discussion / Pull Request.
- endpoint (`str`):
- Endpoint of the Hub. Default is https://huggingface.co.
- git_reference (`str`, *optional*):
- (property) Git reference to which changes can be pushed if this is a Pull Request, `None` otherwise.
- url (`str`):
- (property) URL of the discussion on the Hub.
- """
- title: str
- status: DiscussionStatus
- num: int
- repo_id: str
- repo_type: str
- author: str
- is_pull_request: bool
- created_at: datetime
- endpoint: str
- @property
- def git_reference(self) -> str | None:
- """
- If this is a Pull Request , returns the git reference to which changes can be pushed.
- Returns `None` otherwise.
- """
- if self.is_pull_request:
- return f"refs/pr/{self.num}"
- return None
- @property
- def url(self) -> str:
- """Returns the URL of the discussion on the Hub."""
- if self.repo_type is None or self.repo_type == constants.REPO_TYPE_MODEL:
- return f"{self.endpoint}/{self.repo_id}/discussions/{self.num}"
- return f"{self.endpoint}/{self.repo_type}s/{self.repo_id}/discussions/{self.num}"
- @dataclass
- class DiscussionWithDetails(Discussion):
- """
- Subclass of [`Discussion`].
- Attributes:
- title (`str`):
- The title of the Discussion / Pull Request
- status (`str`):
- The status of the Discussion / Pull Request.
- It can be one of:
- * `"open"`
- * `"closed"`
- * `"merged"` (only for Pull Requests )
- * `"draft"` (only for Pull Requests )
- num (`int`):
- The number of the Discussion / Pull Request.
- repo_id (`str`):
- The id (`"{namespace}/{repo_name}"`) of the repo on which
- the Discussion / Pull Request was open.
- repo_type (`str`):
- The type of the repo on which the Discussion / Pull Request was open.
- Possible values are: `"model"`, `"dataset"`, `"space"`.
- author (`str`):
- The username of the Discussion / Pull Request author.
- Can be `"deleted"` if the user has been deleted since.
- is_pull_request (`bool`):
- Whether or not this is a Pull Request.
- created_at (`datetime`):
- The `datetime` of creation of the Discussion / Pull Request.
- events (`list` of [`DiscussionEvent`])
- The list of [`DiscussionEvents`] in this Discussion or Pull Request.
- conflicting_files (`Union[list[str], bool, None]`, *optional*):
- A list of conflicting files if this is a Pull Request.
- `None` if `self.is_pull_request` is `False`.
- `True` if there are conflicting files but the list can't be retrieved.
- target_branch (`str`, *optional*):
- The branch into which changes are to be merged if this is a
- Pull Request . `None` if `self.is_pull_request` is `False`.
- merge_commit_oid (`str`, *optional*):
- If this is a merged Pull Request , this is set to the OID / SHA of
- the merge commit, `None` otherwise.
- diff (`str`, *optional*):
- The git diff if this is a Pull Request , `None` otherwise.
- endpoint (`str`):
- Endpoint of the Hub. Default is https://huggingface.co.
- git_reference (`str`, *optional*):
- (property) Git reference to which changes can be pushed if this is a Pull Request, `None` otherwise.
- url (`str`):
- (property) URL of the discussion on the Hub.
- """
- events: list["DiscussionEvent"]
- conflicting_files: list[str] | bool | None
- target_branch: str | None
- merge_commit_oid: str | None
- diff: str | None
- class DiscussionEventArgs(TypedDict):
- id: str
- type: str
- created_at: datetime
- author: str
- _event: dict
- @dataclass
- class DiscussionEvent:
- """
- An event in a Discussion or Pull Request.
- Use concrete classes:
- * [`DiscussionComment`]
- * [`DiscussionStatusChange`]
- * [`DiscussionCommit`]
- * [`DiscussionTitleChange`]
- Attributes:
- id (`str`):
- The ID of the event. An hexadecimal string.
- type (`str`):
- The type of the event.
- created_at (`datetime`):
- A [`datetime`](https://docs.python.org/3/library/datetime.html?highlight=datetime#datetime.datetime)
- object holding the creation timestamp for the event.
- author (`str`):
- The username of the Discussion / Pull Request author.
- Can be `"deleted"` if the user has been deleted since.
- """
- id: str
- type: str
- created_at: datetime
- author: str
- _event: dict
- """Stores the original event data, in case we need to access it later."""
- @dataclass
- class DiscussionComment(DiscussionEvent):
- """A comment in a Discussion / Pull Request.
- Subclass of [`DiscussionEvent`].
- Attributes:
- id (`str`):
- The ID of the event. An hexadecimal string.
- type (`str`):
- The type of the event.
- created_at (`datetime`):
- A [`datetime`](https://docs.python.org/3/library/datetime.html?highlight=datetime#datetime.datetime)
- object holding the creation timestamp for the event.
- author (`str`):
- The username of the Discussion / Pull Request author.
- Can be `"deleted"` if the user has been deleted since.
- content (`str`):
- The raw markdown content of the comment. Mentions, links and images are not rendered.
- edited (`bool`):
- Whether or not this comment has been edited.
- hidden (`bool`):
- Whether or not this comment has been hidden.
- """
- content: str
- edited: bool
- hidden: bool
- @property
- def rendered(self) -> str:
- """The rendered comment, as a HTML string"""
- return self._event["data"]["latest"]["html"]
- @property
- def last_edited_at(self) -> datetime:
- """The last edit time, as a `datetime` object."""
- return parse_datetime(self._event["data"]["latest"]["updatedAt"])
- @property
- def last_edited_by(self) -> str:
- """The last edit time, as a `datetime` object."""
- return self._event["data"]["latest"].get("author", {}).get("name", "deleted")
- @property
- def edit_history(self) -> list[dict]:
- """The edit history of the comment"""
- return self._event["data"]["history"]
- @property
- def number_of_edits(self) -> int:
- return len(self.edit_history)
- @dataclass
- class DiscussionStatusChange(DiscussionEvent):
- """A change of status in a Discussion / Pull Request.
- Subclass of [`DiscussionEvent`].
- Attributes:
- id (`str`):
- The ID of the event. An hexadecimal string.
- type (`str`):
- The type of the event.
- created_at (`datetime`):
- A [`datetime`](https://docs.python.org/3/library/datetime.html?highlight=datetime#datetime.datetime)
- object holding the creation timestamp for the event.
- author (`str`):
- The username of the Discussion / Pull Request author.
- Can be `"deleted"` if the user has been deleted since.
- new_status (`str`):
- The status of the Discussion / Pull Request after the change.
- It can be one of:
- * `"open"`
- * `"closed"`
- * `"merged"` (only for Pull Requests )
- """
- new_status: str
- @dataclass
- class DiscussionCommit(DiscussionEvent):
- """A commit in a Pull Request.
- Subclass of [`DiscussionEvent`].
- Attributes:
- id (`str`):
- The ID of the event. An hexadecimal string.
- type (`str`):
- The type of the event.
- created_at (`datetime`):
- A [`datetime`](https://docs.python.org/3/library/datetime.html?highlight=datetime#datetime.datetime)
- object holding the creation timestamp for the event.
- author (`str`):
- The username of the Discussion / Pull Request author.
- Can be `"deleted"` if the user has been deleted since.
- summary (`str`):
- The summary of the commit.
- oid (`str`):
- The OID / SHA of the commit, as a hexadecimal string.
- """
- summary: str
- oid: str
- @dataclass
- class DiscussionTitleChange(DiscussionEvent):
- """A rename event in a Discussion / Pull Request.
- Subclass of [`DiscussionEvent`].
- Attributes:
- id (`str`):
- The ID of the event. An hexadecimal string.
- type (`str`):
- The type of the event.
- created_at (`datetime`):
- A [`datetime`](https://docs.python.org/3/library/datetime.html?highlight=datetime#datetime.datetime)
- object holding the creation timestamp for the event.
- author (`str`):
- The username of the Discussion / Pull Request author.
- Can be `"deleted"` if the user has been deleted since.
- old_title (`str`):
- The previous title for the Discussion / Pull Request.
- new_title (`str`):
- The new title.
- """
- old_title: str
- new_title: str
- def deserialize_event(event: dict) -> DiscussionEvent:
- """Instantiates a [`DiscussionEvent`] from a dict"""
- event_id: str = event["id"]
- event_type: str = event["type"]
- created_at = parse_datetime(event["createdAt"])
- common_args: DiscussionEventArgs = {
- "id": event_id,
- "type": event_type,
- "created_at": created_at,
- "author": event.get("author", {}).get("name", "deleted"),
- "_event": event,
- }
- if event_type == "comment":
- return DiscussionComment(
- **common_args,
- edited=event["data"]["edited"],
- hidden=event["data"]["hidden"],
- content=event["data"]["latest"]["raw"],
- )
- if event_type == "status-change":
- return DiscussionStatusChange(
- **common_args,
- new_status=event["data"]["status"],
- )
- if event_type == "commit":
- return DiscussionCommit(
- **common_args,
- summary=event["data"]["subject"],
- oid=event["data"]["oid"],
- )
- if event_type == "title-change":
- return DiscussionTitleChange(
- **common_args,
- old_title=event["data"]["from"],
- new_title=event["data"]["to"],
- )
- return DiscussionEvent(**common_args)
|