:mod:`dip.io`
=============
.. module:: dip.io

The :mod:`dip.io` module implements the infrastructure for defining and
interfacing with :term:`storage`.

Plugins must provide appropriate support for the following extension points:

``dip.io.codecs``
    This must be supported by any plugin that configures an object implementing
    the :class:`dip.io.IIoManager` interface.  A contribution must implement
    the :class:`dip.io.ICodec` interface.

``dip.io.storage_factories``
    This must be supported by any plugin that configures an object implementing
    the :class:`dip.io.IIoManager` interface.  A contribution must implement
    the :class:`dip.io.IStorageFactory` interface.

``dip.io.storage_policies``
    This must be supported by any plugin that configures an object implementing
    the :class:`dip.io.IIoManager` interface.  A contribution must be a
    callable.


:class:`BaseStorage`
--------------------
.. class:: BaseStorage

    Base class: :class:`~dip.model.Model`

    The BaseStorage storage class is an optional base class for
    implementations of :class:`~dip.io.IStorage`.

    .. method:: BaseStorage.decoder_for_model(model, location)

        Returns one of the storage's codecs that can be used to decode a
        model.  An exception is raised if there is no suitable codec.
        
        :param model:
            is the model.
        :param location:
            is the location.  This is only used in exceptions.
        :return:
            the codec.

    .. method:: BaseStorage.encoder_for_model(model, location)

        Returns one of the storage's codecs that can be used to encode a
        model.  An exception is raised if there is no suitable codec.
        
        :param model:
            is the model.
        :param location:
            is the location.  This is only used in exceptions.
        :return:
            the codec.


:exc:`FormatError`
------------------
.. exception:: FormatError

    Base exception: :class:`~dip.io.StorageError`

    The FormatError class is an exception raised when there is an error
    decoding or encoding an object at a particular storage location.


:class:`ICodec`
---------------
.. class:: ICodec

    Base class: :class:`~dip.model.Interface`

    The ICodec interface defines the API of codecs. 

    .. attribute:: decoder_interface = Subclass(Interface)

        The interface that a model must implement.  It is ``None`` if there is no
        decoder.

    .. attribute:: encoder_interface = Subclass(Interface)

        The interface that a model must implement.  It is ``None`` if there is no
        encoder.

    .. attribute:: format = Str()

        The identifier of the format.

    .. method:: ICodec.decode(model, source, location)

        A model is decoded from a byte stream.
        
        :param model:
            is the model.
        :param source:
            is an iterator that will return the byte stream to be decoded.
        :param location:
            is the storage location where the encoded model is being read from.
            It is mainly used for error reporting.
        :return:
            the decoded model.  This may be the original model populated from
            the storage location, or it may be a different model (of an
            appropriate type) created from the storage location.  If ``None``
            is returned then it is assumed that the decoding was abandoned and
            the user informed appropriately.

    .. method:: ICodec.encode(model, location)

        A model is encoded as a byte stream.
        
        :param model:
            is the model.
        :param location:
            is the storage location where the encoded model will be written to.
            It is mainly used for error reporting.
        :return:
            a generator that will return sections of the encoded byte stream.


:class:`IFilterHints`
---------------------
.. class:: IFilterHints

    Base class: :class:`~dip.model.Interface`

    The IFilterHints interface defines hints provided by a model to storage
    regarding filters, typically used to select files with particular extension
    names.

    .. attribute:: filter = Str()

        The filter string in the format used by
        :class:`~PyQt4.QtGui.QFileDialog`.


