Package SPARQLWrapper :: Module SmartWrapper
[hide private]
[frames] | no frames]

Source Code for Module SPARQLWrapper.SmartWrapper

  1  # -*- coding: utf-8 -*- 
  2   
  3  """ 
  4  @see: U{SPARQL Specification<http://www.w3.org/TR/rdf-sparql-query/>} 
  5  @authors: U{Ivan Herman<http://www.ivan-herman.net>}, U{Sergio Fernández<http://www.wikier.org>}, U{Carlos Tejo Alonso<http://www.dayures.net>} 
  6  @organization: U{World Wide Web Consortium<http://www.w3.org>} and U{Foundation CTIC<http://www.fundacionctic.org/>}. 
  7  @license: U{W3C® SOFTWARE NOTICE AND LICENSE<href="http://www.w3.org/Consortium/Legal/copyright-software">} 
  8  @requires: U{RDFLib<http://rdflib.net>} package. 
  9  """ 
 10   
 11  import urllib2 
 12  from types import * 
 13  import SPARQLWrapper 
 14  from SPARQLWrapper.Wrapper import JSON, SELECT 
 15   
 16  ###################################################################################### 
 17   
18 -class Value(object):
19 """ 20 Class encapsulating a single binding for a variable. 21 22 @cvar URI: the string denoting a URI variable 23 @cvar Literal: the string denoting a Literal variable 24 @cvar TypedLiteral: the string denoting a typed literal variable 25 @cvar BNODE: the string denoting a blank node variable 26 27 @ivar variable: The original variable, stored for an easier reference 28 @type variable: string 29 @ivar value: Value of the binding 30 @type value: string 31 @ivar type: Type of the binding 32 @type type: string; one of L{Value.URI}, L{Value.Literal}, L{Value.TypedLiteral}, or L{Value.BNODE} 33 @ivar lang: Language tag of the binding, or C{None} if not set 34 @type lang: string 35 @ivar datatype: Datatype of the binding, or C{None} if not set 36 @type datatype: string (URI) 37 """ 38 URI = "uri" 39 Literal = "literal" 40 TypedLiteral = "typed-literal" 41 BNODE = "bnode" 42
43 - def __init__(self, variable, binding):
44 """ 45 @param variable: the variable for that binding. Stored for an easier reference 46 @param binding: the binding dictionary part of the return result for a specific binding 47 """ 48 self.variable = variable 49 self.value = binding['value'] 50 self.type = binding['type'] 51 self.lang = None 52 self.datatype = None 53 try: 54 self.lang = binding['xml:lang'] 55 except: 56 # no lang is set 57 pass 58 try: 59 self.datatype = binding['datatype'] 60 except: 61 pass
62
63 - def __repr__(self):
64 cls = self.__class__.__name__ 65 return "%s(%s:%r)" % (cls, self.type, self.value)
66 67 ###################################################################################### 68 69
70 -class Bindings(object):
71 """ 72 Class encapsulating one query result, based on the JSON return format. It decodes the 73 return values to make it a bit more usable for a standard usage. The class consumes the 74 return value and instantiates a number of attributes that can be consulted directly. See 75 the list of variables. 76 77 The U{Serializing SPARQL Query Results in JSON<http://www.w3.org/TR/rdf-sparql-json-res/>} explains the details of the 78 JSON return structures. Very succintly: the return data has "bindings", which means a list of dictionaries. Each 79 dictionary is a possible binding of the SELECT variables to L{Value} instances. This structure is made a bit 80 more usable by this class. 81 82 @ivar fullResult: The original dictionary of the results, stored for an easier reference 83 @ivar head: Header part of the return, see the JSON return format document for details 84 @ivar variables: List of unbounds (variables) of the original query. It is an array of strings. None in the case of an ASK query 85 @ivar bindings: The final bindings: array of dictionaries, mapping variables to L{Value} instances. 86 (If unbound, then no value is set in the dictionary; that can be easily checked with 87 C{var in res.bindings[..]}, for example.) 88 @ivar askResult: by default, set to False; in case of an ASK query, the result of the query 89 @type askResult: Boolean 90 """
91 - def __init__(self, retval):
92 """ 93 @param retval: the query result, instance of a L{Wrapper.QueryResult} 94 """ 95 self.fullResult = retval._convertJSON() 96 self.head = self.fullResult['head'] 97 self.variables = None 98 try: 99 self.variables = self.fullResult['head']['vars'] 100 except: 101 pass 102 103 self.bindings = [] 104 try: 105 for b in self.fullResult['results']['bindings']: 106 # this is a single binding. It is a dictionary per variable; each value is a dictionary again that has to be 107 # converted into a Value instance 108 newBind = {} 109 for key in self.variables: 110 if key in b: 111 # there is a real binding for this key 112 newBind[key] = Value(key, b[key]) 113 self.bindings.append(newBind) 114 except: 115 pass 116 117 self.askResult = False 118 try: 119 self.askResult = self.fullResult["boolean"] 120 except: 121 pass
122
123 - def getValues(self, key):
124 """A shorthand for the retrieval of all bindings for a single key. It is 125 equivalent to "C{[b[key] for b in self[key]]}" 126 @param key: possible variable 127 @return: list of L{Value} instances 128 """ 129 try: 130 return [b[key] for b in self[key]] 131 except: 132 return []
133
134 - def __contains__(self, key):
135 """Emulation of the "C{key in obj}" operator. Key can be a string for a variable or an array/tuple 136 of strings. 137 138 If C{key} is a variable, the return value is C{True} if there is at least one binding where C{key} is 139 bound. If C{key} is an array or tuple, the return value is C{True} if there is at least one binding 140 where I{all} variables in C{key} are bound. 141 142 @param key: possible variable, or array/tuple of variables 143 @return: whether there is a binding of the variable in the return 144 @rtype: Boolean 145 """ 146 if len(self.bindings) == 0: 147 return False 148 if type(key) is list or type(key) is tuple: 149 # check first whether they are all really variables 150 if False in [k in self.variables for k in key]: 151 return False 152 for b in self.bindings: 153 # try to find a binding where all key elements are present 154 if False in [k in b for k in key]: 155 # this is not a binding for the key combination, move on... 156 continue 157 else: 158 # yep, this one is good! 159 return True 160 return False 161 else: 162 if key not in self.variables: 163 return False 164 for b in self.bindings: 165 if key in b: 166 return True 167 return False
168
169 - def __getitem__(self, key):
170 """Emulation of the C{obj[key]} operator. Slice notation is also available. 171 The goal is to choose the right bindings among the available ones. The return values are always 172 arrays of bindings, ie, arrays of dictionaries mapping variable keys to L{Value} instances. 173 The different value settings mean the followings: 174 175 - C{obj[key]} returns the bindings where C{key} has a valid value 176 - C{obj[key1,key2,...]} returns the bindings where I{all} C{key1,key2,...} have valid values 177 - C{obj[(key1,key2,...):(nkey1,nkey2,...)]} returns the bindings where all C{key1,key2,...} have 178 valid values and I{none} of the C{nkey1,nkey2,...} have valid values 179 - C{obj[:(nkey1,nkey2,...)]} returns the bindings where I{none} of the C{nkey1,nkey2,...} have valid values 180 181 In all cases complete bindings are returned, ie, the values for other variables, not present among 182 the keys in the call, may or may not be present depending on the query results. 183 184 @param key: possible variable or array/tuple of keys with possible slice notation 185 @return: list of bindings 186 @rtype: array of variable -> L{Value} dictionaries 187 """ 188 def _checkKeys(keys): 189 if len(keys) == 0: 190 return False 191 for k in keys: 192 if not isinstance(k, basestring) or not k in self.variables: 193 return False 194 return True
195 196 def _nonSliceCase(key): 197 if isinstance(key, basestring) and key != "" and key in self.variables: 198 # unicode or string: 199 return [key] 200 elif type(key) is list or type(key) is tuple: 201 if _checkKeys(key): 202 return key 203 return False
204 205 # The arguments should be reduced to arrays of variables, ie, unicode strings 206 yes_keys = [] 207 no_keys = [] 208 if type(key) is slice: 209 # Note: None for start or stop is all right 210 if key.start: 211 yes_keys = _nonSliceCase(key.start) 212 if not yes_keys: 213 raise TypeError 214 if key.stop: 215 no_keys = _nonSliceCase(key.stop) 216 if not no_keys: 217 raise TypeError 218 else: 219 yes_keys = _nonSliceCase(key) 220 221 # got it right, now get the right binding line with the constraints 222 retval = [] 223 for b in self.bindings: 224 # first check whether the 'yes' part is all there: 225 if False in [k in b for k in yes_keys]: 226 continue 227 if True in [k in b for k in no_keys]: 228 continue 229 # if we got that far, we shouild be all right! 230 retval.append(b) 231 # if retval is of zero length, no hit; an exception should be raised to stay within the python style 232 if len(retval) == 0: 233 raise IndexError 234 return retval 235
236 - def convert(self):
237 """This is just a convenience method, returns C{self}. 238 239 Although C{Binding} is not a subclass of L{QueryResult<SPARQLWrapper.Wrapper.QueryResult>}, it is returned as a result by 240 L{SPARQLWrapper2.query}, just like L{QueryResult<SPARQLWrapper.Wrapper.QueryResult>} is returned by 241 L{SPARQLWrapper.SPARQLWrapper.query}. Consequently, 242 having an empty C{convert} method to imitate L{QueryResult's convert method<SPARQLWrapper.Wrapper.QueryResult.convert>} may avoid unnecessary problems. 243 """ 244 return self
245 246 ############################################################################################################## 247 248
249 -class SPARQLWrapper2(SPARQLWrapper.SPARQLWrapper):
250 """Subclass of L{Wrapper<SPARQLWrapper.SPARQLWrapper>} that works with a JSON SELECT return result only. The query result 251 is automatically set to a L{Bindings} instance. Makes the average query processing a bit simpler..."""
252 - def __init__(self, baseURI, defaultGraph=None):
253 """ 254 Class encapsulating a full SPARQL call. In contrast to the L{SPARQLWrapper<SPARQLWrapper.SPARQLWrapper>} superclass, the return format 255 cannot be set (it is defaulted to L{JSON<Wrapper.JSON>}). 256 @param baseURI: string of the SPARQL endpoint's URI 257 @type baseURI: string 258 @param defaultGraph: URI for the default graph. Default is None, can be set via an explicit call, too 259 @type defaultGraph: string 260 """ 261 super(SPARQLWrapper2, self).__init__(baseURI, returnFormat=JSON, defaultGraph=defaultGraph)
262
263 - def setReturnFormat(self, format):
264 """Set the return format (overriding the L{inherited method<SPARQLWrapper.SPARQLWrapper.setReturnFormat>}). 265 This method does nothing; this class instance should work with JSON only. The method is defined 266 just to avoid possible errors by erroneously setting the return format. 267 When using this class, the user can safely ignore this call. 268 @param format: return format 269 """ 270 pass
271
272 - def query(self):
273 """ 274 Execute the query and do an automatic conversion. 275 276 Exceptions can be raised if either the URI is wrong or the HTTP sends back an error. 277 The usual urllib2 exceptions are raised, which cover possible SPARQL errors, too. 278 279 If the query type is I{not} SELECT, the method falls back to the 280 L{corresponding method in the superclass<SPARQLWrapper.query>}. 281 282 @return: query result 283 @rtype: L{Bindings} instance 284 """ 285 res = super(SPARQLWrapper2, self).query() 286 287 if self.queryType == SELECT: 288 return Bindings(res) 289 else: 290 return res
291
292 - def queryAndConvert(self):
293 """This is here to override the inherited method; it is equivalent to L{query}. 294 295 If the query type is I{not} SELECT, the method falls back to the 296 L{corresponding method in the superclass<SPARQLWrapper.queryAndConvert>}. 297 298 @return: the converted query result. 299 """ 300 if self.queryType == SELECT: 301 return self.query() 302 else: 303 return super(SPARQLWrapper2, self).queryAndConvert()
304