Skip to content

Commit

Permalink
WIP: building a centralized context module
Browse files Browse the repository at this point in the history
  • Loading branch information
gizmo385 committed Sep 12, 2024
1 parent 9c8d737 commit 2f2f7e2
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 22 deletions.
34 changes: 34 additions & 0 deletions lazy_github/lib/context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from typing import Optional

from lazy_github.lib.config import Config
from lazy_github.lib.constants import JSON_CONTENT_ACCEPT_TYPE
from lazy_github.lib.github.client import GithubClient, _get_client
from lazy_github.lib.utils import classproperty


class LazyGithubContext:
"""Globally accessible wrapper class that centralizes access to the configuration and the Github API client"""

_config: Config | None = None
_client: GithubClient | None = None

@classproperty
def config(cls) -> Config:
if cls._config is None:
cls._config = Config.load_config()
return cls._config

@classproperty
def client(cls) -> GithubClient:
# Ideally this is would just be a none check but that doesn't properly type check for some reason
if not isinstance(cls._client, GithubClient):
cls._client = _get_client(config=cls.config)
return cls._client


def github_headers(accept: str = JSON_CONTENT_ACCEPT_TYPE, cache_duration: Optional[int] = None) -> dict[str, str]:
"""Helper function to build headers for Github API requests"""
headers = {"Accept": accept, "Authorization": f"Bearer {LazyGithubContext.client.access_token}"}
max_age = cache_duration or LazyGithubContext.config.cache.default_ttl
headers["Cache-Control"] = f"max-age={max_age}"
return headers
4 changes: 2 additions & 2 deletions lazy_github/lib/github/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ async def user(self) -> User:
_GITHUB_CLIENT: GithubClient | None = None


def _get_client() -> GithubClient:
def _get_client(config: Config | None = None) -> GithubClient:
global _GITHUB_CLIENT
if not _GITHUB_CLIENT:
_GITHUB_CLIENT = GithubClient(Config.load_config(), token())
_GITHUB_CLIENT = GithubClient(config or Config.load_config(), token())
return _GITHUB_CLIENT


Expand Down
19 changes: 9 additions & 10 deletions lazy_github/lib/github/issues.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from typing import TypedDict, Unpack

import lazy_github.lib.github.client as github
from lazy_github.lib.config import Config
from lazy_github.lib.constants import IssueOwnerFilter, IssueStateFilter
from lazy_github.lib.context import LazyGithubContext, github_headers
from lazy_github.models.github import Issue, IssueComment, PartialPullRequest, Repository


