8000 Merge pull request #84 from dahlia/rpc-client-exceptions · nirum-lang/nirum-python@4bd317d · GitHub
[go: up one dir, main page]

Skip to content

Commit 4bd317d

Browse files
authored
Merge pull request #84 from dahlia/rpc-client-exceptions
Make Client to process method error types properly
2 parents a207230 + f2dde2d commit 4bd317d

File tree

4 files changed

+42
-26
lines changed

4 files changed

+42
-26
lines changed

CHANGES.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,13 @@ Version 0.5.1
77
To be released.
88

99
- Added Python 3.6 support.
10+
- Fixed a bug that service client methods hadn't raised the proper error
11+
type but ``nirum.exc.UnexpectedNirumResponseError`` instead. [`#71`_]
1012
- Wheel distributions (``nirum-*.whl``) are now universal between Python 2
1113
and 3. [`#78`_]
14+
- ``nirum.rpc.Service`` had been an old-style class on Python 2, but now
15+
it became a new-style class also on Python 2. (As Python 3 has only new-style
16+
class, there's no change on Python 3.) [`#83`_]
1217
- ``nirum.rpc.Client`` and its subtype became to raise ``TypeError`` with
1318
a better error message when its ``make_request()`` method is overridden and
1419
it returns a wrong artity of tuple. [`#80`_]
@@ -17,8 +22,11 @@ To be released.
1722
it returns a wrong artity of tuple. [`#80`_]
1823
- Fixed a bug that ``Client.ping()`` method had always raised ``TypeError``.
1924
[`#80`_]
25+
- Corrected a typo ``Accepts`` on request headers ``Client`` makes to
26+
``Accept``.
2027

2128
.. _#78: https://github.com/spoqa/nirum-python/pull/78
29+
.. _#83: https://github.com/spoqa/nirum-python/issues/83
2230
.. _#80: https://github.com/spoqa/nirum-python/pull/80
2331

2432

nirum/rpc.py

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
]
3333

3434

35-
class Service:
35+
class Service(object):
3636
"""Nirum RPC service."""
3737

3838
__nirum_service_methods__ = {}
@@ -320,16 +320,37 @@ def __init__(self, url, opener=urllib.request.build_opener()):
320320
self.opener = opener
321321

322322
def ping(self):
323-
r = self.do_request(urllib.parse.urljoin(self.url, './ping/'), {})
324-
return json.loads(r) == 'Ok'
323+
status, _, __ = self.do_request(
324+
urllib.parse.urljoin(self.url, './ping/'),
325+
{}
326+
)
327+
return 200 <= status < 300
325328

326329
def remote_call(self, method_name, payload={}):
327330
qs = urllib.parse.urlencode({'method': method_name})
328331
scheme, netloc, path, _, _ = urllib.parse.urlsplit(self.url)
329332
request_url = urllib.parse.urlunsplit((
330333
scheme, netloc, path, qs, ''
331334
))
332-
return self.do_request(request_url, payload)
335+
status, headers, content = self.do_request(request_url, payload)
336+
content_type = headers.get('Content-Type', '').split(';', 1)[0].strip()
337+
if content_type == 'application/json':
338+
text = content.decode('utf-8')
339+
if 200 <= status < 300:
340+
return text
341+
elif 400 <= status < 500:
342+
error_types = getattr(type(self),
343+
'__nirum_method_error_types__',
344+
{})
345+
try:
346+
error_type = error_types[method_name]
347+
except KeyError:
348+
pass
349+
else:
350+
error_data = json.loads(text)
351+
raise deserialize_meta(error_type, error_data)
352+
raise UnexpectedNirumResponseError(text)
353+
raise UnexpectedNirumResponseError(repr(text))
333354

334355
def make_request(self, method, request_url, headers, payload):
335356
return (
@@ -342,7 +363,7 @@ def do_request(self, request_url, payload):
342363
request_url,
343364
[
344365
('Content-type', 'application/json;charset=utf-8'),
345-
('Accepts', 'application/json'),
366+
('Accept', 'application/json'),
346367
],
347368
payload
348369
)
@@ -394,11 +415,7 @@ def do_request(self, request_url, payload):
394415
for header_name, header_content in headers:
395416
request.add_header(header_name, header_content)
396417
response = self.opener.open(request, None)
397-
response_text = response.read().decode('utf-8')
398-
if 200 <= response.code < 300:
399-
return response_text
400-
else:
401-
raise UnexpectedNirumResponseError(response_text)
418+
return response.code, response.headers, response.read()
402419

403420

404421
# To eliminate imported vars from being overridden by

nirum/test.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import email
12
import socket
23

34
from six import PY3
@@ -18,6 +19,9 @@ class MockHttpResponse(HTTPResponse):
1819
def __init__(self, body, status_code):
1920
self.body = body
2021
self.code = status_code
22+
self.headers = email.message_from_string(
23+
'Content-Type: application/json\n'
24+
)
2125
if PY3:
2226
self.status = status_code
2327

tests/rpc_test.py

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import contextlib
21
import json
32

43
from pytest import fixture, raises, mark
@@ -8,8 +7,7 @@
87

98
from .nirum_schema import import_nirum_fixture
109
from nirum.exc import (InvalidNirumServiceMethodTypeError,
11-
InvalidNirumServiceMethodNameError,
12-
UnexpectedNirumResponseError)
10+
InvalidNirumServiceMethodNameError)
1311
from nirum.rpc import Client, WsgiApp
1412
from nirum.test import MockOpener
1513

@@ -354,21 +352,10 @@ def make_request(self, method, request_url, headers, payload):
354352
)
355353

356354

357-
@contextlib.contextmanager
358-
def assert_error(error_type):
359-
try:
360-
yield
361-
except UnexpectedNirumResponseError as e:
362-
response_json = json.loads(str(e))
363-
assert response_json == error_type().__nirum_serialize__()
364-
else:
365-
assert False # MUST error raised
366-
367-
368355
def test_rpc_error_types():
369356
url = u'http://foobar.com/rpc/'
370357
client = nf.MusicServiceClient(url, MockOpener(url, MusicServiceImpl))
371-
with assert_error(nf.Unknown):
358+
with raises(nf.Unknown):
372359
client.get_music_by_artist_name('error')
373-
with assert_error(nf.BadRequest):
360+
with raises(nf.BadRequest):
374361
client.get_music_by_artist_name('adele')

0 commit comments

Comments
 (0)
0