barsukov 1.0.8__py3-none-any.whl → 1.1.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.
Potentially problematic release.
This version of barsukov might be problematic. Click here for more details.
- barsukov/__init__.py +5 -2
- barsukov/exp/exp_utils.py +5 -5
- barsukov/exp/mwHP.py +147 -75
- barsukov/logger.py +64 -30
- barsukov/obj2file.py +91 -103
- barsukov/script.py +121 -64
- barsukov/time.py +23 -2
- {barsukov-1.0.8.dist-info → barsukov-1.1.0.dist-info}/METADATA +1 -1
- barsukov-1.1.0.dist-info/RECORD +14 -0
- barsukov-1.1.0.dist-info/top_level.txt +1 -0
- 2025-01-24_No Stn_Anon_No Sample_No Description/mw.dill +0 -1
- 2025-01-24_No Stn_Anon_No Sample_No Description/mw.pkl +0 -1
- barsukov/testpickle.py +0 -38
- barsukov-1.0.8.dist-info/RECORD +0 -17
- barsukov-1.0.8.dist-info/top_level.txt +0 -2
- {barsukov-1.0.8.dist-info → barsukov-1.1.0.dist-info}/WHEEL +0 -0
barsukov/__init__.py
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
# Modules:
|
|
2
2
|
from . import time
|
|
3
3
|
from . import data
|
|
4
|
+
|
|
4
5
|
|
|
5
6
|
# Objects/Functions:
|
|
6
7
|
from .script import Script
|
|
7
8
|
from .logger import Logger
|
|
8
|
-
|
|
9
|
+
|
|
10
|
+
from .obj2file import *
|
|
11
|
+
|
|
9
12
|
|
|
10
13
|
# Equipment Objects:
|
|
11
14
|
from .exp.mwHP import mwHP
|
|
12
15
|
|
|
13
|
-
__all__ = ["time", "
|
|
16
|
+
__all__ = ["time", "data", "save_object", "load_object", "Script", "Logger", "mwHP"]
|
|
14
17
|
|
|
15
18
|
|
barsukov/exp/exp_utils.py
CHANGED
|
@@ -5,10 +5,6 @@ from barsukov.time import *
|
|
|
5
5
|
### END Dependencies
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
8
|
### BEGIN Helper functions
|
|
13
9
|
|
|
14
10
|
def log_in_eq(eq_obj, msg, log='default'): # FINISHED 2024/10/26
|
|
@@ -19,6 +15,7 @@ def log_in_eq(eq_obj, msg, log='default'): # FINISHED 2024/10/26
|
|
|
19
15
|
else:
|
|
20
16
|
eq_obj.logger.log(decorated_msg, log)
|
|
21
17
|
|
|
18
|
+
|
|
22
19
|
def initialize_gpib(eq_obj):
|
|
23
20
|
# Initializes a visa.open_resource(). Returns rm.open_resource(). Exits if error.
|
|
24
21
|
if eq_obj.rm is None: # eq_obj has no ResourceManager
|
|
@@ -60,6 +57,7 @@ def initialize_gpib(eq_obj):
|
|
|
60
57
|
eq_obj.log(f'I could not initialize rm.open_resource() for GPIB {eq_obj.gpib_card}::{eq_obj.gpib}. Also check visa_rm, just in case.', log='important')
|
|
61
58
|
sys.exit()
|
|
62
59
|
|
|
60
|
+
|
|
63
61
|
def eq_disconnect(eq_obj):
|
|
64
62
|
try:
|
|
65
63
|
eq_obj.rm.close()
|
|
@@ -67,7 +65,8 @@ def eq_disconnect(eq_obj):
|
|
|
67
65
|
eq_obj.log( f'Successfully disconnected GPIB resource for {eq_obj.gpib_card}::{eq_obj.gpib}.', log='screen')
|
|
68
66
|
except:
|
|
69
67
|
eq_obj.log( f'Failed to disconnect GPIB resource for {eq_obj.gpib_card}::{eq_obj.gpib}.', log='screen')
|
|
70
|
-
|
|
68
|
+
|
|
69
|
+
|
|
71
70
|
def eq_reconnect(eq_obj):
|
|
72
71
|
try:
|
|
73
72
|
import pyvisa as visa
|
|
@@ -77,6 +76,7 @@ def eq_reconnect(eq_obj):
|
|
|
77
76
|
eq_obj.log( f'Initialized: {eq_obj.identify()}', log='important' )
|
|
78
77
|
except:
|
|
79
78
|
eq_obj.log(f'Failed to reconnect GPIB resource for {eq_obj.gpib_card}::{eq_obj.gpib}.', log='important')
|
|
79
|
+
|
|
80
80
|
### END Helper functions
|
|
81
81
|
|
|
82
82
|
|
barsukov/exp/mwHP.py
CHANGED
|
@@ -4,7 +4,6 @@ import sys
|
|
|
4
4
|
from barsukov.exp.exp_utils import *
|
|
5
5
|
### END Dependencies
|
|
6
6
|
|
|
7
|
-
# STATUS: f() finished, nor test it and then add more funcitons
|
|
8
7
|
|
|
9
8
|
class mwHP:
|
|
10
9
|
def __init__(self, gpib=None, visa_rm=None, logger=None, gpib_card=0, log='default', script=None):
|
|
@@ -23,28 +22,19 @@ class mwHP:
|
|
|
23
22
|
self.gpib = gpib
|
|
24
23
|
|
|
25
24
|
self.msg_deco = f'[mwHP {self.gpib_card}::{self.gpib}]'
|
|
26
|
-
#print( 'visa_rm is ', visa_rm )
|
|
27
|
-
#print( 'script is ', script )
|
|
28
25
|
self.eq = initialize_gpib(self) # This will initialize self.eq = visa.open_resource()
|
|
29
26
|
self.log( f'Initialized: {self.identify()}', log='important' ) # This is the 'welcome message' and a check if communication works.
|
|
30
27
|
|
|
31
28
|
self.f_digits = 9 # Digits of precision of mw frequency
|
|
32
29
|
self.f_limits = [0.01, 20.5] # Lower and upper GHz limits
|
|
33
|
-
self.p_digits = 1 #
|
|
34
|
-
self.p_limits = [-15.0, 17.0] #
|
|
35
|
-
self.
|
|
36
|
-
self.pulsew_digits = 3 # digits in ms
|
|
30
|
+
self.p_digits = 1 # Digits of precision of mw power
|
|
31
|
+
self.p_limits = [-15.0, 17.0] # Lower and upper dBm limits
|
|
32
|
+
self.phase_limits = [0.0, 360.0]
|
|
37
33
|
self.pulsef_limits = [0.016, 500]
|
|
38
|
-
self.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
eq_disconnect(self)
|
|
43
|
-
|
|
44
|
-
def reconnect(self):
|
|
45
|
-
eq_reconnect(self)
|
|
46
|
-
|
|
47
|
-
### BEGIN The definition of the following functions may be specific to this equipment.
|
|
34
|
+
self.pulsedc_limits = [0, 100] # Lower and upper % limits
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
### BEGIN The definition of the following functions may be specific to this equipment.
|
|
48
38
|
def query(self, cmd):
|
|
49
39
|
return self.eq.query(cmd)
|
|
50
40
|
|
|
@@ -53,12 +43,47 @@ class mwHP:
|
|
|
53
43
|
|
|
54
44
|
def identify(self):
|
|
55
45
|
return str(self.eq.query('*IDN?'))
|
|
56
|
-
|
|
46
|
+
### END The definition of the following functions may be specific to this equipment.
|
|
47
|
+
def disconnect(self):
|
|
48
|
+
eq_disconnect(self)
|
|
49
|
+
|
|
50
|
+
def reconnect(self):
|
|
51
|
+
eq_reconnect(self)
|
|
57
52
|
|
|
58
53
|
def log(self, msg, log=None):
|
|
59
54
|
if log is None: log=self.eq_default_log
|
|
60
55
|
log_in_eq(self, msg, log=log)
|
|
61
|
-
|
|
56
|
+
### END These functions could be shared across all equipment.
|
|
57
|
+
|
|
58
|
+
def output(self, state=None, log=None, check=False):
|
|
59
|
+
### Always has a return! Which is the state of Output.
|
|
60
|
+
### output() reads and returns the state of Output.
|
|
61
|
+
### output(1) writes state of Output to ON.
|
|
62
|
+
### output(1) returns the state that was actually sent to equipment.
|
|
63
|
+
### output(1, check=True) returns the state queried after writing
|
|
64
|
+
if log is None: log=self.eq_default_log
|
|
65
|
+
if state is None:
|
|
66
|
+
try:
|
|
67
|
+
y = self.eq.query('output?')
|
|
68
|
+
y = int(y)
|
|
69
|
+
self.log(f'Output is {y}.')
|
|
70
|
+
return y
|
|
71
|
+
except:
|
|
72
|
+
self.log(f'Error while reading Output.', log='important')
|
|
73
|
+
return np.nan
|
|
74
|
+
else:
|
|
75
|
+
if (state == 1) or (state == 'on') or (state=='ON') or (state=='On'): sstate = 1
|
|
76
|
+
else: sstate = 0
|
|
77
|
+
try:
|
|
78
|
+
self.eq.write(f'output {sstate}')
|
|
79
|
+
if check: y=self.output(log='no')
|
|
80
|
+
else: y = sstate
|
|
81
|
+
if y == state: self.log(f'Output set to {sstate}.')
|
|
82
|
+
else: self.log(f'Warning: Setting Output to {sstate}, but was asked for {state}.')
|
|
83
|
+
return y
|
|
84
|
+
except:
|
|
85
|
+
self.log(f'Error while changing Output state.', log='important')
|
|
86
|
+
return np.nan
|
|
62
87
|
|
|
63
88
|
|
|
64
89
|
def f(self, f=None, log=None, check=False):
|
|
@@ -85,7 +110,6 @@ class mwHP:
|
|
|
85
110
|
self.eq.write(f'freq {x} GHz')
|
|
86
111
|
if check: y = self.f(log='no')
|
|
87
112
|
else: y = x
|
|
88
|
-
print(y, f)
|
|
89
113
|
if abs(y-f)<10.0**(-self.f_digits): self.log(f'Writing f as {x}.', log=log)
|
|
90
114
|
else: self.log(f'Warning: writing Frequency as {x}, but was asked {f}.', log='important')
|
|
91
115
|
return y
|
|
@@ -93,6 +117,7 @@ class mwHP:
|
|
|
93
117
|
self.log(f'Error while writing Frequency as {f}.', log='important')
|
|
94
118
|
return np.nan
|
|
95
119
|
|
|
120
|
+
|
|
96
121
|
def p(self, p=None, log=None, check=False):
|
|
97
122
|
### Always has a return! Which is the power in dBm.
|
|
98
123
|
### p() reads and returns the power in dBm.
|
|
@@ -124,68 +149,115 @@ class mwHP:
|
|
|
124
149
|
self.log(f'Error while writing Power as {p}.', log='important')
|
|
125
150
|
return np.nan
|
|
126
151
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
### output() reads and returns the state of Output.
|
|
130
|
-
### output(1) writes state of Output to ON.
|
|
131
|
-
### output(1) returns the state that was actually sent to equipment.
|
|
132
|
-
### output(1, check=True) returns the state queried after writing
|
|
152
|
+
|
|
153
|
+
def sweep(self, start, stop, step, dwell, mode, log=None):
|
|
133
154
|
if log is None: log=self.eq_default_log
|
|
134
|
-
|
|
155
|
+
units, write_start, write_stop, mode = '', start, stop, mode.lower()
|
|
156
|
+
if (mode == 'freq') or (mode == 'frequency') or (mode == 'f'):
|
|
157
|
+
write_start = max(self.f_limits[0], min(write_start, self.f_limits[1]))
|
|
158
|
+
write_stop = max(self.f_limits[0], min(write_stop, self.f_limits[1]))
|
|
159
|
+
mode = 'Frequency'
|
|
160
|
+
units = 'GHz'
|
|
161
|
+
if (mode == 'pow') or (mode == 'power') or (mode == 'p'):
|
|
162
|
+
write_start = max(self.p_limits[0], min(write_start, self.p_limits[1]))
|
|
163
|
+
write_stop = max(self.p_limits[0], min(write_stop, self.p_limits[1]))
|
|
164
|
+
mode = 'Power'
|
|
165
|
+
units = 'dBm'
|
|
166
|
+
if (write_start != start):
|
|
167
|
+
self.log(f'Warning: Writing {mode} Sweep start to {write_start} but was asked {start}.', log='important')
|
|
168
|
+
if (write_stop != stop):
|
|
169
|
+
self.log(f'Warning: Writing {mode} Sweep stop to {write_stop} but was asked {stop}.', log='important')
|
|
170
|
+
try:
|
|
171
|
+
self.log(f'{mode} Sweep parameters are start: {write_start} {units}, stop: {write_stop} {units}, step: {step} {units}, dwell: {dwell} s.', log=log)
|
|
172
|
+
self.log(f'Initiating {mode} Sweep: ', log=log)
|
|
173
|
+
from time import sleep
|
|
174
|
+
for point in np.arange(write_start, write_stop+(step/2.0), step):
|
|
175
|
+
if mode == 'Frequency':
|
|
176
|
+
self.f(f=point)
|
|
177
|
+
elif mode == 'Power':
|
|
178
|
+
self.p(p=point)
|
|
179
|
+
sleep(dwell)
|
|
180
|
+
self.log(f'{mode} Sweep completed.', log=log)
|
|
181
|
+
except:
|
|
182
|
+
self.log(f'Error while conducting Sweep.', log='important')
|
|
183
|
+
return np.nan
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def pulse(self, f=None, duty=None, log=None):
|
|
187
|
+
if log is None: log=self.eq_default_log
|
|
188
|
+
if f is None and duty is None:
|
|
135
189
|
try:
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
self.
|
|
139
|
-
|
|
190
|
+
T = float(self.eq.query('puls:per?')) * 10.0**3
|
|
191
|
+
f = 1.0 / T
|
|
192
|
+
w = float(self.eq.query('puls:widt?')) * 10.0**3
|
|
193
|
+
duty = w / T * 100.0
|
|
194
|
+
y = self.eq.query('pulm:stat?')
|
|
195
|
+
y = int(y)
|
|
196
|
+
x = self.eq.query('pulm:sour?')
|
|
197
|
+
x = x[:-1].lower()
|
|
198
|
+
self.log(f'Pulse Frequency {f} KHz, duty-cycle {duty}%. state {y}, source {x}.', log=log)
|
|
199
|
+
return f, duty
|
|
140
200
|
except:
|
|
141
|
-
self.log(f'Error while reading
|
|
201
|
+
self.log(f'Error while reading Pulse state.', log='important')
|
|
142
202
|
return np.nan
|
|
143
203
|
else:
|
|
144
|
-
if
|
|
145
|
-
else: sstate = 0
|
|
204
|
+
if duty is None: duty = 50.0
|
|
146
205
|
try:
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
206
|
+
if f is None and duty != 50.0:
|
|
207
|
+
duty_write = max(self.pulsedc_limits[0], min(float(duty), self.pulsedc_limits[1]))
|
|
208
|
+
T = float(self.eq.query('puls:per?')) * 10.0**3
|
|
209
|
+
w = duty_write * T / 100.0
|
|
210
|
+
self.eq.write(f'puls:widt {w} ms')
|
|
211
|
+
elif f is not None and duty == 50.0:
|
|
212
|
+
f_write = max(self.pulsef_limits[0], min(float(f), self.pulsef_limits[1]))
|
|
213
|
+
duty_write = duty
|
|
214
|
+
T = 1.0 / f_write
|
|
215
|
+
w = duty_write * T / 100.0
|
|
216
|
+
self.eq.write(f'puls:per {T} ms')
|
|
217
|
+
self.eq.write(f'puls:widt {w} ms')
|
|
218
|
+
else:
|
|
219
|
+
f_write = max(self.pulsef_limits[0], min(float(f), self.pulsef_limits[1]))
|
|
220
|
+
duty_write = max(self.pulsedc_limits[0], min(float(duty), self.pulsedc_limits[1]))
|
|
221
|
+
T = 1.0 / f_write
|
|
222
|
+
w = duty_write * T / 100.0
|
|
223
|
+
self.eq.write(f'puls:per {T} ms')
|
|
224
|
+
self.eq.write(f'puls:widt {w} ms')
|
|
153
225
|
except:
|
|
154
|
-
self.log(f'Error while
|
|
226
|
+
self.log(f'Error while writing pulse frequency as {f} and duty cycle as {duty}', log='important')
|
|
155
227
|
return np.nan
|
|
228
|
+
freal, dutyreal = self.pulse()
|
|
229
|
+
if abs(freal - f) < 0.10*float(f): self.log(f'Writing Pulse Frequency as {freal}.', log=log)
|
|
230
|
+
else: self.log(f'Warning:Writing Pulse Frequency as {freal}, but was asked {f}.', log='important')
|
|
231
|
+
if abs(dutyreal - duty) < 0.03*float(duty): self.log(f'Writing Pulse duty cycle as {dutyreal}.', log=log)
|
|
232
|
+
else: self.log(f'Warning:Writing Pulse duty cycle as {dutyreal}, but was asked {duty}.', log='important')
|
|
233
|
+
return freal, dutyreal
|
|
156
234
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
self.log(f'Pulse Frequency {f} KHz, duty-cycle {duty}%. state {y}, source {x}.', log=log)
|
|
169
|
-
return f, duty
|
|
235
|
+
|
|
236
|
+
### BEGIN: OBJ2FILE Tools
|
|
237
|
+
# Prepares the Script object for serialization by removing non-seriable attributes (e.g. logger and rm).
|
|
238
|
+
# Returns:
|
|
239
|
+
# dict: A dictionary representing the serializable state of the Script object.
|
|
240
|
+
def __getstate__(self):
|
|
241
|
+
seriable_data = self.__dict__.copy()
|
|
242
|
+
# take the attributes of unseriable data
|
|
243
|
+
if self.script is None:
|
|
244
|
+
seriable_data['logger'] == 'needsrebuild'
|
|
245
|
+
seriable_data['logger_information'] = self.logger.__getargs__()
|
|
170
246
|
else:
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
self.eq.write(f'puls:per {T} ms')
|
|
189
|
-
self.eq.write(f'puls:widt {w} ms')
|
|
190
|
-
check = self.pulse()
|
|
191
|
-
return check
|
|
247
|
+
seriable_data['script'] == 'needsrebuild'
|
|
248
|
+
seriable_data['script_information'] = self.script.__getstate__()
|
|
249
|
+
seriable_data['rm'] = None
|
|
250
|
+
seriable_data['eq'] = None
|
|
251
|
+
return seriable_data
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def __setstate__(self, seriable_data):
|
|
255
|
+
from barsukov.script import Script
|
|
256
|
+
from barsukov.logger import Logger
|
|
257
|
+
self.__dict__.update(seriable_data)
|
|
258
|
+
if self.script == 'needsrebuild':
|
|
259
|
+
self.script = Script(**seriable_data['script_information'])
|
|
260
|
+
if self.logger == 'needsrebuild':
|
|
261
|
+
self.logger = Logger(**seriable_data['logger_information'])
|
|
262
|
+
eq_reconnect(self)
|
|
263
|
+
### END: OBJ2FILE Tools
|
barsukov/logger.py
CHANGED
|
@@ -5,6 +5,27 @@ from barsukov.time import time_stamp
|
|
|
5
5
|
|
|
6
6
|
class Logger:
|
|
7
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
|
+
"""
|
|
8
29
|
### Don't create multiple Logger objects.
|
|
9
30
|
### Logger can be opened and closed with start() and close() methods.
|
|
10
31
|
### Restarting the logger will log to the same file, unless self.full_file_path has been changed by hand.
|
|
@@ -14,59 +35,52 @@ class Logger:
|
|
|
14
35
|
### The log='important' is for the Logger.log() method only. Try not to use it.
|
|
15
36
|
### Default hyerarchy is logger-default overriden by object-default overriden by instance.
|
|
16
37
|
### Instances, that log errors, will usually use 'both'.
|
|
17
|
-
|
|
18
|
-
|
|
38
|
+
|
|
39
|
+
### BEGIN: Initializing Tools
|
|
19
40
|
def __init__(self,
|
|
20
41
|
description=None, # Will be passed by Script. If not, write a brief description!
|
|
21
42
|
full_folder_path=os.getcwd(), # Will be passed by Script. If not, specify!
|
|
22
43
|
full_file_path=None, # Specify only if you want to log into an already existing file.
|
|
23
44
|
log='both', # Logger default will be passed by Script. If not, you may choose to change.
|
|
24
|
-
start_file=True
|
|
45
|
+
start_file=True,
|
|
25
46
|
):
|
|
26
47
|
|
|
27
|
-
### Initializing all variables before setting/getting them
|
|
48
|
+
### Initializing all variables before setting/getting them
|
|
28
49
|
self.full_file_path = full_file_path # If changed by hand later, needs start() to take effect
|
|
29
50
|
self.description = description # If changed by hand later, needs set_full_file_path and start() to take effect
|
|
30
51
|
self.log_mode = log # Default log mode can be changed by hand any time, no restart needed.
|
|
31
52
|
|
|
32
|
-
if self.full_file_path is not None:
|
|
33
|
-
self.full_folder_path = None
|
|
53
|
+
if self.full_file_path is not None: self.full_folder_path = None
|
|
34
54
|
else:
|
|
35
55
|
self.full_folder_path = full_folder_path # If changed by hand later, needs set_full_file_path and start() to take effect
|
|
36
56
|
self.set_full_file_path(description=description, full_folder_path=full_folder_path)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
self.file = None
|
|
46
|
-
|
|
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
|
+
|
|
47
65
|
self.log(f'Logger initialization complete.', log='important')
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
seriable_data = self.__dict__.copy()
|
|
51
|
-
return seriable_data
|
|
52
|
-
|
|
66
|
+
|
|
67
|
+
|
|
53
68
|
def set_full_file_path(self, description=None, full_folder_path=None):
|
|
54
69
|
### Checking if optional arguments are filled or if defaults are provided ###
|
|
55
70
|
if description is None:
|
|
56
71
|
description = self.description
|
|
57
72
|
if full_folder_path is None:
|
|
58
73
|
full_folder_path = self.full_folder_path
|
|
59
|
-
|
|
74
|
+
|
|
60
75
|
### Create a file name like log_timeStamp_description_.txt ###
|
|
61
76
|
if not (description is None or description == ''):
|
|
62
|
-
description =
|
|
77
|
+
description = f"_{description}"
|
|
63
78
|
else:
|
|
64
79
|
description = ''
|
|
65
|
-
file_name =
|
|
66
|
-
#print(file_name)
|
|
67
|
-
#print(full_folder_path)
|
|
80
|
+
file_name = f"log_{time_stamp()}{description}_.txt"
|
|
68
81
|
self.full_file_path = os.path.join(full_folder_path, file_name)
|
|
69
82
|
|
|
83
|
+
|
|
70
84
|
def start_file(self):
|
|
71
85
|
try:
|
|
72
86
|
self.file = open(self.full_file_path, 'a')
|
|
@@ -74,15 +88,20 @@ class Logger:
|
|
|
74
88
|
except:
|
|
75
89
|
print(f'{time_stamp()} Logger failed to open the log file \"{self.full_file_path}\".', log='important')
|
|
76
90
|
|
|
91
|
+
|
|
77
92
|
def close_file(self): # If closed, you'll need to restart before logging.
|
|
78
93
|
self.log('Logger is closing log file.', log='important')
|
|
79
94
|
self.file.close()
|
|
80
95
|
self.file = None
|
|
96
|
+
### END: Initializing Tools
|
|
97
|
+
|
|
81
98
|
|
|
99
|
+
### BEGIN: logging Tools
|
|
82
100
|
def decorated_msg(self, msg):
|
|
83
101
|
decorated_msg = time_stamp() + ' ' + msg + '\n'
|
|
84
102
|
return decorated_msg
|
|
85
103
|
|
|
104
|
+
|
|
86
105
|
def write_to_file(self, msg):
|
|
87
106
|
if self.file:
|
|
88
107
|
self.file.write(msg)
|
|
@@ -93,6 +112,7 @@ class Logger:
|
|
|
93
112
|
self.file_error = True
|
|
94
113
|
print(f'{time_stamp()} Logger is trying to write to a closed or non-existent file.')
|
|
95
114
|
|
|
115
|
+
|
|
96
116
|
def log(self, msg, log='default'):
|
|
97
117
|
### This is the main function. Log options: 'screen', 'file', 'both', 'no', 'default', 'important'
|
|
98
118
|
if log == 'important' and self.log_mode == 'no':
|
|
@@ -103,7 +123,7 @@ class Logger:
|
|
|
103
123
|
log = self.log_mode
|
|
104
124
|
|
|
105
125
|
decorated_message = self.decorated_msg(msg)
|
|
106
|
-
|
|
126
|
+
|
|
107
127
|
if log == 'both':
|
|
108
128
|
print(self.decorated_msg(msg))
|
|
109
129
|
self.write_to_file(decorated_message)
|
|
@@ -113,9 +133,23 @@ class Logger:
|
|
|
113
133
|
pass
|
|
114
134
|
else: # log == 'screen' or anything else
|
|
115
135
|
print(decorated_message)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
+
|
|
119
153
|
### Use this function in other libraries if needed for debugging -- Not really needed
|
|
120
154
|
DEBUG = False
|
|
121
155
|
def debug(msg):
|
barsukov/obj2file.py
CHANGED
|
@@ -1,105 +1,93 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
#import pickle
|
|
1
|
+
### BEGIN Dependencies ###
|
|
2
|
+
import dill
|
|
5
3
|
import os
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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:
|
|
39
46
|
try:
|
|
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
|
-
return splines['H_to_V']
|
|
88
|
-
|
|
89
|
-
def pack_tosave(self, obj, obj_name=None, overwrite=False, save=False):
|
|
90
|
-
#prepares a dictionary {'obj name':obj, ...}
|
|
91
|
-
tosave = self.tosave
|
|
92
|
-
if obj_name is None: obj_name = obj_name(obj)
|
|
93
|
-
|
|
94
|
-
if overwrite:
|
|
95
|
-
tosave.update({obj_name : obj})
|
|
96
|
-
else:
|
|
97
|
-
add = tosave.setdefault(obj_name, obj) #for already excisting name returns corresponding element and doesn't overwrite
|
|
98
|
-
if add!=obj:
|
|
99
|
-
print(f'Overwriting attempt!')
|
|
100
|
-
|
|
101
|
-
self.tosave = tosave
|
|
102
|
-
if save:
|
|
103
|
-
self.save(tosave)
|
|
104
|
-
return tosave
|
|
105
|
-
|
|
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
|
barsukov/script.py
CHANGED
|
@@ -1,85 +1,110 @@
|
|
|
1
|
+
### BEGIN Dependencies ###
|
|
2
|
+
import sys
|
|
3
|
+
import os
|
|
1
4
|
from barsukov.time import *
|
|
2
5
|
from barsukov.logger import Logger
|
|
6
|
+
### END Dependencies
|
|
3
7
|
|
|
4
|
-
import sys
|
|
5
|
-
import os
|
|
6
8
|
|
|
7
9
|
class Script():
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
log
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
log_full_folder_path
|
|
27
|
-
log_full_file_path
|
|
28
|
-
|
|
10
|
+
"""
|
|
11
|
+
A class that represents a scientific experiment script, managing logging, file handing, and device initialization.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
RECOMMENDED:
|
|
15
|
+
operator (str): The name of the operator (default: 'Anon').
|
|
16
|
+
station (str): The station of the experiment (default: 'No-Station').
|
|
17
|
+
sample (str): The sample being tested (default: 'No-Sample').
|
|
18
|
+
description (str): A brief description of the experiment (default: 'No-Description').
|
|
19
|
+
project_folder (str): The base folder for the project files (default: current directory).
|
|
20
|
+
|
|
21
|
+
OPTIONAL:
|
|
22
|
+
log (str, optional): The logging configuration (default: 'both')
|
|
23
|
+
This is the default log setting which will be passed to the logger.
|
|
24
|
+
It will be overriden by other objects, which in turn will be overriden by methods.
|
|
25
|
+
Choose here and everywhere from 'screen', 'file', 'both', 'no'.
|
|
26
|
+
|
|
27
|
+
BEST NOT TO CHANGE:
|
|
28
|
+
log_full_folder_path (str, optional): Path to save logs (default: current directory).
|
|
29
|
+
log_full_file_path (str, optional): Full path for log file (default: None).
|
|
30
|
+
|
|
31
|
+
Attributes:
|
|
32
|
+
operator (str): The operator's name (e.g., 'ib', 'Rundong', 'Sasha', 'Ameerah', 'Steven', 'Alex', or 'AlexH' if ambiguous).
|
|
33
|
+
station (str): The station where the experiment is conducted (e.g., 'qd', 'ppms', 'mseppms', 'data', 'orange', ...).
|
|
34
|
+
sample (str): The sample being used in the experiment (e.g. 'cro2410a1').
|
|
35
|
+
description (str): A brief description of the experiment (e.g., 'Testing modulation').
|
|
36
|
+
project_folder (str): Absolute path to the directory (e.g., 'D:/Rundong/Projects/AFM sims/2024-07-06 Autooscillations').
|
|
37
|
+
folder_name (str): A generated folder name based on the experiment details.
|
|
38
|
+
full_folder_path (str): The full path to the experiment folder.
|
|
39
|
+
logger (Logger): A Logger instance for logging experiment data.
|
|
40
|
+
rm (ResourceManager or None): The pyvisa ResourceManager used for controlling instruments.
|
|
41
|
+
"""
|
|
42
|
+
### BEGIN: Initializing tools
|
|
43
|
+
def __init__(self,
|
|
44
|
+
operator='Anon',
|
|
45
|
+
station='No-Station',
|
|
46
|
+
sample='No-Sample',
|
|
47
|
+
description='No-Description',
|
|
48
|
+
project_folder = os.getcwd(),
|
|
49
|
+
log='both',
|
|
50
|
+
log_full_folder_path=os.getcwd(),
|
|
51
|
+
log_full_file_path=None,
|
|
29
52
|
):
|
|
30
|
-
|
|
53
|
+
|
|
54
|
+
### Description Attributes
|
|
31
55
|
self.operator = operator
|
|
32
56
|
self.station = station
|
|
33
57
|
self.sample = sample
|
|
34
58
|
self.description = description
|
|
35
59
|
self.project_folder = project_folder
|
|
36
60
|
|
|
37
|
-
self.rm = None
|
|
38
|
-
|
|
39
61
|
### Creating the sub-project folder
|
|
40
|
-
self.folder_name = date()
|
|
62
|
+
self.folder_name = f"{date()}_{self.station}_{self.operator}_{self.sample}_{self.description}"
|
|
41
63
|
self.full_folder_path = os.path.join(self.project_folder, self.folder_name)
|
|
42
64
|
os.makedirs(self.full_folder_path, exist_ok=True)
|
|
43
65
|
|
|
66
|
+
### Logger Attributes
|
|
67
|
+
self.start_logger = True
|
|
68
|
+
self.log_mode = log
|
|
69
|
+
self.log_full_folder_path = log_full_folder_path
|
|
70
|
+
self.log_full_file_path = log_full_file_path
|
|
71
|
+
self.init_logger(start=self.start_logger)
|
|
72
|
+
self.logger_name = self.logger.full_file_path
|
|
73
|
+
|
|
74
|
+
### Equipment Attributes
|
|
75
|
+
self.rm = None
|
|
76
|
+
self.equipment = None
|
|
77
|
+
|
|
78
|
+
def init_logger(self, start):
|
|
44
79
|
### Starting the logger
|
|
45
|
-
|
|
46
|
-
self.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
else:
|
|
52
|
-
self.logger = Logger(
|
|
53
|
-
description=self.operator + '_' + self.description,
|
|
54
|
-
full_folder_path=log_full_folder_path,
|
|
55
|
-
full_file_path=log_full_file_path,
|
|
56
|
-
log=log, # Script.log becomes Logger's default
|
|
57
|
-
start_file=True)
|
|
58
|
-
|
|
80
|
+
self.logger = Logger(
|
|
81
|
+
description=f"{self.operator}_{self.description}",
|
|
82
|
+
full_folder_path=self.log_full_folder_path,
|
|
83
|
+
full_file_path=self.log_full_file_path,
|
|
84
|
+
log=self.log_mode, # Script.log becomes Logger's default
|
|
85
|
+
start_file=start)
|
|
59
86
|
self.logger.log(f'Script object initialized. Logger started.', log='both')
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def __setstate__(self, seriable_data):
|
|
71
|
-
self.__dict__.update(seriable_data)
|
|
72
|
-
self.logger = Logger(**state['logger_information'])
|
|
73
|
-
|
|
74
|
-
def log(self, msg, log='default'): # default means the default of the logger
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def log(self, msg, log='default'):
|
|
90
|
+
"""
|
|
91
|
+
Logs a message using the Script object's logger.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
msg (str): The message to log.
|
|
95
|
+
log (str, optional): The log destination (e.g., 'screen', 'file', 'both'). Defaults to the 'default' of the logger
|
|
96
|
+
"""
|
|
75
97
|
self.logger.log(msg, log=log)
|
|
76
|
-
|
|
98
|
+
### END: Initializing tools
|
|
77
99
|
|
|
78
|
-
### BEGIN: Equipment related stuff
|
|
79
100
|
|
|
101
|
+
### BEGIN: Equipment related stuff
|
|
80
102
|
def init_rm(self):
|
|
81
|
-
|
|
82
|
-
|
|
103
|
+
# Initializes the pyvisa ResourceManager for controlling instruments.
|
|
104
|
+
# Returns ResourceManager The pyvisa ResourceManager object.
|
|
105
|
+
# Raises SystemExit If pyvisa cannot be imported or the ResourceManager cannot be initialized.
|
|
106
|
+
self.equipment = True
|
|
107
|
+
import pyvisa as visa
|
|
83
108
|
try:
|
|
84
109
|
self.rm = visa.ResourceManager()
|
|
85
110
|
except:
|
|
@@ -88,9 +113,41 @@ class Script():
|
|
|
88
113
|
sys.exit()
|
|
89
114
|
self.log(f'Script started pyvisa.ResourceManager.', log='both')
|
|
90
115
|
return self.rm
|
|
116
|
+
### END: Equipment related stuff
|
|
91
117
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def mwHP(self, **kwargs):
|
|
118
|
+
|
|
119
|
+
### BEGIN: Equipment devices
|
|
120
|
+
def mwHP(self, gpib=None, **kwargs):
|
|
121
|
+
"""
|
|
122
|
+
Initializes and returns a mwHP equipment object with the specified parameters.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
gpib (str): gpib number of equipment. Defaults to 'None'.
|
|
126
|
+
**kwargs: Additional keyword arguments passed to the mwHP equipment initialization.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
mwHP: A mwHP equipment object.
|
|
130
|
+
"""
|
|
95
131
|
from barsukov.exp.mwHP import mwHP as eq
|
|
96
|
-
return eq(
|
|
132
|
+
return eq(gpib, logger=self.logger, script=self, **kwargs)
|
|
133
|
+
### END: Equipment devices
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
### BEGIN: OBJ2FILE TOOLS:
|
|
137
|
+
def __getstate__(self):
|
|
138
|
+
# Prepares the Script object for serialization by removing non-seriable attributes (e.g. logger and rm).
|
|
139
|
+
# Returns a dict: A dictionary representing the serializable state of the Script object.
|
|
140
|
+
seriable_data = self.__dict__.copy()
|
|
141
|
+
seriable_data['start_log'] = False
|
|
142
|
+
del seriable_data['logger']
|
|
143
|
+
del seriable_data['rm']
|
|
144
|
+
return seriable_data
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def __setstate__(self, seriable_data):
|
|
148
|
+
# Restores the Script object from its serialized state, including reinitializing the logger and rm.
|
|
149
|
+
# Args: seriable_data (dict): A dictionary representing the serialized state of the Script object
|
|
150
|
+
self.__dict__.update(seriable_data)
|
|
151
|
+
self.init_logger(self.start_logger)
|
|
152
|
+
if self.equipment is True: self.init_rm()
|
|
153
|
+
### END: OBJ2FILE TOOLS:
|
barsukov/time.py
CHANGED
|
@@ -5,12 +5,33 @@ from pytz import timezone
|
|
|
5
5
|
|
|
6
6
|
TIMEZONE = timezone('America/Los_Angeles')
|
|
7
7
|
|
|
8
|
-
def time_stamp():
|
|
8
|
+
def time_stamp():
|
|
9
|
+
"""
|
|
10
|
+
Generates a timestamp in the format 'YYYY-MM-DD_HH-MM-SSS', where the last digit represents 1/10th of a second based on the current date and time.
|
|
11
|
+
|
|
12
|
+
returns:
|
|
13
|
+
str: A string representing the current date and time in the format 'YYYY-MM-DD_HH-MM-SSS'.
|
|
14
|
+
|
|
15
|
+
Example:
|
|
16
|
+
>>> time_stamp()
|
|
17
|
+
'2025-01-28_17-27-210'
|
|
18
|
+
"""
|
|
9
19
|
now = datetime.datetime.now(TIMEZONE)
|
|
10
20
|
formatted_datetime = now.strftime(f"%Y-%m-%d_%H-%M-%S") + str(int( now.microsecond / 100000 ))
|
|
11
21
|
return formatted_datetime
|
|
12
22
|
|
|
13
|
-
|
|
23
|
+
|
|
24
|
+
def date():
|
|
25
|
+
"""
|
|
26
|
+
Generates the current date in the format 'YYYY-MM-DD'.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
str: A string representing the current date in the format 'YYYY-MM-DD'.
|
|
30
|
+
|
|
31
|
+
Example:
|
|
32
|
+
>>> date()
|
|
33
|
+
'2025-01-28'
|
|
34
|
+
"""
|
|
14
35
|
now = datetime.datetime.now(TIMEZONE)
|
|
15
36
|
formatted_datetime = now.strftime(f"%Y-%m-%d")
|
|
16
37
|
return formatted_datetime
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
barsukov/__init__.py,sha256=GVsEnM_uD4x1XN_PIKdD-VSRMNUnvPr2iCWuEHwM6sU,293
|
|
2
|
+
barsukov/logger.py,sha256=nrkS1Pg3WGEjRJQ5MbplhyGYGbfFGkgyxgx1qdSu1x0,6489
|
|
3
|
+
barsukov/obj2file.py,sha256=nivCmCEpmOSaG4VpQgIDb-7hsvdEq45Iuu5HOfRxbcw,3923
|
|
4
|
+
barsukov/script.py,sha256=nrKwEl60u9ces3B8FwRfY4VmlEx5bNvk_hoPaylldP0,6359
|
|
5
|
+
barsukov/time.py,sha256=fSf5JKqr6Pd5691qQcFuBsjDd9alMrfASnndlstLits,1039
|
|
6
|
+
barsukov/data/__init__.py,sha256=IMnOEliXsRMPWeCTprPSddRKg9kwfV-neQiwUwHdpqs,19
|
|
7
|
+
barsukov/data/fft.py,sha256=f9aPLeusVpWiWmXO5n4XwkfQ9xJQhZVFdyhFoT9DB2A,4365
|
|
8
|
+
barsukov/exp/__init__.py,sha256=urLfGpap40kN9ULi53JB0NT-iMsZDSFdBmdSq3ckB0E,19
|
|
9
|
+
barsukov/exp/exp_utils.py,sha256=7qVQJbJGbsNW0JZQ7A1cmI73J6vi_aN8Zu6WMq2-7LE,4789
|
|
10
|
+
barsukov/exp/mwHP.py,sha256=eoX82jon5nIsExvRHO1PIOQAWWWhJYY4N21VtoLXuSw,12136
|
|
11
|
+
barsukov-1.1.0.dist-info/METADATA,sha256=29CE78LQEb-zolKUTIaGwUMwQu2M2HrV9xZxdHBcU-o,791
|
|
12
|
+
barsukov-1.1.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
13
|
+
barsukov-1.1.0.dist-info/top_level.txt,sha256=Js5sHbNjP0UNMB9O5HtCHZqlfHabuNS8nTsHbg-1DDQ,9
|
|
14
|
+
barsukov-1.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
barsukov
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
�
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
�
|
barsukov/testpickle.py
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import dill
|
|
2
|
-
import os
|
|
3
|
-
import barsukov
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def save_object(obj, file_name, update=False, full_folder_path=None, script=None):
|
|
7
|
-
if script is None:
|
|
8
|
-
if full_folder_path is None:
|
|
9
|
-
full_folder_path = os.getcwd()
|
|
10
|
-
else:
|
|
11
|
-
full_folder_path = script.full_folder_path
|
|
12
|
-
full_file_path = os.path.join(full_folder_path, file_name)
|
|
13
|
-
if update:
|
|
14
|
-
with open(full_file_path, 'wb') as file:
|
|
15
|
-
dill.dump(obj, file)
|
|
16
|
-
print("{obj} object successfully saved.")
|
|
17
|
-
else:
|
|
18
|
-
try:
|
|
19
|
-
with open(full_file_path, 'xb') as file:
|
|
20
|
-
dill.dump(obj, file)
|
|
21
|
-
print("{obj} object has been successfully saved.")
|
|
22
|
-
except FileExistsError:
|
|
23
|
-
print(f'Object file already exists. If update, use save_obj(obj={obj}, update=true).')
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def load_object(obj_file, full_folder_path=None, script=None):
|
|
27
|
-
### obj in format objectname.pkl
|
|
28
|
-
if script is None:
|
|
29
|
-
if full_folder_path is None:
|
|
30
|
-
full_folder_path = os.getcwd()
|
|
31
|
-
else:
|
|
32
|
-
full_folder_path = script.full_folder_path
|
|
33
|
-
full_file_path = os.path.join(full_folder_path, obj_file)
|
|
34
|
-
with open(full_file_path, 'rb') as file:
|
|
35
|
-
instance = dill.load(file)
|
|
36
|
-
print(f'{obj_file} object successfully loaded.')
|
|
37
|
-
return instance
|
|
38
|
-
|
barsukov-1.0.8.dist-info/RECORD
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
2025-01-24_No Stn_Anon_No Sample_No Description/mw.dill,sha256=BXy7-09ZNue15mhWvyXR-0agQTFDwOdSi6E30sLQJNE,2
|
|
2
|
-
2025-01-24_No Stn_Anon_No Sample_No Description/mw.pkl,sha256=BXy7-09ZNue15mhWvyXR-0agQTFDwOdSi6E30sLQJNE,2
|
|
3
|
-
barsukov/__init__.py,sha256=1i5yUENPC45RrQ2VXwSlzMRTWmjr_fmkJmmZonUjLIQ,269
|
|
4
|
-
barsukov/logger.py,sha256=i8S-EyO9vZmp-PgHnv4asTvJsS6KjFduO7t78K5CRQ4,5259
|
|
5
|
-
barsukov/obj2file.py,sha256=8BQOkCPnkq1doeIR7SjUeWRka6QwJ4W2pB8GQYhiSUA,3739
|
|
6
|
-
barsukov/script.py,sha256=W5Rx2VJrty0LFEtznX09ubY6Vwx9HDHFAj-rzsQmh38,3766
|
|
7
|
-
barsukov/testpickle.py,sha256=ay3ddGpbdQ2828VE1PdoMzArulPjXw5gtuPvzIjKobM,1320
|
|
8
|
-
barsukov/time.py,sha256=f88VRzAb84og7Bc4V67fg5ZmxnldTZ8vUnzwUVUnuA8,536
|
|
9
|
-
barsukov/data/__init__.py,sha256=IMnOEliXsRMPWeCTprPSddRKg9kwfV-neQiwUwHdpqs,19
|
|
10
|
-
barsukov/data/fft.py,sha256=f9aPLeusVpWiWmXO5n4XwkfQ9xJQhZVFdyhFoT9DB2A,4365
|
|
11
|
-
barsukov/exp/__init__.py,sha256=urLfGpap40kN9ULi53JB0NT-iMsZDSFdBmdSq3ckB0E,19
|
|
12
|
-
barsukov/exp/exp_utils.py,sha256=KwHBcDvV60zVB2GunpEfqbc6WwHOISWpsG24XBO3EkQ,4797
|
|
13
|
-
barsukov/exp/mwHP.py,sha256=ECzEXsTSe14-ZbvV1zmbbgV-11gOIjMUQfceDS2XfLU,8504
|
|
14
|
-
barsukov-1.0.8.dist-info/METADATA,sha256=RN-KBNilCAY9Xdf2GJkHN_lGYf-I6xImfZ6AU_Y7K0A,791
|
|
15
|
-
barsukov-1.0.8.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
16
|
-
barsukov-1.0.8.dist-info/top_level.txt,sha256=IJTKH4emvt-jqLNdlXcYs-YSbyt0P_wruWi-2Dosux8,57
|
|
17
|
-
barsukov-1.0.8.dist-info/RECORD,,
|
|
File without changes
|