Expand All @@ -16,12 +15,12 @@ async def list_issues(repo: Repository, state: IssueStateFilter, owner: IssueOwn
"""Fetch issues (included pull requests) from the repo matching the state/owner filters"""
query_params = {"state": str(state).lower()}
if owner == IssueOwnerFilter.MINE:
user = await github.user()
user = await LazyGithubContext.client.user()
query_params["creator"] = user.login

config = Config.load_config()
headers = github.headers_with_auth_accept(cache_duration=config.cache.list_issues_ttl)
response = await github.get(f"/repos/{repo.owner.login}/{repo.name}/issues", headers=headers, params=query_params)
response = await LazyGithubContext.client.get(
f"/repos/{repo.owner.login}/{repo.name}/issues", headers=github_headers(), params=query_params
)
response.raise_for_status()
result: list[Issue] = []
for issue in response.json():
Expand All @@ -33,30 +32,30 @@ async def list_issues(repo: Repository, state: IssueStateFilter, owner: IssueOwn


async def get_comments(issue: Issue) -> list[IssueComment]:
response = await github.get(issue.comments_url, headers=github.headers_with_auth_accept())
response = await LazyGithubContext.client.get(issue.comments_url, headers=github_headers())
response.raise_for_status()
return [IssueComment(**i) for i in response.json()]


async def create_comment(issue: Issue, comment_body: str) -> IssueComment:
url = f"/repos/{issue.repo.owner.login}/{issue.repo.name}/issues/{issue.number}/comments"
body = {"body": comment_body}
response = await github.post(url, json=body, headers=github.headers_with_auth_accept())
response = await LazyGithubContext.client.post(url, json=body, headers=github_headers())
response.raise_for_status()
return IssueComment(**response.json())


async def update_issue(issue_to_update: Issue, **updated_fields: Unpack[UpdateIssuePayload]) -> Issue:
repo = issue_to_update.repo
url = f"/repos/{repo.owner.login}/{repo.name}/issues/{issue_to_update.number}"
response = await github.patch(url, json=updated_fields, headers=github.headers_with_auth_accept())
response = await LazyGithubContext.client.patch(url, json=updated_fields, headers=github_headers())
response.raise_for_status()
return Issue(**response.json(), repo=repo)


async def create_issue(repo: Repository, title: str, body: str) -> Issue:
url = f"/repos/{repo.owner.login}/{repo.name}/issues"
json_body = {"title": title, "body": body}
response = await github.post(url, json=json_body, headers=github.headers_with_auth_accept())
response = await LazyGithubContext.client.post(url, json=json_body, headers=github_headers())
response.raise_for_status()
return Issue(**response.json(), repo=repo)
18 changes: 11 additions & 7 deletions lazy_github/lib/github/pull_requests.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from lazy_github.lib.config import Config
from lazy_github.lib.constants import DIFF_CONTENT_ACCEPT_TYPE
import lazy_github.lib.github.client as github
from lazy_github.lib.context import LazyGithubContext
from lazy_github.lib.github.issues import list_issues
from lazy_github.models.github import (
FullPullRequest,
Expand All @@ -24,29 +24,32 @@ async def list_for_repo(repo: Repository) -> list[PartialPullRequest]:
async def get_full_pull_request(partial_pr: PartialPullRequest) -> FullPullRequest:
"""Converts a partial pull request into a full pull request"""
url = f"/repos/{partial_pr.repo.owner.login}/{partial_pr.repo.name}/pulls/{partial_pr.number}"
response = await github.get(url, headers=github.headers_with_auth_accept())
headers = LazyGithubContext.client.headers_with_auth_accept()
response = await LazyGithubContext.client.get(url, headers=headers)
response.raise_for_status()
return FullPullRequest(**response.json(), repo=partial_pr.repo)


async def get_diff(pr: FullPullRequest) -> str:
"""Fetches the raw diff for an individual pull request"""
headers = github.headers_with_auth_accept(DIFF_CONTENT_ACCEPT_TYPE)
response = await github.get(pr.diff_url, headers=headers, follow_redirects=True)
headers = LazyGithubContext.client.headers_with_auth_accept(DIFF_CONTENT_ACCEPT_TYPE)
response = await LazyGithubContext.client.get(pr.diff_url, headers=headers, follow_redirects=True)
response.raise_for_status()
return response.text


async def get_review_comments(pr: FullPullRequest, review: Review) -> list[ReviewComment]:
url = f"/repos/{pr.repo.owner.login}/{pr.repo.name}/pulls/{pr.number}/reviews/{review.id}/comments"
response = await github.get(url, headers=github.headers_with_auth_accept())
headers = LazyGithubContext.client.headers_with_auth_accept()
response = await LazyGithubContext.client.get(url, headers=headers)
response.raise_for_status()
return [ReviewComment(**c) for c in response.json()]


async def get_reviews(pr: FullPullRequest, with_comments: bool = True) -> list[Review]:
url = url = f"/repos/{pr.repo.owner.login}/{pr.repo.name}/pulls/{pr.number}/reviews"
response = await github.get(url, headers=github.headers_with_auth_accept())
headers = LazyGithubContext.client.headers_with_auth_accept()
response = await LazyGithubContext.client.get(url, headers=headers)
response.raise_for_status()
reviews: list[Review] = []
for raw_review in response.json():
Expand All @@ -61,7 +64,8 @@ async def reply_to_review_comment(
repo: Repository, issue: Issue, comment: ReviewComment, comment_body: str
) -> ReviewComment:
url = f"/repos/{repo.owner.login}/{repo.name}/pulls/{issue.number}/comments/{comment.id}/replies"
response = await github.post(url, headers=github.headers_with_auth_accept(), json={"body": comment_body})
headers = LazyGithubContext.client.headers_with_auth_accept()
response = await LazyGithubContext.client.post(url, headers=headers, json={"body": comment_body})
response.raise_for_status()
return ReviewComment(**response.json())

Expand Down
10 changes: 10 additions & 0 deletions lazy_github/lib/string_utils.py → lazy_github/lib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,13 @@ def bold(s: str) -> str:
def link(link_text: str, url: str) -> str:
"""Formats a link in Rich-style markup"""
return f"[link={url}]{link_text}[/link]"


class classproperty:
"""Simple implementation of the @property decorator but for classes"""

def __init__(self, func):
self.fget = func

def __get__(self, instance, owner):
return self.fget(owner)
2 changes: 1 addition & 1 deletion lazy_github/ui/widgets/issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from lazy_github.lib.github.issues import get_comments
from lazy_github.lib.messages import IssuesAndPullRequestsFetched, IssueSelected
from lazy_github.lib.string_utils import link
from lazy_github.lib.utils import link
from lazy_github.models.github import Issue, IssueState
from lazy_github.ui.screens.edit_issue import EditIssueModal
from lazy_github.ui.screens.new_issue import NewIssueModal
Expand Down
2 changes: 1 addition & 1 deletion lazy_github/ui/widgets/pull_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
reconstruct_review_conversation_hierarchy,
)
from lazy_github.lib.messages import IssuesAndPullRequestsFetched, PullRequestSelected
from lazy_github.lib.string_utils import bold, link, pluralize
from lazy_github.lib.utils import bold, link, pluralize
from lazy_github.models.github import FullPullRequest, PartialPullRequest
from lazy_github.ui.screens.new_comment import NewCommentModal
from lazy_github.ui.widgets.command_log import log_event
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 2f2f7e2

Please sign in to comment.