Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fix spatialite access with python3
  • Loading branch information
Hugo Mercier committed Sep 5, 2016
1 parent 63654e5 commit 5c3a43e
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 31 deletions.
1 change: 0 additions & 1 deletion ci/travis/linux/qt5/blacklist.txt
Expand Up @@ -5,7 +5,6 @@ PyQgsPalLabelingServer
PyQgsServer
PyQgsServerAccessControl
PyQgsSipCoverage
PyQgsSpatialiteProvider
PyQgsVirtualLayerDefinition
PyQgsVirtualLayerProvider
PyQgsLayerDependencies
Expand Down
6 changes: 3 additions & 3 deletions python/plugins/db_manager/db_plugins/spatialite/connector.py
Expand Up @@ -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():
Expand All @@ -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)
Expand All @@ -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

Expand Down
9 changes: 3 additions & 6 deletions python/plugins/processing/tools/spatialite.py
Expand Up @@ -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):
Expand All @@ -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))
Expand Down Expand Up @@ -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))
Expand Down
35 changes: 35 additions & 0 deletions python/utils.py
Expand Up @@ -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

Expand Down
8 changes: 2 additions & 6 deletions tests/src/python/test_layer_dependencies.py
Expand Up @@ -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()
Expand All @@ -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);")
Expand Down
10 changes: 3 additions & 7 deletions tests/src/python/test_provider_spatialite.py
Expand Up @@ -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')
Expand Down Expand Up @@ -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()"
Expand Down Expand Up @@ -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)
Expand Down
8 changes: 2 additions & 6 deletions tests/src/python/test_provider_virtual.py
Expand Up @@ -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

Expand Down Expand Up @@ -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)")
Expand Down
4 changes: 2 additions & 2 deletions tests/src/python/test_qgsissue7244.py
Expand Up @@ -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()
Expand All @@ -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()"
Expand Down

2 comments on commit 5c3a43e

@nirvn
Copy link
Contributor

@nirvn nirvn commented on 5c3a43e Sep 5, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay!

@nirvn
Copy link
Contributor

@nirvn nirvn commented on 5c3a43e Oct 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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