Skip to content

Commit 5c3a43e

Browse files
author
Hugo Mercier
committedSep 5, 2016
Fix spatialite access with python3
1 parent 63654e5 commit 5c3a43e

File tree

8 files changed

+50
-31
lines changed

8 files changed

+50
-31
lines changed
 

‎ci/travis/linux/qt5/blacklist.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ PyQgsPalLabelingServer
55
PyQgsServer
66
PyQgsServerAccessControl
77
PyQgsSipCoverage
8-
PyQgsSpatialiteProvider
98
PyQgsVirtualLayerDefinition
109
PyQgsVirtualLayerProvider
1110
PyQgsLayerDependencies

‎python/plugins/db_manager/db_plugins/spatialite/connector.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from ..connector import DBConnector
2727
from ..plugin import ConnectionError, DbError, Table
2828

29-
from pyspatialite import dbapi2 as sqlite
29+
from qgis.utils import spatialite_connect
3030

3131

3232
def classFactory():
@@ -43,7 +43,7 @@ def __init__(self, uri):
4343
raise ConnectionError(QApplication.translate("DBManagerPlugin", '"{0}" not found').format(self.dbname))
4444

4545
try:
46-
self.connection = sqlite.connect(self._connectionInfo())
46+
self.connection = spatialite_connect(self._connectionInfo())
4747

4848
except self.connection_error_types() as e:
4949
raise ConnectionError(e)
@@ -60,7 +60,7 @@ def isValidDatabase(self, path):
6060
if not QFile.exists(path):
6161
return False
6262
try:
63-
conn = sqlite.connect(path)
63+
conn = spatialite_connect(path)
6464
except self.connection_error_types():
6565
return False
6666

‎python/plugins/processing/tools/spatialite.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,7 @@
2525

2626
__revision__ = '$Format:%H$'
2727

28-
try:
29-
from pyspatialite import dbapi2 as sqlite
30-
except:
31-
pass
28+
from qgis.utils import spatialite_connect
3229

3330

3431
class DbError(Exception):
@@ -49,7 +46,7 @@ def __init__(self, uri=None):
4946
self.dbname = uri.database()
5047

5148
try:
52-
self.con = sqlite.connect(self.con_info())
49+
self.con = spatialite_connect(self.con_info())
5350

5451
except (sqlite.InterfaceError, sqlite.OperationalError) as e:
5552
raise DbError(unicode(e))
@@ -84,7 +81,7 @@ def init_spatialite(self):
8481
self.con.close()
8582

8683
try:
87-
self.con = sqlite.connect(self.con_info())
84+
self.con = spatialite_connect(self.con_info())
8885

8986
except (sqlite.InterfaceError, sqlite.OperationalError) as e:
9087
raise DbError(unicode(e))

‎python/utils.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,41 @@ def startServerPlugin(packageName):
585585
return True
586586

587587

588+
def spatialite_connect(*args, **kwargs):
589+
"""returns a dbapi2.Connection to a spatialite db
590+
either using pyspatialite if it is present
591+
or using the "mod_spatialite" extension (python3)"""
592+
try:
593+
from pyspatialite import dbapi2
594+
except ImportError:
595+
import sqlite3
596+
con = sqlite3.dbapi2.connect(*args, **kwargs)
597+
con.enable_load_extension(True)
598+
cur = con.cursor()
599+
libs = [
600+
# Spatialite >= 4.2 and Sqlite >= 3.7.17, should work on all platforms
601+
("mod_spatialite", "sqlite3_modspatialite_init"),
602+
# Spatialite >= 4.2 and Sqlite < 3.7.17 (Travis)
603+
("mod_spatialite.so", "sqlite3_modspatialite_init"),
604+
# Spatialite < 4.2 (linux)
605+
("libspatialite.so", "sqlite3_extension_init")
606+
]
607+
found = False
608+
for lib, entry_point in libs:
609+
try:
610+
cur.execute("select load_extension('{}', '{}')".format(lib, entry_point))
611+
except sqlite3.OperationalError:
612+
continue
613+
else:
614+
found = True
615+
break
616+
if not found:
617+
raise RuntimeError("Cannot find any suitable spatialite module")
618+
cur.close()
619+
con.enable_load_extension(False)
620+
return con
621+
return dbapi2.connect(*args, **kwargs)
622+
588623
#######################
589624
# IMPORT wrapper
590625

‎tests/src/python/test_layer_dependencies.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,7 @@
3737

