.. _a-quick-tour: A Quick Tour ************ This tour takes just a few minutes to cover the full cycle of application persistence - from application data object to file storage and back to the application. Object Declaration ================== The first step is to declare a collection of values that will be stored and then recovered at some later point. A simple example appears below: .. literalinclude:: class-and-store/received_job_basic.py The ``ReceivedJob`` class inherits from the :py:class:`~ansar.message.Message` base class, all class members are given default values using named arguments and lastly, the class is registered using the :py:class:`~ansar.bind.bind` function. After default creation - ``j = ReceivedJob()`` - all members of ``j`` contain valid data. The library relies on this behaviour during recovery of data and also at registration time, to determine the data types of individual members. .. note:: Classes can be declared with much more than a few ``int`` and ``str`` members. Refer to :ref:`more-about-types` for an introduction into the deeper topic of `types`. Write An Object To A File ========================= Writing an object into file storage is most conveniently carried out using the :py:class:`~ansar.file.File` class: .. code-block:: python f = ar.File('job', ReceivedJob) j = ReceivedJob() f.store(j) The call to :py:meth:`~ansar.file.File.store` creates or overwrites the ``job.json`` file in the current folder. The contents of the file look like this: .. literalinclude:: class-and-store/received_job_basic.json The file contains an instance of a JSON object. The values for the ``ReceivedJob`` appear as the member ``value``. .. note:: The ``ReceivedJob`` class being passed to the :py:class:`~ansar.file.File` object is an example of a `type expression`. Refer to :ref:`Type Expressions` for the full scope of what that parameter can be. XML is supported as an alternative encoding. The major motivation for providing this alternative is for those projects with significant commitment to XML in their literature and tooling. There may also be relevant external requirements. Adopting XML for storing and recovering of jobs requires a single additional parameter:: f = ar.File('job', ReceivedJob, encoding=ar.CodecXml) j = ReceivedJob() f.store(j) The contents of the new file look like: .. literalinclude:: class-and-store/received_job_basic.xml Use of the XML encoding comes at the cost of increased consumption of resources. XML can consume 2-4 times as much file space as JSON and the increase in consumption of CPU cycles is typically worse. For these reasons the JSON encoding is defined as the default. .. warning:: The XML encoding does not deliver the same capabilities as the JSON encoding, specifically in the area of representation of non-printing values within ``byte`` values. Look :ref:`here` for details. .. note:: By default the :py:meth:`~ansar.file.File.store` method - and its sibling :py:meth:`~ansar.file.File.recover` - auto-append an extension to the supplied file name. This behaviour is consistent throughout the library and especially significant when dealing with collections of files inside folders. The behaviour can be disabled using ``decorate_names=False`` which passes complete responsibility for file names back to the caller. Reading An Object From A File ============================= Reading an object from file storage is also carried out using the :py:class:`~ansar.file.File` class. In fact, we can re-use the same instance from the previous sample: .. code-block:: python j, _ = f.recover() This results in assignment of a fully formed instance of the ``ReceivedJob`` class, to the ``j`` variable. Details like the filename and expected object type were retained in the ``f`` variable and re-applied here. The :py:meth:`~ansar.file.File.recover` method specifically returns a 2-tuple. The first element is the recovered instance and the second element (i.e. the underscore) is a `version tag`. Use of the underscore above obviously discards whatever that version information might have been. This is fine in prototyping code and is also fine in the first version of any software - everything initially defaults to a "no-op" or "nothing to see here". .. note:: Support for version handling is hard-wired into the library. An entire section is devoted to the proper use of the version information (:ref:`versions-upgrading-and-migration`) returned by the :py:meth:`~ansar.file.File.recover` method. For the moment it is enough to know that nothing in the above code fragments is "wrong" or destined to be discarded when the "proper" code is written. A Few Details ============= The operational behaviour of the :py:class:`~ansar.file.File` class can be influenced by passing additional named parameters. The full set of parameters are: - `name` - `te` - `encoding` - `create_default` - `pretty_format` - `decorate_names` The first two are required and often all that is needed - the remainder have default values satisfying most expectations. The `create_default` parameter affects the behaviour of the :py:meth:`~ansar.file.File.recover` method, where a named file does not exist. If set to ``True`` the method will return a default instance of the expected type, rather than raising an exception. By default, file contents are "pretty-printed" for readability and to assist direct editing. Efficiency can be improved by setting this parameter to ``False``. Lastly, setting the ``decorate_names`` parameter to ``False`` disables the auto-append of an encoding-dependent file extension, e.g. ``.xml``. Summary ======= That is a complete introduction into how the library should be used to implement application persistence. The signficant steps were: * registration, * storing * and recovering. From a developer's point of view this represents a low intellectual overhead. It also quietly delivers: * type sophistication, * reading of fully-formed application types * and production-ready version support.