QGIS Processing Grass Provider explanations

Last year (2017) I worked on the QGIS Grass Processing Provider. With time, I finally found how it worked. It is not so complicated but it is not so easy to understand because there is a "trick" on what is called the ext mechanism. Sometimes, developpers contact me by asking for help on this mechanism.

Here is my last email response about this subject. I also put it on my blog for people who want to understand or work on this part of QGIS.

Hello,

it's been a little bit more than one year since I have "retired" from
the QGIS project. It's just because I do have other projects that I am
working for and I had to cut down from some projects.

Well, I can only tell you about the GRASS Processing from QGIS 2.18
(but I bet that this is still the same in QGIS 3).
If you want to use the QGIS GRASS plugin, it is completely different
and I can't help you on this part.

All you have to know is that:

* The GRASS provider for QGIS Processing is just a graphical interface
  in QGIS towards GRASS.
* There is an on-the-fly creation of a GRASS database in a temporary
  directory. Then all the input layers/rasters are imported (or
  referenced) into this GRASS database.
* When you launch an algorithm from the GRASS provider, QGIS launch
  (via the shell or a system call) GRASS command line with the right
  parameters onto the temporary GRASS database. You can read this
  command line in the log.
* If the algorithm returns some results, those are extracted from the
  GRASS temporary database and converted into layers/rasters (and
  directly opened into QGIS if option has been enabled). Then the
  GRASS temporary database is deleted.

To add your add-on in the GRASS provider, you need to:

* Build a description file in
  python/plugins/processing/algs/grass7/description/. Those files just
  describe the different parameters of your algorithm (add-on). You
  can read some of those files to understand the different
  options. The description file filename must respect the algorithm
  name. 
* If your algorithm doesn't require something else than: import input
  data/launch the algorithm/extract data, then you are done. There is
  nothing more to do than the description file. 
* If your algorithm need more actions like a preliminary check on
  data, more than one GRASS command involved or a transformation on
  output data before extracting them, then you need to use the ext
  mechanism. 

The 'ext' mechanism is a (some say kind of dirty) way to add per
algorithm additional logic. There are 4 different levels where you can
add logic: 
- Checking the input parameters, if you want to verify that two
  excluding options have been both enabled. 
- Processing inputs import: if you need to do more than importing
  input layers. 
- Processing the command by itself: if you need to chain more than one
  GRASS command for your algorithm. 
- Processing the outputs export: if you need to do special things
  before exporting layers or if you need special export methods. 

Whenever you want to add some logic on one (or more) level(s), you
have to create a .py file named accordingly to the algorithm name
(modify '.' with '_'), into
python/plugins/processing/algs/grass7/ext. Then you need to create
methods that will respect names:
- Input parameters: checkParameterValuesBeforeExecuting
- Inputs import: processInputs
- Command: processCommand
- Outputs: processOutputs

If there is a Python file with the algorithm name in the ext
directory, methods will be imported from the file and run instead of
the common methods (there are "standard"
processCommand/processInputs/processOutputs/checkParameterValuesBeforeExecuting
in the code of the GRASS provider for QGIS Processing, in
python/plugins/processing/algs/grass7/Grass7Algorithm.py).

If we take the example of v.what.rast, there is an ext file:
ext/v_what_rast.py. In this file there is a processCommand method. It
just launch the standard processCommand but with the
delOutputs option set to True (we do not want to have standard
outputs). Then there is also a customized processOutputs which export
the input vector as an output for QGIS. We need to do this because
v.what.rast modify values directly into the input vector layer. It
doesn't generate dedicated output so we have to build this output
ourself. 

Clearly, if you want to do special things in the ext mechanism, you
will need to read (and understand) the GRASS provider code standard
methods in Grass7Algorithm.py.

I hope that these explanations will ease your work...