def add_entity_field(self, parent_node: MultiDict, path: [str, None], param_name: str, field: str): if not path: # we reached the leaf. It's time to save param parent_node.setdefault(param_name, []).append(field) return # it is not the leaf, continue current_include_name, rest_path = self.split_path_to_current_and_rest( path) current_node = parent_node['include'].get(current_include_name) if current_node is None: # entity is not included. Ignore this param and do not save anywhere return self.add_entity_field(current_node, rest_path, param_name, field)
def add_entity(self, parent_node: MultiDict, path: [str, None]): if not path: # The end, we reached the leaf. All the includes have been initialized with empty dicts return current_include_name, rest_path = self.split_path_to_current_and_rest( path) current_node = parent_node.setdefault('include', MultiDict()).setdefault( current_include_name, MultiDict()) self.add_entity(current_node, rest_path)
class ServerProxy(object): __slots__ = 'client', 'url', 'loop', 'headers', 'encoding' USER_AGENT = u'aiohttp XML-RPC client (Python: {0}, version: {1})'.format(__pyversion__, __version__) def __init__(self, url, client=None, headers=None, encoding=None, **kwargs): self.headers = MultiDict(headers or {}) self.headers.setdefault('Content-Type', 'text/xml') self.headers.setdefault('User-Agent', self.USER_AGENT) self.encoding = encoding self.url = str(url) self.client = client or aiohttp.client.ClientSession(**kwargs) @staticmethod def _make_request(method_name, *args, **kwargs): root = etree.Element('methodCall') method_el = etree.Element('methodName') method_el.text = method_name root.append(method_el) params_el = etree.Element('params') root.append(params_el) for arg in args: param = etree.Element('param') val = etree.Element('value') param.append(val) params_el.append(param) val.append(py2xml(arg)) if kwargs: param = etree.Element('param') val = etree.Element('value') param.append(val) params_el.append(param) val.append(py2xml(kwargs)) return root @staticmethod def _parse_response(body, method_name): try: if log.getEffectiveLevel() <= logging.DEBUG: log.debug("Server response: \n%s", body.decode()) response = etree.fromstring(body) schema.assertValid(response) except etree.DocumentInvalid: raise ValueError("Invalid body") result = response.xpath('//params/param/value/*') if result: return xml2py(result[0]) fault = response.xpath('//fault/value/*') if fault: err = xml2py(fault[0]) raise xml2py_exception( err.get('faultCode', exceptions.SystemError.code), err.get('faultString', 'Unknown error'), default_exc_class=exceptions.ServerError ) raise exceptions.ParseError('Respond body for method "%s" ' 'not contains any response.', method_name) async def __remote_call(self, method_name, *args, **kwargs): async with self.client.post( str(self.url), data=etree.tostring( self._make_request(method_name, *args, **kwargs), xml_declaration=True, encoding=self.encoding ), headers=self.headers, ) as response: response.raise_for_status() return self._parse_response((await response.read()), method_name) def __getattr__(self, method_name): return self[method_name] def __getitem__(self, method_name): def method(*args, **kwargs): return self.__remote_call(method_name, *args, **kwargs) return method def close(self): return self.client.close()
class ServerProxy(object): __slots__ = ( "client", "url", "loop", "headers", "loads", "dumps", "client_owner", ) USER_AGENT = "aiohttp JSON-RPC client (Python: {0}, version: {1})".format( __pyversion__, __version__, ) def __init__(self, url: typing.Union[str, yarl.URL], client: ClientSessionType = None, loop: asyncio.AbstractEventLoop = None, headers: HeadersType = None, client_owner: bool = True, loads=json.loads, dumps=json.dumps, **kwargs): self.headers = MultiDict(headers or {}) self.headers.setdefault("Content-Type", "application/json") self.headers.setdefault("User-Agent", self.USER_AGENT) self.url = str(url) self.loop = loop or asyncio.get_event_loop() self.client = client or aiohttp.client.ClientSession(loop=self.loop, **kwargs) self.client_owner = bool(client_owner) self.loads = loads self.dumps = dumps @staticmethod def _parse_response(response): log.debug("Server response: \n%r", response) if "error" in response: error = response["error"] if not isinstance(error, dict): raise Exception else: raise json2py_exception( error.get("code", exceptions.SystemError.code), error.get("message", "Unknown error"), default_exc_class=exceptions.ServerError, ) return response.get("result") async def __remote_call(self, json_request): request = py2json(json_request) response = await self.client.post( str(self.url), headers=self.headers, data=self.dumps(request), ) response.raise_for_status() if "id" not in request: # Notification return return self._parse_response( self.loads((await response.read()).decode()), ) async def __call__(self, *prepared_methods, return_exceptions=True): request = [] request_indecies = [] for req in prepared_methods: if isinstance(req, Method): req = req.prepare() if isinstance(req, Notification): req = req.prepare() request_indecies.append(req.get("id")) request.append(req) response = await self.client.post( str(self.url), headers=self.headers, data=self.dumps(py2json(request)), ) response.raise_for_status() responses = {} data = self.loads((await response.read()).decode()) for response in data: req_id = response.get("id") if not req_id: continue try: responses[req_id] = self._parse_response(response) except Exception as e: if return_exceptions: responses[req_id] = e continue raise result = [] for req_id in request_indecies: if req_id is None: result.append(None) continue result.append(responses[req_id]) return result def __getattr__(self, method_name) -> Method: return self[method_name] def __getitem__(self, method_name) -> Method: return Method(method_name, self.__remote_call) def create_notification(self, method): return Notification(method, self.__remote_call) async def close(self, force=False): if not self.client_owner and not force: return return await self.client.close() async def __aenter__(self): return self async def __aexit__(self, exc_type, exc_val, exc_tb): if self.client.closed: return await self.close()
class ServerProxy(object): __slots__ = "client", "url", "loop", "headers", "encoding", "huge_tree" USER_AGENT = ("aiohttp XML-RPC client " "(Python: {0}, version: {1})").format( __pyversion__, __version__) def __init__(self, url, client=None, headers=None, encoding=None, huge_tree=False, **kwargs): self.headers = MultiDict(headers or {}) self.headers.setdefault("Content-Type", "text/xml") self.headers.setdefault("User-Agent", self.USER_AGENT) self.encoding = encoding self.huge_tree = huge_tree self.url = str(url) self.client = client or aiohttp.client.ClientSession(**kwargs) @staticmethod def _make_request(method_name, *args, **kwargs): root = etree.Element("methodCall") method_el = etree.Element("methodName") method_el.text = method_name root.append(method_el) params_el = etree.Element("params") root.append(params_el) for arg in args: param = etree.Element("param") val = etree.Element("value") param.append(val) params_el.append(param) val.append(py2xml(arg)) if kwargs: param = etree.Element("param") val = etree.Element("value") param.append(val) params_el.append(param) val.append(py2xml(kwargs)) return root def _parse_response(self, body, method_name): try: if log.getEffectiveLevel() <= logging.DEBUG: log.debug("Server response: \n%s", body.decode()) parser = etree.XMLParser(huge_tree=self.huge_tree) response = etree.fromstring(body, parser) schema.assertValid(response) except etree.DocumentInvalid: raise ValueError("Invalid body") result = response.xpath("//params/param/value") if result: if len(result) < 2: return xml2py(result[0]) return [xml2py(item) for item in result] fault = response.xpath("//fault/value") if fault: err = xml2py(fault[0]) raise xml2py_exception( err.get("faultCode", exceptions.SystemError.code), err.get("faultString", "Unknown error"), default_exc_class=exceptions.ServerError, ) raise exceptions.ParseError( 'Respond body for method "%s" ' "not contains any response.", method_name, ) async def __remote_call(self, method_name, *args, **kwargs): async with self.client.post( str(self.url), data=etree.tostring( self._make_request(method_name, *args, **kwargs), xml_declaration=True, encoding=self.encoding, ), headers=self.headers, ) as response: response.raise_for_status() return self._parse_response((await response.read()), method_name) def __getattr__(self, method_name): # Trick to keep the "close" method available if method_name == "close": return self.__close else: # Magic method dispatcher return _Method(self.__remote_call, method_name) def __aenter__(self): return self.client.__aenter__() def __aexit__(self, exc_type, exc_val, exc_tb): return self.client.__aexit__(exc_type, exc_val, exc_tb) def __close(self): return self.client.close()
class ServerProxy(object): __slots__ = 'client', 'url', 'loop', 'headers', 'loads', 'dumps' USER_AGENT = u'aiohttp JSON-RPC client (Python: {0}, version: {1})'.format(__pyversion__, __version__) def __init__(self, url, client=None, loop=None, headers=None, loads=json.loads, dumps=json.dumps, **kwargs): self.headers = MultiDict(headers or {}) self.headers.setdefault('Content-Type', 'application/json') self.headers.setdefault('User-Agent', self.USER_AGENT) self.url = str(url) self.loop = loop or asyncio.get_event_loop() self.client = client or aiohttp.client.ClientSession(loop=self.loop, **kwargs) self.loads = loads self.dumps = dumps @staticmethod def _parse_response(response): log.debug("Server response: \n%r", response) if 'error' in response: error = response['error'] if not isinstance(error, dict): raise Exception else: raise json2py_exception( error.get('code', exceptions.SystemError.code), error.get('message', 'Unknown error'), default_exc_class=exceptions.ServerError ) return response.get('result') @asyncio.coroutine def __remote_call(self, json_request): response = yield from self.client.post( str(self.url), headers=self.headers, data=self.dumps(py2json(json_request)), ) response.raise_for_status() return self._parse_response( self.loads((yield from response.read()).decode()) ) @asyncio.coroutine def _batch_call(self, prepared_methods): request = [] for idx, req in enumerate(prepared_methods): if isinstance(req, Method): req = req.prepare() req['id'] = idx + 1 request.append(req) response = yield from self.client.post( str(self.url), headers=self.headers, data=self.dumps(py2json(request)), ) response.raise_for_status() responses = [] data = self.loads((yield from response.read()).decode()) for response in data: try: responses.append(self._parse_response(response)) except Exception as e: responses.append(e) return responses def __getattr__(self, method_name) -> Method: return self[method_name] def __getitem__(self, method_name) -> Method: return Method(method_name, self.__remote_call) def close(self): return self.client.close()