4
4
import hashlib
5
5
import json
6
6
from sorcery import dict_of
7
- import os , sys , traceback
7
+ import os , sys , traceback , psutil
8
+ import functools
9
+ import tqdm
10
+ import logging
11
+
12
+ def without (d , key ):
13
+ if key not in d :
14
+ return d
15
+ new_d = d .copy ()
16
+ new_d .pop (key )
17
+ return new_d
18
+
19
+ def is_interactive ():
20
+ import __main__ as main
21
+ return not hasattr (main , '__file__' )
8
22
9
23
def override (xp ):
10
24
import argparse , sys
11
25
parser = argparse .ArgumentParser ()
12
26
_ , unknown = parser .parse_known_args (sys .argv [1 :])
13
27
cmd_args_dict = dict (zip (unknown [:- 1 :2 ],unknown [1 ::2 ]))
14
28
cmd_args_dict = {k .lstrip ('-' ): v for (k ,v ) in cmd_args_dict .items ()}
15
- print (f"cmd_args: { cmd_args_dict } " )
16
29
for k ,v in cmd_args_dict .items ():
17
30
if k in xp :
18
31
xp [k ]= type (xp [k ])(v )
19
32
return xp
20
33
21
34
class edict (EasyDict ):
22
- def __hash__ (self ):
23
- json_dump = json .dumps (self , sort_keys = True , ensure_ascii = True )
24
- digest = hashlib .md5 (json_dump .encode ('utf-8' )).hexdigest ()
25
- identifier = int (digest , 16 )
26
- return identifier
27
35
36
+ def __hash__ (self ):
37
+ try :
38
+ json_dump = json .dumps (self , sort_keys = True , ensure_ascii = True )
39
+ digest = hashlib .md5 (json_dump .encode ('utf-8' )).hexdigest ()
40
+ identifier = int (digest , 16 )
41
+ return identifier
42
+ except :
43
+ return 0
28
44
class Xpl ():
29
45
def __init__ (self ,a ,b ):
30
46
self .a = a
@@ -74,7 +90,8 @@ def edict(self):
74
90
def __iter__ (self ):
75
91
keys = self .keys ()
76
92
values_list = self ._values ()
77
- for values in values_list :
93
+ history = []
94
+ for i , values in enumerate (values_list ):
78
95
79
96
args = edict ({})
80
97
for a , v in zip (keys , values ):
@@ -86,6 +103,9 @@ def __iter__(self):
86
103
xp = selfi .edict ()
87
104
xp = override (xp )
88
105
xp ._hash = hash (xp )
106
+ history += [xp ]
107
+ if i == len (values_list )- 1 :
108
+ xp ._history = history
89
109
yield xp
90
110
91
111
def first (self ):
@@ -99,6 +119,8 @@ def __len__(self):
99
119
return len ([x for x in self ])
100
120
101
121
122
+ # Context managers:
123
+
102
124
class NoPrint :
103
125
def __enter__ (self ):
104
126
self ._original_stdout = sys .stdout
@@ -108,11 +130,26 @@ def __exit__(self, exc_type, exc_val, exc_tb):
108
130
sys .stdout .close ()
109
131
sys .stdout = self ._original_stdout
110
132
133
+ class NoTqdm :
134
+ def __enter__ (self ):
135
+ tqdm .__init__ = functools .partialmethod (tqdm .__init__ , disable = True )
136
+ def __exit__ (self , exc_type , exc_value , exc_traceback ):
137
+ tqdm .__init__ = functools .partialmethod (tqdm .__init__ , disable = False )
138
+
139
+
140
+ class NoLogging :
141
+ def __enter__ (self ):
142
+ self ._old_logging_level = logging .root .manager .disable
143
+ logging .disable (logging .CRITICAL )
144
+
145
+ def __exit__ (self , exc_type , exc_value , traceback ):
146
+ logging .disable (self ._old_logging_level )
147
+
111
148
class Catch :
112
- def __init__ (self , exceptions = [], exit_fn = lambda :None ):
149
+ def __init__ (self , exceptions = [], exit_fn = lambda :None , info = '' ):
113
150
self .allowed_exceptions = exceptions
114
- self .encountered_expcetions = []
115
151
self .exit_fn = exit_fn
152
+ self .info = info
116
153
def __enter__ (self ):
117
154
return self
118
155
@@ -127,6 +164,55 @@ def __exit__(self, exception_type, exception_value, tb):
127
164
_EXCEPTIONS = []
128
165
129
166
if exception_type and (exception_type in self .allowed_exceptions or not self .allowed_exceptions ):
130
- print (f"{ exception_type .__name__ } swallowed!" ,exception_value ,traceback .print_tb (tb ))
131
- _EXCEPTIONS += [dict_of (exception_type ,exception_value ,tb )]
167
+ print (f"{ exception_type .__name__ } swallowed!" ,str ( self . info ), exception_value ,traceback .print_tb (tb ))
168
+ _EXCEPTIONS += [dict_of (exception_type ,exception_value ,tb , info = self . info )]
132
169
return True
170
+
171
+
172
+ class Notifier :
173
+ def __init__ (self , exit_fn = lambda x :None ):
174
+ self .exit_fn = exit_fn
175
+ def __enter__ (self ):
176
+ return self
177
+ def __exit__ (self , * args ):
178
+ self .exit_fn (str (args ))
179
+
180
+ class MeasureRAM :
181
+ def __init__ (self , id = None , logger = print ):
182
+ self .id = id
183
+ self .logger = logger
184
+ if self .logger == print :
185
+ self .logger = type ('logger' , (object ,), {'log' :print })()
186
+
187
+ def __enter__ (self ):
188
+ self .mem_before = psutil .Process (os .getpid ()).memory_info ().rss / (1024 * 1024 )
189
+
190
+ def __exit__ (self , exc_type , exc_val , exc_tb ):
191
+ mem_after = psutil .Process (os .getpid ()).memory_info ().rss / (1024 * 1024 )
192
+ variation_mb = (mem_after - self .mem_before )
193
+ if self .logger :
194
+ self .logger .log (dict_of (self .id ,variation_mb ))
195
+
196
+ class DisableOutput :
197
+ def __init__ (self ):
198
+ self .devnull = None
199
+
200
+ def __enter__ (self ):
201
+ # Disable all output streams
202
+ self .devnull = open (os .devnull , "w" )
203
+ self .old_stdout = sys .stdout
204
+ self .old_stderr = sys .stderr
205
+ sys .stdout = self .devnull
206
+ sys .stderr = self .devnull
207
+ logging .disable (logging .CRITICAL ) # Disable all logging output
208
+ return self
209
+
210
+ def __exit__ (self , * args ):
211
+ # Re-enable the output streams
212
+ sys .stdout = self .old_stdout
213
+ sys .stderr = self .old_stderr
214
+ self .devnull .close ()
215
+ logging .disable (logging .NOTSET ) # Re-enable logging output
216
+
217
+ def write (self , * args , ** kwargs ):
218
+ pass
0 commit comments