Skip to content

response

scrapli.response

MultiResponse

Bases: ScrapliMultiResponse

Source code in scrapli/response.py
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
class MultiResponse(ScrapliMultiResponse):
    def __init__(self, initlist: Optional[Iterable[Any]] = None) -> None:
        """
        Initialize list of responses

        Args:
            initlist: initial list seed data, if any

        Returns:
            None

        Raises:
            N/A

        """
        super().__init__(initlist=initlist)

        self.data: List[Response]

    def __str__(self) -> str:
        """
        Magic str method for MultiResponse class

        Args:
            N/A

        Returns:
            str: str for class object

        Raises:
            N/A

        """
        return (
            f"{self.__class__.__name__} <Success: {not self.failed}; "
            f"Response Elements: {len(self.data)}>"
        )

    @property
    def host(self) -> str:
        """
        Return the host of the multiresponse

        Args:
            N/A

        Returns:
            str: The host of the associated responses

        Raises:
            N/A

        """
        try:
            response = self.data[0]
        except IndexError:
            return ""
        return response.host

    @property
    def failed(self) -> bool:
        """
        Determine if any elements of MultiResponse are failed

        Args:
            N/A

        Returns:
            bool: True for failed

        Raises:
            N/A

        """
        return any(response.failed for response in self.data)

    @property
    def result(self) -> str:
        """
        Build a unified result from all elements of MultiResponse

        Args:
            N/A

        Returns:
            str: Unified result by combining results of all elements of MultiResponse

        Raises:
            N/A

        """
        return "".join(
            "\n".join([response.channel_input, response.result]) for response in self.data
        )

    def raise_for_status(self) -> None:
        """
        Raise a `ScrapliCommandFailure` if any elements are failed

        Args:
            N/A

        Returns:
            None

        Raises:
            ScrapliCommandFailure: if any elements are failed

        """
        if self.failed:
            raise ScrapliCommandFailure()

__init__(initlist: Optional[Iterable[Any]] = None) -> None

Initialize list of responses

Parameters:

Name Type Description Default
initlist Optional[Iterable[Any]]

initial list seed data, if any

None

Returns:

Type Description
None

None

Source code in scrapli/response.py
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
def __init__(self, initlist: Optional[Iterable[Any]] = None) -> None:
    """
    Initialize list of responses

    Args:
        initlist: initial list seed data, if any

    Returns:
        None

    Raises:
        N/A

    """
    super().__init__(initlist=initlist)

    self.data: List[Response]

__str__() -> str

Magic str method for MultiResponse class

Returns:

Name Type Description
str str

str for class object

Source code in scrapli/response.py
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
def __str__(self) -> str:
    """
    Magic str method for MultiResponse class

    Args:
        N/A

    Returns:
        str: str for class object

    Raises:
        N/A

    """
    return (
        f"{self.__class__.__name__} <Success: {not self.failed}; "
        f"Response Elements: {len(self.data)}>"
    )

failed() -> bool property

Determine if any elements of MultiResponse are failed

Returns:

Name Type Description
bool bool

True for failed

Source code in scrapli/response.py
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
@property
def failed(self) -> bool:
    """
    Determine if any elements of MultiResponse are failed

    Args:
        N/A

    Returns:
        bool: True for failed

    Raises:
        N/A

    """
    return any(response.failed for response in self.data)

host() -> str property

Return the host of the multiresponse

Returns:

Name Type Description
str str

The host of the associated responses

Source code in scrapli/response.py
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
@property
def host(self) -> str:
    """
    Return the host of the multiresponse

    Args:
        N/A

    Returns:
        str: The host of the associated responses

    Raises:
        N/A

    """
    try:
        response = self.data[0]
    except IndexError:
        return ""
    return response.host

raise_for_status() -> None

Raise a ScrapliCommandFailure if any elements are failed

Returns:

Type Description
None

None

Raises:

Type Description
ScrapliCommandFailure

if any elements are failed

Source code in scrapli/response.py
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
def raise_for_status(self) -> None:
    """
    Raise a `ScrapliCommandFailure` if any elements are failed

    Args:
        N/A

    Returns:
        None

    Raises:
        ScrapliCommandFailure: if any elements are failed

    """
    if self.failed:
        raise ScrapliCommandFailure()

result() -> str property

Build a unified result from all elements of MultiResponse

Returns:

Name Type Description
str str

Unified result by combining results of all elements of MultiResponse

