Skip to content

Commit e3f02ea

Browse files
authored
Merge pull request #7012 from elpaso/python-provider
Python provider QEP 122
2 parents b2fce73 + 73cfe04 commit e3f02ea

12 files changed

+981
-13
lines changed

python/core/auto_generated/qgsfeatureiterator.sip.in

+6-2
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,15 @@ Wrapper for iterator of features from vector data provider or vector layer
223223

224224
QgsFeatureIterator();
225225
%Docstring
226-
construct invalid iterator
226+
Construct invalid iterator
227+
%End
228+
QgsFeatureIterator( QgsAbstractFeatureIterator *iter /Transfer/ );
229+
%Docstring
230+
Construct a valid iterator
227231
%End
228232
QgsFeatureIterator( const QgsFeatureIterator &fi );
229233
%Docstring
230-
copy constructor copies the iterator, increases ref.count
234+
Copy constructor copies the iterator, increases ref.count
231235
%End
232236
~QgsFeatureIterator();
233237

python/core/auto_generated/qgsprovidermetadata.sip.in

+45
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,51 @@ library object.
3636

3737
QgsProviderMetadata( const QString &_key, const QString &_description, const QString &_library );
3838

39+
QgsProviderMetadata( const QString &key, const QString &description, SIP_PYCALLABLE / AllowNone / );
40+
%Docstring
41+
Metadata for provider with direct provider creation function pointer, where
42+
no library is involved.
43+
44+
.. versionadded:: 3.0
45+
%End
46+
%MethodCode
47+
48+
// Make sure the callable doesn't get garbage collected, this is needed because refcount for a2 is 0
49+
// and the creation function pointer is passed to the metadata and it needs to be kept in memory.
50+
Py_INCREF( a2 );
51+
52+
Py_BEGIN_ALLOW_THREADS
53+
54+
sipCpp = new QgsProviderMetadata( *a0, *a1, [a2]( const QString &dataSource, const QgsDataProvider::ProviderOptions &providerOptions ) -> QgsDataProvider*
55+
{
56+
QgsDataProvider *provider;
57+
provider = nullptr;
58+
PyObject *sipResObj;
59+
SIP_BLOCK_THREADS
60+
61+
sipResObj = sipCallMethod( nullptr, a2, "DD", new QString( dataSource ), sipType_QString, nullptr, new QgsDataProvider::ProviderOptions( providerOptions ), sipType_QgsDataProvider_ProviderOptions, NULL );
62+
63+
if ( sipResObj )
64+
{
65+
if ( sipCanConvertToType( sipResObj, sipType_QgsDataProvider, SIP_NOT_NONE ) )
66+
{
67+
int state0;
68+
int sipIsErr = 0;
69+
provider = reinterpret_cast<QgsDataProvider *>( sipConvertToType( sipResObj, sipType_QgsDataProvider, nullptr, SIP_NOT_NONE, &state0, &sipIsErr ) );
70+
if ( sipIsErr != 0 )
71+
{
72+
sipReleaseType( provider, sipType_QgsDataProvider, state0 );
73+
provider = nullptr;
74+
}
75+
}
76+
}
77+
SIP_UNBLOCK_THREADS
78+
return provider;
79+
} );
80+
81+
Py_END_ALLOW_THREADS
82+
83+
%End
3984

4085
QString key() const;
4186
%Docstring

python/core/auto_generated/qgsproviderregistry.sip.in

+13
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,19 @@ Returns a string containing the available protocol drivers
180180

181181
void registerGuis( QWidget *widget );
182182

183+
bool registerProvider( QgsProviderMetadata *providerMetadata /Transfer/ );
184+
%Docstring
185+
register a new vector data provider from its ``providerMetadata``
186+
187+
:return: true on success, false if a provider with the same key was already registered
188+
189+
.. note::
190+
191+
ownership of the QgsProviderMetadata instance is transferred to the registry
192+
193+
.. versionadded:: 3.2
194+
%End
195+
183196

184197

185198
private:

src/core/qgsfeatureiterator.h

+5-7
Original file line numberDiff line numberDiff line change
@@ -286,15 +286,13 @@ class CORE_EXPORT QgsFeatureIterator
286286
% End
287287
#endif
288288

289-
//! construct invalid iterator
289+
//! Construct invalid iterator
290290
QgsFeatureIterator() = default;
291-
#ifndef SIP_RUN
292-
//! construct a valid iterator
293-
QgsFeatureIterator( QgsAbstractFeatureIterator *iter );
294-
#endif
295-
//! copy constructor copies the iterator, increases ref.count
291+
//! Construct a valid iterator
292+
QgsFeatureIterator( QgsAbstractFeatureIterator *iter SIP_TRANSFER );
293+
//! Copy constructor copies the iterator, increases ref.count
296294
QgsFeatureIterator( const QgsFeatureIterator &fi );
297-
//! destructor deletes the iterator if it has no more references
295+
//! Destructor deletes the iterator if it has no more references
298296
~QgsFeatureIterator();
299297

300298
QgsFeatureIterator &operator=( const QgsFeatureIterator &other );

