encommon 0.17.2__py3-none-any.whl → 0.19.0__py3-none-any.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.
- encommon/config/config.py +3 -2
- encommon/parse/__init__.py +20 -0
- encommon/parse/jinja2.py +282 -0
- encommon/parse/network.py +453 -0
- encommon/parse/test/__init__.py +6 -0
- encommon/parse/test/test_jinja2.py +190 -0
- encommon/parse/test/test_network.py +226 -0
- encommon/types/__init__.py +4 -0
- encommon/types/lists.py +71 -0
- encommon/types/test/test_lists.py +41 -0
- encommon/version.txt +1 -1
- {encommon-0.17.2.dist-info → encommon-0.19.0.dist-info}/METADATA +3 -1
- {encommon-0.17.2.dist-info → encommon-0.19.0.dist-info}/RECORD +16 -10
- {encommon-0.17.2.dist-info → encommon-0.19.0.dist-info}/LICENSE +0 -0
- {encommon-0.17.2.dist-info → encommon-0.19.0.dist-info}/WHEEL +0 -0
- {encommon-0.17.2.dist-info → encommon-0.19.0.dist-info}/top_level.txt +0 -0
encommon/config/config.py
CHANGED
@@ -21,6 +21,7 @@ from ..crypts import Crypts
|
|
21
21
|
from ..types import DictStrAny
|
22
22
|
from ..types import merge_dicts
|
23
23
|
from ..types import setate
|
24
|
+
from ..types import sort_dict
|
24
25
|
|
25
26
|
if TYPE_CHECKING:
|
26
27
|
from ..utils.common import PATHABLE
|
@@ -43,7 +44,7 @@ class Config:
|
|
43
44
|
-------
|
44
45
|
>>> config = Config()
|
45
46
|
>>> config.config
|
46
|
-
{'enconfig': None, '
|
47
|
+
{'enconfig': None, 'encrypts': None, 'enlogger': None}
|
47
48
|
|
48
49
|
:param files: Complete or relative path to config files.
|
49
50
|
:param paths: Complete or relative path to config paths.
|
@@ -275,7 +276,7 @@ class Config:
|
|
275
276
|
:returns: Configuration dumped from the Pydantic model.
|
276
277
|
"""
|
277
278
|
|
278
|
-
return self.params.endumped
|
279
|
+
return sort_dict(self.params.endumped)
|
279
280
|
|
280
281
|
|
281
282
|
@property
|
@@ -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']
|
encommon/parse/jinja2.py
ADDED
@@ -0,0 +1,282 @@
|
|
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 re import DOTALL
|
13
|
+
from re import findall as re_findall
|
14
|
+
from re import match as re_match
|
15
|
+
from typing import Any
|
16
|
+
from typing import Callable
|
17
|
+
from typing import Optional
|
18
|
+
|
19
|
+
from jinja2 import Environment
|
20
|
+
from jinja2 import StrictUndefined
|
21
|
+
|
22
|
+
from ..colors import Color
|
23
|
+
from ..crypts import Hashes
|
24
|
+
from ..times import Duration
|
25
|
+
from ..times import Time
|
26
|
+
from ..types import DictStrAny
|
27
|
+
from ..types import fuzzy_list
|
28
|
+
from ..utils import fuzz_match
|
29
|
+
from ..utils import rgxp_match
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
FILTER = Callable[..., Any]
|
34
|
+
|
35
|
+
JINJA2 = (
|
36
|
+
r'(\{\{.+?\}\})|'
|
37
|
+
r'(\{\%.+?\%\})')
|
38
|
+
|
39
|
+
LITERAL = (
|
40
|
+
r'^((\{([^\{%].+?)?\})|(\[(.+?|)\])'
|
41
|
+
'|True|False|None|'
|
42
|
+
r'(\-?([1-9]\d*|0)(\.\d+)?))$')
|
43
|
+
|
44
|
+
DEFAULT: dict[str, FILTER] = {
|
45
|
+
'Duration': Duration,
|
46
|
+
'Color': Color,
|
47
|
+
'Hashes': Hashes,
|
48
|
+
'Time': Time,
|
49
|
+
'fuzz_match': fuzz_match,
|
50
|
+
'fuzzy_list': fuzzy_list,
|
51
|
+
'rgxp_match': rgxp_match}
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
class Jinja2:
|
56
|
+
"""
|
57
|
+
Parse the provided input and intelligently return value.
|
58
|
+
|
59
|
+
Example
|
60
|
+
-------
|
61
|
+
>>> jinja2 = Jinja2()
|
62
|
+
>>> jinja2.parse('{{ 0 | Time}}')
|
63
|
+
'1970-01-01T00:00:00.000000+0000'
|
64
|
+
|
65
|
+
:param statics: Additional values available for parsing.
|
66
|
+
:param filters: Additional filter functions for parsing.
|
67
|
+
"""
|
68
|
+
|
69
|
+
__statics: DictStrAny
|
70
|
+
__filters: dict[str, FILTER]
|
71
|
+
|
72
|
+
__jinjenv: Environment
|
73
|
+
|
74
|
+
|
75
|
+
def __init__(
|
76
|
+
self,
|
77
|
+
statics: Optional[DictStrAny] = None,
|
78
|
+
filters: Optional[dict[str, FILTER]] = None,
|
79
|
+
) -> None:
|
80
|
+
"""
|
81
|
+
Initialize instance for class using provided parameters.
|
82
|
+
"""
|
83
|
+
|
84
|
+
statics = dict(statics or {})
|
85
|
+
filters = dict(filters or {})
|
86
|
+
|
87
|
+
items = DEFAULT.items()
|
88
|
+
|
89
|
+
for key, filter in items:
|
90
|
+
filters[key] = filter
|
91
|
+
|
92
|
+
self.__statics = statics
|
93
|
+
self.__filters = filters
|
94
|
+
|
95
|
+
jinjenv = Environment(
|
96
|
+
auto_reload=False,
|
97
|
+
autoescape=False,
|
98
|
+
cache_size=0,
|
99
|
+
extensions=[
|
100
|
+
'jinja2.ext.i18n',
|
101
|
+
'jinja2.ext.loopcontrols',
|
102
|
+
'jinja2.ext.do'],
|
103
|
+
keep_trailing_newline=False,
|
104
|
+
lstrip_blocks=False,
|
105
|
+
newline_sequence='\n',
|
106
|
+
optimized=True,
|
107
|
+
trim_blocks=False,
|
108
|
+
undefined=StrictUndefined)
|
109
|
+
|
110
|
+
jinjenv.filters |= filters
|
111
|
+
|
112
|
+
self.__jinjenv = jinjenv
|
113
|
+
|
114
|
+
|
115
|
+
@property
|
116
|
+
def statics(
|
117
|
+
self,
|
118
|
+
) -> DictStrAny:
|
119
|
+
"""
|
120
|
+
Return the value for the attribute from class instance.
|
121
|
+
|
122
|
+
:returns: Value for the attribute from class instance.
|
123
|
+
"""
|
124
|
+
|
125
|
+
return dict(self.__statics)
|
126
|
+
|
127
|
+
|
128
|
+
@property
|
129
|
+
def filters(
|
130
|
+
self,
|
131
|
+
) -> dict[str, FILTER]:
|
132
|
+
"""
|
133
|
+
Return the value for the attribute from class instance.
|
134
|
+
|
135
|
+
:returns: Value for the attribute from class instance.
|
136
|
+
"""
|
137
|
+
|
138
|
+
return dict(self.__filters)
|
139
|
+
|
140
|
+
|
141
|
+
@property
|
142
|
+
def jinjenv(
|
143
|
+
self,
|
144
|
+
) -> Environment:
|
145
|
+
"""
|
146
|
+
Return the value for the attribute from class instance.
|
147
|
+
|
148
|
+
:returns: Value for the attribute from class instance.
|
149
|
+
"""
|
150
|
+
|
151
|
+
return self.__jinjenv
|
152
|
+
|
153
|
+
|
154
|
+
def parser(
|
155
|
+
self,
|
156
|
+
value: str,
|
157
|
+
statics: Optional[DictStrAny] = None,
|
158
|
+
) -> Any:
|
159
|
+
"""
|
160
|
+
Return the provided input using the Jinja2 environment.
|
161
|
+
|
162
|
+
:param value: Input that will be processed and returned.
|
163
|
+
:param statics: Additional values available for parsing.
|
164
|
+
:returns: Provided input using the Jinja2 environment.
|
165
|
+
"""
|
166
|
+
|
167
|
+
statics = statics or {}
|
168
|
+
|
169
|
+
parser = (
|
170
|
+
self.__jinjenv
|
171
|
+
.from_string)
|
172
|
+
|
173
|
+
rendered = (
|
174
|
+
parser(value)
|
175
|
+
.render(**statics))
|
176
|
+
|
177
|
+
return rendered
|
178
|
+
|
179
|
+
|
180
|
+
def parse( # noqa: CFQ004
|
181
|
+
self,
|
182
|
+
value: Any,
|
183
|
+
statics: Optional[DictStrAny] = None,
|
184
|
+
literal: bool = True,
|
185
|
+
) -> Any:
|
186
|
+
"""
|
187
|
+
Return the provided input using the Jinja2 environment.
|
188
|
+
|
189
|
+
:param value: Input that will be processed and returned.
|
190
|
+
:param statics: Additional values available for parsing.
|
191
|
+
:param literal: Determine if Python objects are evaled.
|
192
|
+
:returns: Provided input using the Jinja2 environment.
|
193
|
+
"""
|
194
|
+
|
195
|
+
|
196
|
+
def _final( # noqa: CFQ004
|
197
|
+
value: Any,
|
198
|
+
) -> Any:
|
199
|
+
|
200
|
+
if literal is False:
|
201
|
+
return value
|
202
|
+
|
203
|
+
match = re_match(
|
204
|
+
LITERAL, str(value))
|
205
|
+
|
206
|
+
if match is None:
|
207
|
+
return value
|
208
|
+
|
209
|
+
with suppress(Exception):
|
210
|
+
return leval(value)
|
211
|
+
|
212
|
+
return value
|
213
|
+
|
214
|
+
|
215
|
+
def _parse(
|
216
|
+
value: Any,
|
217
|
+
) -> Any:
|
218
|
+
|
219
|
+
return self.parse(
|
220
|
+
value,
|
221
|
+
statics, literal)
|
222
|
+
|
223
|
+
|
224
|
+
def _parser(
|
225
|
+
value: Any,
|
226
|
+
) -> Any:
|
227
|
+
|
228
|
+
parsed = self.parser(
|
229
|
+
value, statics)
|
230
|
+
|
231
|
+
return _final(parsed)
|
232
|
+
|
233
|
+
|
234
|
+
def _found(
|
235
|
+
value: Any,
|
236
|
+
) -> list[Any]:
|
237
|
+
|
238
|
+
value = str(value)
|
239
|
+
|
240
|
+
return re_findall(
|
241
|
+
JINJA2, value, DOTALL)
|
242
|
+
|
243
|
+
|
244
|
+
if not len(_found(value)):
|
245
|
+
return _final(value)
|
246
|
+
|
247
|
+
|
248
|
+
with suppress(Exception):
|
249
|
+
value = _final(value)
|
250
|
+
|
251
|
+
|
252
|
+
if isinstance(value, dict):
|
253
|
+
|
254
|
+
value = dict(value)
|
255
|
+
|
256
|
+
items = value.items()
|
257
|
+
|
258
|
+
for key, _value in items:
|
259
|
+
|
260
|
+
_value = _parse(_value)
|
261
|
+
|
262
|
+
value[key] = _value
|
263
|
+
|
264
|
+
|
265
|
+
elif isinstance(value, list):
|
266
|
+
|
267
|
+
value = list(value)
|
268
|
+
|
269
|
+
values = enumerate(value)
|
270
|
+
|
271
|
+
for idx, _value in values:
|
272
|
+
|
273
|
+
_value = _parse(_value)
|
274
|
+
|
275
|
+
value[idx] = _value
|
276
|
+
|
277
|
+
|
278
|
+
elif value is not None:
|
279
|
+
value = _parser(value)
|
280
|
+
|
281
|
+
|
282
|
+
return value
|