Raise proper exceptions from search

This commit is contained in:
Alessandro Pasotti 2022-09-01 11:32:13 +02:00
parent fa55567ecf
commit eb76172122
7 changed files with 53 additions and 17 deletions

View File

@ -806,7 +806,7 @@ The caller takes ownership of the returned object.
.. versionadded:: 3.28
%End
virtual QList<QgsLayerMetadataProviderResult> searchLayerMetadata( const QgsMetadataSearchContext &searchContext, const QString &searchString = QString(), const QgsRectangle &geographicExtent = QgsRectangle(), QgsFeedback *feedback = 0 ) const throw( QgsProviderConnectionException );
virtual QList<QgsLayerMetadataProviderResult> searchLayerMetadata( const QgsMetadataSearchContext &searchContext, const QString &searchString = QString(), const QgsRectangle &geographicExtent = QgsRectangle(), QgsFeedback *feedback = 0 ) const throw( QgsProviderConnectionException, QgsNotSupportedException );
%Docstring
Search the stored layer metadata in the connection,
optionally limiting the search to the metadata identifier, title,
@ -815,14 +815,19 @@ abstract, keywords and categories.
``searchString`` limit the search to metadata having an extent intersecting ``geographicExtent``,
an optional ``feedback`` can be used to monitor and control the search process.
The default implementation raises a :py:class:`QgsProviderConnectionException`, data providers may implement
The default implementation raises a :py:class:`QgsNotSupportedException`, data providers may implement
the search functionality.
A :py:class:`QgsProviderConnectionException` is raised in case of errors happening during the search for
providers that implement the search functionality.
:return: a (possibly empty) list of :py:class:`QgsLayerMetadataProviderResult`, throws a :py:class:`QgsProviderConnectionException`
if any error occurred during the search.
:raises QgsProviderConnectionException:
:raises QgsNotSupportedException:
.. versionadded:: 3.28
%End

View File

@ -513,7 +513,7 @@ sub fix_annotations {
$line =~ s/SIP_PYNAME\(\s*(\w+)\s*\)/\/PyName=$1\//;
$line =~ s/SIP_TYPEHINT\(\s*([\w\.\s,\[\]]+?)\s*\)/\/TypeHint="$1"\//g;
$line =~ s/SIP_VIRTUALERRORHANDLER\(\s*(\w+)\s*\)/\/VirtualErrorHandler=$1\//;
$line =~ s/SIP_THROW\(\s*(\w+)\s*\)/throw\( $1 \)/;
$line =~ s/SIP_THROW\(\s*([\w\s,]+?)\s*\)/throw\( $1 \)/;
# combine multiple annotations
# https://regex101.com/r/uvCt4M/5

View File

@ -516,13 +516,13 @@ QList<QgsLayerMetadataProviderResult> QgsGeoPackageProviderConnection::searchLay
}
else
{
QgsDebugMsg( QStringLiteral( "Error reading XML metdadata from connection %1" ).arg( uri() ) );
throw QgsProviderConnectionException( QStringLiteral( "Error reading XML metdadata from connection %1" ).arg( uri() ) );
}
}
}
catch ( const QgsProviderConnectionException &ex )
{
QgsDebugMsg( QStringLiteral( "Error fetching metdadata from connection %1: %2" ).arg( uri(), ex.what() ) );
throw QgsProviderConnectionException( QStringLiteral( "Error fetching metdadata from connection %1: %2" ).arg( uri(), ex.what() ) );
}
}
return results;

View File

@ -1087,7 +1087,7 @@ QList<QgsLayerMetadataProviderResult> QgsAbstractDatabaseProviderConnection::sea
Q_UNUSED( searchContext );
Q_UNUSED( searchString );
Q_UNUSED( geographicExtent );
throw QgsProviderConnectionException( QObject::tr( "Provider %1 has no %2 method" ).arg( providerKey(), QStringLiteral( "searchLayerMetadata" ) ) );
throw QgsNotSupportedException( QObject::tr( "Provider %1 has no %2 method" ).arg( providerKey(), QStringLiteral( "searchLayerMetadata" ) ) );
}
void QgsAbstractDatabaseProviderConnection::dropRasterTable( const QString &, const QString & ) const

View File

