**README** for PLIB Version 0.6.1

:Author:        Peter A. Donis
:Release Date:  14 December 2009

The PLIB package contains a number of useful sub-packages and
modules, all within the ``plib`` package namespace in order to
minimize clutter in the top-level namespace of your Python
installation. Each sub-directory of the ``plib`` directory
contains a sub-package, except for the ``test`` directory, which
contains the PLIB test suite. The source distribution also
contains an ``examples`` directory, which has example programs
using PLIB, and a ``scripts`` directory, which has a few
post-install scripts. (The ``SetupHelper`` directory in the
source distribution is not installed; it contains a helper
module for PLIB's setup script. SetupHelper is available as
a separate package from PyPI under the name ``setuphelper``.)

The PLIB Sub-Packages
=====================

The individual sub-packages and modules contain docstrings
with more information about their usage; here they are
briefly listed and described.

PLIB.CLASSES
------------

Each of the modules in this sub-package contains a single
class with the same name; the ``ModuleProxy`` class from
the ``PLIB.UTILS`` sub-package is used to make all the classes
appear in the ``plib.classes`` namespace. See the sub-package
and ``ModuleProxy`` docstrings for more information.

The classes in this sub-package are mostly a miscellaneous
group, included for no other reason than that I have found
them useful. The only common theme shared by some of them is
implementation of common "policy" for I/O clients and servers,
on top of the basic mechanisms provided by the I/O channel
classes in ``plib.stdlib``.

PLIB.EXTENSIONS
---------------

This sub-package provides a namespace for functions (and
possibly, in the future, other objects) exported from an
extension module written using the Python/C API. The general
philosophy of PLIB is to do everything possible in pure
Python, so the only functions that appear in this sub-package
are those which by their very nature cannot be done in pure
Python.

PLIB.GUI
--------

This is the largest sub-package, and contains a simple GUI
application framework with two main features:

- It lets the same high-level code work with a number of
  different underlying GUI toolkits. Currently supported:
  Qt (versions 3 and 4), KDE (versions 3 and 4), wxWidgets,
  and GTK. (The original reason for writing this sub-package
  was that wxWidgets doesn't use Qt and I like the Qt/KDE
  widgets better, but I wanted code that would run
  cross-platform.)

- It allows you to express the layout of your GUI in terms
  of Python lists and dicts, enabling a much more declarative
  and easy to read (and maintain) coding style.

