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/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
- ### Don't create multiple Logger objects.
9
- ### Logger can be opened and closed with start() and close() methods.
10
- ### Restarting the logger will log to the same file, unless self.full_file_path has been changed by hand.
11
- ### start=True will start the logger automatically, but be careful
12
- ### about the full_folder_path=os.getcwd() in init.
13
- ### Log options are 'screen', 'file', 'both', 'no'. The logger default is 'both'.
14
- ### The log='important' is for the Logger.log() method only. Try not to use it.
15
- ### Default hyerarchy is logger-default overriden by object-default overriden by instance.
16
- ### Instances, that log errors, will usually use 'both'.
17
- ###
18
- """
19
- def __init__(self,
20
- description=None, # Will be passed by Script. If not, write a brief description!
21
- full_folder_path=os.getcwd(), # Will be passed by Script. If not, specify!
22
- full_file_path=None, # Specify only if you want to log into an already existing file.
23
- log='both', # Logger default will be passed by Script. If not, you may choose to change.
24
- start_file=True
25
- ):
26
-
27
- ### Initializing all variables before setting/getting them ###
28
- self.full_file_path = full_file_path # If changed by hand later, needs start() to take effect
29
- self.description = description # If changed by hand later, needs set_full_file_path and start() to take effect
30
- self.log_mode = log # Default log mode can be changed by hand any time, no restart needed.
31
-
32
- if self.full_file_path is not None:
33
- self.full_folder_path = None
34
- else:
35
- self.full_folder_path = full_folder_path # If changed by hand later, needs set_full_file_path and start() to take effect
36
- self.set_full_file_path(description=description, full_folder_path=full_folder_path)
37
-
38
- self.file_error = False # If a problem with file, will be set to True. Just in case for later.
39
- # If problem is remedied, you need to set file_error to False by hand.
40
-
41
- #
42
- if start_file:
43
- self.start_file()
44
- else:
45
- self.file = None
46
-
47
- self.log(f'Logger initialization complete.', log='important')
48
-
49
- def set_full_file_path(self, description=None, full_folder_path=None):
50
- ### Checking if optional arguments are filled or if defaults are provided ###
51
- if description is None:
52
- description = self.description
53
- if full_folder_path is None:
54
- full_folder_path = self.full_folder_path
55
- #
56
- ### Create a file name like log_timeStamp_description_.txt ###
57
- if not (description is None or description == ''):
58
- description = '_' + description
59
- else:
60
- description = ''
61
- file_name = 'log_' + time_stamp() + description + '_.txt'
62
- #print(file_name)
63
- #print(full_folder_path)
64
- self.full_file_path = os.path.join(full_folder_path, file_name)
65
-
66
- def start_file(self):
67
- try:
68
- self.file = open(self.full_file_path, 'a')
69
- self.log('Logging file started.', log='important')
70
- except:
71
- print(f'{time_stamp()} Logger failed to open the log file \"{self.full_file_path}\".', log='important')
72
-
73
- def close_file(self): # If closed, you'll need to restart before logging.
74
- self.log('Logger is closing log file.', log='important')
75
- self.file.close()
76
- self.file = None
77
-
78
- def decorated_msg(self, msg):
79
- decorated_msg = time_stamp() + ' ' + msg + '\n'
80
- return decorated_msg
81
-
82
- def write_to_file(self, msg):
83
- if self.file:
84
- self.file.write(msg)
85
- ### flushing the log file to make sure it's written ###
86
- self.file.flush()
87
- os.fsync(self.file)
88
- else:
89
- self.file_error = True
90
- print(f'{time_stamp()} Logger is trying to write to a closed or non-existent file.')
91
-
92
- def log(self, msg, log='default'):
93
- ### This is the main function. Log options: 'screen', 'file', 'both', 'no', 'default', 'important'
94
- if log == 'important' and self.log_mode == 'no':
95
- log = 'screen'
96
- elif log == 'important' and self.log_mode == 'file':
97
- log = 'both'
98
- elif (log == 'important') or(log == 'default') or (log is None):
99
- log = self.log_mode
100
-
101
- decorated_message = self.decorated_msg(msg)
102
-
103
- if log == 'both':
104
- print(self.decorated_msg(msg))
105
- self.write_to_file(decorated_message)
106
- elif log == 'file':
107
- self.write_to_file(decorated_message)
108
- elif log == 'no':
109
- pass
110
- else: # log == 'screen' or anything else
111
- print(decorated_message)
112
-
113
-
114
-
115
- ### Use this function in other libraries if needed for debugging -- Not really needed
116
- DEBUG = False
117
- def debug(msg):
118
- if DEBUG:
119
- print(msg)
120
- return msg+'\n'
121
- else:
122
- return msg
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
- # This is unfinished
2
-
3
-
4
- #import pickle
5
- import os
6
- #import glob
7
-
8
- import obj_name, time_stamp
9
-
10
- class Obj2File:
11
- def __init__(self, logger=None, log='default', script=None):
12
- self.script = script
13
- self.logger = logger
14
- self.default_log = log
15
- self.msg_deco = f'[Obj2File]'
16
-
17
- if self.logger is None:
18
- try: self.logger = self.script.logger
19
- except: pass
20
-
21
- self.mtj_calib_directory = '/Users/alexandrakorotneva/Desktop/2024-11-18 obj import test'
22
- self.tosave = {}
23
-
24
-
25
- def log(self, msg, log=None):
26
- if log is None: log = self.default_log
27
- if self.logger is not None:
28
- try:
29
- self.logger.log(f'{self.msg_deco} {msg}', log=log)
30
- return
31
- except: pass
32
- print(f'{time_stamp()} {self.msg_deco} {msg}')
33
-
34
- def save(self, obj, directory=None, full_file=None, short_file=None, log='default'):
35
- if full_file is None:
36
- if directory is None: directory = self.script.full_folder_path #current measurement folder
37
- if short_file is None: short_file = f'{time_stamp()}_{obj_name(obj)}.pkl'
38
- full_file = os.path.join(directory, short_file)
39
- try:
40
- with open(full_file, 'wb') as file:
41
- pickle.dump(obj, file)
42
- self.log(f'Object {obj_name(obj)} is written to file {full_file}.', log=log)
43
- except:
44
- self.log('Error: could not write object to file.', log='important')
45
-
46
- def load(self, directory=None, full_file=None, short_file=None, log='default'):
47
- if full_file is None:
48
- if directory is None:
49
- directory = self.script.full_folder_path
50
- if short_file is None:
51
- files = [f for f in glob.glob(os.path.join(directory, '*.pkl'))]
52
- short_file = files[0]
53
- full_file = os.path.join(directory, short_file)
54
-
55
- try:
56
- with open(filepath, 'rb') as file:
57
- toload = pickle.load(file)
58
- self.log(f'Object is uploaded from file {full_file}.', log=log)
59
- except:
60
- self.log('Error: could not upload object from file.', log='important')
61
- return toload
62
-
63
-
64
-
65
-
66
- def mtj_fieldcalib(self, directory=None, upd=False, log='default', spl_ind=None):
67
- if directory is None: directory = self.mtj_calib_directory
68
- else:
69
- if upd:
70
- self.mtj_calib_directory = directory
71
- self.log(f'MTJ station field calibration directory has been updated to {directory}', log='important')
72
-
73
- files = [f for f in glob.glob(os.path.join(directory, '*.pkl'))]
74
- if len(files)==1:
75
- short_file = files[0]
76
- else:
77
- ##
78
-
79
- full_file = os.path.join(directory, short_file)
80
- splines = self.load(full_file=full_file, log=log)
81
-
82
- if spl_ind is None:
83
- return: splines
84
- elif spl_ind=='c':
85
- return: splines['cheap_to_H']
86
- elif spl_ind=='v':
87
- return: Vsplines['V_to_H']
88
- elif spl_ind=='h':
89
- return: splines['H_to_V']
90
-
91
- def pack_tosave(self, obj, obj_name=None, overwrite=False, save=False):
92
- #prepares a dictionary {'obj name':obj, ...}
93
- tosave = self.tosave
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