Source code in scrapli/response.py
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
@property
def result(self) -> str:
    """
    Build a unified result from all elements of MultiResponse

    Args:
        N/A

    Returns:
        str: Unified result by combining results of all elements of MultiResponse

    Raises:
        N/A

    """
    return "".join(
        "\n".join([response.channel_input, response.result]) for response in self.data
    )

Response

Source code in scrapli/response.py
 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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
class Response:
    def __init__(
        self,
        host: str,
        channel_input: str,
        textfsm_platform: str = "",
        genie_platform: str = "",
        failed_when_contains: Optional[Union[str, List[str]]] = None,
    ):
        """
        Scrapli Response

        Store channel_input, resulting output, and start/end/elapsed time information. Attempt to
        determine if command was successful or not and reflect that in a failed attribute.

        Args:
            host: host that was operated on
            channel_input: input that got sent down the channel
            textfsm_platform: ntc-templates friendly platform type
            genie_platform: cisco pyats/genie friendly platform type
            failed_when_contains: list of strings that, if present in final output, represent a
                failed command/interaction

        Returns:
            None

        Raises:
            N/A

        """
        self.host = host
        self.start_time = datetime.now()
        self.finish_time: Optional[datetime] = None
        self.elapsed_time: Optional[float] = None

        self.channel_input = channel_input
        self.textfsm_platform = textfsm_platform
        self.genie_platform = genie_platform
        self.raw_result: bytes = b""
        self.result: str = ""

        if isinstance(failed_when_contains, str):
            failed_when_contains = [failed_when_contains]
        self.failed_when_contains = failed_when_contains
        self.failed = True

    def __bool__(self) -> bool:
        """
        Magic bool method based on channel_input being failed or not

        Args:
            N/A

        Returns:
            bool: True/False if channel_input failed

        Raises:
            N/A

        """
        return self.failed

    def __repr__(self) -> str:
        """
        Magic repr method for Response class

        Args:
            N/A

        Returns:
            str: repr for class object

        Raises:
            N/A

        """
        return (
            f"{self.__class__.__name__}("
            f"host={self.host!r},"
            f"channel_input={self.channel_input!r},"
            f"textfsm_platform={self.textfsm_platform!r},"
            f"genie_platform={self.genie_platform!r},"
            f"failed_when_contains={self.failed_when_contains!r})"
        )

    def __str__(self) -> str:
        """
        Magic str method for Response class

        Args:
            N/A

        Returns:
            str: str for class object

        Raises:
            N/A

        """
        return f"{self.__class__.__name__} <Success: {not self.failed}>"

    def record_response(self, result: bytes) -> None:
        """
        Record channel_input results and elapsed time of channel input/reading output

        Args:
            result: string result of channel_input

        Returns:
            None

        Raises:
            N/A

        """
        self.finish_time = datetime.now()
        self.elapsed_time = (self.finish_time - self.start_time).total_seconds()
        self.raw_result = result

        try:
            self.result = result.decode()
        except UnicodeDecodeError:
            # sometimes we get some "garbage" characters, the iso encoding seems to handle these
            # better but unclear what the other impact is so we'll just catch exceptions and try
            # this encoding
            self.result = result.decode(encoding="ISO-8859-1")

        if not self.failed_when_contains:
            self.failed = False
        elif all(err not in self.result for err in self.failed_when_contains):
            self.failed = False

    def textfsm_parse_output(
        self, template: Union[str, TextIO, None] = None, to_dict: bool = True
    ) -> Union[Dict[str, Any], List[Any]]:
        """
        Parse results with textfsm, always return structured data

        Returns an empty list if parsing fails!

        Args:
            template: string path to textfsm template or opened textfsm template file
            to_dict: convert textfsm output from list of lists to list of dicts -- basically create
                dict from header and row data so it is easier to read/parse the output

        Returns:
            structured_result: empty list or parsed data from textfsm

        Raises:
            N/A

        """
        if template is None:
            template = _textfsm_get_template(
                platform=self.textfsm_platform, command=self.channel_input
            )

        if template is None:
            return []

        template = cast(Union[str, TextIOWrapper], template)
        return textfsm_parse(template=template, output=self.result, to_dict=to_dict) or []

    def genie_parse_output(self) -> Union[Dict[str, Any], List[Any]]:
        """
        Parse results with genie, always return structured data

        Returns an empty list if parsing fails!

        Args:
            N/A

        Returns:
            structured_result: empty list or parsed data from genie

        Raises:
            N/A

        """
        return genie_parse(
            platform=self.genie_platform,
            command=self.channel_input,
            output=self.result,
        )

    def ttp_parse_output(
        self, template: Union[str, TextIOWrapper]
    ) -> Union[Dict[str, Any], List[Any]]:
        """
        Parse results with ttp, always return structured data

        Returns an empty list if parsing fails!

        Args:
            template: string path to ttp template or opened ttp template file

        Returns:
            structured_result: empty list or parsed data from ttp

        Raises:
            N/A

        """
        return ttp_parse(template=template, output=self.result) or []

    def raise_for_status(self) -> None:
        """
        Raise a `ScrapliCommandFailure` if command/config failed

        Args:
            N/A

        Returns:
            None

        Raises:
            ScrapliCommandFailure: if command/config failed

        """
        if self.failed:
            raise ScrapliCommandFailure()

