Skip to content

Commit 859b39a

Browse files
committed
Fixes #20053 decimal separator in csv files
Actually it had nothing to do with CSV being the source, but it was the json exporter passing the values through all field formatters except for the fallback. This resulted in all fields using a 'Range' formatter (which is the default for all numeric types) passing through the formatter and being returned as strings in the json. Worse, if the locale was not a "dot" locale and decimal separator was on, the resulting string could not be easily converted into its original numeric type. Now, instead of checking for the fallback formatter only, there is a white list of formatters that can be applied when we want a json. This is a temporary solution because the "right" way to do it would be either a flag in the formatter to tell if it can be applied when converting to json and/or other "data" formats (csv etc.) or a different new method similar to representValue.
1 parent 1a5a23d commit 859b39a

File tree

2 files changed

+59
-2
lines changed

2 files changed

+59
-2
lines changed

src/core/qgsjsonutils.cpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ QgsCoordinateReferenceSystem QgsJsonExporter::sourceCrs() const
7070
QString QgsJsonExporter::exportFeature( const QgsFeature &feature, const QVariantMap &extraProperties,
7171
const QVariant &id ) const
7272
{
73+
7374
QString s = QStringLiteral( "{\n \"type\":\"Feature\",\n" );
7475

7576
// ID
@@ -119,6 +120,12 @@ QString QgsJsonExporter::exportFeature( const QgsFeature &feature, const QVarian
119120
if ( mIncludeAttributes )
120121
{
121122
QgsFields fields = mLayer ? mLayer->fields() : feature.fields();
123+
// List of formatters through we want to pass the values
124+
QStringList formattersWhiteList;
125+
formattersWhiteList << QStringLiteral( "KeyValue" )
126+
<< QStringLiteral( "List" )
127+
<< QStringLiteral( "ValueRelation" )
128+
<< QStringLiteral( "ValueMap" );
122129

123130
for ( int i = 0; i < fields.count(); ++i )
124131
{
@@ -133,7 +140,7 @@ QString QgsJsonExporter::exportFeature( const QgsFeature &feature, const QVarian
133140
{
134141
QgsEditorWidgetSetup setup = fields.at( i ).editorWidgetSetup();
135142
QgsFieldFormatter *fieldFormatter = QgsApplication::fieldFormatterRegistry()->fieldFormatter( setup.type() );
136-
if ( fieldFormatter != QgsApplication::fieldFormatterRegistry()->fallbackFieldFormatter() )
143+
if ( formattersWhiteList.contains( fieldFormatter->id() ) )
137144
val = fieldFormatter->representValue( mLayer.data(), i, setup.config(), QVariant(), val );
138145
}
139146

tests/src/python/test_qgsjsonutils.py

+51-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
QgsRelation,
3232
QgsEditorWidgetSetup
3333
)
34-
from qgis.PyQt.QtCore import QVariant, QTextCodec
34+
from qgis.PyQt.QtCore import QVariant, QTextCodec, QLocale
3535

3636
start_app()
3737
codec = QTextCodec.codecForName("System")
@@ -676,6 +676,56 @@ def testExportFeatures(self):
676676
]}"""
677677
self.assertEqual(exporter.exportFeatures([feature, feature2]), expected)
678678

679+
def testExportFeaturesWithLocale_regression20053(self):
680+
""" Test exporting feature export with range widgets and locale different than C
681+
Regression: https://issues.qgis.org/issues/20053 - decimal separator in csv files
682+
"""
683+
684+
source = QgsVectorLayer("Point?field=name:string&field=cost:double&field=population:int&field=date:date",
685+
"parent", "memory")
686+
self.assertTrue(source.isValid())
687+
fields = source.fields()
688+
689+
feature = QgsFeature(fields, 5)
690+
feature.setGeometry(QgsGeometry(QgsPoint(5, 6)))
691+
feature.setAttributes(['Valsier Peninsula', 6.8, 198000, '2018-09-10'])
692+
693+
exporter = QgsJsonExporter()
694+
695+
# single feature
696+
expected = """{ "type": "FeatureCollection",
697+
"features":[
698+
{
699+
"type":"Feature",
700+
"id":5,
701+
"geometry":
702+
{"type": "Point", "coordinates": [5, 6]},
703+
"properties":{
704+
"name":"Valsier Peninsula",
705+
"cost":6.8,
706+
"population":198000,
707+
"date":"2018-09-10"
708+
}
709+
}
710+
]}"""
711+
self.assertEqual(exporter.exportFeatures([feature]), expected)
712+
713+
setup = QgsEditorWidgetSetup('Range', {
714+
'AllowNull': True,
715+
'Max': 2147483647,
716+
'Min': -2147483648,
717+
'Precision': 4,
718+
'Step': 1,
719+
'Style': 'SpinBox'
720+
}
721+
)
722+
source.setEditorWidgetSetup(1, setup)
723+
source.setEditorWidgetSetup(2, setup)
724+
725+
QLocale.setDefault(QLocale('it'))
726+
exporter.setVectorLayer(source)
727+
self.assertEqual(exporter.exportFeatures([feature]), expected)
728+
679729

680730
if __name__ == "__main__":
681731
unittest.main()

0 commit comments

Comments
 (0)