@@ -353,50 +353,132 @@ void QgsProcessingModelAlgorithm::setSourceFilePath( const QString &sourceFile )
353
353
mSourceFile = sourceFile;
354
354
}
355
355
356
- QString QgsProcessingModelAlgorithm::asPythonCode () const
356
+ QStringList QgsProcessingModelAlgorithm::asPythonCode ( const QgsProcessing::PythonOutputType outputType, const int indentSize ) const
357
357
{
358
358
QStringList lines;
359
- lines << QStringLiteral ( " ##%1=name" ).arg ( name () );
360
-
361
- QMap< QString, QgsProcessingModelParameter >::const_iterator paramIt = mParameterComponents .constBegin ();
362
- for ( ; paramIt != mParameterComponents .constEnd (); ++paramIt )
359
+ QString indent = QString ( ' ' ).repeated ( indentSize );
360
+ QString currentIndent;
361
+ switch ( outputType )
363
362
{
364
- QString name = paramIt.value ().parameterName ();
365
- if ( parameterDefinition ( name ) )
363
+ case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
366
364
{
367
- lines << parameterDefinition ( name )->asScriptCode ();
368
- }
369
- }
365
+ lines << QStringLiteral ( " from qgis.core import QgsProcessing" );
366
+ lines << QStringLiteral ( " from qgis.core import QgsProcessingAlgorithm" );
367
+ // add specific parameter type imports
368
+ const auto params = parameterDefinitions ();
369
+ QStringList importLines; // not a set - we need regular ordering
370
+ for ( const QgsProcessingParameterDefinition *def : params )
371
+ {
372
+ const QString importString = QgsApplication::processingRegistry ()->parameterType ( def->type () )->pythonImportString ();
373
+ if ( !importString.isEmpty () && !importLines.contains ( importString ) )
374
+ importLines << importString;
375
+ }
376
+ lines << importLines;
377
+ lines << QStringLiteral ( " import processing" );
378
+ lines << QString () << QString ();
370
379
371
- auto safeName = []( const QString & name )->QString
372
- {
373
- QString n = name.toLower ().trimmed ();
374
- QRegularExpression rx ( QStringLiteral ( " [^a-z_]" ) );
375
- n.replace ( rx, QString () );
376
- return n;
377
- };
380
+ auto safeName = []( const QString & name )->QString
381
+ {
382
+ QString n = name.toLower ().trimmed ();
383
+ QRegularExpression rx ( QStringLiteral ( " [^a-z_A-Z0-9]" ) );
384
+ n.replace ( rx, QString () );
385
+ return n;
386
+ };
387
+
388
+ const QString algorithmClassName = safeName ( name () );
389
+ lines << QStringLiteral ( " class %1(QgsProcessingAlgorithm):" ).arg ( algorithmClassName );
390
+
391
+ // createInstance
392
+ lines << indent + QStringLiteral ( " def createInstance(self):" );
393
+ lines << indent + indent + QStringLiteral ( " return %1()" ).arg ( algorithmClassName );
394
+ lines << QString ();
395
+
396
+ // name, displayName
397
+ lines << indent + QStringLiteral ( " def name(self):" );
398
+ lines << indent + indent + QStringLiteral ( " return '%1'" ).arg ( mModelName );
399
+ lines << QString ();
400
+ lines << indent + QStringLiteral ( " def displayName(self):" );
401
+ lines << indent + indent + QStringLiteral ( " return '%1'" ).arg ( mModelName );
402
+ lines << QString ();
403
+
404
+ // group, groupId
405
+ lines << indent + QStringLiteral ( " def group(self):" );
406
+ lines << indent + indent + QStringLiteral ( " return '%1'" ).arg ( mModelGroup );
407
+ lines << QString ();
408
+ lines << indent + QStringLiteral ( " def groupId(self):" );
409
+ lines << indent + indent + QStringLiteral ( " return '%1'" ).arg ( mModelGroupId );
410
+ lines << QString ();
411
+
412
+ // help
413
+ if ( !shortHelpString ().isEmpty () )
414
+ {
415
+ lines << indent + QStringLiteral ( " def shortHelpString(self):" );
416
+ lines << indent + indent + QStringLiteral ( " return '%1'" ).arg ( shortHelpString () );
417
+ lines << QString ();
418
+ }
419
+ if ( !helpUrl ().isEmpty () )
420
+ {
421
+ lines << indent + QStringLiteral ( " def helpUrl(self):" );
422
+ lines << indent + indent + QStringLiteral ( " return '%1'" ).arg ( helpUrl () );
423
+ lines << QString ();
424
+ }
378
425
379
- QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms .constBegin ();
380
- for ( ; childIt != mChildAlgorithms .constEnd (); ++childIt )
381
- {
382
- if ( !childIt->isActive () || !childIt->algorithm () )
383
- continue ;
426
+ // initAlgorithm, parameter definitions
427
+ lines << indent + QStringLiteral ( " def initAlgorithm(self, config=None):" );
428
+ lines.reserve ( lines.size () + params.size () );
429
+ for ( const QgsProcessingParameterDefinition *def : params )
430
+ {
431
+ lines << indent + indent + QStringLiteral ( " self.addParameter(%1)" ).arg ( def->asPythonString () );
432
+ }
384
433
385
- // look through all outputs for child
386
- QMap<QString, QgsProcessingModelOutput> outputs = childIt->modelOutputs ();
387
- QMap<QString, QgsProcessingModelOutput>::const_iterator outputIt = outputs.constBegin ();
388
- for ( ; outputIt != outputs.constEnd (); ++outputIt )
434
+ lines << QString ();
435
+ lines << indent + QStringLiteral ( " def processAlgorithm(self, parameters, context, feedback):" );
436
+ currentIndent = indent + indent;
437
+ break ;
438
+ }
439
+ #if 0
440
+ case Script:
389
441
{
390
- const QgsProcessingOutputDefinition *output = childIt->algorithm ()->outputDefinition ( outputIt->childOutputName () );
391
- lines << QStringLiteral ( " ##%1=output %2" ).arg ( safeName ( outputIt->name () ), output->type () );
442
+ QgsStringMap params;
443
+ QgsProcessingContext context;
444
+ QMap< QString, QgsProcessingModelParameter >::const_iterator paramIt = mParameterComponents.constBegin();
445
+ for ( ; paramIt != mParameterComponents.constEnd(); ++paramIt )
446
+ {
447
+ QString name = paramIt.value().parameterName();
448
+ if ( parameterDefinition( name ) )
449
+ {
450
+ // TODO - generic value to string method
451
+ params.insert( name, parameterDefinition( name )->valueAsPythonString( parameterDefinition( name )->defaultValue(), context ) );
452
+ }
453
+ }
454
+
455
+ if ( !params.isEmpty() )
456
+ {
457
+ lines << QStringLiteral( "parameters = {" );
458
+ for ( auto it = params.constBegin(); it != params.constEnd(); ++it )
459
+ {
460
+ lines << QStringLiteral( " '%1':%2," ).arg( it.key(), it.value() );
461
+ }
462
+ lines << QStringLiteral( "}" )
463
+ << QString();
464
+ }
465
+
466
+ lines << QStringLiteral( "context = QgsProcessingContext()" )
467
+ << QStringLiteral( "context.setProject(QgsProject.instance())" )
468
+ << QStringLiteral( "feedback = QgsProcessingFeedback()" )
469
+ << QString();
470
+
471
+ break;
392
472
}
473
+ #endif
474
+
393
475
}
394
476
395
- lines << QStringLiteral ( " results={}" );
477
+ lines << currentIndent + QStringLiteral ( " results={}" );
478
+ lines << currentIndent + QStringLiteral ( " outputs={}" );
396
479
397
480
QSet< QString > toExecute;
398
- childIt = mChildAlgorithms .constBegin ();
399
- for ( ; childIt != mChildAlgorithms .constEnd (); ++childIt )
481
+ for ( auto childIt = mChildAlgorithms .constBegin (); childIt != mChildAlgorithms .constEnd (); ++childIt )
400
482
{
401
483
if ( childIt->isActive () && childIt->algorithm () )
402
484
toExecute.insert ( childIt->childId () );
@@ -428,15 +510,66 @@ QString QgsProcessingModelAlgorithm::asPythonCode() const
428
510
executedAlg = true ;
429
511
430
512
const QgsProcessingModelChildAlgorithm &child = mChildAlgorithms [ childId ];
431
- lines << child.asPythonCode ();
513
+
514
+ // fill in temporary outputs
515
+ const QgsProcessingParameterDefinitions childDefs = child.algorithm ()->parameterDefinitions ();
516
+ QgsStringMap childParams;
517
+ for ( const QgsProcessingParameterDefinition *def : childDefs )
518
+ {
519
+ if ( def->isDestination () )
520
+ {
521
+ const QgsProcessingDestinationParameter *destParam = static_cast < const QgsProcessingDestinationParameter * >( def );
522
+
523
+ // is destination linked to one of the final outputs from this model?
524
+ bool isFinalOutput = false ;
525
+ QMap<QString, QgsProcessingModelOutput> outputs = child.modelOutputs ();
526
+ QMap<QString, QgsProcessingModelOutput>::const_iterator outputIt = outputs.constBegin ();
527
+ for ( ; outputIt != outputs.constEnd (); ++outputIt )
528
+ {
529
+ if ( outputIt->childOutputName () == destParam->name () )
530
+ {
531
+ QString paramName = child.childId () + ' :' + outputIt.key ();
532
+ childParams.insert ( destParam->name (), QStringLiteral ( " parameters['%1']" ).arg ( paramName ) );
533
+ isFinalOutput = true ;
534
+ break ;
535
+ }
536
+ }
537
+
538
+ if ( !isFinalOutput )
539
+ {
540
+ // output is temporary
541
+
542
+ // check whether it's optional, and if so - is it required?
543
+ bool required = true ;
544
+ if ( destParam->flags () & QgsProcessingParameterDefinition::FlagOptional )
545
+ {
546
+ required = childOutputIsRequired ( child.childId (), destParam->name () );
547
+ }
548
+
549
+ // not optional, or required elsewhere in model
550
+ if ( required )
551
+ {
552
+
553
+ childParams.insert ( destParam->name (), QStringLiteral ( " QgsProcessing.TEMPORARY_OUTPUT" ) );
554
+ }
555
+ }
556
+ }
557
+ }
558
+
559
+ lines << child.asPythonCode ( outputType, childParams, currentIndent.size (), indentSize );
432
560
433
561
executed.insert ( childId );
434
562
}
435
563
}
436
564
437
- lines << QStringLiteral ( " return results" );
565
+ switch ( outputType )
566
+ {
567
+ case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
568
+ lines << currentIndent + QStringLiteral ( " return results" );
569
+ break ;
570
+ }
438
571
439
- return lines. join ( ' \n ' ) ;
572
+ return lines;
440
573
}
441
574
442
575
QMap<QString, QgsProcessingModelAlgorithm::VariableDefinition> QgsProcessingModelAlgorithm::variablesForChildAlgorithm ( const QString &childId, QgsProcessingContext &context, const QVariantMap &modelParameters, const QVariantMap &results ) const
0 commit comments