dbdicom 0.3.7__py3-none-any.whl → 0.3.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.

Potentially problematic release.


This version of dbdicom might be problematic. Click here for more details.

@@ -0,0 +1,386 @@
1
+ import math
2
+ import datetime
3
+
4
+ import numpy as np
5
+ import pydicom
6
+
7
+
8
+
9
+ def get_values(ds, tags):
10
+ """Return a list of values for a dataset"""
11
+
12
+ # https://pydicom.github.io/pydicom/stable/guides/element_value_types.html
13
+ if np.isscalar(tags):
14
+ return get_values(ds, [tags])[0]
15
+
16
+ row = []
17
+ for tag in tags:
18
+ value = None
19
+
20
+ # If the tag is provided as string
21
+ if isinstance(tag, str):
22
+ if hasattr(ds, tag):
23
+ pydcm_value = ds[tag].value
24
+ try:
25
+ VR = pydicom.datadict.dictionary_VR(tag)
26
+ except:
27
+ VR = None
28
+ value = to_set_type(pydcm_value, VR) # ELIMINATE THIS STEP - return pydicom datatypes
29
+
30
+ # If the tag is a tuple of hexadecimal values
31
+ else:
32
+ if tag in ds:
33
+ try:
34
+ VR = pydicom.datadict.dictionary_VR(tag)
35
+ except:
36
+ VR = None
37
+ value = to_set_type(ds[tag].value, VR)
38
+
39
+ # If a tag is not present in the dataset, check if it can be derived
40
+ if value is None:
41
+ value = derive_data_element(ds, tag)
42
+
43
+ row.append(value)
44
+ return row
45
+
46
+
47
+ def set_values(ds, tags, values, VR=None, coords=None):
48
+
49
+ if np.isscalar(tags):
50
+ tags = [tags]
51
+ values = [values]
52
+ VR = [VR]
53
+ elif VR is None:
54
+ VR = [None] * len(tags)
55
+
56
+ if coords is not None: # obsolete
57
+ tags += list(coords.keys())
58
+ values += list(coords.values())
59
+
60
+ for i, tag in enumerate(tags):
61
+
62
+ if values[i] is None:
63
+ if isinstance(tag, str):
64
+ if hasattr(ds, tag):
65
+ del ds[tag]
66
+ else: # hexadecimal tuple
67
+ if tag in ds:
68
+ del ds[tag]
69
+
70
+ elif isinstance(tag, str):
71
+ if hasattr(ds, tag):
72
+ ds[tag].value = format_value(values[i], tag=tag)
73
+ else:
74
+ _add_new(ds, tag, values[i], VR=VR[i])
75
+
76
+ else: # hexadecimal tuple
77
+ if tag in ds:
78
+ ds[tag].value = format_value(values[i], tag=tag)
79
+ else:
80
+ _add_new(ds, tag, values[i], VR=VR[i])
81
+
82
+ #_set_derived_data_element(ds, tag, values[i])
83
+
84
+ return ds
85
+
86
+
87
+ def value(ds, tags):
88
+ # Same as get_values but without VR lookup
89
+
90
+ # https://pydicom.github.io/pydicom/stable/guides/element_value_types.html
91
+ if np.isscalar(tags):
92
+ return get_values(ds, [tags])[0]
93
+
94
+ row = []
95
+ for tag in tags:
96
+ value = None
97
+
98
+ # If the tag is provided as string
99
+ if isinstance(tag, str):
100
+
101
+ if hasattr(ds, tag):
102
+ value = to_set_type(ds[tag].value)
103
+
104
+ # If the tag is a tuple of hexadecimal values
105
+ else:
106
+ if tag in ds:
107
+ value = to_set_type(ds[tag].value)
108
+
109
+ # If a tag is not present in the dataset, check if it can be derived
110
+ if value is None:
111
+ value = derive_data_element(ds, tag)
112
+
113
+ row.append(value)
114
+ return row
115
+
116
+
117
+ def set_value(ds, tags, values):
118
+ # Same as set_values but without VR lookup
119
+ # This excludes new private tags - set those using add_private()
120
+ if np.isscalar(tags):
121
+ tags = [tags]
122
+ values = [values]
123
+
124
+ for i, tag in enumerate(tags):
125
+
126
+ if values[i] is None:
127
+ if isinstance(tag, str):
128
+ if hasattr(ds, tag):
129
+ del ds[tag]
130
+ else: # hexadecimal tuple
131
+ if tag in ds:
132
+ del ds[tag]
133
+
134
+ elif isinstance(tag, str):
135
+ if hasattr(ds, tag):
136
+ ds[tag].value = check_value(values[i], tag)
137
+ else:
138
+ add_new(ds, tag, values[i])
139
+
140
+ else: # hexadecimal tuple
141
+ if tag in ds:
142
+ ds[tag].value = check_value(values[i], tag)
143
+ else:
144
+ add_new(ds, tag, values[i])
145
+
146
+ return ds
147
+
148
+
149
+ def check_value(value, tag):
150
+
151
+ # If the change below is made (TM, DA, DT) then this needs to
152
+ # convert those to string before setting
153
+
154
+ LO = [
155
+ 'SeriesDescription',
156
+ 'StudyDescription',
157
+ ]
158
+ TM = [
159
+ 'AcquisitionTime',
160
+ ]
161
+
162
+ if tag in LO:
163
+ if len(value) > 64:
164
+ return value[-64:]
165
+ if tag in TM:
166
+ return seconds_to_str(value)
167
+
168
+ return value
169
+
170
+
171
+ def add_new(ds, tag, value):
172
+ if not isinstance(tag, pydicom.tag.BaseTag):
173
+ tag = pydicom.tag.Tag(tag)
174
+ if tag.is_private:
175
+ raise ValueError("if you want to add a private data element, use "
176
+ "dataset.add_private()")
177
+ # Add a new data element
178
+ value_repr = pydicom.datadict.dictionary_VR(tag)
179
+ if value_repr == 'US or SS':
180
+ if value >= 0:
181
+ value_repr = 'US'
182
+ else:
183
+ value_repr = 'SS'
184
+ elif value_repr == 'OB or OW':
185
+ value_repr = 'OW'
186
+ ds.add_new(tag, value_repr, format_value(value, value_repr))
187
+
188
+ def _add_new(ds, tag, value, VR='OW'):
189
+ if not isinstance(tag, pydicom.tag.BaseTag):
190
+ tag = pydicom.tag.Tag(tag)
191
+ if not tag.is_private: # Add a new data element
192
+ value_repr = pydicom.datadict.dictionary_VR(tag)
193
+ if value_repr == 'US or SS':
194
+ if value >= 0:
195
+ value_repr = 'US'
196
+ else:
197
+ value_repr = 'SS'
198
+ elif value_repr == 'OB or OW':
199
+ value_repr = 'OW'
200
+ ds.add_new(tag, value_repr, format_value(value, value_repr))
201
+ else:
202
+ if (tag.group, 0x0010) not in ds:
203
+ ds.private_block(tag.group, 'dbdicom ' + str(tag.group), create=True)
204
+ ds.add_new(tag, VR, format_value(value, VR))
205
+
206
+ def format_value(value, VR=None, tag=None):
207
+
208
+ # If the change below is made (TM, DA, DT) then this needs to
209
+ # convert those to string before setting
210
+
211
+ # Slow - dictionary lookup for every value write
212
+
213
+ if VR is None:
214
+ VR = pydicom.datadict.dictionary_VR(tag)
215
+
216
+ if VR == 'LO':
217
+ if len(value) > 64:
218
+ return value[-64:]
219
+ #return value[:64]
220
+ if VR == 'TM':
221
+ return seconds_to_str(value)
222
+ if VR == 'DA':
223
+ if not is_valid_dicom_date(value):
224
+ return '99991231'
225
+
226
+ return value
227
+
228
+
229
+ def is_valid_dicom_date(da_str: str) -> bool:
230
+ if not isinstance(da_str, str) or len(da_str) != 8 or not da_str.isdigit():
231
+ return False
232
+ try:
233
+ datetime.datetime.strptime(da_str, "%Y%m%d")
234
+ return True
235
+ except ValueError:
236
+ return False
237
+
238
+
239
+ def to_set_type(value, VR=None):
240
+ """
241
+ Convert pydicom datatypes to the python datatypes used to set the parameter.
242
+ """
243
+ # Not a good idea to modify pydicom set/get values. confusing and requires extra VR lookups
244
+
245
+ if VR == 'TM':
246
+ # pydicom sometimes returns string values for TM data types
247
+ if isinstance(value, str):
248
+ return str_to_seconds(value)
249
+
250
+ if value.__class__.__name__ == 'MultiValue':
251
+ return [to_set_type(v, VR) for v in value]
252
+ if value.__class__.__name__ == 'PersonName':
253
+ return str(value)
254
+ if value.__class__.__name__ == 'Sequence':
255
+ return [ds for ds in value]
256
+ if value.__class__.__name__ == 'TM':
257
+ return time_to_seconds(value) # return datetime.time
258
+ if value.__class__.__name__ == 'UID':
259
+ return str(value)
260
+ if value.__class__.__name__ == 'IS':
261
+ return int(value)
262
+ if value.__class__.__name__ == 'DT':
263
+ return datetime_to_str(value) # return datetime.datetime
264
+ if value.__class__.__name__ == 'DA': # return datetime.date
265
+ return date_to_str(value)
266
+ if value.__class__.__name__ == 'DSfloat':
267
+ return float(value)
268
+ if value.__class__.__name__ == 'DSdecimal':
269
+ return int(value)
270
+
271
+ return value
272
+
273
+
274
+ def derive_data_element(ds, tag):
275
+ """Tags that are not required but can be derived from other required tags"""
276
+
277
+ if tag == 'SliceLocation' or tag == (0x0020, 0x1041):
278
+ if 'ImageOrientationPatient' in ds and 'ImagePositionPatient' in ds:
279
+ image_orientation = ds['ImageOrientationPatient'].value
280
+ image_position = ds['ImagePositionPatient'].value
281
+ row_cosine = np.array(image_orientation[:3])
282
+ column_cosine = np.array(image_orientation[3:])
283
+ slice_cosine = np.cross(row_cosine, column_cosine)
284
+ return np.dot(np.array(image_position), slice_cosine)
285
+ # To be extended ad hoc with other tags that can be derived
286
+
287
+
288
+ def add_private(ds, tag, value, VR):
289
+ if not isinstance(tag, pydicom.tag.BaseTag):
290
+ tag = pydicom.tag.Tag(tag)
291
+ if (tag.group, 0x0010) not in ds:
292
+ ds.private_block(tag.group, 'dbdicom ' + str(tag.group), create=True)
293
+ ds.add_new(tag, VR, format_value(value, VR))
294
+
295
+
296
+ def str_to_seconds(dicom_tm):
297
+ if dicom_tm is None:
298
+ return None
299
+ if dicom_tm == '':
300
+ return None
301
+ # dicom_tm is of the form 'HHMMSS.FFFFFF'
302
+ # Split the seconds into seconds and fractional seconds
303
+ seconds, fractional_seconds = dicom_tm.split('.')
304
+ # Convert the hours, minutes, and seconds to integers
305
+ hours = int(seconds[:2])
306
+ minutes = int(seconds[2:4])
307
+ seconds = int(seconds[4:])
308
+ # Convert the fractional seconds to a decimal
309
+ fractional_seconds = float('.' + fractional_seconds)
310
+ # Create a datetime object representing the time
311
+ seconds_since_midnight = (hours * 3600) + (minutes * 60) + seconds + fractional_seconds
312
+ return seconds_since_midnight
313
+
314
+ def seconds_to_str(seconds_since_midnight):
315
+ # if not isinstance(seconds_since_midnight, float):
316
+ # return None
317
+ if seconds_since_midnight is None:
318
+ return None
319
+ seconds_since_midnight = float(seconds_since_midnight)
320
+ hours = math.floor(seconds_since_midnight/3600)
321
+ minutes = math.floor((seconds_since_midnight-hours*3600)/60)
322
+ seconds = math.floor(seconds_since_midnight-hours*3600-minutes*60)
323
+ fractional_seconds = round(seconds_since_midnight-hours*3600-minutes*60-seconds, 6)
324
+ hours = str(hours).zfill(2)
325
+ minutes = str(minutes).zfill(2)
326
+ seconds = str(seconds).zfill(2)
327
+ fractional_seconds = str(fractional_seconds)
328
+ fractional_seconds = fractional_seconds.split('.')
329
+ if len(fractional_seconds) == 2:
330
+ fractional_seconds = fractional_seconds[1].ljust(6,'0')
331
+ else:
332
+ fractional_seconds = '0'.ljust(6,'0')
333
+ return hours + minutes + seconds + '.' + fractional_seconds
334
+
335
+ def time_to_seconds(tm):
336
+ if tm is None:
337
+ return None
338
+ hours = tm.hour
339
+ minutes = tm.minute
340
+ seconds = tm.second
341
+ fractional_seconds = tm.microsecond / 1000000.0
342
+ seconds_since_midnight = (hours * 3600) + (minutes * 60) + seconds + fractional_seconds
343
+ return seconds_since_midnight
344
+
345
+ def seconds_to_time(seconds_since_midnight):
346
+ # if not isinstance(seconds_since_midnight, float):
347
+ # return None
348
+ if seconds_since_midnight is None:
349
+ return None
350
+ seconds_since_midnight = float(seconds_since_midnight)
351
+ hours = math.floor(seconds_since_midnight/3600)
352
+ minutes = math.floor((seconds_since_midnight-hours*3600)/60)
353
+ seconds = math.floor(seconds_since_midnight-hours*3600-minutes*60)
354
+ fractional_seconds = round(seconds_since_midnight-hours*3600-minutes*60-seconds, 6)
355
+ microseconds = fractional_seconds*1000000.0
356
+ return datetime.time(int(hours), int(minutes), int(seconds), int(microseconds))
357
+
358
+ def time_to_str(tm):
359
+ if tm is None:
360
+ return None
361
+ hours = tm.hour
362
+ minutes = tm.minute
363
+ seconds = tm.second
364
+ fractional_seconds = tm.microsecond / 1000000.0
365
+ hours = str(hours).zfill(2)
366
+ minutes = str(minutes).zfill(2)
367
+ seconds = str(seconds).zfill(2)
368
+ fractional_seconds = str(fractional_seconds)
369
+ _, fractional_seconds = fractional_seconds.split('.')
370
+ fractional_seconds = fractional_seconds.ljust(6,'0')
371
+ return hours + minutes + seconds + '.' + fractional_seconds
372
+
373
+ def date_to_str(tm):
374
+ if tm is None:
375
+ return None
376
+ year = str(tm.year).rjust(4, '0')
377
+ month = str(tm.month).rjust(2, '0')
378
+ day = str(tm.day).rjust(2, '0')
379
+ return year + month + day
380
+
381
+ def datetime_to_str(dt):
382
+ if dt is None:
383
+ return None
384
+ date = date_to_str(dt.date())
385
+ time = time_to_str(dt.time())
386
+ return date + time
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dbdicom
3
- Version: 0.3.7
3
+ Version: 0.3.9
4
4
  Summary: A pythonic interface for reading and writing DICOM databases
