pydan 1.7__tar.gz

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,471 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Data Helpers
4
+
5
+ import re
6
+ import collections
7
+ import os
8
+ import sys
9
+ import io
10
+ import binascii
11
+ import random
12
+ from datetime import datetime,timezone
13
+ import base64
14
+ import platform # platform.node() -> hostname
15
+ # for yaml
16
+ #from ruamel.yaml.comments import CommentedMap
17
+ import ruamel.yaml
18
+ # for json
19
+ import json
20
+ # for xml
21
+ import dicttoxml
22
+ # self tools
23
+ from pydan import run
24
+
25
+ # repair LANG=C -> utf8
26
+ if(sys.getfilesystemencoding()=="ascii" and sys.getdefaultencoding()=="utf-8"):
27
+ sys.stdout = open(sys.stdout.fileno(), mode='w', encoding='utf8', buffering=1)
28
+
29
+ c={
30
+ "none":"\033[0m",
31
+ "header":"\033[38;5;166m", # orange
32
+ "group":"\033[1;34m", # light blue
33
+ "item":"\033[0;36m", # cian
34
+ "null":"\033[1;30m", # gray
35
+ "date":"\033[38;5;105m", # xviolet
36
+ "str":"\033[0;32m", # green
37
+ "int":"\033[1;32m", # light green
38
+ "float":"\033[38;5;112m", # xolive
39
+ "bool":"\033[1;36m", # white
40
+ "unk":"\033[0;31m", # red
41
+ "varint":"\033[1;35m", # magentab
42
+ "varenv":"\033[0;35m", # magenta
43
+ "varcmd":"\033[1;31m", # red
44
+ "err":"\033[1;31m", # light red
45
+ "important":"\033[1;33m", # light red
46
+ }
47
+
48
+ #{{{ colprint: Imprime un dict por pantalla con colores según el tipo de datos
49
+ def colprint(d,header=None,key=None,indent="",crop=True):
50
+ indentchars=" "
51
+ if(header): print(c["header"]+header+c["none"]);indent=indent+indentchars
52
+
53
+ # Si es diccionario iteramos
54
+ if(type(d)==dict or type(d)==collections.OrderedDict): # or type(d)==CommentedMap):
55
+ #if(type(d)==dict or type(d)==collections.OrderedDict or type(d)==CommentedMap):
56
+ #if hasattr(d,'__iter__') and type(d)!=str:
57
+ if(key!=None): print(indent+c["group"]+key+":"+c["none"]); indent+=indentchars
58
+ if(len(d)==0): print(indent+c["null"]+"empty"+c["none"])
59
+ else:
60
+ for k in d: colprint(d[k], key=k, indent=indent)
61
+ return
62
+
63
+ # Si es lista listamos con [indice]
64
+ #if(type(d)==list):
65
+ # i=0
66
+ # print(indent+c["group"]+key+":"+c["none"])
67
+ # indent=indent+indentchars
68
+ # # Lista de strings
69
+ # #if type(key[0])==str:
70
+ # # for k in d:
71
+ # # print(indent+c["item"]+"["+str(i)+"]: "+c["none"], end='')
72
+
73
+ # #for k in d:
74
+ # # #print(indent+c["group"]+key+"["+str(i)+"]:"+c["none"])
75
+ # # #colprint(k, indent=indent+indentchars)
76
+ # # #print(indent+c["item"]+"["+str(i)+"]: "+c["none"], end='')
77
+ # # colprint(k, indent=indent+c["item"]+"["+str(i)+"]: ")
78
+ # # i=i+1
79
+ # # #print(k);
80
+ #
81
+ # for k in d:
82
+ # #print(indent+c["group"]+key+"["+str(i)+"]:"+c["none"])
83
+ # print(indent+c["group"]+"["+str(i)+"]:"+c["none"])
84
+ # colprint(k, indent=indent+indentchars)
85
+ # # #print(indent+c["item"]+"["+str(i)+"]: "+c["none"], end='')
86
+ # #colprint(k, indent=indent+c["item"]+"["+str(i)+"]: ")
87
+ # i=i+1
88
+ # #print(k);
89
+ # return
90
+
91
+ if type(d)==list or type(d)==tuple:
92
+ # Vacia
93
+ if len(d)==0:
94
+ if(key!=None):
95
+ print(indent+c["group"]+key+"[]: "+c["null"]+"empty"+c["none"]);
96
+ else:
97
+ print(indent+c["null"]+"empty"+c["none"])
98
+ return
99
+
100
+ # Lista de strings o ints
101
+ if type(d[0])==str or type(d[0])==int:
102
+ i=0
103
+ if key!=None:
104
+ print(indent+c["group"]+key+":"+c["none"])
105
+ for k in d:
106
+ colprint(str(k), key="["+str(i)+"]", indent=indent+indentchars)
107
+ i+=1
108
+ else:
109
+ for k in d:
110
+ colprint(str(k), key="["+str(i)+"]", indent=indent)
111
+ i+=1
112
+ return
113
+
114
+ #for k in d:
115
+ # #print(indent+c["group"]+key+"["+str(i)+"]:"+c["none"])
116
+ # #colprint(k, indent=indent+indentchars)
117
+ # #print(indent+c["item"]+"["+str(i)+"]: "+c["none"], end='')
118
+ # colprint(k, indent=indent+c["item"]+"["+str(i)+"]: ")
119
+ # i=i+1
120
+ # #print(k);
121
+
122
+ # Lista de objetos
123
+ if(type(d[0])==dict or type(d[0])==collections.OrderedDict):
124
+ i=0
125
+ for k in d:
126
+ print(indent+c["group"]+key+"["+str(i)+"]:"+c["none"])
127
+ colprint(k, indent=indent+indentchars)
128
+ i=i+1
129
+ return
130
+
131
+ print(c["err"]+"¿list of "+type(d[0]).__name__+"?"+c["none"])
132
+ return
133
+ #print("unknown "+type(d).__name__)
134
+ #return
135
+
136
+ # Mostramos key
137
+ if(key!=None): print(indent+c["item"]+key+": ", end='')
138
+ else: print(indent, end='')
139
+
140
+ # Mostramos valor
141
+ t=type(d)
142
+ if(t==str):
143
+ p=re.compile("\$([a-zA-Z0-9_]*)\$")
144
+ vars=set(p.findall(d))
145
+ for k in vars: d=re.sub("\$"+k+"\$", c["varenv"]+"$"+k+"$"+c["str"], d)
146
+ p=re.compile("\%([a-zA-Z0-9_]*)\%")
147
+ vars=set(p.findall(d))
148
+ for k in vars: d=re.sub("\%"+k+"\%", c["varint"]+"%"+k+"%"+c["str"], d)
149
+ p=re.compile("\(\(([^)]*)\)\)")
150
+ vars=set(p.findall(d))
151
+ for k in vars: d=re.sub("\(\(.*\)\)", c["varcmd"]+"(("+k+"))"+c["str"], d)
152
+ if crop and len(d)>4000:
153
+ print(c["important"]+"###DATA-"+str(len(d))+"###"+c["none"])
154
+ else:
155
+ print(c["str"]+d+c["none"])
156
+ elif(t==datetime):
157
+ dtstr=re.sub("\+00:00", "Z", d.isoformat())
158
+ #dtstr=d.__str__()
159
+ print(c["date"]+dtstr+c["none"])
160
+ elif(t==int):
161
+ print(c["int"]+str(d)+c["none"])
162
+ elif(t==float):
163
+ print(c["float"]+str(d)+c["none"])
164
+ elif(t==bool):
165
+ print(c["bool"]+str(d)+c["none"])
166
+ # elif(t==list):
167
+ # print
168
+ # for i in d:
169
+ # colprint(i,header="x",indent=indent)
170
+ # #print(indent+indentchars+c["str"]+i)
171
+ # #print(d)
172
+ elif(t==type(None)):
173
+ print(c["null"]+"null"+c["none"])
174
+ else:
175
+ print(c["err"]+"¿"+str(t.__name__)+"?"+c["none"])
176
+ #}}}
177
+
178
+ # Por cada item en d reemplaza $var$ por el valor de la variable en la lista varlist
179
+ #{{{ replacevars
180
+ def replacevars(d, varlist, unknownempty=False, emptyremove=False, unknownnull=False, emptynull=False):
181
+ #o=collections.OrderedDict()
182
+ o={}
183
+ for k in d:
184
+ if(type(d[k])==dict or type(d[k])==collections.OrderedDict):
185
+ d[k]=replacevars(d[k], varlist, unknownempty=unknownempty, emptyremove=emptyremove, unknownnull=unknownnull, emptynull=emptynull)
186
+ o[k]=d[k]
187
+ continue
188
+ else:
189
+ if(type(d[k])==str):
190
+ #if(d[k][0]=='$'):
191
+ # var=d[k][1:-1]
192
+ # v=varlist.get(var)
193
+ # if(v): o[k]=v
194
+ #else:
195
+ # o[k]=d[k]
196
+
197
+ # Buscamos variables en varlist
198
+ p=re.compile("\$([a-zA-Z0-9_]*)\$")
199
+ vars=set(p.findall(d[k]))
200
+ # No hay variables
201
+ if(vars==None):
202
+ o[k]=d[k]
203
+ continue
204
+ # Hay variables
205
+ for sk in vars:
206
+ val=varlist.get(sk)
207
+ if(val==None):
208
+ if(unknownempty): val=""
209
+ else:
210
+ if(unknownnull):
211
+ if emptynull: val="$null$"
212
+ else: val="null"
213
+ else:
214
+ continue
215
+ d[k]=re.sub("\$"+sk+"\$", str(val), d[k])
216
+
217
+ if(d[k]=="$null$" and emptynull): continue
218
+ if(d[k]=="" and emptyremove): continue
219
+ o[k]=d[k]
220
+ else:
221
+ o[k]=d[k]
222
+ return o
223
+ #}}}
224
+
225
+ # Por cada item en d reemplaza $e$var$ por variable de entorno
226
+ #{{{ replaceenv
227
+ def replaceenv(d, unknownempty=False, emptyremove=None):
228
+ o=collections.OrderedDict()
229
+ for k in d:
230
+ if(type(d[k])==dict or type(d[k])==collections.OrderedDict):
231
+ d[k]=replaceenv(d[k], unknownempty=unknownempty, emptyremove=emptyremove)
232
+ o[k]=d[k]
233
+ continue
234
+ else:
235
+ if(type(d[k])==str):
236
+ p=re.compile("\$e$([a-zA-Z0-9_]*)\$")
237
+ vars=set(p.findall(d[k]))
238
+ # No hay variables
239
+ if(vars==None):
240
+ o[k]=d[k]
241
+ continue
242
+ # Hay variables
243
+ for sk in vars:
244
+ if (sk=="HOSTNAME"): val=platform.node()
245
+ else: val=os.environ.get(sk)
246
+ if(val==None):
247
+ if(unknownempty): val=""
248
+ else: continue
249
+ d[k]=re.sub("\$e\$"+sk+"\$", val, d[k])
250
+
251
+ if(d[k]=="" and emptyremove): continue
252
+ o[k]=d[k]
253
+ else:
254
+ o[k]=d[k]
255
+ return o
256
+ #}}}
257
+
258
+ # Por cada item en d reemplaza ((cmd)) por la ejecución de cmd
259
+ # Por cada item en d reemplaza $b$file$ por el fichero en b64
260
+ # Por cada item en d reemplaza $t$file$ por el contenido del fichero
261
+ #{{{ runvars
262
+ def runvars(d, unknownempty=False, emptyremove=None):
263
+ o=collections.OrderedDict()
264
+ for k in d:
265
+ if(type(d[k])==dict or type(d[k])==collections.OrderedDict):
266
+ d[k]=runvars(d[k], unknownempty=unknownempty, emptyremove=emptyremove)
267
+ o[k]=d[k]
268
+ continue
269
+ else:
270
+ if(type(d[k])==str):
271
+ modified=False
272
+
273
+ # Comando a ejecutar
274
+ r_buscacmd=re.compile("\(\((.*)\)\)")
275
+ vars=set(r_buscacmd.findall(d[k]))
276
+ # No hay variables
277
+ if(vars==None):
278
+ o[k]=d[k]
279
+ # continue
280
+ else:
281
+ modified=True
282
+ # Hay variables
283
+ for sk in vars:
284
+ # b|fichero -> base64 fichero
285
+ #sk=re.sub(r"^t\|(.*)$", r"cat '\g<1>'", sk)
286
+ sk=re.sub(r"^b\|(.*)$", r"cat '\g<1>'|base64 -w0", sk)
287
+ pars=["bash","-c",sk]
288
+ ex=run.cmd(pars)
289
+ #if ex.retcode==0:
290
+ val=ex.out
291
+ if(val==None):
292
+ if(unknownempty): val=""
293
+ else: continue
294
+ #d[k]=re.sub("\(\("+sk+"\)\)", val, d[k])
295
+ d[k]=re.sub("\(\(.*\)\)", val, d[k])
296
+
297
+ # Fichero base64
298
+ r_buscacmd=re.compile(r"$b$(.*)$")
299
+ vars=set(r_buscacmd.findall(d[k]))
300
+ # No hay variables
301
+ if(vars==None):
302
+ o[k]=d[k]
303
+ else:
304
+ modified=True
305
+ # Hay variables
306
+ for sk in vars:
307
+ f=open(sk, "rb")
308
+ fdata=base64.b64encode(f.read()).decode()
309
+ d[k]=re.sub(r"$b$.*$", fdata, d[k])
310
+
311
+ # Fichero directo
312
+ r_buscacmd=re.compile(r"$t$(.*)$")
313
+ vars=set(r_buscacmd.findall(d[k]))
314
+ # No hay variables
315
+ if(vars==None):
316
+ o[k]=d[k]
317
+ else:
318
+ modified=True
319
+ # Hay variables
320
+ for sk in vars:
321
+ f=open(sk, "r")
322
+ fdata=f.read()
323
+ d[k]=re.sub(r"$t$.*$", fdata, d[k])
324
+
325
+ if modified and d[k]=="" and emptyremove: continue
326
+ o[k]=d[k]
327
+ else:
328
+ o[k]=d[k]
329
+ return o
330
+ #}}}
331
+
332
+ # Values of dict contained in another dict
333
+ def contained(d1, d2):
334
+ for k in d1:
335
+ if d2.get(k)==None: return False
336
+ if(type(d1[k])==dict or type(d1[k])==collections.OrderedDict):
337
+ if not contained(d1[k], d2[k]): return False
338
+ else:
339
+ if d1[k]!=d2[k]: return False
340
+ return True
341
+
342
+
343
+ #{{{ xml tools
344
+
345
+ # XML -> dict
346
+ def fromxml(xmldata):
347
+ return xmltodict.parse("<xml>"+xmldata+"</xml>", disable_entities=True)[xml]
348
+
349
+ #}}}
350
+
351
+ #{{{ json tools
352
+ def fromjson(jsondata):
353
+ return json.loads(jsondata,object_pairs_hook=json_parser_hook)
354
+
355
+ def readjson(jsonfile):
356
+ f=open(jsonfile,"rt")
357
+ json=f.read()
358
+ data=fromjson(json)
359
+ return data
360
+
361
+ def tojson(data,indent=None):
362
+ return json.dumps(data,separators=(',',':'),default=json_serializer_hook,indent=indent)
363
+
364
+ def writejson(data,filename,tabs=0,spaces=0):
365
+ f=open(filename, "w")
366
+ indent=None
367
+ if spaces!=0:
368
+ indent=spaces
369
+ if (tabs==1):
370
+ indent='\t'
371
+ jsondata=tojson(data,indent=indent)
372
+ f.write(jsondata)
373
+ f.write("\n")
374
+ f.close()
375
+
376
+ # json -> dict
377
+ def json_parser_hook(js):
378
+ #out=collections.OrderedDict(js)
379
+ out=dict(js)
380
+ for (key, value) in out.items():
381
+ # Hora con timezone sin milisegundos
382
+ try:
383
+ dt=re.sub("Z$", "UTC",value)
384
+ dt=datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S%Z")
385
+ #dt=dt.replace(tzinfo=datetime.timezone(datetime.timedelta(0)))
386
+ dt=dt.replace(tzinfo=timezone.utc)
387
+ out[key]=dt
388
+ continue
389
+ except: pass
390
+ # Hora con timezone con milisegundos
391
+ try:
392
+ dt=re.sub("Z$", "UTC",value)
393
+ dt=datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S.%f%Z")
394
+ dt=dt.replace(tzinfo=timezone.utc)
395
+ out[key]=dt
396
+ continue
397
+ except: pass
398
+ # Hora sin timezone sin milisegundos
399
+ try:
400
+ out[key]=datetime.strptime(value, "%Y-%m-%dT%H:%M:%S")
401
+ continue
402
+ except: pass
403
+ # Hora sin timezone con milisegundos
404
+ try:
405
+ out[key]=datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%f")
406
+ continue
407
+ except: pass
408
+ return out
409
+
410
+ # dict -> json
411
+ def json_serializer_hook(o):
412
+ if isinstance(o, datetime):
413
+ return re.sub("\+00:00", "Z", o.isoformat())
414
+
415
+ #}}}
416
+
417
+ #{{{ yaml tools
418
+ def fromyaml(yamldata):
419
+ yaml=yamldata.replace("\t", " ")
420
+ data=ruamel.yaml.load(yaml, Loader=ruamel.yaml.Loader)
421
+ return data
422
+
423
+ def readrawyaml(filename):
424
+ # Cargar fichero yaml en dict
425
+ import collections
426
+ ruamel.yaml.representer.RoundTripRepresenter.add_representer(
427
+ collections.OrderedDict, ruamel.yaml.representer.RoundTripRepresenter.represent_ordereddict)
428
+ f=open(filename,"rt")
429
+ yamldata=f.read()
430
+ data=fromyaml(yamldata)
431
+ return data
432
+
433
+ def readyaml(filename):
434
+ data=readrawyaml(filename)
435
+ if data.get("yaml-include"):
436
+ for f in data["yaml-include"]:
437
+ if os.path.isfile(f):
438
+ subdata=readyaml(f)
439
+ data.update(subdata)
440
+ else:
441
+ path=os.path.dirname(filename)
442
+ f=path+os.path.sep+f
443
+ if os.path.isfile(f):
444
+ subdata=read(f)
445
+ data.update(subdata)
446
+ #data["include"]=None
447
+ data.pop("yaml-include")
448
+ return data
449
+
450
+ def yamlupdate(filename,var,val,node=None):
451
+ yaml=ruamel.yaml.YAML()
452
+ yaml.width=4096
453
+ f=open(filename,"r")
454
+ data=yaml.load(f.read())
455
+ f.close()
456
+ datamod=data
457
+ if node:
458
+ for n in node:
459
+ datamod=datamod.get(n)
460
+ datamod[var]=val
461
+ f=open(filename, "w")
462
+ yaml.dump(data, f)
463
+ f.close()
464
+
465
+ def writeyaml(data,filename):
466
+ yaml=ruamel.yaml.YAML()
467
+ f=open(filename, "w")
468
+ yaml.dump(data, f)
469
+ f.close()
470
+
471
+ #}}}
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import subprocess
4
+ import types
5
+ import sys
6
+ import os
7
+ import time
8
+
9
+ def cmd(cmd):
10
+ ret=types.SimpleNamespace()
11
+
12
+ if sys.platform.startswith('win'):
13
+ cmdproc=subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE,creationflags=0x00000200)
14
+ else:
15
+ cmdproc=subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE,preexec_fn=os.setpgrp)
16
+ t1=time.time()
17
+ binout,binerr=cmdproc.communicate()
18
+ t2=time.time()
19
+ ret.time=t2-t1
20
+ ret.out=binout.decode().rstrip()+binerr.decode().rstrip()
21
+ ret.retcode=cmdproc.returncode
22
+ return ret
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import sys
4
+ import os
5
+
6
+ # Directorio del script principal
7
+ #scriptdir=sys.path[0]
8
+
9
+ # Cambiamos al directorio del script principal
10
+ #os.chdir(scriptdir)
11
+
12
+ # Utilizamos scriptdir/lib como path para los import
13
+ #sys.path.insert(1,scriptdir+'/lib')
14
+
15
+ # Cambiamos el nombre del proceso al del script
16
+ import setproctitle
17
+ setproctitle.setproctitle(os.path.basename(sys.argv[0]))
18
+
19
+ # Excepciones coloreadas
20
+ import colored_traceback.always
21
+
22
+ # Exportamos scriptdir al script principal
23
+ #import __main__
24
+ #__main__.scriptdir=scriptdir
25
+
26
+ def parsecmdline():
27
+ cmdline={}
28
+ cmdline["params"]=[]
29
+ cmdline["options"]={}
30
+ i=0
31
+ while i < len(sys.argv)-1:
32
+ i+=1
33
+ s=sys.argv[i]
34
+ if '=' in s:
35
+ keyval=s.split("=")
36
+ cmdline["options"][keyval[0]]=keyval[1]
37
+ elif s[0]=='-':
38
+ i+=1
39
+ val=sys.argv[i]
40
+ key=s[1:]
41
+ if (key[0]=='-'):
42
+ key=key[1:]
43
+ cmdline["options"][key]=val
44
+ else:
45
+ cmdline["params"].append(s)
46
+ if not cmdline["params"]:
47
+ cmdline["cmd"]=""
48
+ else:
49
+ cmdline["cmd"]=cmdline["params"][0]
50
+ return cmdline
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import os
4
+ import platform
5
+
6
+ def creation_date(path_to_file):
7
+ """
8
+ Try to get the date that a file was created, falling back to when it was
9
+ last modified if that isn't possible.
10
+ See http://stackoverflow.com/a/39501288/1709587 for explanation.
11
+ """
12
+ if platform.system() == 'Windows':
13
+ return os.path.getctime(path_to_file)
14
+ else:
15
+ stat = os.stat(path_to_file)
16
+ try:
17
+ return stat.st_birthtime
18
+ except AttributeError:
19
+ # We're probably on Linux. No easy way to get creation dates here,
20
+ # so we'll settle for when its content was last modified.
21
+ return stat.st_mtime
@@ -0,0 +1,13 @@
1
+ Metadata-Version: 1.2
2
+ Name: pydan
3
+ Version: 1.7
4
+ Summary: Python3 Data Utils
5
+ Home-page: UNKNOWN
6
+ Author: Jose Biosca Martín
7
+ Author-email: jbiosca@zone-sys.net
8
+ License: UNKNOWN
9
+ Description: UNKNOWN
10
+ Platform: UNKNOWN
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Requires-Python: >=3.6
@@ -0,0 +1,12 @@
1
+ setup.py
2
+ pydan.egg-info/PKG-INFO
3
+ pydan.egg-info/SOURCES.txt
4
+ pydan.egg-info/dependency_links.txt
5
+ pydan.egg-info/requires.txt
6
+ pydan.egg-info/top_level.txt
7
+ src/__init__.py
8
+ src/jdata.py
9
+ src/run.py
10
+ src/script.py
11
+ src/utils.py
12
+ test/test-jdata.py
@@ -0,0 +1,6 @@
1
+ colored_traceback
2
+ dicttoxml
3
+ ruamel.yaml
4
+ setproctitle
5
+ setuptools
6
+ xmltodict