@ -923,15 +923,19 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
* \a searchString limit the search to metadata having an extent intersecting \a geographicExtent,
* an optional \a feedback can be used to monitor and control the search process.
*
* The default implementation raises a QgsProviderConnectionException, data providers may implement
* The default implementation raises a QgsNotSupportedException, data providers may implement
* the search functionality.
*
* A QgsProviderConnectionException is raised in case of errors happening during the search for
* providers that implement the search functionality.
*
* \returns a (possibly empty) list of QgsLayerMetadataProviderResult, throws a QgsProviderConnectionException
* if any error occurred during the search.
* \throws QgsProviderConnectionException
* \throws QgsNotSupportedException
* \since QGIS 3.28
*/
virtual QList<QgsLayerMetadataProviderResult> searchLayerMetadata( const QgsMetadataSearchContext &searchContext, const QString &searchString = QString(), const QgsRectangle &geographicExtent = QgsRectangle(), QgsFeedback *feedback = nullptr ) const SIP_THROW( QgsProviderConnectionException );
virtual QList<QgsLayerMetadataProviderResult> searchLayerMetadata( const QgsMetadataSearchContext &searchContext, const QString &searchString = QString(), const QgsRectangle &geographicExtent = QgsRectangle(), QgsFeedback *feedback = nullptr ) const SIP_THROW( QgsProviderConnectionException, QgsNotSupportedException );
protected:

View File

@ -195,7 +195,7 @@
* try/catch blocks around call and catch the correct exception, otherwise only
* unknown generic exceptions are available for Python code.
*/
#define SIP_THROW(name)
#define SIP_THROW(name, ...)
/*
* Will insert a `%End` directive in sip files

View File

@ -13,6 +13,8 @@ __copyright__ = 'Copyright 2022, ItOpen'
import os
import shutil
from functools import partial
from stat import S_IREAD, S_IRGRP, S_IROTH, S_IWUSR
from qgis.core import (
QgsPolygon,
@ -21,10 +23,12 @@ from qgis.core import (
QgsMapLayerType,
QgsProviderRegistry,
QgsAbstractLayerMetadataProvider,
QgsLayerMetadataSearchResult,
QgsLayerMetadataSearchResults,
QgsLayerMetadataProviderResult,
QgsMetadataSearchContext,
QgsLayerMetadata,
QgsNotSupportedException,
QgsProviderConnectionException,
)
from qgis.PyQt.QtCore import QTemporaryDir
@ -102,7 +106,7 @@ class PythonLayerMetadataProvider(QgsAbstractLayerMetadataProvider):
assert result.identifier() == 'MD012345'
results = QgsLayerMetadataSearchResult()
results = QgsLayerMetadataSearchResults()
results.addMetadata(result)
results.addError('Bad news from PythonLayerMetadataProvider :(')
@ -114,6 +118,16 @@ QGIS_APP = start_app()
class TestPythonLayerMetadataProvider(unittest.TestCase):
def setUp(self):
super().setUp()
srcpath = os.path.join(TEST_DATA_DIR, 'provider')
shutil.copy(os.path.join(srcpath, 'geopackage.gpkg'), temp_path)
self.conn = os.path.join(temp_path, 'geopackage.gpkg')
shutil.copy(os.path.join(srcpath, 'spatialite.db'), temp_path)
self.conn_sl = os.path.join(temp_path, 'spatialite.db')
def test_metadataRegistryApi(self):
reg = QGIS_APP.layerMetadataProviderRegistry()
@ -141,13 +155,26 @@ class TestPythonLayerMetadataProvider(unittest.TestCase):
reg.unregisterLayerMetadataProvider(md_provider)
self.assertIsNone(reg.layerMetadataProviderFromId('python'))
def setUp(self):
def testExceptions(self):
super().setUp()
srcpath = os.path.join(TEST_DATA_DIR, 'provider')
shutil.copy(os.path.join(srcpath, 'geopackage.gpkg'), temp_path)
self.conn = os.path.join(temp_path, 'geopackage.gpkg')
md = QgsProviderRegistry.instance().providerMetadata('ogr')
def _spatialite(path):
md = QgsProviderRegistry.instance().providerMetadata('spatialite')
conn = md.createConnection(path, {})
conn.searchLayerMetadata(QgsMetadataSearchContext())
def _ogr(path):
md = QgsProviderRegistry.instance().providerMetadata('ogr')
conn = md.createConnection(path, {})
os.chmod(path, S_IREAD | S_IRGRP | S_IROTH)
conn.searchLayerMetadata(QgsMetadataSearchContext())
self.assertRaises(QgsNotSupportedException, partial(_spatialite, self.conn_sl))
self.assertRaises(QgsProviderConnectionException, partial(_ogr, self.conn))
self.assertRaises(QgsNotSupportedException, partial(_ogr, self.conn_sl))
os.chmod(self.conn, S_IWUSR | S_IREAD)
os.chmod(self.conn_sl, S_IWUSR | S_IREAD)
if __name__ == '__main__':