Skip to content

Commit a8a80a9

Browse files
author
Elliot Boschwitz
authored
JSON RPC request class refactor (#368)
Consolidated logic into new Request class and improved PEP8 compliance.
1 parent f627efa commit a8a80a9

File tree

7 files changed

+126
-182
lines changed

7 files changed

+126
-182
lines changed

mssqlcli/jsonrpc/contracts/__init__.py

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,5 @@
22
# Copyright (c) Microsoft Corporation. All rights reserved.
33
# Licensed under the MIT License. See License.txt in the project root for license information.
44
# --------------------------------------------------------------------------------------------
5-
import abc
65

7-
ABC = abc.ABCMeta('ABC', (object,), {}) # compatibile with Python 2 *and* 3.
8-
9-
10-
class Request(ABC):
11-
"""
12-
Abstract request class.
13-
"""
14-
@abc.abstractmethod
15-
def execute(self):
16-
"""
17-
Executes the request.
18-
"""
19-
pass
20-
21-
@abc.abstractmethod
22-
def get_response(self):
23-
"""
24-
Retrieves expected response.
25-
"""
26-
pass
27-
28-
@abc.abstractmethod
29-
def completed(self):
30-
"""
31-
Return state of request.
32-
"""
33-
pass
6+
from mssqlcli.jsonrpc.contracts.request import Request

mssqlcli/jsonrpc/contracts/connectionservice.py

Lines changed: 22 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,46 @@
11
# pylint: disable=too-many-instance-attributes
22
# pylint: disable=too-few-public-methods
33

4-
import logging
54
from mssqlcli.jsonrpc.contracts import Request
65

76

8-
logger = logging.getLogger(u'mssqlcli.connectionservice')
9-
10-
117
class ConnectionRequest(Request):
128
"""
139
SqlToolsService Connection request.
1410
"""
15-
METHOD_NAME = u'connection/connect'
1611

1712
def __init__(self, request_id, owner_uri, json_rpc_client, parameters):
18-
self.request_id = request_id
19-
self.owner_uri = owner_uri
20-
self.finished = False
21-
self.json_rpc_client = json_rpc_client
22-
self.params = ConnectionParams(parameters)
23-
24-
def execute(self):
25-
self.json_rpc_client.submit_request(
26-
self.METHOD_NAME, self.params.format(), self.request_id)
27-
28-
def get_response(self):
29-
"""
30-
Get latest response, event or exception if it occured.
31-
"""
32-
try:
33-
response = self.json_rpc_client.get_response(self.request_id, self.owner_uri)
34-
decoded_response = None
35-
if response:
36-
logger.debug(response)
37-
decoded_response = self.decode_response(response)
38-
39-
if isinstance(decoded_response, ConnectionCompleteEvent):
40-
self.finished = True
41-
self.json_rpc_client.request_finished(self.request_id)
42-
self.json_rpc_client.request_finished(self.owner_uri)
43-
44-
return decoded_response
45-
46-
except Exception as error: # pylint: disable=broad-except
47-
logger.info(str(error))
48-
self.finished = True
49-
self.json_rpc_client.request_finished(self.request_id)
50-
self.json_rpc_client.request_finished(self.owner_uri)
51-
return ConnectionCompleteEvent({
52-
u'params': {
53-
u'ownerUri': self.owner_uri,
54-
u'connectionId': None,
55-
u'messages': str(error),
56-
u'errorMessage': u'Connection request encountered an exception',
57-
u'errorNumber': None
58-
}
59-
})
60-
61-
def completed(self):
62-
"""
63-
Get current request state.
64-
"""
65-
return self.finished
13+
super(ConnectionRequest, self).__init__(request_id, owner_uri, json_rpc_client,
14+
ConnectionParams(parameters),
15+
u'connection/connect',
16+
ConnectionCompleteEvent)
17+
18+
@classmethod
19+
def response_error(cls, error):
20+
return ConnectionCompleteEvent({
21+
u'params': {
22+
u'ownerUri': cls.owner_uri,
23+
u'connectionId': None,
24+
u'messages': str(error),
25+
u'errorMessage': u'Connection request encountered an exception',
26+
u'errorNumber': None
27+
}
28+
})
6629

6730
@staticmethod
68-
def decode_response(obj):
31+
def decode_response(response):
6932
"""
7033
Decode response dictionary into a Connection parameter type.
7134
"""
7235

73-
if u'result' in obj:
74-
return ConnectionResponse(obj)
36+
if u'result' in response:
37+
return ConnectionResponse(response)
7538

76-
if 'method' in obj and obj['method'] == 'connection/complete':
77-
return ConnectionCompleteEvent(obj)
39+
if 'method' in response and response['method'] == 'connection/complete':
40+
return ConnectionCompleteEvent(response)
7841

7942
# Could not decode return st
80-
return obj
43+
return response
8144

8245

8346
class ConnectionDetails:

mssqlcli/jsonrpc/contracts/queryexecutestringservice.py

Lines changed: 18 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -12,51 +12,18 @@ class QueryExecuteStringRequest(Request):
1212
Uses SQL Tools Service query/executeString method.
1313
"""
1414

15-
METHOD_NAME = u'query/executeString'
16-
1715
def __init__(self, request_id, owner_uri, json_rpc_client, parameters):
18-
self.request_id = request_id
19-
self.owner_uri = owner_uri
20-
self.finished = False
21-
self.json_rpc_client = json_rpc_client
22-
self.params = QueryExecuteStringParams(parameters)
23-
24-
def get_response(self):
25-
"""
26-
Get latest response, event or exception if occured.
27-
"""
28-
try:
29-
response = self.json_rpc_client.get_response(self.request_id, self.owner_uri)
30-
31-
decoded_response = None
32-
if response:
33-
decoded_response = QueryExecuteStringRequest.decode_response(response)
34-
35-
if isinstance(decoded_response,
36-
(QueryCompleteEvent, QueryExecuteErrorResponseEvent)):
37-
self.finished = True
38-
self.json_rpc_client.request_finished(self.request_id)
39-
self.json_rpc_client.request_finished(self.owner_uri)
40-
41-
return decoded_response
42-
43-
except Exception as error: # pylint: disable=broad-except
44-
self.finished = True
45-
self.json_rpc_client.request_finished(self.request_id)
46-
self.json_rpc_client.request_finished(self.owner_uri)
47-
return QueryCompleteEvent(
48-
{u'params': None}, exception_message=str(error)
49-
)
50-
51-
def execute(self):
52-
self.json_rpc_client.submit_request(
53-
self.METHOD_NAME, self.params.format(), self.request_id)
54-
55-
def completed(self):
56-
"""
57-
Get current request state.
58-
"""
59-
return self.finished
16+
super(QueryExecuteStringRequest, self).__init__(request_id, owner_uri, json_rpc_client,
17+
QueryExecuteStringParams(parameters),
18+
u'query/executeString',
19+
(QueryCompleteEvent,
20+
QueryExecuteErrorResponseEvent))
21+
22+
@classmethod
23+
def response_error(cls, error):
24+
return QueryCompleteEvent(
25+
{u'params': None}, exception_message=str(error)
26+
)
6027

6128
@staticmethod
6229
def decode_response(response):
@@ -140,44 +107,14 @@ class QuerySubsetRequest(Request):
140107
SqlToolsService QuerySubset Request.
141108
"""
142109

143-
METHOD_NAME = u'query/subset'
144-
145110
def __init__(self, request_id, owner_uri, json_rpc_client, parameters):
146-
self.request_id = request_id
147-
self.owner_uri = owner_uri
148-
self.finished = False
149-
self.json_rpc_client = json_rpc_client
150-
self.params = QuerySubsetParams(parameters)
151-
152-
def completed(self):
153-
"""
154-
Get current request state.
155-
"""
156-
return self.finished
157-
158-
def get_response(self):
159-
try:
160-
response = self.json_rpc_client.get_response(self.request_id, self.owner_uri)
161-
decoded_response = None
162-
if response:
163-
decoded_response = QuerySubsetRequest.decode_response(response)
164-
165-
if isinstance(decoded_response, ResultSubset):
166-
self.finished = True
167-
self.json_rpc_client.request_finished(self.request_id)
168-
self.json_rpc_client.request_finished(self.owner_uri)
169-
170-
return decoded_response
171-
172-
except Exception as error: # pylint: disable=broad-except
173-
self.finished = True
174-
self.json_rpc_client.request_finished(self.request_id)
175-
self.json_rpc_client.request_finished(self.owner_uri)
176-
return ResultSubset(None, error_message=str(error))
177-
178-
def execute(self):
179-
self.json_rpc_client.submit_request(
180-
self.METHOD_NAME, self.params.format(), self.request_id)
111+
super(QuerySubsetRequest, self).__init__(request_id, owner_uri, json_rpc_client,
112+
QuerySubsetParams(parameters),
113+
u'query/subset', ResultSubset)
114+
115+
@classmethod
116+
def response_error(cls, error):
117+
return ResultSubset(None, error_message=str(error))
181118

182119
@staticmethod
183120
def decode_response(response):
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# pylint: disable=too-many-arguments
2+
import logging
3+
import abc
4+
5+
ABC = abc.ABCMeta('ABC', (object,), {}) # compatibile with Python 2 *and* 3.
6+
logger = logging.getLogger(u'mssqlcli.connectionservice')
7+
8+
class Request(ABC):
9+
"""
10+
Abstract request class.
11+
"""
12+
13+
def __init__(self, request_id, owner_uri, json_rpc_client, parameters,
14+
method_name, connectionCompleteEvent):
15+
self.request_id = request_id
16+
self.owner_uri = owner_uri
17+
self.json_rpc_client = json_rpc_client
18+
self.params = parameters
19+
self.method_name = method_name
20+
self.connectionCompleteEvent = connectionCompleteEvent
21+
self.finished = False
22+
23+
@staticmethod
24+
@abc.abstractmethod
25+
def decode_response(response):
26+
"""
27+
Returns decoded response.
28+
"""
29+
pass
30+
31+
@classmethod
32+
@abc.abstractmethod
33+
def response_error(cls, error):
34+
"""
35+
Returns object when response fails.
36+
"""
37+
pass
38+
39+
def execute(self):
40+
"""
41+
Executes the request.
42+
"""
43+
self.json_rpc_client.submit_request(
44+
self.method_name, self.params.format(), self.request_id)
45+
46+
def get_response(self):
47+
"""
48+
Get latest response, event or exception if it occured.
49+
"""
50+
try:
51+
response = self.json_rpc_client.get_response(self.request_id, self.owner_uri)
52+
decoded_response = None
53+
if response:
54+
logger.debug(response)
55+
decoded_response = self.decode_response(response)
56+
57+
if isinstance(decoded_response, self.connectionCompleteEvent):
58+
self.finished = True
59+
self.json_rpc_client.request_finished(self.request_id)
60+
self.json_rpc_client.request_finished(self.owner_uri)
61+
return decoded_response
62+
except Exception as error: # pylint: disable=broad-except
63+
logger.info(str(error))
64+
self.finished = True
65+
self.json_rpc_client.request_finished(self.request_id)
66+
self.json_rpc_client.request_finished(self.owner_uri)
67+
return self.response_error(error)
68+
69+
def completed(self):
70+
"""
71+
Return state of request.
72+
"""
73+
return self.finished

tests/jsonrpc/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
BASELINE_REQUEST = {
2+
u'jsonrpc': u'2.0',
3+
u'params': {
4+
u'Key': u'Value'
5+
},
6+
u'method': u'testMethod/DoThis',
7+
u'id': 1
8+
}

tests/jsonrpc/test_jsonrpc.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import io
77
import unittest
88
import mssqlcli.jsonrpc.jsonrpcclient as jsonrpc
9-
9+
from jsonrpc import BASELINE_REQUEST
1010

1111
class JsonRpcTest(unittest.TestCase):
1212
"""
@@ -42,12 +42,7 @@ def test_basic_request(self):
4242
test_stream.seek(0)
4343
json_rpc_reader = jsonrpc.JsonRpcReader(test_stream)
4444
response = json_rpc_reader.read_response()
45-
baseline = {
46-
u'jsonrpc': u'2.0',
47-
u'params': {
48-
u'Key': u'Value'},
49-
u'method': u'testMethod/DoThis',
50-
u'id': 1}
45+
baseline = BASELINE_REQUEST
5146
self.assertEqual(response, baseline)
5247

5348
json_rpc_reader.close()

tests/jsonrpc/test_jsonrpcclient.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import threading
55
import pytest
66
import mssqlcli.jsonrpc.jsonrpcclient as json_rpc_client
7-
7+
from jsonrpc import BASELINE_REQUEST
88

99
class JsonRpcClientTests(unittest.TestCase):
1010
"""
@@ -306,12 +306,7 @@ def test_get_response_with_id(self):
306306
# Sleeping to give background threads a chance to process response.
307307
time.sleep(1)
308308

309-
baseline = {
310-
u'jsonrpc': u'2.0',
311-
u'params': {
312-
u'Key': u'Value'},
313-
u'method': u'testMethod/DoThis',
314-
u'id': 1}
309+
baseline = BASELINE_REQUEST
315310
response = test_client.get_response(request_id=1)
316311
self.assertEqual(response, baseline)
317312
test_client.shutdown()

0 commit comments

Comments
 (0)