:class:`IIoManager`
-------------------
.. class:: IIoManager

    Base class: :class:`~dip.model.Interface`

    The IIoManager interface defines the API of an i/o manager. 

    .. attribute:: codecs = List(ICodec)

        The available codecs.

    .. attribute:: storage_factories = List(IStorageFactory)

        The available storage factories.

    .. attribute:: storage_policies = List(Callable())

        The storage policies that determines if a format is allowed to be written
        to or read from storage represented by a particular implementation of
        :class:`~dip.io.IStorage`.  Each policy is called with the format
        identifier and the storage as arguments.  A policy should return ``True``
        if the access is allowed.  All policies must return ``True`` for the
        access to proceed.

    .. attribute:: ui = Instance(IIoManagerUi)

        The storage-independent user interfaces.

    .. method:: IIoManager.read(model, location, format)

        Read a model from a location using a particular format.
        
        :param model:
            is the model.
        :param location:
            is the location as a string.  This should identify a valid and
            unambiguous storage location.
        :param format:
            is the format.
        :return:
            the read model.  This may be the original model populated from the
            storage location, or it may be a different model (of an appropriate
            type) created from the storage location.  If ``None`` is returned
            then it is assumed that the read was abandoned and the user
            informed appropriately.

    .. method:: IIoManager.readable_locations_from_string(location, format='')

        Get the list of readable storage location instances for which a
        location specified as a string is valid.
        
        :param location:
            is the location as a string.
        :param format:
            is the identifier of the optional format.
        :return:
            the list of storage location instances.

    .. method:: IIoManager.readable_storage(format='')

        Get the list of the storage instances that can be read from using a
        particular format.
        
        :param format:
            is the identifier of the optional format.
        :return:
            the list of storage instances.

    .. method:: IIoManager.write(model, location, format)

        Write a model to a location using a particular format.
        
        :param model:
            is the model.
        :param location:
            is the location as a string.  This should identify a valid and
            unambiguous storage location.
        :param format:
            is the format.

    .. method:: IIoManager.writeable_locations_from_string(location, format='')

        Get the list of writeable storage location instances for which a
        location specified as a string is valid.
        
        :param location:
            is the location as a string.
        :param format:
            is the identifier of the optional format.
        :return:
            the list of storage location instances.

    .. method:: IIoManager.writeable_storage(format='')

        Get the list of the storage instances that can be written to using
        a particular format.
        
        :param format:
            is the identifier of the optional format.
        :return:
            the list of storage instances.


:class:`IIoManagerUi`
---------------------
.. class:: IIoManagerUi

    Base class: :class:`~dip.model.Interface`

    The IIoManagerUi interface defines the API that implements the various
    storage-independent user interfaces.

    .. attribute:: choose_storage_title = Str()

        The text of the title used in the wizard pages asking the user to choose
        a storage location.

    .. attribute:: choose_readable_location_subtitle = Str()

        The text of the sub-title used in the wizard page asking the user to
        choose a readable storage location.

    .. attribute:: choose_readable_storage_subtitle = Str()

        The text of the sub-title used in the wizard page asking the user to
        choose some readable storage.

    .. attribute:: choose_storage_title = Str()

        The text of the title used in the wizard pages asking the user to choose
        some storage.

    .. attribute:: choose_readable_location_subtitle = Str()

        The text of the sub-title used in the wizard page asking the user to
        choose a writeable storage location.

    .. attribute:: choose_writeable_storage_subtitle = Str()

        The text of the sub-title used in the wizard page asking the user to
        choose some writeable storage.

    .. attribute:: io_manager = Instance(.IIoManager)

        The i/o manager that this is the user interface for.

    .. method:: IIoManagerUi.readable_location_wizard_page(id='')

        Create a wizard page factory for asking the user to provide a
        readable storage location.
        
        :param id:
            is the optional identifier of the page.
        :return:
            the wizard page factory.  The page's view will be an implementation
            of :class:`~dip.ui.IViewStack`.

    .. method:: IIoManagerUi.readable_storage_location(window_title, default_location=None, format='', hints=None, parent=None)

        Ask the user to provide a readable storage location.
        
        :param window_title:
            is the window title to use in any wizards and dialogs.
        :param storage_list:
            is the storage from which the use may choose.  If it is not
            specified then a list of all available readable storage is used.
        :param default_location:
            is the optional default location.
        :param format:
            is the identifier of the optional format.
        :param hints:
            is an optional source of hints.
        :param parent:
            is the optional parent view.
        :return:
            the storage location or ``None`` if the user declined to provide
            one.

    .. method:: IIoManagerUi.readable_storage_wizard_page(bind_to, storage_list=None, id='')

        Create a wizard page factory for asking the user to select from a
        list of readable storage.
        
        :param bind_to:
            is the attribute of the model containing the selected storage.
        :param storage_list:
            is the optional list of available readable storage.
        :param id:
            is the optional identifier of the page.
        :return:
            the wizard page factory.

    .. method:: IIoManagerUi.writeable_location_wizard_page(id='')

        Create a wizard page factory for asking the user to provide a
        writeable storage location.
        
        :param id:
            is the optional identifier of the page.
        :return:
            the wizard page factory.  The page's view will be an implementation
            of :class:`~dip.ui.IViewStack`.

    .. method:: IIoManagerUi.writeable_storage_location(window_title, default_location=None, format='', hints=None, parent=None)

        Ask the user to provide a writeable storage location.
        
        :param window_title:
            is the window title to use in any wizards and dialogs.
        :param default_location:
            is the optional default location.
        :param format:
            is the identifier of the optional format.
        :param hints:
            is an optional source of hints.
        :param parent:
            is the optional parent view.
        :return:
            the storage location or ``None`` if the user declined to provide
            one.

    .. method:: IIoManagerUi.writeable_storage_wizard_page(bind_to, storage_list=None, id='')

        Create a wizard page factory for asking the user to select from a
        list of writeable storage.
        
        :param bind_to:
            is the attribute of the model containing the selected storage.
        :param storage_list:
            is the optional list of available writeable storage.
        :param id:
            is the optional identifier of the page.
        :return:
            the wizard page factory.


