Skip to content

Commit

Permalink
Bringing up to date with RDF Interfaces from W3C
Browse files Browse the repository at this point in the history
  • Loading branch information
Gavin Carothers committed May 10, 2011
1 parent 206aaec commit b24a51a
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 64 deletions.
2 changes: 1 addition & 1 deletion pymantic.wpr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!wing
#!version=3.0
#!version=4.0
##################################################################
# Wing IDE project file #
##################################################################
Expand Down
126 changes: 97 additions & 29 deletions pymantic/primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ def __getnewargs__(self):
object = property(itemgetter(2))

def __str__(self):
return str(self.subject) + ' ' + str(self.predicate) + ' ' + str(self.object) + ' .\n'
return self.subject.toNT() + ' ' + self.predicate.toNT() + ' ' + self.object.toNT() + ' .\n'

def toString(self):
return str(self)

class Quad(tuple):
'Quad(graph, subject, predicate, object)'
Expand Down Expand Up @@ -152,6 +155,9 @@ def __getnewargs__(self):
interfaceName = "Literal"

def __str__(self):
return unicode(self.value)

def toNT(self):
quoted = '"' + nt_escape(self.value) + '"'
if self.language:
return quoted + '@' + self.language
Expand All @@ -160,25 +166,32 @@ def __str__(self):
else:
return quoted


class NamedNode(unicode):

interfaceName = "NamedNode"

@property
def value(self):
return self

def __repr__(self):
return 'NamedNode(' + super(NamedNode, self).__repr__() + ')'
return 'NamedNode(' + self.toNT() + ')'

def __str__(self):
return self.value

def toNT(self):
return '<' + nt_escape(quote_normalized_iri(self.value)) + '>'


class Namespace(NamedNode):
def __call__(self, name):
return NamedNode(self + name)

class BlankNode(object):

interfaceName = "BlankNode"

@property
def value(self):
Expand All @@ -190,6 +203,9 @@ def __repr__(self):
def __str__(self):
return '_:' + self.value

def toNT(self):
return str(self)

from collections import defaultdict
def Index():
return defaultdict(Index)
Expand All @@ -204,56 +220,106 @@ def __init__(self, graph_uri=None):
self._spo = Index()
self._pos = Index()
self._osp = Index()
self._actions = set()

@property
def uri(self):
return self._uri

def addAction(self, action):
self._actions.add(action)
return self

def add(self, triple):
"""Adds the specified Triple to the graph. This method returns the graph
instance it was called on."""
self._triples.add(triple)
self._spo[triple.subject][triple.predicate][triple.object] = triple
self._pos[triple.predicate][triple.object][triple.subject] = triple
self._osp[triple.object][triple.subject][triple.predicate] = triple
return self

def remove(self, triple):
"""Removes the specified Triple from the graph. This method returns the
graph instance it was called on."""
self._triples.remove(triple)
del self._spo[triple.subject][triple.predicate][triple.object]
del self._pos[triple.predicate][triple.object][triple.subject]
del self._osp[triple.object][triple.subject][triple.predicate]
return self

def match(self, subject, predicate, object):
"""This method returns a new sequence of triples which is comprised of
all those triples in the current instance which match the given
arguments, that is, for each triple in this graph, it is included in the
output graph, if:
def match(self, pattern):
if pattern.subject:
if pattern.predicate: # s, p, ???
if pattern.object: # s, p, o
if pattern in self:
yield pattern
* calling triple.subject.equals with the specified subject as an
argument returns true, or the subject argument is null, AND
* calling triple.property.equals with the specified property as an
argument returns true, or the property argument is null, AND
* calling triple.object.equals with the specified object as an argument
returns true, or the object argument is null
This method implements AND functionality, so only triples matching all
of the given non-null arguments will be included in the result.
"""
if subject:
if predicate: # s, p, ???
if object: # s, p, o
if Triple(subject, predicate, object) in self:
yield Triple(subject, predicate, object)
else: # s, p, ?var
for triple in self._spo[pattern.subject][pattern.predicate].itervalues():
for triple in self._spo[subject][predicate].itervalues():
yield triple
else: # s, ?var, ???
if pattern.object: # s, ?var, o
for triple in self._osp[pattern.object][pattern.subject].itervalues():
if object: # s, ?var, o
for triple in self._osp[object][subject].itervalues():
yield triple
else: # s, ?var, ?var
for predicate in self._spo[pattern.subject]:
for triple in self._spo[pattern.subject][predicate].itervalues():
for predicate in self._spo[subject]:
for triple in self._spo[subject][predicate].itervalues():
yield triple
elif pattern.predicate: # ?var, p, ???
if pattern.object: # ?var, p, o
for triple in self._pos[pattern.predicate][pattern.object].itervalues():
elif predicate: # ?var, p, ???
if object: # ?var, p, o
for triple in self._pos[predicate][object].itervalues():
yield triple
else: # ?var, p, ?var
for object in self._pos[pattern.predicate]:
for triple in self._pos[pattern.predicate][object].itervalues():
for object in self._pos[predicate]:
for triple in self._pos[predicate][object].itervalues():
yield triple
elif pattern.object: # ?var, ?var, o
for subject in self._osp[pattern.object]:
for triple in self._osp[pattern.object][subject].itervalues():
elif object: # ?var, ?var, o
for subject in self._osp[object]:
for triple in self._osp[object][subject].itervalues():
yield triple
else:
for triple in self._triples:
yield triple

