Skip to content
Permalink
Browse files
Fix spatialite access with python3
  • Loading branch information
Hugo Mercier committed Sep 5, 2016
1 parent 63654e5 commit 5c3a43e286684c5444e5a10eaea9ae3c8ba4a8c6
@@ -5,7 +5,6 @@ PyQgsPalLabelingServer
PyQgsServer
PyQgsServerAccessControl
PyQgsSipCoverage
PyQgsSpatialiteProvider
PyQgsVirtualLayerDefinition
PyQgsVirtualLayerProvider
PyQgsLayerDependencies
@@ -26,7 +26,7 @@
from ..connector import DBConnector
from ..plugin import ConnectionError, DbError, Table

from pyspatialite import dbapi2 as sqlite
from qgis.utils import spatialite_connect


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

try:
self.connection = sqlite.connect(self._connectionInfo())
self.connection = spatialite_connect(self._connectionInfo())

except self.connection_error_types() as e:
raise ConnectionError(e)
@@ -60,7 +60,7 @@ def isValidDatabase(self, path):
if not QFile.exists(path):
return False
try:
conn = sqlite.connect(path)
conn = spatialite_connect(path)
except self.connection_error_types():
return False

@@ -25,10 +25,7 @@

__revision__ = '$Format:%H$'

try:
from pyspatialite import dbapi2 as sqlite
except:
pass
from qgis.utils import spatialite_connect


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

try:
self.con = sqlite.connect(self.con_info())
self.con = spatialite_connect(self.con_info())

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

try:
self.con = sqlite.connect(self.con_info())
self.con = spatialite_connect(self.con_info())

except (sqlite.InterfaceError, sqlite.OperationalError) as e:
raise DbError(unicode(e))
@@ -585,6 +585,41 @@ def startServerPlugin(packageName):
return True


def spatialite_connect(*args, **kwargs):
"""returns a dbapi2.Connection to a spatialite db
either using pyspatialite if it is present
or using the "mod_spatialite" extension (python3)"""
try:
from pyspatialite import dbapi2
except ImportError:
import sqlite3
con = sqlite3.dbapi2.connect(*args, **kwargs)
con.enable_load_extension(True)
cur = con.cursor()
libs = [
# Spatialite >= 4.2 and Sqlite >= 3.7.17, should work on all platforms
("mod_spatialite", "sqlite3_modspatialite_init"),
# Spatialite >= 4.2 and Sqlite < 3.7.17 (Travis)
("mod_spatialite.so", "sqlite3_modspatialite_init"),
# Spatialite < 4.2 (linux)
("libspatialite.so", "sqlite3_extension_init")
]
found = False
for lib, entry_point in libs:
try:
cur.execute("select load_extension('{}', '{}')".format(lib, entry_point))
except sqlite3.OperationalError:
continue
else:
found = True
break
if not found:
raise RuntimeError("Cannot find any suitable spatialite module")
cur.close()
con.enable_load_extension(False)
return con
return dbapi2.connect(*args, **kwargs)

#######################
# IMPORT wrapper

@@ -37,11 +37,7 @@

import tempfile

try:
from pyspatialite import dbapi2 as sqlite3
except ImportError:
print("You should install pyspatialite to run the tests")
raise ImportError
from qgis.utils import spatialite_connect

# Convenience instances in case you may need them
start_app()
@@ -58,7 +54,7 @@ def setUpClass(cls):
fn = fo.name
fo.close()
cls.fn = fn
con = sqlite3.connect(fn)
con = spatialite_connect(fn)
cur = con.cursor()
cur.execute("SELECT InitSpatialMetadata(1)")
cur.execute("create table node(id integer primary key autoincrement);")
@@ -26,11 +26,7 @@
from providertestbase import ProviderTestCase
from qgis.PyQt.QtCore import QSettings

try:
from pyspatialite import dbapi2 as sqlite3
except ImportError:
print("You should install pyspatialite to run the tests")
raise ImportError
from qgis.utils import spatialite_connect

# Pass no_exit=True: for some reason this crashes on exit on Travis MacOSX
start_app(sys.platform != 'darwin')
@@ -70,7 +66,7 @@ def setUpClass(cls):
cls.dbname = os.path.join(tempfile.gettempdir(), "test.sqlite")
if os.path.exists(cls.dbname):
os.remove(cls.dbname)
con = sqlite3.connect(cls.dbname, isolation_level=None)
con = spatialite_connect(cls.dbname, isolation_level=None)
cur = con.cursor()
cur.execute("BEGIN")
sql = "SELECT InitSpatialMetadata()"
@@ -227,7 +223,7 @@ def test_invalid_iterator(self):
shutil.copy(self.dbname, corrupt_dbname)
layer = QgsVectorLayer("dbname=%s table=test_pg (geometry)" % corrupt_dbname, "test_pg", "spatialite")
# Corrupt the database
open(corrupt_dbname, 'wb').write('')
open(corrupt_dbname, 'wb').write(b'')
layer.getFeatures()
layer = None
os.unlink(corrupt_dbname)
@@ -34,11 +34,7 @@
from providertestbase import ProviderTestCase
from qgis.PyQt.QtCore import QUrl, QVariant

try:
from pyspatialite import dbapi2 as sqlite3
except ImportError:
print("You should install pyspatialite to run the tests")
raise ImportError
from qgis.utils import spatialite_connect

import tempfile

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

from qgis.testing import start_app, unittest

from pyspatialite import dbapi2 as sqlite3
from qgis.utils import spatialite_connect

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

2 comments on commit 5c3a43e

@nirvn

This comment has been minimized.

Copy link
Contributor

@nirvn nirvn replied Sep 5, 2016

Yay!

@nirvn

This comment has been minimized.

Copy link
Contributor

@nirvn nirvn replied Oct 6, 2016

@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.