Skip to content

Commit

Permalink
Merge pull request #26 from mundialis/restore_md
Browse files Browse the repository at this point in the history
restore current version of md file
  • Loading branch information
juleshaas committed Mar 20, 2024
2 parents 8128d05 + ab7b3d4 commit ff40f41
Showing 1 changed file with 42 additions and 39 deletions.
81 changes: 42 additions & 39 deletions How-to-create-a-GRASS-GIS-addon.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ A GRASS python module consists of
- either a python script (most easy with one script as whole addon)
- or C code

#### Reuse & Recycle:
### Reuse & Recycle... and refactor!

- it helps if GRASS GIS source code is there to look at
- best to look at existing GRASS addons
Expand All @@ -43,68 +43,72 @@ A GRASS python module consists of
- inside the GRASS GIS source code all python modules are in folder 'scripts'
- or see https://grasswiki.osgeo.org/wiki/Category:Python, especially https://grasswiki.osgeo.org/wiki/GRASS_Python_Scripting_Library
- use `r.blend --script` and it will generate how it would look like as addon (like a template, not a copy of source code!) (will always create generic long version)
- use of predefinded functions `import grass.script as gscript` (e.g. gscript.run_command, gscript.message, gscript.fatal, gscript.warning, gscript.read_command)
- use of predefinded functions `import grass.script as grass` (e.g. grass.run_command, grass.message, grass.fatal, grass.warning, grass.read_command)
- See [script documentation](https://grass.osgeo.org/grass83/manuals/libpython/script.html) for more usage examples
- located in 'python/script', please read to avoid to reinvent the wheel
- TODO add docs (but better to read source code because it might be more up-to-date)
- use of [grass-gis-helpers](https://github.com/mundialis/grass-gis-helpers) library
- also beware of copying multiple code mutiple times, if there are only small changes. Consider adding methods to [grass-gis-helpers](https://github.com/mundialis/grass-gis-helpers) library instead and reuse.
- use of [github-workflows](https://github.com/mundialis/github-workflows)
- add linting workflow
- add workflow to run tests
- Submitting rules:
- https://github.com/OSGeo/grass/blob/master/CONTRIBUTING.md

#### Structure (here `r.blend` as example)
### Structure (here `r.blend` as example)

1. shebang (first line)

1. header (author, purpose, license)

1. `# % ` comments are important (ignored by python but important for parser)
2. header (author, purpose, license)
3. `# % ` comments are important (ignored by python but important for parser)

- See https://grass.osgeo.org/grass-devel/manuals/g.parser.html

```
```shell
r.blend -c first=aspect second=elevation output=elev_shade_blend
```

###### `# % module`

- including `keyword` to make it appear in keyword searches and lists

###### `# % options`

- (e.g. 'input', 'output', 'first'), some are predefined (predefined or custom, predefined is more convenient but also needs more knowledge to use)
- key is key in command line (e.g. 'first')
- answer is default values
- access them in main function like `options['first']`
- there are also [standard options]("https://grass.osgeo.org/grass84/manuals/parser_standard_options.html) which can be extended

###### `# % flag`

1. `def main():` reads in all variables (`options['first']`)
###### `# % rules`

- a main function is required

1. indefinite additional functions are possible
- define dependencies between options, required options and more. See official [docs](https://grass.osgeo.org/grass84/manuals/g.parser.html#conditional-parameters)

1. include parser at the end before calling main function:
4. `def main():` reads in all variables (`options['first']`)
- a main function is required
5. indefinite additional functions are possible
6. include parser at the end before calling main function:

```
```python
if __name__ == "__main__":
options, flags = gscript.parser()
options, flags = grass.parser()
main()
```

or optionally clean temporary stuff in 'cleanup' function and call it on exit

```
```python
if __name__ == "__main__":
options, flags = gscript.parser()
options, flags = grass.parser()
atexit.register(cleanup)
main()
```

## Best practises

- python style guide
- [PEP 8 – Style Guide for Python Code](https://peps.python.org/pep-0008/%5D)
- [PEP 8 – Style Guide for Python Code](https://peps.python.org/pep-0008/])
- https://trac.osgeo.org/grass/wiki/Submitting
- https://trac.osgeo.org/grass/wiki/Submitting/Python
- html documentation (no full html please, parts are auto-generated at compile time)
Expand All @@ -121,18 +125,24 @@ A GRASS python module consists of
```

- for this to work use message standardisation (look at locale)
- how to name it
- start with 'v.' if it is a vector module
- start with 'r.' if it is a raster module
- start with 'db.' if it is a database module
- try to stick to existing convention but no strickt rules
- do not name it too long

### how to name it

Choose a name depending on the "family":

- start with `v.` if it is a vector module
- start with `r.` if it is a raster module
- start with `i.` if it is a imagery module
- start with `db.` if it is a database module
- try to stick to existing convention but no strickt rules
- do not name it too long
- existing families are d, db, g, i, m, ps, r, r3, t, test and v

### mundialis / actinia specific

- How to handle dependencies (for installation within actinia)
- use `requirements.txt` for python packages
- How can I log to actinia output? (with `gscript.message`)
- How can I log to actinia output? (with `grass.message`)
- GRASS GIS addons need to be installed globally (see `$HOME`)
- Which things are tricky
- `db.login`, `db.connect -d`
Expand All @@ -145,20 +155,15 @@ Choose a name depending on the "family":

#### General steps

- Decide whether it should be a single addon or __multi-module / toolbox__. Example for multi-module is here: [t.sentinel](https://github.com/mundialis/t.sentinel)

- Check for __sensitive information__. If included, remove them and publish without git history (or rewrite if needed).
- Decide whether it should be a single addon or **multi-module / toolbox**. Example for multi-module is here: [t.sentinel](https://github.com/mundialis/t.sentinel)
- Check for **sensitive information**. If included, remove them and publish without git history (or rewrite if needed).

#### License + Copyright

- License is GPL3. If no LICENSE.md exists, create it later directly with GitHub (see section below).
- Copyright: no single person (only as author), `mundialis -> mundialis GmbH & Co. KG`
- Add license information to `*.py` file header:

- License is GPL3. If no LICENSE.md exists, create it later directly with GitHub (see section below).
- Copyright: no single person (only as author), `mundialis -> mundialis GmbH & Co. KG`
- Add license information to `*.py` file header:

```shell
# COPYRIGHT: (C) 2021-2024 by mundialis GmbH & Co. KG and the GRASS Development Team
#
Expand All @@ -178,7 +183,8 @@ Choose a name depending on the "family":
#### Linting

- Add reusable linting workflow as described [here](https://github.com/mundialis/github-workflows?tab=readme-ov-file#python-linting)
```

```yaml
name: Python Flake8, black and pylint code quality check

on: [push]
Expand All @@ -187,6 +193,7 @@ Choose a name depending on the "family":
lint:
uses: mundialis/github-workflows/.github/workflows/linting.yml@main
```

- Run locally. Mind that there might be differences due to version mismatches.
To overcome this, pre-commit hooks from the same repository can be used

Expand All @@ -195,6 +202,7 @@ Choose a name depending on the "family":
flake8 --config=.flake8 --count --statistics --show-source .
pylint .
```

- Fix lint errors which black couldn't fix or add exception to `.flake8` file
- Black does not fix GRASS GIS parameter `#%`. This can be batch changed with `sed -i 's|^#%|# %|g' foo.py`
- There may not be any linting issues left as the pipeline would fail
Expand Down Expand Up @@ -234,9 +242,4 @@ For more information on standardized messages see [here](https://trac.osgeo.org/
- Delete "old" code from internal repository
- Add hint to internal repository README that the addon was moved and where to find it
- Adjust README.md in actinia-assets/grass-gis-addons
- Adjust deployments which use the addon, if applicable

- Delete "old" code from internal repository
- Add hint to internal repository README that the addon was moved and where to find it
- Adjust README.md in actinia-assets/grass-gis-addons
- Adjust deployments which use the addon, if applicable
- Adjust deployments which use the addon, if applicable

0 comments on commit ff40f41

Please sign in to comment.