3838
import tempfile
3939

40-
try:
41-
from pyspatialite import dbapi2 as sqlite3
42-
except ImportError:
43-
print("You should install pyspatialite to run the tests")
44-
raise ImportError
40+
from qgis.utils import spatialite_connect
4541

4642
# Convenience instances in case you may need them
4743
start_app()
@@ -58,7 +54,7 @@ def setUpClass(cls):
5854
fn = fo.name
5955
fo.close()
6056
cls.fn = fn
61-
con = sqlite3.connect(fn)
57+
con = spatialite_connect(fn)
6258
cur = con.cursor()
6359
cur.execute("SELECT InitSpatialMetadata(1)")
6460
cur.execute("create table node(id integer primary key autoincrement);")

‎tests/src/python/test_provider_spatialite.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,7 @@
2626
from providertestbase import ProviderTestCase
2727
from qgis.PyQt.QtCore import QSettings
2828

29-
try:
30-
from pyspatialite import dbapi2 as sqlite3
31-
except ImportError:
32-
print("You should install pyspatialite to run the tests")
33-
raise ImportError
29+
from qgis.utils import spatialite_connect
3430

3531
# Pass no_exit=True: for some reason this crashes on exit on Travis MacOSX
3632
start_app(sys.platform != 'darwin')
@@ -70,7 +66,7 @@ def setUpClass(cls):
7066
cls.dbname = os.path.join(tempfile.gettempdir(), "test.sqlite")
7167
if os.path.exists(cls.dbname):
7268
os.remove(cls.dbname)
73-
con = sqlite3.connect(cls.dbname, isolation_level=None)
69+
con = spatialite_connect(cls.dbname, isolation_level=None)
7470
cur = con.cursor()
7571
cur.execute("BEGIN")
7672
sql = "SELECT InitSpatialMetadata()"
@@ -227,7 +223,7 @@ def test_invalid_iterator(self):
227223
shutil.copy(self.dbname, corrupt_dbname)
228224
layer = QgsVectorLayer("dbname=%s table=test_pg (geometry)" % corrupt_dbname, "test_pg", "spatialite")
229225
# Corrupt the database
230-
open(corrupt_dbname, 'wb').write('')
226+
open(corrupt_dbname, 'wb').write(b'')
231227
layer.getFeatures()
232228
layer = None
233229
os.unlink(corrupt_dbname)

‎tests/src/python/test_provider_virtual.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,7 @@
3434
from providertestbase import ProviderTestCase
3535
from qgis.PyQt.QtCore import QUrl, QVariant
3636

37-
try:
38-
from pyspatialite import dbapi2 as sqlite3
39-
except ImportError:
40-
print("You should install pyspatialite to run the tests")
41-
raise ImportError
37+
from qgis.utils import spatialite_connect
4238

4339
import tempfile
4440

@@ -108,7 +104,7 @@ def test_source_escaping2(self):
108104
def create_test_db(dbfile):
109105
if os.path.exists(dbfile):
110106
os.remove(dbfile)
111-
con = sqlite3.connect(dbfile)
107+
con = spatialite_connect(dbfile)
112108
cur = con.cursor()
113109
cur.execute("SELECT InitSpatialMetadata(1)")
114110
cur.execute("CREATE TABLE test (id INTEGER, name TEXT)")

‎tests/src/python/test_qgsissue7244.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
from qgis.testing import start_app, unittest
2222

23-
from pyspatialite import dbapi2 as sqlite3
23+
from qgis.utils import spatialite_connect
2424

2525
# Convenience instances in case you may need them
2626
start_app()
@@ -38,7 +38,7 @@ def setUpClass(cls):
3838
# create test db
3939
if os.path.exists("test.sqlite"):
4040
os.remove("test.sqlite")
41-
con = sqlite3.connect("test.sqlite", isolation_level=None)
41+
con = spatialite_connect("test.sqlite", isolation_level=None)
4242
cur = con.cursor()
4343
cur.execute("BEGIN")
4444
sql = "SELECT InitSpatialMetadata()"

2 commit comments

Comments
 (2)

nirvn commented on Sep 5, 2016

@nirvn
Contributor

Yay!

nirvn commented on Oct 6, 2016

@nirvn
Contributor

@mhugo , nice; you missed two references to the (removed) sqlite object in db manager's spatialite connector.py (line 744 and line 747) which deals with SQL execution errors.

Please sign in to comment.