:class:`IStorage`
-----------------
.. class:: IStorage

    Base class: :class:`~dip.model.Interface`

    The IStorage interface defines the API of a particular type of
    :term:`storage`.

    .. attribute:: codecs = List(ICodec)

        The codecs that can be used.

    .. attribute:: ui = Instance(IStorageUi)

        The storage-specific user interfaces.

    .. method:: IStorage.explicit_location(location)

        If the storage has explicit storage locations (i.e. a location is
        independent on the value of a model) then convert such a location
        specified as a string to an :class:`~dip.io.IStorageLocation`
        instance.
        
        :param location:
            is the location as a string.  It should be valid for the storage.
        :return:
            the :class:`~dip.io.IStorageLocation` instance or ``None`` if the
            storage does not have explicit storage locations.

    .. method:: IStorage.implicit_location(model)

        If the storage has implicit storage locations (i.e. a location is
        dependent on the value of a model) then create such a location for the
        model.
        
        :param model:
            is the model.
        :return:
            the location or ``None`` if the storage does not have implicit
            storage locations.

    .. method:: IStorage.read(model, location)

        Read a model from a storage location.
        
        :param model:
            is the model.
        :param location:
            is the storage location where the model is read from.
        :return:
            the read model.  This may be the original model populated from the
            storage location, or it may be a different model (of an appropriate
            type) created from the storage location.  If ``None`` is returned
            then it is assumed that the read was abandoned and the user
            informed appropriately.

    .. method:: IStorage.readable_location(location)

        Convert a location specified as a string to a readable
        :class:`~dip.io.IStorageLocation` instance if possible.
        
        :param location:
            is the location as a string.
        :return:
            the :class:`~dip.io.IStorageLocation` instance or ``None`` if the
            location was not valid for this storage.

    .. method:: IStorage.write(model, location)

        Write a model to a storage location.
        
        :param model:
            is the model.
        :param location:
            is the storage location where the model is written to.

    .. method:: IStorage.writeable_location(location)

        Convert a location specified as a string to a writeable
        :class:`~dip.io.IStorageLocation` instance if possible.
        
        :param location:
            is the location as a string.
        :return:
            the :class:`~dip.io.IStorageLocation` instance or ``None`` if the
            location was not valid for this storage.


:class:`IStorageBrowser`
------------------------
.. class:: IStorageBrowser

    Base class: :class:`~dip.model.Interface`

    The IStorageBrowser interface defines the API implemented by a view
    that allows the user to browse storage and select a valid
    :term:`storage location`.

    .. attribute:: invalid_reason = Str()

        This explains why the storage location is invalid.  It will be an empty
        string if the location is valid.

    .. attribute:: location = Instance(IStorageLocation)

        The storage location that the user uses the view to set.

    .. attribute:: storage = Instance(IStorage)

        The storage.