def removeMatches(self, subject, predicate, object):
"""This method removes those triples in the current graph which match
the given arguments."""
for triple in self.match(subject, predicate, object):
self.remove(triple)
return self

def addAll(self, graph_or_triples):
"""Imports the graph or set of triples in to this graph. This method
returns the graph instance it was called on."""
for triple in graph_or_triples:
self.add(triple)
return self

def merge(self, graph):
"""Returns a new Graph which is a concatenation of this graph and the
graph given as an argument."""
new_graph = Graph()
for triple in graph:
new_graph.add(triple)
for triple in self:
new_graph.add(triple)
return new_graph

def __contains__(self, item):
return item in self._triples

Expand All @@ -265,6 +331,10 @@ def __iter__(self):

def toArray(self):
return frozenset(self._triples)





class Dataset(object):

Expand Down Expand Up @@ -293,16 +363,14 @@ def remove_graph(self, graph_or_uri):
def graphs(self):
return self._graphs.values()

def match(self, item):
if hasattr(item, "graph") and item.graph:
quad_pattern = item
matches = self._graphs[quad_pattern.graph].match(q_as_t(quad_pattern))
def match(self, graph, subject, predicate, object):
if graph:
matches = self._graphs[graph].match(subject, predicate, object)
for match in matches:
yield t_as_q(quad_pattern.graph, match)
yield t_as_q(graph, match)
else:
triple_pattern = item
for graph_uri, graph in self._graphs.iteritems():
for match in graph.match(triple_pattern):
for match in graph.match(subject, predicate, object):
yield t_as_q(graph_uri, match)

def __len__(self):
Expand Down
42 changes: 23 additions & 19 deletions pymantic/rdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,17 +195,17 @@ def new(cls, graph, subject = None):

def erase(self):
"""Erase all tripes for this resource from the graph."""
for triple in list(self.graph.match(Triple(self.subject, None, None))):
for triple in list(self.graph.match(self.subject, None, None)):
self.graph.remove(triple)

def is_a(self):
"""Test to see if the subject of this resource has all the necessary
RDF classes applied to it."""
if hasattr(self, 'rdf_classes'):
for rdf_class in self.rdf_classes:
if not any(self.graph.match(Triple(self.subject,
if not any(self.graph.match(self.subject,
self.resolve('rdf:type'),
rdf_class))):
rdf_class)):
return False
return True

Expand All @@ -223,42 +223,46 @@ def __eq__(self, other):
return NotImplemented

def __ne__(self, other):
return not self.__eq__(other)
eq = self.__eq__(other)
if eq is NotImplemented:
return NotImplemented
else:
return not eq

def __hash__(self):
return hash(self.subject)