__bool__() -> bool

Magic bool method based on channel_input being failed or not

Returns:

Name Type Description
bool bool

True/False if channel_input failed

Source code in scrapli/response.py
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
def __bool__(self) -> bool:
    """
    Magic bool method based on channel_input being failed or not

    Args:
        N/A

    Returns:
        bool: True/False if channel_input failed

    Raises:
        N/A

    """
    return self.failed

__init__(host: str, channel_input: str, textfsm_platform: str = '', genie_platform: str = '', failed_when_contains: Optional[Union[str, List[str]]] = None)

Scrapli Response

Store channel_input, resulting output, and start/end/elapsed time information. Attempt to determine if command was successful or not and reflect that in a failed attribute.

Parameters:

Name Type Description Default
host str

host that was operated on

required
channel_input str

input that got sent down the channel

required
textfsm_platform str

ntc-templates friendly platform type

''
genie_platform str

cisco pyats/genie friendly platform type

''
failed_when_contains Optional[Union[str, List[str]]]

list of strings that, if present in final output, represent a failed command/interaction

None

Returns:

Type Description

None

Source code in scrapli/response.py
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
def __init__(
    self,
    host: str,
    channel_input: str,
    textfsm_platform: str = "",
    genie_platform: str = "",
    failed_when_contains: Optional[Union[str, List[str]]] = None,
):
    """
    Scrapli Response

    Store channel_input, resulting output, and start/end/elapsed time information. Attempt to
    determine if command was successful or not and reflect that in a failed attribute.

    Args:
        host: host that was operated on
        channel_input: input that got sent down the channel
        textfsm_platform: ntc-templates friendly platform type
        genie_platform: cisco pyats/genie friendly platform type
        failed_when_contains: list of strings that, if present in final output, represent a
            failed command/interaction

    Returns:
        None

    Raises:
        N/A

    """
    self.host = host
    self.start_time = datetime.now()
    self.finish_time: Optional[datetime] = None
    self.elapsed_time: Optional[float] = None

    self.channel_input = channel_input
    self.textfsm_platform = textfsm_platform
    self.genie_platform = genie_platform
    self.raw_result: bytes = b""
    self.result: str = ""

    if isinstance(failed_when_contains, str):
        failed_when_contains = [failed_when_contains]
    self.failed_when_contains = failed_when_contains
    self.failed = True

__repr__() -> str

Magic repr method for Response class

Returns:

Name Type Description
str str

repr for class object

Source code in scrapli/response.py
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
def __repr__(self) -> str:
    """
    Magic repr method for Response class

    Args:
        N/A

    Returns:
        str: repr for class object

    Raises:
        N/A

    """
    return (
        f"{self.__class__.__name__}("
        f"host={self.host!r},"
        f"channel_input={self.channel_input!r},"
        f"textfsm_platform={self.textfsm_platform!r},"
        f"genie_platform={self.genie_platform!r},"
        f"failed_when_contains={self.failed_when_contains!r})"
    )

__str__() -> str

Magic str method for Response class

Returns:

Name Type Description
str str

str for class object

Source code in scrapli/response.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
def __str__(self) -> str:
    """
    Magic str method for Response class

    Args:
        N/A

    Returns:
        str: str for class object

    Raises:
        N/A

    """
    return f"{self.__class__.__name__} <Success: {not self.failed}>"

genie_parse_output() -> Union[Dict[str, Any], List[Any]]

Parse results with genie, always return structured data

Returns an empty list if parsing fails!

Returns:

Name Type Description
structured_result Union[Dict[str, Any], List[Any]]

