Update to 0.3.0

This commit is contained in:
2022-05-24 14:21:11 +03:00
parent 2068587712
commit 6093826c78
5 changed files with 171 additions and 104 deletions

11
.gitignore vendored Normal file
View File

@@ -0,0 +1,11 @@
# Byte-compiled / optimized / DLL files
__pycache__/
# Distribution / packaging
build/
dist/
jsonrpc.egg-info/
prototypes/
.tox/
tests/

View File

@@ -1,51 +1,66 @@
import json import json
import logging import logging
import traceback
from inspect import signature from inspect import signature
from .exceptions import *
PARSE_ERROR = -32700
INVALID_REQUEST = -32600
METHOD_NOT_FOUND = -32601
INVALID_PARAMS = -32602
INTERNAL_ERROR = -32603
GENERIC_APPLICATION_ERROR = -32000
class JsonRpcException(Exception): log = logging.getLogger(__name__)
"""Исключение
"""
def __init__(self, id, code, message): class Response:
def __init__(self, id: int, result):
self.id = id self.id = id
self.code = code self.result = result
self.message = message
def as_dict(self): def __json__(self):
"""Класс в JSON словарь response = {
""" "jsonrpc": "2.0",
result = { "result": self.result,
'jsonrpc':'2.0', "id": self.id,
'id': self.id,
'error': {
'code': self.code,
'message':self.message
} }
} return response
return result
def __str__(self):
return json.dumps(self.as_dict())
class Method: class Method:
def __init__(self, function, handler = None, fields = None): def __init__(self, function, pre = None):
self.function = function self.function = function
self.handler = handler self.pre = pre
self.fields = fields
def __call__(self, query): def __call__(self, query):
if self.handler is None: params = None
return self.function() if 'params' in query:
result = self.handler(query, self.function) params = query['params']
return result log.error(params)
if isinstance(self.pre, list):
pass
elif type(self.pre).__name__=='function':
self.pre(query)
if params is None:
response = self.function()
elif isinstance(params, list):
response = self.function(*params)
elif isinstance(params, dict):
response = self.function(**params)
else:
raise InvalidParamsError(
id=query['id'],
message='Invalid params: {0}'.format(params)
)
return response
def __repr__(self):
return '<{}>'.format(self.function)
class Wrapper:
def __init__(self, func):
self.func = func
class JSONRPC: class JSONRPC:
@@ -54,23 +69,15 @@ class JSONRPC:
def __init__(self): def __init__(self):
self.methods = {} self.methods = {}
def method(self, name: str, handler = None, fields = None): def method(self, name: str, pre = None):
"""Декоратор метода """Декоратор метода
""" """
assert len(name) > 0, 'Не указано имя метода' assert len(name) > 0, 'Не указано имя метода'
# logging.info('{} {}: {}'.format(
# func.__module__,
# func.__name__,
# func.__doc__
# ))
# funcname = func.__name__
# modulename = func.__module__
def wrap(function): def wrap(function):
# print(func)
method = Method( method = Method(
function = function, function = function,
handler = handler, pre = pre
fields = fields
) )
self.methods[name] = method self.methods[name] = method
return function return function
@@ -127,20 +134,17 @@ class JSONRPC:
"""Валидация запроса """Валидация запроса
""" """
keys = query.keys() keys = query.keys()
logging.info(f'keys: {keys}')
if 'id' not in query: if 'id' not in query:
return JsonRpcException( return InvalidRequestError(
query['id'], id=query['id'],
INVALID_REQUEST, message=f'Некорректный запрос: {query}'
f'Некорректный запрос: {query}' ).__json__()
).as_dict()
if 'method' not in query: if 'method' not in query:
return JsonRpcException( return InvalidRequestError(
query['id'], id=query['id'],
INVALID_REQUEST, message=f'Некорректный запрос: {query}'
f'Некорректный запрос: {query}' ).__json__()
).as_dict()
def process(self, query): def process(self, query):
"""Выполнение метода """Выполнение метода
@@ -148,58 +152,36 @@ class JSONRPC:
self.validate(query) self.validate(query)
name = query['method'] name = query['method']
if name not in self.methods: if name not in self.methods:
return JsonRpcException( result = MethodNotFoundError(
query['id'], query['id'],
METHOD_NOT_FOUND, message=f'Метод не найден: {name}'
f'Метод не найден: {name}' )
).as_dict() return result.__json__()
method = self.methods[name] method = self.methods[name]
params = None
if 'params' in query:
params = query['params']
# for key in params:
# print(f'{key}: {type(params[key]).__name__} = {params[key]}')
logging.debug('params: {}'.format(params))
try: try:
if method.handler is None: response = method(query)
pass except JSONRPCError as e:
else: log.error(traceback.format_exc())
method.handler( # print(traceback.format_exc())
query, response = traceback.format_exc()
method.function except Exception as e:
log.error(traceback.format_exc())
response = InternalError(
id=query['id'],
# message=str(e)
message=traceback.format_exc()
) )
if params is None:
response = method.function()
elif isinstance(params, list):
response = method.function(*params)
elif isinstance(params, dict):
response = method.function(**params)
else: else:
return JsonRpcException( response = Response(
query['id'], id=query['id'],
INVALID_PARAMS, result=response
'Invalid params: {0}'.format(params)
) )
except BaseException as e: result = response.__json__()
result = {
"jsonrpc": "2.0",
"id": query['id'],
"error": {
"message": str(e)
}
}
else:
result = {
"jsonrpc": "2.0",
"id": query['id'],
"result": response
}
return result return result
def __call__(self, queries): def __call__(self, queries):
"""Вызов метода """Вызов метода
""" """
@@ -221,8 +203,8 @@ class JSONRPC:
def __len__(self): def __len__(self):
return len(self.methods) return len(self.methods)
def __setitem__(self, key, function, handler = None, fields = None): def __setitem__(self, key, function, pre=None):
method = Method(function = function, handler = None, fields = None) method = Method(function=function, pre=pre)
self.methods[key] = method self.methods[key] = method
def __delitem__(self, key): def __delitem__(self, key):

