File: _response.py

package info (click to toggle)
python-gvm 26.5.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 5,132 kB
  • sloc: python: 44,662; makefile: 18
file content (115 lines) | stat: -rw-r--r-- 2,806 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
# SPDX-FileCopyrightText: 2024 Greenbone AG
#
# SPDX-License-Identifier: GPL-3.0-or-later

from functools import cached_property
from typing import Optional, TypeVar

from gvm.errors import GvmError
from gvm.xml import Element, parse_xml

from ._request import Request


class StatusError(GvmError):
    """
    The response had an error status

    May be raised when calling `response.raise_for_status()`
    """

    def __init__(self, message: Optional[str], *args, response: "Response"):
        super().__init__(message, *args)
        self.response = response
        self.request = response.request


Self = TypeVar("Self", bound="Response")


class Response:
    """
    A GMP Response
    """

    def __init__(self, *, request: Request, data: bytes) -> None:
        """
        Create a Response object

        Args:
            request: The request corresponding to this response
            data: The data of the response
        """
        self._request = request
        self._data = data
        self.__xml: Optional[Element] = None

    def __root_element(self) -> Element:
        if self.__xml is None:
            self.__xml = self.xml()
        return self.__xml

    def xml(self) -> Element:
        """
        Return the response data as XML Element

        Raises XmlError if the data is not valid XML.
        """
        return parse_xml(self.data)

    @property
    def data(self) -> bytes:
        """
        Return the data of the response as bytes
        """
        return self._data

    @property
    def request(self) -> Request:
        """
        Return the corresponding request of this response
        """
        return self._request

    @cached_property
    def status_code(self) -> Optional[int]:
        """
        The status code of the response

        Returns:
            The status code or None if the response data doesn't contain a valid
            status code.
        """
        root = self.__root_element()
        try:
            status = root.attrib["status"]
            return int(status)
        except (KeyError, ValueError):
            return None

    @property
    def is_success(self) -> bool:
        """
        Returns True if the response contains a success status code
        """
        status = self.status_code
        return status is not None and 200 <= status <= 299

    def raise_for_status(self: Self) -> Self:
        if self.is_success:
            return self
        raise StatusError(
            f"Invalid status code {self.status_code}", response=self
        )

    def __bytes__(self) -> bytes:
        """
        Return the data as bytes
        """
        return self._data

    def __str__(self) -> str:
        """
        Return the data as string
        """
        return self._data.decode()