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 |
