From 3c1c9a81590d120b0728d54b8e3e8ddb521db5d9 Mon Sep 17 00:00:00 2001 From: Matthias Geier Date: Sun, 27 Apr 2014 17:04:29 +0200 Subject: [PATCH 1/4] Improve _init_vio() * move code from SoundFile.__init__() into _init_vio() * the dictionary with callback functions is now "hidden" in _init_vio() * the invocation of sf_open_*() is now clearer * the error message is at the right place * _init_vio() is now a "real" method because self is actually used --- pysoundfile.py | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/pysoundfile.py b/pysoundfile.py index dc330b8..01d421c 100644 --- a/pysoundfile.py +++ b/pysoundfile.py @@ -356,21 +356,14 @@ def __init__(self, file, mode='r', sample_rate=None, channels=None, self._file = _snd.sf_open(file, mode_int, self._info) elif isinstance(file, int): self._file = _snd.sf_open_fd(file, mode_int, self._info, closefd) - else: - # Note: readinto() is not checked - for attr in ('seek', 'read', 'write', 'tell'): - if not hasattr(file, attr): - raise RuntimeError( - "file must be a filename, a file descriptor or " - "a file-like object with the methods " - "'seek()', 'read()', 'write()' and 'tell()'") - # Note: the callback functions in _vio must be kept alive! - self._vio = self._init_vio(file) - vio = _ffi.new("SF_VIRTUAL_IO*", self._vio) - self._file = _snd.sf_open_virtual(vio, mode_int, self._info, - _ffi.NULL) + elif all(hasattr(file, a) for a in ('seek', 'read', 'write', 'tell')): + self._file = _snd.sf_open_virtual( + self._init_vio(file), mode_int, self._info, _ffi.NULL) self._name = str(file) - + else: + raise RuntimeError("file must be a filename, a file descriptor or " + "a file-like object with the methods " + "'seek()', 'read()', 'write()' and 'tell()'") self._handle_error() name = property(lambda self: self._name) @@ -442,11 +435,14 @@ def vio_write(ptr, count, user_data): def vio_tell(user_data): return file.tell() - return {'get_filelen': vio_get_filelen, - 'seek': vio_seek, - 'read': vio_read, - 'write': vio_write, - 'tell': vio_tell} + # Note: the callback functions must be kept alive! + self._vio = {'get_filelen': vio_get_filelen, + 'seek': vio_seek, + 'read': vio_read, + 'write': vio_write, + 'tell': vio_tell} + + return _ffi.new("SF_VIRTUAL_IO*", self._vio) def __del__(self): self.close() From 678ea70cb5fcabe3de31f12d163f2a70896665c6 Mon Sep 17 00:00:00 2001 From: Matthias Geier Date: Sun, 27 Apr 2014 17:16:40 +0200 Subject: [PATCH 2/4] Remove support for _length attribute of file-like objects See also #1. --- pysoundfile.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/pysoundfile.py b/pysoundfile.py index 01d421c..5a50429 100644 --- a/pysoundfile.py +++ b/pysoundfile.py @@ -393,16 +393,14 @@ def __init__(self, file, mode='r', sample_rate=None, channels=None, def _init_vio(self, file): @_ffi.callback("sf_vio_get_filelen") def vio_get_filelen(user_data): - # Streams must set _length or implement __len__ - if hasattr(file, '_length'): - size = file._length - elif not hasattr(file, '__len__'): - old_file_position = file.tell() + # first try __len__(), if not available fall back to seek()/tell() + try: + size = len(file) + except TypeError: + curr = file.tell() file.seek(0, SEEK_END) size = file.tell() - file.seek(old_file_position, SEEK_SET) - else: - size = len(file) + file.seek(curr, SEEK_SET) return size @_ffi.callback("sf_vio_seek") From 86f691c51ac28b36c5665e5148a0eb2ffb96e108 Mon Sep 17 00:00:00 2001 From: Matthias Geier Date: Sun, 27 Apr 2014 17:18:05 +0200 Subject: [PATCH 3/4] Remove unnecessary local variables --- pysoundfile.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pysoundfile.py b/pysoundfile.py index 5a50429..1276236 100644 --- a/pysoundfile.py +++ b/pysoundfile.py @@ -406,8 +406,7 @@ def vio_get_filelen(user_data): @_ffi.callback("sf_vio_seek") def vio_seek(offset, whence, user_data): file.seek(offset, whence) - curr = file.tell() - return curr + return file.tell() @_ffi.callback("sf_vio_read") def vio_read(ptr, count, user_data): @@ -426,8 +425,7 @@ def vio_read(ptr, count, user_data): def vio_write(ptr, count, user_data): buf = _ffi.buffer(ptr, count) data = buf[:] - length = file.write(data) - return length + return file.write(data) @_ffi.callback("sf_vio_tell") def vio_tell(user_data): From 61ba8adcad9165ed4e9a5f44429ef0b30a0cabd3 Mon Sep 17 00:00:00 2001 From: Matthias Geier Date: Sun, 27 Apr 2014 17:29:37 +0200 Subject: [PATCH 4/4] Change "vio" to "virtual_io" As suggested by @bastibe in #31. --- pysoundfile.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pysoundfile.py b/pysoundfile.py index 1276236..1be4bce 100644 --- a/pysoundfile.py +++ b/pysoundfile.py @@ -358,7 +358,7 @@ def __init__(self, file, mode='r', sample_rate=None, channels=None, self._file = _snd.sf_open_fd(file, mode_int, self._info, closefd) elif all(hasattr(file, a) for a in ('seek', 'read', 'write', 'tell')): self._file = _snd.sf_open_virtual( - self._init_vio(file), mode_int, self._info, _ffi.NULL) + self._init_virtual_io(file), mode_int, self._info, _ffi.NULL) self._name = str(file) else: raise RuntimeError("file must be a filename, a file descriptor or " @@ -390,7 +390,7 @@ def __init__(self, file, mode='r', sample_rate=None, channels=None, # avoid confusion if something goes wrong before assigning self._file: _file = None - def _init_vio(self, file): + def _init_virtual_io(self, file): @_ffi.callback("sf_vio_get_filelen") def vio_get_filelen(user_data): # first try __len__(), if not available fall back to seek()/tell() @@ -432,13 +432,13 @@ def vio_tell(user_data): return file.tell() # Note: the callback functions must be kept alive! - self._vio = {'get_filelen': vio_get_filelen, - 'seek': vio_seek, - 'read': vio_read, - 'write': vio_write, - 'tell': vio_tell} + self._virtual_io = {'get_filelen': vio_get_filelen, + 'seek': vio_seek, + 'read': vio_read, + 'write': vio_write, + 'tell': vio_tell} - return _ffi.new("SF_VIRTUAL_IO*", self._vio) + return _ffi.new("SF_VIRTUAL_IO*", self._virtual_io) def __del__(self): self.close()