barsukov 0.0.5__py3-none-any.whl → 1.0.9__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.
- barsukov/__init__.py +18 -14
- barsukov/data/__init__.py +1 -0
- barsukov/data/fft.py +87 -87
- barsukov/exp/exp_utils.py +136 -119
- barsukov/exp/mwHP.py +263 -357
- barsukov/logger.py +160 -122
- barsukov/obj2file.py +93 -107
- barsukov/script.py +153 -82
- barsukov/time.py +37 -16
- {barsukov-0.0.5.dist-info → barsukov-1.0.9.dist-info}/METADATA +47 -48
- barsukov-1.0.9.dist-info/RECORD +14 -0
- barsukov-0.0.5.dist-info/RECORD +0 -14
- {barsukov-0.0.5.dist-info → barsukov-1.0.9.dist-info}/WHEEL +0 -0
- {barsukov-0.0.5.dist-info → barsukov-1.0.9.dist-info}/top_level.txt +0 -0
barsukov/logger.py
CHANGED
|
@@ -1,123 +1,161 @@
|
|
|
1
|
-
### BEGIN Dependencies ###
|
|
2
|
-
import os
|
|
3
|
-
from barsukov.time import time_stamp
|
|
4
|
-
### END Dependencies ###
|
|
5
|
-
|
|
6
|
-
class Logger:
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
):
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
else:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
self.file.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
self.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
self.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
1
|
+
### BEGIN Dependencies ###
|
|
2
|
+
import os
|
|
3
|
+
from barsukov.time import time_stamp
|
|
4
|
+
### END Dependencies ###
|
|
5
|
+
|
|
6
|
+
class Logger:
|
|
7
|
+
"""
|
|
8
|
+
Logger class that handles logging to both screen and file with flexible configuration
|
|
9
|
+
|
|
10
|
+
The logger is started upon initialization.
|
|
11
|
+
It can be started with the 'start()' method and can be closed using the 'close()' method
|
|
12
|
+
It is designed to avoid creating multiple Logger instances. Restarting the logger logs to the same file unless the 'full_file_path' is manually changed
|
|
13
|
+
|
|
14
|
+
Avaliable log options:
|
|
15
|
+
- 'screen': Logs only to the screen.
|
|
16
|
+
- 'file': Logs only to a file.
|
|
17
|
+
- 'both': Logs to both the screen and file.
|
|
18
|
+
- 'no': Disables logging.
|
|
19
|
+
|
|
20
|
+
log level 'important' is used for important logs, typically for internal use with higher priority
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
full_file_path (str): path to the log file (e.g., 'D:/Rundong/Projects/AFM sims/2024-07-06 Autooscillations/text.txt')
|
|
24
|
+
description (str): Description of the log's purpose.
|
|
25
|
+
log_mode (str): Defines the logging mode ('screen', 'file', 'both, or 'no').
|
|
26
|
+
file (file object): Log file object.
|
|
27
|
+
file_error (bool): Flag indicating an error with the file
|
|
28
|
+
"""
|
|
29
|
+
### Don't create multiple Logger objects.
|
|
30
|
+
### Logger can be opened and closed with start() and close() methods.
|
|
31
|
+
### Restarting the logger will log to the same file, unless self.full_file_path has been changed by hand.
|
|
32
|
+
### start=True will start the logger automatically, but be careful
|
|
33
|
+
### about the full_folder_path=os.getcwd() in init.
|
|
34
|
+
### Log options are 'screen', 'file', 'both', 'no'. The logger default is 'both'.
|
|
35
|
+
### The log='important' is for the Logger.log() method only. Try not to use it.
|
|
36
|
+
### Default hyerarchy is logger-default overriden by object-default overriden by instance.
|
|
37
|
+
### Instances, that log errors, will usually use 'both'.
|
|
38
|
+
|
|
39
|
+
### BEGIN: Initializing Tools
|
|
40
|
+
def __init__(self,
|
|
41
|
+
description=None, # Will be passed by Script. If not, write a brief description!
|
|
42
|
+
full_folder_path=os.getcwd(), # Will be passed by Script. If not, specify!
|
|
43
|
+
full_file_path=None, # Specify only if you want to log into an already existing file.
|
|
44
|
+
log='both', # Logger default will be passed by Script. If not, you may choose to change.
|
|
45
|
+
start_file=True,
|
|
46
|
+
):
|
|
47
|
+
|
|
48
|
+
### Initializing all variables before setting/getting them
|
|
49
|
+
self.full_file_path = full_file_path # If changed by hand later, needs start() to take effect
|
|
50
|
+
self.description = description # If changed by hand later, needs set_full_file_path and start() to take effect
|
|
51
|
+
self.log_mode = log # Default log mode can be changed by hand any time, no restart needed.
|
|
52
|
+
|
|
53
|
+
if self.full_file_path is not None: self.full_folder_path = None
|
|
54
|
+
else:
|
|
55
|
+
self.full_folder_path = full_folder_path # If changed by hand later, needs set_full_file_path and start() to take effect
|
|
56
|
+
self.set_full_file_path(description=description, full_folder_path=full_folder_path)
|
|
57
|
+
|
|
58
|
+
if start_file: self.start_file()
|
|
59
|
+
else: self.file = None
|
|
60
|
+
|
|
61
|
+
self.file_error = False
|
|
62
|
+
# If a problem with file, will be set to True. Just in case for later.
|
|
63
|
+
# If problem is remedied, you need to set file_error to False by hand.
|
|
64
|
+
|
|
65
|
+
self.log(f'Logger initialization complete.', log='important')
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def set_full_file_path(self, description=None, full_folder_path=None):
|
|
69
|
+
### Checking if optional arguments are filled or if defaults are provided ###
|
|
70
|
+
if description is None:
|
|
71
|
+
description = self.description
|
|
72
|
+
if full_folder_path is None:
|
|
73
|
+
full_folder_path = self.full_folder_path
|
|
74
|
+
|
|
75
|
+
### Create a file name like log_timeStamp_description_.txt ###
|
|
76
|
+
if not (description is None or description == ''):
|
|
77
|
+
description = f"_{description}"
|
|
78
|
+
else:
|
|
79
|
+
description = ''
|
|
80
|
+
file_name = f"log_{time_stamp()}{description}_.txt"
|
|
81
|
+
self.full_file_path = os.path.join(full_folder_path, file_name)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def start_file(self):
|
|
85
|
+
try:
|
|
86
|
+
self.file = open(self.full_file_path, 'a')
|
|
87
|
+
self.log('Logging file started.', log='important')
|
|
88
|
+
except:
|
|
89
|
+
print(f'{time_stamp()} Logger failed to open the log file \"{self.full_file_path}\".', log='important')
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def close_file(self): # If closed, you'll need to restart before logging.
|
|
93
|
+
self.log('Logger is closing log file.', log='important')
|
|
94
|
+
self.file.close()
|
|
95
|
+
self.file = None
|
|
96
|
+
### END: Initializing Tools
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
### BEGIN: logging Tools
|
|
100
|
+
def decorated_msg(self, msg):
|
|
101
|
+
decorated_msg = time_stamp() + ' ' + msg + '\n'
|
|
102
|
+
return decorated_msg
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def write_to_file(self, msg):
|
|
106
|
+
if self.file:
|
|
107
|
+
self.file.write(msg)
|
|
108
|
+
### flushing the log file to make sure it's written ###
|
|
109
|
+
self.file.flush()
|
|
110
|
+
os.fsync(self.file)
|
|
111
|
+
else:
|
|
112
|
+
self.file_error = True
|
|
113
|
+
print(f'{time_stamp()} Logger is trying to write to a closed or non-existent file.')
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def log(self, msg, log='default'):
|
|
117
|
+
### This is the main function. Log options: 'screen', 'file', 'both', 'no', 'default', 'important'
|
|
118
|
+
if log == 'important' and self.log_mode == 'no':
|
|
119
|
+
log = 'screen'
|
|
120
|
+
elif log == 'important' and self.log_mode == 'file':
|
|
121
|
+
log = 'both'
|
|
122
|
+
elif (log == 'important') or(log == 'default') or (log is None):
|
|
123
|
+
log = self.log_mode
|
|
124
|
+
|
|
125
|
+
decorated_message = self.decorated_msg(msg)
|
|
126
|
+
|
|
127
|
+
if log == 'both':
|
|
128
|
+
print(self.decorated_msg(msg))
|
|
129
|
+
self.write_to_file(decorated_message)
|
|
130
|
+
elif log == 'file':
|
|
131
|
+
self.write_to_file(decorated_message)
|
|
132
|
+
elif log == 'no':
|
|
133
|
+
pass
|
|
134
|
+
else: # log == 'screen' or anything else
|
|
135
|
+
print(decorated_message)
|
|
136
|
+
### END: logging Tools
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
### BEGIN: OBJ2FILE TOOLS:
|
|
140
|
+
def __getargs__(self):
|
|
141
|
+
logger_args = self.__getstate__()
|
|
142
|
+
del logger_args['log_mode']
|
|
143
|
+
del logger_args['file_error']
|
|
144
|
+
del logger_args['file']
|
|
145
|
+
return logger_args
|
|
146
|
+
|
|
147
|
+
def __getstate__(self):
|
|
148
|
+
seriable_data = self.__dict__.copy()
|
|
149
|
+
return seriable_data
|
|
150
|
+
### BEGIN: OBJ2FILE TOOLS:
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
### Use this function in other libraries if needed for debugging -- Not really needed
|
|
154
|
+
DEBUG = False
|
|
155
|
+
def debug(msg):
|
|
156
|
+
if DEBUG:
|
|
157
|
+
print(msg)
|
|
158
|
+
return msg+'\n'
|
|
159
|
+
else:
|
|
160
|
+
return msg
|
|
123
161
|
###
|
barsukov/obj2file.py
CHANGED
|
@@ -1,107 +1,93 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if obj_name is None: obj_name = obj_name(obj)
|
|
95
|
-
|
|
96
|
-
if overwrite:
|
|
97
|
-
tosave.update({obj_name : obj})
|
|
98
|
-
else:
|
|
99
|
-
add = tosave.setdefault(obj_name, obj) #for already excisting name returns corresponding element and doesn't overwrite
|
|
100
|
-
if add!=obj:
|
|
101
|
-
print(f'Overwriting attempt!')
|
|
102
|
-
|
|
103
|
-
self.tosave = tosave
|
|
104
|
-
if save:
|
|
105
|
-
self.save(tosave)
|
|
106
|
-
return tosave
|
|
107
|
-
|
|
1
|
+
### BEGIN Dependencies ###
|
|
2
|
+
import dill
|
|
3
|
+
import os
|
|
4
|
+
from barsukov.logger import debug
|
|
5
|
+
### END Dependencies ###
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def save_object(obj, file_name, update=False, full_folder_path=None, script=None):
|
|
9
|
+
"""
|
|
10
|
+
Saves a class object to a file using the '.pickle' format.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
obj (object): An instance of a class to be saved. (Required)
|
|
14
|
+
file_name (str): Name of the file (must end with '.pickle'). (required)
|
|
15
|
+
update (bool, optional): if 'True', overwrites an existing file. Defaults to 'False'.
|
|
16
|
+
full_folder_path (str, optional): absolute path to the directory (e.g., "C://Users//John//Documents").
|
|
17
|
+
Defaults to the current working directory if not provided.
|
|
18
|
+
script (Script, optional): Script object providing directory information.
|
|
19
|
+
Defaults to 'None'.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
str: Confirmation message upon successful save.
|
|
23
|
+
|
|
24
|
+
Raises:
|
|
25
|
+
FileExistsError: If the file already exists and 'update=False'.
|
|
26
|
+
|
|
27
|
+
Example:
|
|
28
|
+
>>> equipment = mwHP(...)
|
|
29
|
+
>>> save_object(obj=equipment, file_name="mwHP.pickle")
|
|
30
|
+
'equipment successfully saved in mwHP.pickle.'
|
|
31
|
+
"""
|
|
32
|
+
# Check if full_folder_path is provided and is an absolute path:
|
|
33
|
+
if full_folder_path and not os.path.isabs(full_folder_path):
|
|
34
|
+
return debug(f"Please provide an absolute path (e.g., 'C://Users//John//Documents').")
|
|
35
|
+
|
|
36
|
+
#Set folder_path based on the provided or default to current directory
|
|
37
|
+
full_folder_path = full_folder_path or (script.full_folder_path if script else os.getcwd())
|
|
38
|
+
full_file_path = os.path.join(full_folder_path, file_name)
|
|
39
|
+
|
|
40
|
+
if update:
|
|
41
|
+
# If update is True, overwrite the file
|
|
42
|
+
with open(full_file_path, 'wb') as file:
|
|
43
|
+
dill.dump(obj, file)
|
|
44
|
+
return debug(f"{obj} object successfully saved.")
|
|
45
|
+
else:
|
|
46
|
+
try:
|
|
47
|
+
# Try to create the file and save the object
|
|
48
|
+
with open(full_file_path, 'xb') as file:
|
|
49
|
+
dill.dump(obj, file)
|
|
50
|
+
return debug(f"{obj} successfully saved in {file_name}.")
|
|
51
|
+
except FileExistsError:
|
|
52
|
+
# If the file already exists, provide a message
|
|
53
|
+
raise FileExistsError(f"File '{file_name}' already exists. Use 'update=True' to overwrite.")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def load_object(file_name, full_folder_path=None, script=None):
|
|
57
|
+
"""
|
|
58
|
+
Loads a class object stored in a '.pickle' formatted file.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
file_name (str): Class object file (must end in '.pickle'). (Required)
|
|
62
|
+
full_folder_path (str, optional): absolute path to the directory where file exists (excluding the file name).
|
|
63
|
+
Defaults to the current working directory.
|
|
64
|
+
script (Script, optional): Script object providing directory information.
|
|
65
|
+
Defaults to 'None'.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
object: The loaded class object.
|
|
69
|
+
|
|
70
|
+
Raises:
|
|
71
|
+
FileNotFoundError: If the file doesn't exist in the specified location.
|
|
72
|
+
|
|
73
|
+
Example:
|
|
74
|
+
>>> new_equipment = load_object(file_name="mw.pickle")
|
|
75
|
+
'Object successfully loaded from mw.pickle.'
|
|
76
|
+
"""
|
|
77
|
+
# Check if the provided full_folder_path is absolute
|
|
78
|
+
if full_folder_path and not os.path.isabs(full_folder_path):
|
|
79
|
+
return debug(f"Please provide an absolute path (e.g., 'C://Users//John//Documents').")
|
|
80
|
+
|
|
81
|
+
# Set full_folder_path based on provided or default to current directory
|
|
82
|
+
full_folder_path = full_folder_path or (script.full_folder_path if script else os.getcwd())
|
|
83
|
+
full_file_path = os.path.join(full_folder_path, file_name)
|
|
84
|
+
|
|
85
|
+
# Check if the file exists at the specified path
|
|
86
|
+
if not os.path.isabs(full_file_path):
|
|
87
|
+
raise FileNotFoundError(f"The object file {file_name} does not exist at the specified directory.")
|
|
88
|
+
|
|
89
|
+
# load the object from the file
|
|
90
|
+
with open(full_file_path, 'rb') as file:
|
|
91
|
+
instance = dill.load(file)
|
|
92
|
+
print(debug(f'Object successfully loaded from {file_name}.'))
|
|
93
|
+
return instance
|