easy-utils-dev 2.155__tar.gz → 2.157__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.
Files changed (43) hide show
  1. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/PKG-INFO +1 -1
  2. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/debugger.py +42 -24
  3. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/ne1830PSS.py +16 -2
  4. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/uiserver.py +118 -11
  5. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/wsnoclib.py +1 -1
  6. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev.egg-info/PKG-INFO +1 -1
  7. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev.egg-info/SOURCES.txt +0 -1
  8. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/setup.py +1 -1
  9. easy_utils_dev-2.155/easy_utils_dev/debugger-C-PF4PAMMP.py +0 -486
  10. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/MANIFEST.in +0 -0
  11. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/EasySsh.py +0 -0
  12. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/Events.py +0 -0
  13. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/FastQueue.py +0 -0
  14. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/NameObject.py +0 -0
  15. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/__init__.py +0 -0
  16. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/abortable.py +0 -0
  17. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/brevosmtp.py +0 -0
  18. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/check_license.py +0 -0
  19. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/cplib.py +0 -0
  20. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/custom_env.py +0 -0
  21. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/easy_oracle.py +0 -0
  22. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/encryptor.py +0 -0
  23. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/ept.py +0 -0
  24. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/ept_sql/create_dirs.sql +0 -0
  25. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/ept_sql/create_ept_tables.sql +0 -0
  26. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/exceptions.py +0 -0
  27. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/filescompressor.py +0 -0
  28. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/generate_license.py +0 -0
  29. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/keycloakapi.py +0 -0
  30. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/lralib.py +0 -0
  31. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/nsp_kafka.py +0 -0
  32. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/openid_server.py +0 -0
  33. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/optics_utils.py +0 -0
  34. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/require_auth.py +0 -0
  35. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/simple_sqlite.py +0 -0
  36. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/temp_memory.py +0 -0
  37. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/utils.py +0 -0
  38. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/winserviceapi.py +0 -0
  39. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev/wsselib.py +0 -0
  40. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev.egg-info/dependency_links.txt +0 -0
  41. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev.egg-info/requires.txt +0 -0
  42. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/easy_utils_dev.egg-info/top_level.txt +0 -0
  43. {easy_utils_dev-2.155 → easy_utils_dev-2.157}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: easy_utils_dev
3
- Version: 2.155
3
+ Version: 2.157
4
4
  Keywords: python3
5
5
  Classifier: Programming Language :: Python :: 3
6
6
  Requires-Dist: psutil
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  import os
3
3
  import shutil
4
- import sys
4
+ import sys , re , random
5
5
  from datetime import datetime
6
6
  from logging.handlers import RotatingFileHandler
7
7
  from .utils import getRandomKey , convert_mb_to_bytes , getTimestamp, mkdirs , start_thread
@@ -33,6 +33,33 @@ def setGlobalDebugLevel(level='info') :
33
33
  gEvent.dispatchEvent('update_debug_level')
34
34
 
35
35
 
36
+ class CensorFilter(logging.Filter):
37
+ def __init__(self):
38
+ super().__init__()
39
+ self.censored_strings = []
40
+ self.censor_ip = True
41
+ # Regex for IPv4
42
+ self.ip_regex = re.compile(r"\b\d{1,3}(?:\.\d{1,3}){3}\b")
43
+
44
+ def add_censored_string(self, value):
45
+ if value:
46
+ self.censored_strings.append(str(value))
47
+
48
+ def filter(self, record):
49
+ msg = record.getMessage()
50
+
51
+ # Replace registered sensitive strings
52
+ for s in self.censored_strings:
53
+ x = random.randint(5, 10)
54
+ msg = msg.replace(s, '*'*x)
55
+ # Replace IPs
56
+ if self.censor_ip :
57
+ msg = self.ip_regex.sub("***.***.***.***", msg)
58
+ # Overwrite message
59
+ record.msg = msg
60
+ record.args = ()
61
+ return True
62
+
36
63
  class DEBUGGER:
37
64
  def __init__(self
38
65
  , name
@@ -45,7 +72,8 @@ class DEBUGGER:
45
72
  global_debugger=None,
46
73
  disable_log_write=False,
47
74
  file_name=None,
48
- seperate_files=True
75
+ seperate_files=True,
76
+ trust_env_log_path=True
49
77
  ):
50
78
  env = custom_env()
51
79
  setupEnvironment( 'debugger' )
@@ -63,6 +91,7 @@ class DEBUGGER:
63
91
  self.create_log_path(homePath, file_name)
64
92
  self.fullSyntax=fullSyntax
65
93
  self.onScreen= onscreen
94
+ self.trust_env_log_path = trust_env_log_path
66
95
  self.id = id
67
96
  self.stream_service = None
68
97
  if not env['debugger'].get(name) :
@@ -78,6 +107,9 @@ class DEBUGGER:
78
107
  self.global_debugger = global_debugger
79
108
  self.isLogWriteDisabled = disable_log_write
80
109
  self.type = "CUSTOM_DEBUGGER"
110
+ self.censor = CensorFilter()
111
+ console_handler.addFilter(self.censor)
112
+
81
113
  self.seperate_files=seperate_files
82
114
  if fullSyntax :
