Steveeeeeeen's picture
Steveeeeeeen HF staff
Upload folder using huggingface_hub
9f0d781 verified
raw
history blame
12.2 kB
"""
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 List, Literal, Optional, Union
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) -> Optional[str]:
"""
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: Union[List[str], bool, None]
target_branch: Optional[str]
merge_commit_oid: Optional[str]
diff: Optional[str]
@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 = dict(
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)