File: base.py

package info (click to toggle)
python-gabbi 3.0.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 932 kB
  • sloc: python: 3,711; makefile: 60; sh: 32
file content (131 lines) | stat: -rw-r--r-- 4,450 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
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Base classes for response and content handlers."""

from gabbi.exception import GabbiFormatError


class ResponseHandler:
    """Add functionality for making assertions about an HTTP response.

    A subclass may implement two methods: ``action`` and ``preprocess``.

    ``preprocess`` takes one argument, the ``TestCase``. It is called exactly
    once for each test before looping across the assertions. It is used,
    rarely, to copy the ``test.output`` into a useful form (such as a parsed
    DOM).

    ``action`` takes two or three arguments. If ``test_key_value`` is a list
    ``action`` is called with the test case and a single list item. If
    ``test_key_value`` is a dict then ``action`` is called with the test case
    and a key and value pair.
    """

    test_key_suffix = ''
    test_key_value = []

    def __init__(self):
        self._register()

    def __call__(self, test):
        if test.test_data[self._key]:
            self.preprocess(test)
            if not isinstance(
                    test.test_data[self._key], type(self.test_key_value)):
                raise GabbiFormatError(
                    "%s in '%s' has incorrect type, must be %s"
                    % (self._key, test.test_data['name'],
                       type(self.test_key_value)))
            for item in test.test_data[self._key]:
                try:
                    value = test.test_data[self._key][item]
                except (TypeError, KeyError):
                    value = None
                self.action(test, item, value=value)

    def preprocess(self, test):
        """Do any pre-single-test preprocessing."""
        pass

    def action(self, test, item, value=None):
        """Test an individual entry for this response handler.

        If the entry is a key value pair the key is in item and the
        value in value. Otherwise the entry is considered a single item
        from a list.
        """
        pass

    def is_regex(self, value):
        """Check if the value is formatted to looks like a regular expression.

        Meaning it starts and ends with "/".
        """
        return (
            value.startswith('/') and value.endswith('/') and len(value) > 1
        )

    def _register(self):
        """Register this handler on the provided test class."""
        self.response_handler = None
        self.content_handler = None
        if self.test_key_suffix:
            self._key = 'response_%s' % self.test_key_suffix
            self.test_base = {self._key: self.test_key_value}
            self.response_handler = self
        if hasattr(self, 'accepts'):
            self.content_handler = self

    def __eq__(self, other):
        if isinstance(other, ResponseHandler):
            return self.__class__ == other.__class__
        return False

    def __ne__(self, other):
        return not self.__eq__(other)


class ContentHandler(ResponseHandler):
    """A subclass of ResponseHandlers that adds content handling."""

    @staticmethod
    def accepts(content_type):
        """Return True if this handler can handler this type."""
        return False

    @classmethod
    def replacer(cls, response_data, path):
        """Return the string that is replacing RESPONSE."""
        return path

    @staticmethod
    def dumps(data, pretty=False, test=None):
        """Return structured data as a string.

        If pretty is true, prettify.
        """
        return data

    @staticmethod
    def loads(data):
        """Create structured (Python) data from a stream.

        If there is a failure decoding then the handler should
        repackage the error as a gabbi.exception.GabbiDataLoadError.
        """
        return data

    @staticmethod
    def load_data_file(test, file_path):
        """Return the string content of the file specified by the file_path."""
        return test.load_data_file(file_path)