Commit b9f4bd39 authored by Amir MOHAMMADI's avatar Amir MOHAMMADI
Browse files

Merge branch 'iterable' into 'master'

Add dictionary-like operations to the HDF5File class

See merge request !18
parents f55b0af6 2a3529f0
Pipeline #9615 passed with stages
in 8 minutes and 39 seconds
......@@ -6,7 +6,7 @@ import bob.core
import bob.extension
bob.extension.load_bob_library('bob.io.base', __file__)
from ._library import File as File_C, HDF5File as HDF5File_C, extensions
from ._library import File as _File_C, HDF5File as _HDF5File_C, extensions
from . import version
from .version import module as __version__
from .version import api as __api_version__
......@@ -14,8 +14,8 @@ from .version import api as __api_version__
import os
class File(File_C):
__doc__ = File_C.__doc__
class File(_File_C):
__doc__ = _File_C.__doc__
def __enter__(self):
return self
......@@ -24,24 +24,51 @@ class File(File_C):
self.close()
class HDF5File(HDF5File_C):
__doc__ = HDF5File_C.__doc__
class HDF5File(_HDF5File_C):
__doc__ = _HDF5File_C.__doc__
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.close()
return self.close()
def __contains__(self, x):
"""Since .has_key() is deprecated, implement the ``in`` operator to avoid
PEP8 W601.
"""
__doc__ = self.has_key.__doc__
return self.has_key(x)
def __iter__(self):
__doc__ = self.keys.__doc__
return iter(self.keys())
def __getitem__(self, name):
__doc__ = self.get.__doc__
return self.get(name)
def __setitem__(self, name, value):
__doc__ = self.set.__doc__
return self.set(name, value)
def values(self):
'''Yields the datasets contained in the current directory.
Yields
-------
object
The datasets that are being read.
'''
return (self[key] for key in self)
def items(self):
'''Yields the keys and the datasets contained in the current directory.
Yields
-------
tuple
The key and the datasets that are being read in a tuple.
'''
return ((key, self[key]) for key in self)
def _is_string(s):
"""Returns ``True`` if the given object is a string
......
......@@ -477,10 +477,8 @@ def test_copy_constructor():
assert shallow.has_group("/Test")
assert shallow.has_key("/Test/Data")
assert "/Test/Data" in shallow
assert hdf5.filename == shallow.filename
assert hdf5.keys() == shallow.keys()
assert [key for key in hdf5] == shallow.keys()
assert hdf5.cwd == shallow.cwd
assert not deep.has_group("/Test")
......@@ -512,3 +510,23 @@ def test_copy_constructor():
finally:
os.unlink(tmpname)
os.unlink(tmpname2)
def test_python_interfaces():
try:
tmpname = test_utils.temporary_filename()
with HDF5File(tmpname, 'w') as hdf5:
a = numpy.arange(10)
b = a * 2
hdf5['Data'] = a
hdf5.create_group('Group1')
hdf5['Group1/Data'] = b
assert "/Group1/Data" in hdf5
assert [key for key in hdf5] == hdf5.keys()
assert numpy.allclose(hdf5['Data'], hdf5.get('Data'))
assert all(numpy.allclose(c, d) for c, d in zip(hdf5.values(), (a, b)))
for key, value in hdf5.items():
assert numpy.allclose(value, hdf5[key])
finally:
os.unlink(tmpname)
......@@ -157,9 +157,9 @@ is an example:
>>> A = numpy.array(range(4), 'int8').reshape(2,2)
>>> f = bob.io.base.HDF5File('testfile1.hdf5', 'a')
>>> f.set('my_array', A)
>>> del f
>>> f.close()
The result of running ``h5dump`` on the file ``testfile3.hdf5`` should be:
The result of running ``h5dump`` on the file ``testfile1.hdf5`` should be:
.. code-block:: none
......@@ -261,23 +261,49 @@ would return a 1D uint8 array instead of a 2D array.
Pythonic operations on HDF5 files
---------------------------------
You can use some Pythonic opertations on :py:class:`bob.io.base.HDF5File`.
You can iterate over :py:class:`bob.io.base.HDF5File` objects to get an
iterable of keys instead of calling
:py:meth:`bob.io.base.HDF5File.keys`. You can also use the ``in`` keyword
instead of calling :py:meth:`bob.io.base.HDF5File.has_key`. For example:
You can use some Pythonic opertations on :py:class:`bob.io.base.HDF5File`:
* Use the ``with`` statement to open (and automatically close) HDF5 files.
* iterate over :py:class:`bob.io.base.HDF5File` objects to get an
iterable of keys instead of calling :py:meth:`bob.io.base.HDF5File.keys`.
* use the ``in`` keyword instead of calling
:py:meth:`bob.io.base.HDF5File.has_key`.
* use Python's dictionary syntax instead of :py:meth:`bob.io.base.HDF5File.set`
and :py:meth:`bob.io.base.HDF5File.get`.
For example:
.. doctest::
>>> keys = f.keys() # Get a list of keys
>>> keys == [key for key in f] # instead you can also iterate over keys
True
>>> f.has_key('arrayset')
>>> f = bob.io.base.HDF5File('testfile3.hdf5', 'w')
>>> array = numpy.arange(5)
>>> f['my_array'] = array # f.set('my_array', array)
>>> f['my_array'] # f.get('my_array')
array([0, 1, 2, 3, 4])
>>> 'my_array' in f # f.has_key('my_array')
True
>>> 'arrayset' in f # you can use the `in` operator instead of `has_key`
>>> [key for key in f] # f.keys()
['/my_array']
>>> f.create_group('group1')
>>> f.cd('group1')
>>> f['my_array_in_group'] = array
>>> f.cd('/')
>>> # keys(), values(), and items() just like a dictionary
>>> [key for key in f.keys()]
['/my_array', '/group1/my_array_in_group']
>>> [value for value in f.values()]
[array([0, 1, 2, 3, 4]), array([0, 1, 2, 3, 4])]
>>> [(key, value) for key, value in f.items()]
[('/my_array', array([0, 1, 2, 3, 4])), ('/group1/my_array_in_group', array([0, 1, 2, 3, 4]))]
>>> f.close()
>>> # using a with statement to open and close files
>>> with bob.io.base.HDF5File('testfile3.hdf5', 'a') as f:
... f['second_array'] = array
>>> f = bob.io.base.HDF5File('testfile3.hdf5', 'r')
>>> 'second_array' in f
True
Array interfaces
----------------
......@@ -356,35 +382,6 @@ the :py:class:`bob.io.base.File` container:
the read and write operations. Have a look at the manual section for
:py:mod:`bob.io.base` for more details and other shortcuts available.
.. _audiosignal:
Loading and saving audio files
------------------------------
|project| does not yet support audio files (no wav codec). However, it is
possible to use the `SciPy`_ module :py:mod:`scipy.io.wavfile` to do the job.
For instance, to read a wave file, just use the
:py:func:`scipy.io.wavfile.read` function.
.. code-block:: python
>>> import scipy.io.wavfile
>>> filename = '/home/user/sample.wav'
>>> samplerate, data = scipy.io.wavfile.read(filename)
>>> print(type(data))
<... 'numpy.ndarray'>
>>> print(data.shape)
(132474, 2)
In the above example, the stereo audio signal is represented as a 2D `NumPy`
:py:class:`numpy.ndarray`. The first dimension corresponds to the time index
(132474 frames) and the second dimesnion correpsonds to one of the audio
channel (2 channels, stereo). The values in the array correpsond to the wave
magnitudes.
To save a `NumPy` :py:class:`numpy.ndarray` into a wave file, the
:py:func:`scipy.io.wavfile.write` could be used, which also requires the
framerate to be specified.
.. Place here your external references
.. include:: links.rst
......
......@@ -49,5 +49,4 @@ Details
.. automodule:: bob.io.base
:inherited-members:
.. automodule:: bob.io.base.test_utils
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment