def parse_device_dict(xml_dict: dict) -> Dict: keys = list(xml_dict.keys()) for k in keys: m = XML_ROOT_SANITY_PATTERN.findall(k) if len(m) == 3 and m[1][0] and m[2][5]: schema_key = m[1][0] root = m[2][5] xml_dict = flatten_keys(xml_dict, "{%s}" % schema_key)[root] break result = {} for k, v in xml_dict.items(): if isinstance(xml_dict[k], dict): inner_d = {} for inner_k, inner_v in xml_dict[k].items(): parsed_k = XML_OTHER_KEYS.findall(inner_k) if len(parsed_k) == 2: inner_d[parsed_k[0]] = inner_v else: assert len(parsed_k) == 3 inner_d[parsed_k[1]] = inner_v result[k] = inner_d else: result[k] = v return result
def get_action_list( element_dict: dict ) -> List: # [(<method>, [<input1>, ...], [<output1, ...]), ...] service_info = flatten_keys(element_dict, "{%s}" % SERVICE) if "actionList" in service_info: action_list = service_info["actionList"] else: return [] if not len(action_list): # it could be an empty string return [] result: list = [] if isinstance(action_list["action"], dict): arg_dicts = action_list["action"]['argumentList']['argument'] if not isinstance(arg_dicts, list): # when there is one arg arg_dicts = [arg_dicts] return [[ action_list["action"]['name'], [i['name'] for i in arg_dicts if i['direction'] == 'in'], [i['name'] for i in arg_dicts if i['direction'] == 'out'] ]] for action in action_list["action"]: if not action.get('argumentList'): result.append((action['name'], [], [])) else: arg_dicts = action['argumentList']['argument'] if not isinstance(arg_dicts, list): # when there is one arg arg_dicts = [arg_dicts] result.append( (action['name'], [i['name'] for i in arg_dicts if i['direction'] == 'in'], [i['name'] for i in arg_dicts if i['direction'] == 'out'])) return result
def parse_device_dict(xml_dict: Dict[str, Any]) -> Dict[str, Any]: keys = list(xml_dict.keys()) found = False for k in keys: m: List[Tuple[str, str, str, str, str, str]] = XML_ROOT_SANITY_PATTERN.findall(k) if len(m) == 3 and m[1][0] and m[2][5]: schema_key: str = m[1][0] root: str = m[2][5] flattened = flatten_keys(xml_dict, "{%s}" % schema_key) if root not in flattened: raise UPnPError("root device not found") xml_dict = flattened[root] found = True break if not found: raise UPnPError("device not found") result = {} for k, v in xml_dict.items(): if isinstance(xml_dict[k], dict): inner_d = {} for inner_k, inner_v in xml_dict[k].items(): parsed_k = XML_OTHER_KEYS.findall(inner_k) if len(parsed_k) == 2: inner_d[parsed_k[0]] = inner_v else: assert len(parsed_k) == 3, f"expected len=3, got {len(parsed_k)}" inner_d[parsed_k[1]] = inner_v result[k] = inner_d else: result[k] = v return result
def deserialize_scpd_get_response(content: bytes) -> Dict: if XML_VERSION.encode() in content: parsed = CONTENT_PATTERN.findall(content) content = b'' if not parsed else parsed[0][0] xml_dict = etree_to_dict(ElementTree.fromstring(content.decode())) schema_key = DEVICE root = ROOT for k in xml_dict.keys(): m = XML_ROOT_SANITY_PATTERN.findall(k) if len(m) == 3 and m[1][0] and m[2][5]: schema_key = m[1][0] root = m[2][5] break return flatten_keys(xml_dict, "{%s}" % schema_key)[root] return {}
def deserialize_soap_post_response( response: bytes, method: str, service_id: str) -> typing.Dict[str, typing.Dict[str, str]]: parsed: typing.List[ typing.List[bytes]] = CONTENT_NO_XML_VERSION_PATTERN.findall(response) content = b'' if not parsed else parsed[0][0] content_dict = xml_to_dict(content.decode()) envelope = content_dict[ENVELOPE] if not isinstance(envelope[BODY], dict): # raise UPnPError('blank response') return {} # TODO: raise response_body: typing.Dict[str, typing.Dict[str, typing.Dict[ str, str]]] = flatten_keys(envelope[BODY], f"{'{' + service_id + '}'}") if not response_body: # raise UPnPError('blank response') return {} # TODO: raise if FAULT in response_body: fault: typing.Dict[str, typing.Dict[str, typing.Dict[str, str]]] = flatten_keys( response_body[FAULT], "{%s}" % CONTROL) try: raise UPnPError(fault['detail']['UPnPError']['errorDescription']) except (KeyError, TypeError, ValueError): raise UPnPError( f"Failed to decode error response: {json.dumps(fault)}") response_key = None for key in response_body: if method in key: response_key = key break if not response_key: raise UPnPError( f"unknown response fields for {method}: {response_body}") return response_body[response_key]
def deserialize_soap_post_response(response: bytes, method: str, service_id: str) -> dict: parsed = CONTENT_NO_XML_VERSION_PATTERN.findall(response) content = b'' if not parsed else parsed[0][0] content_dict = etree_to_dict(ElementTree.fromstring(content.decode())) envelope = content_dict[ENVELOPE] response_body = flatten_keys(envelope[BODY], "{%s}" % service_id) body = handle_fault(response_body) # raises UPnPError if there is a fault response_key = None if not body: return {} for key in body: if method in key: response_key = key break if not response_key: raise UPnPError("unknown response fields for %s: %s" % (method, body)) return body[response_key]
def get_action_list( element_dict: typing.Dict[str, typing.Union[str, typing.Dict[ str, str], typing.List[typing.Dict[str, typing.Dict[str, str]]]]] ) -> typing.List[typing.Tuple[str, typing.List[str], typing.List[str]]]: service_info = flatten_keys(element_dict, "{%s}" % SERVICE) result: typing.List[typing.Tuple[str, typing.List[str], typing.List[str]]] = [] if "actionList" in service_info: action_list = service_info["actionList"] else: return result if not len(action_list): # it could be an empty string return result action = action_list["action"] if isinstance(action, dict): arg_dicts: typing.List[typing.Dict[str, str]] = [] if not isinstance(action['argumentList']['argument'], list): # when there is one arg arg_dicts.extend([action['argumentList']['argument']]) else: arg_dicts.extend(action['argumentList']['argument']) result.append( (action_list["action"]['name'], [i['name'] for i in arg_dicts if i['direction'] == 'in' ], [i['name'] for i in arg_dicts if i['direction'] == 'out'])) return result assert isinstance(action, list) for _action in action: if not _action.get('argumentList'): result.append((_action['name'], [], [])) else: if not isinstance(_action['argumentList']['argument'], list): # when there is one arg arg_dicts = [_action['argumentList']['argument']] else: arg_dicts = _action['argumentList']['argument'] result.append( (_action['name'], [i['name'] for i in arg_dicts if i['direction'] == 'in'], [i['name'] for i in arg_dicts if i['direction'] == 'out'])) return result
def handle_fault(response: dict) -> dict: if FAULT in response: fault = flatten_keys(response[FAULT], "{%s}" % CONTROL) error_description = fault['detail']['UPnPError']['errorDescription'] raise UPnPError(error_description) return response