Navigation Menu

Skip to content

Commit

Permalink
CSVT support Z and parse real variants
Browse files Browse the repository at this point in the history
  • Loading branch information
elpaso authored and nyalldawson committed Nov 30, 2021
1 parent 792ec70 commit e69ca95
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 4 deletions.
6 changes: 3 additions & 3 deletions src/providers/delimitedtext/qgsdelimitedtextprovider.cpp
Expand Up @@ -247,7 +247,7 @@ QStringList QgsDelimitedTextProvider::readCsvtFieldTypes( const QString &filenam

strTypeList = strTypeList.toLower();
// https://regex101.com/r/BcVPcF/1
const QRegularExpression reTypeList( QRegularExpression::anchoredPattern( QStringLiteral( R"re(^(?:\s*("?)(?:coordx|coordy|point\(x\)|point\(y\)|wkt|integer64|integer|integer\(boolean\)|real|double|longlong|long|int8|string|date|datetime|time)(?:\(\d+(?:\.\d+)?\))?\1\s*(?:,|$))+)re" ) ) );
const QRegularExpression reTypeList( QRegularExpression::anchoredPattern( QStringLiteral( R"re(^(?:\s*("?)(?:coord[xyz]|point\([xyz]\)|wkt|integer64|integer|integer\((?:boolean|int16)\)|real(?:\(float32\))?|double|longlong|long|int8|string|date|datetime|time)(?:\(\d+(?:\.\d+)?\))?\1\s*(?:,|$))+)re" ) ) );
const QRegularExpressionMatch match = reTypeList.match( strTypeList );
if ( !match.hasMatch() )
{
Expand All @@ -262,7 +262,7 @@ QStringList QgsDelimitedTextProvider::readCsvtFieldTypes( const QString &filenam

int pos = 0;
// https://regex101.com/r/QwxaSe/1/
const QRegularExpression reType( QStringLiteral( R"re((coordx|coordy|point\(x\)|point\(y\)|wkt|int8|\binteger\b(?=[^\(])|(?<=integer\()bool(?=ean)|integer64|\binteger\b(?=\(\d+\))|integer64|longlong|\blong\b|real|double|string|\bdate\b|datetime|\btime\b))re" ) );
const QRegularExpression reType( QStringLiteral( R"re((coord[xyz]|point\([xyz]\)|wkt|int8|\binteger\b(?=[^\(])|(?<=integer\()bool(?=ean)|integer64|\binteger\b(?=\((?:\d+|int16)\))|integer64|longlong|\blong\b|real|double|string|\bdate\b|datetime|\btime\b))re" ) );
QRegularExpressionMatch typeMatch = reType.match( strTypeList, pos );
while ( typeMatch.hasMatch() )
{
Expand Down Expand Up @@ -809,7 +809,7 @@ void QgsDelimitedTextProvider::scanFile( bool buildIndexes, bool forceFullScan,
{
typeName = csvtTypes[fieldIdx];
// Map CSVT types to provider types
if ( typeName == QStringLiteral( "coordx" ) || typeName == QStringLiteral( "coordy" ) || typeName == QStringLiteral( "point(x)" ) || typeName == QStringLiteral( "point(y)" ) )
if ( typeName.startsWith( QStringLiteral( "coord" ) ) || typeName.startsWith( QStringLiteral( "point(" ) ) )
{
typeName = QStringLiteral( "double" );
}
Expand Down
26 changes: 25 additions & 1 deletion tests/src/python/test_qgsdelimitedtextprovider.py
Expand Up @@ -37,6 +37,7 @@
from qgis.PyQt.QtCore import QCoreApplication, QVariant, QUrl, QObject, QTemporaryDir, QDate

from qgis.core import (
QgsGeometry,
QgsProviderRegistry,
QgsVectorLayer,
QgsFeatureRequest,
Expand Down Expand Up @@ -1040,7 +1041,6 @@ def _make_test_file(self, csv_content, csvt_content='', uri_options=''):
TestQgsDelimitedTextProviderOther._text_index += 1

basename = 'test_type_detection_{}'.format(self._text_index)
print('Testfile: ' + basename)

csv_file = os.path.join(self.tmp_path, basename + '.csv')
with open(csv_file, 'w+') as f:
Expand Down Expand Up @@ -1239,6 +1239,30 @@ def test_type_detection_csvt(self):
)), "CoordX,CoordY,Integer64(20),Real,String,Integer(10),Integer64(20),Date,Integer(Boolean)", uri_options='xField=X&yField=Y')
self.assertTrue(vl.isSpatial())

# Test Z
vl = self._make_test_file('\n'.join((
"X,Y,Z,fid,freal,ftext,fint,flong,fdate,fbool",
'-106.13127068692,36.0554327720544,1,"1",1.234567,a text,"2000000000","4000000000",2021/11/12,true',
'-105.781333374658,35.7216962612865,123,"2",3.4567889,another text,"2147483646","4000000000",2021/11/12,false',
'-106.108589564828,35.407400712311,"456","3",6.789,text,"2000000000","4000000000",2021/11/13,false',
)), "Point(x),CoordY,Point(z),Integer64(20),Real(float32),String,Integer(10),Integer64(20),Date,Integer(Boolean)", uri_options='xField=X&yField=Y&zField=Z')

fields = {f.name(): (f.type(), f.typeName()) for f in vl.fields()}
self.assertEqual(fields, {
'X': (6, 'double'),
'Y': (6, 'double'),
'Z': (6, 'double'),
'fid': (4, 'longlong'),
'freal': (6, 'double'),
'ftext': (10, 'text'),
'fint': (2, 'integer'),
'flong': (4, 'longlong'),
'fdate': (14, 'date'),
'fbool': (1, 'bool')})

geometries = [f.geometry() for f in vl.getFeatures()]
self.assertGeometriesEqual(geometries[-1], QgsGeometry.fromWkt('PointZ (-106.10858956482799442 35.40740071231100217 456)'))

def test_booleans(self):
"""Test bool detection with user defined literals"""

Expand Down

0 comments on commit e69ca95

Please sign in to comment.