Skip to content
Permalink
Browse files

Fix extraction of ogr LayerName from multi-layer dataset URIs

Adds supports for "layerid" when present.
Drop special handling for "table=" portions found in URI,
making the code more generic.

Includes testcase.

Fixes #15698 - import geodatabase to postgis via processing
  • Loading branch information
strk committed Oct 15, 2016
1 parent 167a5af commit c4222687e002f67604752b016b862039b06a6415
@@ -7,6 +7,7 @@ PLUGIN_INSTALL(processing tests/data ${TEST_DATA_FILES})
IF(ENABLE_TESTS)
INCLUDE(UsePythonTest)
ADD_PYTHON_TEST(ProcessingParametersTest ParametersTest.py)
ADD_PYTHON_TEST(ProcessingToolsTest ToolsTest.py)
ADD_PYTHON_TEST(ProcessingQgisAlgorithmsTest QgisAlgorithmsTest.py)
ADD_PYTHON_TEST(ProcessingGdalAlgorithmsTest GdalAlgorithmsTest.py)
ENDIF(ENABLE_TESTS)
@@ -0,0 +1,119 @@
# -*- coding: utf-8 -*-

"""
***************************************************************************
ToolsTest
---------------------
Date : July 2017
Copyright : (C) 2017 by Nyall Dawson
Email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""

__author__ = 'Nyall Dawson'
__date__ = 'July 2016'
__copyright__ = '(C) 2016, Nyall Dawson'

# This will get replaced with a git SHA1 when you do a git archive

__revision__ = '$Format:%H$'

from qgis.testing import start_app, unittest
from processing.tests.TestData import points2
from processing.tools import vector
from qgis.core import (QgsVectorLayer, QgsFeatureRequest)
from processing.core.ProcessingConfig import ProcessingConfig

import os.path
import errno
import shutil

dataFolder = os.path.join(os.path.dirname(__file__), '../../../../tests/testdata/')
tmpBaseFolder = os.path.join(os.sep, 'tmp', 'qgis_test', str(os.getpid()))


def mkDirP(path):
try:
os.makedirs(path)
except OSError as exc:
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise

start_app()


class VectorTest(unittest.TestCase):

@classmethod
def setUpClass(cls):
mkDirP(tmpBaseFolder)

@classmethod
def tearDownClass(cls):
shutil.rmtree(tmpBaseFolder)
pass

# See http://hub.qgis.org/issues/15698
def test_ogrLayerName(self):
tmpdir = os.path.join(tmpBaseFolder, 'ogrLayerName')
os.mkdir(tmpdir)

def linkTestfile(f, t):
os.link(os.path.join(dataFolder, f), os.path.join(tmpdir, t))

linkTestfile('geom_data.csv', 'a.csv')
name = vector.ogrLayerName(tmpdir)
self.assertEqual(name, 'a')

linkTestfile('wkt_data.csv', 'b.csv')
name = vector.ogrLayerName(tmpdir + '|layerid=0')
self.assertEqual(name, 'a')
name = vector.ogrLayerName(tmpdir + '|layerid=1')
self.assertEqual(name, 'b')

name = vector.ogrLayerName(tmpdir + '|layerid=2')
self.assertEqual(name, 'invalid-layerid')

name = vector.ogrLayerName(tmpdir + '|layername=f')
self.assertEqual(name, 'f') # layername takes precedence

name = vector.ogrLayerName(tmpdir + '|layerid=0|layername=f2')
self.assertEqual(name, 'f2') # layername takes precedence

name = vector.ogrLayerName(tmpdir + '|layername=f2|layerid=0')
self.assertEqual(name, 'f2') # layername takes precedence

def testFeatures(self):
ProcessingConfig.initialize()

test_data = points2()
test_layer = QgsVectorLayer(test_data, 'test', 'ogr')

# test with all features
features = vector.features(test_layer)
self.assertEqual(len(features), 8)
self.assertEqual(set([f.id() for f in features]), set([0, 1, 2, 3, 4, 5, 6, 7]))

previous_value = ProcessingConfig.getSetting(ProcessingConfig.USE_SELECTED)

# using selected features, but no selection
ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, True)
test_layer.removeSelection()
features = vector.features(test_layer)
self.assertEqual(len(features), 8)
self.assertEqual(set([f.id() for f in features]), set([0, 1, 2, 3, 4, 5, 6, 7]))

ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, previous_value)


if __name__ == '__main__':
unittest.main()
@@ -38,6 +38,8 @@

from PyQt4 import QtSql
from PyQt4.QtCore import QVariant, QSettings
from osgeo import ogr

from qgis.core import (QGis, QgsFields, QgsField, QgsGeometry, QgsRectangle,
QgsSpatialIndex, QgsMapLayerRegistry, QgsMapLayer, QgsVectorLayer,
QgsVectorFileWriter, QgsDistanceArea, QgsDataSourceURI, QgsCredentials)
@@ -511,20 +513,26 @@ def ogrConnectionString(uri):


def ogrLayerName(uri):
if 'host' in uri:
regex = re.compile('(table=")(.+?)(\.)(.+?)"')
r = regex.search(uri)
return '"' + r.groups()[1] + '.' + r.groups()[3] + '"'
elif 'dbname' in uri:
regex = re.compile('(table=")(.+?)"')
r = regex.search(uri)
return r.groups()[1]
elif 'layername' in uri:
regex = re.compile('(layername=)(.*)')
r = regex.search(uri)
return r.groups()[1]
else:
return os.path.basename(os.path.splitext(uri)[0])
fields = uri.split('|')
ogruri = fields[0]
fields = fields[1:]
layerid = 0
for f in fields:
if f.startswith('layername='):
# Name encoded in uri, nothing more needed
return f.split('=')[1]
if f.startswith('layerid='):
layerid = int(f.split('=')[1])
# Last layerid= takes precedence, to allow of layername to
# take precedence
ds = ogr.Open(ogruri)
if not ds:
return "invalid-uri"
ly = ds.GetLayer(layerid)
if not ly:
return "invalid-layerid"
name = ly.GetName()
return name


class VectorWriter:

0 comments on commit c422268

Please sign in to comment.
You can’t perform that action at this time.