Skip to content

Commit

Permalink
Fix detection of file extension for bytes (in Py3k)
Browse files Browse the repository at this point in the history
... and disallow bytes for mode/format/subtype/endian.

Regarding mode, this is the same behavior as in the built-in open() function.
  • Loading branch information
mgeier committed Mar 29, 2015
1 parent 7405827 commit 0ac4082
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 24 deletions.
50 changes: 29 additions & 21 deletions soundfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
from cffi import FFI as _FFI
from os import SEEK_SET, SEEK_CUR, SEEK_END

try:
_unicode = unicode # doesn't exist in Python 3.x
except NameError:
_unicode = str

_ffi = _FFI()
_ffi.cdef("""
enum
Expand Down Expand Up @@ -624,14 +629,9 @@ def __init__(self, file, mode='r', samplerate=None, channels=None,
>>> assert myfile.closed
"""
try:
_unicode = unicode # doesn't exist in Python 3.x
except NameError:
_unicode = str

if mode is None:
mode = getattr(file, 'mode', None)
if not isinstance(mode, (_unicode, bytes)):
if not isinstance(mode, (_unicode, str)):
raise TypeError("Invalid mode: {0!r}".format(mode))
modes = set(mode)
if modes.difference('xrwb+') or len(mode) > len(modes):
Expand All @@ -649,23 +649,23 @@ def __init__(self, file, mode='r', samplerate=None, channels=None,

old_fmt = format
if format is None:
format = ''
try:
extension = _os.path.splitext(getattr(file, 'name', file))[-1]
format = extension.lstrip('.').upper()
filename = getattr(file, 'name', file)
format = _os.path.splitext(filename)[-1][1:]
format = format.decode() # raises on Python 3 str
except Exception:
pass
if format not in _formats and 'r' not in modes:
if format.upper() not in _formats and 'r' not in modes:
raise TypeError(
"No format specified and unable to get format from "
"file extension: {0!r}".format(file))
else:
try:
format = format.upper()
except AttributeError:
pass
if not isinstance(format, (_unicode, str)):
raise TypeError("Invalid format: {0!r}".format(format))

self._info = _ffi.new("SF_INFO*")
if 'r' not in modes or format == 'RAW':
if 'r' not in modes or format.upper() == 'RAW':
if samplerate is None:
raise TypeError("samplerate must be specified")
self._info.samplerate = samplerate
Expand Down Expand Up @@ -1234,23 +1234,31 @@ def _prepare_read(self, start, stop, frames):

def _format_int(format, subtype, endian):
"""Return numeric ID for given format|subtype|endian combo."""
if not isinstance(format, (_unicode, str)):
raise TypeError("Invalid format: {0!r}".format(format))
try:
result = _formats[format.upper()]
except (AttributeError, KeyError):
raise ValueError("Invalid format string: {0!r}".format(format))
except KeyError:
raise ValueError("Unknown format: {0!r}".format(format))
if subtype is None:
subtype = default_subtype(format)
if subtype is None:
raise TypeError(
"No default subtype for major format {0!r}".format(format))
elif not isinstance(subtype, (_unicode, str)):
raise TypeError("Invalid subtype: {0!r}".format(subtype))
try:
result |= _subtypes[subtype.upper()]
except (AttributeError, KeyError):
raise ValueError("Invalid subtype string: {0!r}".format(subtype))
except KeyError:
raise ValueError("Unknown subtype: {0!r}".format(subtype))
if endian is None:
endian = 'FILE'
elif not isinstance(endian, (_unicode, str)):
raise TypeError("Invalid endian-ness: {0!r}".format(endian))
try:
result |= _endians[endian.upper() if endian is not None else 'FILE']
except (AttributeError, KeyError):
raise ValueError("Invalid endian-ness: {0!r}".format(endian))
result |= _endians[endian.upper()]
except KeyError:
raise ValueError("Unknown endian-ness: {0!r}".format(endian))

info = _ffi.new("SF_INFO*")
info.format = result
Expand Down
6 changes: 3 additions & 3 deletions tests/test_pysoundfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,13 +363,13 @@ def test_open_with_more_invalid_arguments():
assert "integer" in str(excinfo.value)
with pytest.raises(ValueError) as excinfo:
sf.SoundFile(filename_new, 'w', 44100, 2, format='WAF')
assert "Invalid format string" in str(excinfo.value)
assert "Unknown format" in str(excinfo.value)
with pytest.raises(ValueError) as excinfo:
sf.SoundFile(filename_new, 'w', 44100, 2, 'PCM16', format='WAV')
assert "Invalid subtype string" in str(excinfo.value)
assert "Unknown subtype" in str(excinfo.value)
with pytest.raises(ValueError) as excinfo:
sf.SoundFile(filename_new, 'w', 44100, 2, endian='BOTH', format='WAV')
assert "Invalid endian-ness" in str(excinfo.value)
assert "Unknown endian-ness" in str(excinfo.value)


def test_open_r_and_rplus_with_too_many_arguments():
Expand Down

0 comments on commit 0ac4082

Please sign in to comment.