Metadata-Version: 1.0
Name: mr.bent
Version: 1.0a1
Summary: Mr. Bent knows his numbers.
Home-page: http://dev.plone.org/collective/browser/mr.bent
Author: Plone Foundation
Author-email: plone-developers@lists.sourceforge.net
License: BSD
Download-URL: http://cheeseshop.python.org/pypi/mr.bent/
Description: 
        
        *A fussy little man in impeccable black jacket and pinstripe trousers.*
        
        Introduction
        ------------
        
        Mr Bent is a framework for allowing profile data to be collected in a Python
        application and viewed at different logical levels. The three concepts
        involved are a *plugin*, a piece of code that profiles an application, a
        *context*, a logical block of code for which you want reporting data, and a
        *filter*, a way of getting fine-grained information on where the results for a
        context came from.
        
        Plugins
        -------
        
        Plugins are callables that are given to the '''mkwrapper''' function which
        applies it to a function in your application.
        
        This looks like::
        
        mr.bent.wrapper.mkwrapper(foo.bar, plugincallable, "myplugin")
        
        Which will cause '''plugincallable''' to be called on every invocation of
        '''foo.bar''' and add the results of the plugin to the current context as
        '''myplugin'''.
        
        Plugins can return either a number or an iterable. If it returns an iterable
        it must contain **either** strings or numbers. The case of returning a number
        is considered equivalent to returning an iterable of length 1 of numbers.
        
        Contexts
        --------
        
        A context stores data generated by plugins. At any point a new context can be
        started which will be a "sub-context" of the currently active context. If
        there is no currently active context a new top-level one will be created.
        
        Contexts are named with the dotted name of the function that they are created
        around, and return their data to a callback.
        
        This looks like::
        
        def mycallback(context, result, stats):
        return "%s <!-- %s -->" % (result, `stats`)
        
        mr.bent.wrapper.mkcontext(bar.foo, mycallback)
        
        This example would cause invocations of bar.foo, a function that returns XML,
        to return the XML with a repr of the context dict in a following comment.
        
        When a context ends it returns a mapping of the data it collected. As contexts
        are nested each time parent contexts include the data of their sub-contexts.
        Hence, the top level context returns the overall profiling; there is no need
        to manually aggregate data.
        
        Filters
        -------
        
        A filter is, like most things in Mr. Bent, a wrapper around a function. This
        will default to the dotted name of the callable, but an alternative,
        application specific name can be used instead. This is especially useful for a
        function that is used to render multiple different logical blocks of content.
        
        This looks like::
        
        mr.bent.wrapper.mkfilter(take.me.to.the.foo.bar)
        
        Concrete example
        ----------------
        
        In this example we have an application that renders a page of HTML including
        fragments that are logically different files which are then included into the
        main page.
        
        Example 1::
        
        .-------------.
        |  Top level  |
        `-------------'
        |
        |         .--------------------.
        |---------|  Left hand column  |
        |         `--------------------'
        |                   |
        |                   |              .-------------.
        |                   |--------------|  Login box  |
        |                   |              `-------------'
        |                   |
        |                   |
        |                   |              .------------------.
        |                   `--------------|  Navigation box  |
        |                                  `------------------'
        |
        |         .-----------------.
        |---------|  Content block  |
        |         `-----------------'
        |
        |
        |         .---------------------.
        `---------|  Right hand column  |
        `---------------------'
        |
        |              .----------------.
        `--------------|  Calendar box  |
        `----------------'
        
        In this system we have the following notional plugins (with short names for
        brevity):
        
        :t:
        **A timing plugin**  This plugin returns the number of milliseconds
        between it being invoked and it being stopped
        
        :d:
        **A database access counting plugin** This plugin returns how many times
        data was retrieved from a database.
        
        The return values may look something like this::
        
        {'t': [5, 15, 85, 25], 'd': [0, 1, 2, 8]}
        .-------------.
        |  Top level  |
        `-------------'
        |         {'t': [5, 15], 'd': [0,1]}
        |         .--------------------.
        |---------|  Left hand column  |
        |         `--------------------'
        |                   |              {'t': [5], 'd': [0]}
        |                   |              .-------------.
        |                   |--------------|  Login box  |
        |                   |              `-------------'
        |                   |
        |                   |              {'t': [15], 'd': [1]}
        |                   |              .------------------.
        |                   `--------------|  Navigation box  |
        |                                  `------------------'
        |         {'t': [85], 'd': [2]}
        |         .-----------------.
        |---------|  Content block  |
        |         `-----------------'
        |
        |         {'t': [25], 'd': [8]}
        |         .---------------------.
        `---------|  Right hand column  |
        `---------------------'
        |              {'t': [25], 'd': [8]}
        |              .----------------.
        `--------------|  Calendar box  |
        `----------------'
        
        
        Hence, the user has data at each level he has defined which he can then
        process as he likes.
        
        Lets see that again as a doctest (sorry Florian!)::
        
        >>> from mr.bent.mavolio import create, destroy, current
        >>> create("top")           # Create the top level context
        
        
        >>> create("lefthand")      # Create the left hand column
        >>> create("login")         # and the login portlet
        >>> current()               # show that it's an empty context
        {}
        >>> current()['t'] = [5]    # Plugins did their magic, not shown here
        >>> current()['d'] = [0]
        >>> destroy()               # Leave context
        {'t': [5], 'd': [0]}
        >>> create("nav")           # Create nav
        >>> current()['t']=[15]
        >>> current()['d']=[1]
        >>> destroy()               # Leave nav
        {'t': [15], 'd': [1]}
        >>> destroy()               # Leave left hand column
        {'t': [5, 15], 'd': [0, 1]}
        
        
        >>> create("content")       # Enter content block
        >>> current()['t'] = [85]
        >>> current()['d'] = [2]
        >>> destroy()               # Leave content block
        {'t': [85], 'd': [2]}
        
        
        >>> create("righthand")     # Enter right hand column
        >>> create("cal")           # Enter calendar box
        >>> current()['t']=[25]
        >>> current()['d']=[8]
        >>> destroy()               # Leave calendar
        {'t': [25], 'd': [8]}
        >>> destroy()               # Leave right hand column
        {'t': [25], 'd': [8]}
        
        
        >>> destroy()               # Leave the top level context, get totals
        {'t': [5, 15, 85, 25], 'd': [0, 1, 2, 8]}
        
        
        Method reference
        ----------------
        
        **Utility Methods**
        
        :mr.bent.wrapper.mkwrapper(function, plugin, name):
        Wraps a **function** with a **plugin** which writes its data to the
        current context as **name**
        :mr.bent.wrapper.mkcontext(function, callback):
        Wraps a **function** to create a new context on invocation, and close it
        when it finishes, and give the data to **callback** to handle reporting.
        :mr.bent.wrapper.mkfilter(function):
        Wraps a **function** to be a key that context reporting data can be
        filtered on.
        
        **Low level methods**
        
        :mr.bent.mavolio.create(name):
        Creates a new context called **name**.
        :mr.bent.mavolio.destroy():
        Ends the current context and returns the statistics.
        :mr.bent.mavolio.current():
        Returns the current, in progress, context dict.
        
        
        Changelog
        =========
        
        1.0a1 - Released December 14, 2008
        ----------------------------------
        
        * Initial release
        [matthewwilkes, fschulze, witsch]
        
        
Keywords: statistics profiling
Platform: Any
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Intended Audience :: Other Audience
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Topic :: Software Development :: Libraries :: Python Modules