:class:`IStorageFactory`
------------------------
.. class:: IStorageFactory

    Base class: :class:`~dip.model.Interface`

    The IStorageFactory interface defines the API of a factory for creating
    implementations of :class:`~dip.io.IStorage`.

    .. attribute:: readable = Bool(True)

        This is set if the storage is readable.

    .. attribute:: writeable = Bool(True)

        This is set if the storage is writeable.

    .. method:: IStorageFactory.__call__(codecs)

        Create a storage instance.
        
        :param codecs:
            is the list of codecs that can be used by the storage.
        :return:
            the storage instance.


:class:`IStorageLocation`
-------------------------
.. class:: IStorageLocation

    Base class: :class:`~dip.model.Interface`

    The IStorageLocation interface defines the API of a
    :term:`storage location`.  Once created a storage location object will only
    ever refer to one specific location, i.e. a storage location object is
    never updated to refer to a different location.

    .. attribute:: storage = Instance(IStorage)

        The storage that the location refers to.

    .. method:: IStorageLocation.__str__()

        Return a string representation of the location.  This must be able
        to be parsed by an implementation of
        :meth:`~dip.io.IStorage.valid_location`.
        
        :return:
            the string representation.


:class:`IStorageUi`
-------------------
.. class:: IStorageUi

    Base class: :class:`~dip.model.Interface`

    The IStorageUi interface defines the API that implements the various
    storage specific user interfaces.

    .. attribute:: storage = Instance(.IStorage)

        The storage that this is the user interface for.

    .. method:: IStorageUi.get_read_location(window_title, default_location=None, hints=None, parent=None)

        Get a new location from the user to read from.
        
        :param window_title:
            is the window title, typically used as the title of a dialog.
        :param default_location:
            is an optional default location.
        :param hints:
            is an optional source of hints.
        :param parent:
            is the optional parent view.
        :return:
            the new location or ``None`` if the user cancelled.

    .. method:: IStorageUi.get_write_location(window_title, default_location=None, hints=None, parent=None)

        Get a new location from the user to write to.
        
        :param window_title:
            is the window title, typically used as the title of a dialog.
        :param default_location:
            is an optional default location.
        :param hints:
            is an optional source of hints.
        :param parent:
            is the optional parent view.
        :return:
            the new location or ``None`` if the user cancelled.

    .. method:: IStorageUi.read_browser(default_location=None, hints=None)

        Create a view that allows the user to browse storage and select a
        read location.
        
        :param default_location:
            is an optional default location.
        :param hints:
            is an optional source of hints.
        :return:
            the view which must implement, or can be adapted to,
            :class:`~dip.io.IStorageBrowser`.

    .. method:: IStorageUi.write_browser(default_location=None, hints=None)

        Create a view that allows the user to browse storage and select a
        write location.
        
        :param default_location:
            is an optional default location.
        :param hints:
            is an optional source of hints.
        :return:
            the view which must implement, or can be adapted to,
            :class:`~dip.io.IStorageBrowser`.


:class:`IStreamingStorageFactory`
---------------------------------
.. class:: IStreamingStorageFactory

    Base class: :class:`~dip.io.IStorageFactory`

    The IStreamingStorageFactory interface defines the API of a factory
    that creates an instance of :term:`streaming storage`.


:class:`IStructuredStorageFactory`
----------------------------------
.. class:: IStructuredStorageFactory

    Base classes: :class:`~dip.io.IStorageFactory`, :class:`~dip.io.ICodec`

    The IStructuredStorageFactory interface defines the API of a factory
    that creates an instance of :term:`structured storage`.


:class:`IoManager`
------------------
.. class:: IoManager

    Base class: :class:`~dip.model.Singleton`

    The IoManager class is a singleton that provides access to a default
    :term:`i/o manager`.

    .. attribute:: instance = Instance(IIoManager)

        The i/o manager instance.


:exc:`StorageError`
-------------------
.. exception:: StorageError

    Base exception: :class:`~builtins.Exception`

    The StorageError class is an exception raised when there is an error
    accessing a particular storage location.
