SuRF is an Object – RDF Mapper based on the popular rdflib python library. It exposes the RDF triple sets as sets of resources and seamlessly integrates them into the Object Oriented paradigm of python in a similar manner as ActiveRDF does for ruby.
I’m currently working on extending ways how one can select resources and their attributes. Short intro on what’s possible now. First, let’s look at how one can select resources:
from rdflib.URIRef import URIRef import surf sess = surf.Session(surf.Store(reader = "rdflib")) Person = sess.get_class(surf.ns.FOAF["person"]) # Get all resources that are of type foaf:person persons = Person.all() # The same, but also load their direct and inverse attributes persons = Person.all(full = True) # Limit, offset persons = Person.all(limit = 10, offset = 30) # Look for resources in specific graph persons = Person.all(context = URIRef("http://my_context")) # For filtering use cls.get_by(). Filters are specified as # keyword arguments, argument names follow # "namespace_predicate" naming convention. john_smiths = Person.get_by(foaf_name = "John", foaf_surname = "Smith")
A couple of deficiencies here:
fullarguments are only supported by
all(), they are not supported by
- for both methods, it’s not possible to specify order results
- no shorthand notion to get first element from returned list
So I spent some time thinking and scribbling and getting inspiration from SQLAlchemy. I came up with this syntax:
# Iterator over all person resources persons = Person.all() # First person instance or None if there isn't any first_person = Person.all().first() # First person instance or raises exception if # total person count isn't "1" only_person = Person.all().one() # Iterator over all person resources with fully loaded attributes persons = Person.all().full() # Iterator over all person resources with only direct # attributes loaded, for performance persons = Person.all().full(only_direct = True) # Limit, offset persons = Person.all().limit(10).offset(30) # Sorted by subject URI persons = Person.all().order() # Sorted by name, in descending order persons = Person.all().order(surf.ns.FOAF["name"]).desc() # Specify graph persons = Person.all().context(URIRef("http://my_context")) # get_by also gets all the same features first_five_johns = Person.get_by(foaf_name = "John").order().limit(5)
So that’s how to get hold of resources. How about resource attributes? Currently:
john = sess.get_resource(URIRef("http://johns_uri"), Person) # john.foaf_name is list-like: can be accessed by index, # can be iterated, has length. It also has these two # convenience functions: first_name = john.foaf_name.first only_name = john.foaf_name.one
Currently when accessing attribute all values are returned, in undefined order. There is no way to limit or sort them or to load them from specific graph. So, the idea is to allow all the same operations on attributes that we have on
# Iterator over friend resources john.foaf_knows # Iterator over loaded friend resources john.foaf_knows.full() john.foaf_knows.full(only_direct = True) # First, one john.foaf_knows.first() john.foaf_knows.one() # Limit, offset john.foaf_knows.limit(10).offset(30) # Sort friends by subject URI, sort by attribute john.foaf_knows.order() john.foaf_knows.order(surf.ns.FOAF["name"]) # Graph john.foaf_knows.context(URIRef("http://my_context")) # Filtering, only retrieve friends that are named "Jane" john.foaf_knows.get_by(foaf_name = "Jane") # Combine any of the previous john.foaf_knows.get_by(foaf_name = "Jane").order().limit(10).full()
surf_1_0 branch turns SuRF’s innards upside down, nuts and bolts are all over the place but all in all it looks very promising!