merge GithubObject.pyi/Requester.pyi stubs back to source (#2463)

Co-authored-by: Enrico Minack <github@enrico.minack.dev>
Co-authored-by: Jonathan Leitschuh <jonathan.leitschuh@gmail.com>
This commit is contained in:
Trim21
2023-06-16 11:57:35 -04:00
committed by GitHub
co-authored by Enrico Minack Jonathan Leitschuh
parent 6d4b6d1419
commit b6258f4be9
10 changed files with 461 additions and 680 deletions
+134 -60
View File
@@ -41,40 +41,75 @@
import datetime
import typing
from operator import itemgetter
from typing import (
TYPE_CHECKING,
Any,
Callable,
Dict,
Generic,
List,
Optional,
Type,
Union,
)
from . import Consts, GithubException
from . import Consts
from .GithubException import BadAttributeException, IncompletableObject
if TYPE_CHECKING:
from .Requester import Requester
T = typing.TypeVar("T")
class _NotSetType:
class Attribute(Generic[T]):
@property
def value(self) -> T:
raise NotImplementedError
class _NotSetType(Attribute):
def __repr__(self):
return "NotSet"
value = None
@property
def value(self):
return None
@staticmethod
def remove_unset_items(data: Dict[str, Any]) -> Dict[str, Any]:
return {
key: value
for key, value in data.items()
if not isinstance(value, _NotSetType)
}
NotSet = _NotSetType()
T = typing.TypeVar("T")
OptionallySet = typing.Union[T, _NotSetType]
Opt = Union[T, _NotSetType]
class _ValuedAttribute:
def __init__(self, value):
self.value = value
class _ValuedAttribute(Attribute, Generic[T]):
def __init__(self, value: T):
self._value = value
@property
def value(self) -> T:
return self._value
class _BadAttribute:
def __init__(self, value, expectedType, exception=None):
class _BadAttribute(Attribute):
def __init__(
self, value: Any, expectedType: Any, exception: Optional[Exception] = None
):
self.__value = value
self.__expectedType = expectedType
self.__exception = exception
@property
def value(self):
raise GithubException.BadAttributeException(
self.__value, self.__expectedType, self.__exception
)
raise BadAttributeException(self.__value, self.__expectedType, self.__exception)
class GithubObject:
@@ -86,12 +121,19 @@ class GithubObject:
A global debug flag to enable header validation by requester for all objects
"""
CHECK_AFTER_INIT_FLAG = False
_url: Attribute[str]
@classmethod
def setCheckAfterInitFlag(cls, flag):
def setCheckAfterInitFlag(cls, flag: bool) -> None:
cls.CHECK_AFTER_INIT_FLAG = flag
def __init__(self, requester, headers, attributes, completed):
def __init__(
self,
requester: "Requester",
headers: Dict[str, Union[str, int]],
attributes: Any,
completed: bool,
):
self._requester = requester
self._initAttributes()
self._storeAndUseAttributes(headers, attributes)
@@ -101,7 +143,9 @@ class GithubObject:
if self.CHECK_AFTER_INIT_FLAG: # pragma no branch (Flag always set in tests)
requester.check_me(self)
def _storeAndUseAttributes(self, headers, attributes):
def _storeAndUseAttributes(
self, headers: Dict[str, Union[str, int]], attributes: Any
) -> None:
# Make sure headers are assigned before calling _useAttributes
# (Some derived classes will use headers in _useAttributes)
self._headers = headers
@@ -109,7 +153,7 @@ class GithubObject:
self._useAttributes(attributes)
@property
def raw_data(self):
def raw_data(self) -> Dict[str, Any]:
"""
:type: dict
"""
@@ -117,7 +161,7 @@ class GithubObject:
return self._rawData
@property
def raw_headers(self):
def raw_headers(self) -> Dict[str, Union[str, int]]:
"""
:type: dict
"""
@@ -125,43 +169,45 @@ class GithubObject:
return self._headers
@staticmethod
def _parentUrl(url):
def _parentUrl(url: str) -> str:
return "/".join(url.split("/")[:-1])
@staticmethod
def __makeSimpleAttribute(value, type):
def __makeSimpleAttribute(value: Any, type: Type[T]) -> Attribute[T]:
if value is None or isinstance(value, type):
return _ValuedAttribute(value)
return _ValuedAttribute(value) # type: ignore
else:
return _BadAttribute(value, type)
return _BadAttribute(value, type) # type: ignore
@staticmethod
def __makeSimpleListAttribute(value, type):
def __makeSimpleListAttribute(value: list, type: Type[T]) -> Attribute[T]:
if isinstance(value, list) and all(
isinstance(element, type) for element in value
):
return _ValuedAttribute(value)
return _ValuedAttribute(value) # type: ignore
else:
return _BadAttribute(value, [type])
return _BadAttribute(value, [type]) # type: ignore
@staticmethod
def __makeTransformedAttribute(value, type, transform):
def __makeTransformedAttribute(
value: T, type: Type[T], transform: Callable[[T], Any]
) -> Attribute[T]:
if value is None:
return _ValuedAttribute(None)
return _ValuedAttribute(None) # type: ignore
elif isinstance(value, type):
try:
return _ValuedAttribute(transform(value))
except Exception as e:
return _BadAttribute(value, type, e)
return _BadAttribute(value, type, e) # type: ignore
else:
return _BadAttribute(value, type)
return _BadAttribute(value, type) # type: ignore
@staticmethod
def _makeStringAttribute(value):
def _makeStringAttribute(value: Optional[Union[int, str]]) -> Attribute[str]:
return GithubObject.__makeSimpleAttribute(value, str)
@staticmethod
def _makeIntAttribute(value):
def _makeIntAttribute(value: Optional[Union[int, str]]) -> Attribute[int]:
return GithubObject.__makeSimpleAttribute(value, int)
@staticmethod
@@ -169,21 +215,21 @@ class GithubObject:
return GithubObject.__makeSimpleAttribute(value, float)
@staticmethod
def _makeBoolAttribute(value):
def _makeBoolAttribute(value: Optional[bool]) -> Attribute[bool]:
return GithubObject.__makeSimpleAttribute(value, bool)
@staticmethod
def _makeDictAttribute(value):
def _makeDictAttribute(value: Dict[str, Any]) -> Attribute[dict]:
return GithubObject.__makeSimpleAttribute(value, dict)
@staticmethod
def _makeTimestampAttribute(value):
def _makeTimestampAttribute(value: int) -> Attribute[int]:
return GithubObject.__makeTransformedAttribute(
value, int, datetime.datetime.utcfromtimestamp
)
@staticmethod
def _makeDatetimeAttribute(value):
def _makeDatetimeAttribute(value: Optional[Union[int, str]]) -> Attribute:
def parseDatetime(s):
if (
len(s) == 24
@@ -202,7 +248,7 @@ class GithubObject:
return GithubObject.__makeTransformedAttribute(value, str, parseDatetime)
def _makeClassAttribute(self, klass, value):
def _makeClassAttribute(self, klass: Any, value: Any) -> Attribute:
return GithubObject.__makeTransformedAttribute(
value,
dict,
@@ -210,22 +256,30 @@ class GithubObject:
)
@staticmethod
def _makeListOfStringsAttribute(value):
def _makeListOfStringsAttribute(
value: Union[List[List[str]], List[str], List[Union[str, int]]]
) -> Attribute:
return GithubObject.__makeSimpleListAttribute(value, str)
@staticmethod
def _makeListOfIntsAttribute(value):
def _makeListOfIntsAttribute(value: List[int]) -> Attribute:
return GithubObject.__makeSimpleListAttribute(value, int)
@staticmethod
def _makeListOfDictsAttribute(value):
def _makeListOfDictsAttribute(
value: List[Dict[str, Union[str, List[Dict[str, Union[str, List[int]]]]]]]
) -> Attribute:
return GithubObject.__makeSimpleListAttribute(value, dict)
@staticmethod
def _makeListOfListOfStringsAttribute(value):
def _makeListOfListOfStringsAttribute(
value: List[List[str]],
) -> Attribute:
return GithubObject.__makeSimpleListAttribute(value, list)
def _makeListOfClassesAttribute(self, klass, value):
def _makeListOfClassesAttribute(
self, klass: Any, value: Any
) -> Union[_ValuedAttribute, _BadAttribute]:
if isinstance(value, list) and all(
isinstance(element, dict) for element in value
):
@@ -238,7 +292,14 @@ class GithubObject:
else:
return _BadAttribute(value, [dict])
def _makeDictOfStringsToClassesAttribute(self, klass, value):
def _makeDictOfStringsToClassesAttribute(
self,
klass: Type["NonCompletableGithubObject"],
value: Dict[
str,
Union[int, Dict[str, Union[str, int, None]], Dict[str, Union[str, int]]],
],
) -> Union[_ValuedAttribute, _BadAttribute]:
if isinstance(value, dict) and all(
isinstance(key, str) and isinstance(element, dict)
for key, element in value.items()
@@ -253,20 +314,20 @@ class GithubObject:
return _BadAttribute(value, {str: dict})
@property
def etag(self):
def etag(self) -> Optional[str]:
"""
:type: str
"""
return self._headers.get(Consts.RES_ETAG)
return self._headers.get(Consts.RES_ETAG) # type: ignore
@property
def last_modified(self):
def last_modified(self) -> Optional[str]:
"""
:type: str
"""
return self._headers.get(Consts.RES_LAST_MODIFIED)
return self._headers.get(Consts.RES_LAST_MODIFIED) # type: ignore
def get__repr__(self, params):
def get__repr__(self, params: Dict[str, Any]) -> str:
"""
Converts the object to a nicely printable string.
"""
@@ -285,44 +346,57 @@ class GithubObject:
params=", ".join(list(format_params(params))),
)
def _initAttributes(self):
raise NotImplementedError("BUG: Not Implemented _initAttributes")
def _useAttributes(self, attributes):
raise NotImplementedError("BUG: Not Implemented _useAttributes")
def _completeIfNeeded(self):
raise NotImplementedError("BUG: Not Implemented _completeIfNeeded")
class NonCompletableGithubObject(GithubObject):
def _completeIfNeeded(self):
def _completeIfNeeded(self) -> None:
pass
class CompletableGithubObject(GithubObject):
def __init__(self, requester, headers, attributes, completed):
def __init__(
self,
requester: "Requester",
headers: Dict[str, Union[str, int]],
attributes: Dict[str, Any],
completed: bool,
):
super().__init__(requester, headers, attributes, completed)
self.__completed = completed
def __eq__(self, other):
def __eq__(self, other: Any) -> bool:
return other.__class__ is self.__class__ and other._url.value == self._url.value
def __hash__(self):
return hash(self._url.value)
def __ne__(self, other):
def __ne__(self, other: Any) -> bool:
return not self == other
def _completeIfNotSet(self, value):
if value is NotSet:
def _completeIfNotSet(self, value: Attribute) -> None:
if isinstance(value, _NotSetType):
self._completeIfNeeded()
def _completeIfNeeded(self):
def _completeIfNeeded(self) -> None:
if not self.__completed:
self.__complete()
def __complete(self):
if self._url.value is None:
raise GithubException.IncompletableObject(
400, "Returned object contains no URL", None
)
raise IncompletableObject(400, "Returned object contains no URL", None)
headers, data = self._requester.requestJsonAndCheck("GET", self._url.value)
self._storeAndUseAttributes(headers, data)
self.__completed = True
def update(self, additional_headers=None):
def update(self, additional_headers: Optional[Dict[str, Any]] = None) -> bool:
"""
Check and update the object with conditional request
:rtype: Boolean value indicating whether the object is changed
@@ -341,7 +415,7 @@ class CompletableGithubObject(GithubObject):
if status == 304:
return False
else:
headers, data = self._requester._Requester__check(
headers, data = self._requester._Requester__check( # type: ignore
status, responseHeaders, output
)
self._storeAndUseAttributes(headers, data)