83
115
  f = f"[%(asctime)s]-[{self.name}]-[%(levelname)s]: %(message)s"
@@ -118,8 +150,9 @@ class DEBUGGER:
118
150
  start_thread(target=self.checks_in_bg)
119
151
 
120
152
  def create_log_path(self , base_path , logname ) :
153
+ # print(f"Creating log path : {base_path} {logname}")
121
154
  if not base_path :
122
- base_path = os.path.join(os.getcwd() , 'debug')
155
+ base_path = os.getcwd()
123
156
  if not logname :
124
157
  logname = self.name
125
158
  if base_path :
@@ -128,23 +161,6 @@ class DEBUGGER:
128
161
  self.filename = logname
129
162
  self.lastAbsoluteHomePath = base_path
130
163
  self.log_path_with_filename = os.path.join(base_path, f'{logname}.log')
131
- # print(f"Filename : {self.filename}")
132
- # print(f"Base Home Path : {self.baseHomePath}")
133
- # print(f"Log path With Filename : {self.log_path_with_filename}")
134
- # print(f"Last Absolute Home Path : {self.lastAbsoluteHomePath}")
135
-
136
- def fix_file_not_found_file_rotation(self) :
137
- for i in range(self.BACKUP_COUNT) :
138
- try :
139
- file_path = self.homePath + f'.{i}'
140
- # print(f"Checking log file path : {file_path}")
141
- if not os.path.exists(file_path) :
142
- with open(file_path, 'a+') as f :
143
- # print(f"Creating log file path : {file_path}")
144
- f.write('')
145
- except :
146
- pass
147
-
148
164
 
149
165
  def switch_full_syntax(self , toggle) :
150
166
  if toggle :
@@ -165,9 +181,10 @@ class DEBUGGER:
165
181
  self.console.setFormatter(self.formatter)
166
182
 
167
183
  def updateGlobalHomePath(self ) :
184
+ if not self.trust_env_log_path :
185
+ return
168
186
  if not self.isLogWriteDisabled :
169
187
  getFromEnv = self.env.get('debugger_homepath' , None )
170
- # print(f"getFromEnv : {getFromEnv}")
171
188
  if getFromEnv :
172
189
  self.create_log_path(getFromEnv, self.filename)
173
190
  self.file_handler_class = self.createRotateFileHandler(self.log_path_with_filename)
@@ -258,7 +275,6 @@ class DEBUGGER:
258
275
 
259
276
  def checks_in_bg(self) :
260
277
  while True :
261
- #self.fix_file_not_found_file_rotation()
262
278
  if self.env.get('GLOBAL_DEBUGGER_STREAM_SERVICE') :
263
279
  self.addStreamService(socketio=self.env.get('GLOBAL_DEBUGGER_STREAM_SERVICE'))
264
280
  if self.env.get('debugger_global_level' , None) :
@@ -273,7 +289,8 @@ class DEBUGGER:
273
289
  self.logger.error(f'EASY_UTILS_DEBUG_LEVEL ENV must be one of [info,debug,warning,error,critical] | Current Env Variable Is "{EASY_UTILS_DEBUG_LEVEL}". Skipping ')
274
290
  else :
275
291
  self.set_level(EASY_UTILS_DEBUG_LEVEL)
276
- self.updateGlobalHomePath()
292
+ if self.trust_env_log_path :
293
+ self.updateGlobalHomePath()
277
294
  if os.environ.get("EASY_UTILS_ENABLE_PRINT" , '' ).lower() == 'true' :
278
295
  self.enable_print()
279
296
  sleep(10)
@@ -314,12 +331,13 @@ class DEBUGGER:
314
331
  def changeHomePath( self , path ) :
315
332
  def delet_later(lastAbsoluteHomePath) :
316
333
  if lastAbsoluteHomePath :
317
- sleep(3)
334
+ sleep(1)
318
335
  try :
319
336
  shutil.rmtree(lastAbsoluteHomePath)
320
337
  except :
321
338
  pass
322
339
  start_thread(target=delet_later, args=[self.lastAbsoluteHomePath])
340
+ sleep(.5)
323
341
  self.create_log_path( path , self.filename)
324
342
  self.file_handler_class = self.createRotateFileHandler(self.log_path_with_filename)
325
343
 
@@ -12,9 +12,23 @@ from easy_utils_dev import exceptions
12
12
 
13
13
 
14
14
  class PSS1830 :
15
- def __init__(self , sim=False , debug_name='Auto1830PSS' , auto_enable_tcp_forward=False,file_name=None,debug_home_path=None ) -> None:
15
+ def __init__(self ,
16
+ sim=False ,
17
+ debug_name='Auto1830PSS' ,
18
+ auto_enable_tcp_forward=False,
19
+ file_name=None,
20
+ debug_home_path=None,
21
+ trust_env_log_path=True,
22
+ debugger_kwargs={}
23
+ ) -> None:
16
24
  self.port = None
17
- self.logger = DEBUGGER(debug_name,file_name=file_name, homePath=debug_home_path)
25
+ self.trust_env_log_path = trust_env_log_path
26
+ self.logger = DEBUGGER(
27
+ debug_name,file_name=file_name,
28
+ homePath=debug_home_path,
29
+ trust_env_log_path=trust_env_log_path,
30
+ **debugger_kwargs
31
+ )
18
32
  self.connected = False