5
5
  Author-email: Steven Sourbron <s.sourbron@sheffield.ac.uk>, Ebony Gunwhy <e.gunwhy@sheffield.ac.uk>
6
6
  Project-URL: Homepage, https://openmiblab.github.io/dbdicom/
@@ -1,9 +1,9 @@
1
1
  dbdicom/__init__.py,sha256=dW5aezonmMc_41Dp1PuYmXQlr307RkyJxsJuetkpWso,87
2
- dbdicom/api.py,sha256=lUNLQo3aAAIFVF7IMccNhXAlbf1hMNTU9gHibdfbKcI,14135
2
+ dbdicom/api.py,sha256=oIvTktChBoEl4z0NXHMPVn2ZnPxUUXtZahwrIM7zfx0,14426
3
3
  dbdicom/const.py,sha256=BqBiRRjeiSqDr1W6YvaayD8WKCjG4Cny2NT0GeLM6bI,4269
4
- dbdicom/database.py,sha256=_LUbH7gc9l7j_63AC71DjwxgTUwbEjHSy5kuvRw75Hw,4764
5
- dbdicom/dataset.py,sha256=kbswoVE3-Wtu0uwcSW319KzpdWx5fZphfKxizxJePzc,22773
6
- dbdicom/dbd.py,sha256=yvj4PRj4gP1Qmh0VhibOrZ1oxy9v9qM9iOV0L6C_Ryw,38261
4
+ dbdicom/database.py,sha256=mkYQAAf9fETzUhSQflQFp7RQUBdPlSlDty9nn6KY1jQ,4771
5
+ dbdicom/dataset.py,sha256=2_MB7t9nMzTyq6sEhbu__MjU1VEnO0MdZuhzZK13a1I,14433
6
+ dbdicom/dbd.py,sha256=AP3BGcwWXnHwSov9kcm4CdWzgIDKod9WiGFNOf2aHLE,39799
7
7
  dbdicom/register.py,sha256=_NyNbOEAN_hkwjxupNpr9F5DWUwARCsci8knK41-EsA,13931