Other than selecting the toolkit (which may not be necessary:
the main module of the sub-package can 'auto-detect' which
toolkit to use--the ``plib-setup-gui`` post-install script
does most of the work to enable this--so you only need to
override if you don't like the default), you should not have
to worry about any toolkit internal details; the goal of this
sub-package is to make them all look the same to your code.

Note that the GTK toolkit support in this sub-package is
"experimental" and may be removed if it proves to be more
trouble than it's worth. It's currently included because
wxWidgets' behavior when using GTK as its underlying GUI
framework has some quirks that I haven't been able to work
around yet. However, the GTK implementation of a number of
widgets (particularly tables and list/tree views) is much
less capable than the wxWidgets one, so the Python code for
GTK ends up relying much more on ugly hacks.

PLIB.INI
--------

This sub-package implements an abstract 'INI file' API that
uses ``ConfigParser`` on POSIX systems, and the Windows registry
on Windows systems. As with the ``PLIB.GUI`` sub-package, the
goal is to hide the internal details of the configuration
storage from your code, so all you have to do is define
your configuration structure, again using native Python data
types (lists and dicts).

PLIB.STDLIB
-----------

This is a namespace for various functions and classes that
extend or emulate the Python standard library. Some,
like the ``cached_property`` decorator, are implementations of
patterns that have been known for some time, but which don't
have a "canonical" version in the stdlib yet; rather than
have PLIB depend on some other third-party package, I've
simply provided my own implementations here. Others, like
the ``abstractcontainer`` class and its subclasses, are
re-implementations of standard Python data structures,
written to enable PLIB to make as many things as possible
look like those data structures without having to subclass
the built-ins (which has some downsides for the use cases
I've had thus far--see the docstrings for more information).

There are also two modules in this sub-package namespace:

- The ``coll`` module provides two slightly customized collection
  classes, ``fifo`` and ``stack``, with a common API.

- The ``options`` module provides an easier-to-use overlay for
  the ``optparse`` module which allows you to express your option
  configuration in the form of Python lists, tuples, and dicts,
  and also adds some minimal argument checking functionality.

PLIB.STDLIB.IO
--------------

This sub-package contains classes that encapsulate various forms
of client/server I/O channels. It is organized into sub-packages
itself to make the namespace easier to use; the sub-packages fall
into three categories, and each sub-package in a given category
contains the same basic class names, so they're easier to remember.
The categories are:

- **Device Types**: ``socket`` and ``serial``. Each device type has
  a ``BaseClient`` and ``BaseServer`` class; the ``socket`` type
  also has a ``BaseRequest`` class. These will usually not need to
  be used directly; they are used by the I/O mode classes, and are
  factored out so that each I/O mode sees the same API for a given
  device type.

- **I/O modes**: ``async`` and ``blocking`` (the latter does not just
  mean synchronous: it includes a forking TCP socket server). Each
  I/O mode has a client and server class for both device types, and
  a request class for the ``socket`` device type: the class names are
  ``SerialClient``, ``SerialServer``, ``SocketClient``, ``SocketServer``,
  and ``BaseRequestHandler``. The ``async`` type also has "persistent"
  classes, which support full-duplex asynchronous communication; these
  are the ``PersistentSerial``, ``PersistentSocket``, and
  ``PersistentRequestHandler`` classes. Mixin versions of these classes
  (class names with ``Mixin`` at the end) are also provided, for use
  if alternate data handling is desired (see next bullet), but it is
  normally not necessary to use these "by hand"--see "automatic mixins"
  below.

- **Data Handling**: the I/O mode classes given above include basic
  data handling, but it is *very* basic: the only way it can detect
  that a "message" has been fully received is to detect a closed
  channel. For some applications this is enough, but often more
  sophisticated and robust data handling is needed. This sub-package
  provides two mixin classes, ``TerminatorReadWrite`` and ``ReadWrite``,
  to allow the detection of multiple "messages" in the data stream,
  either by detecting a "terminator" string or by having each message
  include its length at the beginning.

*Automatic Mixins*: To derive your own client or server classes with
alternate data handling "by hand", you would need to use the "mixin"
versions of the appropriate I/O mode classes, and splice the data
handling class into the middle of the base class list; for example::

    from plib.stdlib.io.async import SerialClientMixin, SerialBase
    from plib.stdlib.io.data import TerminatorReadWrite
    
    class AsyncSerialClientWithTerminator(SerialClientMixin,
        TerminatorReadWrite, SerialBase): pass

This is clumsy, but necessary since the read/write handling has to be
*before* the client/server class in the MRO, but *after* the base
device type, for the cooperative ``super`` calls that underlie the
functionality to work properly. However, since the pattern is the
same in each case, it can be automated, and this has been done in the
``async`` and ``blocking`` sub-package namespaces, so that instead of
doing the above class construction "by hand", you can just append a
suffix to your desired class name, thus::

    from plib.stdlib.io.async import SerialClientWithTerminator

The ``WithTerminator`` suffix (or, alternately, ``WithShutdown``
or ``WithReadWrite``) will cause the equivalent of the above class
definition to occur on the fly, so that the resulting class appears
in the ``plib.stdlib.io.async`` namespace (of course the
``plib.stdlib.io.blocking`` namespace has the same capability).
Once this has happened the first time, however, the class definition
is stored in the appropriate namespace, so additional imports of the
same class name (in different modules of your application) will not
re-do the "on the fly" construction; they will just retrieve the
same class object that was previously constructed.

The above machinery is also made available for use with your own custom
read/write handling classes; the ``async`` and ``blocking`` sub-packages
each export a ``get_readwrite_class`` function that does the same
on-the-fly class definition as above, but with your custom read/write
class instead of one of the built-in ones. All you have to do is pass
the function the name of your desired I/O class and your custom
read/write class object::

    from plib.stdlib.io import async
    
    class CustomReadWrite(object):
        # class definition
    
    MyAsyncSerialClient = async.get_readwrite_class('SerialClient',
        CustomReadWrite)

*API Notes*: One of the goals of this sub-package is to provide a
common, consistent API for all the different types of I/O, so that
switching one specific implementation of a certain functionality
for another can be done transparently to the rest of your application's
code. Thus, all of the usable classes follow the same basic pattern of
mixing in the various pieces of functionality: from left to right
in a class's MRO, one finds the type of endpoint (a client or
server mixin class, which may be specialized to the type of I/O),
the type of data formatting, if any (a mixin class from the
``ReadWrite`` module), and the type of I/O, including device type
(socket, serial port, etc.), mode (non-blocking/asynchronous vs.
blocking), and basic data handling. Also, each endpoint type has
a common API independent of the specific type of I/O and mode; a
client can always use the ``client_communicate`` method to send
data to the server and receive a response; a server can always use
the ``serve_forever`` method to start itself; and all I/O objects
override the same methods to implement application-specific
functionality: ``process_data``, to deal with data as it comes in,
and ``query_done``, to determine when the I/O channel should be
closed. (To see examples of all this in action, look at the test
suite in ``test_stdlib_io.py`` and the library module for it,
``stdlib_io_testlib.py``; the library module can use the same
mixin classes to implement test functionality for *all* of the
different mixes of I/O classes in the test suite.)

PLIB.UTILS
----------

This sub-package contains some miscellaneous useful
functions and modules, and also the ``ModuleProxy`` class
referred to above.

PLIB.XML
--------

This sub-package requires the ``lxml`` extension, which uses
the very fast ``libxml2`` library but provides a Pythonic API
similar to ElementTree. The reason for using ``lxml`` instead
of ElementTree itself is that ``lxml`` has two key additional
features:

- Custom element classes: the ``classes`` module in this
  sub-package builds on this feature by using metaclasses
  to automate DTD generation and validation, but the
  feature is also great for many XML applications.

- Full and *fast* XPATH support: this was key in the XML
  application that first prompted me to write this sub-package.
  Yes, I know there are plenty of other Python XML packages
  that do XPATH; the point is to have it *plus* the standard
  ElementTree API *plus* the speed of ``libxml2``.

Installation
============

To install PLIB, you can simply run::

    $ python setup.py install

at a shell prompt from the directory into which you
unzipped the source tarball (the same directory that this
README file is in). This will install PLIB and then
run each of the post-install scripts in the scripts
directory.

Example Programs
================

PLIB comes with example programs that illustrate key features
of the package. After installation, these can be found in the
``$PREFIX/share/plib/examples`` directory. If you have a
POSIX system (Linux or Mac OSX), the ``plib-setup-examples``
post-install script will install symlinks to the example
programs in the ``$PREFIX/bin`` directory.

The Zen of PLIB
===============

There is no single unifying purpose or theme to PLIB, but
like Python itself, it does have a 'Zen' of sorts:

- Express everything possible in terms of built-in Python
  data structures.

- Once you've expressed it that way, what the code is
  going to do with it should be obvious.

- Avoid boilerplate code, *and* boilerplate data. Every
  piece of data your program needs should have one and
  only one source.

Copyright and License
=====================

PLIB is Copyright (C) 2008-2009 by Peter A. Donis.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. (See the LICENSE file for a
copy of version 2 of the License.)

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
