nettoolkit 0.0.3__zip
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.
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/__init__.py +49 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/__pycache__/__init__.cpython-38.pyc +0 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/__pycache__/addressing.cpython-38.pyc +0 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/__pycache__/gpl.cpython-38.pyc +0 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/__pycache__/hierarchy.cpython-38.pyc +0 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/__pycache__/hierarchy_rules.cpython-38.pyc +0 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/__pycache__/jset.cpython-38.pyc +0 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/addressing.py +920 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/gpl.py +1207 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/hierarchy.py +558 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/hierarchy_rules.py +229 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit/jset.py +109 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit-0.0.3-py3.8.egg-info/PKG-INFO +41 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit-0.0.3-py3.8.egg-info/SOURCES.txt +12 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit-0.0.3-py3.8.egg-info/dependency_links.txt +1 -0
- Users/ALI/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/nettoolkit-0.0.3-py3.8.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,1207 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------
|
|
2
|
+
# IMPORTS
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
from inspect import signature
|
|
5
|
+
|
|
6
|
+
import pandas as pd
|
|
7
|
+
|
|
8
|
+
from abc import ABC, abstractproperty, abstractclassmethod
|
|
9
|
+
import datetime
|
|
10
|
+
from re import compile
|
|
11
|
+
from collections import OrderedDict
|
|
12
|
+
from os import popen
|
|
13
|
+
import os
|
|
14
|
+
import threading
|
|
15
|
+
|
|
16
|
+
intBeginWith = compile(r'^\D+')
|
|
17
|
+
|
|
18
|
+
# -----------------------------------------------------------------------------
|
|
19
|
+
# Common Classes #
|
|
20
|
+
# -----------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
class Default():
|
|
23
|
+
"""Default docString"""
|
|
24
|
+
def __str__(self): return self.__doc__
|
|
25
|
+
def _repr(self):
|
|
26
|
+
fields = signature(self.__init__).parameters
|
|
27
|
+
values = ", ".join(repr(getattr(self, f)) for f in fields)
|
|
28
|
+
return f'{type(self).__name__}({values})'
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Container(ABC):
|
|
33
|
+
"""Support Containers callable objects
|
|
34
|
+
object should contain objVar property
|
|
35
|
+
"""
|
|
36
|
+
@abstractproperty
|
|
37
|
+
@property
|
|
38
|
+
def objVar(self): pass
|
|
39
|
+
def __bool__(self): return True if self.objVar else False
|
|
40
|
+
def __len__(self): return len(self.objVar)
|
|
41
|
+
def __dir__(self): return self.objVar # sorted
|
|
42
|
+
def __getitem__(self, i): return self.objVar[i]
|
|
43
|
+
def __setitem__(self, i, v): self.objVar[i] = v
|
|
44
|
+
def __delitem__(self, i): del(self.objVar[i])
|
|
45
|
+
def __contains__(self, i): return i in self.objVar
|
|
46
|
+
def __reversed__(self): return reversed(self.objVar)
|
|
47
|
+
def __missing__(self, i): raise Exception(f'key {i} unavailable') # only for dict subclass
|
|
48
|
+
def __iter__(self):
|
|
49
|
+
if isinstance(self.objVar, (list, tuple, set, str)):
|
|
50
|
+
for line in self.objVar:
|
|
51
|
+
yield line
|
|
52
|
+
elif isinstance(self.objVar, (dict, OrderedDict)):
|
|
53
|
+
for key, value in self.objVar.items():
|
|
54
|
+
yield (key, value)
|
|
55
|
+
|
|
56
|
+
## TBD / NOT IMPLEMENTED YET ##
|
|
57
|
+
class Numeric():
|
|
58
|
+
"""Support Numberic objects"""
|
|
59
|
+
def __add__(self): pass
|
|
60
|
+
def __sub__(self): pass
|
|
61
|
+
def __mul__(self): pass
|
|
62
|
+
def __truediv__(self): pass
|
|
63
|
+
def __floordiv__(self): pass
|
|
64
|
+
def __pow__(self): pass
|
|
65
|
+
def __lshift__(self): pass
|
|
66
|
+
def __rshift__(self): pass
|
|
67
|
+
def __and__(self): pass
|
|
68
|
+
def __xor__(self): pass
|
|
69
|
+
def __or__(self): pass
|
|
70
|
+
|
|
71
|
+
def __iadd__(self): pass
|
|
72
|
+
def __isub__(self): pass
|
|
73
|
+
def __imul__(self): pass
|
|
74
|
+
def __itruediv__(self): pass
|
|
75
|
+
def __ifloordiv__(self): pass
|
|
76
|
+
def __ipow__(self): pass
|
|
77
|
+
def __ilshift__(self): pass
|
|
78
|
+
def __irshift__(self): pass
|
|
79
|
+
def __iand__(self): pass
|
|
80
|
+
def __ixor__(self): pass
|
|
81
|
+
def __ior__(self): pass
|
|
82
|
+
|
|
83
|
+
def __neg__(self): pass
|
|
84
|
+
def __pos__(self): pass
|
|
85
|
+
def __abs__(self): pass
|
|
86
|
+
def __invert__(self): pass
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# -----------------------------------------------------------------------------
|
|
90
|
+
# STRING OPERATIONS #
|
|
91
|
+
# -----------------------------------------------------------------------------
|
|
92
|
+
class STR(Container):
|
|
93
|
+
|
|
94
|
+
@staticmethod
|
|
95
|
+
def foundPos(s, sub, pos=0):
|
|
96
|
+
'''Search for substring in string and return index value result
|
|
97
|
+
--> int
|
|
98
|
+
|
|
99
|
+
:param s: main string to be search within
|
|
100
|
+
:type s: str
|
|
101
|
+
|
|
102
|
+
:param sub: substring which is to be search in to main string
|
|
103
|
+
:type sub: str
|
|
104
|
+
|
|
105
|
+
:param pos: position index, search to be start from
|
|
106
|
+
:type pos: int
|
|
107
|
+
'''
|
|
108
|
+
return s.find(sub, pos)
|
|
109
|
+
|
|
110
|
+
@staticmethod
|
|
111
|
+
def found(s, sub, pos=0):
|
|
112
|
+
'''Search for substring in string and return Boolean result
|
|
113
|
+
--> bool
|
|
114
|
+
|
|
115
|
+
:param s: main string to be search within
|
|
116
|
+
:type s: str
|
|
117
|
+
|
|
118
|
+
:param sub: substring which is to be search in to main string
|
|
119
|
+
:type sub: str
|
|
120
|
+
|
|
121
|
+
:param pos: position index, search to be start from
|
|
122
|
+
:type pos: int
|
|
123
|
+
'''
|
|
124
|
+
try:
|
|
125
|
+
return True if s.find(sub, pos) > -1 else False
|
|
126
|
+
except:
|
|
127
|
+
return False
|
|
128
|
+
|
|
129
|
+
@staticmethod
|
|
130
|
+
def find_within(s, prefix, suffix=None, pos=0):
|
|
131
|
+
'''finds characters between prefix and suffix substrings from string,
|
|
132
|
+
--> tuple: (str, int)
|
|
133
|
+
|
|
134
|
+
:param s: main string to be search within
|
|
135
|
+
:type s: str
|
|
136
|
+
|
|
137
|
+
:param prefix: starting substring
|
|
138
|
+
:type prefix: str
|
|
139
|
+
|
|
140
|
+
:param suffix: ending substring
|
|
141
|
+
:type suffix: str
|
|
142
|
+
|
|
143
|
+
:param pos: position index, search to be start from
|
|
144
|
+
:type pos: int
|
|
145
|
+
|
|
146
|
+
-->Tuple
|
|
147
|
+
--------
|
|
148
|
+
index-0 is returned string
|
|
149
|
+
index-1 is position of returned suffix position
|
|
150
|
+
'''
|
|
151
|
+
p = STR.foundPos(s, prefix, pos=pos)+len(prefix)
|
|
152
|
+
if suffix is None:
|
|
153
|
+
ln = len(s)
|
|
154
|
+
else:
|
|
155
|
+
ln = STR.foundPos(s, suffix, pos=p+1)
|
|
156
|
+
if p == -1:
|
|
157
|
+
return None
|
|
158
|
+
if ln == -1:
|
|
159
|
+
ln = len(s)
|
|
160
|
+
return (s[p:ln], ln)
|
|
161
|
+
|
|
162
|
+
@staticmethod
|
|
163
|
+
def string_within(line, prefix, suffix=None, pos=0):
|
|
164
|
+
'''finds characters between prefix and suffix substrings from string,
|
|
165
|
+
--> str
|
|
166
|
+
|
|
167
|
+
:param s: main string to be search within
|
|
168
|
+
:type s: str
|
|
169
|
+
|
|
170
|
+
:param prefix: starting substring
|
|
171
|
+
:type prefix: str
|
|
172
|
+
|
|
173
|
+
:param suffix: ending substring
|
|
174
|
+
:type suffix: str
|
|
175
|
+
|
|
176
|
+
:param pos: position index, search to be start from
|
|
177
|
+
:type pos: int
|
|
178
|
+
'''
|
|
179
|
+
return STR.find_within(line, prefix, suffix, pos)[0]
|
|
180
|
+
|
|
181
|
+
@staticmethod
|
|
182
|
+
def suffix_index_within(line, prefix, suffix=None, pos=0):
|
|
183
|
+
'''finds characters between prefix and suffix substrings from string,
|
|
184
|
+
--> int: index of suffix
|
|
185
|
+
|
|
186
|
+
:param s: main string to be search within
|
|
187
|
+
:type s: str
|
|
188
|
+
|
|
189
|
+
:param prefix: starting substring
|
|
190
|
+
:type prefix: str
|
|
191
|
+
|
|
192
|
+
:param suffix: ending substring
|
|
193
|
+
:type suffix: str
|
|
194
|
+
|
|
195
|
+
:param pos: position index, search to be start from
|
|
196
|
+
:type pos: int
|
|
197
|
+
'''
|
|
198
|
+
return STR.find_within(line, prefix, suffix, pos)[1]
|
|
199
|
+
|
|
200
|
+
@staticmethod
|
|
201
|
+
def find_multi(s, sub, start=0, count=None, index=True, beginwith=False):
|
|
202
|
+
'''search for multiple substrings 'sub' within string 's'
|
|
203
|
+
usage: find_multi(s, sub, [start=n, [count=c], index=True])
|
|
204
|
+
--> list of indexes/bool
|
|
205
|
+
|
|
206
|
+
:param s: main string
|
|
207
|
+
:type s: str
|
|
208
|
+
|
|
209
|
+
:param sub: sub string ( to be search within main string )
|
|
210
|
+
:type sub: (str, tuple, list)
|
|
211
|
+
|
|
212
|
+
:param start: Optional: substring to be start search from index (def:0)
|
|
213
|
+
:type start: int
|
|
214
|
+
|
|
215
|
+
:param count: Optional: count of character from start index (def:end)
|
|
216
|
+
:type count: int
|
|
217
|
+
|
|
218
|
+
:param index: Optional: return index or boolean values(def:True=Index)
|
|
219
|
+
:type index: bool
|
|
220
|
+
'''
|
|
221
|
+
count = len(s) if count is None else count+start
|
|
222
|
+
if isinstance(sub, str):
|
|
223
|
+
i = s.find(sub, start, count)
|
|
224
|
+
if index:
|
|
225
|
+
if beginwith:
|
|
226
|
+
return i if i == 0 else -1
|
|
227
|
+
else:
|
|
228
|
+
return i
|
|
229
|
+
else:
|
|
230
|
+
if beginwith:
|
|
231
|
+
return True if i == 0 else False
|
|
232
|
+
else:
|
|
233
|
+
return False if i == -1 else True
|
|
234
|
+
elif isinstance(sub, (tuple, list)):
|
|
235
|
+
sl = []
|
|
236
|
+
for x in sub:
|
|
237
|
+
sl.append(STR.find_multi(s, x, start, count, index, beginwith))
|
|
238
|
+
return sl
|
|
239
|
+
else:
|
|
240
|
+
return None
|
|
241
|
+
|
|
242
|
+
@staticmethod
|
|
243
|
+
def find_all(s, sub, start=0, count=None, beginwith=False):
|
|
244
|
+
'''search for multiple substrings 'sub' within string 's'
|
|
245
|
+
usage: find_all(s, sub, [start=n, [count=c]])
|
|
246
|
+
--> (all matches) -> bool
|
|
247
|
+
|
|
248
|
+
:param s: main string
|
|
249
|
+
:type s: str
|
|
250
|
+
|
|
251
|
+
:param sub: sub string ( to be search within main string )
|
|
252
|
+
:type sub: (str, tuple, list)
|
|
253
|
+
|
|
254
|
+
:param start: Optional: substring to be start search from index (def:0)
|
|
255
|
+
:type start: int
|
|
256
|
+
|
|
257
|
+
:param count: Optional: count of character from start index (def:end)
|
|
258
|
+
:type count: int
|
|
259
|
+
'''
|
|
260
|
+
sl = STR.find_multi(s, sub, start, count, False, beginwith)
|
|
261
|
+
try:
|
|
262
|
+
return False if False in sl else True
|
|
263
|
+
except:
|
|
264
|
+
return sl
|
|
265
|
+
|
|
266
|
+
@staticmethod
|
|
267
|
+
def find_any(s, sub, start=0, count=None, beginwith=False):
|
|
268
|
+
'''search for multiple substrings 'sub' within string 's'
|
|
269
|
+
usage: find_any(s, sub, [start=n, [count=c]])
|
|
270
|
+
--> (any matches) -> bool
|
|
271
|
+
|
|
272
|
+
:param s: main string
|
|
273
|
+
:type s: str
|
|
274
|
+
|
|
275
|
+
:param sub: sub string ( to be search within main string )
|
|
276
|
+
:type sub: (str, tuple, list)
|
|
277
|
+
|
|
278
|
+
:param start: Optional: substring to be start search from index (def:0)
|
|
279
|
+
:type start: int
|
|
280
|
+
|
|
281
|
+
:param count: Optional: count of character from start index (def:end)
|
|
282
|
+
:type count: int
|
|
283
|
+
'''
|
|
284
|
+
sl = STR.find_multi(s, sub, start, count, False, beginwith)
|
|
285
|
+
try:
|
|
286
|
+
return True if True in sl else False
|
|
287
|
+
except:
|
|
288
|
+
return sl
|
|
289
|
+
|
|
290
|
+
@staticmethod
|
|
291
|
+
def update(s, searchItem='', replaceItem=''):
|
|
292
|
+
'''Updates string for search item with replace item
|
|
293
|
+
--> str
|
|
294
|
+
|
|
295
|
+
:param s: main string
|
|
296
|
+
:type s: str
|
|
297
|
+
|
|
298
|
+
:param searchItem: search string
|
|
299
|
+
:type searchItem: str
|
|
300
|
+
|
|
301
|
+
:param replaceItem: replace string
|
|
302
|
+
:type replaceItem: str '''
|
|
303
|
+
return s.replace(searchItem, replaceItem)
|
|
304
|
+
|
|
305
|
+
@staticmethod
|
|
306
|
+
def replace_dual_and_split(s, duo=' ', strip=None):
|
|
307
|
+
'''Finds subsequent characters in string and replace those with single,
|
|
308
|
+
plus, splits the string using provided character (duo).
|
|
309
|
+
--> list
|
|
310
|
+
|
|
311
|
+
:param s: Source string
|
|
312
|
+
:type s: str
|
|
313
|
+
|
|
314
|
+
:param duo:characters which requires reductions if susequent
|
|
315
|
+
:type duo: str
|
|
316
|
+
|
|
317
|
+
:param strip: values (-1=lstrip ,0=strip ,1=rstrip) - def:None
|
|
318
|
+
:type strip: int
|
|
319
|
+
'''
|
|
320
|
+
return STR.finddualnreplacesingle(s, strip=0).split(duo)
|
|
321
|
+
|
|
322
|
+
@staticmethod
|
|
323
|
+
def finddualnreplacesingle(s, duo=' ', strip=None):
|
|
324
|
+
'''Finds subsequent characters in string and replace those with single.
|
|
325
|
+
--> str
|
|
326
|
+
|
|
327
|
+
:param s: Source string
|
|
328
|
+
:type s: str
|
|
329
|
+
|
|
330
|
+
:param duo: characters which requires reductions if susequent
|
|
331
|
+
:type duo: str
|
|
332
|
+
|
|
333
|
+
:param strip: values (-1=lstrip ,0=strip ,1=rstrip) - def:None
|
|
334
|
+
:type strip: int
|
|
335
|
+
'''
|
|
336
|
+
while s.find(duo+duo) > -1:
|
|
337
|
+
s = s.replace(duo+duo, duo)
|
|
338
|
+
if strip is not None and isinstance(strip, int):
|
|
339
|
+
if strip == -1:
|
|
340
|
+
return s.lstrip()
|
|
341
|
+
elif strip == 0:
|
|
342
|
+
return s.strip()
|
|
343
|
+
elif strip == 1:
|
|
344
|
+
return s.rstrip()
|
|
345
|
+
else:
|
|
346
|
+
print('invalid strip value detected', strip)
|
|
347
|
+
else:
|
|
348
|
+
print('invalid strip value detected', strip)
|
|
349
|
+
return s
|
|
350
|
+
|
|
351
|
+
@staticmethod
|
|
352
|
+
def indention(s):
|
|
353
|
+
'''get string indention value
|
|
354
|
+
--> int
|
|
355
|
+
|
|
356
|
+
:param s: string
|
|
357
|
+
:type s: str
|
|
358
|
+
'''
|
|
359
|
+
return len(s)-len(s.lstrip())
|
|
360
|
+
|
|
361
|
+
@staticmethod
|
|
362
|
+
def is_blank_line(s):
|
|
363
|
+
'''Is provided string/line a blank line
|
|
364
|
+
---> bool
|
|
365
|
+
|
|
366
|
+
:param s: string
|
|
367
|
+
:type s: str
|
|
368
|
+
'''
|
|
369
|
+
try:
|
|
370
|
+
return True if len(s.strip()) == 0 else False
|
|
371
|
+
except Exception: pass
|
|
372
|
+
|
|
373
|
+
@staticmethod
|
|
374
|
+
def is_hostname_line(s, host):
|
|
375
|
+
'''string/line containing hostname of device
|
|
376
|
+
-->bool
|
|
377
|
+
|
|
378
|
+
:param s: string
|
|
379
|
+
:type s: str
|
|
380
|
+
|
|
381
|
+
:param host: hostname to be find in provided string
|
|
382
|
+
:type host: str
|
|
383
|
+
'''
|
|
384
|
+
return s.find(host) == 0
|
|
385
|
+
|
|
386
|
+
@staticmethod
|
|
387
|
+
def hostname(net_connect):
|
|
388
|
+
'''Hostname from connection'''
|
|
389
|
+
try:
|
|
390
|
+
hns = net_connect.find_prompt()[:-1]
|
|
391
|
+
atPos = STR.foundPos(hns, "@")
|
|
392
|
+
if atPos > -1: hns = hns[atPos+1:]
|
|
393
|
+
return hns
|
|
394
|
+
except:
|
|
395
|
+
pass
|
|
396
|
+
|
|
397
|
+
@staticmethod
|
|
398
|
+
def hostname_from_cli(line, command):
|
|
399
|
+
'''hostname from command line'''
|
|
400
|
+
if not STR.found(line, command): return None
|
|
401
|
+
cmdPos = STR.foundPos(line, command)
|
|
402
|
+
hn = line[:cmdPos].strip()[:-1]
|
|
403
|
+
return hn
|
|
404
|
+
|
|
405
|
+
@staticmethod
|
|
406
|
+
def shrink_if(intName, length=2):
|
|
407
|
+
'''Interface Name shortening for standard 2 Characters '''
|
|
408
|
+
iBW = intBeginWith.match(intName)
|
|
409
|
+
return iBW.group()[:length]+intName[iBW.span()[1]:]
|
|
410
|
+
|
|
411
|
+
@staticmethod
|
|
412
|
+
def if_prefix(intName):
|
|
413
|
+
'''Interface beginning Name'''
|
|
414
|
+
iBW = intBeginWith.match(intName)
|
|
415
|
+
return intName[iBW.start(): iBW.end()]
|
|
416
|
+
|
|
417
|
+
@staticmethod
|
|
418
|
+
def update_str(s, searchItem='', replaceItem=''):
|
|
419
|
+
'''Updates line for search item with replace item'''
|
|
420
|
+
return s.replace(searchItem, replaceItem)
|
|
421
|
+
|
|
422
|
+
@staticmethod
|
|
423
|
+
def get_logfile_name(folder, hn, cmd='', ts='', separator="_@_"):
|
|
424
|
+
'''return log file name for the command on device with/wo provided time_stamp'''
|
|
425
|
+
if ts: ts = separator + ts
|
|
426
|
+
if cmd:
|
|
427
|
+
cmd += ts
|
|
428
|
+
replaceCandidates = ('|', '\\', '/', ':', '*', '?', '"', '<', '>')
|
|
429
|
+
for x in replaceCandidates:
|
|
430
|
+
cmd = STR.update_str(cmd, x, "_")
|
|
431
|
+
cmd = separator + cmd
|
|
432
|
+
return folder+hn+cmd+'.log'
|
|
433
|
+
|
|
434
|
+
@staticmethod
|
|
435
|
+
def string_concate(s, s1, conj=''):
|
|
436
|
+
'''Concatenate strings s and s1 with conjuctor conj
|
|
437
|
+
|
|
438
|
+
:param s: string
|
|
439
|
+
:type s: str
|
|
440
|
+
|
|
441
|
+
:param s1: adder string
|
|
442
|
+
:type s1: string
|
|
443
|
+
|
|
444
|
+
:param conj: conjuctor
|
|
445
|
+
:type conj: string
|
|
446
|
+
'''
|
|
447
|
+
if s == '':
|
|
448
|
+
s = s + s1
|
|
449
|
+
else:
|
|
450
|
+
s = s + conj + s1
|
|
451
|
+
return s
|
|
452
|
+
|
|
453
|
+
@staticmethod
|
|
454
|
+
def right(strg, n):
|
|
455
|
+
'''N-number of characters from right side of string
|
|
456
|
+
--> str
|
|
457
|
+
|
|
458
|
+
:param strg: string
|
|
459
|
+
:type strg: str
|
|
460
|
+
|
|
461
|
+
:param n: number of characters from right
|
|
462
|
+
:type n: int
|
|
463
|
+
'''
|
|
464
|
+
l = len(strg)
|
|
465
|
+
return strg[l-n:l]
|
|
466
|
+
|
|
467
|
+
@staticmethod
|
|
468
|
+
def mid(strg, pos, n=0):
|
|
469
|
+
'''N-number of characters from position in string; default n is till end
|
|
470
|
+
-->str
|
|
471
|
+
:param strg: string
|
|
472
|
+
:type strg: str
|
|
473
|
+
|
|
474
|
+
:param pos: position from where slice to begin
|
|
475
|
+
:type pos: int
|
|
476
|
+
|
|
477
|
+
:param n: number of characters from slice(pos)
|
|
478
|
+
:type n: int
|
|
479
|
+
'''
|
|
480
|
+
l = len(strg)
|
|
481
|
+
if n > 0 :
|
|
482
|
+
return strg[pos-1:pos+n-1]
|
|
483
|
+
else:
|
|
484
|
+
return strg[pos-1:]
|
|
485
|
+
|
|
486
|
+
@staticmethod
|
|
487
|
+
def delete_trailing_remarks(s):
|
|
488
|
+
'''Deletes trailing remarks from Juniper config line/string
|
|
489
|
+
-->str
|
|
490
|
+
:param s: number of characters from right
|
|
491
|
+
:type s: str
|
|
492
|
+
'''
|
|
493
|
+
if s.find("##") > 0:
|
|
494
|
+
s = s[:s.find("##")].rstrip()
|
|
495
|
+
return s.rstrip()
|
|
496
|
+
endingpos = STR.foundPos(s, ";")
|
|
497
|
+
if endingpos < 0: endingpos = STR.foundPos(s, "{")
|
|
498
|
+
if endingpos < 0: endingpos = STR.foundPos(s, "}")
|
|
499
|
+
if endingpos > -1: return s[:endingpos+1]
|
|
500
|
+
return s.rstrip()
|
|
501
|
+
|
|
502
|
+
@staticmethod
|
|
503
|
+
def to_list(s):
|
|
504
|
+
'''Returns list for the provided string - s, split by lines '''
|
|
505
|
+
s = s.split("\n")
|
|
506
|
+
for i, x in enumerate(s):
|
|
507
|
+
s[i] = x + "\n"
|
|
508
|
+
return s
|
|
509
|
+
# return s.split("\n")
|
|
510
|
+
|
|
511
|
+
@staticmethod
|
|
512
|
+
def to_set(s):
|
|
513
|
+
'''return set of values for 'ipList' key from dictionary
|
|
514
|
+
'''
|
|
515
|
+
if isinstance(s, str):
|
|
516
|
+
_s = []
|
|
517
|
+
for _ in s.split('\n'):
|
|
518
|
+
_s.extend(_.split(','))
|
|
519
|
+
return set(LST.remove_empty_members((_s)))
|
|
520
|
+
else:
|
|
521
|
+
return set(s)
|
|
522
|
+
|
|
523
|
+
@staticmethod
|
|
524
|
+
def header_indexes(line):
|
|
525
|
+
exceptional_headers = {'Type', }
|
|
526
|
+
headers = OrderedDict()
|
|
527
|
+
prev_k = None
|
|
528
|
+
for k in STR.replace_dual_and_split(line.rstrip()):
|
|
529
|
+
k = k.strip()
|
|
530
|
+
key = k
|
|
531
|
+
if key in exceptional_headers: key = "__"+key
|
|
532
|
+
headers[key] = [STR.foundPos(line, k), None]
|
|
533
|
+
if prev_k is not None:
|
|
534
|
+
headers[prev_k][1] = STR.foundPos(line, k)
|
|
535
|
+
prev_k = key
|
|
536
|
+
headers[key][1] = 90
|
|
537
|
+
return headers
|
|
538
|
+
|
|
539
|
+
@staticmethod
|
|
540
|
+
def prepend_bgp_as(bgp_as, n):
|
|
541
|
+
s = ''
|
|
542
|
+
for x in range(n): s += str(bgp_as) + " "
|
|
543
|
+
return s[:-1]
|
|
544
|
+
|
|
545
|
+
@staticmethod
|
|
546
|
+
def ending(line, c): return line.strip().endswith(c)
|
|
547
|
+
|
|
548
|
+
@staticmethod
|
|
549
|
+
def starting(line, c): return line.strip().startswith(c)
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
# -----------------------------------------------------------------------------
|
|
553
|
+
# FILE OPERATIONS/ CONVERSIONS #
|
|
554
|
+
# -----------------------------------------------------------------------------
|
|
555
|
+
class IO():
|
|
556
|
+
|
|
557
|
+
@staticmethod
|
|
558
|
+
def file_list_for_time_stamp(hn, ts, folder, splitter="_@_" ):
|
|
559
|
+
files = set()
|
|
560
|
+
for file in os.listdir(folder):
|
|
561
|
+
if not splitter in file: continue
|
|
562
|
+
if hn in file and ts in file:
|
|
563
|
+
files.add(file)
|
|
564
|
+
return files
|
|
565
|
+
|
|
566
|
+
@staticmethod
|
|
567
|
+
def devices_on_log_files(folder, splitter="_@_"):
|
|
568
|
+
devices = set()
|
|
569
|
+
for file in os.listdir(folder):
|
|
570
|
+
if not splitter in file: continue
|
|
571
|
+
hn = file.split(splitter)
|
|
572
|
+
if hn[0][-4:] == '.log': hn[0] = hn[0][:-4]
|
|
573
|
+
devices.add(hn[0])
|
|
574
|
+
return devices
|
|
575
|
+
|
|
576
|
+
@staticmethod
|
|
577
|
+
def timestamps_for_device(devname, folder, splitter="_@_"):
|
|
578
|
+
stamps = set()
|
|
579
|
+
for file in os.listdir(folder):
|
|
580
|
+
if not splitter in file: continue
|
|
581
|
+
if devname in file:
|
|
582
|
+
stamp = file.split(splitter)
|
|
583
|
+
if stamp[-1][-4:] == '.log': stamp[-1] = stamp[-1][:-4]
|
|
584
|
+
stamps.add(stamp[-1])
|
|
585
|
+
return stamps
|
|
586
|
+
|
|
587
|
+
@staticmethod
|
|
588
|
+
def file_to_str(file):
|
|
589
|
+
'''Returns string output for the provided file
|
|
590
|
+
--> str
|
|
591
|
+
|
|
592
|
+
:param file: text input file name/with path
|
|
593
|
+
:type file: str
|
|
594
|
+
'''
|
|
595
|
+
with open(file, 'r') as f:
|
|
596
|
+
s = f.read()
|
|
597
|
+
return s
|
|
598
|
+
|
|
599
|
+
@staticmethod
|
|
600
|
+
def file_to_list(file):
|
|
601
|
+
'''Returns list for the provided file
|
|
602
|
+
--> list
|
|
603
|
+
|
|
604
|
+
:param file: text input file name/with path
|
|
605
|
+
:type file: str
|
|
606
|
+
'''
|
|
607
|
+
file = file.strip()
|
|
608
|
+
if file is None: return None
|
|
609
|
+
with open(file, 'r') as f:
|
|
610
|
+
lines = f.readlines()
|
|
611
|
+
return lines
|
|
612
|
+
|
|
613
|
+
@staticmethod
|
|
614
|
+
def csv_to_tuple(csv):
|
|
615
|
+
'''Returns tuple from the provided comma separated text values
|
|
616
|
+
--> tuple
|
|
617
|
+
|
|
618
|
+
:param csv: comma separated value
|
|
619
|
+
:type csv: str
|
|
620
|
+
'''
|
|
621
|
+
if csv.find('"') and not csv.find('\"'):
|
|
622
|
+
ln = csv.lstrip().split('"')
|
|
623
|
+
return tuple([x for i, x in enumerate(ln) if i % 2 != 0])
|
|
624
|
+
else:
|
|
625
|
+
return tuple(csv.split(','))
|
|
626
|
+
|
|
627
|
+
@staticmethod
|
|
628
|
+
def to_file(filename, matter):
|
|
629
|
+
'''Creates a file with matter
|
|
630
|
+
--> None
|
|
631
|
+
|
|
632
|
+
:param filename: filename with path to be creaed.
|
|
633
|
+
:type filename: str
|
|
634
|
+
|
|
635
|
+
:param matter: matter to write to new created file.
|
|
636
|
+
:type matter: str, list, tuple
|
|
637
|
+
'''
|
|
638
|
+
with open(filename, 'w') as f:
|
|
639
|
+
if isinstance(matter, str):
|
|
640
|
+
f.write(matter)
|
|
641
|
+
elif isinstance(matter, (list, tuple, set)):
|
|
642
|
+
f.write("\n".join(matter))
|
|
643
|
+
|
|
644
|
+
@staticmethod
|
|
645
|
+
def add_to_file(filename, matter, cr=True):
|
|
646
|
+
'''Writes List/text to output filename.
|
|
647
|
+
--> None
|
|
648
|
+
:param filename: Existing filename with path
|
|
649
|
+
:type filename: str
|
|
650
|
+
|
|
651
|
+
:param matter: matter to write to new created file.
|
|
652
|
+
:type matter: str, tuple, list
|
|
653
|
+
|
|
654
|
+
:param cr: carriage return to add at end of each string/line.(default True)
|
|
655
|
+
:type cr: bool
|
|
656
|
+
'''
|
|
657
|
+
if filename != '':
|
|
658
|
+
if isinstance(matter, str):
|
|
659
|
+
if cr and matter and matter[-1] != "\n": matter += "\n"
|
|
660
|
+
with open(filename, 'a') as f:
|
|
661
|
+
f.write(matter)
|
|
662
|
+
elif isinstance(matter, (list, tuple ,set)):
|
|
663
|
+
for i in matter:
|
|
664
|
+
IO.add_to_file(filename, i)
|
|
665
|
+
|
|
666
|
+
@staticmethod
|
|
667
|
+
def update(file, find_item, replace_item):
|
|
668
|
+
'''
|
|
669
|
+
Find and Replace on provided file and saves file
|
|
670
|
+
---> None
|
|
671
|
+
:param file: on which find and replace to be apply
|
|
672
|
+
:type str:
|
|
673
|
+
|
|
674
|
+
:param find_item: Search item
|
|
675
|
+
:type str:
|
|
676
|
+
|
|
677
|
+
:param replace_item: Repalce item for the matched find_item
|
|
678
|
+
:type str:
|
|
679
|
+
|
|
680
|
+
'''
|
|
681
|
+
with open(file, 'r') as f:
|
|
682
|
+
filedata = f.read()
|
|
683
|
+
replace_item = str(replace_item)
|
|
684
|
+
if replace_item == 'nan': replace_item = ''
|
|
685
|
+
newdata = filedata.replace(find_item, str(replace_item))
|
|
686
|
+
with open(file, 'w') as f:
|
|
687
|
+
f.write(newdata)
|
|
688
|
+
|
|
689
|
+
@staticmethod
|
|
690
|
+
def jinja_verification(folder):
|
|
691
|
+
s = ''
|
|
692
|
+
for file in os.listdir(folder):
|
|
693
|
+
goahead = {'GOAHEAD FOR': 0, 'GOAHEAD END': 0,}
|
|
694
|
+
repeatfor = {'REPEAT EACH': 0, 'REPEAT STOP': 0,}
|
|
695
|
+
if not file.endswith(".txt"): continue
|
|
696
|
+
with open(folder + "/" + file, 'r') as f:
|
|
697
|
+
rf = f.read()
|
|
698
|
+
for k, v in goahead.items(): goahead[k] = rf.count(k)
|
|
699
|
+
for k, v in repeatfor.items(): repeatfor[k] = rf.count(k)
|
|
700
|
+
bg, eg = goahead['GOAHEAD FOR'], goahead['GOAHEAD END']
|
|
701
|
+
br, er = repeatfor['REPEAT EACH'], repeatfor['REPEAT STOP']
|
|
702
|
+
if bg != eg or br != er: s += f'Descrepencies found in file: <{file}>\n'
|
|
703
|
+
if bg != eg: s += f"\tGOAHEAD conditions : begins {bg} v/s ends {eg}\n"
|
|
704
|
+
if br != er: s += f"\tREPEAT conditions : begins {br} v/s ends {er}\n\n"
|
|
705
|
+
return s
|
|
706
|
+
|
|
707
|
+
# -----------------------------------------------------------------------------
|
|
708
|
+
# LIST MODIFICATIONS #
|
|
709
|
+
# -----------------------------------------------------------------------------
|
|
710
|
+
|
|
711
|
+
class LST():
|
|
712
|
+
|
|
713
|
+
@staticmethod
|
|
714
|
+
def remove_empty_members(lst):
|
|
715
|
+
empty_members = ('', None, 'N/A', 'nil')
|
|
716
|
+
tmp_lst = [m for m in lst if not m in empty_members]
|
|
717
|
+
return tmp_lst
|
|
718
|
+
|
|
719
|
+
@staticmethod
|
|
720
|
+
def convert_vlans_list_to_range_of_vlans_list(vlan_list):
|
|
721
|
+
vlan_list = sorted(vlan_list)
|
|
722
|
+
vlan_list.append(None)
|
|
723
|
+
range_list, previous_vlan = [], 0
|
|
724
|
+
range_begin, range_end = None, None
|
|
725
|
+
for vlan in vlan_list:
|
|
726
|
+
if previous_vlan + 1 == vlan:
|
|
727
|
+
if not range_begin: range_begin = str(previous_vlan) + "-"
|
|
728
|
+
elif range_begin:
|
|
729
|
+
range_end = previous_vlan
|
|
730
|
+
rangeStr = range_begin + str(range_end)
|
|
731
|
+
range_begin = None
|
|
732
|
+
range_list.append(rangeStr)
|
|
733
|
+
elif previous_vlan:
|
|
734
|
+
range_list.append(previous_vlan)
|
|
735
|
+
else:
|
|
736
|
+
pass
|
|
737
|
+
previous_vlan = vlan
|
|
738
|
+
return range_list
|
|
739
|
+
|
|
740
|
+
@staticmethod
|
|
741
|
+
def list_variants(input_list):
|
|
742
|
+
str_list = [str(_)
|
|
743
|
+
for _ in LST.convert_vlans_list_to_range_of_vlans_list(input_list)]
|
|
744
|
+
# str_list = [str(_)
|
|
745
|
+
# for _ in input_list]
|
|
746
|
+
ssv_list = " ".join(str_list)
|
|
747
|
+
csv_list = ",".join(str_list)
|
|
748
|
+
return {
|
|
749
|
+
'str_list': str_list,
|
|
750
|
+
'ssv_list': ssv_list,
|
|
751
|
+
'csv_list': csv_list,
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
@staticmethod
|
|
755
|
+
def list_of_devices(list_of_files):
|
|
756
|
+
devices = set()
|
|
757
|
+
for file in list_of_files:
|
|
758
|
+
if not file.strip(): continue
|
|
759
|
+
f = ".".join(os.path.basename(file).split(".")[:-1])
|
|
760
|
+
hn = f.split("_")[0]
|
|
761
|
+
if not hn in devices: devices.add(hn)
|
|
762
|
+
return devices
|
|
763
|
+
|
|
764
|
+
@staticmethod
|
|
765
|
+
def split(lst, n):
|
|
766
|
+
s = 0
|
|
767
|
+
lst = tuple(lst)
|
|
768
|
+
for _ in range(s, len(lst), n):
|
|
769
|
+
yield lst[_: s+n]
|
|
770
|
+
s += n
|
|
771
|
+
|
|
772
|
+
@staticmethod
|
|
773
|
+
def list_to_octet(lst):
|
|
774
|
+
l = ''
|
|
775
|
+
for x in lst: l = str(x) if l == '' else l +'.'+ str(x)
|
|
776
|
+
return l
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
# -----------------------------------------------------------------------------
|
|
780
|
+
# DICTIONARY MODIFICATIONS #
|
|
781
|
+
# -----------------------------------------------------------------------------
|
|
782
|
+
|
|
783
|
+
class DIC():
|
|
784
|
+
|
|
785
|
+
# INTERNAL : update dictionary d for provided keyvalue pairs
|
|
786
|
+
# param: d: dest dictionary
|
|
787
|
+
# param: kv: src dictionary with key value pairs
|
|
788
|
+
# --> updated destn dict
|
|
789
|
+
@staticmethod
|
|
790
|
+
def __update_keyValue(d, kv):
|
|
791
|
+
if isinstance(d, dict):
|
|
792
|
+
for k, v in kv.items():
|
|
793
|
+
if isinstance(v, dict):
|
|
794
|
+
for x, y in v.items():
|
|
795
|
+
d = DIC.merge_dict(d, kv)
|
|
796
|
+
else:
|
|
797
|
+
d[k] = v
|
|
798
|
+
return d
|
|
799
|
+
|
|
800
|
+
@staticmethod
|
|
801
|
+
def merge_dict(dx, dy):
|
|
802
|
+
'''Merges two dictionaries for identical keys
|
|
803
|
+
--> dict
|
|
804
|
+
:param dx, dy: Two dictionaries to be merged
|
|
805
|
+
:type dx, dy: dict
|
|
806
|
+
'''
|
|
807
|
+
for k, v in dy.items():
|
|
808
|
+
try:
|
|
809
|
+
dx[k] = DIC.__update_keyValue(dx[k], dy[k])
|
|
810
|
+
except:
|
|
811
|
+
dx[k] = dy[k]
|
|
812
|
+
return dx
|
|
813
|
+
|
|
814
|
+
@staticmethod
|
|
815
|
+
def recursive_dic(dic, indention=0):
|
|
816
|
+
s = ""
|
|
817
|
+
if isinstance(dic, dict):
|
|
818
|
+
for k, v in dic.items():
|
|
819
|
+
s += f"{' '*indention}{k}\n"
|
|
820
|
+
indention += 1
|
|
821
|
+
s += DIC.recursive_dic(v, indention)
|
|
822
|
+
indention -= 1
|
|
823
|
+
elif isinstance(dic, (tuple,list,set)):
|
|
824
|
+
for x in dic:
|
|
825
|
+
if x: s += str(x)+'\n'
|
|
826
|
+
elif isinstance(dic, str):
|
|
827
|
+
if dic: s+= f" {' '*indention}{dic}\n"
|
|
828
|
+
return s
|
|
829
|
+
|
|
830
|
+
# -----------------------------------------------------------------------------
|
|
831
|
+
# DICTIONARY DIFFERECES #
|
|
832
|
+
# -----------------------------------------------------------------------------
|
|
833
|
+
|
|
834
|
+
class DifferenceDict(dict):
|
|
835
|
+
|
|
836
|
+
missing = "- "
|
|
837
|
+
additive = "+ "
|
|
838
|
+
|
|
839
|
+
def __init__(self, d):
|
|
840
|
+
self.d = d
|
|
841
|
+
|
|
842
|
+
def __sub__(self, d): return self.get_change(d, self.missing)
|
|
843
|
+
def __add__(self, d): return self.get_change(d, self.additive)
|
|
844
|
+
|
|
845
|
+
def get_change(self, d, change):
|
|
846
|
+
if isinstance(d, DifferenceDict):
|
|
847
|
+
return dict_differences(self.d, d.d, change)
|
|
848
|
+
elif isinstance(d, dict):
|
|
849
|
+
return dict_differences(self.d, d, change)
|
|
850
|
+
|
|
851
|
+
def _get_differences(subject, change):
|
|
852
|
+
if isinstance(subject, (str, int, float)):
|
|
853
|
+
diff = change + str(subject)
|
|
854
|
+
elif isinstance(subject, set):
|
|
855
|
+
diff = set()
|
|
856
|
+
for item in subject:
|
|
857
|
+
df = _get_differences(item, change)
|
|
858
|
+
diff.add(df)
|
|
859
|
+
elif isinstance(subject, dict):
|
|
860
|
+
diff = dict()
|
|
861
|
+
for key, value in subject.items():
|
|
862
|
+
key = change + str(key)
|
|
863
|
+
if value:
|
|
864
|
+
diff[key] = _get_differences(value, change)
|
|
865
|
+
else:
|
|
866
|
+
diff[key] = ''
|
|
867
|
+
else:
|
|
868
|
+
raise Exception(f"InvalidSubjectTypeError: {type(subject)}:{subject}")
|
|
869
|
+
return diff
|
|
870
|
+
|
|
871
|
+
|
|
872
|
+
def dict_differences(d1, d2, change):
|
|
873
|
+
diff = {}
|
|
874
|
+
if d1 == d2: return None
|
|
875
|
+
if (not (isinstance(d1, (dict, set)) or isinstance(d2, (dict, set))) and
|
|
876
|
+
type(d1) != type(d2)):
|
|
877
|
+
raise Exception(f"TypeMismatch- d1:{type(d1)}d2:{type(d2)} - {d1}{d2}")
|
|
878
|
+
if isinstance(d1, dict):
|
|
879
|
+
for k_d1, v_d1 in d1.items():
|
|
880
|
+
if k_d1 not in d2:
|
|
881
|
+
diff.update( _get_differences({k_d1: v_d1}, change) )
|
|
882
|
+
continue
|
|
883
|
+
if v_d1 == d2[k_d1]: continue
|
|
884
|
+
diff[k_d1] = dict_differences(v_d1, d2[k_d1], change)
|
|
885
|
+
elif isinstance(d1, set):
|
|
886
|
+
diff = _get_differences(d1.difference(d2), change)
|
|
887
|
+
else:
|
|
888
|
+
if d1:
|
|
889
|
+
diff = _get_differences(d1, change)
|
|
890
|
+
|
|
891
|
+
return diff
|
|
892
|
+
|
|
893
|
+
# -----------------------------------------------------------------------------
|
|
894
|
+
# Common Dictionary Methods #
|
|
895
|
+
# -----------------------------------------------------------------------------
|
|
896
|
+
class DictMethods():
|
|
897
|
+
"""PAPA FOR DICTIONARY REPR OBJECTS"""
|
|
898
|
+
def __iter__(self):
|
|
899
|
+
for k, v in self.dic.items():
|
|
900
|
+
yield (k, v)
|
|
901
|
+
|
|
902
|
+
def __getitem__(self, item):
|
|
903
|
+
try:
|
|
904
|
+
return self.dic[item]
|
|
905
|
+
except KeyError:
|
|
906
|
+
return None
|
|
907
|
+
|
|
908
|
+
def __get__(self, key, item):
|
|
909
|
+
try:
|
|
910
|
+
return self[key][item]
|
|
911
|
+
except KeyError:
|
|
912
|
+
return None
|
|
913
|
+
|
|
914
|
+
def __setitem__(self, item, value):
|
|
915
|
+
self.dic[item] = value
|
|
916
|
+
|
|
917
|
+
def __delitem__(self, srno):
|
|
918
|
+
try:
|
|
919
|
+
for k in sorted(self.dic.keys()):
|
|
920
|
+
if k <= srno: continue
|
|
921
|
+
self.dic[k-1] = self.dic[k]
|
|
922
|
+
del(self.dic[k])
|
|
923
|
+
except:
|
|
924
|
+
raise KeyError
|
|
925
|
+
|
|
926
|
+
def append(self, item, value):
|
|
927
|
+
try:
|
|
928
|
+
if not self.dic.get(item):
|
|
929
|
+
self.dic[item] = []
|
|
930
|
+
elif isinstance(self.dic[item], (str, int)):
|
|
931
|
+
self.dic[item] = [self.dic[item],]
|
|
932
|
+
self.dic[item].append(value)
|
|
933
|
+
except:
|
|
934
|
+
raise Exception
|
|
935
|
+
|
|
936
|
+
|
|
937
|
+
# -----------------------------------------------------------------------------
|
|
938
|
+
# LOG OPERATIONS #
|
|
939
|
+
# -----------------------------------------------------------------------------
|
|
940
|
+
|
|
941
|
+
class LOG():
|
|
942
|
+
|
|
943
|
+
@staticmethod
|
|
944
|
+
def time_stamp():
|
|
945
|
+
'''current time stamp (for log purpose)
|
|
946
|
+
--> str
|
|
947
|
+
'''
|
|
948
|
+
return str(datetime.datetime.now())[:19]
|
|
949
|
+
|
|
950
|
+
# -----------------------------------------------------------------------------
|
|
951
|
+
# D-B OPERATIONS #
|
|
952
|
+
# -----------------------------------------------------------------------------
|
|
953
|
+
|
|
954
|
+
class DB():
|
|
955
|
+
|
|
956
|
+
@staticmethod
|
|
957
|
+
def read_excel(file, sheet='Sheet1', **kwargs):
|
|
958
|
+
'''
|
|
959
|
+
reads a sheet from an excel
|
|
960
|
+
--->returns dataframe of that sheet data
|
|
961
|
+
|
|
962
|
+
:param file: source excel database file
|
|
963
|
+
:type str:
|
|
964
|
+
|
|
965
|
+
:param sheet: sheet name on source excel which is to be read.
|
|
966
|
+
:type str:
|
|
967
|
+
|
|
968
|
+
:param kwargs: pandas df arguments to read excel
|
|
969
|
+
:type kwargs: mutli
|
|
970
|
+
'''
|
|
971
|
+
return pd.read_excel(file, sheet_name=sheet, **kwargs)
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
|
|
975
|
+
# ------------------------------------------------------------------------------
|
|
976
|
+
# Excel Data WRITE Class, use with context manager
|
|
977
|
+
# ------------------------------------------------------------------------------
|
|
978
|
+
class XL_WRITE():
|
|
979
|
+
'''EXEL FILE CREATE,
|
|
980
|
+
hostname - excel file name
|
|
981
|
+
**sht_df - sht_name=dataframe
|
|
982
|
+
df - dataframe which data to be copied to Excel.
|
|
983
|
+
sht_name - Sheet Name of Excel where data to be copied
|
|
984
|
+
Excel O/P file will go inside - ./output/ - path
|
|
985
|
+
'''
|
|
986
|
+
|
|
987
|
+
# Object Initializer
|
|
988
|
+
def __init__(self, hostname, folder, index=False, **sht_df):
|
|
989
|
+
i = 0
|
|
990
|
+
self.hostname = hostname
|
|
991
|
+
self.folder = folder
|
|
992
|
+
while True:
|
|
993
|
+
try:
|
|
994
|
+
self.__create_excel(hostname, index, **sht_df)
|
|
995
|
+
break
|
|
996
|
+
except PermissionError:
|
|
997
|
+
i += 1
|
|
998
|
+
hostname = self.hostname+" ("+str(i)+")"
|
|
999
|
+
except Exception as e:
|
|
1000
|
+
print(e)
|
|
1001
|
+
break
|
|
1002
|
+
|
|
1003
|
+
def __repr__(self): return self.op_file
|
|
1004
|
+
|
|
1005
|
+
# write to Excel
|
|
1006
|
+
def __create_excel(self, hostname, index, **sht_df):
|
|
1007
|
+
try:
|
|
1008
|
+
n = 0
|
|
1009
|
+
XL_READ(self.folder + '/'+hostname+'.xlsx', 'tables')
|
|
1010
|
+
while True:
|
|
1011
|
+
n += 1
|
|
1012
|
+
XL_READ(self.folder + '/'+hostname+'-'+str(n)+'.xlsx', 'tables')
|
|
1013
|
+
except:
|
|
1014
|
+
if n == 0:
|
|
1015
|
+
op_file = self.folder + '/'+hostname+'.xlsx'
|
|
1016
|
+
else:
|
|
1017
|
+
op_file = self.folder + '/'+hostname+'-'+str(n)+'.xlsx'
|
|
1018
|
+
self.op_file = op_file
|
|
1019
|
+
with pd.ExcelWriter(op_file) as writer_file:
|
|
1020
|
+
for sht_name, df in sht_df.items():
|
|
1021
|
+
df.to_excel(writer_file, sheet_name=sht_name, index=index)
|
|
1022
|
+
|
|
1023
|
+
|
|
1024
|
+
# ------------------------------------------------------------------------------
|
|
1025
|
+
# Excel Data Read Class
|
|
1026
|
+
# ------------------------------------------------------------------------------
|
|
1027
|
+
class XL_READ:
|
|
1028
|
+
'''EXCEL FILE READING,
|
|
1029
|
+
xl - Excel file to be read
|
|
1030
|
+
shtName - SheetName to be read from given read
|
|
1031
|
+
|
|
1032
|
+
RETURNS
|
|
1033
|
+
-------
|
|
1034
|
+
df - DataFrame object (iterable, lenth, etc. available )
|
|
1035
|
+
|
|
1036
|
+
USAGE EXAMPLE
|
|
1037
|
+
-------------
|
|
1038
|
+
obj = XL_READ('data/cmd_list.xlsx') # get xl df Object
|
|
1039
|
+
|
|
1040
|
+
### Length of records ###
|
|
1041
|
+
print(len(obj))
|
|
1042
|
+
|
|
1043
|
+
### Go thru each record ###
|
|
1044
|
+
for header, value in obj:
|
|
1045
|
+
print(header, value)
|
|
1046
|
+
|
|
1047
|
+
### Get a particular column ###
|
|
1048
|
+
print(obj['command'])
|
|
1049
|
+
|
|
1050
|
+
### FILTERING RECORDS ###
|
|
1051
|
+
# Option:1
|
|
1052
|
+
flt = {'level':1, 'dev_type':'cisco_ios'} # get arguments in a dict
|
|
1053
|
+
x = obj.filter(**flt) # apply filter dict
|
|
1054
|
+
|
|
1055
|
+
# Option:2
|
|
1056
|
+
x = obj.filter(dev_type='cisco_ios', level=1)# apply filter manually
|
|
1057
|
+
|
|
1058
|
+
# Option:3 - pass external df for filter
|
|
1059
|
+
x = obj.filter(level=1) # created a new DataFrame-x
|
|
1060
|
+
x = obj.filter(df=x, dev_type='cisco_ios')# apply flt manually on new DF-x
|
|
1061
|
+
|
|
1062
|
+
# Option:4 Filter Column & return specific columns only.
|
|
1063
|
+
flt = {'level':1, 'dev_type':'cisco_ios'} # get arguments in a dict
|
|
1064
|
+
col = ['command', 'level']
|
|
1065
|
+
x = obj.column_values(column=col, **flt)
|
|
1066
|
+
|
|
1067
|
+
# Check Output for above options
|
|
1068
|
+
print(x) # filtered output all columns
|
|
1069
|
+
print(x['xl_col']) # filtered output with specific col only
|
|
1070
|
+
|
|
1071
|
+
'''
|
|
1072
|
+
|
|
1073
|
+
# Object Initializer
|
|
1074
|
+
def __init__(self, xl, shtName='Sheet1'):
|
|
1075
|
+
self.df = pd.read_excel(xl, sheet_name=shtName)
|
|
1076
|
+
|
|
1077
|
+
# Object Represantation
|
|
1078
|
+
def __repr__(self):
|
|
1079
|
+
return 'Excel data reprezenting class as DataFrame Object - obj.df'
|
|
1080
|
+
|
|
1081
|
+
# Length of Object
|
|
1082
|
+
def __len__(self):
|
|
1083
|
+
return self.df.last_valid_index()+1
|
|
1084
|
+
|
|
1085
|
+
# Object Iterator
|
|
1086
|
+
def __iter__(self):
|
|
1087
|
+
for header, value in self.df.items():
|
|
1088
|
+
yield (header, value)
|
|
1089
|
+
|
|
1090
|
+
# Get a specific Item/Record from Object
|
|
1091
|
+
def __getitem__(self, key):
|
|
1092
|
+
'''get an item from parameters'''
|
|
1093
|
+
return self.df[key]
|
|
1094
|
+
|
|
1095
|
+
|
|
1096
|
+
# Object Data Filter
|
|
1097
|
+
def filter(self, df=None, **kwarg):
|
|
1098
|
+
'''Filter Records
|
|
1099
|
+
df - external data frame ( default object dataframe )
|
|
1100
|
+
kwarg - filters to be applied on df.
|
|
1101
|
+
'''
|
|
1102
|
+
if df is None:
|
|
1103
|
+
tmpdf = self.df
|
|
1104
|
+
else:
|
|
1105
|
+
tmpdf = df
|
|
1106
|
+
for k, v in kwarg.items():
|
|
1107
|
+
try:
|
|
1108
|
+
tmpdf = tmpdf[tmpdf[k]==v]
|
|
1109
|
+
except:
|
|
1110
|
+
pass
|
|
1111
|
+
return tmpdf
|
|
1112
|
+
|
|
1113
|
+
def column_values(self, column, **kwarg):
|
|
1114
|
+
'''selected column output, after filters applied
|
|
1115
|
+
column - a single column name or , list of column names
|
|
1116
|
+
kwarg - filters to be applied
|
|
1117
|
+
'''
|
|
1118
|
+
return self.filter(**kwarg)[column]
|
|
1119
|
+
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
|
|
1123
|
+
# -----------------------------------------------------------------------------
|
|
1124
|
+
# IP OPERATIONS #
|
|
1125
|
+
# -----------------------------------------------------------------------------
|
|
1126
|
+
|
|
1127
|
+
class IP():
|
|
1128
|
+
|
|
1129
|
+
@staticmethod
|
|
1130
|
+
def ping_average(ip):
|
|
1131
|
+
lst = popen(f"ping {ip}").read().split("\n")
|
|
1132
|
+
for x in lst:
|
|
1133
|
+
if "Average" in x:
|
|
1134
|
+
avg = x.split()[-1]
|
|
1135
|
+
s = ''
|
|
1136
|
+
for i, n in enumerate(avg):
|
|
1137
|
+
if n.isdigit(): s += n
|
|
1138
|
+
return int(s)
|
|
1139
|
+
|
|
1140
|
+
@staticmethod
|
|
1141
|
+
def bin2dec(binmask):
|
|
1142
|
+
'''convert binary mask to decimal mask
|
|
1143
|
+
---> decimal mask
|
|
1144
|
+
:param binmask str: binary mask as string
|
|
1145
|
+
'''
|
|
1146
|
+
return 32 - IP.inv2dec(binmask)
|
|
1147
|
+
|
|
1148
|
+
@staticmethod
|
|
1149
|
+
def inv2dec(invmask):
|
|
1150
|
+
'''convert inverse mask to decimal mask
|
|
1151
|
+
---> decimal mask
|
|
1152
|
+
:param invmask str: inverse mask as string
|
|
1153
|
+
'''
|
|
1154
|
+
m_octs = invmask.split(".")
|
|
1155
|
+
count_of_ones = 0
|
|
1156
|
+
for x in m_octs:
|
|
1157
|
+
x = bin(int(x))
|
|
1158
|
+
count_of_ones += x.count("1")
|
|
1159
|
+
return 32 - count_of_ones
|
|
1160
|
+
|
|
1161
|
+
|
|
1162
|
+
# -----------------------------------------------------------------------------
|
|
1163
|
+
# Execution secquences #
|
|
1164
|
+
# -----------------------------------------------------------------------------
|
|
1165
|
+
|
|
1166
|
+
class Multi_Execution(Default):
|
|
1167
|
+
|
|
1168
|
+
max_connections = 30
|
|
1169
|
+
|
|
1170
|
+
def __str__(self): return self._repr()
|
|
1171
|
+
|
|
1172
|
+
def __init__(self, items=None):
|
|
1173
|
+
self.items = items
|
|
1174
|
+
|
|
1175
|
+
def execute_steps(self, multi_thread=True):
|
|
1176
|
+
self.start(multi_thread)
|
|
1177
|
+
|
|
1178
|
+
def start(self, multi_thread=True):
|
|
1179
|
+
if not self.items: return None
|
|
1180
|
+
if multi_thread:
|
|
1181
|
+
self.execute_mt()
|
|
1182
|
+
else:
|
|
1183
|
+
self.execute_sequencial()
|
|
1184
|
+
|
|
1185
|
+
def end(self): pass
|
|
1186
|
+
|
|
1187
|
+
def get_devices(self):
|
|
1188
|
+
self.devices = LST.list_of_devices(self.files)
|
|
1189
|
+
|
|
1190
|
+
def execute_mt(self):
|
|
1191
|
+
for group, items in enumerate(LST.split(self.items, self.max_connections)):
|
|
1192
|
+
self.execute_threads_max(items)
|
|
1193
|
+
|
|
1194
|
+
def execute_threads_max(self, item_list):
|
|
1195
|
+
ts = []
|
|
1196
|
+
for hn in item_list:
|
|
1197
|
+
t = threading.Thread(target=self.execute, args=(hn,) )
|
|
1198
|
+
t.start()
|
|
1199
|
+
ts.append(t)
|
|
1200
|
+
for t in ts: t.join()
|
|
1201
|
+
|
|
1202
|
+
def execute_sequencial(self):
|
|
1203
|
+
for hn in self.items: self.execute(hn)
|
|
1204
|
+
|
|
1205
|
+
@abstractclassmethod
|
|
1206
|
+
def execute(self, hn): pass
|
|
1207
|
+
|