1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
# -*- coding: utf-8 -*-
"""async_upnp_client.exceptions module."""
import asyncio
from enum import IntEnum
from typing import Any, Optional
from xml.etree import ElementTree as ET
import aiohttp
# pylint: disable=too-many-ancestors
class UpnpError(Exception):
"""Base class for all errors raised by this library."""
def __init__(
self, *args: Any, message: Optional[str] = None, **_kwargs: Any
) -> None:
"""Initialize base UpnpError."""
super().__init__(*args, message)
class UpnpContentError(UpnpError):
"""Content of UPnP response is invalid."""
class UpnpActionErrorCode(IntEnum):
"""Error codes for UPnP Action errors."""
INVALID_ACTION = 401
INVALID_ARGS = 402
# (DO_NOT_USE) = 403
ACTION_FAILED = 501
ARGUMENT_VALUE_INVALID = 600
ARGUMENT_VALUE_OUT_OF_RANGE = 601
OPTIONAL_ACTION_NOT_IMPLEMENTED = 602
OUT_OF_MEMORY = 603
HUMAN_INTERVENTION_REQUIRED = 604
STRING_ARGUMENT_TOO_LONG = 605
class UpnpActionError(UpnpError):
"""Server returned a SOAP Fault in response to an Action."""
def __init__(
self,
*args: Any,
error_code: Optional[int] = None,
error_desc: Optional[str] = None,
message: Optional[str] = None,
**kwargs: Any,
) -> None:
"""Initialize from response body."""
if not message:
message = f"Received UPnP error {error_code} ({error_desc})"
super().__init__(*args, message=message, **kwargs)
self.error_code = error_code
self.error_desc = error_desc
class UpnpXmlParseError(UpnpContentError, ET.ParseError):
"""UPnP response is not valid XML."""
def __init__(self, orig_err: ET.ParseError) -> None:
"""Initialize from original ParseError, to match it."""
super().__init__(message=str(orig_err))
self.code = orig_err.code
self.position = orig_err.position
class UpnpValueError(UpnpContentError):
"""Invalid value error."""
def __init__(self, name: str, value: Any) -> None:
"""Initialize."""
super().__init__(message=f"Invalid value for {name}: '{value}'")
self.name = name
self.value = value
class UpnpSIDError(UpnpContentError):
"""Missing Subscription Identifier from response."""
class UpnpXmlContentError(UpnpContentError):
"""XML document does not have expected content."""
class UpnpCommunicationError(UpnpError, aiohttp.ClientError):
"""Error occurred while communicating with the UPnP device ."""
class UpnpResponseError(UpnpCommunicationError):
"""HTTP error code returned by the UPnP device."""
def __init__(
self,
*args: Any,
status: int,
headers: Optional[aiohttp.typedefs.LooseHeaders] = None,
message: Optional[str] = None,
**kwargs: Any,
) -> None:
"""Initialize."""
if not message:
message = f"Did not receive HTTP 200 but {status}"
super().__init__(*args, message=message, **kwargs)
self.status = status
self.headers = headers
class UpnpActionResponseError(UpnpActionError, UpnpResponseError):
"""HTTP error code and UPnP error code.
UPnP errors are usually indicated with HTTP 500 (Internal Server Error) and
actual details in the response body as a SOAP Fault.
"""
def __init__( # pylint: disable=too-many-arguments
self,
*args: Any,
status: int,
headers: Optional[aiohttp.typedefs.LooseHeaders] = None,
error_code: Optional[int] = None,
error_desc: Optional[str] = None,
message: Optional[str] = None,
**kwargs: Any,
) -> None:
"""Initialize."""
if not message:
message = (
f"Received HTTP error code {status}, UPnP error code"
f" {error_code} ({error_desc})"
)
super().__init__(
*args,
status=status,
headers=headers,
error_code=error_code,
error_desc=error_desc,
message=message,
**kwargs,
)
class UpnpClientResponseError(aiohttp.ClientResponseError, UpnpResponseError): # type: ignore
"""HTTP response error with more details from aiohttp."""
class UpnpConnectionError(UpnpCommunicationError, aiohttp.ClientConnectionError):
"""Error in the underlying connection to the UPnP device.
This could indicate that the device is offline.
"""
class UpnpConnectionTimeoutError(
UpnpConnectionError, aiohttp.ServerTimeoutError, asyncio.TimeoutError
):
"""Timeout while communicating with the device."""
class UpnpServerError(UpnpError):
"""Error with a local server."""
class UpnpServerOSError(UpnpServerError, OSError):
"""System-related error when starting a local server."""
def __init___(self, errno: int, strerror: str) -> None:
"""Initialize simplified version of OSError."""
OSError.__init__(self, errno, strerror)
|