Skip to content

Commit

Permalink
Merge pull request #7012 from elpaso/python-provider
Browse files Browse the repository at this point in the history
Python provider QEP 122
  • Loading branch information
elpaso committed Jun 5, 2018
2 parents b2fce73 + 73cfe04 commit e3f02ea
Show file tree
Hide file tree
Showing 12 changed files with 981 additions and 13 deletions.
8 changes: 6 additions & 2 deletions python/core/auto_generated/qgsfeatureiterator.sip.in
Expand Up @@ -223,11 +223,15 @@ Wrapper for iterator of features from vector data provider or vector layer

QgsFeatureIterator();
%Docstring
construct invalid iterator
Construct invalid iterator
%End
QgsFeatureIterator( QgsAbstractFeatureIterator *iter /Transfer/ );
%Docstring
Construct a valid iterator
%End
QgsFeatureIterator( const QgsFeatureIterator &fi );
%Docstring
copy constructor copies the iterator, increases ref.count
Copy constructor copies the iterator, increases ref.count
%End
~QgsFeatureIterator();

Expand Down
45 changes: 45 additions & 0 deletions python/core/auto_generated/qgsprovidermetadata.sip.in
Expand Up @@ -36,6 +36,51 @@ library object.

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

QgsProviderMetadata( const QString &key, const QString &description, SIP_PYCALLABLE / AllowNone / );
%Docstring
Metadata for provider with direct provider creation function pointer, where
no library is involved.

.. versionadded:: 3.0
%End
%MethodCode

// Make sure the callable doesn't get garbage collected, this is needed because refcount for a2 is 0
// and the creation function pointer is passed to the metadata and it needs to be kept in memory.
Py_INCREF( a2 );

Py_BEGIN_ALLOW_THREADS

sipCpp = new QgsProviderMetadata( *a0, *a1, [a2]( const QString &dataSource, const QgsDataProvider::ProviderOptions &providerOptions ) -> QgsDataProvider*
{
QgsDataProvider *provider;
provider = nullptr;
PyObject *sipResObj;
SIP_BLOCK_THREADS

sipResObj = sipCallMethod( nullptr, a2, "DD", new QString( dataSource ), sipType_QString, nullptr, new QgsDataProvider::ProviderOptions( providerOptions ), sipType_QgsDataProvider_ProviderOptions, NULL );

if ( sipResObj )
{
if ( sipCanConvertToType( sipResObj, sipType_QgsDataProvider, SIP_NOT_NONE ) )
{
int state0;
int sipIsErr = 0;
provider = reinterpret_cast<QgsDataProvider *>( sipConvertToType( sipResObj, sipType_QgsDataProvider, nullptr, SIP_NOT_NONE, &state0, &sipIsErr ) );
if ( sipIsErr != 0 )
{
sipReleaseType( provider, sipType_QgsDataProvider, state0 );
provider = nullptr;
}
}
}
SIP_UNBLOCK_THREADS
return provider;
} );

Py_END_ALLOW_THREADS

%End

QString key() const;
%Docstring
Expand Down
13 changes: 13 additions & 0 deletions python/core/auto_generated/qgsproviderregistry.sip.in
Expand Up @@ -180,6 +180,19 @@ Returns a string containing the available protocol drivers

void registerGuis( QWidget *widget );

bool registerProvider( QgsProviderMetadata *providerMetadata /Transfer/ );
%Docstring
register a new vector data provider from its ``providerMetadata``

:return: true on success, false if a provider with the same key was already registered

.. note::

ownership of the QgsProviderMetadata instance is transferred to the registry

.. versionadded:: 3.2
%End



private:
Expand Down
12 changes: 5 additions & 7 deletions src/core/qgsfeatureiterator.h
Expand Up @@ -286,15 +286,13 @@ class CORE_EXPORT QgsFeatureIterator
% End
#endif

//! construct invalid iterator
//! Construct invalid iterator
QgsFeatureIterator() = default;
#ifndef SIP_RUN
//! construct a valid iterator
QgsFeatureIterator( QgsAbstractFeatureIterator *iter );
#endif
//! copy constructor copies the iterator, increases ref.count
//! Construct a valid iterator
QgsFeatureIterator( QgsAbstractFeatureIterator *iter SIP_TRANSFER );
//! Copy constructor copies the iterator, increases ref.count
QgsFeatureIterator( const QgsFeatureIterator &fi );
//! destructor deletes the iterator if it has no more references
//! Destructor deletes the iterator if it has no more references
~QgsFeatureIterator();

