jsonrpc-base

Pure python standard library JSONRPC data interface
git clone git://git.defalsify.org/python-jsonrpc-base.git
Log | Files | Refs | LICENSE

commit d94a42d734765a00bd340260916e1de55a374cbf
parent ae57339500442ef58e300360b7a479ac7e2aa88d
Author: nolash <dev@holbrook.no>
Date:   Fri,  9 Apr 2021 15:57:41 +0200

Improve tests

Diffstat:
Mjsonrpc_std/error.py | 20+++++++++++++++-----
Mjsonrpc_std/parse.py | 9++++++---
Msetup.cfg | 2+-
Mtests/test_error.py | 10++++++++++
Atests/test_parse.py | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 145 insertions(+), 9 deletions(-)

diff --git a/jsonrpc_std/error.py b/jsonrpc_std/error.py @@ -1,16 +1,30 @@ # local imports from .base import JSONRPCBase + class JSONRPCException(Exception, JSONRPCBase): message = 'Unknown' - def __init__(self, v): + def __init__(self, v, request_id=None): context_v = '{} error'.format(self.message) if v != None: context_v += ': ' + v + self.request_id = request_id + super(JSONRPCException, self).__init__(context_v) + # Thanks to https://stackoverflow.com/questions/35282222/in-python-how-do-i-cast-a-class-object-to-a-dict + def __iter__(self): + if self.request_id == None: + raise AttributeError('request id cannot be undefined when serializing error') + yield 'jsonrpc', JSONRPCBase.version_string + yield 'id', self.request_id + yield 'error', { + 'code': self.code, + 'message': str(self), + } + class JSONRPCCustomException(JSONRPCException): code = -32000 @@ -80,7 +94,3 @@ class JSONRPCErrors: if e == None: raise JSONRPCUnhandledErrorException(code) return e(v) - - -class InvalidJSONRPCError(ValueError): - pass diff --git a/jsonrpc_std/parse.py b/jsonrpc_std/parse.py @@ -22,6 +22,8 @@ def jsonrpc_validate_dict(o): method = o.get('method') if method == None: raise JSONRPCParseError('missing method field') + elif type(method).__name__ != 'str': + raise JSONRPCInvalidRequestError('method must be str') params = o.get('params') if params == None: @@ -44,11 +46,12 @@ def jsonrpc_from_str(s): def jsonrpc_from_dict(o): - o = jsonrpc_validate_dict(o) - req = jsonrpc_request(o['method'], request_id=o['id']) - req['params'] = o['params'] + o_parsed = jsonrpc_validate_dict(o) + req = jsonrpc_request(o_parsed['method'], request_id=o_parsed['id']) + req['params'] = o_parsed['params'] return req + def jsonrpc_from_file(f): o = json.load(f) return jsonrpc_from_dict(o) diff --git a/setup.cfg b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = jsonrpc_std -version = 0.0.1a1 +version = 0.0.1a2 description = Pure python standard library JSONRPC data interface author = Louis Holbrook author_email = dev@holbrook.no diff --git a/tests/test_error.py b/tests/test_error.py @@ -1,5 +1,6 @@ # standard imports import unittest +import json # local imports from jsonrpc_std.error import ( @@ -68,5 +69,14 @@ class TestError(unittest.TestCase): print('e {}'.format(o)) + def test_error_serialize(self): + e = JSONRPCParseError('foo', request_id='bar') + o = dict(e) + self.assertEqual(o['jsonrpc'], '2.0') + self.assertEqual(o['id'], 'bar') + self.assertEqual(o['error']['code'], -32700) + self.assertEqual(o['error']['message'], 'Parse error: foo') + + if __name__ == '__main__': unittest.main() diff --git a/tests/test_parse.py b/tests/test_parse.py @@ -0,0 +1,113 @@ +# standard imports +import unittest +import io + +# local imports +from jsonrpc_std.parse import * +from jsonrpc_std.error import ( + JSONRPCParseError, + ) + + +class TestParse(unittest.TestCase): + + + def setUp(self): + self.valid_o = { + 'jsonrpc': '2.0', + 'id': 42, + 'method': 'foo_bazBaz', + 'params': [13, { + 'xyzzy': 666, + 'inky': ['pinky', 'blinky', 'clyde'], + }, + ], + } + + def test_from_dict(self): + r = jsonrpc_from_dict(self.valid_o) + self.assertEqual(r['id'], self.valid_o['id']) + self.assertEqual(r['params'], self.valid_o['params']) + self.assertEqual(r['method'], self.valid_o['method']) + + s = json.dumps(self.valid_o) + r = jsonrpc_from_str(s) + self.assertEqual(r['id'], self.valid_o['id']) + self.assertEqual(r['params'], self.valid_o['params']) + self.assertEqual(r['method'], self.valid_o['method']) + + r = jsonrpc_from_file(io.BytesIO(s.encode('utf-8'))) + self.assertEqual(r['id'], self.valid_o['id']) + self.assertEqual(r['params'], self.valid_o['params']) + self.assertEqual(r['method'], self.valid_o['method']) + + + + def test_missing_version(self): + o = self.valid_o + del o['jsonrpc'] + with self.assertRaises(JSONRPCParseError): + jsonrpc_from_dict(o) + + + def test_id(self): + o = self.valid_o + del o['id'] + with self.assertRaises(JSONRPCParseError): + jsonrpc_from_dict(o) + + o['id'] = None + with self.assertRaises(JSONRPCParseError): + jsonrpc_from_dict(o) + + o['id'] = {} + with self.assertRaises(JSONRPCInvalidRequestError): + jsonrpc_from_dict(o) + + o['id'] = JSONRPCBase() + with self.assertRaises(JSONRPCInvalidRequestError): + jsonrpc_from_dict(o) + + + def test_method(self): + o = self.valid_o + del o['method'] + + with self.assertRaises(JSONRPCParseError): + jsonrpc_from_dict(o) + + o['method'] = None + with self.assertRaises(JSONRPCParseError): + jsonrpc_from_dict(o) + + o['method'] = 42 + with self.assertRaises(JSONRPCInvalidRequestError): + jsonrpc_from_dict(o) + + + o['method'] = {} + with self.assertRaises(JSONRPCInvalidRequestError): + jsonrpc_from_dict(o) + + o['method'] = JSONRPCBase() + with self.assertRaises(JSONRPCInvalidRequestError): + jsonrpc_from_dict(o) + + def test_params(self): + o = self.valid_o + del o['params'] + + with self.assertRaises(JSONRPCParseError): + jsonrpc_from_dict(o) + + o['params'] = None + with self.assertRaises(JSONRPCParseError): + jsonrpc_from_dict(o) + + o['params'] = {} + with self.assertRaises(JSONRPCParseError): + jsonrpc_from_dict(o) + + +if __name__ == '__main__': + unittest.main()