def bare_literals(self, predicate):
"""Objects for a predicate that are language-less, datatype-less Literals."""
return [t.object for t in self.graph.match(Triple(self.subject, predicate, None)) if\
return [t.object for t in self.graph.match(self.subject, predicate, None) if\
hasattr(t.object, 'language') and t.object.language is None and\
hasattr(t.object, 'datatype') and t.object.datatype is None]

def objects_by_lang(self, predicate, lang=None):
"""Objects for a predicate that match a specified language or, if
language is None, have a language specified."""
if lang:
return [t.object for t in self.graph.match(Triple(self.subject, predicate, None)) if\
return [t.object for t in self.graph.match(self.subject, predicate, None) if\
hasattr(t.object, 'language') and lang_match(lang, t.object.language)]
else:
return [t.object for t in self.graph.match(Triple(self.subject, predicate, None)) if\
return [t.object for t in self.graph.match(self.subject, predicate, None) if\
hasattr(t.object, 'language') and t.object.language is not None]

def objects_by_datatype(self, predicate, datatype=None):
"""Objects for a predicate that match a specified datatype or, if
datatype is None, have a datatype specified."""
if datatype:
return [t.object for t in self.graph.match(Triple(self.subject, predicate, None)) if\
return [t.object for t in self.graph.match(self.subject, predicate, None) if\
hasattr(t.object, 'datatype') and t.object.datatype == datatype]
else:
return [t.object for t in self.graph.match(Triple(self.subject, predicate, None)) if\
return [t.object for t in self.graph.match(self.subject, predicate, None) if\
hasattr(t.object, 'datatype') and t.object.datatype is not None]

def objects_by_type(self, predicate, resource_class = None):
"""Objects for a predicate that are instances of a particular Resource
subclass or, if resource_class is none, are Resources."""
selected_objects = []
for t in self.graph.match(Triple(self.subject, predicate, None)):
for t in self.graph.match(self.subject, predicate, None):
obj = t.object
if isinstance(obj, BlankNode) or isinstance(obj, NamedNode):
if resource_class is None or\
Expand All @@ -269,17 +273,17 @@ def objects_by_type(self, predicate, resource_class = None):

def objects(self, predicate):
"""All objects for a predicate."""
return [t.object for t in self.graph.match(Triple(self.subject, predicate, None))]
return [t.object for t in self.graph.match(self.subject, predicate, None)]

def object_of(self, predicate = None):
"""All subjects for which this resource is an object for the given
predicate."""
if predicate is None:
for triple in self.graph.match(Triple(None, None, self.subject)):
for triple in self.graph.match(None, None, self.subject):
yield (self.classify(self.graph, triple.subject), triple.predicate)
else:
predicate = self.resolve(predicate)
for triple in self.graph.match(Triple(None, predicate, self.subject)):
for triple in self.graph.match(None, predicate, self.subject):
yield self.classify(self.graph, triple.subject)

def __getitem__(self, key):
Expand Down Expand Up @@ -383,10 +387,10 @@ def in_graph(cls, graph):
for rdf_class in cls.rdf_classes:
if not subjects:
subjects.update([t.subject for t in graph.match(
Triple(None, cls.resolve('rdf:type'), rdf_class))])
None, cls.resolve('rdf:type'), rdf_class)])
else:
subjects.intersection_update([t.subject for t in graph.match(
Triple(None, cls.resolve('rdf:type'), rdf_class))])
None, cls.resolve('rdf:type'), rdf_class)])
return set(cls(graph, subject) for subject in subjects)

def __repr__(self):
Expand All @@ -408,12 +412,12 @@ def classify(cls, graph, obj):
return None
if isinstance(obj, Literal):
return obj
if any(graph.match(Triple(obj, cls.resolve('rdf:type'), None))):
if any(graph.match(obj, cls.resolve('rdf:type'), None)):
#retrieve_resource(graph, obj)
if not any(graph.match(Triple(obj, cls.resolve('rdf:type'), None))):
if not any(graph.match(obj, cls.resolve('rdf:type'), None)):
return Resource(graph, obj)
types = frozenset([t.object for t in graph.match(
Triple(obj, cls.resolve('rdf:type'), None))])
obj, cls.resolve('rdf:type'), None)])
python_classes = tuple(cls.__metaclass__._classes[t] for t in types if\
t in cls.__metaclass__._classes)
if len(python_classes) == 0:
Expand Down Expand Up @@ -522,7 +526,7 @@ def copy(self, target_subject):
if not isinstance(target_subject, NamedNode) and\
not isinstance(target_subject, BlankNode):
target_subject = NamedNode(target_subject)
for t in self.graph.match(Triple(self.subject, None, None)):
for t in self.graph.match(self.subject, None, None):
self.graph.add((target_subject, t.predicate, t.object))
return self.classify(self.graph, target_subject)

Expand Down
Loading

0 comments on commit b24a51a

Please sign in to comment.