Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/galaxy/util/json.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author | shellac |
---|---|
date | Sat, 02 May 2020 07:14:21 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:26e78fe6e8c4 |
---|---|
1 from __future__ import absolute_import | |
2 | |
3 import collections | |
4 import copy | |
5 import json | |
6 import logging | |
7 import math | |
8 import random | |
9 import string | |
10 | |
11 from six import iteritems, string_types | |
12 | |
13 from ..util import unicodify | |
14 | |
15 __all__ = ("safe_dumps", "validate_jsonrpc_request", "validate_jsonrpc_response", "jsonrpc_request", "jsonrpc_response") | |
16 | |
17 log = logging.getLogger(__name__) | |
18 | |
19 to_json_string = json.dumps | |
20 from_json_string = json.loads | |
21 | |
22 | |
23 def swap_inf_nan(val): | |
24 """ | |
25 This takes an arbitrary object and preps it for jsonifying safely, templating Inf/NaN. | |
26 """ | |
27 if isinstance(val, string_types): | |
28 # basestring first, because it's a sequence and would otherwise get caught below. | |
29 return val | |
30 elif isinstance(val, collections.Sequence): | |
31 return [swap_inf_nan(v) for v in val] | |
32 elif isinstance(val, collections.Mapping): | |
33 return dict([(swap_inf_nan(k), swap_inf_nan(v)) for (k, v) in iteritems(val)]) | |
34 elif isinstance(val, float): | |
35 if math.isnan(val): | |
36 return "__NaN__" | |
37 elif val == float("inf"): | |
38 return "__Infinity__" | |
39 elif val == float("-inf"): | |
40 return "__-Infinity__" | |
41 else: | |
42 return val | |
43 else: | |
44 return val | |
45 | |
46 | |
47 def safe_loads(arg): | |
48 """ | |
49 This is a wrapper around loads that returns the parsed value instead of | |
50 raising a value error. It also avoids autoconversion of non-iterables | |
51 i.e numeric and boolean values. | |
52 """ | |
53 try: | |
54 loaded = json.loads(arg) | |
55 if loaded is not None and not isinstance(loaded, collections.Iterable): | |
56 loaded = arg | |
57 except (TypeError, ValueError): | |
58 loaded = arg | |
59 return loaded | |
60 | |
61 | |
62 def safe_dumps(*args, **kwargs): | |
63 """ | |
64 This is a wrapper around dumps that encodes Infinity and NaN values. It's a | |
65 fairly rare case (which will be low in request volume). Basically, we tell | |
66 json.dumps to blow up if it encounters Infinity/NaN, and we 'fix' it before | |
67 re-encoding. | |
68 """ | |
69 try: | |
70 dumped = json.dumps(*args, allow_nan=False, **kwargs) | |
71 except ValueError: | |
72 obj = swap_inf_nan(copy.deepcopy(args[0])) | |
73 dumped = json.dumps(obj, allow_nan=False, **kwargs) | |
74 if kwargs.get('escape_closing_tags', True): | |
75 return dumped.replace('</', '<\\/') | |
76 return dumped | |
77 | |
78 | |
79 def safe_dumps_formatted(obj): | |
80 """Attempt to format an object for display. | |
81 | |
82 If serialization fails, the object's string representation will be returned instead. | |
83 """ | |
84 try: | |
85 return safe_dumps(obj, sort_keys=True, indent=4, separators=(',', ': ')) | |
86 except TypeError: | |
87 log.warning("JSON serialization failed for object: %s", str(obj)) | |
88 return str(obj) | |
89 | |
90 | |
91 # Methods for handling JSON-RPC | |
92 | |
93 def validate_jsonrpc_request(request, regular_methods, notification_methods): | |
94 try: | |
95 request = json.loads(request) | |
96 except Exception as e: | |
97 return False, request, jsonrpc_response(id=None, | |
98 error=dict(code=-32700, | |
99 message='Parse error', | |
100 data=unicodify(e))) | |
101 try: | |
102 assert 'jsonrpc' in request, \ | |
103 'This server requires JSON-RPC 2.0 and no "jsonrpc" member was sent with the Request object as per the JSON-RPC 2.0 Specification.' | |
104 assert request['jsonrpc'] == '2.0', \ | |
105 'Requested JSON-RPC version "%s" != required version "2.0".' % request['jsonrpc'] | |
106 assert 'method' in request, 'No "method" member was sent with the Request object' | |
107 except AssertionError as e: | |
108 return False, request, jsonrpc_response(request=request, | |
109 error=dict(code=-32600, | |
110 message='Invalid Request', | |
111 data=unicodify(e))) | |
112 try: | |
113 assert request['method'] in (regular_methods + notification_methods) | |
114 except AssertionError: | |
115 return False, request, jsonrpc_response(request=request, | |
116 error=dict(code=-32601, | |
117 message='Method not found', | |
118 data='Valid methods are: %s' % ', '.join(regular_methods + notification_methods))) | |
119 try: | |
120 if request['method'] in regular_methods: | |
121 assert 'id' in request, 'No "id" member was sent with the Request object and the requested method "%s" is not a notification method' % request['method'] | |
122 except AssertionError as e: | |
123 return False, request, jsonrpc_response(request=request, | |
124 error=dict(code=-32600, | |
125 message='Invalid Request', | |
126 data=unicodify(e))) | |
127 return True, request, None | |
128 | |
129 | |
130 def validate_jsonrpc_response(response, id=None): | |
131 try: | |
132 response = json.loads(response) | |
133 except Exception as e: | |
134 log.error('Response was not valid JSON: %s', unicodify(e)) | |
135 log.debug('Response was: %s', response) | |
136 return False, response | |
137 try: | |
138 assert 'jsonrpc' in response, \ | |
139 'This server requires JSON-RPC 2.0 and no "jsonrpc" member was sent with the Response object as per the JSON-RPC 2.0 Specification.' | |
140 assert ('result' in response or 'error' in response), \ | |
141 'Neither of "result" or "error" members were sent with the Response object.' | |
142 if 'error' in response: | |
143 assert int(response['error']['code']), \ | |
144 'The "code" member of the "error" object in the Response is missing or not an integer.' | |
145 assert 'message' in response, \ | |
146 'The "message" member of the "error" object in the Response is missing.' | |
147 except Exception: | |
148 log.exception('Response was not valid JSON-RPC') | |
149 log.debug('Response was: %s' % response) | |
150 return False, response | |
151 if id is not None: | |
152 try: | |
153 assert 'id' in response and response['id'] == id | |
154 except Exception: | |
155 log.error('The response id "%s" does not match the request id "%s"' % (response['id'], id)) | |
156 return False, response | |
157 return True, response | |
158 | |
159 | |
160 def jsonrpc_request(method, params=None, id=None, jsonrpc='2.0'): | |
161 if method is None: | |
162 log.error('jsonrpc_request(): "method" parameter cannot be None') | |
163 return None | |
164 request = dict(jsonrpc=jsonrpc, method=method) | |
165 if params: | |
166 request['params'] = params | |
167 if id is not None and id is True: | |
168 request['id'] = ''.join([random.choice(string.hexdigits) for i in range(16)]) | |
169 elif id is not None: | |
170 request['id'] = id | |
171 return request | |
172 | |
173 | |
174 def jsonrpc_response(request=None, id=None, result=None, error=None, jsonrpc='2.0'): | |
175 if result: | |
176 rval = dict(jsonrpc=jsonrpc, result=result) | |
177 elif error: | |
178 rval = dict(jsonrpc=jsonrpc, error=error) | |
179 else: | |
180 msg = 'jsonrpc_response() called with out a "result" or "error" parameter' | |
181 log.error(msg) | |
182 rval = dict(jsonrpc=jsonrpc, error=msg) | |
183 if id is not None: | |
184 rval['id'] = id | |
185 elif request is not None and 'id' in request: | |
186 rval['id'] = request['id'] | |
187 return rval |