Skip to content
Permalink
Browse files

Fix spatialite access with python3

  • Loading branch information
Hugo Mercier
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.
You can’t perform that action at this time.