diff options
Diffstat (limited to 'creactistore/_templates/lib/rdflib/resource.py')
-rw-r--r-- | creactistore/_templates/lib/rdflib/resource.py | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/creactistore/_templates/lib/rdflib/resource.py b/creactistore/_templates/lib/rdflib/resource.py new file mode 100644 index 0000000..23acf8e --- /dev/null +++ b/creactistore/_templates/lib/rdflib/resource.py @@ -0,0 +1,406 @@ +# -*- coding: utf-8 -*- +from rdflib import py3compat +__doc__ = py3compat.format_doctest_out(""" +The ``Resource`` class wraps a ``Graph`` and a resource reference (i.e. an +``URIRef`` or ``BNode``), to support a resource oriented way of working with a +graph. + +It contains methods directly corresponding to those methods of the Graph +interface that relate to reading and writing data. The difference is that a +Resource also binds a resource identifier, making it possible to work without +tracking both the graph and a current subject. This makes for a "resource +oriented" style, as compared to the triple orientation of the Graph API. + +Resulting generators are also wrapped so that any resource reference values +(``URIRef``s and ``BNode``s) are in turn wrapped as Resources. (Note that this +behaviour differs from the corresponding methods in Graph, were no such +conversion takes place.) + + +Basic Usage Scenario +-------------------- + +Start by importing things we need and define some namespaces:: + + >>> from rdflib import * + >>> FOAF = Namespace("http://xmlns.com/foaf/0.1/") + >>> CV = Namespace("http://purl.org/captsolo/resume-rdf/0.2/cv#") + +Load some RDF data:: + + >>> graph = Graph().parse(format='n3', data=''' + ... @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . + ... @prefix xsd: <http://www.w3.org/2001/XMLSchema#>. + ... @prefix foaf: <http://xmlns.com/foaf/0.1/> . + ... @prefix cv: <http://purl.org/captsolo/resume-rdf/0.2/cv#> . + ... + ... @base <http://example.org/> . + ... + ... </person/some1#self> a foaf:Person; + ... rdfs:comment "Just a Python & RDF hacker."@en; + ... foaf:depiction </images/person/some1.jpg>; + ... foaf:homepage <http://example.net/>; + ... foaf:name "Some Body" . + ... + ... </images/person/some1.jpg> a foaf:Image; + ... rdfs:label "some 1"@en; + ... rdfs:comment "Just an image"@en; + ... foaf:thumbnail </images/person/some1-thumb.jpg> . + ... + ... </images/person/some1-thumb.jpg> a foaf:Image . + ... + ... [] a cv:CV; + ... cv:aboutPerson </person/some1#self>; + ... cv:hasWorkHistory [ cv:employedIn </#company>; + ... cv:startDate "2009-09-04"^^xsd:date ] . + ... ''') + +Create a Resource:: + + >>> person = Resource(graph, URIRef("http://example.org/person/some1#self")) + +Retrieve some basic facts:: + + >>> person.identifier + rdflib.term.URIRef('http://example.org/person/some1#self') + + >>> person.value(FOAF.name) + rdflib.term.Literal(%(u)s'Some Body') + + >>> person.value(RDFS.comment) + rdflib.term.Literal(%(u)s'Just a Python & RDF hacker.', lang=%(u)s'en') + +Resources as unicode are represented by their identifiers as unicode:: + + >>> unicode(person) + %(u)s'http://example.org/person/some1#self' + +Resource references are also Resources, so you can easily get e.g. a qname +for the type of a resource, like:: + + >>> person.value(RDF.type).qname() + %(u)s'foaf:Person' + +Or for the predicates of a resource:: + + >>> sorted(p.qname() for p in person.predicates()) + [%(u)s'foaf:depiction', %(u)s'foaf:homepage', %(u)s'foaf:name', %(u)s'rdf:type', %(u)s'rdfs:comment'] + +Follow relations and get more data from their Resources as well:: + + >>> for pic in person.objects(FOAF.depiction): + ... print(pic.identifier) + ... print(pic.value(RDF.type).qname()) + ... print(pic.label()) + ... print(pic.comment()) + ... print(pic.value(FOAF.thumbnail).identifier) + http://example.org/images/person/some1.jpg + foaf:Image + some 1 + Just an image + http://example.org/images/person/some1-thumb.jpg + + >>> for cv in person.subjects(CV.aboutPerson): + ... work = list(cv.objects(CV.hasWorkHistory))[0] + ... print(work.value(CV.employedIn).identifier) + ... print(work.value(CV.startDate)) + http://example.org/#company + 2009-09-04 + +It's just as easy to work with the predicates of a resource:: + + >>> for s, p in person.subject_predicates(): + ... print(s.value(RDF.type).qname()) + ... print(p.qname()) + ... for s, o in p.subject_objects(): + ... print(s.value(RDF.type).qname()) + ... print(o.value(RDF.type).qname()) + cv:CV + cv:aboutPerson + cv:CV + foaf:Person + +This is useful for e.g. inspection:: + + >>> thumb_ref = URIRef("http://example.org/images/person/some1-thumb.jpg") + >>> thumb = Resource(graph, thumb_ref) + >>> for p, o in thumb.predicate_objects(): + ... print(p.qname()) + ... print(o.qname()) + rdf:type + foaf:Image + +Similarly, adding, setting and removing data is easy:: + + >>> thumb.add(RDFS.label, Literal("thumb")) + >>> print(thumb.label()) + thumb + >>> thumb.set(RDFS.label, Literal("thumbnail")) + >>> print(thumb.label()) + thumbnail + >>> thumb.remove(RDFS.label) + >>> list(thumb.objects(RDFS.label)) + [] + + +Schema Example +-------------- + +With this artificial schema data:: + + >>> graph = Graph().parse(format='n3', data=''' + ... @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . + ... @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . + ... @prefix owl: <http://www.w3.org/2002/07/owl#> . + ... @prefix v: <http://example.org/def/v#> . + ... + ... v:Artifact a owl:Class . + ... + ... v:Document a owl:Class; + ... rdfs:subClassOf v:Artifact . + ... + ... v:Paper a owl:Class; + ... rdfs:subClassOf v:Document . + ... + ... v:Choice owl:oneOf (v:One v:Other) . + ... + ... v:Stuff a rdf:Seq; rdf:_1 v:One; rdf:_2 v:Other . + ... + ... ''') + +From this class:: + + >>> artifact = Resource(graph, URIRef("http://example.org/def/v#Artifact")) + +we can get at subclasses:: + + >>> subclasses = list(artifact.transitive_subjects(RDFS.subClassOf)) + >>> [c.qname() for c in subclasses] + [%(u)s'v:Artifact', %(u)s'v:Document', %(u)s'v:Paper'] + +and superclasses from the last subclass:: + + >>> [c.qname() for c in subclasses[-1].transitive_objects(RDFS.subClassOf)] + [%(u)s'v:Paper', %(u)s'v:Document', %(u)s'v:Artifact'] + +Get items from the Choice:: + + >>> choice = Resource(graph, URIRef("http://example.org/def/v#Choice")) + >>> [it.qname() for it in choice.value(OWL.oneOf).items()] + [%(u)s'v:One', %(u)s'v:Other'] + +And the sequence of Stuff:: + + >>> stuff = Resource(graph, URIRef("http://example.org/def/v#Stuff")) + >>> [it.qname() for it in stuff.seq()] + [%(u)s'v:One', %(u)s'v:Other'] + + +Technical Details +----------------- + +Comparison is based on graph and identifier:: + + >>> g1 = Graph() + >>> t1 = Resource(g1, URIRef("http://example.org/thing")) + >>> t2 = Resource(g1, URIRef("http://example.org/thing")) + >>> t3 = Resource(g1, URIRef("http://example.org/other")) + >>> t4 = Resource(Graph(), URIRef("http://example.org/other")) + + >>> t1 is t2 + False + + >>> t1 == t2 + True + >>> t1 != t2 + False + + >>> t1 == t3 + False + >>> t1 != t3 + True + + >>> t3 != t4 + True + + >>> t3 < t1 and t1 > t3 + True + >>> t1 >= t1 and t1 >= t3 + True + >>> t1 <= t1 and t3 <= t1 + True + + >>> t1 < t1 or t1 < t3 or t3 > t1 or t3 > t3 + False + +Hash is computed from graph and identifier:: + + >>> g1 = Graph() + >>> t1 = Resource(g1, URIRef("http://example.org/thing")) + + >>> hash(t1) == hash(Resource(g1, URIRef("http://example.org/thing"))) + True + + >>> hash(t1) == hash(Resource(Graph(), t1.identifier)) + False + >>> hash(t1) == hash(Resource(Graph(), URIRef("http://example.org/thing"))) + False + +The Resource class is suitable as a base class for mapper toolkits. For +example, consider this utility for accessing RDF properties via qname-like +attributes:: + + >>> class Item(Resource): + ... + ... def __getattr__(self, p): + ... return list(self.objects(self._to_ref(*p.split('_', 1)))) + ... + ... def _to_ref(self, pfx, name): + ... return URIRef(self._graph.store.namespace(pfx) + name) + +It works as follows:: + + >>> graph = Graph().parse(format='n3', data=''' + ... @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . + ... @prefix foaf: <http://xmlns.com/foaf/0.1/> . + ... + ... @base <http://example.org/> . + ... </person/some1#self> + ... foaf:name "Some Body"; + ... foaf:depiction </images/person/some1.jpg> . + ... </images/person/some1.jpg> rdfs:comment "Just an image"@en . + ... ''') + + >>> person = Item(graph, URIRef("http://example.org/person/some1#self")) + + >>> print(person.foaf_name[0]) + Some Body + +The mechanism for wrapping references as resources cooperates with subclasses. +Therefore, accessing referenced resources automatically creates new ``Item`` +objects:: + + >>> isinstance(person.foaf_depiction[0], Item) + True + + >>> print(person.foaf_depiction[0].rdfs_comment[0]) + Just an image + +""") + +from rdflib.term import BNode, URIRef +from rdflib.namespace import RDF + +__all__ = ['Resource'] + +class Resource(object): + + def __init__(self, graph, subject): + self._graph = graph + self._identifier = subject + + graph = property(lambda self: self._graph) + + identifier = property(lambda self: self._identifier) + + def __hash__(self): + return hash(Resource) ^ hash(self._graph) ^ hash(self._identifier) + + def __eq__(self, other): + return (isinstance(other, Resource) and + self._graph == other._graph and + self._identifier == other._identifier) + + __ne__ = lambda self, other: not self == other + + def __lt__(self, other): + if isinstance(other, Resource): + return self._identifier < other._identifier + else: + return False + + __gt__ = lambda self, other: not (self < other or self == other) + __le__ = lambda self, other: self < other or self == other + __ge__ = lambda self, other: not self < other + + def __unicode__(self): + return unicode(self._identifier) + + if py3compat.PY3: + __str__ = __unicode__ + + def add(self, p, o): + self._graph.add((self._identifier, p, o)) + + def remove(self, p, o=None): + self._graph.remove((self._identifier, p, o)) + + def set(self, predicate, object): + self._graph.set((self._identifier, predicate, object)) + + def subjects(self, predicate=None): # rev + return self._resources(self._graph.subjects(predicate, self._identifier)) + + def predicates(self, object=None): + return self._resources(self._graph.predicates(self._identifier, object)) + + def objects(self, predicate=None): + return self._resources(self._graph.objects(self._identifier, predicate)) + + def subject_predicates(self): + return self._resource_pairs( + self._graph.subject_predicates(self._identifier)) + + def subject_objects(self): + return self._resource_pairs( + self._graph.subject_objects(self._identifier)) + + def predicate_objects(self): + return self._resource_pairs( + self._graph.predicate_objects(self._identifier)) + + def value(self, predicate=RDF.value, object=None, default=None, any=True): + return self._cast( + self._graph.value(self._identifier, predicate, object, default, any)) + + def label(self): + return self._graph.label(self._identifier) + + def comment(self): + return self._graph.comment(self._identifier) + + def items(self): + return self._resources(self._graph.items(self._identifier)) + + def transitive_objects(self, predicate, remember=None): + return self._resources(self._graph.transitive_objects( + self._identifier, predicate, remember)) + + def transitive_subjects(self, predicate, remember=None): + return self._resources(self._graph.transitive_subjects( + predicate, self._identifier, remember)) + + def seq(self): + return self._resources(self._graph.seq(self._identifier)) + + def qname(self): + return self._graph.qname(self._identifier) + + def _resource_pairs(self, pairs): + for s1, s2 in pairs: + yield self._cast(s1), self._cast(s2) + + def _resources(self, nodes): + for node in nodes: + yield self._cast(node) + + def _cast(self, node): + if isinstance(node, (BNode, URIRef)): + return self._new(node) + else: + return node + + def _new(self, subject): + return type(self)(self._graph, subject) + + |