99### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
1010# Copyright (C) 2011 Christian Haselgrove
1111
12- import sys
13- import os
14- import stat
15- import errno
16- import time
17- import locale
18- import logging
19- import fuse
20- import nibabel as nib
21- import nibabel .dft as dft
22-
23- from optparse import OptionParser , Option
24-
25- uid = os .getuid ()
26- gid = os .getgid ()
27- encoding = locale .getdefaultlocale ()[1 ]
28-
29- fuse .fuse_python_api = (0 , 2 )
30-
31- logger = logging .getLogger ('nibabel.dft' )
32-
33- class FileHandle :
34-
35- def __init__ (self , fno ):
36- self .fno = fno
37- self .keep_cache = False
38- self .direct_io = False
39- return
40-
41- def __str__ (self ):
42- return 'FileHandle(%d)' % self .fno
43-
44- class DICOMFS (fuse .Fuse ):
45-
46- def __init__ (self , * args , ** kwargs ):
47- self .followlinks = kwargs .pop ('followlinks' , False )
48- fuse .Fuse .__init__ (self , * args , ** kwargs )
49- self .fhs = {}
50- return
51-
52- def get_paths (self ):
53- paths = {}
54- for study in dft .get_studies (self .dicom_path , self .followlinks ):
55- pd = paths .setdefault (study .patient_name_or_uid (), {})
56- patient_info = 'patient information\n '
57- patient_info = 'name: %s\n ' % study .patient_name
58- patient_info += 'ID: %s\n ' % study .patient_id
59- patient_info += 'birth date: %s\n ' % study .patient_birth_date
60- patient_info += 'sex: %s\n ' % study .patient_sex
61- pd ['INFO' ] = patient_info .encode ('ascii' , 'replace' )
62- study_datetime = '%s_%s' % (study .date , study .time )
63- study_info = 'study info\n '
64- study_info += 'UID: %s\n ' % study .uid
65- study_info += 'date: %s\n ' % study .date
66- study_info += 'time: %s\n ' % study .time
67- study_info += 'comments: %s\n ' % study .comments
68- d = {'INFO' : study_info .encode ('ascii' , 'replace' )}
69- for series in study .series :
70- series_info = 'series info\n '
71- series_info += 'UID: %s\n ' % series .uid
72- series_info += 'number: %s\n ' % series .number
73- series_info += 'description: %s\n ' % series .description
74- series_info += 'rows: %d\n ' % series .rows
75- series_info += 'columns: %d\n ' % series .columns
76- series_info += 'bits allocated: %d\n ' % series .bits_allocated
77- series_info += 'bits stored: %d\n ' % series .bits_stored
78- series_info += 'storage instances: %d\n ' % len (series .storage_instances )
79- d [series .number ] = {'INFO' : series_info .encode ('ascii' , 'replace' ),
80- '%s.nii' % series .number : (series .nifti_size , series .as_nifti ),
81- '%s.png' % series .number : (series .png_size , series .as_png )}
82- pd [study_datetime ] = d
83- return paths
84-
85- def match_path (self , path ):
86- wd = self .get_paths ()
87- if path == '/' :
88- logger .debug ('return root' )
89- return wd
90- for part in path .lstrip ('/' ).split ('/' ):
91- logger .debug ("path:%s part:%s" % (path , part ))
92- if part not in wd :
93- return None
94- wd = wd [part ]
95- logger .debug ('return' )
96- return wd
97-
98- def readdir (self , path , fh ):
99- logger .info ('readdir %s' % (path ,))
100- matched_path = self .match_path (path )
101- if matched_path is None :
102- return - errno .ENOENT
103- logger .debug ('matched %s' % (matched_path ,))
104- fnames = [ k .encode ('ascii' , 'replace' ) for k in matched_path .keys () ]
105- fnames .append ('.' )
106- fnames .append ('..' )
107- return [ fuse .Direntry (f ) for f in fnames ]
108-
109- def getattr (self , path ):
110- logger .debug ('getattr %s' % path )
111- matched_path = self .match_path (path )
112- logger .debug ('matched: %s' % (matched_path ,))
113- now = time .time ()
114- st = fuse .Stat ()
115- if isinstance (matched_path , dict ):
116- st .st_mode = stat .S_IFDIR | 0755
117- st .st_ctime = now
118- st .st_mtime = now
119- st .st_atime = now
120- st .st_uid = uid
121- st .st_gid = gid
122- st .st_nlink = len (matched_path )
123- return st
124- if isinstance (matched_path , str ):
125- st .st_mode = stat .S_IFREG | 0644
126- st .st_ctime = now
127- st .st_mtime = now
128- st .st_atime = now
129- st .st_uid = uid
130- st .st_gid = gid
131- st .st_size = len (matched_path )
132- st .st_nlink = 1
133- return st
134- if isinstance (matched_path , tuple ):
135- st .st_mode = stat .S_IFREG | 0644
136- st .st_ctime = now
137- st .st_mtime = now
138- st .st_atime = now
139- st .st_uid = uid
140- st .st_gid = gid
141- st .st_size = matched_path [0 ]()
142- st .st_nlink = 1
143- return st
144- return - errno .ENOENT
145-
146- def open (self , path , flags ):
147- logger .debug ('open %s' % (path ,))
148- matched_path = self .match_path (path )
149- if matched_path is None :
150- return - errno .ENOENT
151- for i in range (1 , 10 ):
152- if i not in self .fhs :
153- if isinstance (matched_path , str ):
154- self .fhs [i ] = matched_path
155- elif isinstance (matched_path , tuple ):
156- self .fhs [i ] = matched_path [1 ]()
157- else :
158- raise - errno .EFTYPE
159- return FileHandle (i )
160- raise - errno .ENFILE
161-
162- # not done
163- def read (self , path , size , offset , fh ):
164- logger .debug ('read' )
165- logger .debug (path )
166- logger .debug (size )
167- logger .debug (offset )
168- logger .debug (fh )
169- return self .fhs [fh .fno ][offset :offset + size ]
170-
171- def release (self , path , flags , fh ):
172- logger .debug ('release' )
173- logger .debug (path )
174- logger .debug (fh )
175- del self .fhs [fh .fno ]
176- return
177-
178- def get_opt_parser ():
179- # use module docstring for help output
180- p = OptionParser (
181- usage = "%s [OPTIONS] <DIRECTORY CONTAINING DICOMSs> <mount point>"
182- % os .path .basename (sys .argv [0 ]),
183- version = "%prog " + nib .__version__ )
184-
185- p .add_options ([
186- Option ("-v" , "--verbose" , action = "count" ,
187- dest = "verbose" , default = 0 ,
188- help = "make noise. Could be specified multiple times" ),
189- ])
190-
191- p .add_options ([
192- Option ("-L" , "--follow-links" , action = "store_true" ,
193- dest = "followlinks" , default = False ,
194- help = "Follow symbolic links in DICOM directory" ),
195- ])
196- return p
12+ from nibabel .cmdline .dicomfs import main
19713
19814if __name__ == '__main__' :
199- parser = get_opt_parser ()
200- (opts , files ) = parser .parse_args ()
201-
202- if opts .verbose :
203- logger .addHandler (logging .StreamHandler (sys .stdout ))
204- logger .setLevel (opts .verbose > 1 and logging .DEBUG or logging .INFO )
205-
206- if len (files ) != 2 :
207- sys .stderr .write ("Please provide two arguments:\n %s\n " % parser .usage )
208- sys .exit (1 )
209-
210- fs = DICOMFS (dash_s_do = 'setsingle' , followlinks = opts .followlinks )
211- fs .parse (['-f' , '-s' , files [1 ]])
212- fs .dicom_path = files [0 ].decode (encoding )
213- try :
214- fs .main ()
215- except fuse .FuseError :
216- # fuse prints the error message
217- sys .exit (1 )
218-
219- sys .exit (0 )
220-
221- # eof
15+ main ()
0 commit comments