74
jsonrpc/exceptions.py Normal file
View File

@@ -0,0 +1,74 @@
class JSONRPCError(Exception):
def __init__(self, id: int, message):
pass
def __json__(self):
result = {
"jsonrpc": "2.0",
"id": self.id,
"error": {
"code": self.CODE,
"message": self.message
}
}
return result
class InvalidRequestError(JSONRPCError):
CODE = -32600
def __init__(self, id: int, message: str = 'Invalid Request'):
self.id = id
self.message = message
self.code = CODE
class ParseError(JSONRPCError):
CODE = -32700
def __init__(self, id: int, message: str = 'Parse error'):
self.id = id
self.message = message
self.code = CODE
class MethodNotFoundError(JSONRPCError):
CODE = -32601
def __init__(self, id: int, message: str = 'Method not found'):
self.id = id
self.message = message
self.code = self.CODE
class InvalidParamsError(JSONRPCError):
CODE = -32602
def __init__(self, id: int, message: str = 'Invalid params'):
self.id = id
self.message = message
self.code = self.CODE
class InternalError(JSONRPCError):
"""Internal JSON-RPC error
"""
CODE = -32603
def __init__(self, id: int, message: str = 'Internal error'):
self.id = id
self.message = message
self.code = self.CODE
class ServerError(JSONRPCError):
"""Reserved for implementation-defined server-errors.
code: -32000 to -32099 Server error.
"""
CODE = -32000
def __init__(self, id: int, message: str = 'Server error'):
self.id = id
self.message = message
self.code = self.CODE

View File

@@ -1,3 +1,3 @@
[metadata] [metadata]
name = jsonrpc name = jsonrpc
version = 0.2.0 version = 0.3.0

View File

@@ -5,7 +5,7 @@ from setuptools import setup, find_packages
setup( setup(
name='jsonrpc', name='jsonrpc',
version='0.2.0', version='0.3.0',
author='RemiZOffAlex', author='RemiZOffAlex',
author_email='remizoffalex@gmail.com', author_email='remizoffalex@gmail.com',
packages=find_packages(exclude=['prototypes', 'tests']), packages=find_packages(exclude=['prototypes', 'tests']),