Message Handling – ordf.handler

This is the operational core of ORDF. In the normal course of events, an application will,

  1. Instantiate a Handler object, which is usually a singleton.
  2. Register one or more handler implementations for reading or writing.
  3. Use the get() and put() methods to respectively retrieve and save Graphs.
  4. Use context() to save Graphs within the context of a ordf.vocab.changeset.ChangeSet.

See the documentation for HandlerPlugin for how handler the implementation works.

Initialising Handlers

class ordf.handler.ConfigError[source]

Raised on configuration error

ordf.handler.init_handler(config)[source]

Initialise a handler based on the configuration dictionary. Typically config will be a section of a configuration file parsed with ConfigParser either directly or accessed via pylons.config

The type of handler to be created, the reading and writing plugins and their initialisation arguments can all be specified:

[app:main]

## handler class to use
ordf.handler = ordf.handler.Handler

## if a handler has a connect() method, it is run with arguments 
## following. this is used e.g. for ordf.handler.queue.RabbitHandler
ordf.connect.queue = readerqueue

## reader plugins
ordf.readers = pairtree

## writer plugins
ordf.writers = pairtree,fourstore,xapian,rabbit

## arguments for the back-ends
pairtree.args = /some/where/data/pairtree
fourstore.args = kbname,soft_limit=-1
xapian.args = 127.0.0.1:44332
rabbit.connect.exchange = foo

Each storage module added to the handler (as a readoer or as a writer) will have a “handler” attribute set by this function that refers back to the handler. In this way storage/index modules that require access to the handler (currently only FuXiReasoner) have it.

Likewise, the handler will have the name of the storage module set as an attribute. e.g.:

.. code-block:: python
getattr(handler, “xapian”)

will return the instance of the xapian storage module. In this way application code can treat the handler instance as a singleton and access the various back-ends simply. It is then possible to call specialised search or other methods as needed.

Reading and Writing Graphs – Handler

class ordf.handler.Handler(**kw)[source]

Handle reading and writing of RDF Graphs

Storage back-ends are registered to an instance of this class for reading and writing. It distributes read and write (:meth:get and :meth:put) operations over these back ends.

Both the write case and some more complex read operations are intimately tied to the use of ordf.changeset.ChangeSet to which this class is the main entry point - it would be unusual, for example, to create a ChangeSet directly.

## initialise some storage
null_storage = HandlerPlugin()

## create the handler
handler = Handler()

## register the storage
handler.register_reader(null_storage)
handler.register_writer(null_storage)

## a read operation: retrieve a graph from storage
handler.get(graph_identifier)

## a write operation: saving with a change context
ctx = handler.context("username", "change reason")
ctx.add(some_graph)
ctx.commit()

If using the :func:init_handler function instead of constructing the handler by hand (which is recommended) then for each storage module will have a “handler” attribute set by that function that refers back to the handler.

Likewise, the handler will have the name of the storage module set as an attribute. e.g.:

.. code-block:: python
getattr(handler, “xapian”)

will return the instance of the xapian storage module.

register_reader(handler, *av, **kw)[source]

Register a writer back-end.

Parameters:
  • handler – either an instance of (a sub-class of) :class:HandlerPlugin or a string. If a string, then uses :meth:HandlerPlugin.find to locate the appropriate implementation.
  • av – positional arguments passed to the handler’s constructor when handler is named with a string.
  • kw – ditto keyword arguments.
register_writer(handler, *av, **kw)[source]

Register a writer back-end.

Parameters are as for :meth:register_reader

get(*av, **kw)[source]

Iterates over all of the registered write handlers and calls their get method.

The first back-end to return a non-None value wins and this value is returned.

The get methods are called wwith the given positional and keyword arguments.

put(*av, **kw)[source]

Iterates over all of the registered write handlers and calls their put method.

The put methods are called with the given positional and keyword arguments.

remove(*av, **kw)[source]

Remove the graph from all storage and indices

context(user, reason)[source]

Return an instance of :class:ChangeContext bound to this handler

Parameters:
  • user – The user (presumed already authenticated via whatever mechanism) requesting the change
  • reason – A short description of the nature of the changes being made.
changeset(csid, *av, **kw)[source]

Given a ChangeSet identifier, return a changeset

history(identifier)[source]

return the history of the graph

Parameters:identifier – a Graph or identifier
Returns:generator of changesets for the given graph, most recent first. Values yielded by the generator will be either instances of :class:ordf.changeset.ChangeSet or lists in the case of multiple parents. This latter is not well tested.
construct(identifier)[source]

Construct the requested graph from stored changesets

Parameters:identifier – a Graph or identifier
query(q)[source]

Execute a SPARQL query if we have a back-end that supports such.

Parameters:q – the query

Base for Storage and Indices – HandlerPlugin

class ordf.handler.HandlerPlugin[source]

Instances of this class implement read and/or write operations on storage and indices.

This is an interface specification for subclassing and null implementation.

The :meth:find class method is used to create handler implementations that may live in various modules. To do this it makes use of the pkg_resources.EntryPoint mechanism. For example, looking at ORDF’s setup.py you can find the entrypoints for the handler implementations that are bundled with this software:

[ordf.handler]
pairtree=ordf.handler.pt:PairTree
rdflib=ordf.handler.rdf:RDFLib
fourstore=ordf.handler.rdf:FourStore
xapian=ordf.handler.xap:Xapian
rabbit=ordf.handler.queue:Rabbit
connect(*av, **kw)[source]
classmethod find(name)[source]

Search in the pkg_resources.EntryPoint named [ordf.handler] for a concrete subclass implementing this interface.

Parameters:name – the name of the plugin to find

If a result is found but is not a subclass of HandlerPlugin a ValueError is raised. If no result is found, an ImportError is raised.

get(identifier)[source]

Retrieve the requested graph

Parameters:identifier – may be a string or :class:rdflib.term.URIRef or an instance of rdflib.graph.Graph in which latter case the graph’s identifier is used as lookup key.
put(graph)[source]

Save or index the given conjunctive graph

Making Changesets – ChangeContext

class ordf.handler.ChangeContext(handler, *av, **kw)[source]

Takes care of constructing changesets and distributes the results

Not to be instantiated directly. Returned from the Handler.context() method.

Typical usage:

ctx = handler.context(...)
ctx.add(graph)
ctx.add(another)
ctx.commit()
add(graph)[source]

Add an RDFLib Graph instance to this changeset context

commit()[source]

Commit any pending changes in this context and distribute them via the handler.

This method actually constructs the ordf.changeset.ChangeSet instance. This ChangeSet is initialised with any positional and keyword arguments that were passed to the present class on creation.

It then iterates over any graphs that have been added with :meth:add and requests the previous version from the Handler.get(). The differences between the previous and current versions are added to the changeset.

Now, ChangeSet in hand, we call the Handler.put() for the changeset and then for each of the new versions of the graphs in turn.

rollback()[source]

Roll back any pending changes in this context

This simply emptying it of graphs that have been previously added using add().