Coverage for gws-app/gws/core/debug.py: 15%
112 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 01:37 +0200
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 01:37 +0200
1"""Debuggging tools"""
3import re
4import socket
5import sys
6import time
7import traceback
9from . import log
12def inspect(arg, max_depth=1, all_props=False):
13 """Inspect the argument upto the given depth"""
15 yield from _dump(arg, None, 0, max_depth or 1, all_props, [])
18def p(*args, lines=False, stack=False, d=3, all=False):
19 """Log an inspection of the arguments"""
21 sep = '-' * 60
23 if lines:
24 for arg in args:
25 for s in enumerate(str(arg).split('\n'), 1):
26 log.debug('%06d:%s' % s, stacklevel=2)
27 log.debug(sep, stacklevel=2)
28 return
30 if stack:
31 for s in traceback.format_stack()[:-1]:
32 log.debug(s.replace('\n', ' '), stacklevel=2)
33 return
35 for arg in args:
36 for s in inspect(arg, max_depth=d, all_props=all):
37 log.debug(s, stacklevel=2)
38 log.debug(sep, stacklevel=2)
41_TIME_STACK = []
44def time_start(label=None):
45 _TIME_STACK.append((time.time(), label or 'default'))
48def time_end():
49 if _TIME_STACK:
50 t2 = time.time()
51 t1, label = _TIME_STACK.pop()
52 log.debug(f'@PROFILE {label} :: {t2 - t1:.2f}', stacklevel=2)
55def pycharm_debugger_check(path_to_pycharm_debug_egg, host, port, suspend=False):
56 """Check for pycharm debugger listeniing.
58 Attempt to open the debugger socket first and return that socket when pydevd asks for it.
59 If there is no socket, then IDEA is not listening, return quickly.
60 """
62 sock = None
63 try:
64 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
65 sock.connect((host, port))
66 except:
67 sock = None
69 if not sock:
70 return False
72 if not path_to_pycharm_debug_egg.endswith('.egg'):
73 if sys.version_info >= (3, 0):
74 path_to_pycharm_debug_egg += '/pycharm-debug-py3k.egg'
75 else:
76 path_to_pycharm_debug_egg += '/pycharm-debug.egg'
78 sys.path.append(path_to_pycharm_debug_egg)
79 pydevd = __import__('pydevd')
81 pydevd.StartClient = lambda h, p: sock
82 pydevd.start_client = lambda h, p: sock
83 pydevd.settrace(host, port=port, stdoutToServer=True, stderrToServer=True, suspend=suspend)
85 return True
88##
91_noexpand = {
92 "<class 'datetime.datetime'>",
93 "<class 'datetime.date'>",
94 "<class 'memoryview'>",
95}
98def _should_list(k, v):
99 if k.startswith('__'):
100 return False
101 if isinstance(v, type):
102 return True
103 if callable(v):
104 return False
105 return True
108_MAX_REPR_LEN = 255
111def _repr(x):
112 s = repr(x)
113 if len(s) > _MAX_REPR_LEN:
114 s = s[:_MAX_REPR_LEN] + '...'
115 return s
118def _dump(x, name, depth, max_depth, all_props, seen):
119 pfx = ' ' * depth
121 if name:
122 pfx += str(name) + ': '
124 t = str(type(x))
125 m = re.match(r"^<(type|class) '(.+?)'>", t)
126 pfx += m.group(2) if m else t
128 try:
129 pfx += '(%d)' % len(x)
130 except (TypeError, AttributeError):
131 pass
133 head = pfx + ' = ' + _repr(x)
135 if not x or isinstance(x, (bool, int, float, str, bytes)):
136 yield head
137 return
139 if not all_props and str(type(x)) in _noexpand:
140 yield head
141 return
143 try:
144 if x in seen:
145 yield head
146 return
147 seen.append(x)
148 except:
149 pass
151 if depth >= max_depth:
152 yield pfx + '...'
153 return
155 if isinstance(x, dict):
156 yield pfx + ' = '
157 for k in x:
158 yield from _dump(x[k], repr(k), depth + 1, max_depth, all_props, seen)
159 return
161 if isinstance(x, (set, list, tuple)):
162 yield pfx + ' = '
163 for k, v in enumerate(x):
164 yield from _dump(v, str(k), depth + 1, max_depth, all_props, seen)
165 return
167 yield head
169 for k in dir(x):
170 try:
171 v = getattr(x, k)
172 except Exception as e:
173 v = '?' + repr(e)
174 if all_props or _should_list(k, v):
175 yield from _dump(v, k, depth + 1, max_depth, all_props, seen)