osbot-utils 1.35.0__py3-none-any.whl → 1.37.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- osbot_utils/context_managers/capture_duration.py +11 -7
- osbot_utils/helpers/trace/Trace_Call.py +44 -0
- osbot_utils/helpers/trace/Trace_Call__Config.py +1 -0
- osbot_utils/helpers/trace/Trace_Call__Handler.py +18 -5
- osbot_utils/testing/Stderr.py +10 -4
- osbot_utils/testing/Stdout.py +9 -3
- osbot_utils/utils/Env.py +6 -1
- osbot_utils/version +1 -1
- {osbot_utils-1.35.0.dist-info → osbot_utils-1.37.0.dist-info}/METADATA +2 -2
- {osbot_utils-1.35.0.dist-info → osbot_utils-1.37.0.dist-info}/RECORD +12 -12
- {osbot_utils-1.35.0.dist-info → osbot_utils-1.37.0.dist-info}/LICENSE +0 -0
- {osbot_utils-1.35.0.dist-info → osbot_utils-1.37.0.dist-info}/WHEEL +0 -0
@@ -1,12 +1,13 @@
|
|
1
|
+
from osbot_utils.base_classes.Type_Safe import Type_Safe
|
1
2
|
from osbot_utils.utils.Misc import timestamp_utc_now
|
2
3
|
|
3
4
|
|
4
|
-
class capture_duration():
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
class capture_duration(Type_Safe):
|
6
|
+
action_name : str
|
7
|
+
duration : float
|
8
|
+
start_timestamp : int
|
9
|
+
end_timestamp : int
|
10
|
+
seconds : float
|
10
11
|
|
11
12
|
def __enter__(self):
|
12
13
|
self.start_timestamp = timestamp_utc_now()
|
@@ -23,7 +24,10 @@ class capture_duration():
|
|
23
24
|
|
24
25
|
def print(self):
|
25
26
|
print()
|
26
|
-
|
27
|
+
if self.action_name:
|
28
|
+
print(f'action "{self.action_name}" took: {self.seconds} seconds')
|
29
|
+
else:
|
30
|
+
print(f'action took: {self.seconds} seconds')
|
27
31
|
|
28
32
|
class print_duration(capture_duration):
|
29
33
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import linecache
|
2
2
|
import sys
|
3
|
+
import threading
|
3
4
|
from functools import wraps
|
4
5
|
|
5
6
|
from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
|
@@ -8,6 +9,8 @@ from osbot_utils.helpers.trace.Trace_Call__Handler import Trace_Call__H
|
|
8
9
|
from osbot_utils.helpers.trace.Trace_Call__Print_Lines import Trace_Call__Print_Lines
|
9
10
|
from osbot_utils.helpers.trace.Trace_Call__Print_Traces import Trace_Call__Print_Traces
|
10
11
|
from osbot_utils.helpers.trace.Trace_Call__View_Model import Trace_Call__View_Model
|
12
|
+
from osbot_utils.testing.Stdout import Stdout
|
13
|
+
from osbot_utils.utils.Str import ansi_to_text
|
11
14
|
|
12
15
|
|
13
16
|
def trace_calls(title = None , print_traces = True , show_locals = False, source_code = False ,
|
@@ -59,6 +62,7 @@ class Trace_Call(Kwargs_To_Self):
|
|
59
62
|
self.config.trace_capture_contains = self.config.trace_capture_contains or [] # and None will be quite common since we can use [] on method's params
|
60
63
|
self.config.print_max_string_length = self.config.print_max_string_length or PRINT_MAX_STRING_LENGTH
|
61
64
|
self.stack = self.trace_call_handler.stack
|
65
|
+
self.trace_on_thread__data = {}
|
62
66
|
#self.prev_trace_function = None # Stores the previous trace function
|
63
67
|
|
64
68
|
|
@@ -94,6 +98,13 @@ class Trace_Call(Kwargs_To_Self):
|
|
94
98
|
#self.print_lines()
|
95
99
|
return view_model
|
96
100
|
|
101
|
+
def print_to_str(self):
|
102
|
+
with Stdout() as stdout:
|
103
|
+
self.print()
|
104
|
+
trace_data = ansi_to_text(stdout.value())
|
105
|
+
return trace_data
|
106
|
+
|
107
|
+
|
97
108
|
def print_lines(self):
|
98
109
|
print()
|
99
110
|
view_model = self.view_data()
|
@@ -106,6 +117,27 @@ class Trace_Call(Kwargs_To_Self):
|
|
106
117
|
self.started = True # set this here so that it does show in the trace
|
107
118
|
sys.settrace(self.trace_call_handler.trace_calls) # Set the new trace function
|
108
119
|
|
120
|
+
def start__on_thread(self, root_node=None):
|
121
|
+
if sys.gettrace() is None:
|
122
|
+
current_thread = threading.current_thread()
|
123
|
+
thread_sys_trace = sys.gettrace()
|
124
|
+
thread_name = current_thread.name
|
125
|
+
thread_id = current_thread.native_id
|
126
|
+
thread_nodes = []
|
127
|
+
thread_data = dict(thread_name = thread_name ,
|
128
|
+
thread_id = thread_id ,
|
129
|
+
thread_nodes = thread_nodes ,
|
130
|
+
thread_sys_trace = thread_sys_trace)
|
131
|
+
title = f"Thread: {thread_name} ({thread_id})"
|
132
|
+
thread_node__for_title = self.trace_call_handler.stack.add_node(title=title) # Add node with name of Thread
|
133
|
+
|
134
|
+
if root_node: # Add node with name of node
|
135
|
+
thread_node__for_root = self.trace_call_handler.stack.add_node(root_node)
|
136
|
+
thread_nodes.append(thread_node__for_root)
|
137
|
+
thread_nodes.append(thread_node__for_title)
|
138
|
+
sys.settrace(self.trace_call_handler.trace_calls)
|
139
|
+
self.trace_on_thread__data[thread_id] = thread_data
|
140
|
+
|
109
141
|
|
110
142
|
def stop(self):
|
111
143
|
if self.started:
|
@@ -113,6 +145,18 @@ class Trace_Call(Kwargs_To_Self):
|
|
113
145
|
self.stack.empty_stack()
|
114
146
|
self.started = False
|
115
147
|
|
148
|
+
def stop__on_thread(self):
|
149
|
+
current_thread = threading.current_thread()
|
150
|
+
thread_id = current_thread.native_id
|
151
|
+
thread_data = self.trace_on_thread__data.get(thread_id)
|
152
|
+
if thread_data: # if there trace_call set up in the current thread
|
153
|
+
thread_sys_trace = thread_data.get('thread_sys_trace')
|
154
|
+
thread_nodes = thread_data.get('thread_nodes')
|
155
|
+
for thread_node in thread_nodes: # remove extra nodes added during start__on_thread
|
156
|
+
self.trace_call_handler.stack.pop(thread_node)
|
157
|
+
sys.settrace(thread_sys_trace) # restore previous sys.trace value
|
158
|
+
del self.trace_on_thread__data[thread_id]
|
159
|
+
|
116
160
|
def stats(self):
|
117
161
|
return self.trace_call_handler.stats
|
118
162
|
|
@@ -33,6 +33,7 @@ class Trace_Call__Config(Kwargs_To_Self):
|
|
33
33
|
trace_capture_contains : list
|
34
34
|
trace_enabled : bool = True
|
35
35
|
trace_ignore_start_with : list
|
36
|
+
trace_ignore_contains : list
|
36
37
|
trace_show_internals : bool
|
37
38
|
trace_up_to_depth : int
|
38
39
|
with_duration_bigger_than : float
|
@@ -20,11 +20,19 @@ GLOBAL_FUNCTIONS_TO_IGNORE = ['value_type_matches_obj_annotation_for_attr'
|
|
20
20
|
'__default__value__' ,
|
21
21
|
'__setattr__' ,
|
22
22
|
'<module>']
|
23
|
-
GLOBAL_MODULES_TO_IGNORE = ['osbot_utils.helpers.trace.Trace_Call'
|
24
|
-
'osbot_utils.helpers.
|
25
|
-
'osbot_utils.helpers.
|
26
|
-
'osbot_utils.
|
27
|
-
'
|
23
|
+
GLOBAL_MODULES_TO_IGNORE = ['osbot_utils.helpers.trace.Trace_Call' , # todo: map out and document why exactly these modules are ignore (and what is the side effect)
|
24
|
+
'osbot_utils.helpers.trace.Trace_Call__Config' ,
|
25
|
+
'osbot_utils.helpers.trace.Trace_Call__View_Model' ,
|
26
|
+
'osbot_utils.helpers.trace.Trace_Call__Print_Traces' ,
|
27
|
+
'osbot_utils.helpers.trace.Trace_Call__Stack' ,
|
28
|
+
'osbot_utils.base_classes.Type_Safe' ,
|
29
|
+
'osbot_utils.helpers.CPrint' , # also see if this should be done here or at the print/view stage
|
30
|
+
'osbot_utils.helpers.Print_Table' ,
|
31
|
+
'osbot_utils.decorators.methods.cache_on_self' ,
|
32
|
+
'codecs' ]
|
33
|
+
|
34
|
+
#GLOBAL_MODULES_TO_IGNORE = []
|
35
|
+
#GLOBAL_FUNCTIONS_TO_IGNORE = []
|
28
36
|
|
29
37
|
class Trace_Call__Handler(Kwargs_To_Self):
|
30
38
|
config : Trace_Call__Config
|
@@ -171,6 +179,11 @@ class Trace_Call__Handler(Kwargs_To_Self):
|
|
171
179
|
if module.startswith(item) or func_name.startswith(item):
|
172
180
|
capture = False
|
173
181
|
break
|
182
|
+
|
183
|
+
for item in self.config.trace_ignore_contains: # Check if the module should be ignored
|
184
|
+
if item in module or item in func_name:
|
185
|
+
capture = False
|
186
|
+
break
|
174
187
|
return capture
|
175
188
|
|
176
189
|
def stack_json__parse_node(self, stack_node: Trace_Call__Stack_Node):
|
osbot_utils/testing/Stderr.py
CHANGED
@@ -2,17 +2,23 @@ import io
|
|
2
2
|
from contextlib import redirect_stderr
|
3
3
|
|
4
4
|
|
5
|
-
class Stderr:
|
5
|
+
class Stderr: # todo: refactor with Stdout whose code is 90% the same as this one. Add class to capture both at the same time
|
6
6
|
def __init__(self):
|
7
7
|
self.output = io.StringIO()
|
8
8
|
self.redirect_stderr = redirect_stderr(self.output)
|
9
9
|
|
10
10
|
def __enter__(self):
|
11
|
-
self.
|
11
|
+
self.start()
|
12
12
|
return self
|
13
13
|
|
14
|
-
def __exit__(self,
|
15
|
-
self.
|
14
|
+
def __exit__(self, *args, **kwargs):
|
15
|
+
self.stop(*args, **kwargs)
|
16
|
+
|
17
|
+
def start(self):
|
18
|
+
self.redirect_stderr.__enter__()
|
19
|
+
|
20
|
+
def stop(self, exc_type=None, exc_inst=None, exc_tb=None):
|
21
|
+
self.redirect_stderr.__exit__(exc_type, exc_inst, exc_tb)
|
16
22
|
|
17
23
|
def value(self):
|
18
24
|
return self.output.getvalue()
|
osbot_utils/testing/Stdout.py
CHANGED
@@ -8,11 +8,17 @@ class Stdout:
|
|
8
8
|
self.redirect_stdout = redirect_stdout(self.output)
|
9
9
|
|
10
10
|
def __enter__(self):
|
11
|
-
self.
|
11
|
+
self.start()
|
12
12
|
return self
|
13
13
|
|
14
|
-
def __exit__(self,
|
15
|
-
self.
|
14
|
+
def __exit__(self, *args, **kwargs):
|
15
|
+
self.stop(*args, **kwargs)
|
16
|
+
|
17
|
+
def start(self):
|
18
|
+
self.redirect_stdout.__enter__()
|
19
|
+
|
20
|
+
def stop(self, exc_type=None, exc_inst=None, exc_tb=None):
|
21
|
+
self.redirect_stdout.__exit__(exc_type, exc_inst, exc_tb)
|
16
22
|
|
17
23
|
def value(self):
|
18
24
|
return self.output.getvalue()
|
osbot_utils/utils/Env.py
CHANGED
@@ -20,7 +20,9 @@ def env__pwd():
|
|
20
20
|
return get_env('PWD', '')
|
21
21
|
|
22
22
|
def env__old_pwd__remove(value):
|
23
|
-
|
23
|
+
if env__old_pwd() != '/': # can't replace with old pwd is just /
|
24
|
+
return value.replace(env__old_pwd(), '')
|
25
|
+
return value
|
24
26
|
|
25
27
|
def env__terminal__is__xterm():
|
26
28
|
return os.getenv('TERM') == 'xterm'
|
@@ -91,6 +93,9 @@ def find_dotenv_file(start_path=None, env_file_to_find='.env'):
|
|
91
93
|
def in_github_action():
|
92
94
|
return os.getenv('GITHUB_ACTIONS') == 'true'
|
93
95
|
|
96
|
+
def in_pytest_with_coverage():
|
97
|
+
return os.getenv('COVERAGE_RUN') == 'true'
|
98
|
+
|
94
99
|
def in_python_debugger():
|
95
100
|
if sys.gettrace() is not None: # Check for a trace function
|
96
101
|
return True
|
osbot_utils/version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
v1.
|
1
|
+
v1.37.0
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: osbot_utils
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.37.0
|
4
4
|
Summary: OWASP Security Bot - Utils
|
5
5
|
Home-page: https://github.com/owasp-sbot/OSBot-Utils
|
6
6
|
License: MIT
|
@@ -22,7 +22,7 @@ Description-Content-Type: text/markdown
|
|
22
22
|
|
23
23
|
Powerful Python util methods and classes that simplify common apis and tasks.
|
24
24
|
|
25
|
-

|
26
26
|
[](https://codecov.io/gh/owasp-sbot/OSBot-Utils)
|
27
27
|
|
28
28
|
|
@@ -6,7 +6,7 @@ osbot_utils/base_classes/Type_Safe.py,sha256=62eV2AnIAN-7VshhOpvWw0v_DZHJucLq10V
|
|
6
6
|
osbot_utils/base_classes/Type_Safe__List.py,sha256=-80C9OhsK6iDR2dAG8yNLAZV0qg5x3faqvSUigFCMJw,517
|
7
7
|
osbot_utils/base_classes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
8
|
osbot_utils/context_managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
-
osbot_utils/context_managers/capture_duration.py,sha256=
|
9
|
+
osbot_utils/context_managers/capture_duration.py,sha256=sdWij3UJzDf1gDCogCO9RDg6Vijh1bZeeLSi3QmZeYs,1345
|
10
10
|
osbot_utils/context_managers/disable_root_loggers.py,sha256=XDMbKATcRbmUQSMKaOhk68DANVdhbBvDxj15iXjIkw0,1056
|
11
11
|
osbot_utils/decorators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
12
|
osbot_utils/decorators/classes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -229,10 +229,10 @@ osbot_utils/helpers/ssh/SSH__Linux__Amazon.py,sha256=ZJFb7LFTvclAuhH5OoOtJ361NoX
|
|
229
229
|
osbot_utils/helpers/ssh/SSH__Python.py,sha256=O2DAwkbXzwkis8lffoqIL2NPSfYcN44Mr8i9Ey2iMKk,2066
|
230
230
|
osbot_utils/helpers/ssh/TestCase__SSH.py,sha256=MD8sq0_kI4f6pEmEO0cLq2mQOhIqbP45ZxFJNG44Jg4,1773
|
231
231
|
osbot_utils/helpers/ssh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
232
|
-
osbot_utils/helpers/trace/Trace_Call.py,sha256=
|
233
|
-
osbot_utils/helpers/trace/Trace_Call__Config.py,sha256=
|
232
|
+
osbot_utils/helpers/trace/Trace_Call.py,sha256=SNaYju1KA6UKaCZcaDoPadvSahdl0vOX27unGl0-ZEM,8825
|
233
|
+
osbot_utils/helpers/trace/Trace_Call__Config.py,sha256=bZyOIWs_4ufNVbpfiT8h_284JFHiFeBAJO15Q5ONaTg,3288
|
234
234
|
osbot_utils/helpers/trace/Trace_Call__Graph.py,sha256=HCrXRKQI42DIQxxyFLcaosWiOcUyoITbeV17ICdXcXM,1156
|
235
|
-
osbot_utils/helpers/trace/Trace_Call__Handler.py,sha256=
|
235
|
+
osbot_utils/helpers/trace/Trace_Call__Handler.py,sha256=hdgiawoC4K2DrMAHbz2706SfEcxPdX9kK0gjyWqjSzQ,12400
|
236
236
|
osbot_utils/helpers/trace/Trace_Call__Print_Lines.py,sha256=cy7zLv0_JNxdOIQPfZk6J9bv6AkIW6O643w0ykClXbw,4820
|
237
237
|
osbot_utils/helpers/trace/Trace_Call__Print_Traces.py,sha256=2LGeWMGP1uhSojGMmJmL3bH2B5LFIlfYEqEPNqoyKJw,8628
|
238
238
|
osbot_utils/helpers/trace/Trace_Call__Stack.py,sha256=pIvZ2yP4tymOQraUR2N5R-qlmg5QijyLxt85zmMajUs,7462
|
@@ -250,8 +250,8 @@ osbot_utils/testing/Logging.py,sha256=rzO1cCwty1oTucbV1q6U2QBIF87oOcvZoAY_R8SQB8
|
|
250
250
|
osbot_utils/testing/Patch_Print.py,sha256=RfY4HGIM06dF6JTKibnN1Uco8YL05xPWe1jS4MUiWV0,1566
|
251
251
|
osbot_utils/testing/Profiler.py,sha256=4em6Lpp0ONRDoDDCZsc_CdAOi_QolKOp4eA7KHN96e4,3365
|
252
252
|
osbot_utils/testing/Pytest.py,sha256=R3qdsIXGcNQcu7iobz0RB8AhbbHhc6t757tZoSZRrxA,730
|
253
|
-
osbot_utils/testing/Stderr.py,sha256=
|
254
|
-
osbot_utils/testing/Stdout.py,sha256=
|
253
|
+
osbot_utils/testing/Stderr.py,sha256=ynf0Wle9NvgneLChzAxFBQ0QlE5sbri_fzJ8bEJMNkc,718
|
254
|
+
osbot_utils/testing/Stdout.py,sha256=Gmxd_dOplXlucdSbOhYhka9sWP-Hmqb7ZuLs_JjtW7Y,592
|
255
255
|
osbot_utils/testing/Temp_Env_Vars.py,sha256=oFuaegBlaV0aySkPe1Nzf-mdIKN03oTUKNfKijGz__M,751
|
256
256
|
osbot_utils/testing/Temp_File.py,sha256=yZBL9MmcNU4PCQ4xlF4rSss4GylKoX3T_AJF-BlQhdI,1693
|
257
257
|
osbot_utils/testing/Temp_Folder.py,sha256=Dbcohr2ciex6w-kB79R41Nuoa0pgpDbKtPGnlMmJ73k,5194
|
@@ -266,7 +266,7 @@ osbot_utils/utils/Assert.py,sha256=u9XLgYn91QvNWZGyPi29SjPJSXRHlm9andIn3NJEVog,1
|
|
266
266
|
osbot_utils/utils/Call_Stack.py,sha256=MAq_0vMxnbeLfCe9qQz7GwJYaOuXpt3qtQwN6wiXsU0,6595
|
267
267
|
osbot_utils/utils/Csv.py,sha256=oHLVpjRJqrLMz9lubMCNEoThXWju5rNTprcwHc1zq2c,1012
|
268
268
|
osbot_utils/utils/Dev.py,sha256=HibpQutYy_iG8gGV8g1GztxNN4l29E4Bi7UZaVL6-L8,1203
|
269
|
-
osbot_utils/utils/Env.py,sha256=
|
269
|
+
osbot_utils/utils/Env.py,sha256=9r1xxCDszX1UUOu0dy3Kf_djaU3I39xgB_QdC80Szdo,5669
|
270
270
|
osbot_utils/utils/Exceptions.py,sha256=KyOUHkXQ_6jDTq04Xm261dbEZuRidtsM4dgzNwSG8-8,389
|
271
271
|
osbot_utils/utils/Files.py,sha256=7W0FmxPvxOapUchEVOKDgUx4JBRs9TCesu60uKkvrto,21765
|
272
272
|
osbot_utils/utils/Functions.py,sha256=0E6alPJ0fJpBiJgFOWooCOi265wSRyxxXAJ5CELBnso,3498
|
@@ -287,8 +287,8 @@ osbot_utils/utils/Toml.py,sha256=dqiegndCJF7V1YT1Tc-b0-Bl6QWyL5q30urmQwMXfMQ,140
|
|
287
287
|
osbot_utils/utils/Version.py,sha256=Ww6ChwTxqp1QAcxOnztkTicShlcx6fbNsWX5xausHrg,422
|
288
288
|
osbot_utils/utils/Zip.py,sha256=riPLKkZJxQjVu8lCm19cOTx5uiLPm1HreB9_BzNXi30,12209
|
289
289
|
osbot_utils/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
290
|
-
osbot_utils/version,sha256=
|
291
|
-
osbot_utils-1.
|
292
|
-
osbot_utils-1.
|
293
|
-
osbot_utils-1.
|
294
|
-
osbot_utils-1.
|
290
|
+
osbot_utils/version,sha256=2lsyLVdcS9K9UON7nV7FJNEMLVIqIhp0nDRL0qX80gE,8
|
291
|
+
osbot_utils-1.37.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
292
|
+
osbot_utils-1.37.0.dist-info/METADATA,sha256=9xLglgYIN1kPnaGfr0hMSIVtvm7e_F9h9xEC-cttwAQ,1266
|
293
|
+
osbot_utils-1.37.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
294
|
+
osbot_utils-1.37.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|