Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

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]    # Simulate plugin results being added to context
>>> 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 - Unreleased

  • Initial release [matthewwilkes, fschulze, witsch]

Release files for mr.bent 1.0a1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mr.bent 1.0a1
File Size Uploaded
mr.bent-1.0a1.zip 22.6 kB Details

Release files / mr.bent-1.0a1.zip

Download URL mr.bent-1.0a1.zip
Size 22.6 kB
Tags Source
SHA-256 checksum
How to use checksums
738802d4c678bc79fb3f5327ca2563c475b0948f4de20b0650c8490b2f32aea5
BLAKE2b-256 checksum
How to use checksums
3c2c7e83ba5bfc668f9125f519129bda9024efea76faceab289707c737c531f0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Release history Release notifications | RSS feed

This release

1.0a1 This release

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page