diff --git a/nibabel/freesurfer/mghformat.py b/nibabel/freesurfer/mghformat.py index f63875b2c6..1091e256a9 100644 --- a/nibabel/freesurfer/mghformat.py +++ b/nibabel/freesurfer/mghformat.py @@ -454,13 +454,13 @@ def writeftr_to(self, fileobj): fileobj.write(ftr_nd.tostring()) -# Register .mgz extension as compressed -@ImageOpener.register_ext_from_image('.mgz', ImageOpener.gz_def) class MGHImage(SpatialImage): """ Class for MGH format image """ header_class = MGHHeader - valid_exts = ('.mgh',) + valid_exts = ('.mgh', '.mgz') + # Register that .mgz extension signals gzip compression + ImageOpener.compress_ext_map['.mgz'] = ImageOpener.gz_def files_types = (('image', '.mgh'),) _compressed_suffixes = () diff --git a/nibabel/openers.py b/nibabel/openers.py index 26bbb09d7b..1969766a55 100644 --- a/nibabel/openers.py +++ b/nibabel/openers.py @@ -149,42 +149,22 @@ def __exit__(self, exc_type, exc_val, exc_tb): class ImageOpener(Opener): - """ Opener-type class passed to image classes to collect compressed extensions + """ Opener-type class to collect extra compressed extensions - This class allows itself to have image extensions added to its class - attributes, via the `register_ex_from_images`. The class can therefore - change state when image classes are defined. + A trivial sub-class of opener to which image classes can add extra + extensions with custom openers, such as compressed openers. + + To add an extension, add a line to the class definition (not __init__): + + ImageOpener.compress_ext_map[ext] = func_def + + ``ext`` is a file extension beginning with '.' and should be included in + the image class's ``valid_exts`` tuple. + + ``func_def`` is a `(function, (args,))` tuple, where `function accepts a + filename as the first parameter, and `args` defines the other arguments + that `function` accepts. These arguments must be any (unordered) subset of + `mode`, `compresslevel`, and `buffering`. """ + # Add new extensions to this dictionary compress_ext_map = Opener.compress_ext_map.copy() - - @classmethod - def register_ext_from_image(opener_klass, ext, func_def): - """Decorator for adding extension / opener_function associations. - - Should be used to decorate classes. Updates ImageOpener class with - desired extension / opener association. Updates decorated class by - adding ```ext``` to ```klass.alternate_exts```. - - Parameters - ---------- - opener_klass : decorated class - ext : file extension to associate `func_def` with. - should start with '.' - func_def : opener function/parameter tuple - Should be a `(function, (args,))` tuple, where `function` accepts - a filename as the first parameter, and `args` defines the - other arguments that `function` accepts. These arguments must - be any (unordered) subset of `mode`, `compresslevel`, - and `buffering`. - - Returns - ------- - opener_klass - """ - def decorate(klass): - assert ext not in opener_klass.compress_ext_map, \ - "Cannot redefine extension-function mappings." - opener_klass.compress_ext_map[ext] = func_def - klass.valid_exts += (ext,) - return klass - return decorate diff --git a/nibabel/tests/test_openers.py b/nibabel/tests/test_openers.py index 08f9730ace..2900a0437e 100644 --- a/nibabel/tests/test_openers.py +++ b/nibabel/tests/test_openers.py @@ -93,8 +93,6 @@ def test_BinOpener(): class TestImageOpener: - valid_exts = () - def setUp(self): self.compress_ext_map = ImageOpener.compress_ext_map.copy() @@ -115,12 +113,9 @@ def file_opener(fileish, mode): # Add the association n_associations = len(ImageOpener.compress_ext_map) - dec = ImageOpener.register_ext_from_image('.foo', - (file_opener, ('mode',))) - dec(self.__class__) + ImageOpener.compress_ext_map['.foo'] = (file_opener, ('mode',)) assert_equal(n_associations + 1, len(ImageOpener.compress_ext_map)) assert_true('.foo' in ImageOpener.compress_ext_map) - assert_true('.foo' in self.valid_exts) with InTemporaryDirectory(): with ImageOpener('test.foo', 'w'):