19
33
  self.channel = None
20
34
  self.nodeName = None
@@ -1,9 +1,12 @@
1
1
  import gc
2
+ import json
2
3
  import time
4
+ from flask.ctx import F
3
5
  from werkzeug.serving import ThreadedWSGIServer
4
- from easy_utils_dev.utils import getRandomKey , generateToken , getTimestamp
6
+ from easy_utils_dev.utils import convertTimestampToDate, getRandomKey , generateToken , getTimestamp
5
7
  from flask_socketio import SocketIO
6
8
  from engineio.async_drivers import gevent
9
+ from engineio.async_drivers import threading as threading_engineio
7
10
  from flask_cors import CORS
8
11
  import logging , os
9
12
  from flask import jsonify, request , current_app , copy_current_request_context
@@ -18,6 +21,9 @@ from werkzeug.serving import make_ssl_devcert
18
21
  from time import sleep
19
22
  from easy_utils_dev.utils import start_thread , getRandomKeysAndStr , mkdirs
20
23
  from easy_utils_dev.temp_memory import TemporaryMemory
24
+ from easy_utils_dev.debugger import DEBUGGER
25
+ import signal
26
+ import sys
21
27
 
22
28
  def getClassById( id ) :
23
29
  return cenv[id]
@@ -92,6 +98,7 @@ class SocketClientObject :
92
98
 
93
99
  class UISERVER :
94
100
  def __init__(self ,
101
+ logger : DEBUGGER = None,
95
102
  id=getRandomKey(n=15),
96
103
  secretkey=generateToken(),
97
104
  serve_with_secret_key=False,
@@ -121,6 +128,7 @@ class UISERVER :
121
128
  self.bg_requests = {}
122
129
  self.socketio_clients = []
123
130
  self.abort_base_url = '/request/abort'
131
+ self.return_exception_as_code_400 = True
124
132
  self.request_reply_base_url= '/request/result'
125
133
  if https :
126
134
  self.httpProtocol = 'https'
@@ -133,6 +141,10 @@ class UISERVER :
133
141
  start_thread(target=self.delete_very_old_requests)
134
142
  self.secret_key_execlude_urls = []
135
143
  self.socketio_rooms = {}
144
+ self.log_url_requests = True
145
+ self.logger = logger
146
+ self.simulate_network_delay = False
147
+
136
148
 
137
149
  def update_cert(self , crt, ssl ) :
138
150
  self.ssl_crt=crt
@@ -158,6 +170,7 @@ class UISERVER :
158
170
 
159
171
  def delete_very_old_requests(self) :
160
172
  while True :
173
+ sleep(320)
161
174
  now = getTimestamp()
162
175
  for key, value in list(self.bg_requests.items()) :
163
176
  value : AbortRequest = value
@@ -165,7 +178,6 @@ class UISERVER :
165
178
  if value.delete_async_request_ts > now :
166
179
  del self.bg_requests[key]
167
180
  gc.collect()
168
- sleep(320)
169
181
 
170
182
  def create_room(self , room_id : str , members : list[str] ) :
171
183
  self.socketio_rooms[room_id] = members
@@ -197,6 +209,14 @@ class UISERVER :
197
209
  else :
198
210
  return { 'status' : 404 , 'message' : 'Request not found or request is not abortable. Check request headers for abortable flag.'}
199
211
 
212
+ @self.app.route(f"/request/traceback/<key>" , methods=['GET'])
213
+ def get_traceback(key : str ) :
214
+ traceback = self.cache.get(key)
215
+ if traceback :
216
+ return { 'status' : 200 , 'traceback' : traceback.get('traceback') }
217
+ else :
218
+ return { 'status' : 404 , 'message' : 'Traceback not found or expired' }
219
+
200
220
  @self.app.route(f'{self.request_reply_base_url}/<id>' , methods=['GET'])
201
221
  def get_result_of_async_request(id : str ) :
202
222
  request : AbortRequest = self.bg_requests.get(id)
@@ -217,6 +237,10 @@ class UISERVER :
217
237
 
218
238
  @self.app.before_request
219
239
  def before_request() :
240
+ if self.log_url_requests and self.logger :
241
+ self.logger.info(f'[{request.method}]: {request.url}' , source='WebServer')
242
+
243
+
220
244
  if (self.serve_with_secret_key) and (request.path not in self.secret_key_execlude_urls) and (request.headers.get('secretkey') != self.secretkey):
221
245
  return jsonify({"error": "Secret key is invalid"}), 401
222
246
 
@@ -257,26 +281,72 @@ class UISERVER :
257
281
  if request.headers.get('async') == 'false' :
258
282
  target_func = current_app.view_functions.get(request.endpoint)
259
283
  if not target_func:
260
- return jsonify({"error": "Route not found"}), 404
284
+ return {"error": "Route not found"}, 404
261
285
  th = start_thread(target=run_async_job_results, args=[target_func , abort ])
262
286
  abort.thread = th
263
287
  self.bg_requests[requestId] = abort
264
288
  return {"status": 200, "message": "Request now in running bg", "abort_id": abort.abort_id} , 200
265
289
 
290
+ if self.return_exception_as_code_400 :
291
+ @self.app.errorhandler(Exception)
292
+ def handle_exception(e):
293
+
294
+ exc_type, exc_value, exc_traceback = sys.exc_info()
295
+ key = getRandomKeysAndStr(n=10)
296
+ tb_last = traceback.extract_tb(exc_traceback)[-1] # Get last traceback frame
297
+ # Example: file, line, function, text
298
+ error_file = tb_last.filename
299
+ error_line = tb_last.lineno
300
+ error_func = tb_last.name
301
+ error_code = tb_last.line
302
+
303
+ # Log the full traceback (optional)
304
+ traceback.print_exc()
305
+ # Customize the error response
306
+ t = getTimestamp()
307
+ response = {
308
+ "status" : 400 ,
309
+ "key" : key,
310
+ "error": str(e),
311
+ "message": str(e),
312
+ "type": type(e).__name__ ,
313
+ "request_full_url" : request.url ,
314
+ "request_method" : request.method ,
315
+ "endpoint" : request.endpoint ,
316
+ "request_path" : request.path ,
317
+ "error_file" : os.path.basename(error_file).replace('.py' , ''),
318
+ "error_line" : error_line,
319
+ "error_func" : error_func,
320
+ "error_code" : error_code,
321
+ 'timestamp' : t ,
322
+ "date" : convertTimestampToDate(t) ,
323
+ 'traceback_url' : f"/request/traceback/{key}"
324
+ }
325
+ self.logger.error(f'error: {json.dumps(response , indent=4)}')
326
+ self.cache.set( custom_key=key , item={**response , 'traceback' : str(traceback.format_exc())} , auto_destroy_period=1800 , store_deleted_key=False )
327
+ # del response['traceback']
328
+ return response , 200
266
329
 
267
330
  @self.app.after_request
268
331
  def after_request(response) :
332
+
333
+ if self.simulate_network_delay :
334
+ time.sleep(self.simulate_network_delay)
335
+
269
336
  try :
270
337
  now = getTimestamp()
271
338
  response.headers['internalid'] = request.internalid
272
339
  response.headers['start_ts'] = request.start_ts
273
340
  response.headers['end_ts'] = now
274
- response.headers['execution'] = round(now - request.start_ts, 2)
341
+ x = round(now - request.start_ts, 2)
342
+ response.headers['execution'] = x
275
343
  if request.abortable :
276
344
  response.headers['abortid'] = request.abort_id
277
345
  response.headers['abortable'] = True
278
346
  except :
279
347
  response.headers['abortable'] = False
348
+ if self.log_url_requests and self.logger :
349
+ self.logger.info(f'[{request.method}]: {request.url} - [{response.status_code}] [secs:{x}]' , source='WebServer')
280
350
  return response
281
351
 
282
352
  # socketio client connected.
@@ -322,12 +392,18 @@ class UISERVER :
322
392
  return self.wsgi_server
323
393
 
324
394
  def shutdownUi(self) :
395
+ if hasattr(self, 'wsgi_server') and self.wsgi_server:
396
+ try:
397
+ self.wsgi_server.shutdown()
398
+ self.wsgi_server.server_close()
399
+ except:
400
+ pass
325
401
  kill_thread(self.thread)
326
- self.wsgi_server.server_close()
327
- self.wsgi_server.shutdown()
328
402
 
329
403
  def _wait_th(self , t ) :
330
- t.join()
404
+ # t.join()
405
+ while True :
406
+ time.sleep(10)
331
407
 
332
408
 
333
409
  def thrStartUi(self , suppress_prints=True) :
@@ -356,15 +432,46 @@ class UISERVER :
356
432
  log.setLevel(logging.ERROR)
357
433
  wsgi_server.serve_forever()
358
434
 
359
- def startUi(self ,daemon , suppress_prints=True) :
435
+ def on_ctrl_c(self , sig=None, frame=None):
436
+ self.stopUi()
437
+ pid = os.getpid()
438
+ os.kill(pid, signal.SIGTERM)
439
+ sys.exit(0)
440
+
441
+
442
+ def startUi(self , daemon=False , suppress_prints=True , block=False) :
360
443
  self.start_before_request()
361
444
  self.thread = self.flaskprocess = Thread(target=self.thrStartUi , args=[suppress_prints])
362
- self.flaskprocess.daemon = False
445
+ self.flaskprocess.daemon = daemon
363
446
  self.flaskprocess.start()
364
447
  start_thread(target=self._wait_th , args=[self.thread] , daemon=daemon)
448
+ signal.signal(signal.SIGINT, self.on_ctrl_c )
449
+ if block:
450
+ self.wait()
365
451
  return self.thread
366
452
 
453
+ def wait(self):
454
+ """
455
+ Block the main thread to keep it alive for signal handling (Ctrl+C).
456
+ This allows Ctrl+C to be properly detected. Call this after startUi()
457
+ if you want signal handling to work.
458
+ """
459
+ try:
460
+ while self.flaskprocess.is_alive():
461
+ self.flaskprocess.join(timeout=0.1)
462
+ except KeyboardInterrupt:
463
+ if not hasattr(self, '_shutting_down'):
464
+ self._shutting_down = True
465
+ self.on_ctrl_c()
466
+ except SystemExit:
467
+ # Re-raise SystemExit to allow proper program termination
468
+ raise
469
+
367
470
  def stopUi(self) :
471
+ if hasattr(self, 'wsgi_server') and self.wsgi_server:
472
+ try:
473
+ self.wsgi_server.shutdown()
474
+ except:
475
+ pass
368
476
  kill_thread(self.thread)
369
- return True
370
-
477
+ return True
@@ -55,7 +55,7 @@ class WSNOCLIB :
55
55
  password ,
56
56
  debug_level='info',
57
57
  debug_name='wsnoclib' ,
58
- debug_homepath='./debug/',
58
+ debug_homepath='./',
59
59
  request_max_count=30,
60
60
  tmp_dir = tempfile.gettempdir() ,
61
61
  kafka = KafkaConfig(),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: easy_utils_dev
3
- Version: 2.155
3
+ Version: 2.157
4
4
  Keywords: python3
5
5
  Classifier: Programming Language :: Python :: 3
6
6
  Requires-Dist: psutil
@@ -10,7 +10,6 @@ easy_utils_dev/brevosmtp.py
10
10
  easy_utils_dev/check_license.py
11
11
  easy_utils_dev/cplib.py
12
12
  easy_utils_dev/custom_env.py
13
- easy_utils_dev/debugger-C-PF4PAMMP.py
14
13
  easy_utils_dev/debugger.py
15
14
  easy_utils_dev/easy_oracle.py
16
15
  easy_utils_dev/encryptor.py
@@ -1,6 +1,6 @@
1
1
  from setuptools import setup, find_packages
2
2
 
3
- VERSION = '2.155'
3
+ VERSION = '2.157'
4
4
 
5
5
  # Setting up
6
6
  setup(
@@ -1,486 +0,0 @@
1
- import logging
2
- import os
3
- import sys
4
- from datetime import datetime
5
- from logging.handlers import RotatingFileHandler
6
- from .utils import getRandomKey , convert_mb_to_bytes , getTimestamp , start_thread
7
- from .custom_env import custom_env , setupEnvironment
8
- from .Events import EventEmitter
9
- from threading import Thread
10
- from time import sleep
11
-
12
- gEvent = EventEmitter()
13
- logging.addLevelName(25, "SCREEN")
14
-
15
- def setGlobalHomePath( path ) :
16
- env = custom_env()
17
- env['debugger_homepath'] = path
18
- gEvent.dispatchEvent('update_home_path')
19
-
20
- def setGlobalDisableOnScreen(on_screen=False) :
21
- env = custom_env()
22
- env['debugger_on_screen'] = on_screen
23
- if not on_screen :
24
- gEvent.dispatchEvent('disable_global_printing')
25
- else :
26
- gEvent.dispatchEvent('enable_global_printing')
27
-
28
-
29
- def setGlobalDebugLevel(level='info') :
30
- env = custom_env()
31
- env['debugger_global_level'] = level
32
- gEvent.dispatchEvent('update_debug_level')
33
-
34
-
35
- class DEBUGGER:
36
- def __init__(self
37
- , name
38
- , level='info',
39
- fullSyntax=True,
40
- onscreen=True,
41
- log_rotation=3,
42
- homePath=None,
43
- id=getRandomKey(9) ,
44
- global_debugger=None,
45
- disable_log_write=False,
46
- file_name=None,
47
- seperate_files=True
48
- ):
49
- env = custom_env()
50
- setupEnvironment( 'debugger' )
51
- debugger_on_screen = env.get('debugger_on_screen' , True)
52
- env['debugger_on_screen'] = debugger_on_screen
53
- self.env = env
54
- self.events = gEvent
55
- self.debuggerLabel = f"{name}"
56
- self.logger = logging.getLogger(self.debuggerLabel)
57
- self.set_level(level)
58
- self.file_handler_class=None
59
- self.LOG_SIZE_THRESHOLD_IN_BYTES = 10 * 1024 * 1024
60
- self.BACKUP_COUNT = log_rotation
61
- self.homePath = homePath
62
- self.lastAbsoluteHomePath= None
63
- self.fullSyntax=fullSyntax
64
- self.onScreen= onscreen
65
- self.id = id
66
- self.how_many_times_write= 0
67
- self.stream_service = None
68
- if not env['debugger'].get(name) :
69
- self.console = console_handler = logging.StreamHandler()
70
- else :
71
- self.console = console_handler = env['debugger'].get(name).console
72
- if not self.logger.hasHandlers() :
73
- self.logger.addHandler(self.console)
74
- self.name = name
75
- self.rotate_disabled=False
76
- self.isInPyinstaller = False
77
- self.log_iterations=0
78
- self.log_iterations_threshold = 200
79
- self.global_debugger = global_debugger
80
- self.isLogWriteDisabled = disable_log_write
81
- self.type = "CUSTOM_DEBUGGER"
82
- self.seperate_files=seperate_files
83
- if fullSyntax :
84
- f = f"[%(asctime)s]-[{self.name}]-[%(levelname)s]: %(message)s"
85
- else :
86
- f = f"[{self.name}]-[%(levelname)s]: %(message)s"
87
- self.syntax = f
88
- self.formatter = logging.Formatter(f , datefmt='%Y-%m-%d %H:%M:%S' )
89
- self.filename = file_name
90
- path = self.homepath(homePath)
91
- if not env['debugger'].get(name) :
92
- console_handler.setFormatter(self.formatter)
93
- if not disable_log_write :
94
- if not env['debugger'].get(name) :
95
- self.file_handler_class = self.createRotateFileHandler(path)
96
- if onscreen :
97
- self.enable_print()
98
- elif not onscreen :
99
- self.disable_print()
100
- self.events.addEventListener('disable_global_printing' , self.disable_print )
101
- self.events.addEventListener('enable_global_printing' , self.enable_print )
102
- self.events.addEventListener('update_home_path' , self.updateGlobalHomePath )
103
- self.events.addEventListener('update_debug_level' , self.updateGlobalSetLevel )
104
- if env['debugger'].get(name) :
105
- self = env['debugger'].get(name)
106
- else:
107
- env['debugger'][id] = self
108
- env['debugger'][name] = self
109
- if not env.get('debugger_on_screen' , True ) :
110
- self.disable_print()
111
- if env.get('debugger_on_screen' , True ) :
112
- self.enable_print()
113
- if os.environ.get("EASY_UTILS_DEBUG_LEVEL") :
114
- EASY_UTILS_DEBUG_LEVEL = os.environ.get("EASY_UTILS_DEBUG_LEVEL")
115
- if not EASY_UTILS_DEBUG_LEVEL.lower() in ['info' , 'debug' , 'warning' , 'error' , 'critical'] :
116
- self.logger.error(f'EASY_UTILS_DEBUG_LEVEL ENV must be one of [info,debug,warning,error,critical] | Current Env Variable Is "{EASY_UTILS_DEBUG_LEVEL}". Skipping ')
117
- else :
118
- self.set_level(EASY_UTILS_DEBUG_LEVEL)
119
- if os.environ.get("EASY_UTILS_ENABLE_PRINT" , '' ).lower() == 'true' :
120
- self.enable_print()
121
-
122
- def switch_full_syntax(self , toggle) :
123
- if toggle :
124
- f = f"[%(asctime)s]-[{self.name}]-[%(levelname)s]: %(message)s"
125
- else :
126
- f = f"[{self.name}]-[%(levelname)s]: %(message)s"
127
- self.syntax = f
128
- self.formatter = logging.Formatter(f , datefmt='%Y-%m-%d %H:%M:%S' )
129
- self.console.setFormatter(self.formatter)
130
-
131
- def custom_log_syntax(self , syntax) :
132
- '''
133
- f"[%(asctime)s]-[{self.name}]-[%(levelname)s]: %(message)s"
134
- '''
135
- f = syntax
136
- self.syntax = f
137
- self.formatter = logging.Formatter(f , datefmt='%Y-%m-%d %H:%M:%S' )
138
- self.console.setFormatter(self.formatter)
139
-
140
- def updateGlobalHomePath(self ) :
141
- if not self.isLogWriteDisabled :
142
- getFromEnv = self.env.get('debugger_homepath' , None )
143
- self.homepath(getFromEnv)
144
- if getFromEnv :
145
- self.file_handler_class = self.createRotateFileHandler(self.homePath)
146
-
147
- def updateGlobalSetLevel( self ) :
148
- self.set_level(self.env['debugger_global_level'])
149
-
150
- def advertiseGlobalDebugLevel(self , level) :
151
- setGlobalDebugLevel(level)
152
-
153
- def disable_rotate(self) :
154
- self.rotate_disabled = True
155
-
156
- def enable_rotate(self) :
157
- self.rotate_disabled = False
158
-
159
- def createRotateFileHandler( self , path ) :
160
- old = self.file_handler_class
161
- if old :
162
- self.logger.removeHandler(old)
163
- file_handler = RotatingFileHandler(path , maxBytes=self.LOG_SIZE_THRESHOLD_IN_BYTES , backupCount=self.BACKUP_COUNT , delay=True )
164
- self.file_handler= file_handler.setFormatter(self.formatter)
165
- self.logger.addHandler(file_handler)
166
- return file_handler
167
-
168
- def update_log_iterantions_threshold(self,threshold : int ):
169
- '''
170
- set value when rotation should be checked. when every on_log function called.
171
- by default rotation will be checked every 200 on_log function call.
172
- '''
173
- self.log_iterations_threshold = threshold
174
-
175
- def updateGlobalDebugger(self , logger ) :
176
- '''
177
- this function pass the log message to other logger to write the same log message to it.
178
- logger must be debugger class.
179
- '''
180
- if logger.type != 'CUSTOM_DEBUGGER' :
181
- raise Exception(f'Invalid logger type. must pass debugger class.')
182
- self.global_debugger = logger
183
-
184
- def getStreamServiceUrlPath(self) :
185
- return self.streampath
186
-
187
- def getStreamService(self) :
188
- return self.stream_service
189
-
190
- def isStreamServiceAvailable(self) :
191
- if self.stream_service :
192
- return True
193
- return False
194
-
195
- def addStreamService( self , socketio , streampath='/debugger/stream/log' ) :
196
- """
197
- This function takes a live socketio server. it emit the log message using default path which is /debugger/stream/log
198
- """
199
- self.stream_service = socketio
200
- self.streampath = streampath
201
-
202
- def updateLogName( self , name ) :
203
- self.name = name
204
-
205
- def disable_log_write(self) :
206
- '''
207
- this function is used to disable the log write to file. if onScreen is enabled, logs will be displayed only on screen.
208
- '''
209
- self.isLogWriteDisabled = True
210
- if self.file_handler_class :
211
- self.logger.removeHandler(self.file_handler_class)
212
-
213
- def enable_log_write(self) :
214
- self.createRotateFileHandler(self.homePath)
215
-
216
- def manage_file_rotation(self, record ) :
217
- handler = self.get_rotate_handler()
218
- if handler.shouldRollover(record) :
219
- handler.doRollover()
220
- self.log_iterations = 0
221
-
222
- def get_rotate_handler(self) :
223
- return self.file_handler_class
224
-
225
- def change_log_size(self, size) -> bool:
226
- '''
227
- change the size of each log file rotation.
228
- default is 10M
229
- size should be passed as MB
230
- '''
231
- size = convert_mb_to_bytes(size)
232
- self.LOG_SIZE_THRESHOLD_IN_BYTES = size
233
- handler = self.get_rotate_handler()
234
- handler.maxBytes = size
235
- return True
236
-
237
-
238
- def checks_in_bg(self) :
239
- while True :
240
- if self.env.get('GLOBAL_DEBUGGER_STREAM_SERVICE') :
241
- self.addStreamService(socketio=self.env.get('GLOBAL_DEBUGGER_STREAM_SERVICE'))
242
- if self.env.get('debugger_global_level' , None) :
243
- self.set_level( level=self.env.get('debugger_global_level') )
244
- if not self.env.get('debugger_on_screen' , True ) :
245
- self.disable_print()
246
- if self.env.get('debugger_on_screen' , True ) :
247
- self.enable_print()
248
- if os.environ.get("EASY_UTILS_DEBUG_LEVEL") :
249
- EASY_UTILS_DEBUG_LEVEL = os.environ.get("EASY_UTILS_DEBUG_LEVEL")
250
- if not EASY_UTILS_DEBUG_LEVEL.lower() in ['info' , 'debug' , 'warning' , 'error' , 'critical'] :
251
- self.logger.error(f'EASY_UTILS_DEBUG_LEVEL ENV must be one of [info,debug,warning,error,critical] | Current Env Variable Is "{EASY_UTILS_DEBUG_LEVEL}". Skipping ')
252
- else :
253
- self.set_level(EASY_UTILS_DEBUG_LEVEL)
254
- self.updateGlobalHomePath()
255
- if os.environ.get("EASY_UTILS_ENABLE_PRINT" , '' ).lower() == 'true' :
256
- self.enable_print()
257
- sleep(5)
258
-
259
- def close(self) :
260
- try :
261
- logging.shutdown()
262
- except :
263
- pass
264
-
265
- def homepath(self , path=None ) :
266
- env = custom_env()
267
- getFromEnv = env.get('debugger_homepath' , None )
268
- if getFromEnv is not None :
269
- self.homePath = getFromEnv
270
- else :
271
- if path is not None :
272
- if self.homePath and '.log' in str(self.homePath):
273
- self.lastAbsoluteHomePath= self.homePath
274
- self.homePath = path
275
- else :
276
- self.homePath = os.path.join(os.getcwd() , 'debug')
277
- if not os.path.exists( self.homePath ) :
278
- try :
279
- os.makedirs( self.homePath )
280
- except :
281
- pass
282
- if self.filename :
283
- self.homePath = os.path.join( self.homePath, f'{self.filename}.log' )
284
- else :
285
- self.homePath = os.path.join( self.homePath, f'{self.name}.log' )
286
- return self.homePath
287
-
288
- def get_current_levels(self):
289
- """
290
- Returns a list of log levels that will be printed based on the current logging level.
291
- """
292
- levels_order = [
293
- ('debug', logging.DEBUG),
294
- ('info', logging.INFO),
295
- ('warning', logging.WARNING),
296
- ('error', logging.ERROR),
297
- ('critical', logging.CRITICAL),
298
- ]
299
- # Optional custom level
300
- if hasattr(logging, 'SCREEN'):
301
- levels_order.append(('screen', logging.SCREEN))
302
- current_level = self.logger.level
303
- # Return all levels with numeric value >= current_level
304
- return [name for name, value in levels_order if value >= current_level]
305
-
306
- def enable_print(self) :
307
- self.onScreen = True
308
- self.logger.addHandler(self.console)
309
-
310
- def disable_print(self) :
311
- self.onScreen = False
312
- self.logger.removeHandler(self.console)
313
-
314
- def changeHomePath( self , path ) :
315
- p = self.homepath(path)
316
- self.file_handler_class = self.createRotateFileHandler(p)
317
- if self.lastAbsoluteHomePath :
318
- os.remove(self.lastAbsoluteHomePath)
319
-
320
- def isGlobalDebuggerDefined(self) :
321
- if self.global_debugger :
322
- return True
323
- else :
324
- return False
325
-
326
- def set_level(self, level : str):
327
- if 'info' in level.lower() : lvl = logging.INFO
328
- elif 'warn' in level.lower() : lvl = logging.WARNING
329
- elif 'warning' in level.lower() : lvl = logging.WARNING
330
- elif 'critical' in level.lower() : lvl = logging.CRITICAL
331
- elif 'debug' in level.lower() : lvl = logging.DEBUG
332
- elif 'error' in level.lower() : lvl = logging.ERROR
333
- elif 'screen' in level.lower() : lvl = logging.SCREEN
334
- else : raise ValueError('Unknown level, not one of [info,warn,warning,critical,debug,error,screen]')
335
- self.currentDebugLevel = level
336
- self.logger.setLevel(lvl)
337
-
338
- def get_current_debug_level(self) :
339
- return self.currentDebugLevel
340
-
341
- def get_logger(self) :
342
- return self.logger
343
-
344
- def before_log(self , message , level) :
345
-
346
- def __call_thread__() :
347
- if not level in self.get_current_levels() :
348
- return
349
- if self.isStreamServiceAvailable() :
350
- d = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
351
- streamUrl = self.getStreamServiceUrlPath()
352
- self.stream_service.emit( streamUrl , {
353
- 'message' : message ,
354
- 'level' : level ,
355
- 'msg' : message,
356
- 'date' : d ,
357
- 'id' : self.id,
358
- 'formate' : 'json' ,
359
- 'source' : self.name ,
360
- 'getTimestamp' : getTimestamp()
361
- })
362
- try :
363
- t= Thread(target=__call_thread__)
364
- # t.daemon=True
365
- t.start()
366
- except :
367
- __call_thread__()
368
-
369
- params = {
370
- 'screen' : True ,
371
- 'file': True
372
- }
373
- if self.onScreen and self.env['debugger_on_screen'] == True :
374
- params['screen'] = True
375
- else :
376
- params['screen'] = False
377
- return params
378
-
379
-
380
- def info(self, message , external_debugger=None,source=None):
381
- def __call__(message) :
382
- if source :
383
- message = f'[{source}]-{message}'
384
- self.before_log(message , 'info')
385
- self.logger.info(message)
386
- if self.isGlobalDebuggerDefined() :
387
- self.global_debugger.info(message)
388
- if external_debugger :
389
- external_debugger.info(message)
390
- try :
391
- r=Thread(target=__call__,args=[message])
392
- r.daemon=True
393
- r.start()
394
- r.join()
395
- except :
396
- __call__(message)
397
-
398
- def debug(self, message , external_debugger=None,source=None):
399
- def __call__(message) :
400
- if source :
401
- message = f'[{source}]-{message}'
402
- self.before_log(message , 'debug')
403
- self.logger.debug(message)
404
- if self.isGlobalDebuggerDefined() :
405
- self.global_debugger.debug(message)
406
- if external_debugger :
407
- external_debugger.debug(message)
408
- try :
409
- r=Thread(target=__call__,args=[message])
410
- r.daemon=True
411
- r.start()
412
- r.join()
413
- except :
414
- __call__(message)
415
-
416
- def warning(self, message , external_debugger=None,source=None):
417
- def __call__(message) :
418
- if source :
419
- message = f'[{source}]-{message}'
420
- self.before_log(message , 'warning')
421
- self.logger.warning(message)
422
- if self.isGlobalDebuggerDefined() :
423
- self.global_debugger.warning(message)
424
- if external_debugger :
425
- external_debugger.warning(message)
426
- try :
427
- r=Thread(target=__call__,args=[message])
428
- r.daemon=True
429
- r.start()
430
- r.join()
431
- except :
432
- __call__(message)
433
-
434
- def error(self, message,external_debugger=None,source=None):
435
- def __call__(message) :
436
- if source :
437
- message = f'[{source}]-{message}'
438
- self.before_log(message , 'error')
439
- self.logger.error(message)
440
- if self.isGlobalDebuggerDefined() :
441
- self.global_debugger.error(message)
442
- if external_debugger :
443
- external_debugger.error(message)
444
- try :
445
- r=Thread(target=__call__,args=[message])
446
- r.daemon=True
447
- r.start()
448
- r.join()
449
- except :
450
- __call__(message)
451
-
452
- def critical(self, message,external_debugger=None,source=None):
453
- def __call__() :
454
- if source :
455
- message = f'[{source}]-{message}'
456
- self.before_log(message , 'critical')
457
- self.logger.critical(message)
458
- if self.isGlobalDebuggerDefined() :
459
- self.global_debugger.critical(message)
460
- if external_debugger :
461
- external_debugger.critical(message)
462
- try :
463
- r=Thread(target=__call__,args=[message])
464
- r.daemon=True
465
- r.start()
466
- r.join()
467
- except :
468
- __call__(message)
469
-
470
- def screen(self, message,external_debugger=None,source=None):
471
- def __call__() :
472
- if source :
473
- message = f'[{source}]-{message}'
474
- self.before_log(message , 'critical')
475
- print(f"{self.syntax}")
476
- if self.isGlobalDebuggerDefined() :
477
- self.global_debugger.critical(message)
478
- if external_debugger :
479
- external_debugger.critical(message)
480
- try :
481
- r=Thread(target=__call__,args=[message])
482
- r.daemon=True
483
- r.start()
484
- r.join()
485
- except :
486
- __call__(message)
File without changes