ayon-core/pype/modules/rest_api/lib/lib.py
2020-05-25 18:20:02 +02:00

197 lines
5.2 KiB
Python

import enum
from http import HTTPStatus
from urllib.parse import urlencode, parse_qs
Splitter = "__splitter__"
class RestMethods(enum.Enum):
GET = "GET"
POST = "POST"
PUT = "PUT"
PATCH = "PATCH"
DELETE = "DELETE"
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.value == other.value
elif isinstance(other, str):
return self.value.lower() == other.lower()
return self.value == other
def __hash__(self):
return enum.Enum.__hash__(self)
@classmethod
def get(cls, name, default=None):
for meth in cls:
if meth == name:
return meth
return default
class HandlerDict(dict):
def __init__(self, data=None, *args, **kwargs):
if not data:
data = {}
super().__init__(data, *args, **kwargs)
def __repr__(self):
return "<{}> {}".format(self.__class__.__name__, str(dict(self)))
class Params(HandlerDict):
pass
class UrlData(HandlerDict):
pass
class RequestData(HandlerDict):
pass
class Query(HandlerDict):
"""Class for url query convert to dict and string."""
def __init__(self, query):
if isinstance(query, dict):
pass
else:
query = parse_qs(query)
super().__init__(query)
def get_string(self):
return urlencode(dict(self), doseq=True)
class Fragment(HandlerDict):
"""Class for url fragment convert to dict and string."""
def __init__(self, fragment):
if isinstance(fragment, dict):
_fragment = fragment
else:
_fragment = {}
for frag in fragment.split("&"):
if not frag:
continue
items = frag.split("=")
value = None
key = items[0]
if len(items) == 2:
value = items[1]
elif len(items) > 2:
value = "=".join(items[1:])
_fragment[key] = value
super().__init__(_fragment)
def get_string(self):
items = []
for parts in dict(self).items():
items.append(
"=".join([p for p in parts if p])
)
return "&".join(items)
class RequestInfo:
"""Object that can be passed to callback as argument.
Contain necessary data for handling request.
Object is created to single use and can be used similar to dict.
:param url_data: Data collected from path when path with dynamic keys
is matching.
:type url_data: dict, None
:param request_data: Data of body from request.
:type request_data: dict, None
:param query: Query from url path of reques.
:type query: str, None
:param fragment: Fragment from url path of reques.
:type fragment: str, None
:param params: Parems from url path of reques.
:type params: str, None
:param method: Method of request (GET, POST, etc.)
:type method: RestMethods
:param handler: Handler handling request from http server.
:type handler: Handler
"""
def __init__(
self, url_data, request_data, query, fragment, params, method, handler
):
self.url_data = UrlData(url_data)
self.request_data = RequestData(request_data)
self.query = Query(query)
self.fragment = Fragment(fragment)
self.params = Params(params)
self.method = method
self.handler = handler
def __getitem__(self, key):
return self.__getattribute__(key)
def __hash__(self):
return {
"url_data": self.url_data,
"request_data": self. request_data,
"query": self.query,
"fragment": self.fragment,
"params": self.params,
"method": self.method,
"handler": self.handler
}
def items(self):
return dict(self).items()
class CallbackResult:
"""Can be used as return value of callback.
It is possible to specify status code, success boolean, message and data
for specify head and body of request response. `abort` should be rather
used when result is error.
:param status_code: Status code of result.
:type status_code: int
:param success: Success is key in body, may be used for handling response.
:type success: bool
:param message: Similar to success, message is key in body and may
be used for handling response.
:type message: str, None
:param data: Data is also key for body in response.
:type data: dict, None
"""
_data = {}
def __init__(
self, status_code=HTTPStatus.OK, success=True, message=None, data=None,
**kwargs
):
self.status_code = status_code
self._data = {
"success": success,
"message": message,
"data": data
}
for k, v in kwargs.items():
self._data[k] = v
def __getitem__(self, key):
return self._data[key]
def __iter__(self):
for key in self._data:
yield key
def get(self, key, default=None):
return self._data.get(key, default)
def items(self):
return self._data.items()