[{"data":1,"prerenderedAt":1712},["ShallowReactive",2],{"doc:\u002Fqgis-plugin-development\u002Fprocessing-provider-plugins":3},{"id":4,"title":5,"body":6,"description":1705,"extension":1706,"meta":1707,"navigation":376,"path":1708,"seo":1709,"stem":1710,"__hash__":1711},"docs\u002Fqgis-plugin-development\u002Fprocessing-provider-plugins\u002Findex.md","Processing Provider Plugins for QGIS",{"type":7,"value":8,"toc":1691},"minimark",[9,14,23,50,55,97,101,104,290,300,304,323,603,630,634,647,851,888,892,906,960,973,977,986,1124,1151,1155,1178,1294,1301,1305,1313,1417,1448,1452,1458,1514,1524,1528,1584,1588,1600,1611,1627,1636,1654,1658,1687],[10,11,13],"h1",{"id":12},"processing-provider-plugins","Processing Provider Plugins",[15,16,17,18,22],"p",{},"A Processing provider is the cleanest way to ship reusable geoprocessing tools inside a QGIS plugin. Instead of bolting a dialog onto a toolbar button, you register your algorithms with the Processing framework, where they appear in the Toolbox alongside native GDAL, GRASS, and QGIS algorithms. From there they gain features for free: a generated parameter dialog, batch execution, history logging, the graphical Model Designer, and the ability to be called from ",[19,20,21],"code",{},"processing.run()"," in any other script. This page explains how to build that provider as part of a plugin, how the provider lifecycle fits the plugin lifecycle, and how this approach differs from dropping a standalone script into your processing scripts folder.",[15,24,25,26,31,32,36,37,40,41,44,45,49],{},"This guide builds on the ",[27,28,30],"a",{"href":29},"\u002Fqgis-plugin-development\u002F","QGIS Plugin Development Guide",". If you have not yet assembled a working plugin skeleton, start with ",[27,33,35],{"href":34},"\u002Fqgis-plugin-development\u002Fplugin-boilerplate-structure\u002F","QGIS Plugin Boilerplate & Structure",", because a provider needs the same ",[19,38,39],{},"__init__.py",", ",[19,42,43],{},"metadata.txt",", and lifecycle hooks. The provider replaces or supplements the UI-focused work covered in ",[27,46,48],{"href":47},"\u002Fqgis-plugin-development\u002Fqt-designer-for-gis-interfaces\u002F","Qt Designer for GIS Interfaces",": Processing generates the dialog for you, so you write parameters instead of widgets.",[51,52,54],"h2",{"id":53},"prerequisites","Prerequisites",[56,57,58,66,73,87,94],"ul",{},[59,60,61,65],"li",{},[62,63,64],"strong",{},"QGIS 3.34 LTR"," or later, with the Processing plugin enabled (it ships and activates by default).",[59,67,68,69,72],{},"A working plugin package that loads cleanly, as described in ",[27,70,71],{"href":34},"Plugin Boilerplate & Structure",".",[59,74,75,76,40,79,82,83,86],{},"Familiarity with the ",[19,77,78],{},"classFactory",[19,80,81],{},"initGui",", and ",[19,84,85],{},"unload"," lifecycle methods.",[59,88,89,90,72],{},"Comfort writing at least one algorithm class — see the child task ",[27,91,93],{"href":92},"\u002Fqgis-plugin-development\u002Fprocessing-provider-plugins\u002Fwrite-custom-processing-algorithm-pyqgis\u002F","Write a Custom Processing Algorithm in PyQGIS",[59,95,96],{},"An SVG or PNG icon for the provider (optional but recommended for Toolbox visibility).",[51,98,100],{"id":99},"provider-algorithms-and-the-toolbox","Provider, Algorithms, and the Toolbox",[15,102,103],{},"A provider is a container. It holds one or more algorithm classes and exposes identity metadata — a machine-readable id, a human-readable name, and an icon. When QGIS starts the Processing registry, it asks every registered provider to load its algorithms, then groups them under the provider's name in the Toolbox tree. The diagram below shows the relationship.",[105,106,111,112,111,116,111,120,111,127,111,136,111,144,111,150,111,154,111,158,111,164,111,170,111,175,111,181,111,187,111,195,111,200,111,203,111,207,111,210,111,214,111,218,111,220,111,222,111,229,111,235,111,241,111,246,111,251,111,255,111,259,111,263,111,267,111,270,111,273],"svg",{"viewBox":107,"role":108,"ariaLabel":109,"xmlns":110},"0 0 760 360","img","Diagram showing a QGIS plugin registering one Processing provider that contains several algorithms, which surface in the Processing Toolbox","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","\n  ",[113,114,115],"title",{},"Provider, algorithms, and Toolbox relationship",[117,118,119],"desc",{},"A plugin's initProcessing method registers a single provider with the processing registry. The provider groups multiple algorithm classes, and each becomes an entry in the Processing Toolbox.",[121,122],"rect",{"x":123,"y":123,"width":124,"height":125,"fill":126},"0","760","360","#f6f3ea",[121,128],{"x":129,"y":129,"width":130,"height":131,"rx":132,"fill":133,"stroke":134,"style":135},"24","200","120","8","#fffdf7","#0f766e","stroke-width:2.5",[137,138,143],"text",{"x":139,"y":140,"fill":141,"style":142},"124","58","#17211d","text-anchor:middle;font-family:sans-serif;font-size:16px;font-weight:bold","Plugin",[137,145,149],{"x":139,"y":146,"fill":147,"style":148},"86","#2f3b35","text-anchor:middle;font-family:monospace;font-size:12px","classFactory()",[137,151,153],{"x":139,"y":152,"fill":147,"style":148},"106","initProcessing()",[137,155,157],{"x":139,"y":156,"fill":147,"style":148},"126","unload()",[121,159],{"x":160,"y":161,"width":130,"height":162,"rx":132,"fill":133,"stroke":163,"style":135},"280","40","88","#b45309",[137,165,169],{"x":166,"y":167,"fill":141,"style":168},"380","74","text-anchor:middle;font-family:sans-serif;font-size:15px;font-weight:bold","Provider",[137,171,174],{"x":166,"y":172,"fill":147,"style":173},"98","text-anchor:middle;font-family:monospace;font-size:11px","QgsProcessingProvider",[176,177],"line",{"x1":178,"y1":179,"x2":160,"y2":179,"stroke":147,"style":180},"224","84","stroke-width:2.5;marker-end:url(#ar)",[137,182,186],{"x":183,"y":184,"fill":147,"style":185},"252","76","text-anchor:middle;font-family:sans-serif;font-size:10px","register",[121,188],{"x":160,"y":189,"width":190,"height":191,"rx":192,"fill":133,"stroke":193,"style":194},"170","150","44","6","#2563eb","stroke-width:2",[137,196,199],{"x":197,"y":198,"fill":147,"style":173},"355","197","Algorithm A",[121,201],{"x":160,"y":202,"width":190,"height":191,"rx":192,"fill":133,"stroke":193,"style":194},"226",[137,204,206],{"x":197,"y":205,"fill":147,"style":173},"253","Algorithm B",[121,208],{"x":160,"y":209,"width":190,"height":191,"rx":192,"fill":133,"stroke":193,"style":194},"282",[137,211,213],{"x":197,"y":212,"fill":147,"style":173},"309","Algorithm C",[176,215],{"x1":166,"y1":216,"x2":197,"y2":189,"stroke":147,"style":217},"128","stroke-width:2;marker-end:url(#ar)",[176,219],{"x1":166,"y1":216,"x2":197,"y2":202,"stroke":147,"style":217},[176,221],{"x1":166,"y1":216,"x2":197,"y2":209,"stroke":147,"style":217},[121,223],{"x":224,"y":161,"width":225,"height":226,"rx":132,"fill":227,"stroke":228,"style":135},"520","216","286","#26322d","#15803d",[137,230,234],{"x":231,"y":232,"fill":233,"style":168},"628","70","#d9f99d","Processing Toolbox",[137,236,240],{"x":237,"y":238,"fill":233,"style":239},"540","110","font-family:monospace;font-size:12px","▾ My Tools",[137,242,245],{"x":243,"y":190,"fill":233,"style":244},"556","font-family:monospace;font-size:11px","▾ Vector",[137,247,250],{"x":248,"y":249,"fill":233,"style":244},"572","180","• Algorithm A",[137,252,254],{"x":248,"y":253,"fill":233,"style":244},"206","• Algorithm B",[137,256,258],{"x":243,"y":257,"fill":233,"style":244},"244","▾ Raster",[137,260,262],{"x":248,"y":261,"fill":233,"style":244},"274","• Algorithm C",[176,264],{"x1":265,"y1":266,"x2":224,"y2":249,"stroke":147,"style":180},"430","192",[176,268],{"x1":265,"y1":269,"x2":224,"y2":253,"stroke":147,"style":180},"248",[176,271],{"x1":265,"y1":272,"x2":224,"y2":261,"stroke":147,"style":180},"304",[274,275,276,277,111],"defs",{},"\n    ",[278,279,285,286,276],"marker",{"id":280,"markerWidth":281,"markerHeight":281,"refX":282,"refY":283,"orient":284},"ar","9","7","4.5","auto","\n      ",[287,288],"path",{"d":289,"fill":147},"M0,0 L9,4.5 L0,9 z",[15,291,292,293,296,297,72],{},"The key insight is that the provider does not run anything itself. It is a registry entry that advertises algorithms. All real work happens inside the algorithm classes, each of which subclasses ",[19,294,295],{},"QgsProcessingAlgorithm"," and implements ",[19,298,299],{},"processAlgorithm()",[51,301,303],{"id":302},"subclassing-qgsprocessingprovider","Subclassing QgsProcessingProvider",[15,305,306,307,40,310,82,313,316,317,319,320,72],{},"The provider class overrides a handful of methods. Three are mandatory in practice: ",[19,308,309],{},"id()",[19,311,312],{},"name()",[19,314,315],{},"loadAlgorithms()",". The rest customize presentation. The ",[19,318,315],{}," method is where you instantiate every algorithm and call ",[19,321,322],{},"addAlgorithm()",[324,325,330],"pre",{"className":326,"code":327,"language":328,"meta":329,"style":329},"language-python shiki shiki-themes github-dark","import os\nfrom qgis.PyQt.QtGui import QIcon\nfrom qgis.core import QgsProcessingProvider\n\nfrom .area_classifier_algorithm import AreaClassifierAlgorithm\nfrom .point_density_algorithm import PointDensityAlgorithm\n\n\nclass MyToolsProvider(QgsProcessingProvider):\n\n    def loadAlgorithms(self):\n        self.addAlgorithm(AreaClassifierAlgorithm())\n        self.addAlgorithm(PointDensityAlgorithm())\n\n    def id(self):\n        # Stable, lowercase, no spaces. Forms part of every algorithm id.\n        return \"mytools\"\n\n    def name(self):\n        # Human-readable label shown as the Toolbox group header.\n        return \"My Tools\"\n\n    def longName(self):\n        return \"My Tools — vector and raster utilities\"\n\n    def icon(self):\n        path = os.path.join(os.path.dirname(__file__), \"icons\", \"provider.svg\")\n        return QIcon(path)\n","python","",[19,331,332,344,358,371,378,391,404,409,414,432,437,449,459,467,472,482,489,499,504,514,520,528,533,543,551,556,566,595],{"__ignoreMap":329},[333,334,336,340],"span",{"class":176,"line":335},1,[333,337,339],{"class":338},"snl16","import",[333,341,343],{"class":342},"s95oV"," os\n",[333,345,347,350,353,355],{"class":176,"line":346},2,[333,348,349],{"class":338},"from",[333,351,352],{"class":342}," qgis.PyQt.QtGui ",[333,354,339],{"class":338},[333,356,357],{"class":342}," QIcon\n",[333,359,361,363,366,368],{"class":176,"line":360},3,[333,362,349],{"class":338},[333,364,365],{"class":342}," qgis.core ",[333,367,339],{"class":338},[333,369,370],{"class":342}," QgsProcessingProvider\n",[333,372,374],{"class":176,"line":373},4,[333,375,377],{"emptyLinePlaceholder":376},true,"\n",[333,379,381,383,386,388],{"class":176,"line":380},5,[333,382,349],{"class":338},[333,384,385],{"class":342}," .area_classifier_algorithm ",[333,387,339],{"class":338},[333,389,390],{"class":342}," AreaClassifierAlgorithm\n",[333,392,394,396,399,401],{"class":176,"line":393},6,[333,395,349],{"class":338},[333,397,398],{"class":342}," .point_density_algorithm ",[333,400,339],{"class":338},[333,402,403],{"class":342}," PointDensityAlgorithm\n",[333,405,407],{"class":176,"line":406},7,[333,408,377],{"emptyLinePlaceholder":376},[333,410,412],{"class":176,"line":411},8,[333,413,377],{"emptyLinePlaceholder":376},[333,415,417,420,424,427,429],{"class":176,"line":416},9,[333,418,419],{"class":338},"class",[333,421,423],{"class":422},"svObZ"," MyToolsProvider",[333,425,426],{"class":342},"(",[333,428,174],{"class":422},[333,430,431],{"class":342},"):\n",[333,433,435],{"class":176,"line":434},10,[333,436,377],{"emptyLinePlaceholder":376},[333,438,440,443,446],{"class":176,"line":439},11,[333,441,442],{"class":338},"    def",[333,444,445],{"class":422}," loadAlgorithms",[333,447,448],{"class":342},"(self):\n",[333,450,452,456],{"class":176,"line":451},12,[333,453,455],{"class":454},"sDLfK","        self",[333,457,458],{"class":342},".addAlgorithm(AreaClassifierAlgorithm())\n",[333,460,462,464],{"class":176,"line":461},13,[333,463,455],{"class":454},[333,465,466],{"class":342},".addAlgorithm(PointDensityAlgorithm())\n",[333,468,470],{"class":176,"line":469},14,[333,471,377],{"emptyLinePlaceholder":376},[333,473,475,477,480],{"class":176,"line":474},15,[333,476,442],{"class":338},[333,478,479],{"class":454}," id",[333,481,448],{"class":342},[333,483,485],{"class":176,"line":484},16,[333,486,488],{"class":487},"sAwPA","        # Stable, lowercase, no spaces. Forms part of every algorithm id.\n",[333,490,492,495],{"class":176,"line":491},17,[333,493,494],{"class":338},"        return",[333,496,498],{"class":497},"sU2Wk"," \"mytools\"\n",[333,500,502],{"class":176,"line":501},18,[333,503,377],{"emptyLinePlaceholder":376},[333,505,507,509,512],{"class":176,"line":506},19,[333,508,442],{"class":338},[333,510,511],{"class":422}," name",[333,513,448],{"class":342},[333,515,517],{"class":176,"line":516},20,[333,518,519],{"class":487},"        # Human-readable label shown as the Toolbox group header.\n",[333,521,523,525],{"class":176,"line":522},21,[333,524,494],{"class":338},[333,526,527],{"class":497}," \"My Tools\"\n",[333,529,531],{"class":176,"line":530},22,[333,532,377],{"emptyLinePlaceholder":376},[333,534,536,538,541],{"class":176,"line":535},23,[333,537,442],{"class":338},[333,539,540],{"class":422}," longName",[333,542,448],{"class":342},[333,544,546,548],{"class":176,"line":545},24,[333,547,494],{"class":338},[333,549,550],{"class":497}," \"My Tools — vector and raster utilities\"\n",[333,552,554],{"class":176,"line":553},25,[333,555,377],{"emptyLinePlaceholder":376},[333,557,559,561,564],{"class":176,"line":558},26,[333,560,442],{"class":338},[333,562,563],{"class":422}," icon",[333,565,448],{"class":342},[333,567,569,572,575,578,581,584,587,589,592],{"class":176,"line":568},27,[333,570,571],{"class":342},"        path ",[333,573,574],{"class":338},"=",[333,576,577],{"class":342}," os.path.join(os.path.dirname(",[333,579,580],{"class":454},"__file__",[333,582,583],{"class":342},"), ",[333,585,586],{"class":497},"\"icons\"",[333,588,40],{"class":342},[333,590,591],{"class":497},"\"provider.svg\"",[333,593,594],{"class":342},")\n",[333,596,598,600],{"class":176,"line":597},28,[333,599,494],{"class":338},[333,601,602],{"class":342}," QIcon(path)\n",[15,604,605,608,609,611,612,615,616,618,619,621,622,625,626,629],{},[62,606,607],{},"Breakdown:"," ",[19,610,309],{}," returns a permanent identifier — never change it after release, because saved Processing models and scripts reference algorithms as ",[19,613,614],{},"provider_id:algorithm_id",". ",[19,617,312],{}," is the display label and may change freely. ",[19,620,315],{}," is called by the framework every time algorithms are refreshed, so it must create fresh instances; do not cache them. ",[19,623,624],{},"icon()"," returns a ",[19,627,628],{},"QIcon","; if you omit it, the provider shows a generic gear.",[51,631,633],{"id":632},"registering-the-provider-in-initprocessing","Registering the Provider in initProcessing",[15,635,636,637,639,640,643,644,646],{},"A plugin exposes its provider through a dedicated ",[19,638,153],{}," method that runs alongside the usual GUI setup. Registration uses the global Processing registry, retrieved from ",[19,641,642],{},"QgsApplication.processingRegistry()",". Crucially, you must remove the provider in ",[19,645,157],{}," so disabling or reloading the plugin does not leave a stale entry.",[324,648,650],{"className":326,"code":649,"language":328,"meta":329,"style":329},"from qgis.core import QgsApplication\nfrom .provider import MyToolsProvider\n\n\nclass MyToolsPlugin:\n    def __init__(self, iface):\n        self.iface = iface\n        self.provider = None\n\n    def initProcessing(self):\n        \"\"\"Create and register the provider with the Processing registry.\"\"\"\n        self.provider = MyToolsProvider()\n        QgsApplication.processingRegistry().addProvider(self.provider)\n\n    def initGui(self):\n        # Called by QGIS when the plugin is enabled.\n        self.initProcessing()\n\n    def unload(self):\n        # Symmetrical teardown — required to avoid duplicate providers on reload.\n        if self.provider is not None:\n            QgsApplication.processingRegistry().removeProvider(self.provider)\n            self.provider = None\n",[19,651,652,663,675,679,683,693,703,715,727,731,740,745,756,767,771,780,785,792,796,805,810,831,840],{"__ignoreMap":329},[333,653,654,656,658,660],{"class":176,"line":335},[333,655,349],{"class":338},[333,657,365],{"class":342},[333,659,339],{"class":338},[333,661,662],{"class":342}," QgsApplication\n",[333,664,665,667,670,672],{"class":176,"line":346},[333,666,349],{"class":338},[333,668,669],{"class":342}," .provider ",[333,671,339],{"class":338},[333,673,674],{"class":342}," MyToolsProvider\n",[333,676,677],{"class":176,"line":360},[333,678,377],{"emptyLinePlaceholder":376},[333,680,681],{"class":176,"line":373},[333,682,377],{"emptyLinePlaceholder":376},[333,684,685,687,690],{"class":176,"line":380},[333,686,419],{"class":338},[333,688,689],{"class":422}," MyToolsPlugin",[333,691,692],{"class":342},":\n",[333,694,695,697,700],{"class":176,"line":393},[333,696,442],{"class":338},[333,698,699],{"class":454}," __init__",[333,701,702],{"class":342},"(self, iface):\n",[333,704,705,707,710,712],{"class":176,"line":406},[333,706,455],{"class":454},[333,708,709],{"class":342},".iface ",[333,711,574],{"class":338},[333,713,714],{"class":342}," iface\n",[333,716,717,719,722,724],{"class":176,"line":411},[333,718,455],{"class":454},[333,720,721],{"class":342},".provider ",[333,723,574],{"class":338},[333,725,726],{"class":454}," None\n",[333,728,729],{"class":176,"line":416},[333,730,377],{"emptyLinePlaceholder":376},[333,732,733,735,738],{"class":176,"line":434},[333,734,442],{"class":338},[333,736,737],{"class":422}," initProcessing",[333,739,448],{"class":342},[333,741,742],{"class":176,"line":439},[333,743,744],{"class":497},"        \"\"\"Create and register the provider with the Processing registry.\"\"\"\n",[333,746,747,749,751,753],{"class":176,"line":451},[333,748,455],{"class":454},[333,750,721],{"class":342},[333,752,574],{"class":338},[333,754,755],{"class":342}," MyToolsProvider()\n",[333,757,758,761,764],{"class":176,"line":461},[333,759,760],{"class":342},"        QgsApplication.processingRegistry().addProvider(",[333,762,763],{"class":454},"self",[333,765,766],{"class":342},".provider)\n",[333,768,769],{"class":176,"line":469},[333,770,377],{"emptyLinePlaceholder":376},[333,772,773,775,778],{"class":176,"line":474},[333,774,442],{"class":338},[333,776,777],{"class":422}," initGui",[333,779,448],{"class":342},[333,781,782],{"class":176,"line":484},[333,783,784],{"class":487},"        # Called by QGIS when the plugin is enabled.\n",[333,786,787,789],{"class":176,"line":491},[333,788,455],{"class":454},[333,790,791],{"class":342},".initProcessing()\n",[333,793,794],{"class":176,"line":501},[333,795,377],{"emptyLinePlaceholder":376},[333,797,798,800,803],{"class":176,"line":506},[333,799,442],{"class":338},[333,801,802],{"class":422}," unload",[333,804,448],{"class":342},[333,806,807],{"class":176,"line":516},[333,808,809],{"class":487},"        # Symmetrical teardown — required to avoid duplicate providers on reload.\n",[333,811,812,815,818,820,823,826,829],{"class":176,"line":522},[333,813,814],{"class":338},"        if",[333,816,817],{"class":454}," self",[333,819,721],{"class":342},[333,821,822],{"class":338},"is",[333,824,825],{"class":338}," not",[333,827,828],{"class":454}," None",[333,830,692],{"class":342},[333,832,833,836,838],{"class":176,"line":530},[333,834,835],{"class":342},"            QgsApplication.processingRegistry().removeProvider(",[333,837,763],{"class":454},[333,839,766],{"class":342},[333,841,842,845,847,849],{"class":176,"line":535},[333,843,844],{"class":454},"            self",[333,846,721],{"class":342},[333,848,574],{"class":338},[333,850,726],{"class":454},[15,852,853,855,856,858,859,862,863,866,867,869,870,873,874,876,877,880,881,883,884,887],{},[62,854,607],{}," Keeping ",[19,857,153],{}," separate from ",[19,860,861],{},"initGui()"," mirrors the convention used by the Plugin Builder template and keeps the registration logic discoverable. ",[19,864,865],{},"addProvider()"," triggers ",[19,868,315],{}," immediately. The ",[19,871,872],{},"removeProvider()"," call in ",[19,875,157],{}," is the single most common omission; without it, the ",[27,878,879],{"href":34},"Plugin Reloader"," will stack duplicate \"My Tools\" groups in the Toolbox every time you reload. Storing the provider on ",[19,882,763],{}," and guarding with ",[19,885,886],{},"is not None"," makes teardown idempotent.",[51,889,891],{"id":890},"grouping-algorithms-within-the-provider","Grouping Algorithms Within the Provider",[15,893,894,895,898,899,902,903,905],{},"A provider can hold dozens of algorithms, so grouping keeps the Toolbox navigable. Grouping is controlled per algorithm, not by the provider, through the algorithm's ",[19,896,897],{},"group()"," and ",[19,900,901],{},"groupId()"," methods. Algorithms sharing the same ",[19,904,901],{}," collapse under one sub-node beneath the provider header.",[324,907,909],{"className":326,"code":908,"language":328,"meta":329,"style":329},"# Inside an algorithm class:\ndef group(self):\n    return \"Vector\"        # Display label for the sub-group\n\ndef groupId(self):\n    return \"vector\"        # Stable identifier used for matching\n",[19,910,911,916,926,937,941,950],{"__ignoreMap":329},[333,912,913],{"class":176,"line":335},[333,914,915],{"class":487},"# Inside an algorithm class:\n",[333,917,918,921,924],{"class":176,"line":346},[333,919,920],{"class":338},"def",[333,922,923],{"class":422}," group",[333,925,448],{"class":342},[333,927,928,931,934],{"class":176,"line":360},[333,929,930],{"class":338},"    return",[333,932,933],{"class":497}," \"Vector\"",[333,935,936],{"class":487},"        # Display label for the sub-group\n",[333,938,939],{"class":176,"line":373},[333,940,377],{"emptyLinePlaceholder":376},[333,942,943,945,948],{"class":176,"line":380},[333,944,920],{"class":338},[333,946,947],{"class":422}," groupId",[333,949,448],{"class":342},[333,951,952,954,957],{"class":176,"line":393},[333,953,930],{"class":338},[333,955,956],{"class":497}," \"vector\"",[333,958,959],{"class":487},"        # Stable identifier used for matching\n",[15,961,962,964,965,967,968,970,971,72],{},[62,963,607],{}," Return an empty string from both methods to place an algorithm directly under the provider with no sub-group. As with the provider id, treat ",[19,966,901],{}," as stable and ",[19,969,897],{}," as cosmetic. Choose group names that read well next to native QGIS groups — \"Vector geometry\", \"Raster terrain\", \"Data management\" — so users can guess where your tools live. The full algorithm class that these methods belong to is built step by step in ",[27,972,93],{"href":92},[51,974,976],{"id":975},"provider-icons-and-branding","Provider Icons and Branding",[15,978,979,980,982,983,985],{},"Icons appear in three places: the provider header in the Toolbox, each algorithm entry, and the generated algorithm dialog title bar. The provider's ",[19,981,624],{}," supplies a default that algorithms inherit unless they override their own ",[19,984,624],{},". Prefer SVG so the icon scales across high-DPI displays.",[324,987,989],{"className":326,"code":988,"language":328,"meta":329,"style":329},"import os\nfrom qgis.PyQt.QtGui import QIcon\nfrom qgis.core import QgsProcessingAlgorithm\n\n\nclass AreaClassifierAlgorithm(QgsProcessingAlgorithm):\n\n    def icon(self):\n        path = os.path.join(\n            os.path.dirname(__file__), \"icons\", \"classify.svg\")\n        return QIcon(path)\n\n    def svgIconPath(self):\n        # Used where QGIS needs a path rather than a QIcon object.\n        return os.path.join(\n            os.path.dirname(__file__), \"icons\", \"classify.svg\")\n",[19,990,991,997,1007,1018,1022,1026,1039,1043,1051,1060,1078,1084,1088,1097,1102,1108],{"__ignoreMap":329},[333,992,993,995],{"class":176,"line":335},[333,994,339],{"class":338},[333,996,343],{"class":342},[333,998,999,1001,1003,1005],{"class":176,"line":346},[333,1000,349],{"class":338},[333,1002,352],{"class":342},[333,1004,339],{"class":338},[333,1006,357],{"class":342},[333,1008,1009,1011,1013,1015],{"class":176,"line":360},[333,1010,349],{"class":338},[333,1012,365],{"class":342},[333,1014,339],{"class":338},[333,1016,1017],{"class":342}," QgsProcessingAlgorithm\n",[333,1019,1020],{"class":176,"line":373},[333,1021,377],{"emptyLinePlaceholder":376},[333,1023,1024],{"class":176,"line":380},[333,1025,377],{"emptyLinePlaceholder":376},[333,1027,1028,1030,1033,1035,1037],{"class":176,"line":393},[333,1029,419],{"class":338},[333,1031,1032],{"class":422}," AreaClassifierAlgorithm",[333,1034,426],{"class":342},[333,1036,295],{"class":422},[333,1038,431],{"class":342},[333,1040,1041],{"class":176,"line":406},[333,1042,377],{"emptyLinePlaceholder":376},[333,1044,1045,1047,1049],{"class":176,"line":411},[333,1046,442],{"class":338},[333,1048,563],{"class":422},[333,1050,448],{"class":342},[333,1052,1053,1055,1057],{"class":176,"line":416},[333,1054,571],{"class":342},[333,1056,574],{"class":338},[333,1058,1059],{"class":342}," os.path.join(\n",[333,1061,1062,1065,1067,1069,1071,1073,1076],{"class":176,"line":434},[333,1063,1064],{"class":342},"            os.path.dirname(",[333,1066,580],{"class":454},[333,1068,583],{"class":342},[333,1070,586],{"class":497},[333,1072,40],{"class":342},[333,1074,1075],{"class":497},"\"classify.svg\"",[333,1077,594],{"class":342},[333,1079,1080,1082],{"class":176,"line":439},[333,1081,494],{"class":338},[333,1083,602],{"class":342},[333,1085,1086],{"class":176,"line":451},[333,1087,377],{"emptyLinePlaceholder":376},[333,1089,1090,1092,1095],{"class":176,"line":461},[333,1091,442],{"class":338},[333,1093,1094],{"class":422}," svgIconPath",[333,1096,448],{"class":342},[333,1098,1099],{"class":176,"line":469},[333,1100,1101],{"class":487},"        # Used where QGIS needs a path rather than a QIcon object.\n",[333,1103,1104,1106],{"class":176,"line":474},[333,1105,494],{"class":338},[333,1107,1059],{"class":342},[333,1109,1110,1112,1114,1116,1118,1120,1122],{"class":176,"line":484},[333,1111,1064],{"class":342},[333,1113,580],{"class":454},[333,1115,583],{"class":342},[333,1117,586],{"class":497},[333,1119,40],{"class":342},[333,1121,1075],{"class":497},[333,1123,594],{"class":342},[15,1125,1126,1128,1129,1132,1133,1136,1137,1139,1140,1143,1144,1147,1148,72],{},[62,1127,607],{}," Resolve icon paths with ",[19,1130,1131],{},"os.path.dirname(__file__)"," rather than a relative string, because Processing does not guarantee the working directory. Implement ",[19,1134,1135],{},"svgIconPath()"," in addition to ",[19,1138,624],{}," so help generation and the Model Designer can locate the asset. If you compiled icons into a Qt resource file (",[19,1141,1142],{},"resources_rc.py","), reference them with the ",[19,1145,1146],{},":\u002F"," prefix, for example ",[19,1149,1150],{},"QIcon(\":\u002Fplugins\u002Fmytools\u002Fclassify.svg\")",[51,1152,1154],{"id":1153},"provider-algorithms-vs-script-algorithms","Provider Algorithms vs. Script Algorithms",[15,1156,1157,1158,1160,1161,1165,1166,1169,1170,1173,1174,1177],{},"Both approaches subclass ",[19,1159,295],{},", but they are deployed and discovered differently. A ",[1162,1163,1164],"em",{},"script algorithm"," is a single ",[19,1167,1168],{},".py"," file dropped into the user's ",[19,1171,1172],{},"processing\u002Fscripts\u002F"," folder (or added via the Toolbox script editor). It appears under the built-in \"Scripts\" provider and requires no plugin. A ",[1162,1175,1176],{},"provider algorithm"," ships inside a plugin, is grouped under your own branded provider, and is installable and updatable through the QGIS Plugin Repository.",[1179,1180,1181,1197],"table",{},[1182,1183,1184],"thead",{},[1185,1186,1187,1191,1194],"tr",{},[1188,1189,1190],"th",{},"Aspect",[1188,1192,1193],{},"Script algorithm",[1188,1195,1196],{},"Provider plugin algorithm",[1198,1199,1200,1215,1226,1240,1261,1272,1283],"tbody",{},[1185,1201,1202,1206,1212],{},[1203,1204,1205],"td",{},"Packaging",[1203,1207,1208,1209,1211],{},"Single ",[19,1210,1168],{}," file",[1203,1213,1214],{},"Full plugin package",[1185,1216,1217,1220,1223],{},[1203,1218,1219],{},"Discovery",[1203,1221,1222],{},"Built-in \"Scripts\" provider",[1203,1224,1225],{},"Your named provider",[1185,1227,1228,1231,1234],{},[1203,1229,1230],{},"Distribution",[1203,1232,1233],{},"Manual copy or shared file",[1203,1235,1236],{},[27,1237,1239],{"href":1238},"\u002Fqgis-plugin-development\u002Fpublishing-to-the-qgis-plugin-repository\u002F","QGIS Plugin Repository",[1185,1241,1242,1245,1248],{},[1203,1243,1244],{},"Grouping\u002Fbranding",[1203,1246,1247],{},"Limited",[1203,1249,1250,1251,1254,1255,1254,1258],{},"Full control via ",[19,1252,1253],{},"id","\u002F",[19,1256,1257],{},"name",[19,1259,1260],{},"icon",[1185,1262,1263,1266,1269],{},[1203,1264,1265],{},"Auto-update",[1203,1267,1268],{},"None",[1203,1270,1271],{},"Through plugin manager",[1185,1273,1274,1277,1280],{},[1203,1275,1276],{},"Multiple algorithms",[1203,1278,1279],{},"One file each",[1203,1281,1282],{},"Many in one provider",[1185,1284,1285,1288,1291],{},[1203,1286,1287],{},"Bundled resources",[1203,1289,1290],{},"Awkward",[1203,1292,1293],{},"Natural (icons, data, helpers)",[15,1295,1296,1297,72],{},"For a one-off utility you keep on a single workstation, a script is faster. For anything shared with a team, distributed publicly, or composed of several related tools, a provider plugin is the right unit. The algorithm code itself is nearly identical, which means you can prototype as a script and later move the same class into a provider with minimal changes. To learn how the resulting algorithms are invoked programmatically, see ",[27,1298,1300],{"href":1299},"\u002Fspatial-data-processing-automation\u002Fbatch-processing-with-pyqgis\u002Frun-processing-algorithm-from-script\u002F","Run a Processing Algorithm from a Script",[51,1302,1304],{"id":1303},"calling-your-providers-algorithms","Calling Your Provider's Algorithms",[15,1306,1307,1308,1310,1311,72],{},"Once registered, your algorithms are addressable by their fully qualified id, ",[19,1309,614],{},". This is what makes a provider so much more useful than a button: any script, model, or other plugin can run your tool through ",[19,1312,21],{},[324,1314,1316],{"className":326,"code":1315,"language":328,"meta":329,"style":329},"import processing\n\nresult = processing.run(\"mytools:areaclassifier\", {\n    \"INPUT\": \"\u002Fdata\u002Fparcels.gpkg|layername=parcels\",\n    \"THRESHOLD\": 1000.0,\n    \"OUTPUT\": \"memory:classified\",\n})\nclassified_layer = result[\"OUTPUT\"]\nprint(classified_layer.featureCount(), \"features classified\")\n",[19,1317,1318,1325,1329,1345,1359,1371,1383,1388,1404],{"__ignoreMap":329},[333,1319,1320,1322],{"class":176,"line":335},[333,1321,339],{"class":338},[333,1323,1324],{"class":342}," processing\n",[333,1326,1327],{"class":176,"line":346},[333,1328,377],{"emptyLinePlaceholder":376},[333,1330,1331,1334,1336,1339,1342],{"class":176,"line":360},[333,1332,1333],{"class":342},"result ",[333,1335,574],{"class":338},[333,1337,1338],{"class":342}," processing.run(",[333,1340,1341],{"class":497},"\"mytools:areaclassifier\"",[333,1343,1344],{"class":342},", {\n",[333,1346,1347,1350,1353,1356],{"class":176,"line":373},[333,1348,1349],{"class":497},"    \"INPUT\"",[333,1351,1352],{"class":342},": ",[333,1354,1355],{"class":497},"\"\u002Fdata\u002Fparcels.gpkg|layername=parcels\"",[333,1357,1358],{"class":342},",\n",[333,1360,1361,1364,1366,1369],{"class":176,"line":380},[333,1362,1363],{"class":497},"    \"THRESHOLD\"",[333,1365,1352],{"class":342},[333,1367,1368],{"class":454},"1000.0",[333,1370,1358],{"class":342},[333,1372,1373,1376,1378,1381],{"class":176,"line":393},[333,1374,1375],{"class":497},"    \"OUTPUT\"",[333,1377,1352],{"class":342},[333,1379,1380],{"class":497},"\"memory:classified\"",[333,1382,1358],{"class":342},[333,1384,1385],{"class":176,"line":406},[333,1386,1387],{"class":342},"})\n",[333,1389,1390,1393,1395,1398,1401],{"class":176,"line":411},[333,1391,1392],{"class":342},"classified_layer ",[333,1394,574],{"class":338},[333,1396,1397],{"class":342}," result[",[333,1399,1400],{"class":497},"\"OUTPUT\"",[333,1402,1403],{"class":342},"]\n",[333,1405,1406,1409,1412,1415],{"class":176,"line":416},[333,1407,1408],{"class":454},"print",[333,1410,1411],{"class":342},"(classified_layer.featureCount(), ",[333,1413,1414],{"class":497},"\"features classified\"",[333,1416,594],{"class":342},[15,1418,1419,1421,1422,1425,1426,1428,1429,1431,1432,1435,1436,1440,1441,1443,1444,1447],{},[62,1420,607],{}," The id ",[19,1423,1424],{},"mytools:areaclassifier"," combines the provider's ",[19,1427,309],{}," with the algorithm's ",[19,1430,312],{},". The parameter dictionary keys are the parameter names you defined in ",[19,1433,1434],{},"initAlgorithm()",". Because the call goes through Processing, the algorithm participates in batch runs and can be chained — see ",[27,1437,1439],{"href":1438},"\u002Fspatial-data-processing-automation\u002Fchaining-processing-algorithms\u002F","Chaining Processing Algorithms"," for composing several into a pipeline. Use ",[19,1442,21],{}," for headless execution; use ",[19,1445,1446],{},"processing.runAndLoadResults()"," when you want the output added to the active project.",[51,1449,1451],{"id":1450},"qgis-version-compatibility","QGIS Version Compatibility",[15,1453,1454,1455,1457],{},"Examples target ",[62,1456,64],{}," (Python 3.12). The provider API has been stable across recent releases.",[1179,1459,1460,1473],{},[1182,1461,1462],{},[1185,1463,1464,1467,1470],{},[1188,1465,1466],{},"QGIS release",[1188,1468,1469],{},"Python",[1188,1471,1472],{},"Provider notes",[1198,1474,1475,1493,1504],{},[1185,1476,1477,1480,1483],{},[1203,1478,1479],{},"3.28 LTR",[1203,1481,1482],{},"3.9",[1203,1484,1485,898,1487,1489,1490,72],{},[19,1486,174],{},[19,1488,865],{}," identical; use ",[19,1491,1492],{},"from qgis.PyQt.QtGui import QIcon",[1185,1494,1495,1498,1501],{},[1203,1496,1497],{},"3.34 LTR",[1203,1499,1500],{},"3.12",[1203,1502,1503],{},"Baseline for this guide; full SVG icon support.",[1185,1505,1506,1509,1511],{},[1203,1507,1508],{},"3.40 \u002F 3.44",[1203,1510,1500],{},[1203,1512,1513],{},"No breaking provider changes; Model Designer improvements benefit branded providers.",[15,1515,1516,1517,1520,1521,1523],{},"Across all three lines, the registration pattern (",[19,1518,1519],{},"QgsApplication.processingRegistry().addProvider()"," \u002F ",[19,1522,872],{},") is unchanged, so a provider written against 3.34 loads without modification on 3.28 and 3.44.",[51,1525,1527],{"id":1526},"key-takeaways","Key Takeaways",[56,1529,1530,1536,1551,1565,1575,1578],{},[59,1531,1532,1533,1535],{},"A provider is a registry container; the real logic lives in ",[19,1534,295],{}," subclasses it holds.",[59,1537,1538,1539,40,1541,82,1543,1545,1546,898,1548,1550],{},"Override ",[19,1540,309],{},[19,1542,312],{},[19,1544,315],{}," at minimum; treat ",[19,1547,309],{},[19,1549,901],{}," as permanent identifiers.",[59,1552,1553,1554,1556,1557,1559,1560,1562,1563,72],{},"Register in ",[19,1555,153],{}," with ",[19,1558,865],{}," and always pair it with ",[19,1561,872],{}," in ",[19,1564,157],{},[59,1566,1567,1568,40,1570,82,1572,1574],{},"Group and brand algorithms through ",[19,1569,897],{},[19,1571,901],{},[19,1573,624],{}," for a navigable Toolbox.",[59,1576,1577],{},"Choose a provider plugin over a script when you need distribution, branding, auto-update, or multiple related tools.",[59,1579,1580,1581,72],{},"Registered algorithms are callable everywhere via ",[19,1582,1583],{},"processing.run(\"provider_id:algorithm_id\", {...})",[51,1585,1587],{"id":1586},"frequently-asked-questions","Frequently Asked Questions",[15,1589,1590,1593,1594,1596,1597,1599],{},[62,1591,1592],{},"Why does my provider appear twice in the Toolbox after editing the plugin?","\nYou reloaded the plugin without calling ",[19,1595,872],{},". The previous instance stayed registered. Implement the symmetrical ",[19,1598,157],{}," shown above, then disable and re-enable the plugin once to clear the orphaned entry.",[15,1601,1602,1605,1606,1608,1609,72],{},[62,1603,1604],{},"Do I need a separate dialog for each algorithm?","\nNo. The Processing framework auto-generates a parameter dialog from the parameters you declare in ",[19,1607,1434],{},". This is the main efficiency gain over the manual Qt approach in ",[27,1610,48],{"href":47},[15,1612,1613,1616,1617,1619,1620,898,1623,1626],{},[62,1614,1615],{},"Can one provider mix vector and raster algorithms?","\nYes. A provider has no type restriction. Use distinct ",[19,1618,901],{}," values such as ",[19,1621,1622],{},"vector",[19,1624,1625],{},"raster"," so the Toolbox organizes them under separate sub-nodes.",[15,1628,1629,1632,1633,1635],{},[62,1630,1631],{},"How do users find my provider's algorithms after installing the plugin?","\nThey open the Processing Toolbox (Ctrl+Alt+T) and look for the group whose header matches your ",[19,1634,312],{},". Algorithms are also searchable by display name in the Toolbox filter box.",[15,1637,1638,1644,1645,1647,1648,1650,1651,1653],{},[62,1639,1640,1641,1643],{},"Is ",[19,1642,153],{}," a required method name?","\nNo, it is a convention. QGIS only calls ",[19,1646,861],{},". You may register the provider directly in ",[19,1649,861],{},", but factoring it into ",[19,1652,153],{}," keeps the code readable and matches the Plugin Builder template.",[51,1655,1657],{"id":1656},"related","Related",[56,1659,1660,1664,1668,1672,1677,1683],{},[59,1661,1662],{},[27,1663,30],{"href":29},[59,1665,1666],{},[27,1667,35],{"href":34},[59,1669,1670],{},[27,1671,48],{"href":47},[59,1673,1674],{},[27,1675,1676],{"href":1238},"Publishing to the QGIS Plugin Repository",[59,1678,1679],{},[27,1680,1682],{"href":1681},"\u002Fqgis-plugin-development\u002Ftesting-and-ci-for-plugins\u002F","Testing & CI for QGIS Plugins",[59,1684,1685],{},[27,1686,93],{"href":92},[1688,1689,1690],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":329,"searchDepth":346,"depth":346,"links":1692},[1693,1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704],{"id":53,"depth":346,"text":54},{"id":99,"depth":346,"text":100},{"id":302,"depth":346,"text":303},{"id":632,"depth":346,"text":633},{"id":890,"depth":346,"text":891},{"id":975,"depth":346,"text":976},{"id":1153,"depth":346,"text":1154},{"id":1303,"depth":346,"text":1304},{"id":1450,"depth":346,"text":1451},{"id":1526,"depth":346,"text":1527},{"id":1586,"depth":346,"text":1587},{"id":1656,"depth":346,"text":1657},"Package custom PyQGIS algorithms as a Processing provider. Subclass QgsProcessingProvider, register it in initProcessing, group algorithms, and add icons.","md",{},"\u002Fqgis-plugin-development\u002Fprocessing-provider-plugins",{"title":5,"description":1705},"qgis-plugin-development\u002Fprocessing-provider-plugins\u002Findex","QxWfu3L7nMUMXQfT8BCwbpjE_XGCkCbEkqxixEQhO_I",1781792483475]