scrapli 2.0.0a0__py3-none-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,148 @@
1
+ """scrapli.netconf_decorators"""
2
+
3
+ from collections.abc import Awaitable, Callable
4
+ from ctypes import c_uint64
5
+ from functools import update_wrapper
6
+ from typing import TYPE_CHECKING, Concatenate, ParamSpec
7
+
8
+ from scrapli.exceptions import OptionsException
9
+ from scrapli.netconf_result import Result
10
+
11
+ if TYPE_CHECKING:
12
+ from scrapli.netconf import Netconf
13
+
14
+ P = ParamSpec("P")
15
+
16
+
17
+ def handle_operation_timeout(
18
+ wrapped: Callable[Concatenate["Netconf", P], Result],
19
+ ) -> Callable[Concatenate["Netconf", P], Result]:
20
+ """
21
+ Wraps a Netconf operation and sets the timeout value for the duration of the operation
22
+
23
+ Args:
24
+ wrapped: the operation function
25
+
26
+ Returns:
27
+ callable: the wrapper function
28
+
29
+ Raises:
30
+ N/A
31
+
32
+ """
33
+
34
+ def wrapper(inst: "Netconf", /, *args: P.args, **kwargs: P.kwargs) -> Result:
35
+ """
36
+ The operation timeout wrapper
37
+
38
+ Args:
39
+ inst: the Netconf instance
40
+ args: the arguments to pass to the wrapped function
41
+ kwargs: the keyword arguments to pass to the wrapped function
42
+
43
+ Returns:
44
+ Result: the result of the wrapped function
45
+
46
+ Raises:
47
+ OptionsException: if the operation timeout failed to set
48
+
49
+ """
50
+ operation_timeout_ns = kwargs.get("operation_timeout_ns")
51
+ if operation_timeout_ns is None:
52
+ return wrapped(inst, *args, **kwargs)
53
+
54
+ if operation_timeout_ns == inst.session_options.operation_timeout_ns:
55
+ return wrapped(inst, *args, **kwargs)
56
+
57
+ if not isinstance(operation_timeout_ns, int):
58
+ # ignore an invalid type for the timeout
59
+ return wrapped(inst, *args, **kwargs)
60
+
61
+ status = inst.ffi_mapping.options_mapping.session.set_operation_timeout_ns(
62
+ inst._ptr_or_exception(),
63
+ c_uint64(operation_timeout_ns),
64
+ )
65
+ if status != 0:
66
+ raise OptionsException("failed to set session operation timeout")
67
+
68
+ res = wrapped(inst, *args, **kwargs)
69
+
70
+ status = inst.ffi_mapping.options_mapping.session.set_operation_timeout_ns(
71
+ inst._ptr_or_exception(),
72
+ c_uint64(operation_timeout_ns),
73
+ )
74
+ if status != 0:
75
+ raise OptionsException("failed to set session operation timeout")
76
+
77
+ return res
78
+
79
+ update_wrapper(wrapper=wrapper, wrapped=wrapped)
80
+
81
+ return wrapper
82
+
83
+
84
+ def handle_operation_timeout_async(
85
+ wrapped: Callable[Concatenate["Netconf", P], Awaitable[Result]],
86
+ ) -> Callable[Concatenate["Netconf", P], Awaitable[Result]]:
87
+ """
88
+ Wraps a Netconf operation and sets the timeout value for the duration of the operation
89
+
90
+ Args:
91
+ wrapped: the operation function
92
+
93
+ Returns:
94
+ callable: the wrapper function
95
+
96
+ Raises:
97
+ N/A
98
+
99
+ """
100
+
101
+ async def wrapper(inst: "Netconf", /, *args: P.args, **kwargs: P.kwargs) -> Result:
102
+ """
103
+ The operation timeout wrapper
104
+
105
+ Args:
106
+ inst: the Netconf instance
107
+ args: the arguments to pass to the wrapped function
108
+ kwargs: the keyword arguments to pass to the wrapped function
109
+
110
+ Returns:
111
+ Result: the result of the wrapped function
112
+
113
+ Raises:
114
+ OptionsException: if the operation timeout failed to set
115
+
116
+ """
117
+ operation_timeout_ns = kwargs.get("operation_timeout_ns")
118
+ if operation_timeout_ns is None:
119
+ return await wrapped(inst, *args, **kwargs)
120
+
121
+ if operation_timeout_ns == inst.session_options.operation_timeout_ns:
122
+ return await wrapped(inst, *args, **kwargs)
123
+
124
+ if not isinstance(operation_timeout_ns, int):
125
+ # ignore an invalid type for the timeout
126
+ return await wrapped(inst, *args, **kwargs)
127
+
128
+ status = inst.ffi_mapping.options_mapping.session.set_operation_timeout_ns(
129
+ inst._ptr_or_exception(),
130
+ c_uint64(operation_timeout_ns),
131
+ )
132
+ if status != 0:
133
+ raise OptionsException("failed to set session operation timeout")
134
+
135
+ res = await wrapped(inst, *args, **kwargs)
136
+
137
+ status = inst.ffi_mapping.options_mapping.session.set_operation_timeout_ns(
138
+ inst._ptr_or_exception(),
139
+ c_uint64(operation_timeout_ns),
140
+ )
141
+ if status != 0:
142
+ raise OptionsException("failed to set session operation timeout")
143
+
144
+ return res
145
+
146
+ update_wrapper(wrapper=wrapper, wrapped=wrapped)
147
+
148
+ return wrapper
@@ -0,0 +1,72 @@
1
+ """scrapli.result"""
2
+
3
+ from dataclasses import dataclass
4
+
5
+
6
+ @dataclass
7
+ class Result:
8
+ """
9
+ Result holds the result of an operation.
10
+
11
+ Args:
12
+ input_:
13
+ host:
14
+ port:
15
+ start_time:
16
+ end_time:
17
+ result_raw:
18
+ result:
19
+ rpc_warnings:
20
+ rpc_errors:
21
+
22
+ Returns:
23
+ None
24
+
25
+ Raises:
26
+ N/A
27
+
28
+ """
29
+
30
+ input_: str
31
+ host: str
32
+ port: int
33
+ start_time: int
34
+ end_time: int
35
+ result_raw: bytes
36
+ result: str
37
+ rpc_warnings: str
38
+ rpc_errors: str
39
+
40
+ @property
41
+ def failed(self) -> bool:
42
+ """
43
+ Returns True if any failed indicators were seen, otherwise False.
44
+
45
+ Args:
46
+ N/A
47
+
48
+ Returns:
49
+ bool: True for failed, otherwise False
50
+
51
+ Raises:
52
+ N/A
53
+
54
+ """
55
+ return bool(self.rpc_errors)
56
+
57
+ @property
58
+ def elapsed_time_seconds(self) -> float:
59
+ """
60
+ Returns the number of seconds the operation took.
61
+
62
+ Args:
63
+ N/A
64
+
65
+ Returns:
66
+ float: duration in seconds
67
+
68
+ Raises:
69
+ N/A
70
+
71
+ """
72
+ return (self.end_time - self.start_time) / 1_000_000_000
scrapli/py.typed ADDED
File without changes
scrapli/session.py ADDED
@@ -0,0 +1,122 @@
1
+ """scrapli.session"""
2
+
3
+ from ctypes import c_char_p, c_uint64
4
+ from dataclasses import dataclass, field
5
+
6
+ from scrapli.exceptions import OptionsException
7
+ from scrapli.ffi_mapping import LibScrapliMapping
8
+ from scrapli.ffi_types import DriverPointer, to_c_string
9
+
10
+
11
+ @dataclass
12
+ class Options:
13
+ """
14
+ Options holds session related options to pass to the ffi layer.
15
+
16
+ Args:
17
+ read_size: read size
18
+ return_char: return char
19
+ operation_timeout_s: operation timeout in s, ignored if operation_timeout_ns set
20
+ operation_timeout_ns: operation timeout in ns
21
+ operation_max_search_depth: operation maximum search depth
22
+ recorder_path: path for session recorder output to write to
23
+
24
+ Returns:
25
+ None
26
+
27
+ Raises:
28
+ N/A
29
+
30
+ """
31
+
32
+ read_size: int | None = None
33
+ return_char: str | None = None
34
+ operation_timeout_s: int | None = None
35
+ operation_timeout_ns: int | None = None
36
+ operation_max_search_depth: int | None = None
37
+ recorder_path: str | None = None
38
+
39
+ _return_char: c_char_p | None = field(init=False, default=None, repr=False)
40
+ _recorder_path: c_char_p | None = field(init=False, default=None, repr=False)
41
+
42
+ def __post_init__(self) -> None:
43
+ if self.operation_timeout_s is not None or self.operation_timeout_ns is not None:
44
+ if self.operation_timeout_ns is None and self.operation_timeout_s is not None:
45
+ self.operation_timeout_ns = int(self.operation_timeout_s / 1e-9)
46
+
47
+ def apply(self, ffi_mapping: LibScrapliMapping, ptr: DriverPointer) -> None: # noqa: C901
48
+ """
49
+ Applies the options to the given driver pointer.
50
+
51
+ Should not be called directly/by users.
52
+
53
+ Args:
54
+ ffi_mapping: the handle to the ffi mapping singleton
55
+ ptr: the pointer to the underlying cli or netconf object
56
+
57
+ Returns:
58
+ None
59
+
60
+ Raises:
61
+ OptionsException: if any option apply returns a non-zero return code.
62
+
63
+ """
64
+ if self.read_size is not None:
65
+ status = ffi_mapping.options_mapping.session.set_read_size(
66
+ ptr, c_uint64(self.read_size)
67
+ )
68
+ if status != 0:
69
+ raise OptionsException("failed to set session read size")
70
+
71
+ if self.return_char is not None:
72
+ self._return_char = to_c_string(self.return_char)
73
+
74
+ status = ffi_mapping.options_mapping.session.set_return_char(ptr, self._return_char)
75
+ if status != 0:
76
+ raise OptionsException("failed to set session return char")
77
+
78
+ if self.operation_timeout_ns is not None:
79
+ status = ffi_mapping.options_mapping.session.set_operation_timeout_ns(
80
+ ptr, c_uint64(self.operation_timeout_ns)
81
+ )
82
+ if status != 0:
83
+ raise OptionsException("failed to set session operation timeout")
84
+
85
+ if self.operation_max_search_depth is not None:
86
+ status = ffi_mapping.options_mapping.session.set_operation_max_search_depth(
87
+ ptr, c_uint64(self.operation_max_search_depth)
88
+ )
89
+ if status != 0:
90
+ raise OptionsException("failed to set session operation max search depth")
91
+
92
+ if self.recorder_path is not None:
93
+ self._recorder_path = to_c_string(self.recorder_path)
94
+
95
+ status = ffi_mapping.options_mapping.session.set_recorder_path(ptr, self._recorder_path)
96
+ if status != 0:
97
+ raise OptionsException("failed to set session recorder path")
98
+
99
+ def __repr__(self) -> str:
100
+ """
101
+ Magic repr method for Options object
102
+
103
+ Args:
104
+ N/A
105
+
106
+ Returns:
107
+ str: repr for Options object
108
+
109
+ Raises:
110
+ N/A
111
+
112
+ """
113
+ return (
114
+ # it will probably be "canonical" to import Options as SessionOptions, so we'll make
115
+ # the repr do that too
116
+ f"Session{self.__class__.__name__}("
117
+ f"read_size={self.read_size!r}, "
118
+ f"return_char={self.return_char!r}) "
119
+ f"operation_timeout_ns={self.operation_timeout_ns!r}) "
120
+ f"operation_max_search_depth={self.operation_max_search_depth!r}) "
121
+ f"recorder_path={self.recorder_path!r}) "
122
+ )