Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[processing] Add util to convert QVariant value to Python literal
  • Loading branch information
nyalldawson committed Feb 1, 2019
1 parent ffa49df commit 37774f9
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 0 deletions.
11 changes: 11 additions & 0 deletions python/core/auto_generated/processing/qgsprocessingutils.sip.in
Expand Up @@ -131,11 +131,22 @@ This function creates a new object and the caller takes responsibility for delet
%Docstring
Normalizes a layer ``source`` string for safe comparison across different
operating system environments.
%End

static QString variantToPythonLiteral( const QVariant &value );
%Docstring
Converts a variant to a Python literal.

.. seealso:: :py:func:`stringToPythonLiteral`

.. versionadded:: 3.6
%End

static QString stringToPythonLiteral( const QString &string );
%Docstring
Converts a string to a Python string literal. E.g. by replacing ' with \'.

.. seealso:: :py:func:`variantToPythonLiteral`
%End


Expand Down
79 changes: 79 additions & 0 deletions src/core/processing/qgsprocessingutils.cpp
Expand Up @@ -31,6 +31,7 @@
#include "qgsvectorlayer.h"
#include "qgsproviderregistry.h"
#include "qgsmeshlayer.h"
#include "qgsreferencedgeometry.h"

QList<QgsRasterLayer *> QgsProcessingUtils::compatibleRasterLayers( QgsProject *project, bool sort )
{
Expand Down Expand Up @@ -389,6 +390,84 @@ QString QgsProcessingUtils::normalizeLayerSource( const QString &source )
return normalized.trimmed();
}

QString QgsProcessingUtils::variantToPythonLiteral( const QVariant &value )
{
if ( !value.isValid() )
return QStringLiteral( "None" );

if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
else if ( value.canConvert<QgsCoordinateReferenceSystem>() )
{
if ( !value.value< QgsCoordinateReferenceSystem >().isValid() )
return QStringLiteral( "QgsCoordinateReferenceSystem()" );
else
return QStringLiteral( "QgsCoordinateReferenceSystem('%1')" ).arg( value.value< QgsCoordinateReferenceSystem >().authid() );
}
else if ( value.canConvert< QgsRectangle >() )
{
QgsRectangle r = value.value<QgsRectangle>();
return QStringLiteral( "'%1, %3, %2, %4'" ).arg( qgsDoubleToString( r.xMinimum() ),
qgsDoubleToString( r.yMinimum() ),
qgsDoubleToString( r.xMaximum() ),
qgsDoubleToString( r.yMaximum() ) );
}
else if ( value.canConvert< QgsReferencedRectangle >() )
{
QgsReferencedRectangle r = value.value<QgsReferencedRectangle>();
return QStringLiteral( "'%1, %3, %2, %4 [%5]'" ).arg( qgsDoubleToString( r.xMinimum() ),
qgsDoubleToString( r.yMinimum() ),
qgsDoubleToString( r.xMaximum() ),
qgsDoubleToString( r.yMaximum() ), r.crs().authid() );
}
else if ( value.canConvert< QgsPointXY >() )
{
QgsPointXY r = value.value<QgsPointXY>();
return QStringLiteral( "'%1,%2'" ).arg( qgsDoubleToString( r.x() ),
qgsDoubleToString( r.y() ) );
}
else if ( value.canConvert< QgsReferencedPointXY >() )
{
QgsReferencedPointXY r = value.value<QgsReferencedPointXY>();
return QStringLiteral( "'%1,%2 [%3]'" ).arg( qgsDoubleToString( r.x() ),
qgsDoubleToString( r.y() ),
r.crs().authid() );
}

switch ( value.type() )
{
case QVariant::Bool:
return value.toBool() ? QStringLiteral( "True" ) : QStringLiteral( "False" );

case QVariant::Double:
return QString::number( value.toDouble() );

case QVariant::Int:
case QVariant::UInt:
return QString::number( value.toInt() );

case QVariant::LongLong:
case QVariant::ULongLong:
return QString::number( value.toLongLong() );

case QVariant::List:
{
QStringList parts;
const QVariantList vl = value.toList();
for ( const QVariant &v : vl )
{
parts << variantToPythonLiteral( v );
}
return parts.join( ',' ).prepend( '[' ).append( ']' );
}

default:
break;
}

return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
}

