Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
fslpy
Manage
Activity
Members
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Analyze
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Evan Edmond
fslpy
Commits
7f7dd1ed
Commit
7f7dd1ed
authored
10 years ago
by
Paul McCarthy
Browse files
Options
Downloads
Patches
Plain Diff
Documented fsl.data package.
parent
ba84cdf7
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
fsl/data/__init__.py
+7
-0
7 additions, 0 deletions
fsl/data/__init__.py
fsl/data/fslimage.py
+215
-144
215 additions, 144 deletions
fsl/data/fslimage.py
fsl/data/imagefile.py
+42
-17
42 additions, 17 deletions
fsl/data/imagefile.py
with
264 additions
and
161 deletions
fsl/data/__init__.py
+
7
−
0
View file @
7f7dd1ed
#!/usr/bin/env python
#
# __init__.py - fsl.data package.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""
Data structures and models.
"""
This diff is collapsed.
Click to expand it.
fsl/data/fslimage.py
+
215
−
144
View file @
7f7dd1ed
...
...
@@ -5,6 +5,9 @@
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""
Classes for representing 3D/4D images, display properties of images, and
collections of images.
"""
import
os
import
sys
...
...
@@ -28,13 +31,13 @@ log = logging.getLogger(__name__)
def
_loadImageFile
(
filename
):
"""
Given the name of an image file, loads it using nibabel. If the file
is large, and is gzipped, it is decompressed to a temporary
location,
so that it can be memory-mapped. A tuple is returned,
consisting of
the nibabel image object, and the name of the file that it
was loaded
from (either the passed-in file name, or the name of the
temporary
decompressed file).
"""
Given the name of an image file, loads it using nibabel.
If the file
is large, and is gzipped, it is decompressed to a temporary
location,
so that it can be memory-mapped. A tuple is returned,
consisting of
the nibabel image object, and the name of the file that it
was loaded
from (either the passed-in file name, or the name of the
temporary
decompressed file).
"""
# If we have a GUI, we can display a dialog
...
...
@@ -48,71 +51,113 @@ def _loadImageFile(filename):
pass
realFilename
=
filename
mbytes
=
op
.
getsize
(
filename
)
/
1048576.0
if
filename
.
endswith
(
'
.nii.gz
'
):
mbytes
=
op
.
getsize
(
filename
)
/
1048576.0
# The mbytes limit is arbitrary
if
filename
.
endswith
(
'
.nii.gz
'
)
and
mbytes
>
512
:
# This limit is arbitrary
if
mbytes
>
512
:
unzipped
,
filename
=
tempfile
.
mkstemp
(
suffix
=
'
.nii
'
)
unzipped
,
filename
=
tempfile
.
mkstemp
(
suffix
=
'
.nii
'
)
unzipped
=
os
.
fdopen
(
unzipped
)
unzipped
=
os
.
fdopen
(
unzipped
)
msg
=
'
{} is a large file ({} MB) - decompressing
'
\
'
to {}, to allow memory mapping...
'
.
format
(
realFilename
,
mbytes
,
filename
)
msg
=
'
{} is a large file ({} MB) - decompressing
'
\
'
to {}, to allow memory mapping...
'
.
format
(
realFilename
,
mbytes
,
filename
)
if
not
haveGui
:
log
.
info
(
msg
)
else
:
busyDlg
=
wx
.
BusyInfo
(
msg
,
wx
.
GetTopLevelWindows
()[
0
])
if
not
haveGui
:
log
.
info
(
msg
)
else
:
busyDlg
=
wx
.
BusyInfo
(
msg
,
wx
.
GetTopLevelWindows
()[
0
])
gzip
=
[
'
gzip
'
,
'
-d
'
,
'
-c
'
,
realFilename
]
log
.
debug
(
'
Running {} > {}
'
.
format
(
'
'
.
join
(
gzip
),
filename
))
gzip
=
[
'
gzip
'
,
'
-d
'
,
'
-c
'
,
realFilename
]
log
.
debug
(
'
Running {} > {}
'
.
format
(
'
'
.
join
(
gzip
),
filename
))
# If the gzip call fails, revert to loading from the gzipped file
try
:
sp
.
call
(
gzip
,
stdout
=
unzipped
)
unzipped
.
close
()
# If the gzip call fails, revert to loading from the gzipped file
try
:
sp
.
call
(
gzip
,
stdout
=
unzipped
)
unzipped
.
close
()
except
OSError
as
e
:
log
.
warn
(
'
gzip call failed ({}) - cannot memory
'
'
map file: {}
'
.
format
(
e
,
realFilename
),
exc_info
=
True
)
unzipped
.
close
()
os
.
remove
(
filename
)
filename
=
realFilename
except
OSError
as
e
:
log
.
warn
(
'
gzip call failed ({}) - cannot memory
'
'
map file: {}
'
.
format
(
e
,
realFilename
),
exc_info
=
True
)
unzipped
.
close
()
os
.
remove
(
filename
)
filename
=
realFilename
if
haveGui
:
busyDlg
.
Destroy
()
if
haveGui
:
busyDlg
.
Destroy
()
return
nib
.
load
(
filename
),
filename
class
Image
(
props
.
HasProperties
):
"""
Class which represents a 3D/4D image. Internally, the image is
loaded/stored using nibabel.
"""
Class which represents a 3D/4D image. Internally, the image is
loaded/stored using :mod:`nibabel`.
Arbitrary data may be associated with an :class:`Image` object, via the
:meth:`getAttribute` and :meth:`setAttribute` methods (which are just
front end wrappers around an internal ``dict`` object).
The following attributes are present on an :class:`Image` object:
:ivar nibImage: The :mod:`nibabel` image object.
:ivar data: A reference to the image data, stored as a
:mod`numpy` array.
:ivar display: A :class:`ImageDisplay` object, defining how this
image should be displayed.
:ivar shape: A list/tuple containing the number of voxels
along each image dimension.
:ivar pixdim: A list/tuple containing the size of one voxel
alon each image dimension.
:ivar voxToWorldMat: A 4*4 array specifying the affine transformation
for transforming voxel coordinates into real world
coordinates.
:ivar worldToVoxMat: A 4*4 array specifying the affine transformation
for transforming real world coordinates into voxel
coordinates.
:ivar imageFile: The name of the file that the image was loaded from.
:ivar tempFile: The name of the temporary file which was created (in
the event that the image was large and was gzipped -
see :func:`_loadImageFile`).
"""
# How the image should be transformd into real world space.
transform
=
props
.
Choice
(
collections
.
OrderedDict
([
(
'
affine
'
,
'
Use qform/sform transformation matrix
'
),
(
'
pixdim
'
,
'
Use pixdims only
'
),
(
'
id
'
,
'
Do not use qform/sform or pixdims
'
)]),
default
=
'
affine
'
)
name
=
props
.
String
()
imageFile
=
props
.
FilePath
()
tempFile
=
props
.
FilePath
()
"""
This property defines how the image should be transformd into real world
space.
- ``affine``: Use the affine transformation matrix stored in the image
(the ``qform``/``sform`` fields in NIFTI1 headers).
- ``pixdim``: Scale voxel sizes by the ``pixdim`` fields in the image
header.
- ``id``: Perform no scaling or transformation - voxels will be
displayed as :math:`1mm^3` isotropic.
"""
name
=
props
.
String
()
"""
The name of this image.
"""
def
__init__
(
self
,
image
):
"""
Initialise an Image object with the given image data or file name.
"""
Initialise an Image object with the given image data or file name.
:arg image: A string containing the name of an image file to load, or
a :mod:`numpy` array, or a :mod:`nibabel` image object.
"""
# The image parameter may be the name of an image file
...
...
@@ -172,24 +217,27 @@ class Image(props.HasProperties):
def
_transformChanged
(
self
,
*
a
):
"""
"""
This method is called when the :attr:`transform` property value
changes. It updates the :attr:`voxToWorldMat`, :attr:`worldToVoxMat`,
and :attr:`pixdim` attributes to reflect the new transformation
type.
"""
if
self
.
transform
==
'
affine
'
:
voxToWorldMat
=
self
.
nibImage
.
get_affine
()
pixdim
s
=
self
.
nibImage
.
get_header
().
get_zooms
()
pixdim
=
self
.
nibImage
.
get_header
().
get_zooms
()
elif
self
.
transform
==
'
pixdim
'
:
pixdim
s
=
self
.
nibImage
.
get_header
().
get_zooms
()
voxToWorldMat
=
np
.
diag
([
pixdim
s
[
0
],
pixdim
s
[
1
],
pixdim
s
[
2
],
1.0
])
pixdim
=
self
.
nibImage
.
get_header
().
get_zooms
()
voxToWorldMat
=
np
.
diag
([
pixdim
[
0
],
pixdim
[
1
],
pixdim
[
2
],
1.0
])
elif
self
.
transform
==
'
id
'
:
voxToWorldMat
=
np
.
identity
(
4
)
pixdim
s
=
[
1.0
,
1.0
,
1.0
]
pixdim
=
[
1.0
,
1.0
,
1.0
]
self
.
voxToWorldMat
=
np
.
array
(
voxToWorldMat
,
dtype
=
np
.
float32
)
self
.
worldToVoxMat
=
linalg
.
inv
(
self
.
voxToWorldMat
)
self
.
pixdim
s
=
pixdim
s
self
.
pixdim
=
pixdim
self
.
voxToWorldMat
=
self
.
voxToWorldMat
.
transpose
()
self
.
worldToVoxMat
=
self
.
worldToVoxMat
.
transpose
()
...
...
@@ -198,7 +246,7 @@ class Image(props.HasProperties):
# location (0, 0) to map to voxel location (0, 0)
if
self
.
transform
in
[
'
pixdim
'
,
'
id
'
]:
for
i
in
range
(
3
):
self
.
voxToWorldMat
[
3
,
i
]
=
self
.
pixdim
s
[
i
]
*
0.5
self
.
voxToWorldMat
[
3
,
i
]
=
self
.
pixdim
[
i
]
*
0.5
self
.
worldToVoxMat
[
3
,
i
]
=
-
0.5
log
.
debug
(
'
Image {} transformation matrix changed: {}
'
.
format
(
...
...
@@ -207,9 +255,8 @@ class Image(props.HasProperties):
def
imageBounds
(
self
,
axis
):
"""
Return the bounds (min, max) of the image, in real world
coordinates, along the specified axis.
"""
Return the bounds (min, max) of the image, in real world
coordinates, along the specified 0-indexed axis.
"""
x
,
y
,
z
=
self
.
shape
[:
3
]
...
...
@@ -238,24 +285,23 @@ class Image(props.HasProperties):
def
worldToVox
(
self
,
p
,
axes
=
None
):
"""
Transforms the given set of points in voxel coordinates to
points in world coordinates, according to the affine
transformation specified in the image file. The returned array
is either a numpy.float64 array, or a single integer value,
depending on the input. There is no guarantee that the returned
array of voxel coordinates is within the bounds of the image
shape. Parameters:
"""
Transforms the given set of points in voxel coordinates to points
in world coordinates, according to the current :attr:`transform`.
The returned array is either a :class:`numpy.float64` array, or a
single ``int`` value, depending on the input. There is no guarantee
that the returned array of voxel coordinates is within the bounds of
the image shape. Parameters:
-
p: N*A array, where N is the number of points, and A
is the number of axes to consider (default: 3)
:arg
p: N*A array, where N is the number of points, and A
is the number of axes to consider (default: 3)
.
-
axes: If None, it is assumed that the input p is a N*3
array, with each point being specified by x,y,z
coordinates. If a single value in the range (0-2),
it is assumed that p is a 1D array. Or, if a
sequence of 2 or 3 values, p must be an array of
N*2 or N*3, respectively.
:arg
axes: If
``
None
``
, it is assumed that the input p is a N*3
array, with each point being specified by x,y,z
coordinates. If a single value in the range (0-2),
it is assumed that p is a 1D array. Or, if a
sequence of 2 or 3 values, p must be an array of
N*2 or N*3, respectively.
"""
voxp
=
self
.
_transform
(
p
,
self
.
worldToVoxMat
,
axes
)
...
...
@@ -273,13 +319,13 @@ class Image(props.HasProperties):
def
voxToWorld
(
self
,
p
,
axes
=
None
):
"""
Transforms the given set of
points in
world
coordinates
to
points in voxel coordinates, according to the affine
transformation specified in the image file. The returned
array is either a numpy.float64 array,
or a single float
value, depending on the input. See the
worldToVox
docstring
for more details.
"""
Transforms the given set of points in world coordinates to
points in
voxel
coordinates
, according to the current
:attr:`transform`.
The returned
array is either a
:class:`
numpy.float64
`
array,
or a single ``float``
value, depending on the input. See the
:meth:`worldToVox` method
for more details.
"""
worldp
=
self
.
_transform
(
p
,
self
.
voxToWorldMat
,
axes
)
...
...
@@ -289,11 +335,11 @@ class Image(props.HasProperties):
def
_transform
(
self
,
p
,
a
,
axes
):
"""
Transforms the given set of points p according to the given
affine transformation a. The transformed points are retur
ne
d
as a numpy.float64 array. See the worldToVox docstring for
more details.
"""
Used by the :meth:`worldToVox` and :meth:`voxToWorld` methods.
Transforms the given set of points ``p`` according to the given affi
ne
transformation ``a``. The transformed points are returned as a
:class:``numpy.float64`` array.
"""
p
=
self
.
_fillPoints
(
p
,
axes
)
...
...
@@ -313,9 +359,8 @@ class Image(props.HasProperties):
def
_fillPoints
(
self
,
p
,
axes
):
"""
Used by the _transform method. Turns the given array p into a N*3
array of x,y,z coordinates. The array p may be a 1D array, or an
"""
Used by the :meth:`_transform` method. Turns the given array p into
a N*3 array of x,y,z coordinates. The array p may be a 1D array, or an
N*2 or N*3 array.
"""
...
...
@@ -347,16 +392,12 @@ class Image(props.HasProperties):
def
getAttribute
(
self
,
name
):
"""
Retrieve the attribute with the given name.
"""
"""
Retrieve the attribute with the given name.
"""
return
self
.
_attributes
[
name
]
def
setAttribute
(
self
,
name
,
value
):
"""
Set an attribute with the given name and the given value.
"""
"""
Set an attribute with the given name and the given value.
"""
self
.
_attributes
[
name
]
=
value
log
.
debug
(
'
Attribute set on {}: {} = {}
'
.
format
(
...
...
@@ -364,31 +405,48 @@ class Image(props.HasProperties):
class
ImageDisplay
(
props
.
HasProperties
):
"""
A class which describes how an image should be displayed. There should
be no need to manually instantiate ImageDisplay objects - one is created
for each Image object, and is accessed via the Image.display attribute.
If a single image needs to be displayed in different ways, then create
away, and manage your own ImageDisplay objects.
"""
A class which describes how an image should be displayed.
There should be no need to manually instantiate :class:`ImageDisplay`
objects - one is created for each :class:`Image` object, and is accessed
via the :attr:`Image.display` instance attribute. If a single image needs
to be displayed in different ways, then create away, and manage your own
:class:`ImageDisplay` objects.
This class doesn
'
t have any functionality - it is up to things which
actually display an Image to adhere to the properties stored in
the
associated ImageDisplay object.
actually display an
:class:`
Image
`
to adhere to the properties stored in
the
associated
:class:`
ImageDisplay
`
object.
"""
enabled
=
props
.
Boolean
(
default
=
True
)
alpha
=
props
.
Real
(
minval
=
0.0
,
maxval
=
1.0
,
default
=
1.0
)
enabled
=
props
.
Boolean
(
default
=
True
)
"""
Should this image be displayed at all?
"""
alpha
=
props
.
Real
(
minval
=
0.0
,
maxval
=
1.0
,
default
=
1.0
)
"""
Transparency - 1.0 is fully opaque, and 0.0 is fully transparent.
"""
displayRange
=
props
.
Bounds
(
ndims
=
1
,
editLimits
=
True
,
labels
=
[
'
Min.
'
,
'
Max.
'
])
"""
Image values which map to the minimum and maximum colour map colours.
"""
samplingRate
=
props
.
Int
(
minval
=
1
,
maxval
=
16
,
default
=
1
,
clamped
=
True
)
rangeClip
=
props
.
Boolean
(
default
=
False
)
cmap
=
props
.
ColourMap
(
default
=
mplcm
.
Greys_r
)
volume
=
props
.
Int
(
minval
=
0
,
maxval
=
0
,
default
=
0
,
clamped
=
True
)
"""
Only display every Nth voxel (a performance tweak).
"""
rangeClip
=
props
.
Boolean
(
default
=
False
)
"""
If ``True``, don
'
t display voxel values which are beyond the
:attr:`displayRange`.
"""
cmap
=
props
.
ColourMap
(
default
=
mplcm
.
Greys_r
)
"""
The colour map, a :class:`matplotlib.colors.Colourmap` instance.
"""
volume
=
props
.
Int
(
minval
=
0
,
maxval
=
0
,
default
=
0
,
clamped
=
True
)
"""
If a 4D image, the current volume to display.
"""
def
is4DImage
(
self
):
"""
Returns ``True`` if this image is 4D, ``False`` otherwise.
"""
return
len
(
self
.
image
.
shape
)
>
3
and
self
.
image
.
shape
[
3
]
>
1
_view
=
props
.
VGroup
((
'
enabled
'
,
props
.
Widget
(
'
volume
'
,
enabledWhen
=
is4DImage
),
'
displayRange
'
,
...
...
@@ -420,9 +478,9 @@ class ImageDisplay(props.HasProperties):
def
__init__
(
self
,
image
):
"""
Create an ImageDisplay for the specified image. The image
p
ar
ameter should be an
Image object
(defined above)
.
"""
Create an :class:`ImageDisplay` for the specified image.
:
ar
g image: A :class:`
Image
`
object.
"""
self
.
image
=
image
...
...
@@ -453,44 +511,58 @@ class ImageDisplay(props.HasProperties):
class
ImageList
(
props
.
HasProperties
):
"""
Class representing a collection of images to be displayed together.
Contains a List property containing Image objects, and some other
properties on which listeners may register themselves to be notified
when the properties of the image collection changes (e.g. image
bounds).
"""
Class representing a collection of images to be displayed together.
Contains a :class:`props.properties_types.List` property containing
:class:`Image` objects, and some other properties on which listeners may
register themselves to be notified when the properties of the image
collection changes (e.g. image bounds).
An :class:`ImageList` object has a few wrapper methods around the
:attr:`images` property, allowing the :class:`ImageList` to be used
as if it were a list itself.
"""
def
_validateImage
(
self
,
atts
,
images
):
"""
Returns ``True`` if all objects in the given ``images`` list are
:class:`Image` objects, ``False`` otherwise.
"""
return
all
(
map
(
lambda
img
:
isinstance
(
img
,
Image
),
images
))
# The images property contains a list of Image objects
images
=
props
.
List
(
validateFunc
=
_validateImage
,
allowInvalid
=
False
)
"""
A list of :class:`Image` objects. to be displayed
"""
# Index of the currently 'selected' image. This property
# is not used by the ImageList, but is provided so that
# other things can control and listen for changes to
# the currently selected image
selectedImage
=
props
.
Int
(
minval
=
0
,
clamped
=
True
)
"""
Index of the currently
'
selected
'
image. This property is not used by
the :class:`ImageList`, but is provided so that other things can control
and listen for changes to the currently selected image
"""
# The bounds property contains the min/max values of
# a bounding box (in real world coordinates) which
# is big enough to contain all of the images in the
# 'images' list. This property shouid be read-only,
# but I don't have a way to enforce it (yet).
bounds
=
props
.
Bounds
(
ndims
=
3
)
"""
This property contains the min/max values of
a bounding box (in real world coordinates) which
is big enough to contain all of the images in the
:attr:`images` list. This property shouid be
read-only, but I don
'
t have a way to enforce it
(yet).
"""
# The location property contains the currently 'selected'
# 3D location in the image list space. This property
# is not used directly by the ImageList object, but it
# is here so that the location selection can be synchronised
# across multiple displays.
location
=
props
.
Point
(
ndims
=
3
,
labels
=
(
'
X
'
,
'
Y
'
,
'
Z
'
))
"""
The location property contains the currently
'
selected
'
3D location in the image list space. This property
is not used directly by the ImageList object, but it
is here so that the location selection can be synchronised
across multiple displays.
"""
def
__init__
(
self
,
images
=
None
):
"""
Create an ImageList object from the given sequence of Image objects.
"""
"""
Create an ImageList object from the given sequence of
:class:`Image` objects.
"""
if
images
is
None
:
images
=
[]
...
...
@@ -514,10 +586,9 @@ class ImageList(props.HasProperties):
def
_imageListChanged
(
self
,
*
a
):
"""
Called whenever an item is added or removed from the list. Registers
listeners with the properties of each image, and updates the image
bounds
"""
Called whenever an item is added or removed from the :attr:`images`
list. Registers listeners with the properties of each image, and
calls the :meth:`_updateImageBounds` method.
"""
for
img
in
self
.
images
:
...
...
@@ -535,9 +606,9 @@ class ImageList(props.HasProperties):
def
_updateImageBounds
(
self
,
*
a
):
"""
Called whenever an item is added or removed from the list, or an
image property changes. Updates the xyz bounds
.
"""
Called whenever an item is added or removed from the
:attr:`images` list, or an image property changes. Updates
the :attr:`bounds` property
.
"""
if
len
(
self
.
images
)
==
0
:
...
...
@@ -574,7 +645,7 @@ class ImageList(props.HasProperties):
def
__iter__
(
self
):
return
self
.
images
.
__iter__
()
def
__contains__
(
self
,
item
):
return
self
.
images
.
__contains__
(
item
)
def
__setitem__
(
self
,
key
,
val
):
return
self
.
images
.
__setitem__
(
key
,
val
)
def
__delitem
(
self
,
key
):
return
self
.
images
.
__delitem__
(
key
)
def
__delitem
__
(
self
,
key
):
return
self
.
images
.
__delitem__
(
key
)
def
index
(
self
,
item
):
return
self
.
images
.
index
(
item
)
def
count
(
self
,
item
):
return
self
.
images
.
count
(
item
)
def
append
(
self
,
item
):
return
self
.
images
.
append
(
item
)
...
...
This diff is collapsed.
Click to expand it.
fsl/data/imagefile.py
+
42
−
17
View file @
7f7dd1ed
...
...
@@ -5,28 +5,38 @@
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""
Convenience functions for adding/stripping supported
file extensions to/from image file names.
"""
import
os
import
os.path
as
op
# The file extensions which we understand. This list is used
# as the default if if the allowedExts parameter is not passed
# to any of the functions in this module.
_allowedExts
=
[
'
.nii
'
,
'
.img
'
,
'
.hdr
'
,
'
.nii.gz
'
,
'
.img.gz
'
]
"""
The file extensions which we understand. This list is used as the default
if if the ``allowedExts`` parameter is not passed to any of the functions in
this module.
"""
_descriptions
=
[
'
NIFTI1 images
'
,
'
ANALYZE75 images
'
,
'
NIFTI1/ANALYZE75 headers
'
,
'
Compressed NIFTI1 images
'
,
'
Compressed ANALYZE75/NIFTI1 images
'
]
"""
Descriptions for each of the extensions in :data:`_allowedExts`.
"""
# The default file extension (TODO read this from $FSLOUTPUTTYPE)
_defaultExt
=
'
.nii.gz
'
"""
The default file extension (TODO read this from ``$FSLOUTPUTTYPE``).
"""
def
wildcard
(
allowedExts
=
None
):
"""
"""
Returns a wildcard string for use in a file dialog, to limit
the acceptable file types.
:arg allowedExts: A list of strings containing the allowed file
extensions.
"""
if
allowedExts
is
None
:
...
...
@@ -38,7 +48,7 @@ def wildcard(allowedExts=None):
exts
=
[
'
*{}
'
.
format
(
ext
)
for
ext
in
allowedExts
]
wcParts
=
[
'
|
'
.
join
((
desc
,
ext
))
for
(
desc
,
ext
)
in
zip
(
descs
,
exts
)]
wcParts
=
[
'
|
'
.
join
((
desc
,
ext
))
for
(
desc
,
ext
)
in
zip
(
descs
,
exts
)]
print
'
|
'
.
join
(
wcParts
)
return
'
|
'
.
join
(
wcParts
)
...
...
@@ -47,8 +57,13 @@ def wildcard(allowedExts=None):
def
isSupported
(
filename
,
allowedExts
=
None
):
"""
Returns True if the given file has a supported extension, False
Returns
``
True
``
if the given file has a supported extension,
``
False
``
otherwise.
:arg filename: The file name to test.
:arg allowedExts: A list of strings containing the allowed file
extensions.
"""
if
allowedExts
is
None
:
allowedExts
=
_allowedExts
...
...
@@ -58,8 +73,13 @@ def isSupported(filename, allowedExts=None):
def
removeExt
(
filename
,
allowedExts
=
None
):
"""
Removes the extension from the given file name. Raises a ValueError
Removes the extension from the given file name. Raises a
:exc:`
ValueError
`
if the file has an unsupported extension.
:arg filename: The file name to strip.
:arg allowedExts: A list of strings containing the allowed file
extensions.
"""
if
allowedExts
is
None
:
allowedExts
=
_allowedExts
...
...
@@ -85,22 +105,27 @@ def addExt(
mustExist
=
False
,
allowedExts
=
None
,
defaultExt
=
None
):
"""
Adds a file extension to the given file prefix. If mustExist is False
(the default), and the file does not already have a supported
extension, the default extension is appended and the new file name
returned. If the prefix already has a supported extension, it is
returned unchanged.
"""
Adds a file extension to the given file ``prefix``.
If mustExist is True, the function checks to see if any files exist
that have the given prefix, and a supported file extension. A
ValueError is raised if:
If ``mustExist`` is False (the default), and the file does not already
have a supported extension, the default extension is appended and the new
file name returned. If the prefix already has a supported extension,
it is returned unchanged.
If ``mustExist`` is ``True``, the function checks to see if any files
exist that have the given prefix, and a supported file extension. A
:exc:`ValueError` is raised if:
- No files exist with the given prefix and a supported extension.
- More than one file exists with the given prefix, and a supported
extension.
Otherwise the full file name is returned.
:arg prefix: The file name refix to modify.
:arg mustExist: Whether the file must exist or not.
:arg allowedExts: List of allowed file extensions.
:arg defaultExt: Default file extension to use.
"""
if
allowedExts
is
None
:
allowedExts
=
_allowedExts
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment