[Python-modules-team] Bug#921027: sparql-wrapper-python: diff for NMU version 1.8.2-0.1

Jonas Smedegaard dr at jones.dk
Tue Feb 12 15:06:28 GMT 2019


Control: tags 921027 + patch
Control: tags 921027 + pending

Dear maintainer,

I've prepared an NMU for sparql-wrapper-python (versioned as 1.8.2-0.1) and
uploaded it to DELAYED/3. Please feel free to tell me if I
should delay it longer.

Regards,

 - Jonas

diff -Nru sparql-wrapper-python-1.7.6/AUTHORS.md sparql-wrapper-python-1.8.2/AUTHORS.md
--- sparql-wrapper-python-1.7.6/AUTHORS.md	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/AUTHORS.md	2018-05-16 22:23:01.000000000 +0200
@@ -23,4 +23,12 @@
 * 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
+* Carlos Martinez-Ortiz ([@cmartinez](https://github.com/cmartinez): improves support for return format HTTP parameter
+* Christian Amsüss ([@chrysn](https://github.com/chrysn)): dependecy fixes
+* Chris Lamb ([@lamby](https://github.com/lamby)): typo
+* Hugo van Kemenade ([@hugovk](https://github.com/hugovk)): update classifiers (Python 3.6)
+* Edward Betts([@EdwardBetts](https://github.com/EdwardBetts)): Correct spelling mistakes
+* Carlos Martínez([@c-martinez](https://github.com/c-martinez)): Mainly support for CSV and TSV results in SPARQL SELECT queries
+* Dan Michael O. Heggø([@danmichaelo](https://github.com/danmichaelo)): update README with SPARQLWrapper2 example
+* Sam Clements([@ borntyping](https://github.com/ borntyping)): Provide hints about setting properly the timeout
 
diff -Nru sparql-wrapper-python-1.7.6/ChangeLog.txt sparql-wrapper-python-1.8.2/ChangeLog.txt
--- sparql-wrapper-python-1.7.6/ChangeLog.txt	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/ChangeLog.txt	2018-05-16 22:23:01.000000000 +0200
@@ -1,5 +1,25 @@
 SPARQLWrapper's changelog:
 -------------------------
+2018-05-26  1.8.2   - Fixed bug (#100)
+                    - Updated doc
+                    - Added Unauthorized exception in SPARQLWrapperExceptions
+                    - Added support for custom HTTP headers (#52)
+                    - Changed timeout setting (#106)
+
+
+2018-02-25  1.8.1   - Update classifiers (Python 3.6)
+                    - Added some documentation about the parameter to indicate the output format
+                    - Fixed typo in width calculation
+                    - Added support for CSV, TSV (PR #98)
+                    - Added support for Only HTTP Content Negotiation (#82)
+
+2016-12-07  1.8.0   - Updated return formats for not content negotiation situations
+                    - Included license in the MANIFEST (issue #76)
+                    - Added explicit support for RDF/XML as allowed format (issue #75)
+                    - Added proper shebang (issue #78)
+                    - Moved keepalive as optional dependency (issue #79)
+                    - Fixed hash check on prefixes (issue #77)
+                    - Fixed epydoc warnings (issue #41)
 
 2015-12-18  1.7.6   - Removed wrong response encoding (issue #70)
                     - Authorization header bug when using Python 3 (issue #71)
diff -Nru sparql-wrapper-python-1.7.6/debian/changelog sparql-wrapper-python-1.8.2/debian/changelog
--- sparql-wrapper-python-1.7.6/debian/changelog	2019-01-01 11:07:53.000000000 +0100
+++ sparql-wrapper-python-1.8.2/debian/changelog	2019-02-12 15:57:58.000000000 +0100
@@ -1,3 +1,19 @@
+sparql-wrapper-python (1.8.2-0.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+
+  [ upstream ]
+  * New release(s).
+    Closes: Bug#921027.
+
+  [ Ondřej Nový ]
+  * Convert git repository from git-dpm to gbp layout.
+
+  [ Jonas Smedegaard ]
+  * Drop patch 0001, adopted upstream.
+
+ -- Jonas Smedegaard <dr at jones.dk>  Tue, 12 Feb 2019 15:57:58 +0100
+
 sparql-wrapper-python (1.7.6-3) unstable; urgency=medium
 
   * Team upload.
diff -Nru sparql-wrapper-python-1.7.6/debian/.git-dpm sparql-wrapper-python-1.8.2/debian/.git-dpm
--- sparql-wrapper-python-1.7.6/debian/.git-dpm	2019-01-01 11:03:52.000000000 +0100
+++ sparql-wrapper-python-1.8.2/debian/.git-dpm	1970-01-01 01:00:00.000000000 +0100
@@ -1,12 +0,0 @@
-# see git-dpm(1) from git-dpm package
-50ce8301ed453915a58dd9403c02dee74f89236d
-50ce8301ed453915a58dd9403c02dee74f89236d
-ecd5c3dc5869e3bc4f0cc7f8c41a8a93eb8ab291
-ecd5c3dc5869e3bc4f0cc7f8c41a8a93eb8ab291
-sparql-wrapper-python_1.7.6.orig.tar.gz
-504cb01474071c547a6413b4f14351783d0826f1
-32973
-# as per https://python-modules.alioth.debian.org/policy.html
-debianTag="debian/%e%v"
-patchedTag="patched/%e%v"
-upstreamTag="upstream/%e%u"
diff -Nru sparql-wrapper-python-1.7.6/debian/patches/0001-Drop-keepalive-from-requirements.txt-Closes-846871.patch sparql-wrapper-python-1.8.2/debian/patches/0001-Drop-keepalive-from-requirements.txt-Closes-846871.patch
--- sparql-wrapper-python-1.7.6/debian/patches/0001-Drop-keepalive-from-requirements.txt-Closes-846871.patch	2019-01-01 11:03:52.000000000 +0100
+++ sparql-wrapper-python-1.8.2/debian/patches/0001-Drop-keepalive-from-requirements.txt-Closes-846871.patch	1970-01-01 01:00:00.000000000 +0100
@@ -1,37 +0,0 @@
-From 50ce8301ed453915a58dd9403c02dee74f89236d Mon Sep 17 00:00:00 2001
-From: chrysn <chrysn at fsfe.org>
-Date: Mon, 5 Dec 2016 19:20:56 +0100
-Subject: Drop keepalive from requirements.txt (Closes: #846871)
-
-As keepalive support is a weak dependency (absence makes keepalive
-enabling only raise a warning and otherwise a no-op), listing it as a
-dependency causes trouble with test setups. Demoting it to an extra
-(feature) dependency.
-
-Bug: https://github.com/RDFLib/sparqlwrapper/pull/79
----
- requirements.txt | 1 -
- setup.py         | 3 +++
- 2 files changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/requirements.txt b/requirements.txt
-index cdd0693..55ec214 100644
---- a/requirements.txt
-+++ b/requirements.txt
-@@ -1,2 +1 @@
- rdflib>=4.0
--keepalive>=0.5
-diff --git a/setup.py b/setup.py
-index 5198f46..035525f 100755
---- a/setup.py
-+++ b/setup.py
-@@ -57,6 +57,9 @@ setup(
-       platforms = ['any'],
-       packages = ['SPARQLWrapper'],
-       install_requires = _install_requires,
-+      extras_require = {
-+        'keepalive': ['keepalive>=0.5'],
-+      },
-       classifiers =  [
-         'Development Status :: 5 - Production/Stable',
-         'Intended Audience :: Developers',
diff -Nru sparql-wrapper-python-1.7.6/debian/patches/series sparql-wrapper-python-1.8.2/debian/patches/series
--- sparql-wrapper-python-1.7.6/debian/patches/series	2019-01-01 11:03:52.000000000 +0100
+++ sparql-wrapper-python-1.8.2/debian/patches/series	1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-0001-Drop-keepalive-from-requirements.txt-Closes-846871.patch
diff -Nru sparql-wrapper-python-1.7.6/.gitignore sparql-wrapper-python-1.8.2/.gitignore
--- sparql-wrapper-python-1.7.6/.gitignore	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/.gitignore	2018-05-16 22:23:01.000000000 +0200
@@ -6,3 +6,6 @@
 doc
 .idea
 *.iml
+.project
+.pydevproject
+.settings/
\ Intet linjeskift ved filafslutning
diff -Nru sparql-wrapper-python-1.7.6/Makefile sparql-wrapper-python-1.8.2/Makefile
--- sparql-wrapper-python-1.7.6/Makefile	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/Makefile	2018-05-16 22:23:01.000000000 +0200
@@ -11,3 +11,6 @@
 
 clean:
 	rm -rf $(DOCDIR)
+	rm -rf build
+	find . -name "*.pyc" -delete
+
diff -Nru sparql-wrapper-python-1.7.6/MANIFEST.in sparql-wrapper-python-1.8.2/MANIFEST.in
--- sparql-wrapper-python-1.7.6/MANIFEST.in	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/MANIFEST.in	2018-05-16 22:23:01.000000000 +0200
@@ -3,3 +3,4 @@
 include test/*.py
 include scripts/*.py
 include requirements.txt
+include LICENSE.txt
diff -Nru sparql-wrapper-python-1.7.6/README.md sparql-wrapper-python-1.8.2/README.md
--- sparql-wrapper-python-1.7.6/README.md	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/README.md	2018-05-16 22:23:01.000000000 +0200
@@ -3,7 +3,64 @@
 [![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` is a simple Python wrapper around a SPARQL service to remotelly execute your queries.
+It helps in creating the query invokation and, possibly, convert the result into a more manageable format. 
+
+
+## Installation
+
+From PyPi:
+
+    $ pip install sparqlwrapper
+
+
+From GitHub::
+
+    $ pip install git+https://github.com/rdflib/sparqlwrapper#egg=sparqlwrapper
+
+From Debian
+
+    $ sudo apt-get install python-sparqlwrapper
+
+## Usage
+
+Create an instance to execute your query:
+
+```python
+from SPARQLWrapper import SPARQLWrapper, JSON
+
+sparql = SPARQLWrapper("http://dbpedia.org/sparql")
+sparql.setQuery("""
+    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+    SELECT ?label
+    WHERE { <http://dbpedia.org/resource/Asturias> rdfs:label ?label }
+""")
+sparql.setReturnFormat(JSON)
+results = sparql.query().convert()
+
+for result in results["results"]["bindings"]:
+    print('%s: %s' % (result["label"]["xml:lang"], result["label"]["value"]))
+```
+
+There is also a `SPARQLWrapper2` class that works with JSON SELECT results only and wraps the results to make processing of average queries a bit simpler.
+
+```python
+from SPARQLWrapper import SPARQLWrapper2
+
+sparql = SPARQLWrapper2("http://dbpedia.org/sparql")
+sparql.setQuery("""
+    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+    SELECT ?label
+    WHERE { <http://dbpedia.org/resource/Asturias> rdfs:label ?label }
+""")
+
+for result in sparql.query().bindings:
+    print('%s: %s' % (result["label"].lang, result["label"].value))
+```
+
+## Source code
+
+The source distribution contains:
 
 * `SPARQLWrapper`: the Python library. You should copy the directory somewhere into your `PYTHONPATH`. Alternatively, you can also run the distutils scripts:
 
@@ -13,3 +70,11 @@
   
 * `script`: some scripts to run the library against some SPARQL endpoints.
 
+## Documentation
+
+The SPARQLWrapper documentation is available online at https://rdflib.github.io/sparqlwrapper/doc/latest/.
+
+## License
+
+The package is licensed under [W3C license](https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document).
+
diff -Nru sparql-wrapper-python-1.7.6/requirements.txt sparql-wrapper-python-1.8.2/requirements.txt
--- sparql-wrapper-python-1.7.6/requirements.txt	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/requirements.txt	2018-05-16 22:23:01.000000000 +0200
@@ -1,2 +1 @@
 rdflib>=4.0
-keepalive>=0.5
diff -Nru sparql-wrapper-python-1.7.6/run_tests_py3.sh sparql-wrapper-python-1.8.2/run_tests_py3.sh
--- sparql-wrapper-python-1.7.6/run_tests_py3.sh	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/run_tests_py3.sh	2018-05-16 22:23:01.000000000 +0200
@@ -1,15 +1,23 @@
 #!/bin/bash
 
+# FOR MANUAL RUNNING, IT REQUIRES modules: 2to3, python3-setuptools, python3-nose
+# REMEMBER to remove PYTHON_VERSION SUFFIX
+# Please, install the required tools previously:
+# $ sudo apt-get install 2to3
+# $ sudo apt-get install python3-setuptools
+# $ sudo apt-get install python3-nose
+
 function cmdcheck() {
-    command -v $0 >/dev/null 2>&1 || { echo >&2 "ERROR: command $0 required but it's not installed; aborting..."; exit -1; }
+    command -v $1 >/dev/null 2>&1 || { echo >&2 "ERROR: command $1 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
+#cmdcheck 2to3-$PYTHON_VERSION
+#cmdcheck nosetests-$PYTHON_VERSION
+#cmdcheck nosetests3
 
 python3 setup.py build
 
@@ -24,7 +32,11 @@
 
 cd build/py3_testing
 
-2to3-$PYTHON_VERSION -wn --no-diffs test
+if command -v 2to3-$PYTHON_VERSION; then
+    2to3-$PYTHON_VERSION -wn --no-diffs test
+else
+    2to3 -wn --no-diffs test
+fi
 
 sed -i.bak s/urllib2._opener/urllib.request._opener/g test/wrapper_test.py
 
diff -Nru sparql-wrapper-python-1.7.6/scripts/example-dbpedia.py sparql-wrapper-python-1.8.2/scripts/example-dbpedia.py
--- sparql-wrapper-python-1.7.6/scripts/example-dbpedia.py	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/scripts/example-dbpedia.py	2018-05-16 22:23:01.000000000 +0200
@@ -28,4 +28,3 @@
 sparql.setReturnFormat(JSON)
 results = sparql.query()
 results.print_results()
-
diff -Nru sparql-wrapper-python-1.7.6/scripts/example-optional.py sparql-wrapper-python-1.8.2/scripts/example-optional.py
--- sparql-wrapper-python-1.7.6/scripts/example-optional.py	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/scripts/example-optional.py	2018-05-16 22:23:01.000000000 +0200
@@ -1,7 +1,7 @@
 #!/usr/bin/python
 # -*- coding: utf-8 -*-
 
-from SPARQLWrapper import SPARQLWrapper, JSON, XML, N3, RDF
+from SPARQLWrapper import SPARQLWrapper, JSON
 
 sparql = SPARQLWrapper("http://dbpedia.org/sparql")
 sparql.setQuery("""
diff -Nru sparql-wrapper-python-1.7.6/scripts/example.py sparql-wrapper-python-1.8.2/scripts/example.py
--- sparql-wrapper-python-1.7.6/scripts/example.py	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/scripts/example.py	2018-05-16 22:23:01.000000000 +0200
@@ -1,7 +1,7 @@
 #!/usr/bin/python
 # -*- coding: utf-8 -*-
 
-from SPARQLWrapper import SPARQLWrapper, JSON, XML, N3, RDF
+from SPARQLWrapper import SPARQLWrapper, JSON, XML, N3, RDF, CSV, TSV
 
 sparql = SPARQLWrapper("http://dbpedia.org/sparql")
 sparql.setQuery("""
@@ -35,3 +35,14 @@
 results = sparql.query().convert()
 print results.serialize()
 
+# CSV example
+print '\n\n*** CSV Example'
+sparql.setReturnFormat(CSV)
+results = sparql.query().convert()
+print results
+
+# TSV example
+print '\n\n*** TSV Example'
+sparql.setReturnFormat(TSV)
+results = sparql.query().convert()
+print results
diff -Nru sparql-wrapper-python-1.7.6/scripts/sparql.py sparql-wrapper-python-1.8.2/scripts/sparql.py
--- sparql-wrapper-python-1.7.6/scripts/sparql.py	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/scripts/sparql.py	2018-05-16 22:23:01.000000000 +0200
@@ -1,83 +1,84 @@
 #!/usr/bin/python
 # -*- coding: utf-8 -*-
 
-
-from SPARQLWrapper import SPARQLWrapper2, SPARQLWrapper, TURTLE
-import sys, getopt
+import sys
+import getopt
+from SPARQLWrapper import SPARQLWrapper2
 
 localSparqler = "http://localhost:2020/sparql"
 localVirtuoso = "http://localhost:8890/sparql"
 
-def main(server,query,sponge=False) :
+def main(server, query, sponge=False):
     sparql = SPARQLWrapper2(server)
-    if sponge : sparql.addExtraURITag("should-sponge","grab-everything")
-        
+    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 :
+    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 :
+                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: <<None>>" % v
             print str.encode('utf-8')
         print
-            
-    
-    
+
+
+
 # -------------------------------------------------------------------------------------------------------------
-server   = localSparqler
-query    = ""
-sponge  = False
-usagetxt="""%s [-s] [-u url] [file]
+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() :
+def usage():
     print usagetxt % sys.argv[0]
     sys.exit(1)
 
-if __name__ == '__main__' :
-    if len(sys.argv) == 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" :
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], "shu:pv")
+        for o, a in opts:
+            if o == "-s":
                 server = localSparqler
-            elif o == "-v" :
+            elif o == "-v":
                 server = localVirtuoso
                 sponge = True
-            elif o == "-h" :
+            elif o == "-h":
                 print usage
                 sys.exit(0)
-            elif o == "-u" :
+            elif o == "-u":
                 server = a
-            elif o == "-p" :
+            elif o == "-p":
                 sponge = True
-        if query == "" and len(args) > 0 :
+        if query == "" and len(args) > 0:
             inp = file(args[0])
             query = ""
-            for l in inp :
+            for l in inp:
                 query += l
-    except :
+    except:
         usage()
-    if query == "" : usage()
-    main(server,query,sponge)
-
+    if query == "":
+        usage()
+    main(server, query, sponge)
diff -Nru sparql-wrapper-python-1.7.6/setup.py sparql-wrapper-python-1.8.2/setup.py
--- sparql-wrapper-python-1.7.6/setup.py	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/setup.py	2018-05-16 22:23:01.000000000 +0200
@@ -1,3 +1,4 @@
+#!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
 import sys
@@ -51,20 +52,30 @@
       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,
+      extras_require = {
+        'keepalive': ['keepalive>=0.5'],
+      },
       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 :: 2.7',
         'Programming Language :: Python :: 3',
+        'Programming Language :: Python :: 3.3',
+        'Programming Language :: Python :: 3.4',
+        'Programming Language :: Python :: 3.5',
+        'Programming Language :: Python :: 3.6',
+        'Programming Language :: Python :: Implementation :: CPython',
+        'Programming Language :: Python :: Implementation :: PyPy',
+        'Topic :: Software Development :: Libraries :: Python Modules',
       ],
-      keywords = 'python sparql rdf rdflib',
+      keywords = ['python', 'sparql', 'rdf', 'rdflib'],
       use_2to3 = True
 )
diff -Nru sparql-wrapper-python-1.7.6/SPARQLWrapper/__init__.py sparql-wrapper-python-1.8.2/SPARQLWrapper/__init__.py
--- sparql-wrapper-python-1.7.6/SPARQLWrapper/__init__.py	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/SPARQLWrapper/__init__.py	2018-05-16 22:23:01.000000000 +0200
@@ -3,24 +3,23 @@
 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.
+possibly, convert the result into a more manageable format.
 
 The following packages are used:
 
-  - for JSON, the U{simplejson<http://cheeseshop.python.org/pypi/simplejson>} package: C{http://cheeseshop.python.org/pypi/simplejson}
-  - for RDF/XML, the U{RDFLib<http://rdflib.net>}: C{http://rdflib.net}
+  - for JSON, the U{simplejson<https://pypi.python.org/pypi/simplejson>} package
+  - for RDF/XML, the U{RDFLib<https://rdflib.readthedocs.io>}
 
 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/<http://www.ivan-herman.net/Misc/PythonStuff/SPARQL/>}. It is also
-available from U{Sourceforge<https://sourceforge.net/projects/sparql-wrapper/>} under the project named "C{sparql-wrapper}".
+U{https://github.com/RDFLib/sparqlwrapper/releases<https://github.com/RDFLib/sparqlwrapper/releases>}.
 Documentation is included in the distribution.
 
 
-Basic QUERY Usage
-=================
+Basic QUERY Usage (SELECT)
+==========================
 
 Simple query
 ------------
@@ -30,9 +29,9 @@
 
  from SPARQLWrapper import SPARQLWrapper
  queryString = "SELECT * WHERE { ?s ?p ?o. }"
- sparql = SPARQLWrapper("http://localhost:2020/sparql")
+ sparql = SPARQLWrapper("http://example.org/sparql")
  # add a default graph, though that can also be part of the query string
- sparql.addDefaultGraph("http://www.example.com/data.rdf")
+ sparql.addDefaultGraph("http://www.example.org/graph-selected")
  sparql.setQuery(queryString)
  try :
     ret = sparql.query()
@@ -40,7 +39,7 @@
  except :
     deal_with_the_exception()
 
-If C{SPARQLWrapper("http://localhost:2020/sparql",returnFormat=SPARQLWrapper.JSON)} was used, the result would be in
+If C{SPARQLWrapper("http://example.org/sparql",returnFormat=SPARQLWrapper.JSON)} was used, the result would be in
 U{JSON format<http://www.w3.org/TR/rdf-sparql-json-res/>} instead of XML (provided the sparql
 processor can return JSON).
 
@@ -51,7 +50,8 @@
 
   - for XML, the U{xml.dom.minidom<http://docs.python.org/library/xml.dom.minidom.html>} (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<http://cheeseshop.python.org/pypi/simplejson>} package (C{http://cheeseshop.python.org/pypi/simplejson}) to generate a Python dictionary
+  - for JSON, the U{simplejson<https://pypi.python.org/pypi/simplejson>} package (C{https://pypi.python.org/pypi/simplejson}) to generate a Python dictionary
+  - for CSV/TSV, a simple C{string}
 
 There are two ways to generate this conversion:
 
@@ -83,9 +83,9 @@
 
  from SPARQLWrapper import SPARQLWrapper2
  queryString = "SELECT ?subj ?prop WHERE { ?subj ?prop ?o. }"
- sparql = SPARQLWrapper2("http://localhost:2020/sparql")
+ sparql = SPARQLWrapper2("http://example.org/sparql")
  # add a default graph, though that can also be in the query string
- sparql.addDefaultGraph("http://www.example.com/data.rdf")
+ sparql.addDefaultGraph("http://www.example.org/graph-selected")
  sparql.setQuery(queryString)
  try :
      ret = sparql.query()
@@ -103,9 +103,9 @@
 
  from SPARQLWrapper import SPARQLWrapper2
  queryString = "SELECT ?subj ?o ?opt WHERE { ?subj <http://a.b.c> ?o. OPTIONAL { ?subj <http://d.e.f> ?opt }}"
- sparql = SPARQLWrapper2("http://localhost:2020/sparql")
+ sparql = SPARQLWrapper2("http://example.org/sparql")
  # add a default graph, though that can also be in the query string
- sparql.addDefaultGraph("http://www.example.com/data.rdf")
+ sparql.addDefaultGraph("http://www.example.org/graph-selected")
  sparql.setQuery(queryString)
  try :
      ret = sparql.query()
@@ -131,12 +131,13 @@
 ========================
 
 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 
+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<http://rdflib.net>} (C{http://rdflib.net}) package is used to convert the result into a C{Graph} instance.
+For RDF/XML and JSON-LD, the U{RDFLib<https://rdflib.readthedocs.io>} package is used to convert the result into a C{Graph} instance.
+For Turtle, a string is returned.
 
 GET or POST
 ===========
@@ -147,8 +148,6 @@
 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
 ===============
 
@@ -156,17 +155,17 @@
 
 @summary: Python interface to SPARQL services
 @see: U{SPARQL Specification<http://www.w3.org/TR/rdf-sparql-query/>}
- at authors: U{Ivan Herman<http://www.ivan-herman.net>}, U{Sergio Fernández<http://www.wikier.org>}, U{Carlos Tejo Alonso<http://www.dayures.net>}
+ at authors: U{Ivan Herman<http://www.ivan-herman.net>}, U{Sergio Fernández<http://www.wikier.org>}, U{Carlos Tejo Alonso<http://www.dayures.net>}, U{Alexey Zakhlestin<https://indeyets.ru/>}
 @organization: U{World Wide Web Consortium<http://www.w3.org>}, U{Salzburg Research<http://www.salzburgresearch.at>} and U{Foundation CTIC<http://www.fundacionctic.org/>}.
 @license: U{W3C® SOFTWARE NOTICE AND LICENSE<href="http://www.w3.org/Consortium/Legal/copyright-software">}
- at requires: U{simplejson<http://cheeseshop.python.org/pypi/simplejson>} package.
- at requires: U{RDFLib<http://rdflib.net>} package.
+ at requires: U{simplejson<https://pypi.python.org/pypi/simplejson>} package.
+ at requires: U{RDFLib<https://rdflib.readthedocs.io>} package.
 """
 
-__version__ = "1.7.6"
+__version__ = "1.8.2"
 """The version of SPARQLWrapper"""
 
-__authors__  = "Ivan Herman, Sergio Fernández, Carlos Tejo Alonso, Alexey Zakhlestin"
+__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"
@@ -178,14 +177,14 @@
 __contact__ = "rdflib-dev at googlegroups.com"
 """Mail list to contact to other people RDFLib and SPARQLWrappers folks and developers"""
 
-__date__    = "2015-12-18"
+__date__ = "2018-05-16"
 """Last update"""
 
-__agent__   = "sparqlwrapper %s (rdflib.github.io/sparqlwrapper)" % __version__
+__agent__ = "sparqlwrapper %s (rdflib.github.io/sparqlwrapper)" % __version__
 
 
 from Wrapper import SPARQLWrapper
-from Wrapper import XML, JSON, TURTLE, N3, JSONLD, RDF
+from Wrapper import XML, JSON, TURTLE, N3, JSONLD, RDF, RDFXML, CSV, TSV
 from Wrapper import GET, POST
 from Wrapper import SELECT, CONSTRUCT, ASK, DESCRIBE, INSERT, DELETE
 from Wrapper import URLENCODED, POSTDIRECTLY
diff -Nru sparql-wrapper-python-1.7.6/SPARQLWrapper/KeyCaseInsensitiveDict.py sparql-wrapper-python-1.8.2/SPARQLWrapper/KeyCaseInsensitiveDict.py
--- sparql-wrapper-python-1.7.6/SPARQLWrapper/KeyCaseInsensitiveDict.py	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/SPARQLWrapper/KeyCaseInsensitiveDict.py	2018-05-16 22:23:01.000000000 +0200
@@ -18,12 +18,12 @@
             self[k] = v
 
     def __setitem__(self, key, value):
-        if (hasattr(key, "lower")):
+        if hasattr(key, "lower"):
             key = key.lower()
         dict.__setitem__(self, key, value)
 
     def __getitem__(self, key):
-        if (hasattr(key, "lower")):
+        if hasattr(key, "lower"):
             key = key.lower()
         return dict.__getitem__(self, key)
 
@@ -31,4 +31,3 @@
         if hasattr(key, "lower"):
             key = key.lower()
         dict.__delitem__(self, key)
-
diff -Nru sparql-wrapper-python-1.7.6/SPARQLWrapper/SmartWrapper.py sparql-wrapper-python-1.8.2/SPARQLWrapper/SmartWrapper.py
--- sparql-wrapper-python-1.7.6/SPARQLWrapper/SmartWrapper.py	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/SPARQLWrapper/SmartWrapper.py	2018-05-16 22:23:01.000000000 +0200
@@ -8,11 +8,10 @@
 @requires: U{RDFLib<http://rdflib.net>} package.
 """
 
-import SPARQLWrapper
-from SPARQLWrapper.Wrapper import JSON, SELECT
 import urllib2
 from types import *
-
+import SPARQLWrapper
+from SPARQLWrapper.Wrapper import JSON, SELECT
 
 ######################################################################################
 
@@ -36,29 +35,29 @@
     @ivar datatype: Datatype of the binding, or C{None} if not set
     @type datatype: string (URI)
     """
-    URI          = "uri"
-    Literal      = "literal"
+    URI = "uri"
+    Literal = "literal"
     TypedLiteral = "typed-literal"
-    BNODE        = "bnode"
+    BNODE = "bnode"
 
-    def __init__(self,variable,binding) :
+    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.variable = variable
+        self.value = binding['value']
+        self.type = binding['type']
+        self.lang = None
+        self.datatype = None
+        try:
             self.lang = binding['xml:lang']
-        except :
+        except:
             # no lang is set
             pass
-        try :
+        try:
             self.datatype = binding['datatype']
-        except :
+        except:
             pass
 
     def __repr__(self):
@@ -89,50 +88,50 @@
     @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) :
+    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 :
+        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'] :
+        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 :
+                for key in self.variables:
+                    if key in b:
                         # there is a real binding for this key
-                        newBind[key] = Value(key,b[key])
+                        newBind[key] = Value(key, b[key])
                 self.bindings.append(newBind)
-        except :
+        except:
             pass
 
         self.askResult = False
-        try :
+        try:
             self.askResult = self.fullResult["boolean"]
-        except :
+        except:
             pass
 
-    def getValues(self,key) :
+    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 :
+        try:
             return [b[key] for b in self[key]]
-        except :
+        except:
             return []
 
-    def __contains__(self,key) :
+    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.
 
@@ -144,26 +143,30 @@
         @return: whether there is a binding of the variable in the return
         @rtype: Boolean
         """
-        if len(self.bindings) == 0 : return False
+        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 :
+            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 ] :
+                if False in [k in b for k in key]:
                     # this is not a binding for the key combination, move on...
                     continue
-                else :
+                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
+        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) :
+    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.
@@ -182,49 +185,55 @@
         @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
+        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 :
+        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) :
+                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 :
+        no_keys = []
+        if type(key) is slice:
             # Note: None for start or stop is all right
-            if key.start :
+            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 :
+                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 :
+        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 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 :
+        if len(retval) == 0:
             raise IndexError
         return retval
 
-    def convert(self) :
+    def convert(self):
         """This is just a convenience method, returns C{self}.
 
         Although C{Binding} is not a subclass of L{QueryResult<SPARQLWrapper.Wrapper.QueryResult>}, it is returned as a result by
@@ -238,7 +247,7 @@
 
 
 class SPARQLWrapper2(SPARQLWrapper.SPARQLWrapper):
-    """Subclass of L{Wrapper<SPARQLWrapper.SPARQLWrapper>} that works with a JSON SELECT return result only. The query result 
+    """Subclass of L{Wrapper<SPARQLWrapper.SPARQLWrapper>} 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):
         """
@@ -246,7 +255,7 @@
         cannot be set (it is defaulted to L{JSON<Wrapper.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
+        @param 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)
@@ -254,7 +263,7 @@
     def setReturnFormat(self, format):
         """Set the return format (overriding the L{inherited method<SPARQLWrapper.SPARQLWrapper.setReturnFormat>}).
         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.
+        just to avoid possible errors by erroneously setting the return format.
         When using this class, the user can safely ignore this call.
         @param format: return format
         """
diff -Nru sparql-wrapper-python-1.7.6/SPARQLWrapper/SPARQLExceptions.py sparql-wrapper-python-1.8.2/SPARQLWrapper/SPARQLExceptions.py
--- sparql-wrapper-python-1.7.6/SPARQLWrapper/SPARQLExceptions.py	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/SPARQLWrapper/SPARQLExceptions.py	2018-05-16 22:23:01.000000000 +0200
@@ -16,8 +16,8 @@
     Base class for SPARQL Wrapper exceptions
     """
 
-    msg = "an exception has occured"
-    
+    msg = "an exception has occurred"
+
     def __init__(self, response=None):
         if response:
             formatted_msg = "%s: %s. \n\nResponse:\n%s" % (self.__class__.__name__, self.msg, response)
@@ -48,3 +48,11 @@
     """
 
     msg = "it was impossible to connect with the endpoint in that address, check if it is correct"
+
+class Unauthorized(SPARQLWrapperException):
+    """
+    Access is denied due to invalid credentials (unauthorized).
+    @since: 1.8.2
+    """
+
+    msg = "access is denied due to invalid credentials (unauthorized). Check the credentials"
diff -Nru sparql-wrapper-python-1.7.6/SPARQLWrapper/SPARQLUtils.py sparql-wrapper-python-1.8.2/SPARQLWrapper/SPARQLUtils.py
--- sparql-wrapper-python-1.7.6/SPARQLWrapper/SPARQLUtils.py	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/SPARQLWrapper/SPARQLUtils.py	1970-01-01 01:00:00.000000000 +0100
@@ -1,29 +0,0 @@
-# -*- coding: utf8 -*-
-
-"""
-
-SPARQL Wrapper Utils
-
- at authors: U{Ivan Herman<http://www.ivan-herman.net>}, U{Sergio Fernández<http://www.wikier.org>}, U{Carlos Tejo Alonso<http://www.dayures.net>}
- at organization: U{World Wide Web Consortium<http://www.w3.org>} and U{Foundation CTIC<http://www.fundacionctic.org/>}.
- at license: U{W3C SOFTWARE NOTICE AND LICENSE<href="http://www.w3.org/Consortium/Legal/copyright-software">}
-
-"""
-
-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
-
diff -Nru sparql-wrapper-python-1.7.6/SPARQLWrapper/Wrapper.py sparql-wrapper-python-1.8.2/SPARQLWrapper/Wrapper.py
--- sparql-wrapper-python-1.7.6/SPARQLWrapper/Wrapper.py	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/SPARQLWrapper/Wrapper.py	2018-05-16 22:23:01.000000000 +0200
@@ -4,9 +4,13 @@
 """
 @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.
+ at var RDFXML: to be used to set the return format to RDF/XML explicitly.
 @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
+ at var CSV: to be used to set the return format to CSV
+ at var TSV: to be used to set the return format to TSV
+ at var JSONLD: to be used to set the return format to JSON-LD
 
 @var POST: to be used to set HTTP POST
 @var GET: to be used to set HTTP GET. This is the default.
@@ -16,6 +20,20 @@
 @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.
 
+ at var INSERT: to be used to set the query type to INSERT.
+ at var DELETE: to be used to set the query type to DELETE.
+ at var CREATE: to be used to set the query type to CREATE.
+ at var CLEAR: to be used to set the query type to CLEAR.
+ at var DROP: to be used to set the query type to DROP.
+ at var LOAD: to be used to set the query type to LOAD.
+ at var COPY: to be used to set the query type to COPY.
+ at var MOVE: to be used to set the query type to MOVE.
+ at var ADD: to be used to set the query type to ADD.
+
+
+ at var BASIC: BASIC HTTP Authentication method
+ at var DIGEST: DIGEST HTTP Authentication method
+
 @see: U{SPARQL Specification<http://www.w3.org/TR/rdf-sparql-query/>}
 @authors: U{Ivan Herman<http://www.ivan-herman.net>}, U{Sergio Fernández<http://www.wikier.org>}, U{Carlos Tejo Alonso<http://www.dayures.net>}
 @organization: U{World Wide Web Consortium<http://www.w3.org>}, U{Salzburg Research<http://www.salzburgresearch.at>} and U{Foundation CTIC<http://www.fundacionctic.org/>}.
@@ -26,7 +44,6 @@
 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
@@ -34,22 +51,108 @@
 
 import json
 from KeyCaseInsensitiveDict import KeyCaseInsensitiveDict
-from SPARQLExceptions import QueryBadFormed, EndPointNotFound, EndPointInternalError
-from SPARQLUtils import deprecated
+from SPARQLExceptions import QueryBadFormed, EndPointNotFound, EndPointInternalError, Unauthorized
 from SPARQLWrapper import __agent__
 
-#  Possible output format keys...
+#  From <https://www.w3.org/TR/sparql11-protocol/#query-success>
+#  The response body of a successful query operation with a 2XX response is either:
+#  * SELECT and ASK: a SPARQL Results Document in XML, JSON, or CSV/TSV format.
+#  * DESCRIBE and CONSTRUCT: an RDF graph serialized, for example, in the RDF/XML syntax, or an equivalent RDF graph serialization.
+#
+#  Possible parameter keys and values...
+#  Examples:
+#  - ClioPatria: the SWI-Prolog Semantic Web Server <http://cliopatria.swi-prolog.org/home>
+#    * Parameter key: "format" <http://cliopatria.swi-prolog.org/help/http>
+#    * Parameter value must have one of these values: "rdf+xml", "json", "csv", "application/sparql-results+xml" or "application/sparql-results+json".
+#
+#  - OpenLink Virtuoso  <http://virtuoso.openlinksw.com>
+#    * Parameter key: "format" or "output"
+#    * Parameter value, like directly:
+#      "text/html" (HTML), "text/x-html+tr" (HTML (Faceted Browsing Links)), "application/vnd.ms-excel"
+#      "application/sparql-results+xml" (XML), "application/sparql-results+json", (JSON)
+#      "application/javascript" (Javascript), "text/turtle" (Turtle), "application/rdf+xml" (RDF/XML)
+#      "text/plain" (N-Triples), "text/csv" (CSV), "text/tab-separated-values" (TSV)
+#    * Parameter value, like indirectly:
+#      "HTML" (alias text/html), "JSON" (alias application/sparql-results+json), "XML" (alias application/sparql-results+xml), "TURTLE" (alias text/rdf+n3), JavaScript (alias application/javascript)
+#       See  <http://virtuoso.openlinksw.com/dataspace/doc/dav/wiki/Main/VOSSparqlProtocol#Additional HTTP Response Formats -- SELECT>
+#
+#  - Fuseki (formerly there was Joseki) <https://jena.apache.org/documentation/serving_data/>
+#    * Parameter key: "format" or "output"
+#      See Fuseki 1: https://github.com/apache/jena/blob/master/jena-fuseki1/src/main/java/org/apache/jena/fuseki/HttpNames.java
+#      See Fuseki 2: https://github.com/apache/jena/blob/master/jena-arq/src/main/java/org/apache/jena/riot/web/HttpNames.java
+#    * Fuseki 1 - Short names for "output=" : "json", "xml", "sparql", "text", "csv", "tsv", "thrift"
+#      See <https://github.com/apache/jena/blob/master/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ResponseResultSet.java>
+#    * Fuseki 2 - Short names for "output=" : "json", "xml", "sparql", "text", "csv", "tsv", "thrift"
+#      See <https://github.com/apache/jena/blob/master/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseResultSet.java>
+#
+#  - Eclipse RDF4J (formerly known as Sesame) <http://rdf4j.org/>
+#    * Uses only content negotiation (no URL parameters).
+#    * See <http://rdf4j.org/doc/the-rdf4j-server-rest-api/#The_QUERY_operation>
+#
+#  - RASQAL <http://librdf.org/rasqal/>
+#    * Parameter key: "results"
+#    * Uses roqet as RDF query utility
+#      For variable bindings, the values of FORMAT vary upon what Rasqal supports but include simple
+#      for a simple text format (default), xml for the SPARQL Query Results XML format, csv for SPARQL CSV,
+#      tsv for SPARQL TSV, rdfxml and turtle for RDF syntax formats, and json for a JSON version of the results.
+#
+#      For RDF graph results, the values of FORMAT are ntriples (N-Triples, default),
+#      rdfxml-abbrev (RDF/XML Abbreviated), rdfxml (RDF/XML), turtle (Turtle),
+#      json (RDF/JSON resource centric), json-triples (RDF/JSON triples) or
+#      rss-1.0 (RSS 1.0, also an RDF/XML syntax).
+#
+#      See <http://librdf.org/rasqal/roqet.html>
+#
+#  - Marklogic <http://marklogic.com>
+#    * Uses content negotiation (no URL parameters).
+#    * You can use following methods to query triples <https://docs.marklogic.com/guide/semantics/semantic-searches#chapter>:
+#      - SPARQL mode in Query Console. For details, see Querying Triples with SPARQL
+#      - XQuery using the semantics functions, and Search API, or a combination of XQuery and SPARQL. For details, see Querying Triples with XQuery or JavaScript.
+#      - HTTP via a SPARQL endpoint. For details, see Using Semantics with the REST Client API.
+#    * Formats are specified as part of the HTTP Accept headers of the REST request. <https://docs.marklogic.com/guide/semantics/REST#id_92428>
+#      - When you query the SPARQL endpoint with REST Client APIs, you can specify the result output format.  <https://docs.marklogic.com/guide/semantics/REST#id_54258>
+#        The response type format depends on the type of query and the MIME type in the HTTP Accept header.
+#      - This table describes the MIME types and Accept Header/Output formats (MIME type) for different types of SPARQL queries. See <https://docs.marklogic.com/guide/semantics/REST#id_54258> and <https://docs.marklogic.com/guide/semantics/loading#id_70682>
+#        SELECT "application/sparql-results+xml", "application/sparql-results+json", "text/html", "text/csv"
+#        CONSTRUCT or DESCRIBE "application/n-triples", "application/rdf+json", "application/rdf+xml", "text/turtle", "text/n3", "application/n-quads", "application/trig"
+#        ASK queries return a boolean (true or false).
+#
+#  - AllegroGraph <https://franz.com/agraph/allegrograph/>
+#    * Uses only content negotiation (no URL parameters).
+#    * The server always looks at the Accept header of a request, and tries to
+#      generate a response in the format that the client asks for. If this fails,
+#      a 406 response is returned. When no Accept, or an Accept of */* is specified,
+#      the server prefers text/plain, in order to make it easy to explore the interface from a web browser.
+#    * Accept header expected (values returned by server when a wrong header is sent):
+#    ** SELECT
+#    *** application/sparql-results+xml
+#    *** application/sparql-results+json (and application/json)
+#    *** text/csv
+#    *** text/tab-separated-values
+#    *** OTHERS: application/sparql-results+ttl, text/integer, application/x-lisp-structured-expression, text/table, application/processed-csv, text/simple-csv, application/x-direct-upis
+#
+#    ** CONSTRUCT
+#    *** application/rdf+xml
+#    *** text/rdf+n3
+#    *** OTHERS: text/integer, application/json, text/plain, text/x-nquads, application/trix, text/table, application/x-direct-upis
+#
+#      See <https://franz.com/agraph/support/documentation/current/http-protocol.html>
+
+
 JSON   = "json"
 JSONLD = "json-ld"
 XML    = "xml"
 TURTLE = "turtle"
 N3     = "n3"
 RDF    = "rdf"
-_allowedFormats = [JSON, XML, TURTLE, N3, RDF]
+RDFXML = "rdf+xml"
+CSV    = "csv"
+TSV    = "tsv"
+_allowedFormats = [JSON, XML, TURTLE, N3, RDF, RDFXML, CSV, TSV]
 
 # Possible HTTP methods
 POST = "POST"
-GET  = "GET"
+GET = "GET"
 _allowedRequests = [POST, GET]
 
 # Possible HTTP Authentication methods
@@ -57,7 +160,7 @@
 DIGEST = "DIGEST"
 _allowedAuth = [BASIC, DIGEST]
 
-# Possible SPARQL/SPARUL query type
+# Possible SPARQL/SPARUL query type (aka SPARQL Query forms)
 SELECT     = "SELECT"
 CONSTRUCT  = "CONSTRUCT"
 ASK        = "ASK"
@@ -77,7 +180,7 @@
 # Possible methods to perform requests
 URLENCODED = "urlencoded"
 POSTDIRECTLY = "postdirectly"
-_REQUEST_METHODS  = [URLENCODED, 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
@@ -89,14 +192,17 @@
 # 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"]
+_SPARQL_JSON     = ["application/sparql-results+json", "application/json", "text/javascript", "application/javascript"] # VIVO server returns "application/javascript"
 _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"]
+_CSV             = ["text/csv"]
+_TSV             = ["text/tab-separated-values"]
+_XML             = ["application/xml"]
 _ALL             = ["*/*"]
-_RDF_POSSIBLE    = _RDF_XML + _RDF_N3
-_SPARQL_POSSIBLE = _SPARQL_XML + _SPARQL_JSON + _RDF_XML + _RDF_N3
-_SPARQL_PARAMS   = ["query"]
+_RDF_POSSIBLE    = _RDF_XML + _RDF_N3 + _XML
+
+_SPARQL_PARAMS = ["query"]
 
 try:
     import rdflib_jsonld
@@ -106,11 +212,11 @@
     #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 
+# 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"]
 
@@ -127,12 +233,30 @@
 
     @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
+    @ivar endpoint: SPARQL endpoint's URI
+    @type endpoint: string
+    @ivar updateEndpoint: SPARQL endpoint's URI for update operations (if it's a different one). Default is C{None}
+    @type updateEndpoint: string
+    @ivar agent: The User-Agent for the HTTP request header.
+    @type agent: string
+    @ivar _defaultGraph: URI for the default graph. Default is C{None}, the value can be set either via an L{explicit call<addParameter>}("default-graph-uri", uri) or as part of the query string.
+    @type _defaultGraph: string
+    @ivar user: The username of the credentials for querying the current endpoint. Default is C{None}, the value can be set an L{explicit call<setCredentials>}.
+    @type user: string
+    @ivar passwd: The password of the credentials for querying the current endpoint. Default is C{None}, the value can be set an L{explicit call<setCredentials>}.
+    @type passwd: string
+    @ivar http_auth: HTTP Authentication type. The default value is L{BASIC}. Possible values are L{BASIC} or L{DIGEST}
+    @type http_auth: string
+    @ivar onlyConneg: Option for allowing (or not) only HTTP Content Negotiation (so dismiss the use of HTTP parameters).The default value is L{False}.
+    @type onlyConneg: boolean
+    @ivar customHttpHeaders: Custom HTTP Headers to be included in the request. Important: These headers override previous values (including C{Content-Type}, C{User-Agent}, C{Accept} and C{Authorization} if they are present). It is a dictionary where keys are the header field nada and values are the header values.
+    @type customHttpHeaders: dict
     """
     pattern = re.compile(r"""
         ((?P<base>(\s*BASE\s*<.*?>)\s*)|(?P<prefixes>(\s*PREFIX\s+.+:\s*<.*?>)\s*))*
         (?P<queryType>(CONSTRUCT|SELECT|ASK|DESCRIBE|INSERT|DELETE|CREATE|CLEAR|DROP|LOAD|COPY|MOVE|ADD))
     """, re.VERBOSE | re.IGNORECASE)
+    comments_pattern = re.compile(r"(^|\n)\s*#.*?\n")
 
     def __init__(self, endpoint, updateEndpoint=None, returnFormat=XML, defaultGraph=None, agent=__agent__):
         """
@@ -141,7 +265,7 @@
         @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}.
+        @param returnFormat: Default: L{XML}.
         Can be set to JSON or Turtle/N3
 
         No local check is done, the parameter is simply
@@ -149,11 +273,13 @@
         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
+        L{JSON}, L{XML}, L{TURTLE}, L{N3}, L{RDFXML}, L{CSV}, L{TSV} (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<addDefaultGraph>} or as part of the query string.
+        @param defaultGraph: URI for the default graph. Default is None, the value can be set either via an L{explicit call<addDefaultGraph>} or as part of the query string.
         @type defaultGraph: string
+        @param agent: The User-Agent for the HTTP request header.
+        @type agent: string
         """
         self.endpoint = endpoint
         self.updateEndpoint = updateEndpoint if updateEndpoint else endpoint
@@ -162,6 +288,8 @@
         self.passwd = None
         self.http_auth = BASIC
         self._defaultGraph = defaultGraph
+        self.onlyConneg = False # Only Content Negotiation
+        self.customHttpHeaders = {}
 
         if returnFormat in _allowedFormats:
             self._defaultReturnFormat = returnFormat
@@ -171,8 +299,9 @@
         self.resetQuery()
 
     def resetQuery(self):
-        """Reset the query, ie, return format, query, default or named graph settings, etc,
-        are reset to their default values."""
+        """Reset the query, ie, return format, method, 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)
@@ -182,24 +311,28 @@
         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
+        @param format: Possible values are L{JSON}, L{XML}, L{TURTLE}, L{N3}, L{RDF}, L{RDFXML}, L{CSV}, L{TSV}, L{JSONLD} (constants in this module). All other cases are ignored.
+        @type format: string
+        @raise ValueError: If L{JSONLD} is tried to set and the current instance does not support JSON-LD.
         """
-        if format in _allowedFormats :
+        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)))
+            warnings.warn("Ignore format '%s'; current instance supports: %s." %(format, ", ".join(_allowedFormats)), SyntaxWarning)
 
     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
+        @param format: Possible values are L{JSON}, L{XML}, L{TURTLE}, L{N3}, L{RDF}, L{RDFXML}, L{CSV}, L{TSV} (constants in this module). All other cases are ignored.
+        @type format: string
+        @return: Returns a boolean after checking if a return format is supported.
+        @rtype: bool
         """
         return (format in _allowedFormats)
 
@@ -211,22 +344,30 @@
         """
         self.timeout = int(timeout)
 
+    def setOnlyConneg(self, onlyConneg):
+        """Set this option for allowing (or not) only HTTP Content Negotiation (so dismiss the use of HTTP parameters).
+        @since: 1.8.1
+
+        @param onlyConneg: True if only HTTP Content Negotiation is allowed; False is HTTP parameters are allowed also.
+        @type onlyConneg: bool
+        """
+        self.onlyConneg = onlyConneg
+
     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 
+        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
+        @param method: Possible values are C{SPARQLWrapper.URLENCODED} (URL-encoded) or C{SPARQLWrapper.POSTDIRECTLY} (POST directly). All other cases are ignored.
+        @type method: string
         """
         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.
@@ -236,7 +377,6 @@
         """
         self.addParameter("default-graph-uri", uri)
 
-    @deprecated
     def addNamedGraph(self, uri):
         """
             Add a named graph URI.
@@ -246,12 +386,12 @@
         """
         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 
+            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.
+            Alias of L{SPARQLWrapper.addParameter} method.
             @param key: key of the query part
             @type key: string
             @param value: value of the query part
@@ -260,14 +400,14 @@
         """
         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 
+            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
+            @return: Returns a boolean indicating if the adding has been accomplished.
             @rtype: bool
             @deprecated: use addParameter(name, value) instead of this method
         """
@@ -277,12 +417,15 @@
     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 
+            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 
+            If the param C{query} is tried to be set, this intent is dismissed.
+            Returns a boolean indicating if the set has been accomplished.
+            @param name: name
             @type name: string
             @param value: value
             @type value: string
+            @return: Returns a boolean indicating if the adding has been accomplished.
             @rtype: bool
         """
         if name in _SPARQL_PARAMS:
@@ -293,11 +436,45 @@
             self.parameters[name].append(value)
             return True
 
+    def addCustomHttpHeader(self, httpHeaderName, httpHeaderValue):
+        """
+            Add a custom HTTP header (this method can override all HTTP headers).
+            IMPORTANT: Take into acount that each previous value for the header field names
+            C{Content-Type}, C{User-Agent}, C{Accept} and C{Authorization} would be overriden
+            if the header field name is present as value of the parameter C{httpHeaderName}.
+            @since: 1.8.2
+
+            @param httpHeaderName: The header field name.
+            @type httpHeaderName: string
+            @param httpHeaderValue: The header field value.
+            @type httpHeaderValue: string
+        """
+        self.customHttpHeaders[httpHeaderName] = httpHeaderValue
+
+    def clearCustomHttpHeader(self, httpHeaderName):
+        """
+            Clear the values of a custom Http Header previously setted.
+            Returns a boolean indicating if the clearing has been accomplished.
+            @since: 1.8.2
+
+            @param httpHeaderName: name
+            @type httpHeaderName: string
+            @return: Returns a boolean indicating if the clearing has been accomplished.
+            @rtype: bool
+        """
+        try:
+            del self.customHttpHeaders[httpHeaderName]
+            return True
+        except KeyError:
+            return False
+
     def clearParameter(self, name):
         """
-            Clear the values ofd a concrete parameter.
-            @param name: name 
+            Clear the values of a concrete parameter.
+            Returns a boolean indicating if the clearing has been accomplished.
+            @param name: name
             @type name: string
+            @return: Returns a boolean indicating if the clearing has been accomplished.
             @rtype: bool
         """
         if name in _SPARQL_PARAMS:
@@ -311,7 +488,7 @@
 
     def setCredentials(self, user, passwd):
         """
-            Set the credentials for querying the current endpoint
+            Set the credentials for querying the current endpoint.
             @param user: username
             @type user: string
             @param passwd: password
@@ -322,9 +499,11 @@
 
     def setHTTPAuth(self, auth):
         """
-           Set the HTTP Authentication type (Basic or Digest)
-           @param auth: auth type
-           @type auth: string
+            Set the HTTP Authentication type. Possible values are L{BASIC} or L{DIGEST}.
+            @param auth: auth type
+            @type auth: string
+            @raise TypeError: If the C{auth} parameter is not an string.
+            @raise ValueError: If the C{auth} parameter has not one of the valid values: L{BASIC} or L{DIGEST}.
         """
         if not isinstance(auth, str):
             raise TypeError('setHTTPAuth takes a string')
@@ -333,15 +512,15 @@
         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, 
+            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
+            @raise TypeError: If the C{query} parameter is not an unicode-string or utf-8 encoded byte-string.
         """
         if sys.version < '3':  # have to write it like this, for 2to3 compatibility
             if isinstance(query, unicode):
@@ -359,41 +538,44 @@
                 raise TypeError('setQuery takes either unicode-strings or utf-8 encoded byte-strings')
 
         self.queryString = query
-        self.queryType   = self._parseQueryType(query)
+        self.queryType = self._parseQueryType(query)
 
-    def _parseQueryType(self,query):
+    def _parseQueryType(self, query):
         """
-            Parse the SPARQL query and return its type (ie, L{SELECT}, L{ASK}, etc).
+            Internal method for parsing 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,
+            methods running; in fact, this means that the query is erroneous, 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
+            @return: the type of SPARQL query (aka SPARQL query form)
             @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)
+            query = query if (isinstance(query, str)) else query.encode('ascii', 'ignore')
+            query = self._cleanComments(query)
             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 :
+
+        if r_queryType in _allowedQueryTypes:
             return r_queryType
-        else :
+        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):
+    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.
+        @type method: string
         """
-        if method in _allowedRequests : self.method = method
+        if method in _allowedRequests:
+            self.method = method
 
     def setUseKeepAlive(self):
         """Make urllib2 use keep-alive.
@@ -401,6 +583,11 @@
         """
         try:
             from keepalive import HTTPHandler
+
+            if urllib2._opener and any(isinstance(h, HTTPHandler) for h in urllib2._opener.handlers):
+                # already installed
+                return
+
             keepalive_handler = HTTPHandler()
             opener = urllib2.build_opener(keepalive_handler)
             urllib2.install_opener(opener)
@@ -408,21 +595,36 @@
             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
+        """ Returns C{TRUE} if SPARQLWrapper is configured for executing SPARQL Update request.
+        @return: Returns C{TRUE} if SPARQLWrapper is configured for executing SPARQL Update request
+        @rtype: 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
+        """ Returns C{TRUE} if SPARQLWrapper is configured for executing SPARQL Query request.
+        @return: Returns C{TRUE} if SPARQLWrapper is configured for executing SPARQL Query request.
+        @rtype: bool
         """
         return not self.isSparqlUpdateRequest()
 
+    def _cleanComments(self, query):
+        """ Internal method for returning the query after all occurrence of singleline comments are removed (issues #32 and #77).
+        @param query: The query
+        @type query: string
+        @return: the query after all occurrence of singleline comments are removed.
+        @rtype: string
+        """
+        return re.sub(self.comments_pattern, "\n\n", query)
+
     def _getRequestEncodedParameters(self, query=None):
+        """ Internal method for getting the request encoded parameters.
+        @param query: The query
+        @type query: string
+        """
         query_parameters = self.parameters.copy()
 
-        if query and type(query) == tuple and len(query) == 2:
+        if query and (isinstance(query, tuple)) and len(query) == 2:
             #tuple ("query"/"update", queryString)
             query_parameters[query[0]] = [query[1]]
 
@@ -430,8 +632,17 @@
         # 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]
+        if not self.onlyConneg:
+            for f in _returnFormatSetting:
+                query_parameters[f] = [self.returnFormat]
+                # Virtuoso is not supporting a correct Accept header and an unexpected "output"/"format" parameter value. It returns a 406.
+                # "tsv" and "json-ld" are not supported as a correct "output"/"format" parameter value but "text/tab-separated-values" is a valid value,
+                # and there is no problem to send both.
+                if self.returnFormat in [TSV, JSONLD]:
+                    acceptHeader = self._getAcceptHeader() # to obtain the mime-type "text/tab-separated-values"
+                    if "*/*" in acceptHeader:
+                        acceptHeader = "" # clear the value in case of "*/*"
+                    query_parameters[f] += [acceptHeader]
 
         pairs = (
             "%s=%s" % (
@@ -444,16 +655,24 @@
         return '&'.join(pairs)
 
     def _getAcceptHeader(self):
+        """ Internal method for getting the HTTP Accept Header.
+        @see: U{Hypertext Transfer Protocol -- HTTP/1.1 - Header Field Definitions<https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1>}
+        """
         if self.queryType in [SELECT, ASK]:
             if self.returnFormat == XML:
                 acceptHeader = ",".join(_SPARQL_XML)
             elif self.returnFormat == JSON:
                 acceptHeader = ",".join(_SPARQL_JSON)
+            elif self.returnFormat == CSV: # Allowed for SELECT and ASK (https://www.w3.org/TR/2013/REC-sparql11-protocol-20130321/#query-success) but only described for SELECT (https://www.w3.org/TR/sparql11-results-csv-tsv/)
+                acceptHeader = ",".join(_CSV)
+            elif self.returnFormat == TSV: # Allowed for SELECT and ASK (https://www.w3.org/TR/2013/REC-sparql11-protocol-20130321/#query-success) but only described for SELECT (https://www.w3.org/TR/sparql11-results-csv-tsv/)
+                acceptHeader = ",".join(_TSV)
             else:
                 acceptHeader = ",".join(_ALL)
+                warnings.warn("Sending Accept header '*/*' because unexpected returned format '%s' in a '%s' SPARQL query form" % (self.returnFormat, self.queryType), RuntimeWarning)
         elif self.queryType in [INSERT, DELETE]:
             acceptHeader = "*/*"
-        else:
+        else: #CONSTRUCT, DESCRIBE
             if self.returnFormat == N3 or self.returnFormat == TURTLE:
                 acceptHeader = ",".join(_RDF_N3)
             elif self.returnFormat == XML:
@@ -462,12 +681,14 @@
                 acceptHeader = ",".join(_RDF_JSONLD)
             else:
                 acceptHeader = ",".join(_ALL)
+                warnings.warn("Sending Accept header '*/*' because unexpected returned format '%s' in a '%s' SPARQL query form" % (self.returnFormat, self.queryType), RuntimeWarning)
         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
+        @raise NotImplementedError: If the C{HTTP authentification} method is not one of the valid values: L{BASIC} or L{DIGEST}.
+        @return: request a C{urllib2.Request} object of the urllib2 Python library
         """
         request = None
 
@@ -520,27 +741,37 @@
                 raise NotImplementedError("Expecting one of: {0}, but received: {1}".format(valid_types,
                                                                                             self.http_auth))
 
+        # The header field name is capitalized in the request.add_header method.
+        for customHttpHeader in self.customHttpHeaders:
+            request.add_header(customHttpHeader, self.customHttpHeaders[customHttpHeader])
+
         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
+        @return: tuples with the raw request plus the expected format.
+        @raise QueryBadFormed: If the C{HTTP return code} is C{400}.
+        @raise Unauthorized: If the C{HTTP return code} is C{401}.
+        @raise EndPointNotFound: If the C{HTTP return code} is C{404}.
+        @raise EndPointInternalError: If the C{HTTP return code} is C{500}.
         """
-        if self.timeout:
-            socket.setdefaulttimeout(self.timeout)
-
         request = self._createRequest()
 
         try:
-            response = urlopener(request)
+            if self.timeout:
+                response = urlopener(request, timeout=self.timeout)
+            else:
+                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 == 401:
+                raise Unauthorized(e.read())
             elif e.code == 500:
                 raise EndPointInternalError(e.read())
             else:
@@ -595,12 +826,15 @@
     would work, too.
 
     @ivar response: the direct HTTP response; a file-like object, as return by the C{urllib2.urlopen} library call.
+    @ivar requestedFormat: The requested format. The possible values are: L{JSON}, L{XML}, L{RDFXML}, L{TURTLE}, L{N3}, L{RDF}, L{CSV}, L{TSV}, L{JSONLD}.
+    @type requestedFormat: string
+
     """
-    def __init__(self,result):
+    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):
+        if isinstance(result, tuple):
             self.response = result[0]
             self.requestedFormat = result[1]
         else:
@@ -608,16 +842,16 @@
         """Direct response, see class comments for details"""
 
     def geturl(self):
-        """Return the URI of the original call.
-        @return: URI
+        """Return the URL of the original call.
+        @return: URL of the original call
         @rtype: string
         """
         return self.response.geturl()
 
     def info(self):
         """Return the meta-information of the HTTP result.
-        @return: meta information
-        @rtype: dictionary
+        @return: meta information of the HTTP result
+        @rtype: dict
         """
         return KeyCaseInsensitiveDict(self.response.info())
 
@@ -636,7 +870,7 @@
         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
+        @rtype: dict
         """
         return json.loads(self.response.read().decode("utf-8"))
 
@@ -655,16 +889,16 @@
         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
+        @rtype: RDFLib C{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=' ')
+        # (DEPRECATED) this is a strange hack. If the publicID is not set, rdflib (or the underlying xml parser) makes a funny
+        # (DEPRECATED) (and, as far as I could see, meaningless) error message...
+        retval.load(self.response) # (DEPRECATED) publicID=' ')
         return retval
 
     def _convertN3(self):
@@ -676,16 +910,34 @@
         """
         return self.response.read()
 
+    def _convertCSV(self):
+        """
+        Convert a CSV 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 _convertTSV(self):
+        """
+        Convert a TSV 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
+        Convert a RDF JSON-LD 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
         """
         from rdflib import ConjunctiveGraph
         retval = ConjunctiveGraph()
-        retval.load(self.response, format='json-ld', publicID=' ')
+        retval.load(self.response, format='json-ld')# (DEPRECATED), publicID=' ')
         return retval
 
     def convert(self):
@@ -693,7 +945,9 @@
         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 the case of RDF/XML, the value is converted via RDFLib into a C{Graph} instance;
+            - in the case of RDF Turtle/N3, a string is returned;
+            - in the case of CSV/TSV, a string is returned.
         In all other cases the input simply returned.
 
         @return: the converted query result. See the conversion methods for more details.
@@ -706,66 +960,76 @@
                 message = "Format requested was %s, but %s (%s) has been returned by the endpoint"
                 warnings.warn(message % (requested.upper(), format_name, mime), RuntimeWarning)
 
+        # TODO. In order to compare properly, the requested QueryType (SPARQL Query Form) is needed. For instance, the unexpected N3 requested for a SELECT would return XML
         if "content-type" in self.info():
-            ct = self.info()["content-type"]
+            ct = self.info()["content-type"] # returned Content-Type value
 
             if _content_type_in_list(ct, _SPARQL_XML):
                 _validate_format("XML", [XML], ct, self.requestedFormat)
                 return self._convertXML()
+            elif _content_type_in_list(ct, _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)
+                _validate_format("RDF/XML", [RDF, XML, RDFXML], 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, _CSV):
+                _validate_format("CSV", [CSV], ct, self.requestedFormat)
+                return self._convertCSV()
+            elif _content_type_in_list(ct, _TSV):
+                _validate_format("TSV", [TSV], ct, self.requestedFormat)
+                return self._convertTSV()
             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)
+            else:
+                warnings.warn("unknown response content type '%s' returning raw response..." %(ct), RuntimeWarning)
         return self.response.read()
 
     def print_results(self, minWidth=None):
         results = self._convertJSON()
-        if minWidth :
+        if minWidth:
             width = self.__get_results_width(results, minWidth)
-        else :
+        else:
             width = self.__get_results_width(results)
         index = 0
-        for var in results["head"]["vars"] :
-            print ("?" + var).ljust(width[index]),"|",
+        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"] :
+        for result in results["results"]["bindings"]:
             index = 0
-            for var in results["head"]["vars"] :
+            for var in results["head"]["vars"]:
                 result = self.__get_prettyprint_string_sparql_var_result(result[var])
-                print result.ljust(width[index]),"|",
+                print result.ljust(width[index]), "|",
                 index += 1
             print
 
     def __get_results_width(self, results, minWidth=2):
         width = []
-        for var in results["head"]["vars"] :
+        for var in results["head"]["vars"]:
             width.append(max(minWidth, len(var)+1))
-        for result in results["results"]["bindings"] :
+        for result in results["results"]["bindings"]:
             index = 0
-            for var in results["head"]["vars"] :
+            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
+                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)
+        datatype = result.get("datatype", None)
         if lang is not None:
-            value+="@"+lang
+            value += "@"+lang
         if datatype is not None:
-            value+=" ["+datatype+"]"
+            value += " ["+datatype+"]"
         return value
diff -Nru sparql-wrapper-python-1.7.6/test/agrovoc-allegrograph.py sparql-wrapper-python-1.8.2/test/agrovoc-allegrograph.py
--- sparql-wrapper-python-1.7.6/test/agrovoc-allegrograph.py	1970-01-01 01:00:00.000000000 +0100
+++ sparql-wrapper-python-1.8.2/test/agrovoc-allegrograph.py	2018-05-16 22:23:01.000000000 +0200
@@ -0,0 +1,515 @@
+# -*- coding: utf-8 -*-
+#!/usr/bin/python
+
+import inspect
+import os
+import sys
+import logging
+import unittest
+
+# 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
+
+try:
+    from rdflib.graph import ConjunctiveGraph
+except ImportError:
+    from rdflib import ConjunctiveGraph
+from SPARQLWrapper import SPARQLWrapper, XML, N3, JSONLD, JSON, CSV, TSV, POST, GET, SELECT, CONSTRUCT, ASK, DESCRIBE
+from SPARQLWrapper.Wrapper import _SPARQL_XML, _SPARQL_JSON, _XML, _RDF_XML, _RDF_N3, _RDF_JSONLD, _CSV, _TSV
+from SPARQLWrapper.SPARQLExceptions import QueryBadFormed
+
+_SPARQL_SELECT_ASK_POSSIBLE = _SPARQL_XML + _SPARQL_JSON + _CSV + _TSV + _XML # only used in test
+_SPARQL_DESCRIBE_CONSTRUCT_POSSIBLE = _RDF_XML + _RDF_N3 + _XML # only used in test. Same as Wrapper._RDF_POSSIBLE
+
+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
+
+logging.basicConfig()
+
+endpoint = "http://202.45.139.84:10035/catalogs/fao/repositories/agrovoc"
+
+prefixes = """
+    PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+    PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
+"""
+
+selectQuery = """
+    SELECT ?label
+    WHERE {
+    <http://aims.fao.org/aos/agrovoc/c_aca7ac6d> skos:prefLabel ?label .
+    }
+"""
+
+selectQueryCSV_TSV = """
+    SELECT ?label ?created
+    WHERE {
+    <http://aims.fao.org/aos/agrovoc/c_aca7ac6d> skos:prefLabel ?label ;
+         <http://purl.org/dc/terms/created> ?created
+    }
+"""
+askQuery = """
+    ASK { <http://aims.fao.org/aos/agrovoc/c_aca7ac6d> a ?type }
+"""
+
+constructQuery = """
+    CONSTRUCT {
+        _:v skos:prefLabel ?label .
+        _:v rdfs:comment "this is only a mock node to test library"
+    }
+    WHERE {
+        <http://aims.fao.org/aos/agrovoc/c_aca7ac6d> skos:prefLabel ?label .
+    }
+"""
+
+describeQuery = """
+    DESCRIBE <http://aims.fao.org/aos/agrovoc/c_aca7ac6d>
+"""
+
+queryBadFormed = """
+    PREFIX prop: <http://dbpedia.org/property/>
+    PREFIX res: <http://dbpedia.org/resource/>
+    FROM <http://dbpedia.org/sparql?default-graph-uri=http%3A%2F%2Fdbpedia.org&should-sponge=&query=%0D%0ACONSTRUCT+%7B%0D%0A++++%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FBudapest%3E+%3Fp+%3Fo.%0D%0A%7D%0D%0AWHERE+%7B%0D%0A++++%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FBudapest%3E+%3Fp+%3Fo.%0D%0A%7D%0D%0A&format=application%2Frdf%2Bxml>
+    SELECT ?lat ?long
+    WHERE {
+        res:Budapest prop:latitude ?lat;
+        prop:longitude ?long.
+    }      
+"""
+
+queryManyPrefixes = """
+    PREFIX conf: <http://richard.cyganiak.de/2007/pubby/config.rdf#>
+    PREFIX meta: <http://example.org/metadata#>
+    PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+    PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+    PREFIX owl: <http://www.w3.org/2002/07/owl#>
+    PREFIX dc: <http://purl.org/dc/elements/1.1/>
+    PREFIX dcterms: <http://purl.org/dc/terms/>
+    PREFIX foaf: <http://xmlns.com/foaf/0.1/>
+    PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
+    PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
+    PREFIX dbpedia: <http://dbpedia.org/resource/>
+    PREFIX o: <http://dbpedia.org/ontology/>
+    PREFIX p: <http://dbpedia.org/property/>
+    PREFIX yago: <http://dbpedia.org/class/yago/>
+    PREFIX units: <http://dbpedia.org/units/>
+    PREFIX geonames: <http://www.geonames.org/ontology#>
+    PREFIX prv: <http://purl.org/net/provenance/ns#>
+    PREFIX prvTypes: <http://purl.org/net/provenance/types#>
+    PREFIX foo: <http://purl.org/foo>
+
+    SELECT ?label
+    WHERE {
+        <http://dbpedia.org/resource/Asturias> rdfs:label ?label .
+    }
+"""
+
+
+queryWithCommaInCurie_1 = """
+    PREFIX dbpedia: <http://dbpedia.org/resource/>
+    SELECT ?article ?title WHERE {
+        ?article ?relation dbpedia:Victoria\\,\\_British\\_Columbia .
+        ?article <http://xmlns.com/foaf/0.1/isPrimaryTopicOf> ?title
+    }
+"""
+
+queryWithCommaInCurie_2 = """
+    PREFIX dbpedia: <http://dbpedia.org/resource/>
+    SELECT ?article ?title WHERE {
+        ?article ?relation dbpedia:Category\:Victoria\,\_British\_Columbia .
+        ?article <http://xmlns.com/foaf/0.1/isPrimaryTopicOf> ?title
+    }
+"""
+
+queryWithCommaInUri = """
+    SELECT ?article ?title WHERE {
+        ?article ?relation <http://dbpedia.org/resource/Category:Victoria,_British_Columbia> .
+        ?article <http://xmlns.com/foaf/0.1/isPrimaryTopicOf> ?title
+    }
+"""
+
+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
+
+###############
+#### SELECT ###
+###############
+
+    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()
+
+    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()
+
+    def testSelectByGETinCSV(self):
+        result = self.__generic(selectQueryCSV_TSV, CSV, GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _CSV], ct
+        results = result.convert()
+
+    def testSelectByPOSTinCSV(self):
+        result = self.__generic(selectQueryCSV_TSV, CSV, POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _CSV], ct
+        results = result.convert()
+
+    def testSelectByGETinTSV(self):
+        result = self.__generic(selectQueryCSV_TSV, TSV, GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _TSV], ct
+        results = result.convert()
+
+    def testSelectByPOSTinTSV(self):
+        result = self.__generic(selectQueryCSV_TSV, TSV, POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _TSV], ct
+        results = result.convert()
+
+    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)
+
+    # asking for an unexpected return format for SELECT queryType
+    def testSelectByGETinN3(self):
+        result = self.__generic(selectQuery, N3, GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_SELECT_ASK_POSSIBLE], ct
+        results = result.convert()
+        results.toxml()
+
+    # asking for an unexpected return format for SELECT queryType
+    def testSelectByGETinJSONLD(self):
+        result = self.__generic(selectQuery, JSONLD, GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_SELECT_ASK_POSSIBLE], ct
+        results = result.convert()
+
+    # asking for an unexpected return format for SELECT queryType
+    def testSelectByGETinUnknow(self):
+        result = self.__generic(selectQuery, "foo", GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_SELECT_ASK_POSSIBLE], ct
+        results = result.convert()
+
+     # asking for an unexpected return format for SELECT queryType
+    def testSelectByPOSTinUnknow(self):
+        result = self.__generic(selectQuery, "bar", POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_SELECT_ASK_POSSIBLE], ct
+        results = result.convert()
+
+################################################################################
+
+###############
+#### ASK ###
+###############
+
+    def testAskByGETinXML(self):
+        result = self.__generic(askQuery, XML, GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_XML], ct
+        results = result.convert()
+
+    def testAskByPOSTinXML(self):
+        result = self.__generic(askQuery, XML, POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_XML], ct
+        results = result.convert()
+        results.toxml()
+
+    def testAskByGETinJSON(self):
+        result = self.__generic(askQuery, 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 testAskByPOSTinJSON(self):
+        result = self.__generic(askQuery, 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)
+
+    # asking for an unexpected return format for ASK queryType
+    def testAskByGETinN3(self):
+        result = self.__generic(askQuery, N3, GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_SELECT_ASK_POSSIBLE], ct
+        results = result.convert()
+        results.toxml()
+
+    # asking for an unexpected return format for ASK queryType
+    def testAskByGETinJSONLD(self):
+        result = self.__generic(askQuery, JSONLD, GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_SELECT_ASK_POSSIBLE], ct
+        results = result.convert()
+
+    # asking for an unexpected return format for ASK queryType
+    def testAskByGETinUnknow(self):
+        result = self.__generic(askQuery, "foo", GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_SELECT_ASK_POSSIBLE], ct
+        results = result.convert()
+
+     # asking for an unexpected return format for ASK queryType
+    def testAskByPOSTinUnknow(self):
+        result = self.__generic(askQuery, "bar", POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_SELECT_ASK_POSSIBLE], ct
+        results = result.convert()
+
+################################################################################
+
+##################
+#### CONSTRUCT ###
+##################
+
+    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)
+
+    # JSON-LD is not supported currently for AllegroGraph
+    @unittest.skip("JSON-LD is not supported currently for AllegroGraph")
+    def testConstructByGETinJSONLD(self):
+        result = self.__generic(constructQuery, JSONLD, GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _RDF_JSONLD], ct
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    # JSON-LD is not supported currently for AllegroGraph
+    @unittest.skip("JSON-LD is not supported currently for AllegroGraph")
+    def testConstructByPOSTinJSONLD(self):
+        result = self.__generic(constructQuery, JSONLD, POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _RDF_JSONLD], ct
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    # asking for an unexpected return format for CONSTRUCT queryType
+    def testConstructByGETinJSON(self):
+        result = self.__generic(constructQuery, JSON, GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_DESCRIBE_CONSTRUCT_POSSIBLE], ct
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    # asking for an unexpected return format for CONSTRUCT queryType
+    def testConstructByPOSTinJSON(self):
+        result = self.__generic(constructQuery, JSON, POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_DESCRIBE_CONSTRUCT_POSSIBLE], ct
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    # asking for an unexpected return format for CONSTRUCT queryType
+    def testConstructByGETinUnknow(self):
+        result = self.__generic(constructQuery, "foo", GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_DESCRIBE_CONSTRUCT_POSSIBLE], ct
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    # asking for an unexpected return format for CONSTRUCT queryType
+    def testConstructByPOSTinUnknow(self):
+        result = self.__generic(constructQuery, "bar", POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_DESCRIBE_CONSTRUCT_POSSIBLE], ct
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+################################################################################
+
+#################
+#### DESCRIBE ###
+#################
+
+    def testDescribeByGETinXML(self):
+        result = self.__generic(describeQuery, 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 testDescribeByPOSTinXML(self):
+        result = self.__generic(describeQuery, 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 testDescribeByGETinN3(self):
+        result = self.__generic(describeQuery, 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 testDescribeByPOSTinN3(self):
+        result = self.__generic(describeQuery, 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)
+
+    # JSON-LD is not supported currently for AllegroGraph
+    @unittest.skip("JSON-LD is not supported currently for AllegroGraph")
+    def testDescribeByGETinJSONLD(self):
+        result = self.__generic(describeQuery, JSONLD, GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _RDF_JSONLD], ct
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    # JSON-LD is not supported currently for AllegroGraph
+    @unittest.skip("JSON-LD is not supported currently for AllegroGraph")
+    def testDescribeByPOSTinJSONLD(self):
+        result = self.__generic(describeQuery, JSONLD, POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _RDF_JSONLD], ct
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    # asking for an unexpected return format for DESCRIBE queryType
+    def testDescribeByGETinJSON(self):
+        result = self.__generic(describeQuery, JSON, GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_DESCRIBE_CONSTRUCT_POSSIBLE], ct
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    # asking for an unexpected return format for DESCRIBE queryType
+    def testDescribeByPOSTinJSON(self):
+        result = self.__generic(describeQuery, JSON, POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_DESCRIBE_CONSTRUCT_POSSIBLE], ct
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    # asking for an unexpected return format for DESCRIBE queryType
+    def testDescribeByGETinUnknow(self):
+        result = self.__generic(describeQuery, "foo", GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_DESCRIBE_CONSTRUCT_POSSIBLE], ct
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    # asking for an unexpected return format for DESCRIBE queryType
+    def testDescribeByPOSTinUnknow(self):
+        result = self.__generic(describeQuery, "bar", POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_DESCRIBE_CONSTRUCT_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()
+
+    @unittest.skip("Allegrograph returns Value \"\\\" not recognized Error. See #94")
+    def testQueryWithComma_1(self):
+        result = self.__generic(queryWithCommaInCurie_1, XML, GET)
+
+    @unittest.skip("Allegrograph returns Value \"\\\" not recognized Error. See #94")
+    def testQueryWithComma_2(self):
+        result = self.__generic(queryWithCommaInCurie_2, XML, POST)
+
+    def testQueryWithComma_3(self):
+        result = self.__generic(queryWithCommaInUri, XML, GET)
+
+if __name__ == "__main__":
+    unittest.main()
diff -Nru sparql-wrapper-python-1.7.6/test/dbpedia.py sparql-wrapper-python-1.8.2/test/dbpedia.py
--- sparql-wrapper-python-1.7.6/test/dbpedia.py	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/test/dbpedia.py	1970-01-01 01:00:00.000000000 +0100
@@ -1,254 +0,0 @@
-# -*- 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: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
-    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
-"""
-
-selectQuery = """
-    SELECT ?label
-    WHERE {
-    <http://dbpedia.org/resource/Asturias> rdfs:label ?label .
-    }
-"""
-
-constructQuery = """
-    CONSTRUCT {
-        _:v rdfs:label ?label .
-        _:v rdfs:comment "this is only a mock node to test library"
-    }
-    WHERE {
-        <http://dbpedia.org/resource/Asturias> rdfs:label ?label .
-    }
-"""
-
-queryBadFormed = """
-    PREFIX prop: <http://dbpedia.org/property/>
-    PREFIX res: <http://dbpedia.org/resource/>
-    FROM <http://dbpedia.org/sparql?default-graph-uri=http%3A%2F%2Fdbpedia.org&should-sponge=&query=%0D%0ACONSTRUCT+%7B%0D%0A++++%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FBudapest%3E+%3Fp+%3Fo.%0D%0A%7D%0D%0AWHERE+%7B%0D%0A++++%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FBudapest%3E+%3Fp+%3Fo.%0D%0A%7D%0D%0A&format=application%2Frdf%2Bxml>
-    SELECT ?lat ?long
-    WHERE {
-        res:Budapest prop:latitude ?lat;
-        prop:longitude ?long.
-    }      
-"""
-
-queryManyPrefixes = """
-    PREFIX conf: <http://richard.cyganiak.de/2007/pubby/config.rdf#>
-    PREFIX meta: <http://example.org/metadata#>
-    PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
-    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
-    PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
-    PREFIX owl: <http://www.w3.org/2002/07/owl#>
-    PREFIX dc: <http://purl.org/dc/elements/1.1/>
-    PREFIX dcterms: <http://purl.org/dc/terms/>
-    PREFIX foaf: <http://xmlns.com/foaf/0.1/>
-    PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
-    PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
-    PREFIX dbpedia: <http://dbpedia.org/resource/>
-    PREFIX o: <http://dbpedia.org/ontology/>
-    PREFIX p: <http://dbpedia.org/property/>
-    PREFIX yago: <http://dbpedia.org/class/yago/>
-    PREFIX units: <http://dbpedia.org/units/>
-    PREFIX geonames: <http://www.geonames.org/ontology#>
-    PREFIX prv: <http://purl.org/net/provenance/ns#>
-    PREFIX prvTypes: <http://purl.org/net/provenance/types#>
-    PREFIX foo: <http://purl.org/foo>
-
-    SELECT ?label
-    WHERE {
-        <http://dbpedia.org/resource/Asturias> 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()
-
diff -Nru sparql-wrapper-python-1.7.6/test/dbpedia-virtuoso.py sparql-wrapper-python-1.8.2/test/dbpedia-virtuoso.py
--- sparql-wrapper-python-1.7.6/test/dbpedia-virtuoso.py	1970-01-01 01:00:00.000000000 +0100
+++ sparql-wrapper-python-1.8.2/test/dbpedia-virtuoso.py	2018-05-16 22:23:01.000000000 +0200
@@ -0,0 +1,509 @@
+# -*- coding: utf-8 -*-
+#!/usr/bin/python
+
+import inspect
+import os
+import sys
+import logging
+
+# 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, CSV, TSV, POST, GET, SELECT, CONSTRUCT, ASK, DESCRIBE
+from SPARQLWrapper.Wrapper import _SPARQL_XML, _SPARQL_JSON, _XML, _RDF_XML, _RDF_N3, _RDF_JSONLD, _CSV, _TSV
+from SPARQLWrapper.SPARQLExceptions import QueryBadFormed
+
+_SPARQL_SELECT_ASK_POSSIBLE = _SPARQL_XML + _SPARQL_JSON + _CSV + _TSV + _XML # only used in test
+_SPARQL_DESCRIBE_CONSTRUCT_POSSIBLE = _RDF_XML + _RDF_N3 + _XML # only used in test. Same as Wrapper._RDF_POSSIBLE
+
+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
+
+logging.basicConfig()
+
+endpoint = "http://dbpedia.org/sparql"
+
+prefixes = """
+    PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+"""
+
+selectQuery = """
+    SELECT ?label
+    WHERE {
+    <http://dbpedia.org/resource/Asturias> rdfs:label ?label .
+    }
+"""
+
+selectQueryCSV_TSV = """
+    SELECT ?label ?wikiPageID
+    WHERE {
+    <http://dbpedia.org/resource/Asturias> rdfs:label ?label ;
+         <http://dbpedia.org/ontology/wikiPageID> ?wikiPageID
+    }
+"""
+
+askQuery = """
+    ASK { <http://dbpedia.org/resource/Asturias> a ?type }
+"""
+
+constructQuery = """
+    CONSTRUCT {
+        _:v rdfs:label ?label .
+        _:v rdfs:comment "this is only a mock node to test library"
+    }
+    WHERE {
+        <http://dbpedia.org/resource/Asturias> rdfs:label ?label .
+    }
+"""
+
+describeQuery = """
+    DESCRIBE <http://dbpedia.org/resource/Asturias>
+"""
+
+queryBadFormed = """
+    PREFIX prop: <http://dbpedia.org/property/>
+    PREFIX res: <http://dbpedia.org/resource/>
+    FROM <http://dbpedia.org/sparql?default-graph-uri=http%3A%2F%2Fdbpedia.org&should-sponge=&query=%0D%0ACONSTRUCT+%7B%0D%0A++++%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FBudapest%3E+%3Fp+%3Fo.%0D%0A%7D%0D%0AWHERE+%7B%0D%0A++++%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FBudapest%3E+%3Fp+%3Fo.%0D%0A%7D%0D%0A&format=application%2Frdf%2Bxml>
+    SELECT ?lat ?long
+    WHERE {
+        res:Budapest prop:latitude ?lat;
+        prop:longitude ?long.
+    }
+"""
+
+queryManyPrefixes = """
+    PREFIX conf: <http://richard.cyganiak.de/2007/pubby/config.rdf#>
+    PREFIX meta: <http://example.org/metadata#>
+    PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+    PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+    PREFIX owl: <http://www.w3.org/2002/07/owl#>
+    PREFIX dc: <http://purl.org/dc/elements/1.1/>
+    PREFIX dcterms: <http://purl.org/dc/terms/>
+    PREFIX foaf: <http://xmlns.com/foaf/0.1/>
+    PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
+    PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
+    PREFIX dbpedia: <http://dbpedia.org/resource/>
+    PREFIX o: <http://dbpedia.org/ontology/>
+    PREFIX p: <http://dbpedia.org/property/>
+    PREFIX yago: <http://dbpedia.org/class/yago/>
+    PREFIX units: <http://dbpedia.org/units/>
+    PREFIX geonames: <http://www.geonames.org/ontology#>
+    PREFIX prv: <http://purl.org/net/provenance/ns#>
+    PREFIX prvTypes: <http://purl.org/net/provenance/types#>
+    PREFIX foo: <http://purl.org/foo>
+
+    SELECT ?label
+    WHERE {
+        <http://dbpedia.org/resource/Asturias> rdfs:label ?label .
+    }
+"""
+
+queryWithCommaInCurie_1 = """
+    PREFIX dbpedia: <http://dbpedia.org/resource/>
+    SELECT ?article ?title WHERE {
+        ?article ?relation dbpedia:Victoria\\,\\_British\\_Columbia .
+        ?article <http://xmlns.com/foaf/0.1/isPrimaryTopicOf> ?title
+    }
+"""
+
+queryWithCommaInCurie_2 = """
+    PREFIX dbpedia: <http://dbpedia.org/resource/>
+    SELECT ?article ?title WHERE {
+        ?article ?relation dbpedia:Category\:Victoria\,\_British\_Columbia .
+        ?article <http://xmlns.com/foaf/0.1/isPrimaryTopicOf> ?title
+    }
+"""
+
+queryWithCommaInUri = """
+    SELECT ?article ?title WHERE {
+        ?article ?relation <http://dbpedia.org/resource/Category:Victoria,_British_Columbia> .
+        ?article <http://xmlns.com/foaf/0.1/isPrimaryTopicOf> ?title
+    }
+"""
+
+class SPARQLWrapperTests(unittest.TestCase):
+
+    def __generic(self, query, returnFormat, method, onlyConneg=False):
+        sparql = SPARQLWrapper(endpoint)
+        sparql.setQuery(prefixes + query)
+        sparql.setReturnFormat(returnFormat)
+        sparql.setMethod(method)
+        sparql.setOnlyConneg(onlyConneg)
+        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()
+
+    def testSelectByGETinCSV(self):
+        result = self.__generic(selectQueryCSV_TSV, CSV, GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _CSV], ct
+        results = result.convert()
+
+    def testSelectByPOSTinCSV(self):
+        result = self.__generic(selectQueryCSV_TSV, CSV, POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _CSV], ct
+        results = result.convert()
+
+    def testSelectByGETinTSV(self):
+        result = self.__generic(selectQueryCSV_TSV, TSV, GET, True)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _TSV], ct
+        results = result.convert()
+
+    def testSelectByPOSTinTSV(self):
+        result = self.__generic(selectQueryCSV_TSV, TSV, POST, True)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _TSV], ct
+        results = result.convert()
+
+    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)
+
+    # asking for an unexpected return format for SELECT queryType
+    @unittest.skip("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_SELECT_ASK_POSSIBLE], "returned Content-Type='%s'. Expected fail due to Virtuoso configuration" %(ct)
+        results = result.convert()
+        self.assertEqual(type(results), bytes)
+
+    # asking for an unexpected return format for SELECT queryType
+    def testSelectByGETinUnknow(self):
+        result = self.__generic(selectQuery, "foo", GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_SELECT_ASK_POSSIBLE], ct
+        results = result.convert()
+
+    # asking for an unexpected return format for SELECT queryType
+    def testSelectByPOSTinUnknow(self):
+        result = self.__generic(selectQuery, "bar", POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_SELECT_ASK_POSSIBLE], ct
+        results = result.convert()
+
+################################################################################
+
+    def testAskByGETinXML(self):
+        result = self.__generic(askQuery, 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 testAskByPOSTinXML(self):
+        result = self.__generic(askQuery, XML, POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_XML], ct
+        results = result.convert()
+        results.toxml()
+
+    def testAskByGETinCSV(self):
+        result = self.__generic(askQuery, CSV, GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _CSV], ct
+        results = result.convert()
+
+    def testAskByPOSTinCSV(self):
+        result = self.__generic(askQuery, CSV, POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _CSV], ct
+        results = result.convert()
+
+    def testAskByGETinTSV(self):
+        result = self.__generic(askQuery, TSV, GET, True)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _TSV], ct
+        results = result.convert()
+
+    def testAskByPOSTinTSV(self):
+        result = self.__generic(askQuery, TSV, POST, True)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _TSV], ct
+        results = result.convert()
+
+    def testAskByGETinJSON(self):
+        result = self.__generic(askQuery, 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 testAskByPOSTinJSON(self):
+        result = self.__generic(askQuery, 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)
+
+    # asking for an unexpected return format for ASK queryType
+    @unittest.skip("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")
+    def testAskByGETinN3(self):
+        result = self.__generic(askQuery, N3, GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_SELECT_ASK_POSSIBLE], "returned Content-Type='%s'. Expected fail due to Virtuoso configuration" %(ct)
+        results = result.convert()
+        self.assertEqual(type(results), bytes)
+
+    # asking for an unexpected return format for ASK queryType
+    def testAskByGETinUnknow(self):
+        result = self.__generic(askQuery, "foo", GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_SELECT_ASK_POSSIBLE], ct
+        results = result.convert()
+
+    # asking for an unexpected return format for ASK queryType
+    def testAskByPOSTinUnknow(self):
+        result = self.__generic(askQuery, "bar", POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_SELECT_ASK_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)
+
+    # asking for an unexpected return format for CONSTRUCT queryType
+    @unittest.skip("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 _SPARQL_DESCRIBE_CONSTRUCT_POSSIBLE], "returned Content-Type='%s'. Expected fail due to Virtuoso configuration" %(ct)
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    # asking for an unexpected return format for CONSTRUCT queryType
+    @unittest.skip("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 testConstructByPOSTinJSON(self):
+        result = self.__generic(constructQuery, JSON, POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_DESCRIBE_CONSTRUCT_POSSIBLE], "returned Content-Type='%s'. Expected fail due to Virtuoso configuration" %(ct)
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    def testConstructByGETinJSONLD(self):
+        result = self.__generic(constructQuery, JSONLD, GET, True)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _RDF_JSONLD], "returned Content-Type='%s'." %(ct)
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    def testConstructByPOSTinJSONLD(self):
+        result = self.__generic(constructQuery, JSONLD, POST, True)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _RDF_JSONLD], "returned Content-Type='%s'." %(ct)
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    # asking for an unexpected return format for CONSTRUCT queryType
+    def testConstructByGETinUnknow(self):
+        result = self.__generic(constructQuery, "foo", GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_DESCRIBE_CONSTRUCT_POSSIBLE], ct
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    # asking for an unexpected return format for CONSTRUCT queryType
+    def testConstructByPOSTinUnknow(self):
+        result = self.__generic(constructQuery, "bar", POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_DESCRIBE_CONSTRUCT_POSSIBLE], ct
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+###############################################################################
+
+    def testDescribeByGETinXML(self):
+        result = self.__generic(describeQuery, 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 testDescribeByPOSTinXML(self):
+        result = self.__generic(describeQuery, 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 testDescribeByGETinN3(self):
+        result = self.__generic(describeQuery, 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 testDescribeByPOSTinN3(self):
+        result = self.__generic(describeQuery, 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)
+
+    # asking for an unexpected return format for DESCRIBE queryType
+    @unittest.skip("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 testDescribeByGETinJSON(self):
+        result = self.__generic(describeQuery, JSON, GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_DESCRIBE_CONSTRUCT_POSSIBLE], "returned Content-Type='%s'. Expected fail due to Virtuoso configuration" %(ct)
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    # asking for an unexpected return format for DESCRIBE queryType
+    @unittest.skip("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 testDescribeByPOSTinJSON(self):
+        result = self.__generic(describeQuery, JSON, POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_DESCRIBE_CONSTRUCT_POSSIBLE], "returned Content-Type='%s'. Expected fail due to Virtuoso configuration" %(ct)
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    def testDescribeByGETinJSONLD(self):
+        result = self.__generic(describeQuery, JSONLD, GET, True)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _RDF_JSONLD], "returned Content-Type='%s'." %(ct)
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    def testDescribeByPOSTinJSONLD(self):
+        result = self.__generic(describeQuery, JSONLD, POST, True)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _RDF_JSONLD], "returned Content-Type='%s'." %(ct)
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    # asking for an unexpected return format for DESCRIBE queryType
+    def testDescribeByGETinUnknow(self):
+        result = self.__generic(describeQuery, "foo", GET)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_DESCRIBE_CONSTRUCT_POSSIBLE], ct
+        results = result.convert()
+        self.assertEqual(type(results), ConjunctiveGraph)
+
+    # asking for an unexpected return format for DESCRIBE queryType
+    def testDescribeByPOSTinUnknow(self):
+        result = self.__generic(describeQuery, "bar", POST)
+        ct = result.info()["content-type"]
+        assert True in [one in ct for one in _SPARQL_DESCRIBE_CONSTRUCT_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()
+
+    @unittest.skip("Virtuoso returns a QueryBadFormed Error. See #94")
+    def testQueryWithComma_1(self):
+        result = self.__generic(queryWithCommaInCurie_1, XML, GET)
+
+    @unittest.skip("Virtuoso returns a QueryBadFormed Error. See #94")
+    def testQueryWithComma_2(self):
+        result = self.__generic(queryWithCommaInCurie_2, XML, GET)
+
+    def testQueryWithComma_3(self):
+        result = self.__generic(queryWithCommaInUri, XML, GET)
+
+if __name__ == "__main__":
+    unittest.main()
diff -Nru sparql-wrapper-python-1.7.6/test/wrapper_test.py sparql-wrapper-python-1.8.2/test/wrapper_test.py
--- sparql-wrapper-python-1.7.6/test/wrapper_test.py	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/test/wrapper_test.py	2018-05-16 22:23:01.000000000 +0200
@@ -4,14 +4,13 @@
 import sys
 
 import logging
-logging.basicConfig()
 
 import unittest
 import urllib2
-from urlparse import urlparse
+from urlparse import urlparse, parse_qsl, parse_qs
 from urllib2 import Request
 
-from cgi import parse_qs
+logging.basicConfig()
 
 # prefer local copy to the one which is installed
 # hack from http://stackoverflow.com/a/6098238/280539
@@ -23,13 +22,6 @@
     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
@@ -39,6 +31,12 @@
 
 import SPARQLWrapper.Wrapper as _victim
 
+from SPARQLWrapper import SPARQLWrapper
+from SPARQLWrapper import XML, GET, POST, JSON, JSONLD, N3, TURTLE, RDF, SELECT, INSERT, RDFXML, CSV, TSV
+from SPARQLWrapper import URLENCODED, POSTDIRECTLY
+from SPARQLWrapper import BASIC, DIGEST
+from SPARQLWrapper.Wrapper import QueryResult, QueryBadFormed, EndPointNotFound, EndPointInternalError
+
 
 class FakeResult(object):
     def __init__(self, request):
@@ -120,7 +118,7 @@
             return parameters
         else:
             result = {}
-            for k,vs in parameters.iteritems():
+            for k, vs in parameters.iteritems():
                 result[k] = [v.encode('utf-8') for v in vs]
             return result
 
@@ -159,28 +157,37 @@
         self.wrapper.setQuery('CONSTRUCT WHERE {?a ?b ?c}')
         self.wrapper.setReturnFormat(N3)
         self.wrapper.addParameter('a', 'b')
+        self.wrapper.setOnlyConneg(True)
 
         request = self._get_request(self.wrapper)
         parameters = self._get_parameters_from_request(request)
+        onlyConneg = self.wrapper.onlyConneg
 
         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.assertTrue(onlyConneg)
 
         self.wrapper.resetQuery()
 
         request = self._get_request(self.wrapper)
         parameters = self._get_parameters_from_request(request)
+        onlyConneg = self.wrapper.onlyConneg
 
         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)
+        self.assertFalse('a' in parameters)
+        self.assertTrue(onlyConneg)
 
     def testSetReturnFormat(self):
-        self.assertRaises(ValueError, self.wrapper.setReturnFormat, 'nonexistent format')
+        with warnings.catch_warnings(record=True) as w:
+            self.wrapper.setReturnFormat('nonexistent format')
+            self.assertEqual(1, len(w), "Warning due to non expected format")
+
         self.assertEqual(XML, self.wrapper.query().requestedFormat)
 
         self.wrapper.setReturnFormat(JSON)
@@ -189,7 +196,7 @@
         try:
             import rdflib_jsonld
             self.wrapper.setReturnFormat(JSONLD)
-            self.assertEqual(JSONLD, self.wrapper.query().requestedFormat)   
+            self.assertEqual(JSONLD, self.wrapper.query().requestedFormat)
         except ImportError:
             self.assertRaises(ValueError, self.wrapper.setReturnFormat, JSONLD)
 
@@ -199,6 +206,9 @@
         self.assertTrue(self.wrapper.supportsReturnFormat(TURTLE))
         self.assertTrue(self.wrapper.supportsReturnFormat(N3))
         self.assertTrue(self.wrapper.supportsReturnFormat(RDF))
+        self.assertTrue(self.wrapper.supportsReturnFormat(RDFXML))
+        self.assertTrue(self.wrapper.supportsReturnFormat(CSV))
+        self.assertTrue(self.wrapper.supportsReturnFormat(TSV))
         self.assertFalse(self.wrapper.supportsReturnFormat('nonexistent format'))
 
         try:
@@ -229,11 +239,59 @@
         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 testAddCustomHttpHeader(self):
+        request = self._get_request(self.wrapper)
+        self.assertFalse(request.has_header('Foo'))
+
+        # Add new header field name
+        self.wrapper.addCustomHttpHeader('Foo', 'bar')
+        request = self._get_request(self.wrapper)
+        self.assertTrue(request.has_header('Foo'))
+        self.assertEqual("bar", request.get_header('Foo'))
+
+        # Override a new field name
+        self.wrapper.addCustomHttpHeader('Foo', 'bar')
+        request = self._get_request(self.wrapper)
+        self.assertTrue(request.has_header('Foo'))
+        self.assertEqual("bar", request.get_header('Foo'))
+        self.wrapper.addCustomHttpHeader('Foo', 'bar_2')
+        request = self._get_request(self.wrapper)
+        self.assertTrue(request.has_header('Foo'))
+        self.assertEqual("bar_2", request.get_header('Foo'))
+
+        # Override header field name
+        self.wrapper.addCustomHttpHeader('User-agent', 'Another UA')
+        request = self._get_request(self.wrapper)
+        self.assertEqual("Another UA", request.get_header('User-agent'))
+
+    def testClearCustomHttpHeader(self):
+        request = self._get_request(self.wrapper)
+        self.assertFalse(request.has_header('Foo'))
+
+        # Add new header field name
+        self.wrapper.addCustomHttpHeader('Foo_1', 'bar_1')
+        self.wrapper.addCustomHttpHeader('Foo_2', 'bar_2')
+        self.wrapper.addCustomHttpHeader('Foo_3', 'bar_3')
+
+
+        self.assertFalse(self.wrapper.clearCustomHttpHeader('Foo_4'))
+        self.assertTrue(self.wrapper.clearCustomHttpHeader('Foo_3'))
+
+        customHttpHeaders = self.wrapper.customHttpHeaders
+
+        self.assertTrue('Foo_1' in customHttpHeaders)
+        self.assertTrue('Foo_2' in customHttpHeaders)
+        self.assertEqual('bar_1', customHttpHeaders['Foo_1'])
+        self.assertEqual('bar_2', customHttpHeaders['Foo_2'])
+
+        self.assertFalse(self.wrapper.clearCustomHttpHeader('Foo_3'), 'already cleaned')
+
+
     def testSetHTTPAuth(self):
         self.assertRaises(TypeError, self.wrapper.setHTTPAuth, 123)
 
@@ -260,11 +318,11 @@
 
         self.wrapper.setQuery('PREFIX e: <http://example.org/> INSERT {e:a e:b e:c}')
         self.assertEqual(INSERT, self.wrapper.queryType)
-        
-        self.wrapper.setQuery("""#CONSTRUCT {?s ?p ?o} 
+
+        self.wrapper.setQuery("""#CONSTRUCT {?s ?p ?o}
                                    SELECT ?s ?p ?o
                                    WHERE {?s ?p ?o}""")
-        self.assertEqual(SELECT, self.wrapper.queryType)        
+        self.assertEqual(SELECT, self.wrapper.queryType)
 
         with warnings.catch_warnings(record=True) as w:
             self.wrapper.setQuery('UNKNOWN {e:a e:b e:c}')
@@ -489,6 +547,161 @@
         finally:
             _victim.QueryResult = _oldQueryResult
 
+    def testComments(self):
+        # see issue #32
+        self.wrapper.setQuery("""
+# this is a comment
+select * where { ?s ?p ?o }
+""")
+        self.assertTrue(self.wrapper.isSparqlQueryRequest())
+
+    def testHashInPrefixes(self):
+        # see issue #77
+        self.wrapper.setQuery("""
+PREFIX rdfs:    <http://www.w3.org/2000/01/rdf-schema#>
+select * where { ?s ?p ?o }
+""")
+        self.assertTrue(self.wrapper.isSparqlQueryRequest())
+
+    def testHashInPrefixComplex(self):
+        # see issue #77
+        self.wrapper.setQuery("""
+PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+PREFIX rdfs:    <http://www.w3.org/2000/01/rdf-schema#>
+PREFIX weather: <http://hal.zamia.org/weather/>
+PREFIX dbo:     <http://dbpedia.org/ontology/> 
+PREFIX dbr:     <http://dbpedia.org/resource/> 
+PREFIX dbp:     <http://dbpedia.org/property/> 
+PREFIX xml:     <http://www.w3.org/XML/1998/namespace> 
+PREFIX xsd:     <http://www.w3.org/2001/XMLSchema#> 
+
+SELECT DISTINCT ?location ?cityid ?timezone ?label
+WHERE {
+  ?location weather:cityid ?cityid .
+  ?location weather:timezone ?timezone .
+  ?location rdfs:label ?label .
+}
+""")
+        self.assertTrue(self.wrapper.isSparqlQueryRequest())
+
+    def testHashWithNoComments(self):
+        # see issue #77
+        query = """
+PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+
+SELECT *
+WHERE {
+  ?s ?p ?o .
+}
+"""
+        parsed_query = self.wrapper._cleanComments(query)
+        self.assertEquals(query, parsed_query)
+
+    def testCommentBeginningLine(self):
+        # see issue #77
+        query = """
+PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+# a comment
+SELECT *
+WHERE {
+  ?s ?p ?o .
+}
+"""
+        expected_parsed_query = """
+PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+
+SELECT *
+WHERE {
+  ?s ?p ?o .
+}
+"""
+        parsed_query = self.wrapper._cleanComments(query)
+        self.assertEquals(expected_parsed_query, parsed_query)
+
+    def testCommentEmtpyLine(self):
+        # see issue #77
+        query = """
+PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+     # a comment
+SELECT *
+WHERE {
+  ?s ?p ?o .
+}
+"""
+        expected_parsed_query = """
+PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+
+SELECT *
+WHERE {
+  ?s ?p ?o .
+}
+"""
+        parsed_query = self.wrapper._cleanComments(query)
+        self.assertEquals(expected_parsed_query, parsed_query)
+
+    def testCommentsFirstLine(self):
+        # see issue #77
+        query = """#CONSTRUCT {?s ?p ?o}
+                                   SELECT ?s ?p ?o
+                                   WHERE {?s ?p ?o}"""
+        expected_parsed_query = """
+
+                                   SELECT ?s ?p ?o
+                                   WHERE {?s ?p ?o}"""
+
+        parsed_query = self.wrapper._cleanComments(query)
+        self.assertEquals(expected_parsed_query, parsed_query)
+
+    @unittest.skip("issue #80")
+    def testCommentAfterStatements(self):
+        # see issue #77
+        query = """
+PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+
+SELECT *
+WHERE {     # this is the where condition
+  ?s ?p ?o .
+}
+"""
+        expected_parsed_query = """
+PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+
+SELECT *
+WHERE {
+  ?s ?p ?o .
+}
+"""
+        parsed_query = self.wrapper._cleanComments(query)
+        self.assertEquals(expected_parsed_query, parsed_query)
+
+    def testSingleLineQueryLine(self):
+        # see issue #74
+        query = "prefix whatever: <http://example.org/blah#> ASK { ?s ?p ?o }"
+        parsed_query = self.wrapper._cleanComments(query)
+        self.assertEquals(query, parsed_query)
+
+        self.wrapper.setQuery(query)
+        self.assertTrue(self.wrapper.isSparqlQueryRequest())
+
+    def testOnlyConneg(self):
+        # see issue #82
+        query = "prefix whatever: <http://example.org/blah#> ASK { ?s ?p ?o }"
+        self.wrapper.setOnlyConneg(False)
+        self.wrapper.setQuery(query)
+        request = self._get_request(self.wrapper)
+        request_params = dict(parse_qsl(urlparse(request.get_full_url()).query))
+        for returnFormatSetting in ["format", "output", "results"]: # Obviously _returnFormatSetting is not accessible from SPARQLWrapper, so we copy&paste the possible values
+            self.assertTrue(returnFormatSetting in request_params, "URL parameter '%s' was not sent, and it was expected" %returnFormatSetting)
+
+        #ONLY Content Negotiation
+        self.wrapper.resetQuery()
+        self.wrapper.setOnlyConneg(True)
+        self.wrapper.setQuery(query)
+        request = self._get_request(self.wrapper)
+        request_params = dict(parse_qsl(urlparse(request.get_full_url()).query))
+        for returnFormatSetting in ["format", "output", "results"]: # Obviously _returnFormatSetting is not accessible from SPARQLWrapper, so we copy&paste the possible values
+            self.assertFalse(returnFormatSetting in request_params, "URL parameter '%s' was sent, and it was not expected (only Content Negotiation)" %returnFormatSetting)
+
 
 class QueryResult_Test(unittest.TestCase):
 
@@ -554,8 +767,8 @@
 
         def _mime_vs_type(mime, requested_type):
             """
-            @param mime:
-            @param requested_type:
+            @param mime: mimetype/Content-Type of the response
+            @param requested_type: requested mimetype (alias)
             @return: number of warnings produced by combo
             """
             with warnings.catch_warnings(record=True) as w:
@@ -568,14 +781,22 @@
 
                 return len(w)
 
+        # In the cases of "application/ld+json" and "application/rdf+xml", the
+        # RDFLib raised a warning because the manually created QueryResult has no real
+        # response value (implemented a fake read).
+        # "WARNING:rdflib.term:  does not look like a valid URI, trying to serialize this will break."
         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(0, _mime_vs_type("application/ld+json", JSON)) # Warning
+        self.assertEqual(0, _mime_vs_type("application/ld+json", JSONLD)) # Warning
+        self.assertEqual(0, _mime_vs_type("application/rdf+xml", XML)) # Warning
+        self.assertEqual(0, _mime_vs_type("application/rdf+xml", RDF)) # Warning
+        self.assertEqual(0, _mime_vs_type("application/rdf+xml", RDFXML)) # Warning
+        self.assertEqual(0, _mime_vs_type("text/csv", CSV))
+        self.assertEqual(0, _mime_vs_type("text/tab-separated-values", TSV))
+        self.assertEqual(0, _mime_vs_type("application/xml", XML))
 
         self.assertEqual(1, _mime_vs_type("application/x-foo-bar", XML), "invalid mime")
 
@@ -583,11 +804,10 @@
         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))
-
+        self.assertEqual(1, _mime_vs_type("application/ld+json", XML))  # Warning
+        self.assertEqual(1, _mime_vs_type("application/ld+json", N3))  # Warning
+        self.assertEqual(1, _mime_vs_type("application/rdf+xml", JSON))  # Warning
+        self.assertEqual(1, _mime_vs_type("application/rdf+xml", N3))  # Warning
 
 if __name__ == "__main__":
     unittest.main()
diff -Nru sparql-wrapper-python-1.7.6/.travis.yml sparql-wrapper-python-1.8.2/.travis.yml
--- sparql-wrapper-python-1.7.6/.travis.yml	2015-12-18 10:22:56.000000000 +0100
+++ sparql-wrapper-python-1.8.2/.travis.yml	2018-05-16 22:23:01.000000000 +0200
@@ -6,11 +6,16 @@
 
 python:
     - 2.7
-    - 3.2
     - 3.3
     - 3.4
+    - 3.5
+    - 3.6
+    - 3.7-dev
     - pypy
 
+before_install:
+    - pip install --upgrade pip setuptools
+
 install:
     - python setup.py sdist && pip install ./dist/*
 



More information about the Python-modules-team mailing list