8
8
  dbdicom/external/__init__.py,sha256=XNQqfspyf6vFGedXlRKZsUB8k8E-0W19Uamwn8Aioxo,316
9
9
  dbdicom/external/__pycache__/__init__.cpython-311.pyc,sha256=pXAQ35ixd92fm6YcuHgzR1t6RcASQ-cHhU1wOA5b8sw,542
@@ -35,7 +35,7 @@ dbdicom/external/dcm4che/lib/windows-x86/clib_jiio_util.dll,sha256=wi4yyrI1gTRo_
35
35
  dbdicom/external/dcm4che/lib/windows-x86/opencv_java.dll,sha256=QanyzLy0Cd79-aOVPwOcXwikUYeutne0Au-Um91_B4M,8505856
36
36
  dbdicom/external/dcm4che/lib/windows-x86-64/opencv_java.dll,sha256=TmjW2SbG4MR3GQ95T8xCVVDLgsdKukgaHBPUvWkfXp8,11039232
37
37
  dbdicom/sop_classes/ct_image.py,sha256=16PNv_0e1_7cfxE12JWlx5YQeaTAQVzwtXTjxs3aonk,2812
38
- dbdicom/sop_classes/enhanced_mr_image.py,sha256=13j4EGXniBpJxpzzL3Xa4y3g5OKhMd5Ct7cjPGOYQY4,35496
38
+ dbdicom/sop_classes/enhanced_mr_image.py,sha256=8JWg8I86YtYBKYgiZdsA-OHPFS6_1GpW4lYCudKMAI4,33379
39
39
  dbdicom/sop_classes/mr_image.py,sha256=1biIw7R26Fc38FAeSlWxd29VO17e8cEQdDIdLbeXTzw,10959
