encommon 0.18.0__py3-none-any.whl → 0.19.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ """
2
+ Functions and routines associated with Enasis Network Common Library.
3
+
4
+ This file is part of Enasis Network software eco-system. Distribution
5
+ is permitted, for more information consult the project license file.
6
+ """
7
+
8
+
9
+
10
+ from .jinja2 import Jinja2
11
+ from .network import Network
12
+ from .network import insubnet_ip
13
+ from .network import isvalid_ip
14
+
15
+
16
+ __all__ = [
17
+ 'Jinja2',
18
+ 'Network',
19
+ 'insubnet_ip',
20
+ 'isvalid_ip']
@@ -0,0 +1,332 @@
1
+ """
2
+ Functions and routines associated with Enasis Network Common Library.
3
+
4
+ This file is part of Enasis Network software eco-system. Distribution
5
+ is permitted, for more information consult the project license file.
6
+ """
7
+
8
+
9
+
10
+ from ast import literal_eval as leval
11
+ from contextlib import suppress
12
+ from copy import copy
13
+ from copy import deepcopy
14
+ from re import DOTALL
15
+ from re import findall as re_findall
16
+ from re import match as re_match
17
+ from typing import Any
18
+ from typing import Callable
19
+ from typing import Optional
20
+
21
+ from jinja2 import Environment
22
+ from jinja2 import StrictUndefined
23
+
24
+ from .network import Network
25
+ from .network import insubnet_ip
26
+ from .network import isvalid_ip
27
+ from ..colors import Color
28
+ from ..crypts import Hashes
29
+ from ..times import Duration
30
+ from ..times import Time
31
+ from ..times import unitime
32
+ from ..types import DictStrAny
33
+ from ..types import dedup_list
34
+ from ..types import fuzzy_list
35
+ from ..types import hasstr
36
+ from ..types import inlist
37
+ from ..types import instr
38
+ from ..types import merge_dicts
39
+ from ..types import rplstr
40
+ from ..types import sort_dict
41
+ from ..types import strplwr
42
+ from ..utils import fuzz_match
43
+ from ..utils import rgxp_match
44
+
45
+
46
+
47
+ FILTER = Callable[..., Any]
48
+
49
+ JINJA2 = (
50
+ r'(\{\{.+?\}\})|'
51
+ r'(\{\%.+?\%\})')
52
+
53
+ LITERAL = (
54
+ r'^((\{([^\{%].+?)?\})|(\[(.+?|)\])'
55
+ '|True|False|None|'
56
+ r'(\-?([1-9]\d*|0)(\.\d+)?))$')
57
+
58
+
59
+
60
+ DEFAULT: dict[str, FILTER] = {
61
+
62
+ # Python builtins
63
+ 'all': all,
64
+ 'any': any,
65
+ 'copy': copy,
66
+ 'deepcopy': deepcopy,
67
+
68
+ # encommon.times
69
+ 'Duration': Duration,
70
+ 'Time': Time,
71
+
72
+ # encommon.colors
73
+ 'Color': Color,
74
+
75
+ # encommon.crypts
76
+ 'Hashes': Hashes,
77
+
78
+ # encommon.parse
79
+ 'Network': Network,
80
+ 'insubnet_ip': insubnet_ip,
81
+ 'isvalid_ip': isvalid_ip,
82
+
83
+ # encommon.times
84
+ 'unitime': unitime,
85
+
86
+ # encommon.types
87
+ 'strplwr': strplwr,
88
+ 'hasstr': hasstr,
89
+ 'instr': instr,
90
+ 'inlist': inlist,
91
+ 'rplstr': rplstr,
92
+ 'dedup_list': dedup_list,
93
+ 'fuzzy_list': fuzzy_list,
94
+ 'merge_dicts': merge_dicts,
95
+ 'sort_dict': sort_dict,
96
+
97
+ # encommon.utils
98
+ 'fuzz_match': fuzz_match,
99
+ 'rgxp_match': rgxp_match}
100
+
101
+
102
+
103
+ class Jinja2:
104
+ """
105
+ Parse the provided input and intelligently return value.
106
+
107
+ Example
108
+ -------
109
+ >>> jinja2 = Jinja2()
110
+ >>> jinja2.parse('{{ 0 | Time}}')
111
+ '1970-01-01T00:00:00.000000+0000'
112
+
113
+ :param statics: Additional values available for parsing.
114
+ :param filters: Additional filter functions for parsing.
115
+ """
116
+
117
+ __statics: DictStrAny
118
+ __filters: dict[str, FILTER]
119
+
120
+ __jinjenv: Environment
121
+
122
+
123
+ def __init__(
124
+ self,
125
+ statics: Optional[DictStrAny] = None,
126
+ filters: Optional[dict[str, FILTER]] = None,
127
+ ) -> None:
128
+ """
129
+ Initialize instance for class using provided parameters.
130
+ """
131
+
132
+ statics = dict(statics or {})
133
+ filters = dict(filters or {})
134
+
135
+ items = DEFAULT.items()
136
+
137
+ for key, filter in items:
138
+ filters[key] = filter
139
+
140
+ self.__statics = statics
141
+ self.__filters = filters
142
+
143
+ jinjenv = Environment(
144
+ auto_reload=False,
145
+ autoescape=False,
146
+ cache_size=0,
147
+ extensions=[
148
+ 'jinja2.ext.i18n',
149
+ 'jinja2.ext.loopcontrols',
150
+ 'jinja2.ext.do'],
151
+ keep_trailing_newline=False,
152
+ lstrip_blocks=False,
153
+ newline_sequence='\n',
154
+ optimized=True,
155
+ trim_blocks=False,
156
+ undefined=StrictUndefined)
157
+
158
+ jinjenv.filters |= filters
159
+
160
+ self.__jinjenv = jinjenv
161
+
162
+
163
+ @property
164
+ def statics(
165
+ self,
166
+ ) -> DictStrAny:
167
+ """
168
+ Return the value for the attribute from class instance.
169
+
170
+ :returns: Value for the attribute from class instance.
171
+ """
172
+
173
+ return dict(self.__statics)
174
+
175
+
176
+ @property
177
+ def filters(
178
+ self,
179
+ ) -> dict[str, FILTER]:
180
+ """
181
+ Return the value for the attribute from class instance.
182
+
183
+ :returns: Value for the attribute from class instance.
184
+ """
185
+
186
+ return dict(self.__filters)
187
+
188
+
189
+ @property
190
+ def jinjenv(
191
+ self,
192
+ ) -> Environment:
193
+ """
194
+ Return the value for the attribute from class instance.
195
+
196
+ :returns: Value for the attribute from class instance.
197
+ """
198
+
199
+ return self.__jinjenv
200
+
201
+
202
+ def parser(
203
+ self,
204
+ value: str,
205
+ statics: Optional[DictStrAny] = None,
206
+ ) -> Any:
207
+ """
208
+ Return the provided input using the Jinja2 environment.
209
+
210
+ :param value: Input that will be processed and returned.
211
+ :param statics: Additional values available for parsing.
212
+ :returns: Provided input using the Jinja2 environment.
213
+ """
214
+
215
+ statics = (
216
+ dict(statics or {})
217
+ | self.__statics)
218
+
219
+ parser = (
220
+ self.__jinjenv
221
+ .from_string)
222
+
223
+ rendered = (
224
+ parser(value)
225
+ .render(**statics))
226
+
227
+ return rendered
228
+
229
+
230
+ def parse( # noqa: CFQ004
231
+ self,
232
+ value: Any,
233
+ statics: Optional[DictStrAny] = None,
234
+ literal: bool = True,
235
+ ) -> Any:
236
+ """
237
+ Return the provided input using the Jinja2 environment.
238
+
239
+ :param value: Input that will be processed and returned.
240
+ :param statics: Additional values available for parsing.
241
+ :param literal: Determine if Python objects are evaled.
242
+ :returns: Provided input using the Jinja2 environment.
243
+ """
244
+
245
+
246
+ def _final( # noqa: CFQ004
247
+ value: Any,
248
+ ) -> Any:
249
+
250
+ if literal is False:
251
+ return value
252
+
253
+ match = re_match(
254
+ LITERAL, str(value))
255
+
256
+ if match is None:
257
+ return value
258
+
259
+ with suppress(Exception):
260
+ return leval(value)
261
+
262
+ return value
263
+
264
+
265
+ def _parse(
266
+ value: Any,
267
+ ) -> Any:
268
+
269
+ return self.parse(
270
+ value,
271
+ statics, literal)
272
+
273
+
274
+ def _parser(
275
+ value: Any,
276
+ ) -> Any:
277
+
278
+ parsed = self.parser(
279
+ value, statics)
280
+
281
+ return _final(parsed)
282
+
283
+
284
+ def _found(
285
+ value: Any,
286
+ ) -> list[Any]:
287
+
288
+ value = str(value)
289
+
290
+ return re_findall(
291
+ JINJA2, value, DOTALL)
292
+
293
+
294
+ if not len(_found(value)):
295
+ return _final(value)
296
+
297
+
298
+ with suppress(Exception):
299
+ value = _final(value)
300
+
301
+
302
+ if isinstance(value, dict):
303
+
304
+ value = dict(value)
305
+
306
+ items = value.items()
307
+
308
+ for key, _value in items:
309
+
310
+ _value = _parse(_value)
311
+
312
+ value[key] = _value
313
+
314
+
315
+ elif isinstance(value, list):
316
+
317
+ value = list(value)
318
+
319
+ values = enumerate(value)
320
+
321
+ for idx, _value in values:
322
+
323
+ _value = _parse(_value)
324
+
325
+ value[idx] = _value
326
+
327
+
328
+ elif value is not None:
329
+ value = _parser(value)
330
+
331
+
332
+ return value