QgsFeatureIterator &operator=( const QgsFeatureIterator &other );
Expand Down
2 changes: 1 addition & 1 deletion src/core/qgsmaplayer.cpp
Expand Up @@ -912,7 +912,7 @@ QString QgsMapLayer::loadNamedProperty( const QString &uri, QgsMapLayer::Propert
QFile myFile( uri );
if ( myFile.open( QFile::ReadOnly ) )
{
QgsDebugMsg( QString( "file found %1" ).arg( uri ) );
QgsDebugMsgLevel( QString( "file found %1" ).arg( uri ), 2 );
// read file
resultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
if ( !resultFlag )
Expand Down
45 changes: 43 additions & 2 deletions src/core/qgsprovidermetadata.h
Expand Up @@ -58,10 +58,51 @@ class CORE_EXPORT QgsProviderMetadata
/**
* Metadata for provider with direct provider creation function pointer, where
* no library is involved.
* \note not available in Python bindings
* \since QGIS 3.0
*/
SIP_SKIP QgsProviderMetadata( const QString &key, const QString &description, const QgsProviderMetadata::CreateDataProviderFunction &createFunc );
#ifndef SIP_RUN
QgsProviderMetadata( const QString &key, const QString &description, const QgsProviderMetadata::CreateDataProviderFunction &createFunc );
#else
QgsProviderMetadata( const QString &key, const QString &description, SIP_PYCALLABLE / AllowNone / );
% MethodCode

// Make sure the callable doesn't get garbage collected, this is needed because refcount for a2 is 0
// and the creation function pointer is passed to the metadata and it needs to be kept in memory.
Py_INCREF( a2 );

Py_BEGIN_ALLOW_THREADS

sipCpp = new QgsProviderMetadata( *a0, *a1, [a2]( const QString &dataSource, const QgsDataProvider::ProviderOptions &providerOptions ) -> QgsDataProvider*
{
QgsDataProvider *provider;
provider = nullptr;
PyObject *sipResObj;
SIP_BLOCK_THREADS

sipResObj = sipCallMethod( nullptr, a2, "DD", new QString( dataSource ), sipType_QString, nullptr, new QgsDataProvider::ProviderOptions( providerOptions ), sipType_QgsDataProvider_ProviderOptions, NULL );

if ( sipResObj )
{
if ( sipCanConvertToType( sipResObj, sipType_QgsDataProvider, SIP_NOT_NONE ) )
{
int state0;
int sipIsErr = 0;
provider = reinterpret_cast<QgsDataProvider *>( sipConvertToType( sipResObj, sipType_QgsDataProvider, nullptr, SIP_NOT_NONE, &state0, &sipIsErr ) );
if ( sipIsErr != 0 )
{
sipReleaseType( provider, sipType_QgsDataProvider, state0 );
provider = nullptr;
}
}
}
SIP_UNBLOCK_THREADS
return provider;
} );

Py_END_ALLOW_THREADS

% End
#endif

/**
* This returns the unique key associated with the provider
Expand Down
21 changes: 21 additions & 0 deletions src/core/qgsproviderregistry.cpp
Expand Up @@ -525,6 +525,27 @@ void QgsProviderRegistry::registerGuis( QWidget *parent )
}
}

bool QgsProviderRegistry::registerProvider( QgsProviderMetadata *providerMetadata )
{
if ( providerMetadata )
{
if ( mProviders.find( providerMetadata->key() ) == mProviders.end() )
{
mProviders[ providerMetadata->key() ] = providerMetadata;
return true;
}
else
{
QgsDebugMsgLevel( QStringLiteral( "Cannot register provider metadata: a provider with the same key (%1) was already registered!" ).arg( providerMetadata->key() ), 2 );
}
}
else
{
QgsDebugMsgLevel( QStringLiteral( "Trying to register a null metadata provider!" ), 2 );
}
return false;
}

QString QgsProviderRegistry::fileVectorFilters() const
{
return mVectorFileFilters;
Expand Down
8 changes: 8 additions & 0 deletions src/core/qgsproviderregistry.h
Expand Up @@ -179,6 +179,14 @@ class CORE_EXPORT QgsProviderRegistry

void registerGuis( QWidget *widget );

/**
* \brief register a new vector data provider from its \a providerMetadata
* \return true on success, false if a provider with the same key was already registered
* \note ownership of the QgsProviderMetadata instance is transferred to the registry
* \since QGIS 3.2
*/
bool registerProvider( QgsProviderMetadata *providerMetadata SIP_TRANSFER );

/**
* Open the given vector data source
*
Expand Down
7 changes: 6 additions & 1 deletion src/core/qgsvectordataprovider.cpp
Expand Up @@ -408,6 +408,12 @@ QVariant QgsVectorDataProvider::maximumValue( int index ) const

QStringList QgsVectorDataProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
{
QStringList results;

// Safety belt
if ( index < 0 || index >= fields().count() )
return results;

QgsFeature f;
QgsAttributeList keys;
keys.append( index );
Expand All @@ -420,7 +426,6 @@ QStringList QgsVectorDataProvider::uniqueStringsMatching( int index, const QStri
QgsFeatureIterator fi = getFeatures( request );

QSet<QString> set;
QStringList results;

while ( fi.nextFeature( f ) )
{
Expand Down
1 change: 1 addition & 0 deletions tests/src/python/CMakeLists.txt
Expand Up @@ -11,6 +11,7 @@ ENDIF (WITH_SERVER)
ADD_PYTHON_TEST(PyCoreAdittions test_core_additions.py)
ADD_PYTHON_TEST(PyQgsActionManager test_qgsactionmanager.py)
ADD_PYTHON_TEST(PyQgsAFSProvider test_provider_afs.py)
ADD_PYTHON_TEST(PyQgsPythonProvider test_provider_python.py)
ADD_PYTHON_TEST(PyQgsAggregateCalculator test_qgsaggregatecalculator.py)
ADD_PYTHON_TEST(PyQgsAnnotation test_qgsannotation.py)
ADD_PYTHON_TEST(PyQgsApplication test_qgsapplication.py)
Expand Down

0 comments on commit e3f02ea

Please sign in to comment.