Skip to content

Commit e17c094

Browse files
authored
Replace Response class with a NamedTuple (#141)
Also removes convert_camel_case option, and rename dispatch's "context" param to "extra".
1 parent 04bfd1d commit e17c094

File tree

8 files changed

+177
-346
lines changed

8 files changed

+177
-346
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# jsonrpcserver Change Log
22

3+
## 5.0.0 (Coming Soon)
4+
5+
- Methods now take a "context" as the first param. It includes the request
6+
object, plus an "extra" value (None if not passed to dispatch).
7+
- dispatch's context param renamed to "extra". This value is included in the
8+
context object passed to every method.
9+
- Removed "convert camel case" option.
10+
11+
Refactoring/internal changes:
12+
13+
- Changed all classes (Request, Response, Methods) to NamedTuples.
14+
315
## 4.2.0 (Nov 9, 2020)
416

517
- Add ability to use custom serializer and deserializer ([#125](https://github.com/bcb/jsonrpcserver/pull/125))

doc/api.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,6 @@ below):
116116

117117
Adds log handlers, to log all requests and responses to stderr.
118118

119-
**convert_camel_case**
120-
121-
Attempts to clean up requests before processing, by changing the method and
122-
parameter names to snake case. Default is *False*.
123-
124119
**debug**
125120

126121
If True, more information is included in error responses, such as an exception
@@ -138,7 +133,6 @@ placed in the current or home directory:
138133
```ini
139134
[general]
140135
basic_logging = yes
141-
convert_camel_case = yes
142136
debug = yes
143137
trim_log_values = yes
144138
```

jsonrpcserver/async_dispatcher.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
validate,
2121
)
2222
from .methods import Method, Methods, global_methods, validate_args, lookup
23-
from .request import NOCONTEXT, Request
23+
from .request import Request
2424
from .response import (
2525
BatchResponse,
2626
InvalidJSONResponse,
@@ -69,7 +69,6 @@ async def dispatch_pure(
6969
methods: Methods,
7070
*,
7171
context: Any,
72-
convert_camel_case: bool,
7372
debug: bool,
7473
serialize: Callable,
7574
deserialize: Callable,
@@ -81,9 +80,7 @@ async def dispatch_pure(
8180
except ValidationError as exc:
8281
return InvalidJSONRPCResponse(data=None, debug=debug)
8382
return await call_requests(
84-
create_requests(
85-
deserialized, context=context, convert_camel_case=convert_camel_case
86-
),
83+
create_requests(deserialized, context=context),
8784
methods,
8885
debug=debug,
8986
serialize=serialize,
@@ -96,8 +93,7 @@ async def dispatch(
9693
methods: Optional[Methods] = None,
9794
*,
9895
basic_logging: bool = False,
99-
convert_camel_case: bool = False,
100-
context: Any = NOCONTEXT,
96+
context: Optional[dict] = None,
10197
debug: bool = False,
10298
trim_log_values: bool = False,
10399
serialize: Callable = default_serialize,
@@ -115,7 +111,6 @@ async def dispatch(
115111
methods,
116112
debug=debug,
117113
context=context,
118-
convert_camel_case=convert_camel_case,
119114
serialize=serialize,
120115
deserialize=deserialize,
121116
)

jsonrpcserver/dispatcher.py

Lines changed: 63 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,16 @@
1515
from types import SimpleNamespace
1616
from typing import (
1717
Any,
18+
Callable,
1819
Dict,
1920
Generator,
2021
Iterable,
2122
List,
23+
NamedTuple,
2224
Optional,
2325
Set,
2426
Tuple,
2527
Union,
26-
Callable,
2728
)
2829

2930
from apply_defaults import apply_config # type: ignore
@@ -33,7 +34,7 @@
3334

3435
from .log import log_
3536
from .methods import Method, Methods, global_methods, validate_args, lookup
36-
from .request import NOCONTEXT, Request
37+
from .request import Request, is_notification, NOID
3738
from .response import (
3839
ApiErrorResponse,
3940
BatchResponse,
@@ -63,6 +64,11 @@
6364
config = ConfigParser(default_section="dispatch")
6465
config.read([".jsonrpcserverrc", os.path.expanduser("~/.jsonrpcserverrc")])
6566

67+
Context = NamedTuple(
68+
"Context",
69+
[("request", Request), ("extra", Any)],
70+
)
71+
6672

6773
def add_handlers() -> Tuple[logging.Handler, logging.Handler]:
6874
# Request handler
@@ -159,12 +165,12 @@ def handle_exceptions(request: Request, debug: bool) -> Generator:
159165
logging.exception(exc)
160166
handler.response = ExceptionResponse(exc, id=request.id, debug=debug)
161167
finally:
162-
if request.is_notification:
168+
if is_notification(request):
163169
handler.response = NotificationResponse()
164170

165171

166172
def safe_call(
167-
request: Request, methods: Methods, *, debug: bool, serialize: Callable
173+
request: Request, methods: Methods, *, debug: bool, extra: Any, serialize: Callable
168174
) -> Response:
169175
"""
170176
Call a Request, catching exceptions to ensure we always return a Response.
@@ -179,7 +185,17 @@ def safe_call(
179185
A Response object.
180186
"""
181187
with handle_exceptions(request, debug) as handler:
182-
result = call(lookup(methods, request.method), *request.args, **request.kwargs)
188+
if isinstance(request.params, list):
189+
result = call(
190+
lookup(methods, request.method),
191+
*([Context(request=request, extra=extra)] + request.params),
192+
)
193+
else:
194+
result = call(
195+
lookup(methods, request.method),
196+
Context(request=request, extra=extra),
197+
**request.params,
198+
)
183199
# Ensure value returned from the method is JSON-serializable. If not,
184200
# handle_exception will set handler.response to an ExceptionResponse
185201
serialize(result)
@@ -192,6 +208,8 @@ def safe_call(
192208
def call_requests(
193209
requests: Union[Request, Iterable[Request]],
194210
methods: Methods,
211+
*,
212+
extra: Any,
195213
debug: bool,
196214
serialize: Callable,
197215
) -> Response:
@@ -204,44 +222,59 @@ def call_requests(
204222
debug: Include more information in error responses.
205223
serialize: Function that is used to serialize data.
206224
"""
207-
if isinstance(requests, Iterable):
208-
return BatchResponse(
209-
[safe_call(r, methods, debug=debug, serialize=serialize) for r in requests],
225+
return (
226+
BatchResponse(
227+
[
228+
safe_call(
229+
r, methods=methods, debug=debug, extra=extra, serialize=serialize
230+
)
231+
for r in requests
232+
],
210233
serialize_func=serialize,
211234
)
212-
return safe_call(requests, methods, debug=debug, serialize=serialize)
235+
if isinstance(requests, list)
236+
else safe_call(
237+
requests, methods=methods, debug=debug, extra=extra, serialize=serialize
238+
)
239+
)
213240

214241

215242
def create_requests(
216-
requests: Union[Dict, List], *, context: Any = NOCONTEXT, convert_camel_case: bool
243+
requests: Union[Dict, List[Dict]],
217244
) -> Union[Request, Set[Request]]:
218245
"""
219-
Create a Request object from a dictionary (or list of them).
246+
Converts a raw deserialized request dictionary to a Request (namedtuple).
220247
221248
Args:
222-
requests: Request object, or a collection of them.
223-
methods: The list of methods that can be called.
224-
context: If specified, will be the first positional argument in all requests.
225-
convert_camel_case: Will convert the method name/any named params to snake case.
249+
requests: Request dict, or a list of dicts.
226250
227251
Returns:
228-
A Request object, or a collection of them.
252+
A Request object, or a list of them.
229253
"""
230-
if isinstance(requests, list):
231-
return {
232-
Request(context=context, convert_camel_case=convert_camel_case, **request)
254+
return (
255+
[
256+
Request(
257+
method=request["method"],
258+
params=request.get("params", []),
259+
id=request.get("id", NOID),
260+
)
233261
for request in requests
234-
}
235-
return Request(context=context, convert_camel_case=convert_camel_case, **requests)
262+
]
263+
if isinstance(requests, list)
264+
else Request(
265+
method=requests["method"],
266+
params=requests.get("params", []),
267+
id=requests.get("id", NOID),
268+
)
269+
)
236270

237271

238272
def dispatch_pure(
239273
request: str,
240274
methods: Methods,
241275
*,
242-
context: Any,
243-
convert_camel_case: bool,
244276
debug: bool,
277+
extra: Any,
245278
serialize: Callable,
246279
deserialize: Callable,
247280
) -> Response:
@@ -255,9 +288,8 @@ def dispatch_pure(
255288
Args:
256289
request: The incoming request string.
257290
methods: Collection of methods that can be called.
258-
context: If specified, will be the first positional argument in all requests.
259-
convert_camel_case: Will convert the method name/any named params to snake case.
260291
debug: Include more information in error responses.
292+
extra: Will be included in the context dictionary passed to methods.
261293
serialize: Function that is used to serialize data.
262294
deserialize: Function that is used to deserialize data.
263295
Returns:
@@ -270,10 +302,9 @@ def dispatch_pure(
270302
except ValidationError as exc:
271303
return InvalidJSONRPCResponse(data=None, debug=debug)
272304
return call_requests(
273-
create_requests(
274-
deserialized, context=context, convert_camel_case=convert_camel_case
275-
),
276-
methods,
305+
create_requests(deserialized),
306+
methods=methods,
307+
extra=extra,
277308
debug=debug,
278309
serialize=serialize,
279310
)
@@ -285,8 +316,7 @@ def dispatch(
285316
methods: Optional[Methods] = None,
286317
*,
287318
basic_logging: bool = False,
288-
convert_camel_case: bool = False,
289-
context: Any = NOCONTEXT,
319+
extra: Optional[dict] = None,
290320
debug: bool = False,
291321
trim_log_values: bool = False,
292322
serialize: Callable = default_serialize,
@@ -303,9 +333,7 @@ def dispatch(
303333
request: The incoming request string.
304334
methods: Collection of methods that can be called. If not passed, uses the
305335
internal methods object.
306-
context: If specified, will be the first positional argument in all requests.
307-
convert_camel_case: Convert keys in params dictionary from camel case to snake
308-
case.
336+
extra: Extra data available inside methods (as context.extra).
309337
debug: Include more information in error responses.
310338
trim_log_values: Show abbreviated requests and responses in log.
311339
serialize: Function that is used to serialize data.
@@ -327,8 +355,7 @@ def dispatch(
327355
request,
328356
methods,
329357
debug=debug,
330-
context=context,
331-
convert_camel_case=convert_camel_case,
358+
extra=extra,
332359
serialize=serialize,
333360
deserialize=deserialize,
334361
)

0 commit comments

Comments
 (0)