SPARUL Update Queries Via SPARQLWrapper And A Virtuoso Server

If you ever had a burning desire to use SPARUL updates (aka SPARQL/1.1) on an Ubuntu machine via SPARQLWrapper you probably seen the following error message

Traceback (most recent call last):
File "./wquery", line 93, in test
ret = m_sparql.query()
File "/usr/local/lib/python2.7/dist-packages/SPARQLWrapper/Wrapper.py", line 390, in query
return QueryResult(self._query())
File "/usr/local/lib/python2.7/dist-packages/SPARQLWrapper/Wrapper.py", line 369, in _query
raise e
urllib2.HTTPError: HTTP Error 406: Unacceptable

it turns out that it is resolved on 1.5.3, however at the time of the writing PIP only carries SPARQLWrapper 1.5.2. to get the fresh version one must pull from SVN:

svn checkout svn://svn.code.sf.net/p/sparql-wrapper/code/trunk sparql-wrapper-code

And here is the test code to write a RDF record to the quad-store:

 iquery = 'INSERT IN GRAPH <nepomuk:/sourceforge.net/users/mcradle/resources/ontologies/magic-bucket> {<http://www.example.org/subject> <http://example.org/predicate> <http://example.org/ob>}'
 m_sparql = SPARQLWrapper(endpoint = "http://localhost:8893/sparql/", updateEndpoint = "http://localhost:8893/sparql-auth/")
 m_sparql.addDefaultGraph ("nepomuk:/sourceforge.net/users/mcradle/resources/ontologies/magic-bucket")
 m_sparql.setCredentials(user = "user", passwd = "password")
 m_sparql.setQuery(iquery)
 m_sparql.setReturnFormat(JSON)
 ret = m_sparql.query()

This now ends with HTTP/1.1 Error 401:

mcradle@carver:~/workdir/remember/nepomuk/nepomuk$ ./wquery "http://www.example2.org/subject" "http://www.example2.org/predicate13" "http://www.example2.org/object"
INSERT IN GRAPH <nepomuk:/sourceforge.net/users/mcradle/resources/ontologies/magic-bucket> {<http://www.example2.org/subject> <http://www.example2.org/predicate13> <http://www.example2.org/object> }
send: 'GET /sparql-auth?output=xml&format=xml&results=xml&update=INSERT+IN+GRAPH+%3Cnepomuk%3A%2Fsourceforge.net%2Fusers%2Fmcradle%2Fresources%2Fontologies%2Fmagic-bucket%3E+%7B%3Chttp%3A%2F%2Fwww.example2.org%2Fsubject%3E+%3Chttp%3A%2F%2Fwww.example2.org%2Fpredicate13%3E+%3Chttp%3A%2F%2Fwww.example2.org%2Fobject%3E+%7D HTTP/1.1\r\nAccept-Encoding: identity\r\nAccept: */*\r\nHost: localhost:8891\r\nConnection: close\r\nAuthorization: Digest cmVtZW1iZXI6cmVtZW1iZXI=\n\r\nUser-Agent: sparqlwrapper 1.5.3 (http://sparql-wrapper.sourceforge.net/)\r\n\r\n'
reply: 'HTTP/1.1 401 Unauthorized\r\n'
header: Server: Virtuoso/06.01.3127 (Linux) i686-pc-linux-gnu
header: Connection: close
header: Content-Type: text/html; charset=UTF-8
header: Date: Sat, 01 Jun 2013 16:40:16 GMT
header: Accept-Ranges: bytes
header: Content-Length: 0
Traceback (most recent call last):
 File "./wquery", line 118, in <module>
 registerStatement2 (t_subject, t_predicate, t_object)
 File "./wquery", line 107, in registerStatement2
 ret = m_sparql.query()
 File "/home/mcradle/workdir/remember/sparqlwrapper/sparql-wrapper-code/src/SPARQLWrapper/Wrapper.py", line 391, in query
 return QueryResult(self._query())
 File "/home/mcradle/workdir/remember/sparqlwrapper/sparql-wrapper-code/src/SPARQLWrapper/Wrapper.py", line 370, in _query
 raise e
urllib2.HTTPError: HTTP Error 401: Unauthorized

But this is because SPARQLWrapper does not support digest auth , so I monkey patched my 1.5.3 SPARQLWrapper to see if it helps:

mcradle@carver:~/workdir/remember/sparqlwrapper/sparql-wrapper-code$ diff -u /mcradle/temp/sparqlwrapper/sparql-wrapper-code/src/SPARQLWrapper/Wrapper.py ./src/SPARQLWrapper/Wrapper.py                                                
--- /tmp/sparqlwrapper/sparql-wrapper-code/src/SPARQLWrapper/Wrapper.py        2013-05-19 00:34:20.597501904 +0300                                                                                                             
+++ ./src/SPARQLWrapper/Wrapper.py      2013-06-01 19:53:38.808090704 +0300                                                                                                                                                             
@@ -343,8 +344,15 @@                                                                                                                                                                                                                    
                                                                                                                                                                                                                                        
         request.add_header("User-Agent", self.agent)                                                                                                                                                                                   
         request.add_header("Accept", acceptHeader)                                                                                                                                                                                     
         if (self.user and self.passwd):                                                                                                                                                                                                
             request.add_header("Authorization", "Basic " + base64.encodestring("%s:%s" % (self.user,self.passwd)))                                                                                                                     
+            passman = urllib2.HTTPPasswordMgrWithDefaultRealm()                                                                                                                                                                        
+            passman.add_password(None, self.updateEndpoint, self.user, self.passwd)                                                                                                                                                    
+            auth_handler = urllib2.HTTPDigestAuthHandler(passman)                                                                                                                                                                      
+            opener = urllib2.build_opener(auth_handler)                                                                                                                                                                                
+            urllib2.install_opener(opener)                                                                                                                                                                                             
+                                                                                                                                                                                                                                       
         return request                                                                                                                                                                                                                 
                                                                                                                                                                                                                                        
     def _query(self):                                     

it further turns out that virtuoso-opensource 6.1.4+dfsg1-0ubuntu1 is not compliant with the new update= notation that replaces the query= syntax in case of a SPARQL 1.1 update operation, according to the SPARQL 1.1 spec anyway.

so one needs to override the SPARQLWrapper Query keyword when a SPARQL 1.1 update is used in a SPARQLWrapper Query:

sparql.queryType= SELECT

I can finally update my virtuoso database by using SPARQLWrapper!

Advertisements
This entry was posted in Uncategorized and tagged , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s