pax_global_header00006660000000000000000000000064126347501600014516gustar00rootroot0000000000000052 comment=ac7ea90f1f5b9bba8bbd9456223c90cb5a9bd18a sparqlwrapper-1.7.6/000077500000000000000000000000001263475016000144345ustar00rootroot00000000000000sparqlwrapper-1.7.6/.gitignore000066400000000000000000000000731263475016000164240ustar00rootroot00000000000000*~ *.pyc SPARQLWrapper.egg-info build dist doc .idea *.iml sparqlwrapper-1.7.6/.travis.yml000066400000000000000000000003321263475016000165430ustar00rootroot00000000000000# http://travis-ci.org/RDFLib/sparqlwrapper sudo: false language: python python: - 2.7 - 3.2 - 3.3 - 3.4 - pypy install: - python setup.py sdist && pip install ./dist/* script: ./tests.sh sparqlwrapper-1.7.6/AUTHORS.md000066400000000000000000000032541263475016000161070ustar00rootroot00000000000000# Authors * Ivan Herman ([@iherman](http://github.com/iherman)) * Sergio Fernández ([@wikier](http://github.com/wikier)) * Carlos Tejo ([@dayures](http://github.com/dayures)) * Alexey Zakhlestin ([@indeyets](http://github.com/indeyets)) # Contributors * Obey Arthur Liu ([@ArthurLiu](http://github.com/ArthurLiu)): different patches * Christopher Lenz ([@cmlenz](http://github.com/cmlenz)): feature to allow developers to choose the json module * Pēteris Caune ([@cuu508](http://github.com/cuu508)): great feedback and patches * Bogdan Benea ([bugdone@users.sourceforge.net](mailto:bugdone@users.sourceforge.net)), patch for the query regular expresion * William Waites ([@wwaites](http://github.com/wwaites)): patches for RDFLib3 * Christoph Burgmer ([@cburgmer](http://github.com/cburgmer)): patches for RDFLib3 * Thomas Kluyver ([@takluyver](http://github.com/takluyver)): patches for Python 3.x * Diego Berrueta ([@berrueta](http://github.com/berrueta)): new function for printing results as table * Olivier Berger ([@olberger](http://github.com/olberger)): patch regarding raw response for unknown formats * Benjamin Cogrel ([@bcogrel](http://github.com/bcogrel)): standard query types * Urs Holzer ([@uholzer](http://github.com/uholzer)): features, patches and testing * Alf Lervåg ([@alf](http://github.com/alf)): setup patch * Nolan Nichols ([@nicholsn](http://github.com/nicholsn)): http disgest auth support * Kevin Turner ([@keturn](https://github.com/keturn)): `SmartWrapper.Value.__repr__()` implementation * Marcelo Jorge Vieira ([@marcelometal](https://github.com/marcelometal)): typos * Trevor Andersen ([@trevorandersen](https://github.com/trevorandersen): patches for Python 3.x sparqlwrapper-1.7.6/ChangeLog.txt000066400000000000000000000107541263475016000170330ustar00rootroot00000000000000SPARQLWrapper's changelog: ------------------------- 2015-12-18 1.7.6 - Removed wrong response encoding (issue #70) - Authorization header bug when using Python 3 (issue #71) 2015-11-19 1.7.5 - Removed pip dependency on setup (issue #69) 2015-11-05 1.7.4 - Fixed packaging (issue #66) 2015-11-05 1.7.3 - Finally fixed the keepalive issue in all Pyhon versions (issue #65) - Removed old JSON layer in favor of the native json module 2015-11-03 1.7.2 - Moved to the new keepalive package (issues #53 and #61) 2015-10-29 1.7.1 - Fixed build in Python 3.x (issue #57) 2015-10-29 1.7.0 - Added support to HTTP Digest Auth Support (issue #45) - Improved print_results showing language tag (xml:lang) and datatype - Updated to RDFLib 4.x 2014-08-26 1.6.4 - Fixed unicode problems on setup (issue #42) 2014-08-26 1.6.3 - Fixed unicode problems with urllib in Python 3 (issue #35) - Restored SPARQLWrapper2 class (issue #36) - Enhanced warning for missing rdflib-jsonld (issue #38) - Fixed build system (issue #39) 2014-07-24 1.6.2 - Fixed query type detection with comments (issue #32) 2014-07-21 1.6.1 - Added missing query types (issue #17) - Added a new method to the API to select the request method to be fully SPARQL 1.1 Protocol compliant (issue #28) - Improved the test suite coverage, including support to run the tests under Python 3.x (issues #20, #24 and #31) 2014-05-09 1.6.0 - Returning raw response in case of unknown content type returned - Fixed some issues with the last version of the SPARQL 1.1 Update Protocol - setQuery() doesn't imply resetQuery() anymore - Deprecated addCustomParameter(), addParameter() and clearParameter() come to provide all required functionality - SPARQLWrapper, QueryResult, Value, Bindings (and classes inherited from them) are new-style classes now - POST queries are accompanied by full set of parameters now - Added rudimentary support for JSON-LD - Added proper unit tests without dependencies of external endpoints - Fixed Python 3 compatibility issues in SmartWrapper module 2012-08-28 1.5.2 - Implemented update operation according the latest SPARQL 1.1 Protocol drafts (i.e., switching to 'update' parameter) 2012-07-10 1.5.1 - Added the possibility to use two different endpoints for reading and writing operations - New print_results() function for users testing 2012-02-01 1.5.0 - Update handling 500's coming from SPARQL endpoint (feature request #3198363) - Added Python 3.x support (feature request 3022722) - Warning when returned format would be different than the requested one 2011-01-28 1.4.2 - Updated for working with RDFLib3 too (feature request #3117442) - fixed bug with prefixes' regex (#2320024) 2010-01-11 1.4.1 - Supporting keep-alive in SPARQLWrapper if urlgrabber is available (ticket #2929881) - fixed bugs (#2949834) 2009-12-14 1.4.0 - Added some support for SPARUL - Improved HTTP related code - Many other minor bugs fixed 2009-09-23 1.3.2 - Remove pyxml dependency. Instead, use xml.dom.minidom - Updated setup installation (added rdflib dependency) - Updated example.py (added XML, N3 and RDF examples) 2009-09-11 1.3.1 - Remove simplejson dependency for python => 2.6 version - Added feature to choose the json module to use 2009-05-06 1.3.0 - Added a new method to add custom parameters (deprecated old way to do it) 2009-04-27 1.2.1 - Updated setup installation - Patched to work with JSON in Python>=2.6 2008-07-10 1.2.0 - Allowed non-standard extensions (such as SPARUL). - Exceptions fixed. - Added another example. 2008-03-24 1.1.0 - Renamed package name to SPARQLWrapper. - Added a basic catalog of exceptions. 2008-03-07 1.0.1 - Fixed some cosmetic things. 2008-02-14 1.0.0 - First stable release. - Main functionality stabilized. - Project moved to SourceForge. 2007-07-06 0.2.0 - First public release of the library. sparqlwrapper-1.7.6/LICENSE.txt000066400000000000000000000041261263475016000162620ustar00rootroot00000000000000SPARQL Python Wrapper is released under the W3C SOFTWARE NOTICE AND LICENSE. This work (and included software, documentation such as READMEs, or other related items) is being provided by the copyright holders under the following license. By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions. Permission to copy, modify, and distribute this software and its documentation, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications: 1. The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. 2. Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C Software Short Notice should be included (hypertext is preferred, text is permitted) within the body of any redistributed or derivative code. 3. Notice of any changes or modifications to the files, including the date changes were made. (We recommend you provide URIs to the location from which the code is derived.) THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION. The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the software without specific, written prior permission. Title to copyright in this software and any associated documentation will at all times remain with copyright holders. See also http://www.w3.org/Consortium/Legal/copyright-software for further details sparqlwrapper-1.7.6/MANAGEMENT.md000066400000000000000000000024521263475016000163750ustar00rootroot00000000000000# Management documentation The project keeps a very low-profile on managing, so we try to keep it simple. ## Contributions Every contributor (patchs, pull requests, new features, etc) gets part of ownership by be mentioned as contributor to the project (`AUTHORS.md`). ## Release ### Software The release process is quite simple, just few things have to be done: First, do not forget to update the changelog (`ChangeLog.txt` file). That information could be added later to the release at github. Then you have to [create a release](https://github.com/blog/1547-release-your-software) by tagging the master branch: git tag x.y.z git push --tags And then upload the release to pypi: python setup.py register sdist --formats=gztar,zip bdist_egg upload Please, don't forget to increment to the next module (`SPARQLWrapper/__init__.py` file). ### Documentation In order to provide online documentation, some steps need to be accomplished: 1. First, generate the documentation using [epydoc](http://epydoc.sourceforge.net/) using the makefile make doc 2. And then upload the documentation generated (`doc` folder) to GitHub Pages (`gh-pages` branch). 3. After that, the online version of the documentation would be available on [GitHub Pages](http://rdflib.github.io/sparqlwrapper/resources/doc). sparqlwrapper-1.7.6/MANIFEST.in000066400000000000000000000001361263475016000161720ustar00rootroot00000000000000include *.md exclude Makefile include test/*.py include scripts/*.py include requirements.txt sparqlwrapper-1.7.6/Makefile000066400000000000000000000004351263475016000160760ustar00rootroot00000000000000# SPARQLWrapper Makefile NAME=SPARQLWrapper VERSION=`python -c "import SPARQLWrapper,sys;sys.stdout.write(SPARQLWrapper.__version__)";` DESTDIR = DOCDIR=doc doc: clean mkdir -p $(DOCDIR) epydoc -v -n "$(NAME) $(VERSION)" -o $(DOCDIR) --html SPARQLWrapper clean: rm -rf $(DOCDIR) sparqlwrapper-1.7.6/README.md000066400000000000000000000011471263475016000157160ustar00rootroot00000000000000# SPARQL Endpoint interface to Python [![Build Status](https://secure.travis-ci.org/RDFLib/sparqlwrapper.svg?branch=master)](https://travis-ci.org/RDFLib/sparqlwrapper) [![PyPi version](https://badge.fury.io/py/SPARQLWrapper.svg)](https://pypi.python.org/pypi/SPARQLWrapper) The distribution contains: * `SPARQLWrapper`: the Python library. You should copy the directory somewhere into your `PYTHONPATH`. Alternatively, you can also run the distutils scripts: python setup.py install * `test`: some unit and integrations tests * `script`: some scripts to run the library against some SPARQL endpoints. sparqlwrapper-1.7.6/SPARQLWrapper/000077500000000000000000000000001263475016000167775ustar00rootroot00000000000000sparqlwrapper-1.7.6/SPARQLWrapper/KeyCaseInsensitiveDict.py000066400000000000000000000021111263475016000237150ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ A simple implementation of a key case-insensitive dictionary. @authors: U{Ivan Herman}, U{Sergio Fernández}, U{Carlos Tejo Alonso} @organization: U{World Wide Web Consortium} and U{Foundation CTIC}. @license: U{W3C® SOFTWARE NOTICE AND LICENSE} """ class KeyCaseInsensitiveDict(dict): """ A simple implementation of a key case-insensitive dictionary """ def __init__(self, d={}): for k, v in d.items(): self[k] = v def __setitem__(self, key, value): if (hasattr(key, "lower")): key = key.lower() dict.__setitem__(self, key, value) def __getitem__(self, key): if (hasattr(key, "lower")): key = key.lower() return dict.__getitem__(self, key) def __delitem__(self, key): if hasattr(key, "lower"): key = key.lower() dict.__delitem__(self, key) sparqlwrapper-1.7.6/SPARQLWrapper/SPARQLExceptions.py000066400000000000000000000027101263475016000224150ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ SPARQL Wrapper exceptions @authors: U{Ivan Herman}, U{Sergio Fernández}, U{Carlos Tejo Alonso} @organization: U{World Wide Web Consortium} and U{Foundation CTIC}. @license: U{W3C® SOFTWARE NOTICE AND LICENSE} """ class SPARQLWrapperException(Exception): """ Base class for SPARQL Wrapper exceptions """ msg = "an exception has occured" def __init__(self, response=None): if response: formatted_msg = "%s: %s. \n\nResponse:\n%s" % (self.__class__.__name__, self.msg, response) else: formatted_msg = "%s: %s." % (self.__class__.__name__, self.msg) super(SPARQLWrapperException, self).__init__(formatted_msg) class EndPointInternalError(SPARQLWrapperException): """ Exception type for 500 Internal Server Error responses. """ msg = "endpoint returned code 500 and response" class QueryBadFormed(SPARQLWrapperException): """ Query Bad Formed exception """ msg = "a bad request has been sent to the endpoint, probably the sparql query is bad formed" class EndPointNotFound(SPARQLWrapperException): """ End Point Not Found exception """ msg = "it was impossible to connect with the endpoint in that address, check if it is correct" sparqlwrapper-1.7.6/SPARQLWrapper/SPARQLUtils.py000066400000000000000000000020031263475016000213670ustar00rootroot00000000000000# -*- coding: utf8 -*- """ SPARQL Wrapper Utils @authors: U{Ivan Herman}, U{Sergio Fernández}, U{Carlos Tejo Alonso} @organization: U{World Wide Web Consortium} and U{Foundation CTIC}. @license: U{W3C SOFTWARE NOTICE AND LICENSE} """ import warnings def deprecated(func): """ This is a decorator which can be used to mark functions as deprecated. It will result in a warning being emmitted when the function is used. @see: http://code.activestate.com/recipes/391367/ """ def newFunc(*args, **kwargs): warnings.warn("Call to deprecated function %s." % func.__name__, category=DeprecationWarning, stacklevel=2) return func(*args, **kwargs) newFunc.__name__ = func.__name__ newFunc.__doc__ = func.__doc__ newFunc.__dict__.update(func.__dict__) return newFunc sparqlwrapper-1.7.6/SPARQLWrapper/SmartWrapper.py000066400000000000000000000312721263475016000220050ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ @see: U{SPARQL Specification} @authors: U{Ivan Herman}, U{Sergio Fernández}, U{Carlos Tejo Alonso} @organization: U{World Wide Web Consortium} and U{Foundation CTIC}. @license: U{W3C® SOFTWARE NOTICE AND LICENSE} @requires: U{RDFLib} package. """ import SPARQLWrapper from SPARQLWrapper.Wrapper import JSON, SELECT import urllib2 from types import * ###################################################################################### class Value(object): """ Class encapsulating a single binding for a variable. @cvar URI: the string denoting a URI variable @cvar Literal: the string denoting a Literal variable @cvar TypedLiteral: the string denoting a typed literal variable @cvar BNODE: the string denoting a blank node variable @ivar variable: The original variable, stored for an easier reference @type variable: string @ivar value: Value of the binding @type value: string @ivar type: Type of the binding @type type: string; one of L{Value.URI}, L{Value.Literal}, L{Value.TypedLiteral}, or L{Value.BNODE} @ivar lang: Language tag of the binding, or C{None} if not set @type lang: string @ivar datatype: Datatype of the binding, or C{None} if not set @type datatype: string (URI) """ URI = "uri" Literal = "literal" TypedLiteral = "typed-literal" BNODE = "bnode" def __init__(self,variable,binding) : """ @param variable: the variable for that binding. Stored for an easier reference @param binding: the binding dictionary part of the return result for a specific binding """ self.variable = variable self.value = binding['value'] self.type = binding['type'] self.lang = None self.datatype = None try : self.lang = binding['xml:lang'] except : # no lang is set pass try : self.datatype = binding['datatype'] except : pass def __repr__(self): cls = self.__class__.__name__ return "%s(%s:%r)" % (cls, self.type, self.value) ###################################################################################### class Bindings(object): """ Class encapsulating one query result, based on the JSON return format. It decodes the return values to make it a bit more usable for a standard usage. The class consumes the return value and instantiates a number of attributes that can be consulted directly. See the list of variables. The U{Serializing SPARQL Query Results in JSON} explains the details of the JSON return structures. Very succintly: the return data has "bindings", which means a list of dictionaries. Each dictionary is a possible binding of the SELECT variables to L{Value} instances. This structure is made a bit more usable by this class. @ivar fullResult: The original dictionary of the results, stored for an easier reference @ivar head: Header part of the return, see the JSON return format document for details @ivar variables: List of unbounds (variables) of the original query. It is an array of strings. None in the case of an ASK query @ivar bindings: The final bindings: array of dictionaries, mapping variables to L{Value} instances. (If unbound, then no value is set in the dictionary; that can be easily checked with C{var in res.bindings[..]}, for example.) @ivar askResult: by default, set to False; in case of an ASK query, the result of the query @type askResult: Boolean """ def __init__(self,retval) : """ @param retval: the query result, instance of a L{Wrapper.QueryResult} """ self.fullResult = retval._convertJSON() self.head = self.fullResult['head'] self.variables = None try : self.variables = self.fullResult['head']['vars'] except : pass self.bindings = [] try : for b in self.fullResult['results']['bindings'] : # this is a single binding. It is a dictionary per variable; each value is a dictionary again that has to be # converted into a Value instance newBind = {} for key in self.variables : if key in b : # there is a real binding for this key newBind[key] = Value(key,b[key]) self.bindings.append(newBind) except : pass self.askResult = False try : self.askResult = self.fullResult["boolean"] except : pass def getValues(self,key) : """A shorthand for the retrieval of all bindings for a single key. It is equivalent to "C{[b[key] for b in self[key]]}" @param key: possible variable @return: list of L{Value} instances """ try : return [b[key] for b in self[key]] except : return [] def __contains__(self,key) : """Emulation of the "C{key in obj}" operator. Key can be a string for a variable or an array/tuple of strings. If C{key} is a variable, the return value is C{True} if there is at least one binding where C{key} is bound. If C{key} is an array or tuple, the return value is C{True} if there is at least one binding where I{all} variables in C{key} are bound. @param key: possible variable, or array/tuple of variables @return: whether there is a binding of the variable in the return @rtype: Boolean """ if len(self.bindings) == 0 : return False if type(key) is list or type(key) is tuple: # check first whether they are all really variables if False in [ k in self.variables for k in key ]: return False for b in self.bindings : # try to find a binding where all key elements are present if False in [ k in b for k in key ] : # this is not a binding for the key combination, move on... continue else : # yep, this one is good! return True return False else : if key not in self.variables : return False for b in self.bindings : if key in b : return True return False def __getitem__(self,key) : """Emulation of the C{obj[key]} operator. Slice notation is also available. The goal is to choose the right bindings among the available ones. The return values are always arrays of bindings, ie, arrays of dictionaries mapping variable keys to L{Value} instances. The different value settings mean the followings: - C{obj[key]} returns the bindings where C{key} has a valid value - C{obj[key1,key2,...]} returns the bindings where I{all} C{key1,key2,...} have valid values - C{obj[(key1,key2,...):(nkey1,nkey2,...)]} returns the bindings where all C{key1,key2,...} have valid values and I{none} of the C{nkey1,nkey2,...} have valid values - C{obj[:(nkey1,nkey2,...)]} returns the bindings where I{none} of the C{nkey1,nkey2,...} have valid values In all cases complete bindings are returned, ie, the values for other variables, not present among the keys in the call, may or may not be present depending on the query results. @param key: possible variable or array/tuple of keys with possible slice notation @return: list of bindings @rtype: array of variable -> L{Value} dictionaries """ def _checkKeys(keys) : if len(keys) == 0 : return False for k in keys : if not isinstance(k, basestring) or not k in self.variables: return False return True def _nonSliceCase(key) : if isinstance(key, basestring) and key != "" and key in self.variables : # unicode or string: return [key] elif type(key) is list or type(key) is tuple: if _checkKeys(key) : return key return False # The arguments should be reduced to arrays of variables, ie, unicode strings yes_keys = [] no_keys = [] if type(key) is slice : # Note: None for start or stop is all right if key.start : yes_keys = _nonSliceCase(key.start) if not yes_keys: raise TypeError if key.stop : no_keys = _nonSliceCase(key.stop) if not no_keys: raise TypeError else : yes_keys = _nonSliceCase(key) # got it right, now get the right binding line with the constraints retval = [] for b in self.bindings : # first check whether the 'yes' part is all there: if False in [k in b for k in yes_keys] : continue if True in [k in b for k in no_keys] : continue # if we got that far, we shouild be all right! retval.append(b) # if retval is of zero length, no hit; an exception should be raised to stay within the python style if len(retval) == 0 : raise IndexError return retval def convert(self) : """This is just a convenience method, returns C{self}. Although C{Binding} is not a subclass of L{QueryResult}, it is returned as a result by L{SPARQLWrapper2.query}, just like L{QueryResult} is returned by L{SPARQLWrapper.SPARQLWrapper.query}. Consequently, having an empty C{convert} method to imitate L{QueryResult's convert method} may avoid unnecessary problems. """ return self ############################################################################################################## class SPARQLWrapper2(SPARQLWrapper.SPARQLWrapper): """Subclass of L{Wrapper} that works with a JSON SELECT return result only. The query result is automatically set to a L{Bindings} instance. Makes the average query processing a bit simpler...""" def __init__(self, baseURI, defaultGraph=None): """ Class encapsulating a full SPARQL call. In contrast to the L{SPARQLWrapper} superclass, the return format cannot be set (it is defaulted to L{JSON}). @param baseURI: string of the SPARQL endpoint's URI @type baseURI: string @keyword defaultGraph: URI for the default graph. Default is None, can be set via an explicit call, too @type defaultGraph: string """ super(SPARQLWrapper2, self).__init__(baseURI, returnFormat=JSON, defaultGraph=defaultGraph) def setReturnFormat(self, format): """Set the return format (overriding the L{inherited method}). This method does nothing; this class instance should work with JSON only. The method is defined just to avoid possible errors by erronously setting the return format. When using this class, the user can safely ignore this call. @param format: return format """ pass def query(self): """ Execute the query and do an automatic conversion. Exceptions can be raised if either the URI is wrong or the HTTP sends back an error. The usual urllib2 exceptions are raised, which cover possible SPARQL errors, too. If the query type is I{not} SELECT, the method falls back to the L{corresponding method in the superclass}. @return: query result @rtype: L{Bindings} instance """ res = super(SPARQLWrapper2, self).query() if self.queryType == SELECT: return Bindings(res) else: return res def queryAndConvert(self): """This is here to override the inherited method; it is equivalent to L{query}. If the query type is I{not} SELECT, the method falls back to the L{corresponding method in the superclass}. @return: the converted query result. """ if self.queryType == SELECT: return self.query() else: return super(SPARQLWrapper2, self).queryAndConvert() sparqlwrapper-1.7.6/SPARQLWrapper/Wrapper.py000066400000000000000000001001311263475016000207650ustar00rootroot00000000000000# -*- coding: utf-8 -*- # epydoc # """ @var JSON: to be used to set the return format to JSON @var XML: to be used to set the return format to XML (SPARQL XML format or RDF/XML, depending on the query type). This is the default. @var TURTLE: to be used to set the return format to Turtle @var N3: to be used to set the return format to N3 (for most of the SPARQL services this is equivalent to Turtle) @var RDF: to be used to set the return RDF Graph @var POST: to be used to set HTTP POST @var GET: to be used to set HTTP GET. This is the default. @var SELECT: to be used to set the query type to SELECT. This is, usually, determined automatically. @var CONSTRUCT: to be used to set the query type to CONSTRUCT. This is, usually, determined automatically. @var ASK: to be used to set the query type to ASK. This is, usually, determined automatically. @var DESCRIBE: to be used to set the query type to DESCRIBE. This is, usually, determined automatically. @see: U{SPARQL Specification} @authors: U{Ivan Herman}, U{Sergio Fernández}, U{Carlos Tejo Alonso} @organization: U{World Wide Web Consortium}, U{Salzburg Research} and U{Foundation CTIC}. @license: U{W3C® SOFTWARE NOTICE AND LICENSE} @requires: U{RDFLib} package. """ import urllib import urllib2 from urllib2 import urlopen as urlopener # don't change the name: tests override it import socket import base64 import re import sys import warnings import json from KeyCaseInsensitiveDict import KeyCaseInsensitiveDict from SPARQLExceptions import QueryBadFormed, EndPointNotFound, EndPointInternalError from SPARQLUtils import deprecated from SPARQLWrapper import __agent__ # Possible output format keys... JSON = "json" JSONLD = "json-ld" XML = "xml" TURTLE = "turtle" N3 = "n3" RDF = "rdf" _allowedFormats = [JSON, XML, TURTLE, N3, RDF] # Possible HTTP methods POST = "POST" GET = "GET" _allowedRequests = [POST, GET] # Possible HTTP Authentication methods BASIC = "BASIC" DIGEST = "DIGEST" _allowedAuth = [BASIC, DIGEST] # Possible SPARQL/SPARUL query type SELECT = "SELECT" CONSTRUCT = "CONSTRUCT" ASK = "ASK" DESCRIBE = "DESCRIBE" INSERT = "INSERT" DELETE = "DELETE" CREATE = "CREATE" CLEAR = "CLEAR" DROP = "DROP" LOAD = "LOAD" COPY = "COPY" MOVE = "MOVE" ADD = "ADD" _allowedQueryTypes = [SELECT, CONSTRUCT, ASK, DESCRIBE, INSERT, DELETE, CREATE, CLEAR, DROP, LOAD, COPY, MOVE, ADD] # Possible methods to perform requests URLENCODED = "urlencoded" POSTDIRECTLY = "postdirectly" _REQUEST_METHODS = [URLENCODED, POSTDIRECTLY] # Possible output format (mime types) that can be converted by the local script. Unfortunately, # it does not work by simply setting the return format, because there is still a certain level of confusion # among implementations. # For example, Joseki returns application/javascript and not the sparql-results+json thing that is required... # Ie, alternatives should be given... # Andy Seaborne told me (June 2007) that the right return format is now added to his CVS, ie, future releases of # joseki will be o.k., too. The situation with turtle and n3 is even more confusing because the text/n3 and text/turtle # mime types have just been proposed and not yet widely used... _SPARQL_DEFAULT = ["application/sparql-results+xml", "application/rdf+xml", "*/*"] _SPARQL_XML = ["application/sparql-results+xml"] _SPARQL_JSON = ["application/sparql-results+json", "text/javascript", "application/json"] _RDF_XML = ["application/rdf+xml"] _RDF_N3 = ["text/rdf+n3", "application/n-triples", "application/turtle", "application/n3", "text/n3", "text/turtle"] _RDF_JSONLD = ["application/x-json+ld", "application/ld+json"] _ALL = ["*/*"] _RDF_POSSIBLE = _RDF_XML + _RDF_N3 _SPARQL_POSSIBLE = _SPARQL_XML + _SPARQL_JSON + _RDF_XML + _RDF_N3 _SPARQL_PARAMS = ["query"] try: import rdflib_jsonld _allowedFormats.append(JSONLD) _RDF_POSSIBLE = _RDF_POSSIBLE + _RDF_JSONLD except ImportError: #warnings.warn("JSON-LD disabled because no suitable support has been found", RuntimeWarning) pass # This is very ugly. The fact is that the key for the choice of the output format is not defined. # Virtuoso uses 'format', joseki uses 'output', rasqual seems to use "results", etc. Lee Feigenbaum # told me that virtuoso also understand 'output' these days, so I removed 'format'. I do not have # info about the others yet, ie, for the time being I keep the general mechanism. Hopefully, in a # future release, I can get rid of that. However, these processors are (hopefully) oblivious to the # parameters they do not understand. So: just repeat all possibilities in the final URI. UGLY!!!!!!! _returnFormatSetting = ["format", "output", "results"] ####################################################################################################### class SPARQLWrapper(object): """ Wrapper around an online access to a SPARQL Web entry point. The same class instance can be reused for subsequent queries. The values of the base Graph URI, return formats, etc, are retained from one query to the next (in other words, only the query string changes). The instance can also be reset to its initial values using the L{resetQuery} method. @cvar pattern: regular expression used to determine whether a query is of type L{CONSTRUCT}, L{SELECT}, L{ASK}, or L{DESCRIBE}. @type pattern: compiled regular expression (see the C{re} module of Python) @ivar baseURI: the URI of the SPARQL service """ pattern = re.compile(r""" ((?P(\s*BASE\s*<.*?>)\s*)|(?P(\s*PREFIX\s+.+:\s*<.*?>)\s*))* (?P(CONSTRUCT|SELECT|ASK|DESCRIBE|INSERT|DELETE|CREATE|CLEAR|DROP|LOAD|COPY|MOVE|ADD)) """, re.VERBOSE | re.IGNORECASE) def __init__(self, endpoint, updateEndpoint=None, returnFormat=XML, defaultGraph=None, agent=__agent__): """ Class encapsulating a full SPARQL call. @param endpoint: string of the SPARQL endpoint's URI @type endpoint: string @param updateEndpoint: string of the SPARQL endpoint's URI for update operations (if it's a different one) @type updateEndpoint: string @keyword returnFormat: Default: L{XML}. Can be set to JSON or Turtle/N3 No local check is done, the parameter is simply sent to the endpoint. Eg, if the value is set to JSON and a construct query is issued, it is up to the endpoint to react or not, this wrapper does not check. Possible values: L{JSON}, L{XML}, L{TURTLE}, L{N3} (constants in this module). The value can also be set via explicit call, see below. @type returnFormat: string @keyword defaultGraph: URI for the default graph. Default is None, the value can be set either via an L{explicit call} or as part of the query string. @type defaultGraph: string """ self.endpoint = endpoint self.updateEndpoint = updateEndpoint if updateEndpoint else endpoint self.agent = agent self.user = None self.passwd = None self.http_auth = BASIC self._defaultGraph = defaultGraph if returnFormat in _allowedFormats: self._defaultReturnFormat = returnFormat else: self._defaultReturnFormat = XML self.resetQuery() def resetQuery(self): """Reset the query, ie, return format, query, default or named graph settings, etc, are reset to their default values.""" self.parameters = {} if self._defaultGraph: self.addParameter("default-graph-uri", self._defaultGraph) self.returnFormat = self._defaultReturnFormat self.method = GET self.setQuery("""SELECT * WHERE{ ?s ?p ?o }""") self.timeout = None self.requestMethod = URLENCODED def setReturnFormat(self, format): """Set the return format. If not an allowed value, the setting is ignored. @param format: Possible values: are L{JSON}, L{XML}, L{TURTLE}, L{N3}, L{RDF} (constants in this module). All other cases are ignored. @type format: str """ if format in _allowedFormats : self.returnFormat = format elif format == JSONLD: raise ValueError("Current instance does not support JSON-LD; you might want to install the rdflib-json package.") else: raise ValueError("Invalid format '%s'; current instance supports: %s.", (format, ", ".join(_allowedFormats))) def supportsReturnFormat(self, format): """Check if a return format is supported. @param format: Possible values: are L{JSON}, L{XML}, L{TURTLE}, L{N3}, L{RDF} (constants in this module). All other cases are ignored. @type format: bool """ return (format in _allowedFormats) def setTimeout(self, timeout): """Set the timeout (in seconds) to use for querying the endpoint. @param timeout: Timeout in seconds. @type timeout: int """ self.timeout = int(timeout) def setRequestMethod(self, method): """Set the internal method to use to perform the request for query or update operations, either URL-encoded (C{SPARQLWrapper.URLENCODED}) or POST directly (C{SPARQLWrapper.POSTDIRECTLY}). Further details at U{http://www.w3.org/TR/sparql11-protocol/#query-operation} and U{http://www.w3.org/TR/sparql11-protocol/#update-operation}. @param method: method @type method: str """ if method in _REQUEST_METHODS: self.requestMethod = method else: warnings.warn("invalid update method '%s'" % method, RuntimeWarning) @deprecated def addDefaultGraph(self, uri): """ Add a default graph URI. @param uri: URI of the graph @type uri: string @deprecated: use addParameter("default-graph-uri", uri) instead of this method """ self.addParameter("default-graph-uri", uri) @deprecated def addNamedGraph(self, uri): """ Add a named graph URI. @param uri: URI of the graph @type uri: string @deprecated: use addParameter("named-graph-uri", uri) instead of this method """ self.addParameter("named-graph-uri", uri) @deprecated def addExtraURITag(self, key, value): """ Some SPARQL endpoints require extra key value pairs. E.g., in virtuoso, one would add C{should-sponge=soft} to the query forcing virtuoso to retrieve graphs that are not stored in its local database. @param key: key of the query part @type key: string @param value: value of the query part @type value: string @deprecated: use addParameter(key, value) instead of this method """ self.addParameter(key, value) @deprecated def addCustomParameter(self, name, value): """ Method is kept for backwards compatibility. Historically, it "replaces" parameters instead of adding @param name: name @type name: string @param value: value @type value: string @rtype: bool @deprecated: use addParameter(name, value) instead of this method """ self.clearParameter(name) return self.addParameter(name, value) def addParameter(self, name, value): """ Some SPARQL endpoints allow extra key value pairs. E.g., in virtuoso, one would add C{should-sponge=soft} to the query forcing virtuoso to retrieve graphs that are not stored in its local database. @param name: name @type name: string @param value: value @type value: string @rtype: bool """ if name in _SPARQL_PARAMS: return False else: if name not in self.parameters: self.parameters[name] = [] self.parameters[name].append(value) return True def clearParameter(self, name): """ Clear the values ofd a concrete parameter. @param name: name @type name: string @rtype: bool """ if name in _SPARQL_PARAMS: return False else: try: del self.parameters[name] return True except KeyError: return False def setCredentials(self, user, passwd): """ Set the credentials for querying the current endpoint @param user: username @type user: string @param passwd: password @type passwd: string """ self.user = user self.passwd = passwd def setHTTPAuth(self, auth): """ Set the HTTP Authentication type (Basic or Digest) @param auth: auth type @type auth: string """ if not isinstance(auth, str): raise TypeError('setHTTPAuth takes a string') elif auth.upper() in _allowedAuth: self.http_auth = auth.upper() else: valid_types = ", ".join(_allowedAuth) raise ValueError("Value should be one of {0}".format(valid_types)) def setQuery(self, query): """ Set the SPARQL query text. Note: no check is done on the validity of the query (syntax or otherwise) by this module, except for testing the query type (SELECT, ASK, etc). Syntax and validity checking is done by the SPARQL service itself. @param query: query text @type query: string @bug: #2320024 """ if sys.version < '3': # have to write it like this, for 2to3 compatibility if isinstance(query, unicode): pass elif isinstance(query, str): query = query.decode('utf-8') else: raise TypeError('setQuery takes either unicode-strings or utf-8 encoded byte-strings') else: if isinstance(query, str): pass elif isinstance(query, bytes): query = query.decode('utf-8') else: raise TypeError('setQuery takes either unicode-strings or utf-8 encoded byte-strings') self.queryString = query self.queryType = self._parseQueryType(query) def _parseQueryType(self,query): """ Parse the SPARQL query and return its type (ie, L{SELECT}, L{ASK}, etc). Note that the method returns L{SELECT} if nothing is specified. This is just to get all other methods running; in fact, this means that the query is erronous, because the query must be, according to the SPARQL specification, one of Select, Ask, Describe, or Construct. The SPARQL endpoint should raise an exception (via urllib) for such syntax error. @param query: query text @type query: string @rtype: string """ try: query = query if type(query)==str else query.encode('ascii', 'ignore') query = re.sub(re.compile("#.*?\n" ), "" , query) # remove all occurance singleline comments (issue #32) r_queryType = self.pattern.search(query).group("queryType").upper() except AttributeError: warnings.warn("not detected query type for query '%s'" % query.replace("\n", " "), RuntimeWarning) r_queryType = None if r_queryType in _allowedQueryTypes : return r_queryType else : #raise Exception("Illegal SPARQL Query; must be one of SELECT, ASK, DESCRIBE, or CONSTRUCT") warnings.warn("unknown query type '%s'" % r_queryType, RuntimeWarning) return SELECT def setMethod(self,method): """Set the invocation method. By default, this is L{GET}, but can be set to L{POST}. @param method: should be either L{GET} or L{POST}. Other cases are ignored. """ if method in _allowedRequests : self.method = method def setUseKeepAlive(self): """Make urllib2 use keep-alive. @raise ImportError: when could not be imported keepalive.HTTPHandler """ try: from keepalive import HTTPHandler keepalive_handler = HTTPHandler() opener = urllib2.build_opener(keepalive_handler) urllib2.install_opener(opener) except ImportError: warnings.warn("keepalive support not available, so the execution of this method has no effect") def isSparqlUpdateRequest(self): """ Returns TRUE if SPARQLWrapper is configured for executing SPARQL Update request @return: bool """ return self.queryType in [INSERT, DELETE, CREATE, CLEAR, DROP, LOAD, COPY, MOVE, ADD] def isSparqlQueryRequest(self): """ Returns TRUE if SPARQLWrapper is configured for executing SPARQL Query request @return: bool """ return not self.isSparqlUpdateRequest() def _getRequestEncodedParameters(self, query=None): query_parameters = self.parameters.copy() if query and type(query) == tuple and len(query) == 2: #tuple ("query"/"update", queryString) query_parameters[query[0]] = [query[1]] # This is very ugly. The fact is that the key for the choice of the output format is not defined. # Virtuoso uses 'format',sparqler uses 'output' # However, these processors are (hopefully) oblivious to the parameters they do not understand. # So: just repeat all possibilities in the final URI. UGLY!!!!!!! for f in _returnFormatSetting: query_parameters[f] = [self.returnFormat] pairs = ( "%s=%s" % ( urllib.quote_plus(param.encode('UTF-8'), safe='/'), urllib.quote_plus(value.encode('UTF-8'), safe='/') ) for param, values in query_parameters.items() for value in values ) return '&'.join(pairs) def _getAcceptHeader(self): if self.queryType in [SELECT, ASK]: if self.returnFormat == XML: acceptHeader = ",".join(_SPARQL_XML) elif self.returnFormat == JSON: acceptHeader = ",".join(_SPARQL_JSON) else: acceptHeader = ",".join(_ALL) elif self.queryType in [INSERT, DELETE]: acceptHeader = "*/*" else: if self.returnFormat == N3 or self.returnFormat == TURTLE: acceptHeader = ",".join(_RDF_N3) elif self.returnFormat == XML: acceptHeader = ",".join(_RDF_XML) elif self.returnFormat == JSONLD and JSONLD in _allowedFormats: acceptHeader = ",".join(_RDF_JSONLD) else: acceptHeader = ",".join(_ALL) return acceptHeader def _createRequest(self): """Internal method to create request according a HTTP method. Returns a C{urllib2.Request} object of the urllib2 Python library @return: request """ request = None if self.isSparqlUpdateRequest(): #protocol details at http://www.w3.org/TR/sparql11-protocol/#update-operation uri = self.updateEndpoint if self.method != POST: warnings.warn("update operations MUST be done by POST") if self.requestMethod == POSTDIRECTLY: request = urllib2.Request(uri + "?" + self._getRequestEncodedParameters()) request.add_header("Content-Type", "application/sparql-update") request.data = self.queryString.encode('UTF-8') else: # URL-encoded request = urllib2.Request(uri) request.add_header("Content-Type", "application/x-www-form-urlencoded") request.data = self._getRequestEncodedParameters(("update", self.queryString)).encode('ascii') else: #protocol details at http://www.w3.org/TR/sparql11-protocol/#query-operation uri = self.endpoint if self.method == POST: if self.requestMethod == POSTDIRECTLY: request = urllib2.Request(uri + "?" + self._getRequestEncodedParameters()) request.add_header("Content-Type", "application/sparql-query") request.data = self.queryString.encode('UTF-8') else: # URL-encoded request = urllib2.Request(uri) request.add_header("Content-Type", "application/x-www-form-urlencoded") request.data = self._getRequestEncodedParameters(("query", self.queryString)).encode('ascii') else: # GET request = urllib2.Request(uri + "?" + self._getRequestEncodedParameters(("query", self.queryString))) request.add_header("User-Agent", self.agent) request.add_header("Accept", self._getAcceptHeader()) if self.user and self.passwd: if self.http_auth == BASIC: credentials = "%s:%s" % (self.user, self.passwd) request.add_header("Authorization", "Basic %s" % base64.b64encode(credentials.encode('utf-8')).decode('utf-8')) elif self.http_auth == DIGEST: realm = "SPARQL" pwd_mgr = urllib2.HTTPPasswordMgr() pwd_mgr.add_password(realm, uri, self.user, self.passwd) opener = urllib2.build_opener() opener.add_handler(urllib2.HTTPDigestAuthHandler(pwd_mgr)) urllib2.install_opener(opener) else: valid_types = ", ".join(_allowedAuth) raise NotImplementedError("Expecting one of: {0}, but received: {1}".format(valid_types, self.http_auth)) return request def _query(self): """Internal method to execute the query. Returns the output of the C{urllib2.urlopen} method of the standard Python library @return: tuples with the raw request plus the expected format """ if self.timeout: socket.setdefaulttimeout(self.timeout) request = self._createRequest() try: response = urlopener(request) return response, self.returnFormat except urllib2.HTTPError, e: if e.code == 400: raise QueryBadFormed(e.read()) elif e.code == 404: raise EndPointNotFound(e.read()) elif e.code == 500: raise EndPointInternalError(e.read()) else: raise e def query(self): """ Execute the query. Exceptions can be raised if either the URI is wrong or the HTTP sends back an error (this is also the case when the query is syntactically incorrect, leading to an HTTP error sent back by the SPARQL endpoint). The usual urllib2 exceptions are raised, which therefore cover possible SPARQL errors, too. Note that some combinations of return formats and query types may not make sense. For example, a SELECT query with Turtle response is meaningless (the output of a SELECT is not a Graph), or a CONSTRUCT query with JSON output may be a problem because, at the moment, there is no accepted JSON serialization of RDF (let alone one implemented by SPARQL endpoints). In such cases the returned media type of the result is unpredictable and may differ from one SPARQL endpoint implementation to the other. (Endpoints usually fall back to one of the "meaningful" formats, but it is up to the specific implementation to choose which one that is.) @return: query result @rtype: L{QueryResult} instance """ return QueryResult(self._query()) def queryAndConvert(self): """Macro like method: issue a query and return the converted results. @return: the converted query result. See the conversion methods for more details. """ res = self.query() return res.convert() ####################################################################################################### class QueryResult(object): """ Wrapper around an a query result. Users should not create instances of this class, it is generated by a L{SPARQLWrapper.query} call. The results can be converted to various formats, or used directly. If used directly: the class gives access to the direct http request results L{self.response}: it is a file-like object with two additional methods: C{geturl()} to return the URL of the resource retrieved and C{info()} that returns the meta-information of the HTTP result as a dictionary-like object (see the urllib2 standard library module of Python). For convenience, these methods are also available on the instance. The C{__iter__} and C{next} methods are also implemented (by mapping them to L{self.response}). This means that the common idiom:: for l in obj : do_something_with_line(l) would work, too. @ivar response: the direct HTTP response; a file-like object, as return by the C{urllib2.urlopen} library call. """ def __init__(self,result): """ @param result: HTTP response stemming from a L{SPARQLWrapper.query} call, or a tuple with the expected format: (response,format) """ if (type(result) == tuple): self.response = result[0] self.requestedFormat = result[1] else: self.response = result """Direct response, see class comments for details""" def geturl(self): """Return the URI of the original call. @return: URI @rtype: string """ return self.response.geturl() def info(self): """Return the meta-information of the HTTP result. @return: meta information @rtype: dictionary """ return KeyCaseInsensitiveDict(self.response.info()) def __iter__(self): """Return an iterator object. This method is expected for the inclusion of the object in a standard C{for} loop. """ return self.response.__iter__() def next(self): """Method for the standard iterator.""" return self.response.next() def _convertJSON(self): """ Convert a JSON result into a Python dict. This method can be overwritten in a subclass for a different conversion method. @return: converted result @rtype: Python dictionary """ return json.loads(self.response.read().decode("utf-8")) def _convertXML(self): """ Convert an XML result into a Python dom tree. This method can be overwritten in a subclass for a different conversion method. @return: converted result @rtype: PyXlib DOM node """ from xml.dom.minidom import parse return parse(self.response) def _convertRDF(self): """ Convert a RDF/XML result into an RDFLib triple store. This method can be overwritten in a subclass for a different conversion method. @return: converted result @rtype: RDFLib Graph """ try: from rdflib.graph import ConjunctiveGraph except ImportError: from rdflib import ConjunctiveGraph retval = ConjunctiveGraph() # this is a strange hack. If the publicID is not set, rdflib (or the underlying xml parser) makes a funny #(and, as far as I could see, meaningless) error message... retval.load(self.response, publicID=' ') return retval def _convertN3(self): """ Convert a RDF Turtle/N3 result into a string. This method can be overwritten in a subclass for a different conversion method. @return: converted result @rtype: string """ return self.response.read() def _convertJSONLD(self): """ Convert a RDF JSON-LDresult into an RDFLib triple store. This method can be overwritten in a subclass for a different conversion method. @return: converted result @rtype: RDFLib Graph """ from rdflib import ConjunctiveGraph retval = ConjunctiveGraph() retval.load(self.response, format='json-ld', publicID=' ') return retval def convert(self): """ Encode the return value depending on the return format: - in the case of XML, a DOM top element is returned; - in the case of JSON, a simplejson conversion will return a dictionary; - in the case of RDF/XML, the value is converted via RDFLib into a Graph instance. In all other cases the input simply returned. @return: the converted query result. See the conversion methods for more details. """ def _content_type_in_list(real, expected): return True in [real.find(mime) != -1 for mime in expected] def _validate_format(format_name, allowed, mime, requested): if requested not in allowed: message = "Format requested was %s, but %s (%s) has been returned by the endpoint" warnings.warn(message % (requested.upper(), format_name, mime), RuntimeWarning) if "content-type" in self.info(): ct = self.info()["content-type"] if _content_type_in_list(ct, _SPARQL_XML): _validate_format("XML", [XML], ct, self.requestedFormat) return self._convertXML() elif _content_type_in_list(ct, _SPARQL_JSON): _validate_format("JSON", [JSON], ct, self.requestedFormat) return self._convertJSON() elif _content_type_in_list(ct, _RDF_XML): _validate_format("RDF/XML", [RDF, XML], ct, self.requestedFormat) return self._convertRDF() elif _content_type_in_list(ct, _RDF_N3): _validate_format("N3", [N3, TURTLE], ct, self.requestedFormat) return self._convertN3() elif _content_type_in_list(ct, _RDF_JSONLD): _validate_format("JSON(-LD)", [JSONLD, JSON], ct, self.requestedFormat) return self._convertJSONLD() warnings.warn("unknown response content type, returning raw response...", RuntimeWarning) return self.response.read() def print_results(self, minWidth=None): results = self._convertJSON() if minWidth : width = self.__get_results_width(results, minWidth) else : width = self.__get_results_width(results) index = 0 for var in results["head"]["vars"] : print ("?" + var).ljust(width[index]),"|", index += 1 print print "=" * (sum(width) + 3 * len(width)) for result in results["results"]["bindings"] : index = 0 for var in results["head"]["vars"] : result = self.__get_prettyprint_string_sparql_var_result(result[var]) print result.ljust(width[index]),"|", index += 1 print def __get_results_width(self, results, minWidth=2): width = [] for var in results["head"]["vars"] : width.append(max(minWidth, len(var)+1)) for result in results["results"]["bindings"] : index = 0 for var in results["head"]["vars"] : result = self.__get_prettyprint_string_sparql_var_result(result[var]) width[index] = max(width[index], len(result)) index =+ 1 return width def __get_prettyprint_string_sparql_var_result(self, result): value = result["value"] lang = result.get("xml:lang", None) datatype = result.get("datatype",None) if lang is not None: value+="@"+lang if datatype is not None: value+=" ["+datatype+"]" return value sparqlwrapper-1.7.6/SPARQLWrapper/__init__.py000066400000000000000000000217541263475016000211210ustar00rootroot00000000000000# -*- coding: utf8 -*- u""" This is a wrapper around a SPARQL service. It helps in creating the query URI and, possibly, convert the result into a more managable format. The following packages are used: - for JSON, the U{simplejson} package: C{http://cheeseshop.python.org/pypi/simplejson} - for RDF/XML, the U{RDFLib}: C{http://rdflib.net} These packages are imported in a lazy fashion, ie, only when needed. Ie, if the user never intends to use the JSON format, the C{simplejson} package is not imported and the user does not have to install it. The package can be downloaded in C{zip} and C{.tar.gz} formats from U{http://www.ivan-herman.net/Misc/PythonStuff/SPARQL/}. It is also available from U{Sourceforge} under the project named "C{sparql-wrapper}". Documentation is included in the distribution. Basic QUERY Usage ================= Simple query ------------ The simplest usage of this module looks as follows (using the default, ie, U{XML return format}, and special URI for the SPARQL Service):: from SPARQLWrapper import SPARQLWrapper queryString = "SELECT * WHERE { ?s ?p ?o. }" sparql = SPARQLWrapper("http://localhost:2020/sparql") # add a default graph, though that can also be part of the query string sparql.addDefaultGraph("http://www.example.com/data.rdf") sparql.setQuery(queryString) try : ret = sparql.query() # ret is a stream with the results in XML, see except : deal_with_the_exception() If C{SPARQLWrapper("http://localhost:2020/sparql",returnFormat=SPARQLWrapper.JSON)} was used, the result would be in U{JSON format} instead of XML (provided the sparql processor can return JSON). Automatic conversion of the results ----------------------------------- To make processing somewhat easier, the package can do some conversions automatically from the return result. These are: - for XML, the U{xml.dom.minidom} (C{http://docs.python.org/library/xml.dom.minidom.html}) is used to convert the result stream into a Python representation of a DOM tree - for JSON, the U{simplejson} package (C{http://cheeseshop.python.org/pypi/simplejson}) to generate a Python dictionary There are two ways to generate this conversion: - use C{ret.convert()} in the return result from C{sparql.query()} in the code above - use C{sparql.queryAndConvert()} to get the converted result right away if the intermediate stream is not used For example, in the code below:: try : sparql.setReturnFormat(SPARQLWrapper.JSON) ret = sparql.query() dict = ret.convert() except: deal_with_the_exception() the value of C{dict} is a Python dictionary of the query result, based on the U{JSON format}. The L{SPARQLWrapper} class can be subclassed by overriding the conversion routines if the user wants to use something else. Partial interpretation of the results ------------------------------------- A further help is to offer an extra, partial interpretation of the results, again to cover most of the practical use cases. Based on the U{JSON format}, the L{SmartWrapper.Bindings} class can perform some simple steps in decoding the JSON return results. If L{SPARQLWrapper2} is used instead of L{SPARQLWrapper}, this result format is generated. Note that this relies on a JSON format only, ie, it has to be checked whether the SPARQL service can return JSON or not. Here is a simple code that makes use of this feature:: from SPARQLWrapper import SPARQLWrapper2 queryString = "SELECT ?subj ?prop WHERE { ?subj ?prop ?o. }" sparql = SPARQLWrapper2("http://localhost:2020/sparql") # add a default graph, though that can also be in the query string sparql.addDefaultGraph("http://www.example.com/data.rdf") sparql.setQuery(queryString) try : ret = sparql.query() print ret.variables # this is an array consisting of "subj" and "prop" for binding in ret.bindings : # each binding is a dictionary. Let us just print the results print "%s: %s (of type %s)" % ("s",binding[u"subj"].value,binding[u"subj"].type) print "%s: %s (of type %s)" % ("p",binding[u"prop"].value,binding[u"prop"].type) except: deal_with_the_exception() To make this type of code even easier to realize, the C{[]} and C{in} operators are also implemented on the result of L{SmartWrapper.Bindings}. This can be used to check and find a particular binding (ie, particular row in the return value). This features becomes particularly useful when the C{OPTIONAL} feature of SPARQL is used. For example:: from SPARQLWrapper import SPARQLWrapper2 queryString = "SELECT ?subj ?o ?opt WHERE { ?subj ?o. OPTIONAL { ?subj ?opt }}" sparql = SPARQLWrapper2("http://localhost:2020/sparql") # add a default graph, though that can also be in the query string sparql.addDefaultGraph("http://www.example.com/data.rdf") sparql.setQuery(queryString) try : ret = sparql.query() print ret.variables # this is an array consisting of "subj", "o", "opt" if (u"subj",u"prop",u"opt") in ret : # there is at least one binding covering the optional "opt", too bindings = ret[u"subj",u"o",u"opt"] # bindings is an array of dictionaries with the full bindings for b in bindings : subj = b[u"subj"].value o = b[u"o"].value opt = b[u"opt"].value # do something nice with subj, o, and opt # another way of accessing to values for a single variable: # take all the bindings of the "subj" subjbind = ret.getValues(u"subj") # an array of Value instances ... except: deal_with_the_exception() CONSTRUCT, ASK, DESCRIBE ======================== All the examples so far were based on the SELECT queries. If the query includes, eg, the C{CONSTRUCT} keyword then the accepted return formats should be different: eg, C{SPARQLWrapper.XML} means C{RDF/XML} and most of the SPARQL engines can also return the results in C{Turtle}. The package, though it does not contain a full SPARQL parser, makes an attempt to determine the query type when the query is set. This should work in most of the cases (but there is a possibility to set this manually, in case something goes wrong). For RDF/XML, the U{RDFLib} (C{http://rdflib.net}) package is used to convert the result into a C{Graph} instance. GET or POST =========== By default, all SPARQL services are invoked using HTTP GET. However, POST might be useful if the size of the query extends a reasonable size; this can be set in the query instance. Note that some combination may not work yet with all SPARQL processors (eg, there are implementations where POST+JSON return does not work). Hopefully, this problem will eventually disappear. Note that SPARQLWrapper only supports nowadays query using POST via URL-encoded. Acknowledgement =============== The package was greatly inspired by U{Lee Feigenbaum's similar package for Javascript}. @summary: Python interface to SPARQL services @see: U{SPARQL Specification} @authors: U{Ivan Herman}, U{Sergio Fernández}, U{Carlos Tejo Alonso} @organization: U{World Wide Web Consortium}, U{Salzburg Research} and U{Foundation CTIC}. @license: U{W3C® SOFTWARE NOTICE AND LICENSE} @requires: U{simplejson} package. @requires: U{RDFLib} package. """ __version__ = "1.7.6" """The version of SPARQLWrapper""" __authors__ = "Ivan Herman, Sergio Fernández, Carlos Tejo Alonso, Alexey Zakhlestin" """The primary authors of SPARQLWrapper""" __license__ = "W3C® SOFTWARE NOTICE AND LICENSE, http://www.w3.org/Consortium/Legal/copyright-software" """The license governing the use and distribution of SPARQLWrapper""" __url__ = "http://rdflib.github.io/sparqlwrapper" """The URL for SPARQLWrapper's homepage""" __contact__ = "rdflib-dev@googlegroups.com" """Mail list to contact to other people RDFLib and SPARQLWrappers folks and developers""" __date__ = "2015-12-18" """Last update""" __agent__ = "sparqlwrapper %s (rdflib.github.io/sparqlwrapper)" % __version__ from Wrapper import SPARQLWrapper from Wrapper import XML, JSON, TURTLE, N3, JSONLD, RDF from Wrapper import GET, POST from Wrapper import SELECT, CONSTRUCT, ASK, DESCRIBE, INSERT, DELETE from Wrapper import URLENCODED, POSTDIRECTLY from Wrapper import BASIC, DIGEST from SmartWrapper import SPARQLWrapper2 sparqlwrapper-1.7.6/ez_setup.py000066400000000000000000000240551263475016000166520ustar00rootroot00000000000000#!python """Bootstrap setuptools installation If you want to use setuptools in your package's setup.py, just include this file in the same directory with it, and add this to the top of your setup.py:: from ez_setup import use_setuptools use_setuptools() If you want to require a specific version of setuptools, set a download mirror, or use an alternate download directory, you can do so by supplying the appropriate options to ``use_setuptools()``. This file can also be run as a script to install or upgrade setuptools. """ import sys DEFAULT_VERSION = "0.6c11" DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] md5_data = { 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', 'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090', 'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4', 'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7', 'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5', 'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de', 'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b', 'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2', 'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086', 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20', 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab', 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53', 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2', 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e', 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372', 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902', 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de', 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b', 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03', 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a', 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6', 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a', } import sys, os try: from hashlib import md5 except ImportError: from md5 import md5 def _validate_md5(egg_name, data): if egg_name in md5_data: digest = md5(data).hexdigest() if digest != md5_data[egg_name]: print >>sys.stderr, ( "md5 validation of %s failed! (Possible download problem?)" % egg_name ) sys.exit(2) return data def use_setuptools( version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, download_delay=15 ): """Automatically find/download setuptools and make it available on sys.path `version` should be a valid setuptools version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where setuptools will be downloaded, if it is not already available. If `download_delay` is specified, it should be the number of seconds that will be paused before initiating a download, should one be required. If an older version of setuptools is installed, this routine will print a message to ``sys.stderr`` and raise SystemExit in an attempt to abort the calling script. """ was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules def do_download(): egg = download_setuptools(version, download_base, to_dir, download_delay) sys.path.insert(0, egg) import setuptools; setuptools.bootstrap_install_from = egg try: import pkg_resources except ImportError: return do_download() try: pkg_resources.require("setuptools>="+version); return except pkg_resources.VersionConflict, e: if was_imported: print >>sys.stderr, ( "The required version of setuptools (>=%s) is not available, and\n" "can't be installed while this script is running. Please install\n" " a more recent version first, using 'easy_install -U setuptools'." "\n\n(Currently using %r)" ) % (version, e.args[0]) sys.exit(2) else: del pkg_resources, sys.modules['pkg_resources'] # reload ok return do_download() except pkg_resources.DistributionNotFound: return do_download() def download_setuptools( version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, delay = 15 ): """Download setuptools from a specified location and return its filename `version` should be a valid setuptools version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where the egg will be downloaded. `delay` is the number of seconds to pause before an actual download attempt. """ import urllib2, shutil egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) url = download_base + egg_name saveto = os.path.join(to_dir, egg_name) src = dst = None if not os.path.exists(saveto): # Avoid repeated downloads try: from distutils import log if delay: log.warn(""" --------------------------------------------------------------------------- This script requires setuptools version %s to run (even to display help). I will attempt to download it for you (from %s), but you may need to enable firewall access for this script first. I will start the download in %d seconds. (Note: if this machine does not have network access, please obtain the file %s and place it in this directory before rerunning this script.) ---------------------------------------------------------------------------""", version, download_base, delay, url ); from time import sleep; sleep(delay) log.warn("Downloading %s", url) src = urllib2.urlopen(url) # Read/write all in one block, so we don't create a corrupt file # if the download is interrupted. data = _validate_md5(egg_name, src.read()) dst = open(saveto,"wb"); dst.write(data) finally: if src: src.close() if dst: dst.close() return os.path.realpath(saveto) def main(argv, version=DEFAULT_VERSION): """Install or upgrade setuptools and EasyInstall""" try: import setuptools except ImportError: egg = None try: egg = download_setuptools(version, delay=0) sys.path.insert(0,egg) from setuptools.command.easy_install import main return main(list(argv)+[egg]) # we're done here finally: if egg and os.path.exists(egg): os.unlink(egg) else: if setuptools.__version__ == '0.0.1': print >>sys.stderr, ( "You have an obsolete version of setuptools installed. Please\n" "remove it from your system entirely before rerunning this script." ) sys.exit(2) req = "setuptools>="+version import pkg_resources try: pkg_resources.require(req) except pkg_resources.VersionConflict: try: from setuptools.command.easy_install import main except ImportError: from easy_install import main main(list(argv)+[download_setuptools(delay=0)]) sys.exit(0) # try to force an exit else: if argv: from setuptools.command.easy_install import main main(argv) else: print "Setuptools version",version,"or greater has been installed." print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' def update_md5(filenames): """Update our built-in md5 registry""" import re for name in filenames: base = os.path.basename(name) f = open(name,'rb') md5_data[base] = md5(f.read()).hexdigest() f.close() data = [" %r: %r,\n" % it for it in md5_data.items()] data.sort() repl = "".join(data) import inspect srcfile = inspect.getsourcefile(sys.modules[__name__]) f = open(srcfile, 'rb'); src = f.read(); f.close() match = re.search("\nmd5_data = {\n([^}]+)}", src) if not match: print >>sys.stderr, "Internal error!" sys.exit(2) src = src[:match.start(1)] + repl + src[match.end(1):] f = open(srcfile,'w') f.write(src) f.close() if __name__=='__main__': if len(sys.argv)>2 and sys.argv[1]=='--md5update': update_md5(sys.argv[2:]) else: main(sys.argv[1:]) sparqlwrapper-1.7.6/requirements.txt000066400000000000000000000000331263475016000177140ustar00rootroot00000000000000rdflib>=4.0 keepalive>=0.5 sparqlwrapper-1.7.6/run_tests_py3.sh000077500000000000000000000015211263475016000176130ustar00rootroot00000000000000#!/bin/bash function cmdcheck() { command -v $0 >/dev/null 2>&1 || { echo >&2 "ERROR: command $0 required but it's not installed; aborting..."; exit -1; } } cmdcheck python3 PYTHON_VERSION=`python3 -c "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));sys.stdout.write(t)";` cmdcheck 2to3-$PYTHON_VERSION cmdcheck nosetests-$PYTHON_VERSION python3 setup.py build if [ -d build/py3_testing ]; then rm -r build/py3_testing echo "removed build/py3_testing directory from previous run" fi mkdir build/py3_testing cp -r test build/py3_testing/ cp -r build/lib/SPARQLWrapper build/py3_testing/ cd build/py3_testing 2to3-$PYTHON_VERSION -wn --no-diffs test sed -i.bak s/urllib2._opener/urllib.request._opener/g test/wrapper_test.py if hash nosetests3 2>/dev/null; then nosetests3 else nosetests fi cd ../.. sparqlwrapper-1.7.6/scripts/000077500000000000000000000000001263475016000161235ustar00rootroot00000000000000sparqlwrapper-1.7.6/scripts/example-dbpedia.py000066400000000000000000000013601263475016000215160ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- from SPARQLWrapper import SPARQLWrapper, JSON sparql = SPARQLWrapper("http://dbpedia.org/sparql") sparql.setQuery(""" PREFIX rdfs: SELECT ?label WHERE { rdfs:label ?label } """) sparql.setReturnFormat(JSON) results = sparql.query() results.print_results() print sparql.setQuery(""" PREFIX rdfs: PREFIX dbpo: SELECT ?subdivision ?label WHERE { dbpo:subdivisionName ?subdivision . ?subdivision rdfs:label ?label . } """) sparql.setReturnFormat(JSON) results = sparql.query() results.print_results() sparqlwrapper-1.7.6/scripts/example-optional.py000066400000000000000000000014001263475016000217460ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- from SPARQLWrapper import SPARQLWrapper, JSON, XML, N3, RDF sparql = SPARQLWrapper("http://dbpedia.org/sparql") sparql.setQuery(""" PREFIX rdfs: SELECT ?person ?party WHERE { ?person OPTIONAL { ?person ?party } } """) # JSON example print '\n\n*** JSON Example' sparql.setReturnFormat(JSON) results = sparql.query().convert() for result in results["results"]["bindings"]: if result.has_key("party"): print "* " + result["person"]["value"] + " ** " + result["party"]["value"] else: print result["person"]["value"] sparqlwrapper-1.7.6/scripts/example.py000066400000000000000000000015771263475016000201420ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- from SPARQLWrapper import SPARQLWrapper, JSON, XML, N3, RDF sparql = SPARQLWrapper("http://dbpedia.org/sparql") sparql.setQuery(""" PREFIX rdfs: SELECT ?label WHERE { rdfs:label ?label } """) # JSON example print '\n\n*** JSON Example' sparql.setReturnFormat(JSON) results = sparql.query().convert() for result in results["results"]["bindings"]: print result["label"]["value"] # XML example print '\n\n*** XML Example' sparql.setReturnFormat(XML) results = sparql.query().convert() print results.toxml() # N3 example print '\n\n*** N3 Example' sparql.setReturnFormat(N3) results = sparql.query().convert() print results # RDF example print '\n\n*** RDF Example' sparql.setReturnFormat(RDF) results = sparql.query().convert() print results.serialize() sparqlwrapper-1.7.6/scripts/sparql.py000077500000000000000000000043771263475016000200150ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- from SPARQLWrapper import SPARQLWrapper2, SPARQLWrapper, TURTLE import sys, getopt localSparqler = "http://localhost:2020/sparql" localVirtuoso = "http://localhost:8890/sparql" def main(server,query,sponge=False) : sparql = SPARQLWrapper2(server) if sponge : sparql.addExtraURITag("should-sponge","grab-everything") sparql.setQuery(query) res = sparql.query() variables = res.variables print "Variables:" print variables print print "Bindings:" for b in res.bindings : for v in res.variables : try : val = b[v] if val.lang : str = "%s: %s@%s" % (v,val.value,val.lang) elif val.datatype : str = "%s: %s^^%s" % (v,val.value,val.datatype) else : str = "%s: %s" % (v,val.value) except KeyError : # no binding to that one... str = "%s: <>" % v print str.encode('utf-8') print # ------------------------------------------------------------------------------------------------------------- server = localSparqler query = "" sponge = False usagetxt="""%s [-s] [-u url] [file] -s: use local sparqler (default) -v: use local virtuoso -u url: server url -p: issue an extra sponge for virtuoso file: sparql query file """ def usage() : print usagetxt % sys.argv[0] sys.exit(1) if __name__ == '__main__' : if len(sys.argv) == 1: usage() try : opts,args = getopt.getopt(sys.argv[1:],"shu:pv") for o,a in opts : if o == "-s" : server = localSparqler elif o == "-v" : server = localVirtuoso sponge = True elif o == "-h" : print usage sys.exit(0) elif o == "-u" : server = a elif o == "-p" : sponge = True if query == "" and len(args) > 0 : inp = file(args[0]) query = "" for l in inp : query += l except : usage() if query == "" : usage() main(server,query,sponge) sparqlwrapper-1.7.6/setup.py000077500000000000000000000041731263475016000161560ustar00rootroot00000000000000# -*- coding: utf-8 -*- import sys try: from ez_setup import use_setuptools use_setuptools() except: pass from setuptools import setup try: import six py3 = six.PY3 except: py3 = sys.version_info[0] >= 3 # metadata if py3: import re _version_re = re.compile(r'__version__\s*=\s*"(.*)"') _authors_re = re.compile(r'__authors__\s*=\s*"(.*)"') _url_re = re.compile(r'__url__\s*=\s*"(.*)"') for line in open('SPARQLWrapper/__init__.py', encoding='utf-8'): version_match = _version_re.match(line) if version_match: version = version_match.group(1) authors_match = _authors_re.match(line) if authors_match: authors = authors_match.group(1) url_match = _url_re.match(line) if url_match: url = url_match.group(1) else: import SPARQLWrapper version = SPARQLWrapper.__version__ authors = SPARQLWrapper.__authors__ url = SPARQLWrapper.__url__ # requirements with open('requirements.txt', 'r') as f: _install_requires = [line.rstrip('\n') for line in f] setup( name = 'SPARQLWrapper', version = version, description = 'SPARQL Endpoint interface to Python', long_description = 'This is a wrapper around a SPARQL service. It helps in creating the query URI and, possibly, convert the result into a more manageable format.', license = 'W3C SOFTWARE NOTICE AND LICENSE', author = authors, author_email = "ivan at ivan-herman net, sergio at wikier org, carlos.tejo at gmail com, indeyets at gmail com", url = url, download_url = 'https://github.com/RDFLib/sparqlwrapper/releases', platforms = ['any'], packages = ['SPARQLWrapper'], install_requires = _install_requires, classifiers = [ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: W3C License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', ], keywords = 'python sparql rdf rdflib', use_2to3 = True ) sparqlwrapper-1.7.6/test/000077500000000000000000000000001263475016000154135ustar00rootroot00000000000000sparqlwrapper-1.7.6/test/dbpedia.py000077500000000000000000000234061263475016000173650ustar00rootroot00000000000000# -*- coding: utf8 -*- #!/usr/bin/python import inspect import os import sys # prefer local copy to the one which is installed # hack from http://stackoverflow.com/a/6098238/280539 _top_level_path = os.path.realpath(os.path.abspath(os.path.join( os.path.split(inspect.getfile(inspect.currentframe()))[0], ".." ))) if _top_level_path not in sys.path: sys.path.insert(0, _top_level_path) # end of hack import unittest try: from rdflib.graph import ConjunctiveGraph except ImportError: from rdflib import ConjunctiveGraph from SPARQLWrapper import SPARQLWrapper, XML, N3, JSONLD, JSON, POST, GET, SELECT, CONSTRUCT, ASK, DESCRIBE from SPARQLWrapper.Wrapper import _SPARQL_DEFAULT, _SPARQL_XML, _SPARQL_JSON, _SPARQL_POSSIBLE, _RDF_XML, _RDF_N3, _RDF_JSONLD, _RDF_POSSIBLE from SPARQLWrapper.SPARQLExceptions import QueryBadFormed try: from urllib.error import HTTPError # Python 3 except ImportError: from urllib2 import HTTPError # Python 2 try: bytes # Python 2.6 and above except NameError: bytes = str import logging logging.basicConfig() endpoint = "http://dbpedia.org/sparql" prefixes = """ PREFIX rdf: PREFIX rdfs: """ selectQuery = """ SELECT ?label WHERE { rdfs:label ?label . } """ constructQuery = """ CONSTRUCT { _:v rdfs:label ?label . _:v rdfs:comment "this is only a mock node to test library" } WHERE { rdfs:label ?label . } """ queryBadFormed = """ PREFIX prop: PREFIX res: FROM SELECT ?lat ?long WHERE { res:Budapest prop:latitude ?lat; prop:longitude ?long. } """ queryManyPrefixes = """ PREFIX conf: PREFIX meta: PREFIX rdf: PREFIX rdfs: PREFIX xsd: PREFIX owl: PREFIX dc: PREFIX dcterms: PREFIX foaf: PREFIX skos: PREFIX geo: PREFIX dbpedia: PREFIX o: PREFIX p: PREFIX yago: PREFIX units: PREFIX geonames: PREFIX prv: PREFIX prvTypes: PREFIX foo: SELECT ?label WHERE { rdfs:label ?label . } """ class SPARQLWrapperTests(unittest.TestCase): def __generic(self, query, returnFormat, method): sparql = SPARQLWrapper(endpoint) sparql.setQuery(prefixes + query) sparql.setReturnFormat(returnFormat) sparql.setMethod(method) try: result = sparql.query() except HTTPError: # An ugly way to get the exception, but the only one that works # both on Python 2.5 and Python 3. e = sys.exc_info()[1] if e.code == 400: sys.stdout.write("400 Bad Request, probably query is not well formed") elif e.code == 406: sys.stdout.write("406 Not Acceptable, maybe query is not well formed") else: sys.stdout.write(str(e)) sys.stdout.write("\n") return False else: return result def testSelectByGETinXML(self): result = self.__generic(selectQuery, XML, GET) ct = result.info()["content-type"] assert True in [one in ct for one in _SPARQL_XML], ct results = result.convert() results.toxml() def testSelectByPOSTinXML(self): result = self.__generic(selectQuery, XML, POST) ct = result.info()["content-type"] assert True in [one in ct for one in _SPARQL_XML], ct results = result.convert() results.toxml() # Virtuoso returns text/rdf+n3. It MUST return SPARQL Results Document in XML (sparql-results+xml), JSON (sparql-results+json), or CSV/TSV (text/csv or text/tab-separated-values) see http://www.w3.org/TR/sparql11-protocol/#query-success # URI generated http://dbpedia.org/sparql?query=%0A++++PREFIX+rdf%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F1999%2F02%2F22-rdf-syntax-ns%23%3E%0A++++PREFIX+rdfs%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F2000%2F01%2Frdf-schema%23%3E%0A%0A++++SELECT+%3Flabel%0A++++WHERE+%7B%0A++++%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FAsturias%3E+rdfs%3Alabel+%3Flabel+.%0A++++%7D%0A def _testSelectByGETinN3(self): result = self.__generic(selectQuery, N3, GET) ct = result.info()["content-type"] assert True in [one in ct for one in _SPARQL_XML], ct assert True in [one in ct for one in _SPARQL_POSSIBLE], ct results = result.convert() self.assertEqual(type(results), bytes) def testSelectByGETinJSON(self): result = self.__generic(selectQuery, JSON, GET) ct = result.info()["content-type"] assert True in [one in ct for one in _SPARQL_JSON], ct results = result.convert() self.assertEqual(type(results), dict) def testSelectByPOSTinJSON(self): result = self.__generic(selectQuery, JSON, POST) ct = result.info()["content-type"] assert True in [one in ct for one in _SPARQL_JSON], ct results = result.convert() self.assertEqual(type(results), dict) def testSelectByGETinUnknow(self): result = self.__generic(selectQuery, "foo", GET) ct = result.info()["content-type"] assert True in [one in ct for one in _SPARQL_POSSIBLE], ct results = result.convert() def testSelectByPOSTinUnknow(self): result = self.__generic(selectQuery, "bar", POST) ct = result.info()["content-type"] assert True in [one in ct for one in _SPARQL_POSSIBLE], ct results = result.convert() def testConstructByGETinXML(self): result = self.__generic(constructQuery, XML, GET) ct = result.info()["content-type"] assert True in [one in ct for one in _RDF_XML], ct results = result.convert() self.assertEqual(type(results), ConjunctiveGraph) def testConstructByPOSTinXML(self): result = self.__generic(constructQuery, XML, POST) ct = result.info()["content-type"] assert True in [one in ct for one in _RDF_XML], ct results = result.convert() self.assertEqual(type(results), ConjunctiveGraph) def testConstructByGETinN3(self): result = self.__generic(constructQuery, N3, GET) ct = result.info()["content-type"] assert True in [one in ct for one in _RDF_N3], ct results = result.convert() self.assertEqual(type(results), bytes) def testConstructByPOSTinN3(self): result = self.__generic(constructQuery, N3, POST) ct = result.info()["content-type"] assert True in [one in ct for one in _RDF_N3], ct results = result.convert() self.assertEqual(type(results), bytes) # Virtuoso returns application/sparql-results+json. It MUST return an RDF graph [RDF-CONCEPTS] serialized, for example, in the RDF/XML syntax [RDF-XML], or an equivalent RDF graph serialization, for SPARQL Query forms DESCRIBE and CONSTRUCT). See http://www.w3.org/TR/sparql11-protocol/#query-success def _testConstructByGETinJSON(self): result = self.__generic(constructQuery, JSON, GET) ct = result.info()["content-type"] assert True in [one in ct for one in _RDF_POSSIBLE], ct results = result.convert() self.assertEqual(type(results), ConjunctiveGraph) def _testConstructByPOSTinJSON(self): result = self.__generic(constructQuery, _RDF_JSONLD, POST) ct = result.info()["content-type"] assert True in [one in ct for one in _RDF_POSSIBLE], ct results = result.convert() self.assertEqual(type(results), bytes) def testConstructByGETinUnknow(self): result = self.__generic(constructQuery, "foo", GET) ct = result.info()["content-type"] assert True in [one in ct for one in _RDF_POSSIBLE], ct results = result.convert() self.assertEqual(type(results), ConjunctiveGraph) def testConstructByPOSTinUnknow(self): result = self.__generic(constructQuery, "bar", POST) ct = result.info()["content-type"] assert True in [one in ct for one in _RDF_POSSIBLE], ct results = result.convert() self.assertEqual(type(results), ConjunctiveGraph) def testQueryBadFormed(self): self.assertRaises(QueryBadFormed, self.__generic, queryBadFormed, XML, GET) # def testQueryManyPrefixes(self): # result = self.__generic(queryManyPrefixes, XML, GET) def testKeepAlive(self): sparql = SPARQLWrapper(endpoint) sparql.setQuery('SELECT * WHERE {?s ?p ?o} LIMIT 10') sparql.setReturnFormat(JSON) sparql.setMethod(GET) sparql.setUseKeepAlive() sparql.query() sparql.query() if __name__ == "__main__": unittest.main() sparqlwrapper-1.7.6/test/wrapper_test.py000066400000000000000000000514121263475016000205070ustar00rootroot00000000000000# -*- coding: utf-8 -*- import inspect import os import sys import logging logging.basicConfig() import unittest import urllib2 from urlparse import urlparse from urllib2 import Request from cgi import parse_qs # prefer local copy to the one which is installed # hack from http://stackoverflow.com/a/6098238/280539 _top_level_path = os.path.realpath(os.path.abspath(os.path.join( os.path.split(inspect.getfile(inspect.currentframe()))[0], ".." ))) if _top_level_path not in sys.path: sys.path.insert(0, _top_level_path) # end of hack from SPARQLWrapper import SPARQLWrapper from SPARQLWrapper import XML, GET, POST, JSON, JSONLD, N3, TURTLE, RDF, SELECT, INSERT from SPARQLWrapper import URLENCODED, POSTDIRECTLY from SPARQLWrapper import BASIC, DIGEST from SPARQLWrapper.Wrapper import QueryResult, QueryBadFormed, EndPointNotFound, EndPointInternalError # we don't want to let Wrapper do real web-requests. so, we are… # constructing a simple Mock! from urllib2 import HTTPError from io import StringIO import warnings import SPARQLWrapper.Wrapper as _victim class FakeResult(object): def __init__(self, request): self.request = request def urlopener(request): return FakeResult(request) def urlopener_error_generator(code): def urlopener_error(request): raise HTTPError(request.get_full_url, code, '', {}, StringIO(u'')) return urlopener_error def urlopener_check_data_encoding(request): if sys.version < '3': # have to write it like this, for 2to3 compatibility if isinstance(request.data, unicode): raise TypeError else: if isinstance(request.data, str): raise TypeError # DONE class TestCase(unittest.TestCase): def assertIsInstance(self, obj, cls, msg=None, *args, **kwargs): """Python < v2.7 compatibility. Assert 'obj' is instance of 'cls'""" try: f = super(TestCase, self).assertIsInstance except AttributeError: self.assertTrue(isinstance(obj, cls), *args, **kwargs) else: f(obj, cls, *args, **kwargs) def assertIsNone(self, obj, msg=None, *args, **kwargs): """Python < v2.7 compatibility. Assert 'obj' is None""" try: f = super(TestCase, self).assertIsNone except AttributeError: self.assertEqual(obj, None, *args, **kwargs) else: f(obj, *args, **kwargs) class SPARQLWrapper_Test(TestCase): @staticmethod def _get_request(wrapper): return wrapper.query().response.request # possible due to mock above @staticmethod def _get_parameters_from_request(request): if request.get_method() == 'GET': pieces_str = urlparse(request.get_full_url()).query else: if sys.version < '3': pieces_str = request.data else: pieces_str = request.data.decode('ascii') return parse_qs(pieces_str) @staticmethod def _get_request_parameters(wrapper): request = SPARQLWrapper_Test._get_request(wrapper) parameters = SPARQLWrapper_Test._get_parameters_from_request(request) return parameters @staticmethod def _get_request_parameters_as_bytes(wrapper): request = SPARQLWrapper_Test._get_request(wrapper) parameters = SPARQLWrapper_Test._get_parameters_from_request(request) if sys.version < '3': return parameters else: result = {} for k,vs in parameters.iteritems(): result[k] = [v.encode('utf-8') for v in vs] return result def setUp(self): self.wrapper = SPARQLWrapper(endpoint='http://example.org/sparql') _victim.urlopener = urlopener def testConstructor(self): try: SPARQLWrapper() self.fail("SPARQLWrapper constructor should fail without arguments") except TypeError: pass wrapper = SPARQLWrapper(endpoint='http://example.org/sparql/') self.assertEqual(XML, wrapper.returnFormat, 'default return format is XML') self.assertTrue( wrapper.agent.startswith('sparqlwrapper'), 'default user-agent should start with "sparqlwrapper"' ) wrapper = SPARQLWrapper(endpoint='http://example.org/sparql/', returnFormat='wrongformat') self.assertEqual(XML, wrapper.returnFormat, 'default return format is XML') wrapper = SPARQLWrapper(endpoint='http://example.org/sparql/', defaultGraph='http://example.org/default') parameters = self._get_request_parameters(wrapper) self.assertEqual( ['http://example.org/default'], parameters.get('default-graph-uri'), 'default graph is set' ) def testReset(self): self.wrapper.setMethod(POST) self.wrapper.setQuery('CONSTRUCT WHERE {?a ?b ?c}') self.wrapper.setReturnFormat(N3) self.wrapper.addParameter('a', 'b') request = self._get_request(self.wrapper) parameters = self._get_parameters_from_request(request) self.assertEqual('POST', request.get_method()) self.assertTrue(parameters['query'][0].startswith('CONSTRUCT')) self.assertTrue('rdf+n3' in request.get_header('Accept')) self.assertTrue('a' in parameters) self.wrapper.resetQuery() request = self._get_request(self.wrapper) parameters = self._get_parameters_from_request(request) self.assertEqual('GET', request.get_method()) self.assertTrue(parameters['query'][0].startswith('SELECT')) self.assertFalse('rdf+n3' in request.get_header('Accept')) self.assertTrue('sparql-results+xml' in request.get_header('Accept')) self.assertFalse('a' in parameters) def testSetReturnFormat(self): self.assertRaises(ValueError, self.wrapper.setReturnFormat, 'nonexistent format') self.assertEqual(XML, self.wrapper.query().requestedFormat) self.wrapper.setReturnFormat(JSON) self.assertEqual(JSON, self.wrapper.query().requestedFormat) try: import rdflib_jsonld self.wrapper.setReturnFormat(JSONLD) self.assertEqual(JSONLD, self.wrapper.query().requestedFormat) except ImportError: self.assertRaises(ValueError, self.wrapper.setReturnFormat, JSONLD) def testsSupportsReturnFormat(self): self.assertTrue(self.wrapper.supportsReturnFormat(XML)) self.assertTrue(self.wrapper.supportsReturnFormat(JSON)) self.assertTrue(self.wrapper.supportsReturnFormat(TURTLE)) self.assertTrue(self.wrapper.supportsReturnFormat(N3)) self.assertTrue(self.wrapper.supportsReturnFormat(RDF)) self.assertFalse(self.wrapper.supportsReturnFormat('nonexistent format')) try: import rdflib_jsonld self.assertTrue(self.wrapper.supportsReturnFormat(JSONLD)) except ImportError: self.assertFalse(self.wrapper.supportsReturnFormat(JSONLD)) def testAddParameter(self): self.assertFalse(self.wrapper.addParameter('query', 'dummy')) self.assertTrue(self.wrapper.addParameter('param1', 'value1')) self.assertTrue(self.wrapper.addParameter('param1', 'value2')) self.assertTrue(self.wrapper.addParameter('param2', 'value2')) pieces = self._get_request_parameters(self.wrapper) self.assertTrue('param1' in pieces) self.assertEqual(['value1', 'value2'], pieces['param1']) self.assertTrue('param2' in pieces) self.assertEqual(['value2'], pieces['param2']) self.assertNotEqual(['dummy'], 'query') def testSetCredentials(self): request = self._get_request(self.wrapper) self.assertFalse(request.has_header('Authorization')) self.wrapper.setCredentials('login', 'password') request = self._get_request(self.wrapper) self.assertTrue(request.has_header('Authorization')) # expected header for login:password # should succeed for python 3 since pull request #72 self.assertEqual("Basic bG9naW46cGFzc3dvcmQ=", request.get_header('Authorization')) def testSetHTTPAuth(self): self.assertRaises(TypeError, self.wrapper.setHTTPAuth, 123) self.wrapper.setCredentials('login', 'password') request = self._get_request(self.wrapper) self.assertTrue(request.has_header('Authorization')) self.assertIsNone(urllib2._opener) self.wrapper.setHTTPAuth(DIGEST) self.assertIsNone(urllib2._opener) request = self._get_request(self.wrapper) self.assertFalse(request.has_header('Authorization')) self.assertEqual(self.wrapper.http_auth, DIGEST) self.assertIsInstance(urllib2._opener, urllib2.OpenerDirector) self.assertRaises(ValueError, self.wrapper.setHTTPAuth, 'OAuth') self.wrapper.http_auth = "OAuth" self.assertRaises(NotImplementedError, self._get_request, self.wrapper) def testSetQuery(self): self.wrapper.setQuery('PREFIX example: SELECT * WHERE {?s ?p ?v}') self.assertEqual(SELECT, self.wrapper.queryType) self.wrapper.setQuery('PREFIX e: INSERT {e:a e:b e:c}') self.assertEqual(INSERT, self.wrapper.queryType) self.wrapper.setQuery("""#CONSTRUCT {?s ?p ?o} SELECT ?s ?p ?o WHERE {?s ?p ?o}""") self.assertEqual(SELECT, self.wrapper.queryType) with warnings.catch_warnings(record=True) as w: self.wrapper.setQuery('UNKNOWN {e:a e:b e:c}') self.assertEqual(SELECT, self.wrapper.queryType, 'unknown queries result in SELECT') def testSetQueryEncodingIssues(self): #further details from issue #35 query = u'INSERT DATA { "これはテストです" }' query_bytes = query.encode('utf-8') self.wrapper.setMethod(POST) self.wrapper.setRequestMethod(POSTDIRECTLY) self.wrapper.setQuery(query) request = self._get_request(self.wrapper) self.assertEquals(query_bytes, request.data) self.wrapper.setQuery(query_bytes) request = self._get_request(self.wrapper) self.assertEquals(query_bytes, request.data) self.wrapper.setRequestMethod(URLENCODED) self.wrapper.setQuery(query) parameters = self._get_request_parameters_as_bytes(self.wrapper) self.assertEquals(query_bytes, parameters['update'][0]) self.wrapper.setQuery(query_bytes) parameters = self._get_request_parameters_as_bytes(self.wrapper) self.assertEquals(query_bytes, parameters['update'][0]) try: self.wrapper.setQuery(query.encode('sjis')) self.fail() except UnicodeDecodeError: self.assertTrue(True) try: self.wrapper.setQuery({'foo': 'bar'}) self.fail() except TypeError: self.assertTrue(True) def testSetTimeout(self): self.wrapper.setTimeout(10) self.assertEqual(10, self.wrapper.timeout) self.wrapper.resetQuery() self.assertEqual(None, self.wrapper.timeout) def testClearParameter(self): self.wrapper.addParameter('param1', 'value1') self.wrapper.addParameter('param1', 'value2') self.wrapper.addParameter('param2', 'value2') self.assertFalse(self.wrapper.clearParameter('query')) self.assertTrue(self.wrapper.clearParameter('param1')) pieces = self._get_request_parameters(self.wrapper) self.assertFalse('param1' in pieces) self.assertTrue('param2' in pieces) self.assertEqual(['value2'], pieces['param2']) self.assertFalse(self.wrapper.clearParameter('param1'), 'already cleaned') def testSetMethod(self): self.wrapper.setMethod(POST) request = self._get_request(self.wrapper) self.assertEqual("POST", request.get_method()) self.wrapper.setMethod(GET) request = self._get_request(self.wrapper) self.assertEqual("GET", request.get_method()) def testSetRequestMethod(self): self.assertEqual(URLENCODED, self.wrapper.requestMethod) self.wrapper.setRequestMethod(POSTDIRECTLY) self.assertEqual(POSTDIRECTLY, self.wrapper.requestMethod) def testIsSparqlUpdateRequest(self): self.wrapper.setQuery('DELETE WHERE {?s ?p ?o}') self.assertTrue(self.wrapper.isSparqlUpdateRequest()) self.wrapper.setQuery('DELETE DATA { }') self.assertTrue(self.wrapper.isSparqlUpdateRequest()) self.wrapper.setQuery(""" PREFIX example: BASE DELETE WHERE {?s ?p ?o} """) self.assertTrue(self.wrapper.isSparqlUpdateRequest()) self.wrapper.setQuery('WITH DELETE DATA { }') self.assertTrue(self.wrapper.isSparqlUpdateRequest()) self.wrapper.setQuery('INSERT DATA { }') self.assertTrue(self.wrapper.isSparqlUpdateRequest()) self.wrapper.setQuery('WITH INSERT DATA { }') self.assertTrue(self.wrapper.isSparqlUpdateRequest()) self.wrapper.setQuery('CREATE GRAPH ') self.assertTrue(self.wrapper.isSparqlUpdateRequest()) self.wrapper.setQuery('CLEAR GRAPH ') self.assertTrue(self.wrapper.isSparqlUpdateRequest()) self.wrapper.setQuery('DROP GRAPH ') self.assertTrue(self.wrapper.isSparqlUpdateRequest()) self.wrapper.setQuery('MOVE GRAPH TO GRAPH ') self.assertTrue(self.wrapper.isSparqlUpdateRequest()) self.wrapper.setQuery('LOAD INTO GRAPH ') self.assertTrue(self.wrapper.isSparqlUpdateRequest()) self.wrapper.setQuery('COPY TO GRAPH ') self.assertTrue(self.wrapper.isSparqlUpdateRequest()) self.wrapper.setQuery('ADD TO GRAPH ') self.assertTrue(self.wrapper.isSparqlUpdateRequest()) def testIsSparqlQueryRequest(self): self.wrapper.setQuery('SELECT * WHERE {?s ?p ?o}') self.assertTrue(self.wrapper.isSparqlQueryRequest()) self.wrapper.setQuery(""" PREFIX example: BASE ASK WHERE {?s ?p ?o} """) self.assertTrue(self.wrapper.isSparqlQueryRequest()) self.assertFalse(self.wrapper.isSparqlUpdateRequest()) def testQuery(self): qr = self.wrapper.query() self.assertTrue(isinstance(qr, QueryResult)) request = qr.response.request # possible due to mock above self.assertTrue(isinstance(request, Request)) parameters = self._get_parameters_from_request(request) self.assertTrue('query' in parameters) self.assertTrue('update' not in parameters) self.wrapper.setMethod(POST) self.wrapper.setQuery('PREFIX e: INSERT {e:a e:b e:c}') parameters = self._get_request_parameters(self.wrapper) self.assertTrue('update' in parameters) self.assertTrue('query' not in parameters) _victim.urlopener = urlopener_error_generator(400) try: self.wrapper.query() self.fail('should have raised exception') except QueryBadFormed as e: # TODO: check exception-format pass except: self.fail('got wrong exception') _victim.urlopener = urlopener_error_generator(404) try: self.wrapper.query() self.fail('should have raised exception') except EndPointNotFound as e: # TODO: check exception-format pass except: self.fail('got wrong exception') _victim.urlopener = urlopener_error_generator(500) try: self.wrapper.query() self.fail('should have raised exception') except EndPointInternalError as e: # TODO: check exception-format pass except: self.fail('got wrong exception') _victim.urlopener = urlopener_error_generator(999) try: self.wrapper.query() self.fail('should have raised exception') except HTTPError as e: # TODO: check exception-format pass except: self.fail('got wrong exception') def testQueryEncoding(self): query = 'INSERT DATA { "é" }' wrapper = SPARQLWrapper('http://example.com:3030/example') wrapper.setMethod(POST) wrapper.setRequestMethod(URLENCODED) wrapper.setQuery(query) _victim.urlopener = urlopener_check_data_encoding wrapper.query() def testQueryAndConvert(self): _oldQueryResult = _victim.QueryResult class FakeQueryResult(object): def __init__(self, result): pass def convert(self): return True try: _victim.QueryResult = FakeQueryResult result = self.wrapper.queryAndConvert() self.assertEqual(True, result) finally: _victim.QueryResult = _oldQueryResult class QueryResult_Test(unittest.TestCase): def testConstructor(self): qr = QueryResult('result') self.assertEqual('result', qr.response) try: format = qr.requestedFormat self.fail('format is not supposed to be set') except: pass qr = QueryResult(('result', 'format')) self.assertEqual('result', qr.response) self.assertEqual('format', qr.requestedFormat) def testProxyingToResponse(self): class FakeResponse(object): def __init__(self): self.geturl_called = False self.info_called = False self.iter_called = False self.next_called = False def geturl(self): self.geturl_called = True def info(self): self.info_called = True return {"key": "value"} def __iter__(self): self.iter_called = True def next(self): self.next_called = True result = FakeResponse() qr = QueryResult(result) qr.geturl() qr.__iter__() qr.next() self.assertTrue(result.geturl_called) self.assertTrue(result.iter_called) self.assertTrue(result.next_called) info = qr.info() self.assertTrue(result.info_called) self.assertEqual('value', info.__getitem__('KEY'), 'keys should be case-insensitive') def testConvert(self): class FakeResponse(object): def __init__(self, content_type): self.content_type = content_type def info(self): return {"Content-type": self.content_type} def read(self, len): return '' def _mime_vs_type(mime, requested_type): """ @param mime: @param requested_type: @return: number of warnings produced by combo """ with warnings.catch_warnings(record=True) as w: qr = QueryResult((FakeResponse(mime), requested_type)) try: qr.convert() except: pass return len(w) self.assertEqual(0, _mime_vs_type("application/sparql-results+xml", XML)) self.assertEqual(0, _mime_vs_type("application/sparql-results+json", JSON)) self.assertEqual(0, _mime_vs_type("text/n3", N3)) self.assertEqual(0, _mime_vs_type("text/turtle", TURTLE)) self.assertEqual(0, _mime_vs_type("application/ld+json", JSON)) self.assertEqual(0, _mime_vs_type("application/ld+json", JSONLD)) self.assertEqual(0, _mime_vs_type("application/rdf+xml", XML)) self.assertEqual(0, _mime_vs_type("application/rdf+xml", RDF)) self.assertEqual(1, _mime_vs_type("application/x-foo-bar", XML), "invalid mime") self.assertEqual(1, _mime_vs_type("application/sparql-results+xml", N3)) self.assertEqual(1, _mime_vs_type("application/sparql-results+json", XML)) self.assertEqual(1, _mime_vs_type("text/n3", JSON)) self.assertEqual(1, _mime_vs_type("text/turtle", XML)) self.assertEqual(1, _mime_vs_type("application/ld+json", XML)) self.assertEqual(1, _mime_vs_type("application/ld+json", N3)) self.assertEqual(1, _mime_vs_type("application/rdf+xml", JSON)) self.assertEqual(1, _mime_vs_type("application/rdf+xml", N3)) if __name__ == "__main__": unittest.main() sparqlwrapper-1.7.6/tests.sh000077500000000000000000000004151263475016000161350ustar00rootroot00000000000000#!/bin/bash PYTHON_VERSION=`python -c "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));sys.stdout.write(t)";` echo "running tests on python $PYTHON_VERSION.x..." if [[ $PYTHON_VERSION == 3.* ]] ; then . run_tests_py3.sh else nosetests fi