summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Marshall <catchjosh@gmail.com>2021-03-30 12:32:11 +0900
committerJosh Marshall <catchjosh@gmail.com>2021-03-30 12:32:11 +0900
commit0cf6f80b517bc0e7f0539cd21516fcb7118e2220 (patch)
treecf9150928bce61a05beb4066d8cd546cc4c82f4d
parent73f252aaceab9bb28a62d1d5ba2967cc455c4068 (diff)
downloadjsonrpclib-0cf6f80b517bc0e7f0539cd21516fcb7118e2220.tar.gz
Removing Python 2 fallbacks, tweaking test runners, fixing flake8 errors.
-rw-r--r--dev-requirements.txt14
-rw-r--r--jsonrpclib/SimpleJSONRPCServer.py62
-rw-r--r--jsonrpclib/__init__.py10
-rw-r--r--jsonrpclib/jsonclass.py11
-rw-r--r--jsonrpclib/jsonrpc.py106
-rw-r--r--tests.py71
6 files changed, 115 insertions, 159 deletions
diff --git a/dev-requirements.txt b/dev-requirements.txt
index c1c28fa..a75fca4 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -1,11 +1,3 @@
-coverage==4.4
-linecache2==1.0.0
-nose==1.3.7
-pluggy==0.4.0
-py==1.4.33
-six==1.10.0
-tox==2.7.0
-traceback2==1.4.0
-unittest2==1.1.0
-virtualenv==15.1.0
-wheel==0.29.0
+coverage==5.5
+flake8==3.9.0
+pytest==6.2.2
diff --git a/jsonrpclib/SimpleJSONRPCServer.py b/jsonrpclib/SimpleJSONRPCServer.py
index 708c5d2..5addcf0 100644
--- a/jsonrpclib/SimpleJSONRPCServer.py
+++ b/jsonrpclib/SimpleJSONRPCServer.py
@@ -1,27 +1,21 @@
-import jsonrpclib
-from jsonrpclib import Fault
-from jsonrpclib.jsonrpc import USE_UNIX_SOCKETS
-try:
- import xmlrpc.server as SimpleXMLRPCServer # Python 3.x
- import socketserver as SocketServer
-except ImportError:
- import SimpleXMLRPCServer # Python 2.7
- import SocketServer
-import socket
import logging
import os
-import traceback
+import socket
+import socketserver
import sys
+import traceback
+import xmlrpc.server
+
try:
import fcntl
except ImportError:
# For Windows
fcntl = None
-try:
- basestring # Python 2.7
-except NameError:
- basestring = str # Python 3.x
+import jsonrpclib
+from jsonrpclib import Fault
+from jsonrpclib.jsonrpc import USE_UNIX_SOCKETS
+
def get_version(request):
# must be a dict
@@ -46,7 +40,7 @@ def validate_request(request):
request.setdefault('params', [])
method = request.get('method', None)
params = request.get('params')
- if not method or not isinstance(method, basestring) or \
+ if not method or not isinstance(method, str) or \
not isinstance(params, (list, dict, tuple)):
fault = Fault(
-32600, 'Invalid request parameters or method.', rpcid=rpcid
@@ -55,10 +49,10 @@ def validate_request(request):
return True
-class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
+class SimpleJSONRPCDispatcher(xmlrpc.server.SimpleXMLRPCDispatcher):
def __init__(self, encoding=None):
- SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(
+ xmlrpc.server.SimpleXMLRPCDispatcher.__init__(
self, allow_none=True, encoding=encoding)
def _marshaled_dispatch(self, data, dispatch_method=None):
@@ -103,7 +97,7 @@ class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
params = request.get('params')
try:
response = self._dispatch(method, params)
- except:
+ except Exception:
exc_type, exc_value, exc_tb = sys.exc_info()
fault = Fault(-32603, '%s:%s' % (exc_type, exc_value))
return fault.response()
@@ -116,7 +110,7 @@ class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
rpcid=request['id']
)
return response
- except:
+ except Exception:
exc_type, exc_value, exc_tb = sys.exc_info()
fault = Fault(-32603, '%s:%s' % (exc_type, exc_value))
return fault.response()
@@ -131,7 +125,7 @@ class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
return self.instance._dispatch(method, params)
else:
try:
- func = SimpleXMLRPCServer.resolve_dotted_attribute(
+ func = xmlrpc.server.resolve_dotted_attribute(
self.instance,
method,
True
@@ -147,7 +141,7 @@ class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
return response
# except TypeError:
# return Fault(-32602, 'Invalid parameters.')
- except:
+ except Exception:
err_lines = traceback.format_exc().splitlines()
trace_string = '%s | %s' % (err_lines[-3], err_lines[-1])
fault = jsonrpclib.Fault(-32603, 'Server error: %s' %
@@ -158,7 +152,7 @@ class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
class SimpleJSONRPCRequestHandler(
- SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
+ xmlrpc.server.SimpleXMLRPCRequestHandler):
def do_POST(self):
if not self.is_rpc_path_valid():
@@ -176,7 +170,7 @@ class SimpleJSONRPCRequestHandler(
data = ''.join(L)
response = self.server._marshaled_dispatch(data)
self.send_response(200)
- except Exception as ex:
+ except Exception:
self.send_response(500)
err_lines = traceback.format_exc().splitlines()
trace_string = '%s | %s' % (err_lines[-3], err_lines[-1])
@@ -195,7 +189,7 @@ class SimpleJSONRPCRequestHandler(
self.connection.shutdown(1)
-class SimpleJSONRPCServer(SocketServer.TCPServer, SimpleJSONRPCDispatcher):
+class SimpleJSONRPCServer(socketserver.TCPServer, SimpleJSONRPCDispatcher):
allow_reuse_address = True
@@ -204,10 +198,8 @@ class SimpleJSONRPCServer(SocketServer.TCPServer, SimpleJSONRPCDispatcher):
address_family=socket.AF_INET):
self.logRequests = logRequests
SimpleJSONRPCDispatcher.__init__(self, encoding)
- # TCPServer.__init__ has an extra parameter on 2.6+, so
- # check Python version and decide on how to call it
- vi = sys.version_info
self.address_family = address_family
+
if USE_UNIX_SOCKETS and address_family == socket.AF_UNIX:
# Unix sockets can't be bound if they already exist in the
# filesystem. The convention of e.g. X11 is to unlink
@@ -217,17 +209,15 @@ class SimpleJSONRPCServer(SocketServer.TCPServer, SimpleJSONRPCDispatcher):
os.unlink(addr)
except OSError:
logging.warning("Could not unlink socket %s", addr)
- # if python 2.5 and lower
- if vi[0] < 3 and vi[1] < 6:
- SocketServer.TCPServer.__init__(self, addr, requestHandler)
- else:
- SocketServer.TCPServer.__init__(
- self, addr, requestHandler, bind_and_activate)
+
+ socketserver.TCPServer.__init__(
+ self, addr, requestHandler, bind_and_activate)
if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'):
flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
flags |= fcntl.FD_CLOEXEC
fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)
+
class CGIJSONRPCRequestHandler(SimpleJSONRPCDispatcher):
def __init__(self, encoding=None):
@@ -235,8 +225,8 @@ class CGIJSONRPCRequestHandler(SimpleJSONRPCDispatcher):
def handle_jsonrpc(self, request_text):
response = self._marshaled_dispatch(request_text)
- print( 'Content-Type: application/json-rpc' )
- print( 'Content-Length: %d' % len(response) )
+ print('Content-Type: application/json-rpc')
+ print('Content-Length: %d' % len(response))
print()
sys.stdout.write(response)
diff --git a/jsonrpclib/__init__.py b/jsonrpclib/__init__.py
index 6e884b8..91dd5f9 100644
--- a/jsonrpclib/__init__.py
+++ b/jsonrpclib/__init__.py
@@ -1,6 +1,12 @@
from jsonrpclib.config import Config
-config = Config.instance()
from jsonrpclib.history import History
-history = History.instance()
from jsonrpclib.jsonrpc import Server, MultiCall, Fault
from jsonrpclib.jsonrpc import ProtocolError, loads, dumps
+
+config = Config.instance()
+history = History.instance()
+
+__all__ = [
+ "config", "Config", "history", "History", "Server", "MultiCall",
+ "Fault", "ProtocolError", "loads", "dumps"
+]
diff --git a/jsonrpclib/jsonclass.py b/jsonrpclib/jsonclass.py
index 31f829d..17e3653 100644
--- a/jsonrpclib/jsonclass.py
+++ b/jsonrpclib/jsonclass.py
@@ -5,12 +5,8 @@ from jsonrpclib import config
iter_types = (dict, list, tuple)
value_types = (bool, )
-try:
- string_types = (basestring, ) # Python 2.7
- numeric_types = (int, long, float)
-except NameError:
- string_types = (str, ) # Python 3.x
- numeric_types = (int, float)
+string_types = (str, )
+numeric_types = (int, float)
supported_types = iter_types+string_types+numeric_types+value_types
invalid_module_chars = r'[^a-zA-Z0-9\_\.]'
@@ -77,7 +73,8 @@ def dump(obj, serialize_method=None, ignore_attribute=None, ignore=[]):
def load(obj):
- if obj is None or isinstance(obj, string_types + numeric_types + value_types):
+ if obj is None or isinstance(
+ obj, string_types + numeric_types + value_types):
return obj
if isinstance(obj, list):
diff --git a/jsonrpclib/jsonrpc.py b/jsonrpclib/jsonrpc.py
index 4861e4a..9eeadcb 100644
--- a/jsonrpclib/jsonrpc.py
+++ b/jsonrpclib/jsonrpc.py
@@ -46,48 +46,28 @@ appropriately.
See http://code.google.com/p/jsonrpclib/ for more info.
"""
-try:
- # Python 3.x
- from xmlrpc.client import Transport as XMLTransport
- from xmlrpc.client import SafeTransport as XMLSafeTransport
- from xmlrpc.client import ServerProxy as XMLServerProxy
- from xmlrpc.client import _Method as XML_Method
-except ImportError:
- # Python 2.7
- from xmlrpclib import Transport as XMLTransport
- from xmlrpclib import SafeTransport as XMLSafeTransport
- from xmlrpclib import ServerProxy as XMLServerProxy
- from xmlrpclib import _Method as XML_Method
-
+from xmlrpc.client import Transport as XMLTransport
+from xmlrpc.client import SafeTransport as XMLSafeTransport
+from xmlrpc.client import ServerProxy as XMLServerProxy
+from xmlrpc.client import _Method as XML_Method
+import json
import string
import random
-try:
- basestring # Python 2.7
-except NameError:
- basestring = str # Python 3.x
+from jsonrpclib import Config
+from jsonrpclib import History
+from http.client import HTTPConnection
+from socket import socket
-# Library includes
-from jsonrpclib import config
-from jsonrpclib import history
+USE_UNIX_SOCKETS = False
-# JSON library importing
-cjson = None
-json = None
try:
- import cjson
+ from socket import AF_UNIX, SOCK_STREAM
+ USE_UNIX_SOCKETS = True
except ImportError:
- try:
- import json
- except ImportError:
- try:
- import simplejson as json
- except ImportError:
- raise ImportError(
- 'You must have the cjson, json, or simplejson ' +
- 'module(s) available.'
- )
+ pass
+
IDCHARS = string.ascii_lowercase+string.digits
@@ -105,20 +85,11 @@ class UnixSocketMissing(Exception):
def jdumps(obj, encoding='utf-8'):
# Do 'serialize' test at some point for other classes
- global cjson
- if cjson:
- return cjson.encode(obj)
- else:
-# return json.dumps(obj, encoding=encoding)
- return json.dumps(obj)
+ return json.dumps(obj)
def jloads(json_string):
- global cjson
- if cjson:
- return cjson.decode(json_string)
- else:
- return json.loads(json_string)
+ return json.loads(json_string)
# XMLRPClib re-implementations
@@ -130,16 +101,15 @@ class ProtocolError(Exception):
class TransportMixIn(object):
""" Just extends the XMLRPC transport where necessary. """
- user_agent = config.user_agent
- # for Python 2.7 support
- _connection = (None, None)
- _extra_headers = []
+ user_agent = Config.instance().user_agent
def send_content(self, connection, request_body):
connection.putheader("Content-Type", "application/json-rpc")
connection.putheader("Content-Length", str(len(request_body)))
connection.endheaders()
if request_body:
+ if type(request_body) == str:
+ request_body = request_body.encode("utf8")
connection.send(request_body)
def getparser(self):
@@ -180,19 +150,6 @@ class SafeTransport(TransportMixIn, XMLSafeTransport):
TransportMixIn.__init__(self)
XMLSafeTransport.__init__(self)
-try:
- from httplib import HTTPConnection
-except ImportError:
- from http.client import HTTPConnection
-from socket import socket
-
-USE_UNIX_SOCKETS = False
-
-try:
- from socket import AF_UNIX, SOCK_STREAM
- USE_UNIX_SOCKETS = True
-except ImportError:
- pass
if (USE_UNIX_SOCKETS):
@@ -219,9 +176,9 @@ class ServerProxy(XMLServerProxy):
try:
from urllib.parse import splittype, splithost # python 3.x
except ImportError:
- from urllib import splittype, splithost
+ from urllib.parse import splittype, splithost
if not version:
- version = config.version
+ version = Config.instance().version
self.__version = version
schema, uri = splittype(uri)
if schema not in ('http', 'https', 'unix'):
@@ -264,7 +221,7 @@ class ServerProxy(XMLServerProxy):
return
def _run_request(self, request, notify=None):
- history.add_request(request)
+ History.instance().add_request(request)
response = self.__transport.request(
self.__host,
@@ -279,7 +236,7 @@ class ServerProxy(XMLServerProxy):
# the response object, or expect the Server to be
# outputting the response appropriately?
- history.add_response(response)
+ History.instance().add_response(response)
if not response:
return None
return_obj = loads(response)
@@ -379,7 +336,6 @@ class MultiCallIterator(object):
def __iter__(self):
for i in range(0, len(self.results)):
yield self[i]
- raise StopIteration
def __getitem__(self, i):
item = self.results[i]
@@ -419,6 +375,7 @@ class MultiCall(object):
__call__ = _request
+
# These lines conform to xmlrpclib's "compatibility" line.
# Not really sure if we should include these, but oh well.
Server = ServerProxy
@@ -437,7 +394,7 @@ class Fault(object):
def response(self, rpcid=None, version=None):
if not version:
- version = config.version
+ version = Config.instance().version
if rpcid:
self.rpcid = rpcid
return dumps(
@@ -458,12 +415,12 @@ def random_id(length=8):
class Payload(dict):
def __init__(self, rpcid=None, version=None):
if not version:
- version = config.version
+ version = Config.instance().version
self.id = rpcid
self.version = float(version)
def request(self, method, params=[]):
- if not isinstance(method, basestring):
+ if not isinstance(method, str):
raise ValueError('Method name must be a string.')
if not self.id:
self.id = random_id()
@@ -508,7 +465,7 @@ def dumps(
the rpcid argument since the 2.0 spec requires it for responses.
"""
if not version:
- version = config.version
+ version = Config.instance().version
if isinstance(methodname, str) and \
not isinstance(params, (tuple, list, dict)) and \
not isinstance(params, Fault):
@@ -532,7 +489,7 @@ def dumps(
'Method name must be a string, or methodresponse must '
'be set to True.')
- if config.use_jsonclass is True:
+ if Config.instance().use_jsonclass is True:
from jsonrpclib import jsonclass
params = jsonclass.dump(params)
if methodresponse is True:
@@ -561,7 +518,7 @@ def loads(data):
# if the above raises an error, the implementing server code
# should return something like the following:
# { 'jsonrpc':'2.0', 'error': fault.error(), id: None }
- if config.use_jsonclass is True:
+ if Config.instance().use_jsonclass is True:
from jsonrpclib import jsonclass
result = jsonclass.load(result)
return result
@@ -576,7 +533,8 @@ def check_for_errors(result):
raise TypeError('Response is not a dict.')
if 'jsonrpc' in result.keys() and float(result['jsonrpc']) > 2.0:
raise NotImplementedError('JSON-RPC version not yet supported.')
- if 'result' not in result.keys() and 'error' not in result.keys():
+ if 'result' not in result.keys() and \
+ 'error' not in result.keys():
raise ValueError('Response does not have a result or error key.')
if 'error' in result.keys() and result['error'] is not None:
code = result['error']['code']
diff --git a/tests.py b/tests.py
index 72d846d..8db665c 100644
--- a/tests.py
+++ b/tests.py
@@ -56,6 +56,10 @@ class TestCompatibility(unittest.TestCase):
self.server = server_set_up(addr=('', self.port))
self.client = Server('http://localhost:%d' % self.port)
+ def tearDown(self):
+ self.server.stop()
+ self.server.join()
+
# v1 tests forthcoming
# Version 2.0 Tests
@@ -287,6 +291,8 @@ class InternalTests(unittest.TestCase):
self.addCleanup(self.cleanup)
def cleanup(self):
+ self.server.stop()
+ self.server.join()
history.size = ORIGINAL_HISTORY_SIZE
history.clear()
@@ -429,37 +435,40 @@ class InternalTests(unittest.TestCase):
result = sub_service_proxy.add(21, 21)
self.assertTrue(result == 42)
-if jsonrpc.USE_UNIX_SOCKETS:
- # We won't do these tests unless Unix Sockets are supported
-
- @unittest.skip("Skipping Unix socket tests right now.")
- class UnixSocketInternalTests(InternalTests):
- """
- These tests run the same internal communication tests,
- but over a Unix socket instead of a TCP socket.
- """
- def setUp(self):
- suffix = "%d.sock" % get_port()
-
- # Open to safer, alternative processes
- # for getting a temp file name...
- temp = tempfile.NamedTemporaryFile(
- suffix=suffix
- )
- self.port = temp.name
- temp.close()
- self.server = server_set_up(
- addr=self.port,
- address_family=socket.AF_UNIX
- )
+@unittest.skipIf(
+ not jsonrpc.USE_UNIX_SOCKETS or "SKIP_UNIX_SOCKET_TESTS" in os.environ,
+ "Skipping Unix socket tests -- unsupported in this environment.")
+class UnixSocketInternalTests(InternalTests):
+ """
+ These tests run the same internal communication tests,
+ but over a Unix socket instead of a TCP socket.
+ """
+ def setUp(self):
+ suffix = "%d.sock" % get_port()
- def get_client(self):
- return Server('unix:/%s' % self.port)
+ # Open to safer, alternative processes
+ # for getting a temp file name...
+ temp = tempfile.NamedTemporaryFile(
+ suffix=suffix
+ )
+ self.port = temp.name
+ temp.close()
- def tearDown(self):
- """ Removes the tempory socket file """
- os.unlink(self.port)
+ self.server = server_set_up(
+ addr=self.port,
+ address_family=socket.AF_UNIX
+ )
+
+ def get_client(self):
+ print(f"Serving on {self.port}")
+ return Server('unix:/%s' % self.port)
+
+ def tearDown(self):
+ """ Removes the tempory socket file """
+ self.server.stop()
+ self.server.join()
+ os.unlink(self.port)
class UnixSocketErrorTests(unittest.TestCase):
@@ -537,7 +546,11 @@ def server_set_up(addr, address_family=socket.AF_INET):
server.register_function(service.summation, 'sum')
server.register_function(service.summation, 'notify_sum')
server.register_function(service.summation, 'namespace.sum')
+
+ def stop():
+ server.shutdown()
+
server_proc = Thread(target=server.serve_forever)
- server_proc.daemon = True
+ server_proc.stop = stop
server_proc.start()
return server_proc