40
40
  dbdicom/sop_classes/parametric_map.py,sha256=2OKBuC2bo03OEpKqimQS-nVGFp1cKRPYwVgmDGVf1JU,12288
41
41
  dbdicom/sop_classes/secondary_capture.py,sha256=wgNRX8qyhV7HR7Jq2tQWPPuGpiRzYl6qPOgK6qFbPUc,4541
@@ -45,10 +45,10 @@ dbdicom/sop_classes/xray_angiographic_image.py,sha256=nWysCGaEWKVNItnOgyJfcGMpS3
45
45
  dbdicom/utils/arrays.py,sha256=cZo6hKk-pg_e2WCs9vxW9dxX04gmH3EwSZKFX1n8pq4,1451
46
46
  dbdicom/utils/dcm4che.py,sha256=Vxq8NYWWK3BuqJkzhBQ89oMqzJlnxqTxgsgTo_Frznc,2317
47
47
  dbdicom/utils/files.py,sha256=qhWNJqeWnRjDNbERpC6Mz962_TW9mFdvd2lnBbK3xt4,2259
48
- dbdicom/utils/image.py,sha256=qsU_wOdleZCqU5g7LSp8OXKmoG109NauYx7wad_ZQ7Q,3839
49
- dbdicom/utils/variables.py,sha256=vUh5cDnmCft5hoXDYXUvfkg5Cy5WlgMAogU38Y_BKRo,5753
50
- dbdicom-0.3.7.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
51
- dbdicom-0.3.7.dist-info/METADATA,sha256=kSsHB7e2v_JdenBx6j9hewbYIOsPucwANgvL_BZEjXw,1030
52
- dbdicom-0.3.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
53
- dbdicom-0.3.7.dist-info/top_level.txt,sha256=nJWxXg4YjD6QblfmhrzTMXcr8FSKNc0Yk-CAIDUsYkQ,8
54
- dbdicom-0.3.7.dist-info/RECORD,,
48
+ dbdicom/utils/image.py,sha256=zRM1O0bxPp-qpf3Iv_GRS1omKaMN1SgSkAwufWLJ0Fk,3863
49
+ dbdicom/utils/pydicom_dataset.py,sha256=XM3EERsCWPlEaUzVaFQSbPNiNbEGwxIbf-sUKKf_YxA,12755
50
+ dbdicom-0.3.9.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
51
+ dbdicom-0.3.9.dist-info/METADATA,sha256=aNhxdZoSLOvA-OIJOPGsL-BPWjUWFoNNJd2ICWjZUGk,1030
52
+ dbdicom-0.3.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
53
+ dbdicom-0.3.9.dist-info/top_level.txt,sha256=nJWxXg4YjD6QblfmhrzTMXcr8FSKNc0Yk-CAIDUsYkQ,8
54
+ dbdicom-0.3.9.dist-info/RECORD,,
@@ -1,161 +0,0 @@
1
- import math
2
- import datetime
3
-
4
- def str_to_seconds(dicom_tm):
5
- if dicom_tm is None:
6
- return None
7
- if dicom_tm == '':
8
- return None
9
- # dicom_tm is of the form 'HHMMSS.FFFFFF'
10
- # Split the seconds into seconds and fractional seconds
11
- seconds, fractional_seconds = dicom_tm.split('.')
12
- # Convert the hours, minutes, and seconds to integers
13
- hours = int(seconds[:2])
14
- minutes = int(seconds[2:4])
15
- seconds = int(seconds[4:])
16
- # Convert the fractional seconds to a decimal
17
- fractional_seconds = float('.' + fractional_seconds)
18
- # Create a datetime object representing the time
19
- seconds_since_midnight = (hours * 3600) + (minutes * 60) + seconds + fractional_seconds
20
- return seconds_since_midnight
21
-
22
- def seconds_to_str(seconds_since_midnight):
23
- # if not isinstance(seconds_since_midnight, float):
24
- # return None
25
- if seconds_since_midnight is None:
26
- return None
27
- seconds_since_midnight = float(seconds_since_midnight)
28
- hours = math.floor(seconds_since_midnight/3600)
29
- minutes = math.floor((seconds_since_midnight-hours*3600)/60)
30
- seconds = math.floor(seconds_since_midnight-hours*3600-minutes*60)
31
- fractional_seconds = round(seconds_since_midnight-hours*3600-minutes*60-seconds, 6)
32
- hours = str(hours).zfill(2)
33
- minutes = str(minutes).zfill(2)
34
- seconds = str(seconds).zfill(2)
35
- fractional_seconds = str(fractional_seconds)
36
- fractional_seconds = fractional_seconds.split('.')
37
- if len(fractional_seconds) == 2:
38
- fractional_seconds = fractional_seconds[1].ljust(6,'0')
39
- else:
40
- fractional_seconds = '0'.ljust(6,'0')
41
- return hours + minutes + seconds + '.' + fractional_seconds
42
-
43
- def time_to_seconds(tm):
44
- if tm is None:
45
- return None
46
- hours = tm.hour
47
- minutes = tm.minute
48
- seconds = tm.second
49
- fractional_seconds = tm.microsecond / 1000000.0
50
- seconds_since_midnight = (hours * 3600) + (minutes * 60) + seconds + fractional_seconds
51
- return seconds_since_midnight
52
-
53
- def seconds_to_time(seconds_since_midnight):
54
- # if not isinstance(seconds_since_midnight, float):
55
- # return None
56
- if seconds_since_midnight is None:
57
- return None
58
- seconds_since_midnight = float(seconds_since_midnight)
59
- hours = math.floor(seconds_since_midnight/3600)
60
- minutes = math.floor((seconds_since_midnight-hours*3600)/60)
61
- seconds = math.floor(seconds_since_midnight-hours*3600-minutes*60)
62
- fractional_seconds = round(seconds_since_midnight-hours*3600-minutes*60-seconds, 6)
63
- microseconds = fractional_seconds*1000000.0
64
- return datetime.time(int(hours), int(minutes), int(seconds), int(microseconds))
65
-
66
- def time_to_str(tm):
67
- if tm is None:
68
- return None
69
- hours = tm.hour
70
- minutes = tm.minute
71
- seconds = tm.second
72
- fractional_seconds = tm.microsecond / 1000000.0
73
- hours = str(hours).zfill(2)
74
- minutes = str(minutes).zfill(2)
75
- seconds = str(seconds).zfill(2)
76
- fractional_seconds = str(fractional_seconds)
77
- _, fractional_seconds = fractional_seconds.split('.')
78
- fractional_seconds = fractional_seconds.ljust(6,'0')
79
- return hours + minutes + seconds + '.' + fractional_seconds
80
-
81
- def date_to_str(tm):
82
- if tm is None:
83
- return None
84
- year = str(tm.year).rjust(4, '0')
85
- month = str(tm.month).rjust(2, '0')
86
- day = str(tm.day).rjust(2, '0')
87
- return year + month + day
88
-
89
- def datetime_to_str(dt):
90
- if dt is None:
91
- return None
92
- date = date_to_str(dt.date())
93
- time = time_to_str(dt.time())
94
- return date + time
95
-
96
-
97
- def test_all_conversions(sec, dcm, tim, date, date_str, dt, dt_str):
98
-
99
- assert seconds_to_str(None) is None
100
- assert str_to_seconds(dcm) == sec
101
- assert seconds_to_str(sec) == dcm
102
- assert str_to_seconds(seconds_to_str(sec)) == sec
103
- assert seconds_to_str(str_to_seconds(dcm)) == dcm
104
- assert time_to_seconds(tim) == sec
105
- assert seconds_to_time(sec) == tim
106
- assert time_to_seconds(seconds_to_time(sec)) == sec
107
- assert seconds_to_time(time_to_seconds(tim)) == tim
108
- assert date_to_str(date) == date_str
109
- assert time_to_str(tim) == dcm
110
- assert datetime_to_str(dt) == dt_str
111
-
112
-
113
- def test_module():
114
-
115
- sec = 13*60*60 + 12*60 + 40 + 0.03
116
- dcm = '131240.030000'
117
- tim = datetime.time(13, 12, 40, 30000)
118
- date = datetime.date(2023, 3, 1)
119
- date_str = '20230301'
120
- dt = datetime.datetime(2023, 3, 1, 13, 12, 40, 30000)
121
- dt_str = '20230301131240.030000'
122
-
123
- test_all_conversions(sec, dcm, tim, date, date_str, dt, dt_str)
124
-
125
- sec = 7*60*60 + 12*60 + 40 + 0.03
126
- dcm = '071240.030000'
127
- tim = datetime.time(7, 12, 40, 30000)
128
- date = datetime.date(2023, 3, 1)
129
- date_str = '20230301'
130
- dt = datetime.datetime(2023, 3, 1, 7, 12, 40, 30000)
131
- dt_str = '20230301071240.030000'
132
-
133
- test_all_conversions(sec, dcm, tim, date, date_str, dt, dt_str)
134
-
135
- sec = 7*60*60 + 3*60 + 40 + 0.03
136
- dcm = '070340.030000'
137
- tim = datetime.time(7, 3, 40, 30000)
138
- date = datetime.date(2023, 3, 1)
139
- date_str = '20230301'
140
- dt = datetime.datetime(2023, 3, 1, 7, 3, 40, 30000)
141
- dt_str = '20230301070340.030000'
142
-
143
- test_all_conversions(sec, dcm, tim, date, date_str, dt, dt_str)
144
-
145
- sec = 7*60*60 + 3*60 + 4 + 0.03
146
- dcm = '070304.030000'
147
- tim = datetime.time(7, 3, 4, 30000)
148
- date = datetime.date(2023, 3, 1)
149
- date_str = '20230301'
150
- dt = datetime.datetime(2023, 3, 1, 7, 3, 4, 30000)
151
- dt_str = '20230301070304.030000'
152
-
153
- test_all_conversions(sec, dcm, tim, date, date_str, dt, dt_str)
154
-
155
- print('dbdicom.utils.variables passed all tests')
156
-
157
-
158
- if __name__ == "__main__":
159
-
160
- test_module()
161
-