diff --git a/src/process/qgsprocess.cpp b/src/process/qgsprocess.cpp index 4293d20af211..ae3d3af51991 100644 --- a/src/process/qgsprocess.cpp +++ b/src/process/qgsprocess.cpp @@ -287,9 +287,18 @@ int QgsProcessingExec::run( const QStringList &constArgs ) QgsUnitTypes::AreaUnit areaUnit = QgsUnitTypes::AreaUnknownUnit; QString projectPath; QVariantMap params; - for ( int i = 3; i < args.count(); i++ ) + bool paramsEnded = false; + int i = 3; + for ( ; i < args.count(); i++ ) { QString arg = args.at( i ); + + if ( arg == QLatin1String( "--" ) ) + { + paramsEnded = true; + break; + } + if ( arg.startsWith( QLatin1String( "--" ) ) ) arg = arg.mid( 2 ); @@ -322,11 +331,24 @@ int QgsProcessingExec::run( const QStringList &constArgs ) } else { - std::cerr << QStringLiteral( "Invalid parameter value %1. Parameter values must be of the form \"--NAME=VALUE\"\n" ).arg( arg ).toLocal8Bit().constData(); + std::cerr << QStringLiteral( "Invalid parameter value %1. Parameter values must be entered after \"--\" e.g.\n Example:\n qgis_process run algorithm_name -- PARAM1=VALUE PARAM2=42\"\n" ).arg( arg ).toLocal8Bit().constData(); return 1; } } + // After '--' we only have params + for ( ; i < args.count(); i++ ) + { + const QString arg = args.at( i ); + const QStringList parts = arg.split( '=' ); + if ( parts.count() >= 2 ) + { + const QString name = parts.first(); + const QString value = parts.mid( 1 ).join( '=' ); + params.insert( name, value ); + } + } + return execute( algId, params, ellipsoid, distanceUnit, areaUnit, useJson, projectPath ); } else @@ -349,7 +371,7 @@ void QgsProcessingExec::showUsage( const QString &appName ) << "\tplugins\tlist available and active plugins\n" << "\tlist\tlist all available processing algorithms\n" << "\thelp\tshow help for an algorithm. The algorithm id or a path to a model file must be specified.\n" - << "\trun\truns an algorithm. The algorithm id or a path to a model file and parameter values must be specified. Parameter values are specified via the --PARAMETER=VALUE syntax.\n" + << "\trun\truns an algorithm. The algorithm id or a path to a model file and parameter values must be specified. Parameter values are specified after -- with PARAMETER=VALUE syntax.\n" << "\t\tIf required, the ellipsoid to use for distance and area calculations can be specified via the \"--ELLIPSOID=name\" argument.\n" << "\t\tIf required, an existing QGIS project to use during the algorithm execution can be specified via the \"--PROJECT_PATH=path\" argument.\n"; diff --git a/tests/src/python/test_qgsprocessexecutable.py b/tests/src/python/test_qgsprocessexecutable.py index 9c4b8830a293..994f3c457651 100644 --- a/tests/src/python/test_qgsprocessexecutable.py +++ b/tests/src/python/test_qgsprocessexecutable.py @@ -160,7 +160,7 @@ def testAlgorithmRunNoArgs(self): self.assertIn('inputs', output.lower()) self.assertEqual(rc, 1) - def testAlgorithmRun(self): + def testAlgorithmRunLegacy(self): output_file = self.TMP_DIR + '/polygon_centroid.shp' rc, output, err = self.run_process(['run', 'native:centroids', '--INPUT={}'.format(TEST_DATA_DIR + '/polys.shp'), '--OUTPUT={}'.format(output_file)]) if os.environ.get('TRAVIS', '') != 'true': @@ -172,9 +172,21 @@ def testAlgorithmRun(self): self.assertTrue(os.path.exists(output_file)) self.assertEqual(rc, 0) + def testAlgorithmRun(self): + output_file = self.TMP_DIR + '/polygon_centroid.shp' + rc, output, err = self.run_process(['run', 'native:centroids', '--', 'INPUT={}'.format(TEST_DATA_DIR + '/polys.shp'), 'OUTPUT={}'.format(output_file)]) + if os.environ.get('TRAVIS', '') != 'true': + # Travis DOES have errors, due to QStandardPaths: XDG_RUNTIME_DIR not set warnings raised by Qt + self.assertFalse(err) + self.assertIn('0...10...20...30...40...50...60...70...80...90', output.lower()) + self.assertIn('results', output.lower()) + self.assertIn('OUTPUT:\t' + output_file, output) + self.assertTrue(os.path.exists(output_file)) + self.assertEqual(rc, 0) + def testAlgorithmRunJson(self): output_file = self.TMP_DIR + '/polygon_centroid2.shp' - rc, output, err = self.run_process(['run', '--json', 'native:centroids', '--INPUT={}'.format(TEST_DATA_DIR + '/polys.shp'), '--OUTPUT={}'.format(output_file)]) + rc, output, err = self.run_process(['run', '--json', 'native:centroids', '--', 'INPUT={}'.format(TEST_DATA_DIR + '/polys.shp'), 'OUTPUT={}'.format(output_file)]) res = json.loads(output) self.assertIn('gdal_version', res) @@ -201,7 +213,7 @@ def testModelHelp(self): def testModelRun(self): output_file = self.TMP_DIR + '/model_output.shp' - rc, output, err = self.run_process(['run', TEST_DATA_DIR + '/test_model.model3', '--FEATS={}'.format(TEST_DATA_DIR + '/polys.shp'), '--native:centroids_1:CENTROIDS={}'.format(output_file)]) + rc, output, err = self.run_process(['run', TEST_DATA_DIR + '/test_model.model3', '--', 'FEATS={}'.format(TEST_DATA_DIR + '/polys.shp'), 'native:centroids_1:CENTROIDS={}'.format(output_file)]) if os.environ.get('TRAVIS', '') != 'true': # Travis DOES have errors, due to QStandardPaths: XDG_RUNTIME_DIR not set warnings raised by Qt self.assertFalse(err)