QString QgsProcessingUtils::stringToPythonLiteral( const QString &string )
{
QString s = string;
Expand Down
10 changes: 10 additions & 0 deletions src/core/processing/qgsprocessingutils.h
Expand Up @@ -149,8 +149,18 @@ class CORE_EXPORT QgsProcessingUtils
*/
static QString normalizeLayerSource( const QString &source );

/**
* Converts a variant to a Python literal.
*
* \see stringToPythonLiteral()
* \since QGSIS 3.6
*/
static QString variantToPythonLiteral( const QVariant &value );

/**
* Converts a string to a Python string literal. E.g. by replacing ' with \'.
*
* \see variantToPythonLiteral()
*/
static QString stringToPythonLiteral( const QString &string );

Expand Down
24 changes: 24 additions & 0 deletions tests/src/analysis/testqgsprocessing.cpp
Expand Up @@ -576,6 +576,7 @@ class TestQgsProcessing: public QObject
void combineFields();
void fieldNamesToIndices();
void indicesToFields();
void variantToPythonLiteral();
void stringToPythonLiteral();
void defaultExtensionsForProvider();
void supportedExtensions();
Expand Down Expand Up @@ -7506,6 +7507,29 @@ void TestQgsProcessing::indicesToFields()
QCOMPARE( fields3, QgsFields() );
}

void TestQgsProcessing::variantToPythonLiteral()
{
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QVariant() ), QStringLiteral( "None" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QVariant::fromValue( QgsProperty::fromExpression( QStringLiteral( "1+2" ) ) ) ), QStringLiteral( "QgsProperty.fromExpression('1+2')" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QVariant::fromValue( QgsCoordinateReferenceSystem() ) ), QStringLiteral( "QgsCoordinateReferenceSystem()" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QVariant::fromValue( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3111" ) ) ) ), QStringLiteral( "QgsCoordinateReferenceSystem('EPSG:3111')" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QVariant::fromValue( QgsRectangle( 1, 2, 3, 4 ) ) ), QStringLiteral( "'1, 3, 2, 4'" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QVariant::fromValue( QgsReferencedRectangle( QgsRectangle( 1, 2, 3, 4 ), QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:28356" ) ) ) ) ), QStringLiteral( "'1, 3, 2, 4 [EPSG:28356]'" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QVariant::fromValue( QgsPointXY( 1, 2 ) ) ), QStringLiteral( "'1,2'" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QVariant::fromValue( QgsReferencedPointXY( QgsPointXY( 1, 2 ), QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:28356" ) ) ) ) ), QStringLiteral( "'1,2 [EPSG:28356]'" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( true ), QStringLiteral( "True" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( false ), QStringLiteral( "False" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( 5 ), QStringLiteral( "5" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( 5.5 ), QStringLiteral( "5.5" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( 5LL ), QStringLiteral( "5" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QVariantList() << true << QVariant() << QStringLiteral( "a" ) ), QStringLiteral( "[True,None,'a']" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QStringLiteral( "a" ) ), QStringLiteral( "'a'" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QString() ), QStringLiteral( "''" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QStringLiteral( "a 'string'" ) ), QStringLiteral( "'a \\'string\\''" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QStringLiteral( "a \"string\"" ) ), QStringLiteral( "'a \\\"string\\\"'" ) );
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QStringLiteral( "a \n str\tin\\g" ) ), QStringLiteral( "'a \\n str\\tin\\\\g'" ) );
}

void TestQgsProcessing::stringToPythonLiteral()
{
QCOMPARE( QgsProcessingUtils::stringToPythonLiteral( QStringLiteral( "a" ) ), QStringLiteral( "'a'" ) );
Expand Down

0 comments on commit 37774f9

Please sign in to comment.