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

dbdicom/api.py CHANGED
@@ -1,10 +1,18 @@
1
+ import os
2
+ import shutil
3
+ import zipfile
4
+ from pathlib import Path
1
5
  from typing import Union
6
+ from tqdm import tqdm
7
+
2
8
 
3
9
  import vreg
4
10
 
5
11
  from dbdicom.dbd import DataBaseDicom
6
12
 
7
13
 
14
+
15
+
8
16
  def open(path:str) -> DataBaseDicom:
9
17
  """Open a DICOM database
10
18
 
@@ -363,10 +371,74 @@ def unique(pars:list, entity:list) -> dict:
363
371
  return u
364
372
 
365
373
 
374
+ def archive(path, archive_path):
375
+ dbd = open(path)
376
+ dbd.archive(archive_path)
377
+ dbd.close()
378
+
379
+
380
+ def restore(archive_path, path):
381
+ _copy_and_extract_zips(archive_path, path)
382
+ dbd = open(path)
383
+ dbd.close()
366
384
 
367
385
 
386
+ def _copy_and_extract_zips(src_folder, dest_folder):
387
+ if not os.path.exists(dest_folder):
388
+ os.makedirs(dest_folder)
368
389
 
390
+ # First pass: count total files
391
+ total_files = sum(len(files) for _, _, files in os.walk(src_folder))
369
392
 
370
- if __name__=='__main__':
393
+ with tqdm(total=total_files, desc="Copying and extracting") as pbar:
394
+ for root, dirs, files in os.walk(src_folder):
395
+ rel_path = os.path.relpath(root, src_folder)
396
+ dest_path = os.path.join(dest_folder, rel_path)
397
+ os.makedirs(dest_path, exist_ok=True)
371
398
 
399
+ for file in files:
400
+ src_file_path = os.path.join(root, file)
401
+ dest_file_path = os.path.join(dest_path, file)
402
+
403
+ if file.lower().endswith('.zip'):
404
+ try:
405
+ zip_dest_folder = dest_file_path[:-4]
406
+ with zipfile.ZipFile(src_file_path, 'r') as zip_ref:
407
+ zip_ref.extractall(zip_dest_folder)
408
+ #tqdm.write(f"Extracted ZIP: {src_file_path}")
409
+ #_flatten_folder(zip_dest_folder) # still needed?
410
+ except zipfile.BadZipFile:
411
+ tqdm.write(f"Bad ZIP file skipped: {src_file_path}")
412
+ else:
413
+ shutil.copy2(src_file_path, dest_file_path)
414
+
415
+ pbar.update(1)
416
+
417
+
418
+ def _flatten_folder(root_folder):
419
+ for dirpath, dirnames, filenames in os.walk(root_folder, topdown=False):
420
+ for filename in filenames:
421
+ src_path = os.path.join(dirpath, filename)
422
+ dst_path = os.path.join(root_folder, filename)
423
+
424
+ # If file with same name exists, optionally rename or skip
425
+ if os.path.exists(dst_path):
426
+ base, ext = os.path.splitext(filename)
427
+ counter = 1
428
+ while os.path.exists(dst_path):
429
+ dst_path = os.path.join(root_folder, f"{base}_{counter}{ext}")
430
+ counter += 1
431
+
432
+ shutil.move(src_path, dst_path)
433
+
434
+ # Remove empty subdirectories (but skip the root folder)
435
+ if dirpath != root_folder:
436
+ try:
437
+ os.rmdir(dirpath)
438
+ except OSError:
439
+ print(f"Could not remove {dirpath} — not empty or in use.")
440
+
441
+
442
+
443
+ if __name__=='__main__':
372
444
  pass
dbdicom/dbd.py CHANGED
@@ -2,6 +2,7 @@ import os
2
2
  from datetime import datetime
3
3
  import json
4
4
  from typing import Union
5
+ import zipfile
5
6
 
6
7
  from tqdm import tqdm
7
8
  import numpy as np
@@ -880,6 +881,34 @@ class DataBaseDicom():
880
881
  register.add_instance(self.register, attr, rel_path)
881
882
 
882
883
 
884
+ def archive(self, archive_path):
885
+ # TODO add flat=True option for zipping at patient level
886
+ for pt in tqdm(self.register, desc='Archiving '):
887
+ for st in pt['studies']:
888
+ zip_dir = os.path.join(
889
+ archive_path,
890
+ f"Patient__{pt['PatientID']}",
891
+ f"Study__{st['StudyID']}__{st['StudyDescription']}",
892
+ )
893
+ os.makedirs(zip_dir, exist_ok=True)
894
+ for sr in st['series']:
895
+ try:
896
+ zip_file = os.path.join(
897
+ zip_dir,
898
+ f"Series__{sr['SeriesNumber']}__{sr['SeriesDescription']}.zip",
899
+ )
900
+ with zipfile.ZipFile(zip_file, 'w') as zipf:
901
+ for rel_path in sr['instances'].values():
902
+ file = os.path.join(self.path, rel_path)
903
+ zipf.write(file, arcname=os.path.basename(file))
904
+ except Exception as e:
905
+ raise RuntimeError(
906
+ f"Error extracting series {sr['SeriesDescription']} "
907
+ f"in study {st['StudyDescription']} of patient {pt['PatientID']}."
908
+ )
909
+
910
+
911
+
883
912
 
884
913
  def infer_slice_spacing(vols):
885
914
  # In case spacing between slices is not (correctly) encoded in
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dbdicom
3
- Version: 0.3.6
3
+ Version: 0.3.7
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=GiXke8CmCjfzGnRnHqKtuq68rA7yFB4BY74VsWSb0E4,11469
2
+ dbdicom/api.py,sha256=lUNLQo3aAAIFVF7IMccNhXAlbf1hMNTU9gHibdfbKcI,14135
3
3
  dbdicom/const.py,sha256=BqBiRRjeiSqDr1W6YvaayD8WKCjG4Cny2NT0GeLM6bI,4269
4
4
  dbdicom/database.py,sha256=_LUbH7gc9l7j_63AC71DjwxgTUwbEjHSy5kuvRw75Hw,4764
5
5
  dbdicom/dataset.py,sha256=kbswoVE3-Wtu0uwcSW319KzpdWx5fZphfKxizxJePzc,22773
6
- dbdicom/dbd.py,sha256=_Fj9xFpx6Rsr5UH5YR6PJaJPSOl4cMfNmk9V2b1dEyo,36894
6
+ dbdicom/dbd.py,sha256=yvj4PRj4gP1Qmh0VhibOrZ1oxy9v9qM9iOV0L6C_Ryw,38261
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
@@ -47,8 +47,8 @@ dbdicom/utils/dcm4che.py,sha256=Vxq8NYWWK3BuqJkzhBQ89oMqzJlnxqTxgsgTo_Frznc,2317
47
47
  dbdicom/utils/files.py,sha256=qhWNJqeWnRjDNbERpC6Mz962_TW9mFdvd2lnBbK3xt4,2259
48
48
  dbdicom/utils/image.py,sha256=qsU_wOdleZCqU5g7LSp8OXKmoG109NauYx7wad_ZQ7Q,3839
49
49
  dbdicom/utils/variables.py,sha256=vUh5cDnmCft5hoXDYXUvfkg5Cy5WlgMAogU38Y_BKRo,5753
50
- dbdicom-0.3.6.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
51
- dbdicom-0.3.6.dist-info/METADATA,sha256=cl4tN9uUuh7Cr_5V0zlBCwyTfWdJH69C4kAettD0CFg,1030
52
- dbdicom-0.3.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
53
- dbdicom-0.3.6.dist-info/top_level.txt,sha256=nJWxXg4YjD6QblfmhrzTMXcr8FSKNc0Yk-CAIDUsYkQ,8
54
- dbdicom-0.3.6.dist-info/RECORD,,
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,,