Add Parameters to a Processing Algorithm
The parameters are the algorithm's interface. Get them right and the framework builds a dialog, validates the input, populates the field picker from the chosen layer, exposes everything to batch mode and the modeller, and hands your code clean typed values. Get them wrong and users type layer names into text boxes.
This recipe belongs to Processing Provider Plugins. It covers the parameter types you will actually use, defaults and optional inputs, parameters that depend on each other, and the correct way to read each kind inside processAlgorithm().
Prerequisites
- QGIS 3.34 LTR (bundled Python 3.12) or newer.
- An algorithm class — see Write a Custom Processing Algorithm in PyQGIS.
- A provider to register it with, from Register a Processing Provider in a Plugin.
Declare the parameters
from qgis.core import (QgsProcessingAlgorithm, QgsProcessing,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterField,
QgsProcessingParameterNumber,
QgsProcessingParameterEnum,
QgsProcessingParameterBoolean,
QgsProcessingParameterFeatureSink)
INPUT = "INPUT"
GROUP_FIELD = "GROUP_FIELD"
MIN_AREA = "MIN_AREA"
UNITS = "UNITS"
KEEP_EMPTY = "KEEP_EMPTY"
OUTPUT = "OUTPUT"
class SummariseParcelsAlgorithm(QgsProcessingAlgorithm):
def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(
INPUT, self.tr("Parcel layer"),
[QgsProcessing.TypeVectorPolygon]))
self.addParameter(QgsProcessingParameterField(
GROUP_FIELD, self.tr("Group by field"),
parentLayerParameterName=INPUT,
type=QgsProcessingParameterField.Any))
self.addParameter(QgsProcessingParameterNumber(
MIN_AREA, self.tr("Minimum area"),
type=QgsProcessingParameterNumber.Double,
defaultValue=0.0, minValue=0.0))
self.addParameter(QgsProcessingParameterEnum(
UNITS, self.tr("Report units"),
options=[self.tr("square metres"), self.tr("hectares")],
defaultValue=1))
self.addParameter(QgsProcessingParameterBoolean(
KEEP_EMPTY, self.tr("Keep groups with no parcels"),
defaultValue=False))
self.addParameter(QgsProcessingParameterFeatureSink(
OUTPUT, self.tr("Summary")))
Breakdown: Constants for the parameter names keep the definition and the reads in sync — a typo in a string literal produces None at run time rather than an error at load time. QgsProcessingParameterFeatureSource restricted to polygons means the picker only offers polygon layers, which removes a whole class of user mistake; it also accepts a selection-only checkbox and a file path, all for free. The field parameter's parentLayerParameterName is what makes its dropdown populate from whichever layer the user picked, and it is the difference between a field picker and a text box. The enum stores an index, not the label, which is the most common misreading of the parameters dictionary.
Read them correctly
Each parameter type has its own accessor, and using the wrong one is the usual source of a TypeError deep in an algorithm.
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, INPUT, context)
field = self.parameterAsString(parameters, GROUP_FIELD, context)
minimum = self.parameterAsDouble(parameters, MIN_AREA, context)
units_index = self.parameterAsEnum(parameters, UNITS, context)
keep_empty = self.parameterAsBool(parameters, KEEP_EMPTY, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, INPUT))
divisor = 10000.0 if units_index == 1 else 1.0
...
Breakdown: parameterAsSource() returns a QgsProcessingFeatureSource, which honours the user's "selected features only" choice automatically — this is why algorithms should take a source rather than a layer. The enum accessor returns the index into the options list you declared, so map it to meaning explicitly rather than comparing against a translated string, which would break in any other language. parameterAsDouble and parameterAsBool handle the conversion from whatever the caller passed, including the strings that arrive from the command line. Checking the source for None and raising with invalidSourceError() gives the framework's standard, translated message instead of an AttributeError three lines later.
Optional parameters and advanced sections
Not every input belongs on the front of the dialog.
overlay = QgsProcessingParameterFeatureSource(
"OVERLAY", self.tr("Clip to boundary"),
[QgsProcessing.TypeVectorPolygon], optional=True)
overlay.setFlags(overlay.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(overlay)
tolerance = QgsProcessingParameterNumber(
"TOLERANCE", self.tr("Snapping tolerance"),
type=QgsProcessingParameterNumber.Double, defaultValue=0.01)
tolerance.setFlags(tolerance.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(tolerance)
Breakdown: optional=True lets the user leave it blank, and your code must then handle None — which is exactly the point, because an optional clip layer is a genuinely different code path. FlagAdvanced moves the parameter into the collapsible Advanced section, which is where anything with a good default belongs; a dialog with four visible fields and six advanced ones is far more approachable than one with ten. Both flags are combined with the existing flags rather than replacing them, using the bitwise or — assigning the flag directly clears everything else, including the hidden and expression flags.
Validate before the work starts
Parameters that are individually valid can be jointly wrong — a field that is not numeric, a distance in the wrong units for the layer's CRS, two layers in incompatible projections.
def checkParameterValues(self, parameters, context):
source = self.parameterAsSource(parameters, INPUT, context)
field = self.parameterAsString(parameters, GROUP_FIELD, context)
if source is not None and field:
index = source.fields().lookupField(field)
if index >= 0 and not source.fields().at(index).isNumeric():
if self.parameterAsEnum(parameters, UNITS, context) == 1:
return False, self.tr("Hectare output needs a numeric field")
return super().checkParameterValues(parameters, context)
Breakdown: checkParameterValues() runs before the algorithm starts and returns a tuple of validity and message; the framework shows the message in the dialog and refuses to run. Doing this here rather than raising inside processAlgorithm() matters in batch mode, where a hundred rows should be validated before any of them execute rather than failing on row sixty. Always delegate to super() at the end so the framework's own checks — mandatory parameters, writable outputs — still apply.
Outputs are parameters too
The sink declared alongside the inputs above is what gives the user an output chooser, and reading it inside processAlgorithm() is slightly unusual because it returns two values.
# inside processAlgorithm
sink, dest_id = self.parameterAsSink(
parameters, OUTPUT, context, fields, QgsWkbTypes.NoGeometry, source.sourceCrs())
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, OUTPUT))
return {OUTPUT: dest_id}
Breakdown: A sink parameter gives the user the full output chooser — a file, a GeoPackage layer, a PostGIS table, a temporary layer — without your code caring which. parameterAsSink() returns two values, the sink to write to and the destination id to return, and returning the id is what lets the framework add the result to the map, chain it into a model, or report its path. Declaring NoGeometry here produces an attribute-only table, which is exactly right for a summary and a common thing to get wrong by copying a geometry-carrying example.
QGIS version compatibility
| QGIS version | Python | Notes |
|---|---|---|
| 3.22 LTR | 3.9 | All parameter types shown, plus flags and checkParameterValues. |
| 3.28 LTR | 3.9 | Identical. |
| 3.34 LTR | 3.12 | Baseline for this page. |
| 3.40 / 3.44 | 3.12 | Adds further parameter types (point cloud layers, area and volume numbers); existing ones unchanged. |
Parameter names are part of your public interface: models and scripts reference them. Renaming one breaks every saved model that uses the algorithm, so choose plain uppercase names early and keep them.
Troubleshooting
- The field dropdown is empty.
parentLayerParameterNameis missing or names a parameter that does not exist. parameterAsEnum()returns 0 for everything. You are comparing against labels; it returns the index intooptions.- An optional parameter crashes the algorithm. It is
Nonewhen blank. Handle that branch explicitly. - The advanced section is empty and everything is visible. The flag was assigned rather than combined with the existing flags.
- Batch mode fails on every row. Validation is inside
processAlgorithm()instead ofcheckParameterValues(). - The output never appears on the map.
processAlgorithm()did not return the destination id in its dictionary.
Conclusion
Declare parameters with the specific type that matches the input — feature source, field with a parent layer, number with limits, enum with options — give everything a sensible default, and push anything with a good default into the advanced section. Read each with its matching accessor, remembering that enums give indices and sinks give two values, and validate combinations in checkParameterValues() so batch runs fail before they start rather than halfway through.
Frequently Asked Questions
Should I take a layer or a feature source? A source. It honours the "selected features only" option and accepts a file path as well as a loaded layer, so the algorithm works in more contexts for no extra code.
How do I let the user enter an expression?
Use QgsProcessingParameterExpression with a parent layer, which gives the expression builder with the right fields — see Evaluate a QGIS Expression in PyQGIS.
Can a parameter depend on another parameter's value?
Field, expression and band parameters can name a parent layer. Beyond that, validate the combination in checkParameterValues(); the dialog cannot rebuild itself dynamically.
What is the difference between a sink and a file output? A sink writes features and can target any provider; a file destination parameter is just a path, for algorithms writing something that is not a layer, such as a report.
How do defaults appear in batch mode? Each row starts from the declared defaults, so good defaults save the most typing exactly where there is the most of it.
Can I give a parameter its own help text?
Yes — setHelp() on the definition adds a tooltip, and shortHelpString() on the algorithm can describe each parameter in the panel beside the dialog. Both are worth filling in for anything whose units or expectations are not obvious from the label alone.
Do parameter labels need translating?
Yes — wrap them in self.tr(). They are the algorithm's entire visible interface, as covered in Translate a QGIS Plugin with Qt Linguist.