File: exceptions.py

package info (click to toggle)
async-upnp-client 0.44.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,072 kB
  • sloc: python: 11,921; xml: 2,826; sh: 32; makefile: 6
file content (173 lines) | stat: -rw-r--r-- 5,013 bytes parent folder | download
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)