Skip to content

Commit 9835998

Browse files
authored
Merge branch 'master' into loadsave-pathlib_compat
2 parents 180fd50 + 30c0bc5 commit 9835998

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+3028
-892
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
.project
1717
.pydevproject
1818
*.py.orig
19+
.DS_Store
1920

2021
# Not sure what the next one is for
2122
*.kpf

Changelog

+64
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,70 @@ Gerhard (SG) and Eric Larson (EL).
2424

2525
References like "pr/298" refer to github pull request numbers.
2626

27+
2.3 (Tuesday 12 June 2018)
28+
==========================
29+
30+
New features
31+
------------
32+
* TRK <=> TCK streamlines conversion CLI tools (pr/606) (MC, reviewed by CM)
33+
* Image slicing for SpatialImages (pr/550) (CM)
34+
35+
Enhancements
36+
------------
37+
* Simplfiy MGHImage and add footer fields (pr/569) (CM, reviewed by MB)
38+
* Force sform/qform codes to be ints, rather than numpy types (pr/575) (Paul
39+
McCarthy, reviewed by MB, CM)
40+
* Auto-fill color table in FreeSurfer annotation file (pr/592) (Paul McCarthy,
41+
reviewed by CM, MB)
42+
* Set default intent code for CIFTI2 images (pr/604) (Mathias Goncalves,
43+
reviewed by CM, Satra Ghosh, MB, Tim Coalson)
44+
* Raise informative error on empty files (pr/611) (Pradeep Raamana, reviewed
45+
by CM, MB)
46+
* Accept degenerate filenames such as ``.nii`` (pr/621) (Dimitri
47+
Papadopoulos-Orfanos, reviewed by Yaroslav Halchenko)
48+
* Take advantage of ``IndexedGzipFile`` ``drop_handles`` flag to release
49+
filehandles by default (pr/614) (Paul McCarthy, reviewed by CM, MB)
50+
51+
Bug fixes
52+
---------
53+
* Preserve first point of `LazyTractogram` (pr/588) (MC, reviewed by Nil
54+
Goyette, CM, MB)
55+
* Stop adding extraneous metadata padding (pr/593) (Jon Stutters, reviewed by
56+
CM, MB)
57+
* Accept lower-case orientation codes in TRK files (pr/600) (Kesshi Jordan,
58+
MB, reviewed by MB, MC, CM)
59+
* Annotation file reading (pr/592) (Paul McCarthy, reviewed by CM, MB)
60+
* Fix buffer size calculation in ArraySequence (pr/597) (Serge Koudoro,
61+
reviewed by MC, MB, Eleftherios Garyfallidis, CM)
62+
* Resolve ``UnboundLocalError`` in Python 3 (pr/607) (Jakub Kaczmarzyk,
63+
reviewed by MB, CM)
64+
* Do not crash on non-``ImportError`` failures in optional imports (pr/618)
65+
(Yaroslav Halchenko, reviewed by CM)
66+
* Return original array from ``get_fdata`` for array image, if no cast
67+
required (pr/638, MB, reviewed by CM)
68+
69+
Maintenance
70+
-----------
71+
* Use SSH address to use key-based auth (pr/587) (CM, reviewed by MB)
72+
* Fix doctests for numpy 1.14 array printing (pr/591) (MB, reviewed by CM)
73+
* Refactor for pydicom 1.0 API changes (pr/599) (MB, reviewed by CM)
74+
* Increase test coverage, remove unreachable code (pr/602) (CM, reviewed by
75+
Yaroslav Halchenko, MB)
76+
* Move ``nib-ls`` and other programs to a new cmdline module (pr/601, pr/615)
77+
(Chris Cheng, reviewed by MB, Yaroslav Halchenko)
78+
* Remove deprecated numpy indexing (EL, reviewed by CM)
79+
* Update documentation to encourage ``get_fdata`` over ``get_data`` (pr/637,
80+
MB, reviewed by CM)
81+
82+
API changes and deprecations
83+
----------------------------
84+
* Support for ``keep_file_open = 'auto'`` as a parameter to ``Opener()`` will
85+
be deprecated in 2.4, for removal in 3.0. Accordingly, support for
86+
``openers.KEEP_FILE_OPEN_DEFAULT = 'auto'`` will be dropped on the same
87+
schedule.
88+
* Drop-in support for ``indexed_gzip < 0.7`` has been removed.
89+
90+
2791
2.2.1 (Wednesday 22 November 2017)
2892
==================================
2993

bin/nib-dicomfs

+2-208
Original file line numberDiff line numberDiff line change
@@ -9,213 +9,7 @@
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

19814
if __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

Comments
 (0)