bastibe/PySoundFile — pull request #60 by mgeier (2014-08-06 13:27:06+00:00)
Title: Change open modes to be more in line with Python's open() function

Until very recently I had the opinion that if a feature is available in both libsndfile and plain old Python, we should do it in libsndfile's way.

It seems that my opinion is changing ...

I wanted to fix `SoundFile.__init__()` (see #59) and got the idea that probably the real problem is that libsndfile tries to handle different situations within a single `SFM_RDWR` mode.

One solution to the whole problem would be to use Python's native file modes instead of the ones provided by libsndfile.
Initially, I thought this wouldn't be possible (see commit message of a3295f7fe118c82ed53257625966c07964adab30), but it's actually only impossible if read-write mode has to be one single mode.

I'm proposing to allow the following modes:

* read-only: `'rb'`, `'r'` (for convenience, we would internally add `'b'` to that because we only ever deal with binary files)
* write-only: `'wb'`, `'w'`, `'xb'` (raises `FileExistsError` to avoid accidental overwriting), `'x'`
* read/write existing: `'r+b'`, `'r+'`
* read/write new: `'w+b'`, `'w+'`, `'x+b'`, `'x+'`

In addition, we could allow `mode=None` where the mode is obtained from the `mode` attribute of the user-provided file-like object.

All other Python file modes should be disallowed, especially `'a'` (because I think it wouldn't play nicely with libsndfile) and `'t'`.
Our current `'rw'` mode should also be disallowed.

In the documentation, we could state that "`'b'` is always implied" and use the variants without `'b'` for simplicity.
However, this would be a difference to Python, where `'t'` is implied.
The default could be `mode='r'`, as before.

All this would have the additional advantage that `'x'` mode would be possible, making sure that no files are accidentally overwritten.

In order to implement this, we would have to use Python's `open()` function and then pass the opened file to libsndfile.
This could be done either as file object or as file descriptor.
I guess libsndfile does its own buffering (?), therefore it would make sense to use `open(..., buffering=0)`.
I guess the "virtual I/O" callback functions are a little less efficient, so it may be better to get the file descriptor with `fileno()` and pass this to libsndfile.

In order to be consistent with Python's `open()`, we should also make sure that the read and write positions are modified accordingly after opening.
For the same reason, we should probably also drop the `which` argument from `seek()`, as already suggested by @bastibe (~~I don't remember where exactly~~ *update:* https://github.com/bastibe/PySoundFile/pull/35#issuecomment-49274456).
It would also finally make sense to add a `tell()` method (see #44).