1
Fork 0
mirror of https://github.com/RGBCube/GitHubWrapper synced 2025-05-18 06:55:09 +00:00

Adding files to repos

This commit is contained in:
VarMonke 2022-05-11 11:33:22 +05:30
parent 72bd647c9b
commit 3d49dd9246
5 changed files with 102 additions and 37 deletions

View file

@ -59,6 +59,7 @@ class GHClient:
token: Optional[:class:`str`] token: Optional[:class:`str`]
The authenticated Client's token, if applicable. The authenticated Client's token, if applicable.
""" """
has_started: bool = False has_started: bool = False
def __init__( def __init__(
@ -109,7 +110,7 @@ class GHClient:
raise Exception('HTTP Session doesn\'t exist') from exc raise Exception('HTTP Session doesn\'t exist') from exc
def __repr__(self) -> str: def __repr__(self) -> str:
return f'<{self.__class__.__name__} has_auth={bool(self.__auth)}>' return f'<Client has_auth={bool(self.__auth)}>'
@overload @overload
def check_limits(self, as_dict: Literal[True] = True) -> Dict[str, Union[str, int]]: def check_limits(self, as_dict: Literal[True] = True) -> Dict[str, Union[str, int]]:
@ -318,7 +319,9 @@ class GHClient:
""" """
return Gist(await self.http.get_gist(gist), self.http) return Gist(await self.http.get_gist(gist), self.http)
async def create_gist(self, *, files: List[File], description: str, public: bool) -> Gist: async def create_gist(
self, *, files: List[File], description: str = 'Gist from Github-Api-Wrapper', public: bool = True
) -> Gist:
"""Creates a Gist with the given files, requires authorisation. """Creates a Gist with the given files, requires authorisation.
Parameters Parameters

View file

@ -1,7 +1,7 @@
# == exceptions.py ==# # == exceptions.py ==#
import datetime import datetime
from typing import Tuple from typing import Optional, Tuple
from aiohttp import ClientResponse from aiohttp import ClientResponse
@ -162,3 +162,10 @@ class RepositoryAlreadyExists(ResourceAlreadyExists):
def __init__(self): def __init__(self):
msg = 'The requested repository already exists.' msg = 'The requested repository already exists.'
super().__init__(msg) super().__init__(msg)
class FileAlreadyExists(ResourceAlreadyExists):
def __init__(self, msg: Optional[str] = None):
if msg is None:
msg = 'The requested file already exists.'
super().__init__(msg)

View file

@ -1,20 +1,24 @@
# == http.py ==# # == http.py ==#
from __future__ import annotations from __future__ import annotations
from asyncio.base_subprocess import ReadSubprocessPipeProto
from base64 import b64encode
import json import json
import re import re
from datetime import datetime from datetime import datetime
from types import SimpleNamespace from types import SimpleNamespace
from typing import Any, Dict, NamedTuple, Optional, Type, Tuple, Union, List from typing import Any, Dict, Literal, NamedTuple, Optional, Type, Tuple, Union, List
from typing_extensions import TypeAlias from typing_extensions import TypeAlias, reveal_type
import platform import platform
import aiohttp import aiohttp
from .exceptions import * from .exceptions import *
from .exceptions import GistNotFound, RepositoryAlreadyExists, MissingPermissions from .exceptions import GistNotFound, RepositoryAlreadyExists, MissingPermissions
from .objects import User, Gist, Repository, File from .exceptions import FileAlreadyExists
from .exceptions import ResourceAlreadyExists
from .objects import User, Gist, Repository, File, bytes_to_b64
from .urls import * from .urls import *
from . import __version__ from . import __version__
@ -300,3 +304,23 @@ class http:
if result.status == 401: if result.status == 401:
raise NoAuthProvided raise NoAuthProvided
raise RepositoryAlreadyExists raise RepositoryAlreadyExists
async def add_file(self, owner: str, repo_name: str, filename: str, content: str, message: str, branch: str):
"""Adds a file to the given repo."""
data = {
'content': bytes_to_b64(content=content),
'message': message,
'branch': branch,
}
result = await self.session.put(ADD_FILE_URL.format(owner, repo_name, filename), data=json.dumps(data))
if 200 <= result.status <= 299:
return await result.json()
if result.status == 401:
raise NoAuthProvided
if result.status == 409:
raise FileAlreadyExists
if result.status == 422:
raise FileAlreadyExists('This file exists, and can only be edited.')
return await result.json(), result.status

View file

@ -1,7 +1,11 @@
# == objects.py ==# # == objects.py ==#
from __future__ import annotations from __future__ import annotations
from base64 import b64encode
import json
from typing import TYPE_CHECKING, Any, Optional, Tuple, Union, Dict, List from typing import TYPE_CHECKING, Any, Literal, Optional, Tuple, Union, Dict, List
import aiohttp
if TYPE_CHECKING: if TYPE_CHECKING:
from .http import http from .http import http
@ -35,8 +39,13 @@ def repr_dt(_datetime: datetime) -> str:
return _datetime.strftime(r'%d-%m-%Y, %H:%M:%S') return _datetime.strftime(r'%d-%m-%Y, %H:%M:%S')
def bytes_to_b64(content) -> str:
return b64encode(content.encode('utf-8')).decode('ascii')
class APIObject: class APIObject:
"""Top level class for objects created from the API""" """Top level class for objects created from the API"""
__slots__: Tuple[str, ...] = ('_response', '_http') __slots__: Tuple[str, ...] = ('_response', '_http')
def __init__(self, response: Dict[str, Any], _http: http) -> None: def __init__(self, response: Dict[str, Any], _http: http) -> None:
@ -102,6 +111,7 @@ class User(_BaseUser):
created_at: :class:`datetime.datetime` created_at: :class:`datetime.datetime`
The time of creation of the user. The time of creation of the user.
""" """
__slots__ = ( __slots__ = (
'login', 'login',
'id', 'id',
@ -130,7 +140,6 @@ class User(_BaseUser):
return f'<{self.__class__.__name__} login: {self.login!r}, id: {self.id}, created_at: {self.created_at}>' return f'<{self.__class__.__name__} login: {self.login!r}, id: {self.id}, created_at: {self.created_at}>'
class PartialUser(_BaseUser): class PartialUser(_BaseUser):
__slots__ = ( __slots__ = (
'site_admin', 'site_admin',
@ -182,6 +191,7 @@ class Repository(APIObject):
default_branch: :class:`str` default_branch: :class:`str`
The name of the default branch of the repository. The name of the default branch of the repository.
""" """
if TYPE_CHECKING: if TYPE_CHECKING:
id: int id: int
name: str name: str
@ -198,7 +208,6 @@ class Repository(APIObject):
'disabled', 'disabled',
'updated_at', 'updated_at',
'open_issues_count', 'open_issues_count',
'default_branch',
'clone_url', 'clone_url',
'stargazers_count', 'stargazers_count',
'watchers_count', 'watchers_count',
@ -253,9 +262,25 @@ class Repository(APIObject):
def forks(self) -> int: def forks(self) -> int:
return self._response.get('forks') return self._response.get('forks')
@property
def default_branch(self) -> str:
""":class:`str`: The default branch of the repository."""
return self._response.get('default_branch')
async def delete(self) -> None: async def delete(self) -> None:
"""Deletes the repository.""" """Deletes the repository."""
return await self._http.delete_repo(self.owner.name, self.name,) #type: ignore return await self._http.delete_repo(
self.owner.name, # type: ignore this shit is not my fault
self.name,
) # type: ignore
async def add_file(self, filename: str, message: str, content: str, branch: Optional[str] = None) -> None:
"""Adds a file to the repository."""
if branch is None:
branch = self.default_branch
return await self._http.add_file(owner=self.owner.name, repo_name=self.name, filename=filename, content=content, message=message, branch=branch) # type: ignore
class Issue(APIObject): class Issue(APIObject):
@ -278,6 +303,7 @@ class Issue(APIObject):
closed_by: Optional[Union[:class:`PartialUser`, :class:`User`]] closed_by: Optional[Union[:class:`PartialUser`, :class:`User`]]
The user the issue was closed by, if applicable. The user the issue was closed by, if applicable.
""" """
__slots__ = ( __slots__ = (
'id', 'id',
'title', 'title',
@ -331,13 +357,14 @@ class File:
Parameters Parameters
---------- ----------
fp: Union[:class:`str`, :class:`io.StringIO`] fp: Union[:class:`str`, :class:`io.StringIO`, :class:`io.BytesIO`]
The filepath or StringIO representing a file to upload. The filepath or StringIO representing a file to upload.
If providing a StringIO instance, a filename shuold also be provided to the file. If providing a StringIO instance, a filename shuold also be provided to the file.
filename: :class:`str` filename: :class:`str`
An override to the file's name, encouraged to provide this if using a StringIO instance. An override to the file's name, encouraged to provide this if using a StringIO instance.
""" """
def __init__(self, fp: Union[str, io.StringIO], filename: str = 'DefaultFilename.txt') -> None:
def __init__(self, fp: Union[str, io.StringIO, io.BytesIO], filename: str = 'DefaultFilename.txt') -> None:
self.fp = fp self.fp = fp
self.filename = filename self.filename = filename
@ -346,12 +373,10 @@ class File:
if os.path.exists(self.fp): if os.path.exists(self.fp):
with open(self.fp) as fp: with open(self.fp) as fp:
data = fp.read() data = fp.read()
return data return data
return self.fp return self.fp
elif isinstance(self.fp, io.BytesIO): elif isinstance(self.fp, io.BytesIO):
return self.fp.read() return self.fp.read().decode('utf-8')
elif isinstance(self.fp, io.StringIO): # type: ignore elif isinstance(self.fp, io.StringIO): # type: ignore
return self.fp.getvalue() return self.fp.getvalue()
@ -376,6 +401,7 @@ class Gist(APIObject):
created_at: :class:`datetime.datetime` created_at: :class:`datetime.datetime`
The time the gist was created at. The time the gist was created at.
""" """
__slots__ = ( __slots__ = (
'id', 'id',
'html_url', 'html_url',
@ -444,6 +470,7 @@ class Organization(APIObject):
avatar_url: :class:`str` avatar_url: :class:`str`
The url of the organization's avatar. The url of the organization's avatar.
""" """
__slots__ = ( __slots__ = (
'login', 'login',
'id', 'id',

View file

@ -28,6 +28,10 @@ REPOS_URL = BASE_URL + '/repos/{0}' # repos of a user
REPO_URL = BASE_URL + '/repos/{0}/{1}' # a specific repo REPO_URL = BASE_URL + '/repos/{0}/{1}' # a specific repo
ADD_FILE_URL = BASE_URL + '/repos/{}/{}/contents/{}'
ADD_FILE_BRANCH = BASE_URL + ''
REPO_ISSUE_URL = REPO_URL + '/issues/{2}' # a specific issue REPO_ISSUE_URL = REPO_URL + '/issues/{2}' # a specific issue
# == gist urls ==# # == gist urls ==#