empty list or parsed data from genie

Source code in scrapli/response.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
def genie_parse_output(self) -> Union[Dict[str, Any], List[Any]]:
    """
    Parse results with genie, always return structured data

    Returns an empty list if parsing fails!

    Args:
        N/A

    Returns:
        structured_result: empty list or parsed data from genie

    Raises:
        N/A

    """
    return genie_parse(
        platform=self.genie_platform,
        command=self.channel_input,
        output=self.result,
    )

raise_for_status() -> None

Raise a ScrapliCommandFailure if command/config failed

Returns:

Type Description
None

None

Raises:

Type Description
ScrapliCommandFailure

if command/config failed

Source code in scrapli/response.py
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
def raise_for_status(self) -> None:
    """
    Raise a `ScrapliCommandFailure` if command/config failed

    Args:
        N/A

    Returns:
        None

    Raises:
        ScrapliCommandFailure: if command/config failed

    """
    if self.failed:
        raise ScrapliCommandFailure()

record_response(result: bytes) -> None

Record channel_input results and elapsed time of channel input/reading output

Parameters:

Name Type Description Default
result bytes

string result of channel_input

required

Returns:

Type Description
None

None

Source code in scrapli/response.py
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
def record_response(self, result: bytes) -> None:
    """
    Record channel_input results and elapsed time of channel input/reading output

    Args:
        result: string result of channel_input

    Returns:
        None

    Raises:
        N/A

    """
    self.finish_time = datetime.now()
    self.elapsed_time = (self.finish_time - self.start_time).total_seconds()
    self.raw_result = result

    try:
        self.result = result.decode()
    except UnicodeDecodeError:
        # sometimes we get some "garbage" characters, the iso encoding seems to handle these
        # better but unclear what the other impact is so we'll just catch exceptions and try
        # this encoding
        self.result = result.decode(encoding="ISO-8859-1")

    if not self.failed_when_contains:
        self.failed = False
    elif all(err not in self.result for err in self.failed_when_contains):
        self.failed = False

textfsm_parse_output(template: Union[str, TextIO, None] = None, to_dict: bool = True) -> Union[Dict[str, Any], List[Any]]

Parse results with textfsm, always return structured data

Returns an empty list if parsing fails!

Parameters:

Name Type Description Default
template Union[str, TextIO, None]

string path to textfsm template or opened textfsm template file

None
to_dict bool

convert textfsm output from list of lists to list of dicts -- basically create dict from header and row data so it is easier to read/parse the output

True

Returns:

Name Type Description
structured_result Union[Dict[str, Any], List[Any]]

empty list or parsed data from textfsm

Source code in scrapli/response.py
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
def textfsm_parse_output(
    self, template: Union[str, TextIO, None] = None, to_dict: bool = True
) -> Union[Dict[str, Any], List[Any]]:
    """
    Parse results with textfsm, always return structured data

    Returns an empty list if parsing fails!

    Args:
        template: string path to textfsm template or opened textfsm template file
        to_dict: convert textfsm output from list of lists to list of dicts -- basically create
            dict from header and row data so it is easier to read/parse the output

    Returns:
        structured_result: empty list or parsed data from textfsm

    Raises:
        N/A

    """
    if template is None:
        template = _textfsm_get_template(
            platform=self.textfsm_platform, command=self.channel_input
        )

    if template is None:
        return []

    template = cast(Union[str, TextIOWrapper], template)
    return textfsm_parse(template=template, output=self.result, to_dict=to_dict) or []

ttp_parse_output(template: Union[str, TextIOWrapper]) -> Union[Dict[str, Any], List[Any]]

Parse results with ttp, always return structured data

Returns an empty list if parsing fails!

Parameters:

Name Type Description Default
template Union[str, TextIOWrapper]

string path to ttp template or opened ttp template file

required

Returns:

Name Type Description
structured_result Union[Dict[str, Any], List[Any]]

empty list or parsed data from ttp

Source code in scrapli/response.py
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
def ttp_parse_output(
    self, template: Union[str, TextIOWrapper]
) -> Union[Dict[str, Any], List[Any]]:
    """
    Parse results with ttp, always return structured data

    Returns an empty list if parsing fails!

    Args:
        template: string path to ttp template or opened ttp template file

    Returns:
        structured_result: empty list or parsed data from ttp

    Raises:
        N/A

    """
    return ttp_parse(template=template, output=self.result) or []