[rdfio] Fix methods for objects without language attribute

Some graph methods will crash if some data are not URIs and have no language attribute (eg. BlankNode). Fix this.

Side effect for Redland LibRdf: since this library raises an exception when trying to get an URI for a blank node, we should also handle this case.

Closes #5582296.

authorYann Voté <yann.vote@logilab.fr>
changeset7b78a9be712b
branchdefault
phasepublic
hiddenno
parent revision#628fcc6f0723 [test] Fix ccplugin tests
child revision#67672a4dd0ef Support for specifying label's kind on *.add_concept methods
files modified by this revision
rdfio.py
test/data/bnode.n3
test/unittest_rdfio.py
# HG changeset patch
# User Yann Voté <yann.vote@logilab.fr>
# Date 1435569103 -7200
# Mon Jun 29 11:11:43 2015 +0200
# Node ID 7b78a9be712bf4724fc0b406eb305c8d0cbb6967
# Parent 628fcc6f072311fe12dc3d35ab422172297f6a2d
[rdfio] Fix methods for objects without language attribute

Some graph methods will crash if some data are not URIs and have no
``language`` attribute (eg. ``BlankNode``). Fix this.

Side effect for Redland LibRdf: since this library raises an exception when
trying to get an URI for a blank node, we should also handle this case.

Closes #5582296.

diff --git a/rdfio.py b/rdfio.py
@@ -348,10 +348,12 @@
1              subject = str(statement.subject.uri)
2              predicate = str(statement.predicate.uri)
3              object = statement.object
4              if object.is_literal():
5                  object = self._py_literal(statement.object)
6 +            elif object.is_blank():
7 +                object = str(statement.object.blank_identifier)
8              else:
9                  object = str(statement.object.uri)
10              yield subject, predicate, object
11 
12      def objects(self, entity_uri, predicate_uri):
@@ -362,10 +364,12 @@
13                          predicate=self._uri_node(predicate_uri),
14                          object=None)
15          for statement in self._model.find_statements(qs):
16              if statement.object.is_literal():
17                  yield self._py_literal(statement.object)
18 +            elif statement.object.is_blank():
19 +                yield str(statement.object.blank_identifier)
20              else:
21                  yield str(statement.object.uri)
22 
23      def subjects(self, predicate_uri, entity_uri):
24          """Yield subject URIs that are linked to `entity_uri` through
@@ -415,11 +419,11 @@
25      def triples(self):
26          """Yield every triples in the graph."""
27          for subj, pred, obj in self._graph.triples((None, None, None)):
28              if isinstance(obj, self.uri):
29                  obj = unicode(obj)
30 -            elif obj.language is not None:
31 +            elif getattr(obj, 'language', None) is not None:
32                  obj = unicode_with_language(obj.toPython(), obj.language)
33              else:
34                  obj = obj.toPython()
35              yield unicode(subj), unicode(pred), obj
36 
@@ -428,11 +432,11 @@
37          `predicate_uri`.
38          """
39          for obj in self._graph.objects(self.uri(entity_uri), self.uri(predicate_uri)):
40              if isinstance(obj, self.uri):
41                  yield unicode(obj)
42 -            elif obj.language is not None:
43 +            elif getattr(obj, 'language', None) is not None:
44                  yield unicode_with_language(obj.toPython(), obj.language)
45              else:
46                  yield obj.toPython()
47 
48      def subjects(self, predicate_uri, entity_uri):
diff --git a/test/data/bnode.n3 b/test/data/bnode.n3
@@ -0,0 +1,3 @@
49 +@prefix foaf: <http://xmlns.com/foaf/0.1/> .
50 +
51 +<http://example.org/people/Alice> foaf:knows _:charlie .
diff --git a/test/unittest_rdfio.py b/test/unittest_rdfio.py
@@ -177,11 +177,15 @@
52      return entities_dict
53 
54 
55  class RDFGraphTCMixIn(object):
56 
57 -    def setUp(self):
58 +    def setUp(self, uris=None):
59 +        """Create a sample RDF graph and add some triples to it.
60 +
61 +        Also load triples from the given URIs.
62 +        """
63          graph = self.graph = self.build_graph()
64          self.bob = graph.uri("http://example.org/people/Bob")
65          self.knows = graph.uri("http://foaf.com/knows")
66          self.alice = graph.uri("http://example.org/people/Alice")
67          self.firstname = graph.uri("http://foaf.com/firstname")
@@ -191,15 +195,18 @@
68          graph.add(self.bob, self.firstname, "bob")
69          graph.add(self.bob, self.age, 45)
70          graph.add(self.bob, self.desc, ul("man", "en"))
71          graph.add(self.alice, self.firstname, "alice")
72          graph.add(self.alice, self.age, 25)
73 +        uris = uris or []
74 +        for uri in uris:
75 +            graph.load(uri)
76 
77      def build_graph(self):
78          raise NotImplementedError
79 
80 -    _triples = set([
81 +    _triples = set([  # Only miss (Alice, knows, BNode)
82          ('http://example.org/people/Alice', 'http://foaf.com/age', 25),
83          ('http://example.org/people/Alice', 'http://foaf.com/firstname', u'alice'),
84          ('http://example.org/people/Bob', 'http://foaf.com/firstname', u'bob'),
85          ('http://example.org/people/Bob', 'http://foaf.com/age', 45),
86          ('http://example.org/people/Bob', 'http://dc.com/description', ul('man', 'en')),
@@ -217,11 +224,11 @@
87          result = list(graph.objects(self.alice, self.firstname))
88          self.assertEqual(result, ["alice"])
89 
90      def test_triples(self):
91          triples = set(self.graph.triples())
92 -        self.assertEqual(triples, self._triples)
93 +        self.assertTrue(self._triples.issubset(triples))
94 
95      def test_load_dump_roundtrip(self):
96          for rdf_format in ('xml',):  # 'n3', 'nt'): XXX other formats fail, but sounds due to the
97                                       # underlying lib
98              self.set_description('testing roundtrip for the %s format' % rdf_format)
@@ -234,27 +241,27 @@
99                  fobj.close()
100                  graph = self.build_graph()
101                  graph.load('file://' + fobj.name, rdf_format=rdf_format)
102              finally:
103                  os.unlink(fobj.name)
104 -        self.assertEqual(set(graph.triples()), self._triples)
105 +        self.assertTrue(self._triples.issubset(set(graph.triples())))
106 
107 
108  class RDFLibRDFGraphTC(RDFGraphTCMixIn, TestCase):
109      build_graph = RDFLibRDFGraph
110 
111      @require_module('rdflib')
112      def setUp(self):
113 -        super(RDFLibRDFGraphTC, self).setUp()
114 +        super(RDFLibRDFGraphTC, self).setUp(uris=[self.datapath('bnode.n3')])
115 
116 
117  class LibRDFRDFGraphTC(RDFGraphTCMixIn, TestCase):
118      build_graph = LibRDFRDFGraph
119 
120      @require_module('RDF')
121      def setUp(self):
122 -        super(LibRDFRDFGraphTC, self).setUp()
123 +        super(LibRDFRDFGraphTC, self).setUp(uris=[self.datapath('bnode.n3')])
124 
125 
126  def skos_rdf_registry():
127      xy = RDFRegistry()
128      xy.register_prefix('dc', 'http://purl.org/dc/elements/1.1/')