src/core/qgsmaplayer.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -912,7 +912,7 @@ QString QgsMapLayer::loadNamedProperty( const QString &uri, QgsMapLayer::Propert
912912
QFile myFile( uri );
913913
if ( myFile.open( QFile::ReadOnly ) )
914914
{
915-
QgsDebugMsg( QString( "file found %1" ).arg( uri ) );
915+
QgsDebugMsgLevel( QString( "file found %1" ).arg( uri ), 2 );
916916
// read file
917917
resultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
918918
if ( !resultFlag )

src/core/qgsprovidermetadata.h

+43-2
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,51 @@ class CORE_EXPORT QgsProviderMetadata
5858
/**
5959
* Metadata for provider with direct provider creation function pointer, where
6060
* no library is involved.
61-
* \note not available in Python bindings
6261
* \since QGIS 3.0
6362
*/
64-
SIP_SKIP QgsProviderMetadata( const QString &key, const QString &description, const QgsProviderMetadata::CreateDataProviderFunction &createFunc );
63+
#ifndef SIP_RUN
64+
QgsProviderMetadata( const QString &key, const QString &description, const QgsProviderMetadata::CreateDataProviderFunction &createFunc );
65+
#else
66+
QgsProviderMetadata( const QString &key, const QString &description, SIP_PYCALLABLE / AllowNone / );
67+
% MethodCode
68+
69+
// Make sure the callable doesn't get garbage collected, this is needed because refcount for a2 is 0
70+
// and the creation function pointer is passed to the metadata and it needs to be kept in memory.
71+
Py_INCREF( a2 );
72+
73+
Py_BEGIN_ALLOW_THREADS
74+
75+
sipCpp = new QgsProviderMetadata( *a0, *a1, [a2]( const QString &dataSource, const QgsDataProvider::ProviderOptions &providerOptions ) -> QgsDataProvider*
76+
{
77+
QgsDataProvider *provider;
78+
provider = nullptr;
79+
PyObject *sipResObj;
80+
SIP_BLOCK_THREADS
81+
82+
sipResObj = sipCallMethod( nullptr, a2, "DD", new QString( dataSource ), sipType_QString, nullptr, new QgsDataProvider::ProviderOptions( providerOptions ), sipType_QgsDataProvider_ProviderOptions, NULL );
83+
84+
if ( sipResObj )
85+
{
86+
if ( sipCanConvertToType( sipResObj, sipType_QgsDataProvider, SIP_NOT_NONE ) )
87+
{
88+
int state0;
89+
int sipIsErr = 0;
90+
provider = reinterpret_cast<QgsDataProvider *>( sipConvertToType( sipResObj, sipType_QgsDataProvider, nullptr, SIP_NOT_NONE, &state0, &sipIsErr ) );
91+
if ( sipIsErr != 0 )
92+
{
93+
sipReleaseType( provider, sipType_QgsDataProvider, state0 );
94+
provider = nullptr;
95+
}
96+
}
97+
}
98+
SIP_UNBLOCK_THREADS
99+
return provider;
100+
} );
101+
102+
Py_END_ALLOW_THREADS
103+
104+
% End
105+
#endif
65106

66107
/**
67108
* This returns the unique key associated with the provider

src/core/qgsproviderregistry.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,27 @@ void QgsProviderRegistry::registerGuis( QWidget *parent )
525525
}
526526
}
527527

528+
bool QgsProviderRegistry::registerProvider( QgsProviderMetadata *providerMetadata )
529+
{
530+
if ( providerMetadata )
531+
{
532+
if ( mProviders.find( providerMetadata->key() ) == mProviders.end() )
533+
{
534+
mProviders[ providerMetadata->key() ] = providerMetadata;
535+
return true;
536+
}
537+
else
538+
{
539+
QgsDebugMsgLevel( QStringLiteral( "Cannot register provider metadata: a provider with the same key (%1) was already registered!" ).arg( providerMetadata->key() ), 2 );
540+
}
541+
}
542+
else
543+
{
544+
QgsDebugMsgLevel( QStringLiteral( "Trying to register a null metadata provider!" ), 2 );
545+
}
546+
return false;
547+
}
548+
528549
QString QgsProviderRegistry::fileVectorFilters() const
529550
{
530551
return mVectorFileFilters;

src/core/qgsproviderregistry.h

+8
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,14 @@ class CORE_EXPORT QgsProviderRegistry
179179

180180
void registerGuis( QWidget *widget );
181181

182+
/**
183+
* \brief register a new vector data provider from its \a providerMetadata
184+
* \return true on success, false if a provider with the same key was already registered
185+
* \note ownership of the QgsProviderMetadata instance is transferred to the registry
186+
* \since QGIS 3.2
187+
*/
188+
bool registerProvider( QgsProviderMetadata *providerMetadata SIP_TRANSFER );
189+
182190
/**
183191
* Open the given vector data source
184192
*

src/core/qgsvectordataprovider.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,12 @@ QVariant QgsVectorDataProvider::maximumValue( int index ) const
408408

409409
QStringList QgsVectorDataProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
410410
{
411+
QStringList results;
412+
413+
// Safety belt
414+
if ( index < 0 || index >= fields().count() )
415+
return results;
416+
411417
QgsFeature f;
412418
QgsAttributeList keys;
413419
keys.append( index );
@@ -420,7 +426,6 @@ QStringList QgsVectorDataProvider::uniqueStringsMatching( int index, const QStri
420426
QgsFeatureIterator fi = getFeatures( request );
421427

422428
QSet<QString> set;
423-
QStringList results;
424429

425430
while ( fi.nextFeature( f ) )
426431
{

tests/src/python/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ ENDIF (WITH_SERVER)
1111
ADD_PYTHON_TEST(PyCoreAdittions test_core_additions.py)
1212
ADD_PYTHON_TEST(PyQgsActionManager test_qgsactionmanager.py)
1313
ADD_PYTHON_TEST(PyQgsAFSProvider test_provider_afs.py)
14+
ADD_PYTHON_TEST(PyQgsPythonProvider test_provider_python.py)
1415
ADD_PYTHON_TEST(PyQgsAggregateCalculator test_qgsaggregatecalculator.py)
1516
ADD_PYTHON_TEST(PyQgsAnnotation test_qgsannotation.py)
1617
ADD_PYTHON_TEST(PyQgsApplication test_qgsapplication.py)

0 commit comments

Comments
 (0)