diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 417fd385408..8aee9f93823 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,6 +14,9 @@ It assumes that you have some very basic knowledge of Git and GitHub, but if you don't just go through some tutorial online or ask on the GRASS GIS developer mailing list. +To contribute effectively, please familiarize yourself with our +[Programming Style Guide](./doc/development/style_guide.md). + ### First time setup * Create an account on GitHub. diff --git a/doc/development/style_guide.md b/doc/development/style_guide.md new file mode 100644 index 00000000000..8268114ad5d --- /dev/null +++ b/doc/development/style_guide.md @@ -0,0 +1,889 @@ +# GRASS Programming Style Guide + +1. [Code Style and Formatting](#code-style-and-formatting) + 1. [Python](#python) + 2. [C and C++](#c-and-c) + 3. [Using pre-commit](#using-pre-commit) + 4. [Documentation](#documentation) +2. [Best Practices](#best-practices) + 1. [General](#general) + 2. [Python scripts](#developing-python-scripts) + 3. [GRASS Addons](#developing-grass-addons) + 4. [GRASS GUI](#developing-grass-gui) + +## Code Style and Formatting + +### Python + +We follow the [PEP8](http://www.python.org/dev/peps/pep-0008/) style guide for +Python. Docstrings follow [PEP257](http://www.python.org/dev/peps/pep-0257/) and +use +[Sphinx style](https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html). + +We use the following tools in the continuous integration to ensure compliance +with PEP8, consistent formatting, and readable and error-free code: + +- [Flake8](https://flake8.pycqa.org/en/latest/) tool to ensure compliance with + PEP8 +- [Black](https://black.readthedocs.io/en/stable/) code formatter to ensure + consistent code formatting +- [Pylint](https://pylint.readthedocs.io/en/latest/) static code analyser to + find bad code practices or errors + +Note that while the entire GRASS code base is Black formatted, full compliance +with PEP8, Flake8, and Pylint practices is still work in progress. + +See [using pre-commit](#using-pre-commit) for pre-commit setup and usage to +simplify performing of these checks. + +#### Black + +Use Black to format files: + +```bash +black {source_file_or_directory} +``` + +Black is configured via [pyproject.toml](../../pyproject.toml). The line +length is set to 88 characters. + +#### Flake8 + +Use Flake8 to check formatting and basic issues in all files: + +```bash +flake8 python_file.py +``` + +The root directory contains [.flake8](../../.flake8) configuration file which +contains a less strict configuration for legacy code. It will be used by default +when running Flake8 within GRASS source code. For new files, you can use the +default configuration: + +```bash +flake8 --isolated --max-line-length=88 {path_to_python_file} +``` + +For specific, temporary issues, you can explicitly specify which errors or +warnings to ignore: + +```bash +flake8 --ignore=E203,E266,E501 --max-line-length=88 python_file.py +``` + +### C and C++ + +C and C++ code is formatted with +[ClangFormat](https://clang.llvm.org/docs/ClangFormat.html). Contributions are +expected to be formatted with `clang-format` (currently with version 15+). The +most convenient method to install clang-format and format files is +[using pre-commit](#using-pre-commit). + +Alternatively, using separately installed clang-format on modified files: + +```bash +clang-format -i +``` + +The ClangFormat settings for the repo are defined in +[.clang-format](../../.clang-format). + +If using pre-commit is not an option, for whatever reason, there is a helper +script [grass_clang_format.sh](./utils/grass_clang_format.sh), which simplifies +bulk reformatting. + +### Using pre-commit + +It is highly recommended to install and use [pre-commit](https://pre-commit.com) +before submitting any new or modified code or any other content. The pre-commit +uses Git hooks to check validity and executes automated formatting for +a range of file formats, including C/C++ and Python. Pre-commit installs +all necessary tools in a virtual environment upon first use. + +If you never used pre-commit before, you must start by installing it on your +system. You only do it once: + +```bash +python -m pip install pre-commit +``` + +Pre-commit must then be activated in the code repository. Change the directory +to the root folder and use the `install` command: + +```bash +cd + +# once per repo +pre-commit install +``` + +Pre-commit will then be automatically triggered by the `git commit` command. If +it finds any problem it will abort the commit and try to solve it automatically. +In that case review the changes and run again `git add` and +`git commit`. + +It is also possible to run pre-commit manually, e.g: + +```bash +pre-commit run clang-format --all-files +pre-commit run black --all-files +``` + +Or to target a specific set of files: + +```bash +pre-commit run --files raster/r.sometool/* +``` + +The pre-commit hooks set is defined in +[.pre-commit-config.yaml](../../.pre-commit-config.yaml). + +It is possible to temporally disable the pre-commit hooks in the repo, e.g. while +working on older branches: + +```bash +# backporting... +pre-commit uninstall +``` + +And to reactivate pre-commit again: + +```bash +git switch main +pre-commit install +``` + +### Documentation + +There are three types of documentation: C API, Python API and tool documentation. + +#### C API documentation + +We +[​use doxygen and document the functions](https://grass.osgeo.org/programming8/) +directly in the source code. See `lib/gis/open.c` and `lib/gis/gislib.dox` for +examples. + +#### Python API documentation + +Python API documentation is written in reStructuredText (reST) which is +compiled with Sphinx (see +[grass package documentation](https://grass.osgeo.org/grass-devel/manuals/libpython/)) + +```python +def func(arg1, arg2): + """Summary line. + + Extended description of function. + + :param int arg1: Description of arg1. + :param str arg2: Description of arg2. + :raise: ValueError if arg1 is equal to arg2 + :return: Description of return value + :rtype: bool + + Example: + + >>> a=1 + >>> b=2 + >>> func(a,b) + True + """ + + if arg1 == arg2: + raise ValueError('arg1 must not be equal to arg2') + + return True +``` + +See +[Sphinx docstring formatting](https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html) +for more details. + +#### Tool documentation + +Documentation of a tool should come with clear descriptions, hints on the +implemented algorithm and example(s) with figures. + +Each tool (also called "module") comes with its own manual page written in +simple HTML. The HTML file contains **no header nor footer**. The complete HTML +file is autogenerated during the compilation process (with ``--html-description +parameter``). In order to make sure that manuals build without issues, it can be +useful to validate the HTML before submitting, e.g. with +[validator.w3.org](https://validator.w3.org/). + +Name the documentation file `'.html'`, e.g., if the tool is named +r.example, the documentation file should be named `r.example.html`. + +##### Markup style guide + +The structure consists of several required and optional sections: + +```html +

DESCRIPTION

+ + +

NOTES

+ + +

EXAMPLES

+ + +

TODO

+ + +

KNOWN ISSUES

+ + +

REFERENCES

+ + +

SEE ALSO

+ + +

AUTHORS

+ +``` + +Sections _Notes_, _Examples_, _References_, and _Authors_ can be also in +singular form (e.g, _Note_). + +Note that HTML is converted to man pages by +[utils/g.html2man/](../../utils/g.html2man/). +Since the man conversion is limited, please use no other HTML tags than: + +```html +
+


    1. +

        
      <tr> <ul> +``` + +More notes on markup: + +- Tool names (i.e., v.category) should be emphasized with `<em>v.category</em>`. +- Flags and parameter names written in boldface like `<b>-f</b>` and + `<b>input</b>`. +- Shell commands, names, values, etc. should use `<tt>42</tt>`. +- Emphasized phrases `<i>should use italics</i>`. +- In order to minimize potential git merge conflicts, please break a line at + approximately 70-80 chars. + +Examples should be coded like this: + +```html +<div class="code"> +<pre> +v.to.db map=soils type=area option=area column=area_size unit=h +</pre> +</div> +``` + +The `<h2>SEE ALSO</h2>` section of each page should be alphabetized: + +```html +<em> + <a href="d.shade.html">d.shade</a>, <a href="r.shade.html">r.shade</a> +</em> +``` + +Alternatively, the section can provide details on how each of the linked tools +or pages is relevant: + +```html +<em> + <a href="r.shade.html">r.shade</a> for computing shaded relief, + <a href="d.shade.html">d.shade</a> for displaying shaded relief with other data, + <a href="g.region.html">g.region</a> for managing the resolution. +</em> +``` + +In this case, the list can be ordered thematically rather than alphabetically. +Either all tools should have the description or none (do not mix the styles). + +##### Images + +**Naming convention:** `tool_name.png` or `tool_name_keyword.png` (in both cases, +dots in tool name are replaced by underscores) + +Examples: + +- `d_geodesic.png` +- `r_resamp_stats_6m_20m.png` +- `g_gui_rlisetup_8.png` +- `v_clean_rmsa.png` + +**Image size:** ideally **600 pixel width** (height depends on that), use e.g. +ImageMagic: + +```bash +mogrify -resize 600x file.png +``` + +Smaller images are also possible when appropriate, e.g. when a lot of images are +included or they are something special, e.g. equations, icons or simple +diagrams. Larger images are supported, too, see below for an optimal inclusion +into the HTML page. + +Please **compress** PNG images with: + +```bash +# color quantization +# optional, but usually worth it +# note: may change colors +pngnq -n 128 -s 3 file.png + +# shuffle original and quantitized image names +mv file.png file_ORIG.png +mv file-nq8.png file.png + +# compress better (lossless) +optipng -o5 file.png +``` + +**Format:** Images should be ideally in PNG (well, JPG and GIF is allowed as well +when appropriate but usually it is not!). Vector graphics should be included in +pages as raster images (i.e. PNGs) for portability but the original format +(preferably SVG) should be committed to the repository as well. + +Adding the image to the HTML page (r.viewshed example, the screenshot is shown +with a width of 600 pixel but it is clickable in the manual page). If a larger +image is displayed as shrunk, both **width** and **height** HTML parameters +(values must be calculated according to the picture size!) should be set: + +```html +<div align="center" style="margin: 10px"> + <a href="r_viewshed.png"> + <img + src="r_viewshed.png" + width="600" + height="600" + alt="r.viewshed example" + border="0" + /></a><br/> + <i>Figure: Viewshed shown on shaded terrain (observer position in the + north-east quadrant with white dot; 5m above ground)</i> +</div> +``` + +## Best Practices + +### General + +#### Computational Region + +Tools typically **do not change the computational region based on the input +data**. Raster processing tools should respect the current computational region. + +**Why?** Users should be able to re-run a command or workflow with different +computational regions to, e.g., test processing in a small area and then move to +a larger one. Also, changing the current region globally can break parallel +processing. + +**Exceptions**: Tools importing data typically import the entire dataset, respecting +of the region may be implemented as an optional feature (e.g., r.in.gdal). This +is to avoid, e.g., importing data under finer resolution than their native +resolution. Another exception is raster processing where alignment +of the cells plays a crucial role and there is a clear answer to how the +alignment should be done. In that case, the tool may change the resolution. Some +tools, such as r.mapcalc, opt for providing additional computational region +handling policies. Finally, some operations are meant to use all the data, e.g., +creating metadata, these operations should not use the current computational +region. + +If you need to change the computational region, there are ways to change it only +within your script, not affecting the current region. + +#### Mapsets + +**Output data should be always written to the current mapset**. This is ensured +by build-in GRASS mechanisms, so there is nothing which needs to be done in the +tool. If a tool modifies inputs, the input must be in the current mapset. + +The tool should accept inputs from any mapset in the current project. The +user-provided name **may or may not include mapset name** and the tool needs to +respect that. + +#### Input and Output Geospatial Data Format + +An analytical tool should read and write geospatial data as GRASS raster or +vector maps. Importing from and exporting to other data formats should be left +to dedicated import and export tools, e.g., _v.import_. The exceptions are +import and export of data, e.g., _r.in.xyz_. + +Processing and analytical tools can then use simple names to refer to the +data within GRASS projects instead of file paths. This follows the separation of +concerns principle: format conversion and CRS transformations are separate from +analysis. + +#### Overwriting Existing Data + +A tool should not overwrite existing data unless specified by the user using the +`--overwrite` flag. The GRASS command line parser automatically checks for +output data (raster, vector maps) existence and ends the tool execution with a +proper error message in case the output already exists. If the flag is set by +the user (`--overwrite` in command line, `overwrite=True` in Python), the parser +enables the overwriting for the tool. + +The `--overwrite` flag can be globally enabled by setting the environment variable +`GRASS_OVERWRITE` to 1. Notably, the GRASS session from _grass.jupyter_ sets +`GRASS_OVERWRITE` to 1 to enable re-running of the cells and notebooks. + +#### Mask + +GRASS GIS has a global mask managed by the _r.mask_ tool and represented by a +raster called MASK. Raster tools called as a subprocess will automatically +respect the globally set mask when reading the data. For outputs, respecting of +the mask is optional. + +Tools **should not set or remove the global mask**. If the tool cannot avoid +setting the mask internally, it should check for presence of the mask and fail +if the mask is present. The tools should not remove and later restore the +original mask because that creates confusing behavior for interactive use and +breaks parallel processing. + +Generally, any mask behavior should be documented unless it is the standard case +where masked cells do not participate in the computation and are represented as +NULL cells (no data) in the output. + +#### Formatting messages + +Put raster, vector maps, imagery groups etc. in brackets: + +```text +Raster map <elevation> not found. +``` + +Put file paths, SQL queries into single quotes: + +```text +File '/path/to/file.txt' not found. +``` + +First letter should be capitalized. + +Avoid contractions (cannot instead of can't). + +Be consistent with periods. Complete sentences or all parts of a message with +multiple sentences should end with periods. Short phrases should not. +Punctuated events, such as errors, deserve a period, e.g., _"Operation +complete."_ Phrases which imply ongoing action should have an ellipse, e.g., + _"Reading raster map..."_. + +### Developing Python scripts + +#### Import Python Scripting Library + +```python +import grass.script as gs + +gs.run_command(...) +``` + +#### String formatting + +User messages should be translatable and for formatting, use `str.format()`, not +f-strings: + +```python +gs.warning(_("Raster map <{}> not found.").format(input_map)) +``` + +For strings that are not translatable, use f-strings: + +```python +r_mapcalc_expression = f"{output_map} = {input_map} * 3" +``` + +#### Temporary files + +To create a temporary file, use `NamedTemporaryFile` with a context manager. In +this example, we open a temporary file for writing, write something and then we +can use it in another tool. Once we do not need it anymore, we need to delete it +ourselves. + +```python +import tempfile + +with tempfile.NamedTemporaryFile(mode="w", delete=False) as tmp_file: + file_path = tmp_file.name + tmp_file.write(...) + +gs.try_remove(file_path) +``` + +#### Changing computational region + +If a tool needs to change the computational region for part of the computation, +temporary region in Python API is the simplest way to do it: + +```python +gs.use_temp_region() # From now on, use a separate region in the script. +# Set the computational region with g.region as needed. +grass.run_command('g.region', raster='input') +gs.del_temp_region() +# Original region applies now. +``` + +This makes any changes done in the tool local for the tool without influencing +other tools running in the same session. + +If you need even more control, use the GRASS_REGION environment variable which +is passed to subprocesses. Python API has functions which help with the setup: + +```python +os.environ["GRASS_REGION"] = gs.region_env(raster=input_raster) +``` + +If different subprocesses need different regions, use different environments: + +```python +env = os.environ.copy() +env["GRASS_REGION"] = gs.region_env(raster=input_raster) +gs.run_command("r.slope.aspect", elevation=input_raster, slope=slope, env=env) +``` + +This approach makes the computational region completely safe for parallel +processes as no region-related files are modified. + +#### Temporary Maps + +Using temporary maps is preferred over using temporary mapsets. This follows the +rule that writing should be done only to the current mapset. Some users may have +write permissions only for their mapsets, but not for creating other mapsets. + +The following script creates a temporary name using `gs.append_node_pid` which +uses node (computer) name and process identifier to create unique, but +identifiable name. The temporary maps are removed when the script ends. + +```python +import atexit + +import grass.script as gs + + +def remove(name): + gs.run_command( + "g.remove", + type="raster", + name=name, + flags="f", + quiet=True, + errors="ignore", + ) + + + +def main(): + temporary = gs.append_node_pid("tmp_mapcalc") + atexit.register(remove, temporary) + + gs.mapcalc(f"{temporary} = rand(1, 10)") + + +if __name__ == "__main__": + main() +``` + +#### Checking inputs of a tool + +Use gs.findfile() when there is a need to test if a map exists. + +```python +# test for input raster map +result = gs.find_file(map_name, element='raster') +if not result['file']: + gs.fatal(_("Raster map <{}> not found").format(map_name)) + +# test for input vector map +result = gs.find_file(map_name, element='vector') +if not result['file']: + gs.fatal(_("Vector map <{}> not found").format(map_name)) +``` + +Tools need to accommodate input map names with (_elevation_) and without mapset +(_elevation@PERMANENT_). If you need only the map name without mapset, you can +do: + +```python +map_name = map_name.split("@")[0] +``` + +If you need the full name or the mapset only, use _gs.findfile_: + +```python +file_info = gs.find_file(map_name, element="raster") +full_name = file_info["fullname"] +name = file_info["name"] +mapset = file_info["mapset"] +``` + +#### Messages + +For any informational output, use the _gs.message_ function or _gs.verbose_. For +error messages, use _gs.fatal_ (ends execution) or _gs.error_ (just prints error, +so additional code needs to handle next steps and communicate them to the user). +For warnings, use _gs.warning_. For debugging purposes use _gs.debug_. + +```py +# normal message: +gs.message(_("Done.")) + +# verbose message: +gs.verbose(_("Computation finished successfully.")) + +# warning: +gs.warning(_("No input values found, using default values.")) + +# error: +gs.error(_("No map found.")) + +# fatal error: +# prints error and exits or raises exception (use set_raise_on_error to set the behavior) +gs.fatal(_("No map found, exiting.")) + +# debug output (users can use g.gisenv to enable/disable) +# debug level is 1 to 5 (5 is most detailed) +# debug message should not be translated +gs.debug(f"Our calculated value is: {value}."), 3) +``` + +Do not use the `print` function for informational output. This is reserved for +standard tool output if it has one. + +### Developing GRASS Addons + +#### Use Standard Options in Interface + +GRASS tools must use the GRASS parser to handle its command line parameters. To +make writing parameters simpler and the interfaces more unified, use standard +options. See +[Parser standard options](https://grass.osgeo.org/grass-devel/manuals/parser_standard_options.html). +For example, use this: + +```python +# %option G_OPT_V_INPUT +# %end +# %option G_OPT_R_OUTPUT +# %end +``` + +If needed, override values which need to be different: + +```python +# %option G_OPT_V_INPUT +# % key: point_input +# % label: Name of input vector map with points +# % description: Points used for sampling the raster input +# %end +# %option G_OPT_R_OUTPUT +# % key: raster_input +# % label: Name of sampled raster map +# % description: Raster map which will be sampled by the points +# %end +``` + +Do not repeat the values when a standard option defines them. + +#### Consider both Flags and Options to modify behavior + +Flags are boolean options that default to false. Their names +are only one character. They are defined using: + +```python +# %flag +# % key: n +# % description: Consider zeros to be null values +# %end +``` + +On the command line, the flag is used with dash as `-n`. In Python, the flag +would be used in the _flags_ parameter of `run_command`: + +```python +gs.run_command(..., flags="n", ...) +``` + +However, options are often better because they improve readability, clarify the +default behavior, and allow for extension of the interface. + +**Example:** Consider a tool which by default produces human-readable plain +text output. Then you add JSON output which is +enabled by a flag `j`. Later, you decide to add YAML output. This now needs to +be flag `y` which needs to be exclusive with flag `j`. Soon, you have several +related flags each exclusive with all the others. Using an option instead of a +flag from the beginning allows the interface to accommodate more formats. In +this example, an option named `format` can have default value `plain` and `json` +for JSON output. When you later add YAML, you simply add `yaml` to the possible +values without a need for additional options or flags. The interface definition +for the example would look like: + +```python +# %option +# % key: format +# % type: string +# % required: yes +# % options: plain,json,yaml +# % label: Output format +# % descriptions: plain;Plain text output;json;JSON output;yaml;YAML output +# % answer: plain +# %end +``` + +#### Adding description and keywords + +Each tool needs to have a description and at least 3 keywords: + +<!-- markdownlint-disable line-length --> + +```python +# %module +# % label: Generates a raster map using gaussian random number generator. +# % description: Mean and standard deviation of gaussian deviates can be expressed by the user. +# % keyword: raster +# % keyword: surface +# % keyword: random +# %end +``` + +<!-- markdownlint-enable line-length --> + +Notes: + +- the **first** keyword is the tool family which goes to the + [tool family index](https://grass.osgeo.org/grass-devel/manuals/general.html) + in the manual and should correspond to the first part of the tool name + (e.g., r is for raster). +- the **second** keyword is the overall topic which goes to the + [topic index](https://grass.osgeo.org/grass-devel/manuals/topics.html) in the + manual +- the **third** (and more) keyword goes to the + [keyword index](https://grass.osgeo.org/grass-devel/manuals/keywords.html) in + the manual + +These index manual pages are autogenerated during the build process of GRASS +GIS. + +#### Lazy import of optional dependencies + +A tool may use a package that is not [required](../../REQUIREMENTS.md) +by GRASS GIS and may not be available on a user's system. +In these cases, import only after the _gs.parser_ call. In that way the +tool can be safely compiled even if the dependency is not installed. + +```python +def main(): + options, flags = gs.parser() + try: + import pandas as pd # noqa: E402 + except ModuleNotFoundError: + gs.fatal(_("Pandas library not installed")) +``` + +#### Tool name + +Try to use names which describe shortly the intended purpose of the tool. + +The first letters for the tool name should be: + +```text +d. - display tools +db. - database tools +g. - general GIS management tools +i. - imagery tools +m. - miscellaneous tool tools +ps. - postscript tools +r. - raster tools +r3. - raster3D tools +v. - vector tools +t. - temporal tools +g.gui - GUI tools +``` + +Some additional naming conventions + +- specialized export tools: (type).out.(format) eg: _r.out.arc_, _v.out.ascii_ +- specialized import tools: (type).in.(format) eg: _r.in.arc_, _v.in.ascii_ +- conversion tools: (type).to.(type) eg: _r.to.vect_, _v.to.rast_, + _r3.to.rast_ + +Avoid tool names with more than two dots in the name. Example: instead of +_r.to.rast3.elev_ use _r.to.rast3elev_. + +#### Data processing history + +Tools should record processing history to the output data. For vectors: + +```python +gs.vector_history(output) +``` + +For rasters: + +```python +gs.raster_history(output, overwrite=True) +``` + +### Developing GRASS GUI + +Follow +[wxPython style guide](https://wiki.wxpython.org/wxPython%20Style%20Guide). + +Please use the following docstring template: + +```py +"""! +@package dir.example + +@brief Short example package description + +Classes: + - example::ExampleClass + +(C) 2024 by the GRASS Development Team + +This program is free software under the GNU General Public License +(>=v2). Read the file COPYING that comes with GRASS for details. + +@author First Author <first somewhere.com> +@author Second Author <second somewhere.com> +@author Some Other <third somewhere.com> (some particular change) +""" +``` + +#### Translations + +To enable [translating of messages](https://weblate.osgeo.org/projects/grass-gis/) +to other languages, use full strings, e.g. (good example): + +```python +if ...: + win.SetLabel(_("Name for new 3D raster map to create")) +else: + win.SetLabel(_("Name for new raster map to create")) +``` + +instead of constructing string from several parts (bad example): + +```python +# don't do this +if ...: + maplabel = 'raster map' +else: + maplabel = '3D raster map' +win.SetLabel(_("Name for new {} to create").format(maplabel)) +``` + +Sometimes the string might have different translation depending on the context +(is it a verb or a noun? matching ending of a word for particular gender; etc). +To help translators, it is suggested to add a comment explaining the context of +string. The comment must start with GTC keyword and must be on a line before +string: + +```python +self.bwizard = wx.Button(..., + # GTC New location + label = _("N&ew")) + +# GTC %s will be replaced with name of current shell +gs.message(_("Running through {}").format(shellname)) +``` diff --git a/doc/development/submitting/docs.md b/doc/development/submitting/docs.md deleted file mode 100644 index 04dccff4403..00000000000 --- a/doc/development/submitting/docs.md +++ /dev/null @@ -1,213 +0,0 @@ -# Submitting Documentation - -There are three types of documentation - -- **Library programmer's manual**: we [​use doxygen and document the functions](https://grass.osgeo.org/programming8/) - directly in the source code. See lib/gis/\*.c and lib/gis/gislib.dox for examples - -- **User manual**: each command ("module") comes with its own page. We write it - in simple HTML, storing the manual in a file `'<module>.html'` within the - subdirectory of the module. See below for details on the structure. - -- **Python documentation**: written in Markdown which is compiled with Sphinx - (see [​PyGRASS documentation](https://grass.osgeo.org/grass-stable/manuals/libpython/pygrass_index.html)) - -## HTML Pages - -The manual pages are not only fundamental for the users but also the -"business card" of the respective module. An ideal page comes with clear -descriptions, hints on the implemented algorithm and example(s). - -- Note: Do not upload broken or even empty HTML manual pages. This breaks things - in various places. -- To avoid the insertion of overly complicated HTML tags (see also below), we - strongly suggest to use a plain text editor rather than a HTML editor for - editing. - -Important: The HTML file contains **no header nor footer**. The complete HTML -file is autogenerated during the compilation process (indeed, it is generated -in a virtual session directly after compilation of the module). In this virtual -session the module is called internally with --html-description which generates -the parameters/flags list in HTML format, along with `'<module>.html'`, HTML -header and footer the final HTML manual page is created and stored in the target -binaries directory. In a separate process, the MAN format is generated from the -complete HTML files. In order to make sure that manuals build without issues, it -can be useful to validate the HTML before submitting, e.g. here: -[​https://validator.w3.org/](https://validator.w3.org/) - -### Module Manual Pages - -Place the documentation in HTML format into `'<module>.html'`, where `<module>` -is the name of the module. E.g. if the module is named r.example, the -documentation file should be named r.example.html. - -The easiest way to do this is to study an existing HTML page (to get the page -style, e.g. [​vector/v.to.db/v.to.db.html](https://github.com/OSGeo/grass/blob/main/vector/v.to.db/v.to.db.html) -[manual](https://grass.osgeo.org/grass-stable/manuals/v.to.db.html)). With a few -exceptions, header and footer are NOT allowed. You can add figures (PNG format); -the figure name prefix should be the module name. See -[​raster/r.terraflow/r.terraflow.html](https://github.com/OSGeo/grass/blob/main/raster/r.terraflow/r.terraflow.html) -([manual](https://grass.osgeo.org/grass-stable/manuals/r.terraflow.html)) for -an example. - -A number of major sections should be present in each help page. - -R = Required -S = Suggested -O = Optional - -In recommended order (in bold the required entries): - -```html -**R: <h2>DESCRIPTION</h2>** -S: <h2>NOTE</H2>, <h2>NOTES</h2> -S: <h2>EXAMPLE</h2>, <h2>EXAMPLES</h2> -O: <h2>TODO</h2> -O: <h2>KNOWN ISSUES</h2> -O: <h2>REFERENCE</h2>, <h2>REFERENCES</h2> -**R: <h2>SEE ALSO</h2>** -**R: <h2>AUTHOR</h2>, <h2>AUTHORS</h2>** -``` - -Note that the parameter manual section is auto-generated upon compilation. This -is done by running the module in a virtual session after compilation (see the -output of 'make'). To subsequently verify the final HTML page, check the -resulting HTML pages which will be stored with the name of the module. - -Examples (please add some more) should be coded like this: - -```html -<div class="code"><pre> -v.to.db map=soils type=area option=area column=area_size unit=h -</pre></div> -``` - -The [​online WWW manual pages](https://grass.osgeo.org/grass-stable/manuals/) are -updated daily (from GitHub repository). - -### Supported HTML Tags - -Since the MAN conversion of g.html2man is limited, please use no other HTML -tags than: - -```html -<a> <b> <body> <br> <code> <dd> <dl> <dt> <em> -<h2> <h3> <h4> <head> <hr> <i> <img> <li> <ol> <p> -<pre> <sup> <table> <td> <th> <title> <tr> <ul> -``` - -- Note that all tags have a closing tag except for `<hr>`, `<br>` and `<p>`. -- Use lower case forms. -- Do not insert `<p>` after `<h2>...</h2>` or `<h3>...</h3>` - -Note that HTML is converted to MAN pages by [tools/g.html2man/](https://trac.osgeo.org/grass/browser/grass/trunk/tools/g.html2man) - -### Markup style guide - -- Module names (i.e., v.category) should be emphasized with `<em>module</em>`. -- Flags and parameter names written in boldface like `<b>-f</b>` and `<b>input</b>`. -- Shell commands, names, values, etc. should use `<tt>42</tt>`. -- Emphasized phrases `<i>should use italics</i>`. - -The `<h2>SEE ALSO</h2>` section of each page should also be alphabetized. - -### Footer - -No footer to be added, since it will be added automatically during compilation. - -### Break long lines - -In order to minimize potential git merge conflicts, please break a line -at approximately 70-80 chars. - -Hints: - -- "geany" editor can format a paragraph with CTRL-j -- "atom" can do that as well -- "kate": activate it in Settings -> Kate -> Editing -> General -> enable static - word-wrap, set 72 - -## Images - -Naming convention: `module_name.png` or `module_name_keyword.png` (in both -cases, dots in module name are replaced by underscores) - -Examples: - -- `d_geodesic.png` -- `r_resamp_stats_6m_20m.png` -- `g_gui_rlisetup_8.png` -- `v_clean_rmsa.png` - -Image size: ideally **600 pixel width** (height depends on that), use -e.g. ImageMagic: - -```bash -mogrify -resize 600x file.png -``` - -Smaller images are also possible when appropriate, e.g. when a lot of images -are included or they are something special, e.g. equations, icons or simple -diagrams. Larger images are supported, too, see below for an optimal inclusion -into the HTML page. - -Please **compress** PNG images with: - -```bash -# color quantization -# optional, but usually worth it -# note: may change colors -pngnq -n 128 -s 3 file.png - -# shuffle original and quantitized image names -mv file.png file_ORIG.png -mv file-nq8.png file.png - -# compress better (lossless) -optipng -o5 file.png -``` - -See helper script -[source:grass-addons/tools/svn-image.sh](https://trac.osgeo.org/grass/browser/grass-addons/tools/svn-image.sh). - -Format: Images should be ideally in PNG (well, JPG and GIF is allowed as well -when appropriate but usually it is not!). Vector graphics should be included in -pages as raster images (i.e. PNGs) for portability but the original format -(preferably SVG) should be committed to the repository as well. - -Adding the image to the HTML page (r.viewshed example, the screenshot is shown -with a width of 600 pixel but it is clickable in the manual page). If a larger -image is displayed as shrunk, both **width** and **height** HTML parameters -(values must be calculated according to the picture size!) should be set: - -```html -<div align="center" style="margin: 10px"> -<a href="r_viewshed.png"> -<img src="r_viewshed.png" width="600" height="600" alt="r.viewshed example" border="0"> -</a><br> -<i>Figure: Viewshed shown on shaded terrain (observer position in the north-east -quadrant with white dot; 5m above ground)</i> -</div> -``` - -## Wording - -When writing documentation, honor existing terminologies, names, and wording -as they are used in GRASS GIS. Obviously, the current state is not perfect or -completely consistent, so if you identify problems, discuss them with the -community and provide suggestions and reasoning for the new wording. If you -are an experienced GRASS GIS user, keep in mind new users and their first-time -experience with GRASS GIS and their experience with other software. If you are -a new user of GRASS GIS, keep in mind current users and stability of "GRASS GIS -approach." If new terminologies, not used in GRASS GIS before are needed, please -refer first to OGC and OSGeo projects, especially GDAL and PROJ. - -For example, use "module" not "function" (means something different in -programming), "tool" (OK, but too general), "program" (does not cover usage -from GUI where it is a dialog), "script" (implementation detail), or "procedure" -(uncommon in this context and similar to workflow) when talking about the -individual executables. The word "command" is applicable when talking about -what is being executed in the command line. - -To applicable extent, this applies also to source code comments, user-visible -messages and strings, debug messages, APIs, and naming of concepts in general. diff --git a/doc/development/submitting/general.md b/doc/development/submitting/general.md deleted file mode 100644 index 48630fd3531..00000000000 --- a/doc/development/submitting/general.md +++ /dev/null @@ -1,262 +0,0 @@ -# Submitting General Notes - -## Module behaviour: computational region settings - -The current region or [​computational region](https://grasswiki.osgeo.org/wiki/Computational_region) -is the actual setting of the region boundaries and the actual raster resolution. -It can be considered as region of interest (ROI). - -As a general rule in GRASS GIS (new module implementations should follow this!): - -- **Raster maps** are always imported completely at their own resolution - (exception: WMS imported layers). -- **Vector maps** are always imported completely. -- In computations, - - raster input maps are automatically cropped/padded and rescaled (using - nearest neighbour resampling) to match the current region in order to - produce the output raster map or to query values. - - Raster output maps have their bounds and resolution equal to those of the - current computational region. - - Vector maps are always considered completely. - -## Submitting code - -Be sure to develop on top of the _latest_ GRASS GIS code which is in a Git -repository on GitHub. See [​CONTRIBUTING](https://github.com/OSGeo/grass/blob/master/CONTRIBUTING.md) -file there. - -### Commit messages - -Generally, the commit message (log message) should give an information about -_what changed in the code_ and _how the change affects the functionality_. -Additionally, the change of dependencies and changes of functionality of depended -code should be discussed if applicable. - -The general format of a message is: - -```txt -module or library: description (possible Trac ticket, merge commit or related commit) -``` - -**Good examples** (of single line commit messages): - -```txt -r.to.vect: corrected x in the crowded message -g.mremove: Changed the interface to that of g.mlist and added exclude= (ticket #2228) -libraster: Added raster name and row info to get/put\_row error messages -vlib/pg: column check must be case-insensitive -wxGUI/lmgr: add measuring of distances also to Layer Manager -wxGUI: workaround for not visible toolbars on Mac with wxPython 3 -``` - -Include ticket using hash mark and ticket number, e.g. `#2228`, and another commit -(revision) using letter r and revision number, e.g. `r60975`. This will allow Trac -(and perhaps other systems) to create a link to the ticket or commit (or revision). -However, do not rely on this and always include the information about what and why -the commit is changing and how (consider browsing commit messages in command line). - -It is possible and allowed to do multiline commit messages but you should consider -the following. First, multiline commit messages should be used to provide further -details about the commit. They should not be used to describe large changes of -code. Instead, these large changes should be split into the separate commits with -shorted commit messages. Note that this not only simplifies writing of good, -simple and readable commit messages but it also makes code review and regression -testing easier. Second, if you have a lot to say about the commit you should -perhaps include this in the comments or documentation (you can refer there to -tickets or other commits too in the same way as in commit messages, although they -will not be automatically linked). - -Write the commit messages in the way that they can be used to create/update -change logs, [release](https://github.com/OSGeo/grass/releases) pages and -news in general. - -Don't include your name (or id) to commit message, this is stored separately and -automatically. However, if you are committing someone's code (e.g. path) or you -are writing the code together with someone, include his or her name. - -Include the module, library or component name as a prefix separated by colon, -e.g. `libraster:`. You don't have to include file names in the commit message, -they are managed by SVN itself. - -If you are not sure if your style is correct, ask on mailing list. - -Some **bad examples** (of single line commit messages): - -```txt -r.slope.aspect: fix compilation -(missing information what exactly was broken and reasoning behind the fix; it's -clear that we are not trying to break something by the commit) - -wxGUI/render: attempt to fix #560 -(missing information what is #560 and how we are trying to fix it) - -Add tests for Table and Columns classes -(we don't know where the classes belongs to, prefix pygrass: or -pythonlib/pygrass would tell us in this case) - -fix bug introduced in r60216 -(missing information how the bug was fixed and which bug it was) - -fix r60216 (i18n) -(it should probably say something like: wxGUI: fix insufficient handling of i18n -(introduced in r60216)) - -libraster:Added raster name and row info to get/put\_row error messages -(missing space after colon) - -d.histogram launched from map display toolbar doesn't work -(this is description of what is wrong, not how it is fixed) - -fixed loading from a file, should I backport it? -(commit messages are not for opening discussions or general communication) -``` - -### Creating (legacy) diffs - -Be sure to create unified (`diff -u`) format. "Plain" diffs (the default format) -are risky, because they will apply without warning to code which has been -substantially changed; they are also harder to read than unified. - -Such diffs should be made from the top-level directory, e.g. -`git diff display/d.vect/main.c`; that way, the diff will include the pathname -rather than just an ambiguous `main.c`. - -### Comments - -PLEASE take the time to add comments throughout your code explaining what the -code is doing. It will save a HUGE amount of time and frustration for other -programmers that may have to change your code in the future. - -### End Of Line - -Make sure a new line is at the end of each file and UNIX style newlines are -used (`\n`). - -### Branches and backports - -The GRASS GIS repository on GitHub has the "main" and several release branches. -All the development should happen in "main" (the development branch). All the other -branches are usually associated with releases and should contain stable code -which is being prepared towards the given release. - -When a bug is fixed the fix should be committed to "main", tested there, and then -backported to the release branch or branches, if appropriate. The testing before -doing a backport should include user testing, running of automated test (if -available), and compilation of the whole source tree (ideally after the -`make distclean` step). Note that testing should already be done also prior to -the original commit to "main". Also note that not all these steps have to be -done manually, you can take an advantage of our [​CI](https://github.com/OSGeo/grass/actions). - -Often there is more than one active release branch. You can also choose to backport -only to the closest branch. If you are backporting to other release branches than -just the closets one, make sure you always backport to all the branches between -"main" and the furthest branch you are backporting to. For example, let's say we -have release branches 3.6 and 3.5, if you backport to 3.5, you should backport to -3.6, too. - -Backport only complete fixes. When you are not sure if the fix is complete or if -there is an possibility that some details such as wording will change, wait with -the backport for a little while and backport all the changes together to reduce -number of commits which needs to be reviewed (right now or in the future). You -can also backport multiple commits from "main" as one commit if you think it is -appropriate. - -Include the number of the pull request when you are backporting, into the commit -message, for example: `less verbose messages (backport of PR #1234)`. This will help -matching the file content in between branches and tracking if the commits were -backported. - -## Makefiles - -When writing Makefiles, use the current standard. - -If you have to use commands, please check for: - -| avoid | use instead | -|-------------------|-------------------------------| -| make target | $(MAKE) target | -| mkdir target | $(MKDIR) target | -| cp (executable) | $(INSTALL) -m 755 file target | -| cp (normal file) | $(INSTALL) -m 644 file target | -| ar | $(AR) | - - `rm`: be VERY careful with recursive remove. Also beware of removing - `$(FOO)*` if `$(FOO)` has any chance of being empty. - -Examples: see below examples or others - -[raster/r.info/Makefile](https://github.com/OSGeo/grass/blob/main/raster/r.info/Makefile) -[vector/v.edit/Makefile](https://github.com/OSGeo/grass/blob/main/vector/v.info/Makefile) - -If you are unsure, please ask on the GRASS Developers list. - -### AutoConf - -If you need to add support for a different library in the 'configure' script, you -should first seek consent in the grass-dev mailing list (see below), then you need -to expand 'configure.ac' and subsequently run `autoconf-2.71` (later versions -will not work) to re-generate 'configure'. - -## Naming Conventions - -Have a look at the [INSTALL](https://github.com/OSGeo/grass/blob/main/INSTALL.md) -file. - -For consistency, use `README.md` rather than `README.txt` for any `README` files. - -### Variables - -GRASS/Environment variables: - -If you add a new variable, please follow the naming convention. All variables -are described in -the [variables](https://grass.osgeo.org/grass-stable/manuals/variables.html) file. - -### Modules - -Try to use module names which describe shortly the intended purpose of the module. - -The first letters for module name should be: - -```text -d. - display commands -db. - database commands -g. - general GIS management commands -i. - imagery commands -m. - miscellaneous tool commands -ps. - postscript commands -r. - raster commands -r3. - raster3D commands -v. - vector commands -``` - -Some additional naming conventions - -- export modules: (type).out.(format) eg: `r.out.arc`, `v.out.ascii` -- import module: (type).in.(format) eg: `r.in.arc`, `v.in.ascii` -- conversion modules: (type).to.(type) eg: `r.to.vect`, `v.to.rast`, `r3.to.rast` - -Avoid module names with more than two dots in the name. Example: instead of -`r.to.rast3.elev` use `r.to.rast3elev` - -## Code Quality - -Follow the best writing practices specified by GRASS -[contributing rules](https://github.com/OSGeo/grass/blob/main/CONTRIBUTING.md) -for a given language. - -Write tests for your code. See the [testing guide](https://grass.osgeo.org/grass-stable/manuals/libpython/gunittest_testing.html) -or existing examples ([g.list](https://github.com/OSGeo/grass/tree/main/general/g.list/testsuite)). - -## Contact us - -Tell the other developers about the new code using the following e-mail: - -grass-dev@… - -To subscribe to this mailing list, see -[​https://lists.osgeo.org/mailman/listinfo/grass-dev](https://lists.osgeo.org/mailman/listinfo/grass-dev) - -In case of questions feel free to contact the developers at the above mailing list. - -[​https://grass.osgeo.org/contribute/development/](https://grass.osgeo.org/contribute/development/) diff --git a/doc/development/submitting/message_standardization.md b/doc/development/submitting/message_standardization.md deleted file mode 100644 index c7dce3e5b75..00000000000 --- a/doc/development/submitting/message_standardization.md +++ /dev/null @@ -1,610 +0,0 @@ -# Message Standardization - -In order to reduce the amount of similar strings please use standardized -messages. This helps with message translation as well. - -## How should Errors/Warnings/Messages be formatted - -- Only user derived variables should be bracketed, not GRASS derived variables, - for example: - - ```text - Yes: Creating raster map <%s>. Pass 1 of 7 ... - No: Creating <raster> map <%s>. Pass [1] of [7] ... - ``` - -- strings `< >` - raster, vector maps, group names, etc., e.g. - - Raster map `<%s>` not found -- strings `' '` \- paths, SQL queries, etc., e.g. - - File '%s' not found - - Unable to create table: '%s' - -### Discussion - -- The \[bracketed\] parenthetical disrupts the flow of the phrase and doesn't - help enhance clarity of meaning. IMHO, this reads better without \[\] - brackets: "_Line %d deleted._" \[\] Brackets should be used when value is - outside of the phrase: _"Unknown line \[%d\]"_. --HB - -### Statistics - -<!-- markdownlint-disable line-length --> -| symbol | number of code lines (2007-04-11) | 2008-02-14 (6.3svn) | 2009-08-02 (7.0svn) | 2013-06-21 (7.0svn) | -|--------|-----------------------------------|---------------------|---------------------|---------------------| -| `<%s>` | 637 | 1406 | 1935 | 2398 | -| `[%s]` | 690 | 427 | 222 | 189 | -| `'%s'` | 354 | 370 | 537 | 689 | -| `<%d>` | 12 | 7 | 11 | 18 | -| `[%d]` | 207 | 13 | 137 | 136 | -| `'%d'` | 3 | 1 | 1 | 3 | -<!-- markdownlint-enable line-length --> - -```bash -TYPES="<%s> \[%s\] '%s' <%d> \[%d\] '%d'" - -for TYPE in $TYPES ; do - NUM_HITS=`grep -rI "$TYPE" * | grep -v '/.svn/\|^dist.i686-\|locale/po/' | wc -l` - echo "$TYPE $NUM_HITS" -done -``` - -## Macros to be defined for C library - -- `MSG_RASTER_NOT_FOUND_IN_MAPSET` - "Raster map <%s> not found in <%s>" -- `MSG_CANNOT_OPEN_RASTER` - "Unable to open raster map <%s>" -- `MSG_CANNOT_OPEN_FILE` - Unable to open file <%s> - -Note: Problem with xgettext package. How to use macros to work with xgettext? - -## Standard messages sandbox - -- First letter should be capitalized -- Use the present tense - (cannot instead of could not; **better: unable to**; even better: avoid the - issue altogether by rewording like "File not found.") -- Avoid contractions (cannot instead of can't) -- Good sentence construction - ("Cannot find input map <%s>" instead of "It could not be find input map <%s>"; - possibly better: "Input map <%s> not found.") -- Be consistent with periods. Either end all phrases with a period or none. - Without periods the translators save also some time - Complete sentences or all parts of a message with multiple sentences should - end with periods. Short phrases should not. Punctuated events, such as errors, - deserve a period. e.g. _"Operation complete."_ Phrases which imply ongoing - action look odd if missing an ellipse or any other form of punctuation. - Phrase != Sentence. --HB -- Either all **module** descriptions should end with periods or not. As some - are multi-sentence, and thus should end in a period for consistency within - the message, so probably they all should end in one. Currently by my count - 237 end with '.', 139 do not. In the multi-sentence case it may be possible - to put the simple description in the module->label field and additional - explanitory text into the ->description field. -- **option** and **flag** descriptions generally should not end in a period - (more likely to be phrases than sentences). But they can suffer the same - multi-sentence period problem as module descriptions. In this case splitting - out additional text into a ->label, ->description split may help. -- Suspension points used to indicate some process is being done should be - placed next to last word, without space. e.g. - - ```text - Reading raster map... - ``` - - instead of - - ```text - Reading raster map ... - ``` - - HB: FWIW & my 2c, 1) to me keeping the space before the ellipse looks better, - is this a purely cosmetic choice or is there some style logic? \[wikipedia - article on the ellipse was cited on grass-dev, I would argue that refers to - printed typeset text not monospace terminal text, strangely suggests - punctuation+3 dots (....), is just one other guy's opinion, and I'm still not - swayed\] 2) these messages may be good candidates for G\_verbose\_message(). - - HB 2c more: (i.landsat.rgb example) - - ```text - Processing <$i>... - - Processing <$i> ... - ``` - - The version with the space just looks better. The version without just - looks wrong. But when the line ends with a word, no-space doesn't look - that bad: (v.in.ascii) - - ```text - Importing points... - - Importing points ... - ``` - -- Module descriptions should use all the same verbal tense. Currently some - of them can be found in infinitive and others in present. - -### DB messages - -db\_open\_database(), db\_start\_driver\_open\_database() - -> Unable to open database <%s> by driver <%s> - -db\_execute\_immediate() - -> Unable to insert new record: '%s' -> Unable to create table: '%s' -> Unable to drop table: '%s' - -db\_grant\_on\_table() - -> Unable to grant privileges on table <%s> - -db\_start\_driver() - -> Unable to start driver <%s> - -db\_describe\_table() - -> Unable to describe table <%s> - -db\_select\_value() - -> Unable to select record from table <%s> (key %s, column %s) -> No records selected from table <%s> - -db\_fetch() - -> Unable to fetch data from table <%s> - -db\_create\_index(), db\_create\_index2() - -> Unable to create index for table <%s>, key <%s> - -db\_copy\_table(), db\_copy\_table\_by\_ints() - -> Unable to copy table <%s> - -db\_delete\_table() - -> Unable to delete table <%s> - -db\_table\_exists() - -> Unable to find table <%s> linked to vector map <%s> - -db\_get\_column() - -> Column <%s> not found in table <%s> - -db\_list\_tables() - -> Unable to get list tables in database <%s> - -db\_open\_select\_cursor() - -> Unable to open select cursor: '%s' - -db\_create\_table() - -> Unable to create table <%s> - -db\_get\_num\_rows() - -> Unable select records from table <%s> - -### General messages - -G\_legal\_filename() - -> <%s> is an illegal file name - -G\_set\_window() - -> Invalid graphics coordinates -> Unable to set region - -D\_do\_conversions() - -> Error calculating graphics-region conversions - -G\_tempfile() - -> Unable to open temporary file <%s> - -G\_get\_projinfo() - -> Unable to get projection info of raster map - -G\_get\_projunits() - -> Unable to get projection units of raster map - -### Raster messages - -G\_find\_raster2() - -> Raster map <%s> not found -> Raster map <%s> not found in the current mapset -> Raster map <%s> not found in mapset <%s> - -Rast\_open\_old() \[in GRASS 6: G\_open\_cell\_old()\] - -> Unable to open raster map <%s> - -Rats\_open\_new \[in GRASS 6: G\_open\_cell\_new()\] - -> Unable to create raster map <%s> - -Rast\_close() \[in GRASS 6: G\_close\_cell()\] - -> Unable to close raster map <%s> - -Rast\_get\_cellhd() \[in GRASS 6: G\_get\_cellhd()\] - -> Unable to read header of raster map <%s> - -Rast\_get\_row() \[in GRASS 6: G\_get\_raster\_row()\] - -> Unable to read raster map <%s> row %d - -Rast\_put\_row() \[in GRASS 6: G\_put\_raster\_row()\] - -> Failed writing raster map <%s> row %d - -Rast\_write\_cats \[in GRASS 6: G\_write\_cats()\] - -> Unable to write category file for raster map <%s> - -Rast\_read\_colors() \[in GRASS 6: G\_read\_colors()\] - -> Unable to read color file of raster map <%s> - -Rast\_read\_cats() \[in GRASS 6: G\_read\_cats()\] - -> Unable to read category file of raster map <%s> - -Rast\_fp\_range() \[in GRASS 6: G\_read\_fp\_range()\] - -> Unable to read fp range of raster map <%s> - -Rast\_read\_range() \[in GRASS 6: G\_read\_range()\] - -> Unable to read range of raster map <%s> - -### 3D raster messages - -G\_find\_grid3() - -> 3D raster map <%s> not found -> 3D raster map <%s> not found in the current mapset -> 3D raster map <%s> not found in mapset <%s> - -G3d\_openCellOld() - -> Unable to open 3D raster map <%s> - -G3d\_range\_load() - -> Unable to read range of 3D raster map <%s> - -G3d\_closeCell() - -> Unable to close 3D raster map <%s> - -### Vector messages - -G\_find\_vector2() - -> Vector map <%s> not found -> Vector map <%s> not found in the current mapset -> Vector map <%s> not found in mapset <%s> - -Vect\_open\_old() - -> Unable to open vector map <%s> -> Unable to open vector map <%s> at topology level %d - -Vect\_open\_new() - -> Unable to create vector map <%s> - -Vect\_get\_field(), Vect\_get\_dblink() - -> Database connection not defined for layer %d - -Vect\_get\_area\_centroid() - -> Area %d without centroid or Skipping area %d without centroid - -Vect\_open\_old\_head() - -> Unable to open header file of vector map <%s> - -Vect\_map\_add\_dblink() - -> Unable to add database link for vector map <%s> - -Vect\_read\_next\_line - -> Unable to read vector map <%s> feature id %d - -### Discussion (Standard messages sandbox) - -- "Map \<roads\> in \<user1\>" or "Map \<roads\@user1\>" - - "Map \<roads@user1\>" preferred - \[\[User:Landa|ML\]\] - - If the element was given on the command line, the user knows which mapset - it came from, and the @mapset part is just extra noise. If the element is - taken from the data (how? i.group?) where the user hasn't explicitly - defined the map, then @mapset it appropriate. Also output maps are always - created in the current mapset\* so @mapset is redundant and should not be - used for new maps. \[\* i.rectify, r.in.gdal, v.in.ogr are exceptions that - can create maps in other mapsets or new locations\] --HB - -_Proposed standard responses in bold._ - -- `G_get_raster_row()` - "**Unable to read raster map <%s> row %d**" - - ```text - Cannot get raster raster of input map - Cannot raster raster of input map - Cannot read raster row [%d] - can't read row in input elevation map - Could not read from <%s> - Could not read from <%s>, row=%d - Error getting input null cells - error reading hue data - Error reading 'hue' map - Error reading input - error reading intensity data - Error reading 'intensity' map - Error reading map %s - Error reading row of data - error reading saturation data - Error reading 'saturation' map - G_get_raster_row failed - reading map - Reading map - Reading row %d - read_row: error reading data - %s: Unable to read raster map [%s] - Unable to get row %d from raster map - Unable to get row %d from <%s> - Unable to read map raster row %d - Unable to read raster row. - Unable to read raster row %d - Unable to read row %i\n - ``` - -- `G_put_raster_row()` - "**Failed writing raster map <%s> row %d**" - - ```text - Cannot write row to raster map - Cannot write to <%s> - Error while writing new cell map. - Error writing cell map during transform. - error writing data - Error writing output map - G_put_raster_row failed (file system full?) - %s - ERROR writing %s - Unable to properly write output raster map - unable to write map row %d - ``` - -- `G_open_cell_new()` - "**Unable to create raster map <%s>**" - - ```text - Cannot open output raster map <%s> - can't open %s - Error in opening output file <%s> - Unable to create output <%s> - Unable to create raster map <%s> - Unable to create raster map [%s] - Unable to open cell map <%s> for output.\n - Unable to open output file. - Unable to open the cell map MASK. - ``` - -- `G_open_cell_old()` - "**Unable to open raster map <%s>**" - - ```text - Cannot find map %s - Cannot find mapset for %s - Cannot open File %s - Cannot open input raster map <%s> - Cannot open map %s - Cannot open raster map - Cannot open raster map <%s> - Cannot open raster map [%s] - Cannot open raster map [%s]! - Cannot open %s - Cannot open seed map <%s@%s>! - Cannot open terrain raster map <%s@%s>! - Can't open input map - can't open raster map [%s] - can't open raster map <%s> in mapset %s - can't open %s - Could not open raster <%s> - Could not open raster '%s' - Error in opening input file <%s> - Not able to open cellfile for [%s] - Problem opening input file [%s] - Raster file <%s> not found - Raster map [%s] not found - <%s> cellfile not found - %s: Couldn't open raster <%s@%s> - %s: o_open_file: could not open raster map %s in %s - Unable to open band files. - Unable to open cellfile for [%s] - Unable to open map <%s> - Unable to open MASK - Unable to open raster map [%s] - Unable to open raster <%s> - unable to open [%s] in [%s] - Unable to proceed - ``` - -- `G_find_raster()` - "**Raster map <%s> not found**" - - ```text - albedo raster map <%s> not found - aspin raster map <%s> not found - Cannot find map %s - Cannot find mapset for %s - Cannot find raster map - Cannot find %s - cell file [%s] not found - coefbh raster map <%s> not found - elevin raster map <%s> not found - Input map [%s] in location [%s] in mapset [%s] not found. - latin raster map <%s> not found - linkein raster map <%s> not found - No clump map specified and MASK not set. - Raster file [%s] not found. Exiting. - Raster map [%s] already exists.\nPlease try another. - Raster map <%s> not found - Raster map [%s] not found - Raster <%s> already exist. - Raster <%s> not found - Raster '%s' not found - Requested raster map <%s> not found - [%s] cannot be found! - %s - exits in Mapset <%s>, select another name - slopein raster map <%s> not found - %s: more than %d files not allowed - %s - not found - %s: o_open_file: raster map %s not found - %s: <%s> raster map not found - %s: %s - raster map not found - %s: %s - Unable to find the imaginary-image. - %s: %s - Unable to find the real-image map. - stringliteral - Training map [%s] not found. - Unable to find base map <%s> - Unable to find cell map <%s> - Unable to find cover map <%s> - Unable to find file [%s]. - Unable to find input cell map <%s> - ``` - -- `G_find_raster2()` - "**Raster map <%s> not found**" - - ```text - Raster map <%s> not found in current mapset - Raster map <%s> not found - Raster file [%s] not found. Exiting. - ``` - -- `G_find_vector()` - "**Vector map <%s> not found**" - - ```text - Cannot find vector map - Could not find input map <%s> - Could not find input map <%s>. - Could not find input map '%s'. - Could not find input map <%s> in current mapset. - Could not find input map <%s>\n - Could not find input %s - Could not find input %s\n - Could not find input vector map <%s> - Could not find input vector map %s - Could not find network input map '%s'. - Could not find vector map <%s> in current mapset - ``` - -- `G_tempfile()` - "**Unable to open temporary file <%s>**" - - ```text - Unable to write the temporary file - Unable to open temp file. - Unable to open tempfile - Unable to open temporary file <%s> - ``` - -## Systematic Approach - -- Collect all possible error states from functions -- assign error codes for macros? -- `G_option()` parameters - (like output->description = ("Path to resulting ASCII file");) - -Note: Would be possible to conctretize your ideas? (MartinL) - -### Parameters and flags - -Fix the parameters and flags. Make it a concept. See -[proposal(s)](https://trac.osgeo.org/grass/browser/grass/trunk/doc/parms_flags.txt) - -## Verbosity levels - -### Current abstract concept - -<!-- markdownlint-disable line-length --> -| type | `GRASS_VERBOSE` | libgis | command line | result | libgis fn | -|----------|-----------------|-------------|--------------------|------------------------------------------------------|-------------------------------------------------------| -| verbose | 3 | `MAX_LEVEL` | `--verbose` | print progress and all messages messages | `G_verbose_message()` | -| standard | 2 | `STD_LEVEL` | | print progress and selected messages | `G_message()` | -| brief | 1 | | | print only progress information (% done) | `G_percent()`, `G_clicker()`, `G_important_message()` | -| quiet | 0 | `MIN_LEVEL` | `--quiet` | print nothing (only ERRORs and WARNINGs) | `G_warning()`, `G_fatal_error()` | -| debug | | 0-5 | | print debug message at DEBUG level set with g.gisenv | `G_debug(#, "")` | -| mute | \- | | `2>&1 > /dev/null` | only for use in rare occasions | | -<!-- markdownlint-enable line-length --> - -#### Proposal - -- module output (should be "parsable") is not controlled by - `GRASS_VERBOSE` \[use fprintf (stdout, ...)\] -- quiet - only warnings and fatal errors are printed -- brief - all `G_percent()` and `G_important_message()` (especially connected to - progress information??) -- standard - all `G_percent()` and selected `G_message()` -- verbose - all `G_percent()` + `G_message()` + `G_verbose_message()` - -#### Modification - -- **remove** verbose level → standard == all `G_percent()` + `G_messages()` - why?? --HB -- remove "--verbose" from help pages, manually mention where it does work. - it only does something in a few modules -- move some messages to `G_debug()` -- move some messages to `G_verbose_message()` -- move some messages to `G_important_message()` -- change level numbers to 1, 3, 5 -- Add new `G_msg(int level, "%format", ...);` lib function. Existing - `G_message()` could stay and would be the same as `G_msg(LEVEL_STD,...)`. - -#### Discussion (Current abstract concept) - -- HB: I'm quite happy to leave the current system as it is, but use - `GRASS_MESSAGE_FORMAT=silent` to switch off `G_percent()`,`G_clicker()` output. - Mixing a sliding verbosity scale plus a binary switch or >= rule for when - `G_percent()` happens in the same variable is very messy IMO. - -### Alternative abstract concept - -(Binary method, 3=1+2) - -_How to deal with --verbose messages? add levels 4 (vmsg+msg) and -5(vmsg+msg+progress) ?_ - -<!-- markdownlint-disable line-length --> -| | | | | -|---------------------|--------------------|----------------|---------------------------------| -| standard | 3 | `PERMSG_MODE` | print progress and messages | -| standard | 2 | `MESSAGE_MODE` | print only messages | -| brief | 1 | `PERCENT_MODE` | print only progress information | -| silent but not mute | 0 | `QUIET_MODE` | print nothing (but ERR and WAR) | -| mute | `2>&1 > /dev/null` | | | -<!-- markdownlint-enable line-length --> diff --git a/doc/development/submitting/python.md b/doc/development/submitting/python.md deleted file mode 100644 index a9fe71394bd..00000000000 --- a/doc/development/submitting/python.md +++ /dev/null @@ -1,423 +0,0 @@ -# Submitting Python Code - -When submitting Python code to GRASS GIS GitHub repository -([​https://github.com/OSGeo/grass/pulls](https://github.com/OSGeo/grass/pulls)), -please take care of following rules: - -## File structure - -### GRASS module - -Instructions for the GRASS script parser can be found in the -[​g.parser](https://grass.osgeo.org/grass-stable/manuals/g.parser.html) module's -help page. - -Use the directory structure to place your script appropriately into the source -tree: scripts go into `scripts` directory. - -Also add a `Makefile` and a `<module>.html` file into this directory. See existing -Python scripts for examples. - -Add a header section to the script you submit and make sure you include the -copyright. The purpose section is meant to contain a general over view of the -code in the file to assist other programmers that will need to make changes to -your code. For this purpose use a comment and [​Python docstring](https://www.python.org/dev/peps/pep-0257/). - -Example (fictitious header for a script called _g.myscript_): - -```py -#!/usr/bin/env python - -############################################################################## -# MODULE: g.myscript -# -# AUTHOR(S): Alice Doe <email AT some domain> -# -# PURPOSE: Describe your script here from maintainer perspective -# -# COPYRIGHT: (C) 2022 Alice Doe and the GRASS Development Team -# -# This program is free software under the GNU General Public -# License (>=v2). Read the file COPYING that comes with GRASS -# for details. -############################################################################## - -"""Describe your script here from Python user perspective""" -``` - -The copyright protects your rights according to GNU General Public License -([​https://www.gnu.org/licenses/](https://www.gnu.org/licenses/)). - -You can easily autogenerate the header and parameters from an existing module -using the `--script` flag. Example: - -```bash -d.rast --script -``` - -Just select an existing module which is close to your application to save efforts. - -### Python library - -Files are placed in `lib/python`. This directory becomes a package `grass` after -compilation. Each subdirectory is a subpackage. - -## Style - -### Indentation - -Use 4-space indentation (GNU Emacs python-mode default). **Do not use tabs -(tabulators) at all**. Note that Python determines nesting based upon indentation, -so it is quite crucial to be consistent, i.e. use given rules. - -### Automation - -Use Black to format new files: - -```bash -black python_file.py -``` - -Use Flake8 to check formatting of all files: - -```bash -flake8 --extend-ignore=E203,E266,E501 --max-line-length=88 python_file.py -``` - -If the file you changed gives too many error in lines you did not change, see -if the directory or any parent directory contains a file called .flake8 which -contains a less strict configuration for this legacy code. Use it with the -`--config` pararameter: - -```bash -flake8 --config {path_to_flake8_file} {path_to_python_file} -``` - -For example like this: - -```bash -flake8 --config lib/python/.flake8 lib/python/temporal/register.py -``` - -:exclamation: -It is very convenient and recommended to [use pre-commit](./submitting.md#use-pre-commit) -to do both Black formatting and Flake8 file validation. - -### Editor settings for 4-space indentation - -The correct editor settings for Python indentation - -- [​Geany](https://www.geany.org/) editor: - - Edit > Preferences > Editor > Indentation tab > Type: Spaces -- [​PyCharm](https://www.jetbrains.com/pycharm/) IDE: - - already fine and includes code-linting -- [​atom](https://atom.io/) IDE: - - ... -- [​GNU Emacs](https://www.gnu.org/software/emacs/) editor: - - python-mode default -- [​spyder](https://www.spyder-ide.org/) editor: - - ... - -For the usage of editors for GRASS GIS Python programming, see -[​https://grasswiki.osgeo.org/wiki/Tools\_for\_Python\_programming#PyCharm\_IDE](https://grasswiki.osgeo.org/wiki/Tools_for_Python_programming#PyCharm_IDE) - -### PEP8 standard Style - -Follow PEP8 standard and use the `pep8` tool to check compliance of your code to -this standard. You can either install it with `pip3` or it is offered for your -operating system as package `python3-pep8` `python3-pycodestyle`. - -Update 2020: - -- `pep8` has been renamed to `pycodestyle-3` - - Use of the `pep8` tool will be removed in future, please install and use - `pycodestyle-3` instead. - -Note that not all code is currently compliant to complete PEP8, so we are using -a custom configuration stored in `tools/pep8config.txt` -([​here](https://github.com/OSGeo/grass/blob/master/tools/pep8config.txt) shipped -within the GRASS GIS source code), so use: - -```bash -pycodestyle-3 --config=grass_master/tools/pep8config.txt directory_to_check -``` - -Alternatively, you can use `pycodestyle-3` with `--diff` option to check just -the parts of the code you have changed: - -```bash -git diff | pycodestyle-3 --diff --config=grass_master/tools/pep8config.txt -``` - -The best practice is to use `pycodestyle-3` with default configuration (i.e., -without custom configuration file) for new files and new code in old files. - -Do not fix (intentionally or unintentionally) existing style issues in code -(at lines) you are not changing. If you are fixing style issues, do it in a -separate commit. - -Summary of the most important rules: - -- Make sure a new line is at the end of each file. - -- Use three double quotes for docstrings (`"""..."""`). Use double quotes for - translatable (user visible) strings, single quotes for the rest. -- Remove trailing whitespace from the end of lines. Empty lines should not contain - any spaces. -- Put space between operators: - -```py -# use this: -angle = angle * pi / 180 -# not this: -angle = angle*pi/180 -``` - -- Do not use space around parentheses: - -```py -# use this: -grass.run_command('g.region', raster='myrast') -# not this: -grass.run_command( 'g.region', raster='myrast' ) -``` - -- Do not use space around '=' in a keyword argument: - -```py -# use this: -grass.run_command('g.region', raster='myrast') -# not this: -grass.run_command( 'g.region', raster = 'myrast' ) -``` - -- Use space after comma: - -```py -# use this: -a = [1, 2, 3] -# not this: -a = [1,2,3] -``` - -- Good practice is to use named parameters in functions: - -```py -# use this: -dlg = wx.FileDialog(parent=self, message=_("Choose file to save current workspace"), - wildcard=_("GRASS Workspace File (*.gxw)|*.gxw"), style=wx.FD_SAVE) -# not this: -dlg = wx.FileDialog(self, _("Choose file to save current workspace"), - _("GRASS Workspace File (*.gxw)|*.gxw"), wx.FD_SAVE) -``` - -## Writing the code - -### Temporary files - -Create and use secure temporary files and directories. Use the grass.tempfile() -or grass.tempdir() functions to do this. e.g. - -```py -# setup temporary file -TMP = grass.tempfile() -if TMP is None: - grass.fatal("Unable to create temporary files") -``` - -TODO: this needs to be fixed, it's more complicated - -### Temporary region - -If your script needs to modify computational region, use the following functions: - -```py -grass.use_temp_region() -# now you can safely modify the region -grass.run_command('g.region', raster='input') -# and when you are done: -grass.del_temp_region() -``` - -Note that changing computational region is usually not necessary and not even -expected. Typically, user sets region before running the script and expects all -computations to be done within this region. - -### Checking inputs of a module - -Use grass.findfile() when there is a need to test if a map exists. - -```py -# test for input raster map -result = grass.find_file(name=map_name, element='cell', quiet=True) -if not result['file'] - grass.fatal("Raster map <%s> not found" % map_name) - -# test for input vector map -result = grass.find_file(name=map_name, element='vector', quiet=True) -if not result['file'] - grass.fatal("Vector map <%s> not found" % map_name) -``` - -... and so forth. See 'g.manual g.findfile' for details. - -### Overwrite maps - -Do not use `overwrite=True` when calling a module from a Python script, if to -overwrite or not should be automatically detected based on calling of the script -with `--o` or without. - -### Messages - -For any informational output, use the grass.message() function. For error -messages should be used grass.fatal\_error() or grass.error() and for warnings -grass.warning(). For debugging purposes grass.debug(). - -```py -# normal message: -grass.message(_("Done")) - -# verbose message: -grass.verbose(_("Computation finished successfully")) - -# warning: -grass.warning(_("No input values found, using default values")) - -# error: -grass.error(_("No map found")) - -# fatal error: -# prints error and exits or raises exception (use set_raise_on_error to set the behavior) -grass.fatal_error("No map found, exiting") - -# debug output (use g.gisenv to enable/disable) -# debug level is 1 to 5 (5 is most detailed) -grass.debug(_("Our calculated value is: %d" % value), 3) -``` - -Do not use the `print` statement (print function in Python 3) for informational -output. This is reserved for standard module output if it has one. - -### Translations - -To enable translating of messages to other languages (than English), use full -strings, e.g. (good example): - -```py -if ...: - win.SetLabel(_("Name for new 3D raster map to create")) -else: - win.SetLabel(_("Name for new raster map to create")) -``` - -instead of constructing string from several parts (bad example): - -```py -if ...: - maplabel = 'raster map' -else: - maplabel = '3D raster map' -win.SetLabel(_("Name for new %s to create") % maplabel) -``` - -Sometimes the string might have different translation depending on the context -(is it a verb or a noun? matching ending of a word for particular gender; etc). -To help translators, it is suggested to add a comment explaining the context of -string. The comment must start with GTC keyword and must be on a line before -string: - -```py -self.bwizard = wx.Button(..., - # GTC New location - label = _("N&ew")) - -# GTC %s will be replaced with name of current shell -grass.message(_("Running through %s") % shellname) -``` - -See also locale/README for more information on translation process and related -issues. - -### Adding description and keywords - -Each module needs to have a description and at least 3 keywords. Here an example -from scripts/g.extension/g.extension.py: - -<!-- markdownlint-disable line-length --> -```py -\# %module -# % label: Maintains GRASS Addons extensions in local GRASS installation. -# % description: Downloads and installs extensions from GRASS Addons repository or other source into the local GRASS installation or removes installed extensions. -# % keyword: general -# % keyword: installation -# % keyword: extensions -# % keyword: addons -# % keyword: download -# %end -``` -<!-- markdownlint-enable line-length --> - -Notes: - -- the **first** keyword is the module family (**g**.list belongs to "general") - which go to the [module family index](https://grass.osgeo.org/grass74/manuals/general.html) - in the manual -- the **second** keyword is the overall topic which go to the - [topic index](https://grass.osgeo.org/grass74/manuals/topics.html) in the manual -- the **third\* (and more) keyword is describing further keywords which go to - the [keyword index](https://grass.osgeo.org/grass74/manuals/keywords.html) in - the manual** - -These index manual pages are autogenerated during the build process of GRASS GIS. - -### Dependencies on external Python libraries - -With dependencies on external, non-standard modules should use lazy imports: -[​https://lists.osgeo.org/pipermail/grass-dev/2018-October/090321.html](https://lists.osgeo.org/pipermail/grass-dev/2018-October/090321.html) - -## Documentation and comments - -Comment your classes and functions with docstrings. Use Sphinx (reStructuredText) -syntax. - -Comment also the code itself such as the meaning of variables, conditions etc. - -Take the time to add comments throughout your code explaining what the code is -doing. It will save a huge amount of time and frustration for other programmers -that may have to change your code in the future. - -## Checking the code - -Use tools such as [​pylint](https://www.pylint.org/) and pep8 to check your code -(both style and correctness). Just note that default settings of these tools is -not fully compatible with wxGUI/wxPython style and that some of the reported -errors may not apply to your code. - -## Testing - -[​https://grass.osgeo.org/grass-stable/manuals/libpython/](https://grass.osgeo.org/grass-stable/manuals/libpython/) - -## See also - -### Related submitting rules - -- [General](./general.md) general GRASS and git instructions -- [Docs](./docs.md) user documentation of modules and GUI -- [wxGUI](./wxGUI.md) wxPython-based GUI has its own rules - -### GRASS GIS documentation - -- GRASS Programming manual for C API and existing classes: - [​https://grass.osgeo.org/programming8/](https://grass.osgeo.org/programming8/) - (add more specific link) -- GRASS scripts in Python: [​https://grasswiki.osgeo.org/wiki/GRASS\_and\_Python](https://grasswiki.osgeo.org/wiki/GRASS_and_Python) -- GRASS scripts in PyGRASS: [​https://grass.osgeo.org/grass-stable/manuals/libpython/](https://grass.osgeo.org/grass-stable/manuals/libpython/) -- Python based wxGUI: [​https://grass.osgeo.org/grass-stable/manuals/wxgui/](https://grass.osgeo.org/grass-stable/manuals/wxgui/) - -### External documentation - -- Style Guide for Python Code: [​https://peps.python.org/pep-0008/](https://peps.python.org/pep-0008/) -- Python Style Guide by Guido van Rossum: - [​https://www.python.org/doc/essays/styleguide/](https://www.python.org/doc/essays/styleguide/) -- Additional info on Python docstrings: - [​https://epydoc.sourceforge.net/docstrings.html](https://epydoc.sourceforge.net/docstrings.html) diff --git a/doc/development/submitting/submitting.md b/doc/development/submitting/submitting.md deleted file mode 100644 index fb1a60af10b..00000000000 --- a/doc/development/submitting/submitting.md +++ /dev/null @@ -1,133 +0,0 @@ -# GRASS GIS development - -GRASS - Geographic Resources Analysis Support System has been under continual -development since 1982. The strength and success of GRASS GIS relies on the user -community. With this in mind, the philosophy of the GRASS Development Team is to -encourage users to develop their own unique tools and applications for GRASS. If -you develop tools and techniques that you feel would benefit other GRASS users, -please see below how to structure code and documentation for the benefit of all. - -## Submitting rules - -Be sure to check your code against these rules: - -- [General notes](./general.md) -- [C code](./submitting_c.md) -- [Python code](./python.md) -- [wxGUI code](./wxGUI.md) (wxPython-based GUI code) -- [Documentation-related notes](./docs.md) (HTML, MAN) -- [User message standardization](./message_standardization.md): formatting, - standard phrases, i18N etc. - -### Use pre-commit - -It is highly recommended to install and use [pre-commit](https://pre-commit.com) -before submitting any new or modified code or any other content. The pre-commit -Git hooks set checks validity and executes automated formatting for -a range of file formats, including C/C++ and Python. Pre-commit installs -all necessary tools in a virtual environment upon first use. - -If you never used pre-commit before, you must start by installing it on your -system. You only do it once: - -```bash -python -m pip install pre-commit -``` - -Pre-commit must then be activated in the code repository. Change the directory -to the root folder and use the `install` command: - -```bash -cd <grass_source_dir> - -# once per repo -pre-commit install -``` - -Pre-commit will then be automatically triggered by the `git commit` command. If -it finds any problem it will abort the commit and try to solve it automatically. -In that case review the changes and run again `git add` and -`git commit`. - -It is also possible to run pre-commit manually, e.g: - -```bash -pre-commit run clang-format --all-files -pre-commit run black --all-files -``` - -Or to target a specific set of files: - -```bash -pre-commit run --files raster/r.somemodule/* -``` - -The pre-commit hooks set is defined in -[.pre-commit-config.yaml](../../../.pre-commit-config.yaml). - -It is possible to temporally disable the pre-commit hooks in the repo, e.g. while -working on older branches: - -```bash -# backporting... -pre-commit uninstall -``` - -And to reactivate pre-commit again: - -```bash -git switch main -pre-commit install -``` - -## GRASS GIS programming best practice - -There are many unwritten rules how GRASS modules should work, what they should -do and what they shouldn't do. There is always some reason why some things are -considered as "good" or "bad", still they are just noted in some long GRASS -developer mailing list conversations. These pages here aim at collecting such -ideas which are floating around in the -[​GRASS-dev](https://lists.osgeo.org/mailman/listinfo/grass-dev) mailing list (and -other places) to help new module developers/bugfixers to understand many little -tricks how GRASS modules should work. - -### New list item adding guide - -List items should be short and general. Add only things that are relevant to all -modules or module groups. There should be reason why such rule/hint exists - add -reference to ML archive thread or short description why such rule is important. -Look into the documentation above for already existing specific rules. Feel free -to add code/pseudocode samples, if they apply. - -## GRASS best practice list (unsorted) - -- Read the rules above -- All GRASS modules should accept map names in format "map@mapset". [​https://lists.osgeo.org/pipermail/grass-dev/2008-February/035629.html](https://lists.osgeo.org/pipermail/grass-dev/2008-February/035629.html) -- Module should **not** write/change maps in other mapsets than current mapset. [​https://lists.osgeo.org/pipermail/grass-dev/2008-February/035637.html](https://lists.osgeo.org/pipermail/grass-dev/2008-February/035637.html) - -## GRASS GIS Addons - -- Check your code against the **Submitting rules** (see above) -- Upload your code with the git client ([git usage](https://trac.osgeo.org/grass/wiki/HowToGit)) -- Once uploaded to the GRASS GIS Addons GitHub repository: - - Addons appear in the [​Addons manual pages](https://grass.osgeo.org/grass-stable/manuals/addons/) - when being registered in the parent Makefile - - note to devs only: the addons are created via cronjobs on the server (user - can install them via g.extension) - -- GRASS GIS Python Addons - - with dependencies on external, non-standard modules should use lazy imports: - [​https://lists.osgeo.org/pipermail/grass-dev/2018-October/090321.html](https://lists.osgeo.org/pipermail/grass-dev/2018-October/090321.html) - - that represent sets of modules and eventually also share functions across - modules can be grouped into one addon directory, like e.g.: - - [​https://github.com/OSGeo/grass-addons/tree/master/grass7/gui/wxpython/wx.metadata](https://github.com/OSGeo/grass-addons/tree/master/grass7/gui/wxpython/wx.metadata) - or - - [​https://github.com/OSGeo/grass-addons/tree/master/grass7/raster/r.green](https://github.com/OSGeo/grass-addons/tree/master/grass7/raster/r.green) - -## Submitting code to GitHub - -See [HowToGit](https://trac.osgeo.org/grass/wiki/HowToGit) - -## See also - -- [​https://grass.osgeo.org/contribute/development/](https://grass.osgeo.org/contribute/development/) diff --git a/doc/development/submitting/submitting_c.md b/doc/development/submitting/submitting_c.md deleted file mode 100644 index b8b956d7488..00000000000 --- a/doc/development/submitting/submitting_c.md +++ /dev/null @@ -1,457 +0,0 @@ -# Submitting C code - -When submitting C code to GRASS GIS GitHub repository, please take care of -following rules (see also -[RFC/7_LanguageStandardsSupport](https://trac.osgeo.org/grass/wiki/RFC/7_LanguageStandardsSupport#CLanguage)): - -## API Manual - -Get and read the GRASS Programmer's Manual here: - -<https://grass.osgeo.org/programming8/> - -Or generate it from this source code (the programmer's manual is integrated in -the source code in doxygen style): - -```bash -make htmldocs -make pdfdocs -``` - -## Directory Conventions - -Use the directory structure to place your module appropriately into the source tree - -- libraries go into `lib/` -- raster modules go into `raster/` -- vector modules go into `vector/` -- ... - -Consider to take a look at "GNU Coding Standards": -<https://www.gnu.org/prep/standards/> - -## Headers - -Add a header section to file main.c of your module and make sure you include the -copyright. The purpose section is meant to contain a general overview of the code -in the file to assist other programmers that will need to make changes to your -code. If you are modifying an existing file you may under no circumstances remove -prior copyright or licensing text that is not your own, even for a major rewrite. -If any original code or code that is in part derived from another's original work -remains, it must be properly cited. - -Example: - -```c -/**************************************************************************** - * - * MODULE: g.foo - * AUTHOR(S): John Doe <jdoe at somewhere org> - * PURPOSE: Provide short description of module here... - * COPYRIGHT: (C) 2010 by John Doe, and the GRASS Development Team - * - * This program is free software under the GNU General Public - * License (>=v2). Read the COPYING file that comes with GRASS - * for details. - * - *****************************************************************************/ -``` - -The copyright protects your rights according to GNU General Public License -<https://www.gnu.org>. - -### GRASS Config Header - -To ensure that the software system continues to work, please include - -`#include <grass/config.h>` - -in your files and make use of the various system dependencies contained therein. -As one example of this, see [lib/gmath/fft.c​](../../../lib/gmath/fft.c). Please -refrain from declaring system functions within the software; include the proper -header files (conditionally dependent on config.h macros if necessary) instead. - -### Other Headers - -Order of include headers - -In general, headers should be included in the order: - -1. Core system headers (stdio.h, ctype.h, ...) -2. Headers for non-core system components (X11, libraries). -3. Headers for core systems of the package being compiled - (grass/gis.h, grass/glocale.h, ...) -4. Headers for the specific library/program being compiled (geodesic.h, ...) - -Each class of header has an obligation to be compatible with those above it in -the list, but not those below it. - -## Functions - -### Void - -Always specify the return type for ALL functions including those that return type -"void", and insert return statements for any function which returns a value. - -Also, use ANSI C prototypes to declare your functions. For module return values, -see "Exit status" below. - -Examples: - -```c -void G_something(void); -int G_something_else(int, int); - -void G_something(void) -{ - /* Snipped out code */ - - return; -} - -int G_something_else(int x, int y) -{ - /* Snipped out code */ - - return 0; -} -``` - -### G_asprintf() - -Use the GRASS library function G_asprintf() instead of the standard C functions -asprintf(), vsnprintf() and snprintf(). These functions are not portable or have -other issues. Example: - -```c -char *msg; - -G_asprintf(&msg, "%s", parameters); -do_something_with_msg(); -G_free(msg); -``` - -Note that you should free memory when G_asprintf() is used. - -### Memory Allocations - -Use the following GRASS library functions instead of the standard C functions. -The reason for this is that the following functions ensure good programming -practice (e.g. always checking if memory was allocated) and/or improves -portability. PLEASE refer to the programmers manual for the proper use (e.g. -determining if any casts are needed for arguments or return values) of these -library functions. They may perform a task slightly different from their -corresponding C library function, and thus, their use may not be the same. - -```c -G_malloc(); // instead of malloc() -G_calloc(); // instead of calloc() -G_realloc(); // instead of realloc() -G_free(); // instead of free() -G_getenv(); // instead of getenv() -G_setenv(); // instead of setenv() -G_unsetenv(); // instead of unsetenv() -G_sleep(); // instead of sleep() -``` - -Could somebody please add others (please verify that they are useful and safe -first) - -### Naming Conventions - -Use function names which fulfill the official GNU naming convention: -<https://www.gnu.org/prep/standards/html_node/Names.html#Names> - -Instead of naming a function like: MyNewFunction() use underscores for separation -and lower case letters: my_new_function()`. - -### Comments - -If you want to comment code portions, use - -```c -#ifdef notdef - portion_to_be_commented; -#endif -``` - -This is safe comparing to nested `/* comments */` - -Functions in the library must be documented in doxygen style to get them into the -programmer's manual (generate with make pdfdocs or make htmldocs). See -[lib/gis/](../../../lib/gis/) for examples. - -### Documentation in Doxygen - -Use doxygen style for source code documentation. It is required for GRASS libraries, -but also recommended for GRASS modules. - -Do not use structural command inside documentation block since it leads to some -duplication of information (e.g. do not use \fn command in comment blocks). The -exception is \file command for documenting a file, in this case structural command -is required. - -For files - -```c -/*! - \file snap.c - - \brief Vector library - Clean vector map (snap lines) - - (C) 2001-2008 by the GRASS Development Team - - This program is free software under the GNU General Public - License (>=v2). Read the file COPYING that comes with GRASS - for details. - - \author Radim Blazek -*/ -``` - -For functions - -<!-- markdownlint-disable line-length --> -```c -/*! - \brief Snap lines in vector map to existing vertex in threshold - - For details see Vect_snap_lines_list() - - \param Map pointer to input vector map - \param type filter features of given type to be snap - \param thresh threshold value for snapping - \param[out] Err pointer to vector map where lines representing snap are written or NULL - \param[out] msgout file pointer where messages will be written or NULL - - \return 1 -*/ -``` -<!-- markdownlint-enable line-length --> - -## Modules - -### Returning Value Of Main function - -Module exit status is defined as EXIT_SUCCESS or EXIT_FAILURE (declared in -stdlib.h), e.g. - -```c -{ - ... - if (G_parser (argc, argv)) - exit (EXIT_FAILURE); - - ... - exit (EXIT_SUCCESS); -} -``` - -### Messages - -Use fprintf() instead of printf(). For errors and warnings please use the -G_fatal_error() and G_warning() functions. General messages for the user should -use G_message() while debug messages should use G_debug() whenever possible. - -There are two variants to G_message(): G_verbose_message() which will only display -the message if in --verbose mode, and G_important_message() which will always -show the message unless the module is running in --quiet mode. G_fatal_error() and -G_warning() will always be displayed regardless of verbosity setting. Messages -sent to any of these functions will be printed to stderr. - -G_message() output is not expected to be sent to pipe or file. - -Messages aiming at the user should be marked for translation. Output meant for -automatic parsing by other software should not be marked for translation. -Generally all modules producing output should include localisation header: - -```c -#include "glocale.h" -``` - -Afterwards mark all user visible strings with the gettext macro \_("message"): - -```c -G_fatal_error(_("Vector map <%s> not found"), name); -``` - -It is suggested to add a comment line before translatable user message to give a -hint to translators about meaning or use of cumbersome or obscure message. First -word in the comment must be GTC: GRASS translation comment, - -Example: - -```c -/* GTC: Name of a projection */ -G_message(_("State Plane")); -``` - -Any message with a noun in plural form has to pass `n_()` macro, even if for the -English language is not required! The syntax is -`n_("English singular", "English plural", count)` - -```c -G_message( n_("%d map from mapset <%s> removed", - "%d maps from mapset <%s> removed", count), count, mapset); -/* Notice double use of "count" - as an argument for both functions - - n_() and G_message() */ - -G_message( n_("%d map selected", "%d maps selected", count), count); -G_message( n_("One file removed", "%d files removed", count) count); -/* Both of forms of singular case "%d file" or "One file" are correct. - The choice between them is purely stylistic one. */ - -/* Although in English it is not necessary to provide a separate - text if "n" always is >1, other languages do have a difference if "n" - is i.e. 2-4, or n==10 etc. */ -G_message( n_("Remove map", "Remove maps", count)); -/* Number it self doesn't have to be used in the output text */ -``` - -Pipe/file data output: For data output redirected to pipe or file, please use -fprintf() and specify the stdout stream as follows: - -```c -fprintf(stdout, ...); -fflush(stdout); - -fflush(stdout); /* always required when using fprintf(stdout, ...). */ -``` - -### Map History - -Have a function included in your module which writes to the history file of the -map (e.g. command line, parameters etc.). See e.g. -[raster/r.patch/main.c​](../../../raster/r.patch/main.c) (the same applies to -vector and raster3d modules!) - -### Standardized Options and Flags - -Standard parser options: use G_define_standard_option() whenever possible to -define standard module command line options. This will save you time, create fewer -bugs, and make things easier on the translators. See -[lib/gis/parser_standard_options.c]​(../../../lib/gis/parser_standard_options.c) -for details of the function definition. - -### Adding description and keywords - -Each module needs to have a description and at least 3 keywords. Here an example -from general/g.list/main.c: - -```c -G_gisinit(argv[0]); - -module = G_define_module(); -G_add_keyword(_("general")); -G_add_keyword(_("map management")); -G_add_keyword(_("list")); -G_add_keyword(_("search")); -module->description = - _("Lists available GRASS data base files of " - "the user-specified data type optionally using the search pattern."); -``` - -Notes: - -- the **first** keyword is the module family (**g**.list belongs to "general") - which go to the - [module family index](https://grass.osgeo.org/grass74/manuals/general.html) - in the manual -- the **second** keyword is the overall topic which go to the - [topic index](https://grass.osgeo.org/grass74/manuals/topics.html) in the manual -- the **third\* (and more) keyword is describing further keywords which go to the - [keyword index](https://grass.osgeo.org/grass74/manuals/keywords.html) - in the manual** - -These index manual pages are autogenerated during the build process of GRASS GIS. - -## Source Code Formatting - -C and C++ code is formatted with [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html). -Contributions to main branch (and grass8 branch for grass-addons) are expected -to be formatted with `clang-format` (currently with version 15+). The most -convenient method to install clang-format and format files is -[using pre-commit](./submitting.md#use-pre-commit). - -Alternatively, using separately installed clang-format on modified files: - -```bash -clang-format -i <new_or_modified_file.c> -``` - -The ClangFormat settings for the repo are defined in -[.clang-format](../../../.clang-format). - -If using pre-commit is not an option, for whatever reason, there is a helper -script [grass_clang_format.sh](./utils/grass_clang_format.sh), which simplifies -bulk reformatting. Before using this script you need to install `clang-format` -and make sure it is available on PATH. - -```bash -# Simple way to install clang-format (optional) -python -m pip install 'clang-format==15.0.6' - -# Run script to format all files in source repo -./utils/grass_clang_format.sh - -# It is also possible to format the content in a (one) given directory (faster) -./utils/grass_clang_format.sh ./lib/raster - -# Setting GRASS_CLANG_FORMAT enables use of clang-format by other name/path -GRASS_CLANG_FORMAT="clang-format-15" ./utils/grass_clang_format.sh -``` - -## Compilation - -Platform dependent code: - -Do not remove `#ifdef __CYGWIN__` and/or `#ifndef __CYGWIN__` lines and their -encapsulated lines from source code (one example was that someone removed -drand48 definition.) - -### Compiler Flags - -Suggested compiler flags: We suggest to use very strict compiler flags to capture -errors at the very beginning. Here our list of flags, please use them to configure -you development version of GRASS GIS. - -See also <https://grasswiki.osgeo.org/wiki/Compile_and_Install> - -#### GNU/Linux - -```bash -MYCFLAGS="-g -Wall -Werror-implicit-function-declaration -Wreturn-type \ - -fno-common -fexceptions" -MYCXXFLAGS="-g -Wall" -MYLDFLAGS="-Wl,--no-undefined -Wl,-z,relro" - -CFLAGS="$MYCFLAGS" CXXFLAGS="$MYCXXFLAGS" LDFLAGS="$MYLDFLAGS" ./configure ... -``` - -#### MacOSX - -(to be suggested, see ​macosx/ReadMe.rtf) - -#### MS-Windows - -(to be suggested, see CompileOnWindows) - -#### FreeBSD / NetBSD - -(to be suggested) - -See also <https://grasswiki.osgeo.org/wiki/Compile_and_Install#FreeBSD_.2F_NetBSD> - -#### IBM/AIX - -(to be suggested) - -See also <https://grasswiki.osgeo.org/wiki/Compile_and_Install#AIX> - -#### Solaris - -(to be suggested) - -See also <https://grasswiki.osgeo.org/wiki/Compile_and_Install#AIX> - -... diff --git a/doc/development/submitting/wxGUI.md b/doc/development/submitting/wxGUI.md deleted file mode 100644 index 830f8da5871..00000000000 --- a/doc/development/submitting/wxGUI.md +++ /dev/null @@ -1,137 +0,0 @@ -# Submitting wxGUI - -GUI is divided into components. One component is usually placed in one directory. - -Remember that functionality such as generating plots should be primarily -provided by library or modules not GUI. - -Try to create create also `g.gui.*` module for the new GUI component. It helps -advanced users to access functionality and developers to test it. Moreover, it -helps to keep components separated and thus, it supports re-usability. - -## File structure - -Add a header section to each file you submit and make sure you include the -copyright. The purpose section is meant to contain a general over view of the -code in the file to assist other programmers that will need to make changes to -your code. For this purpose use Python docstring. - -The copyright protects your rights according to GNU General Public License -(<www.gnu.org>). - -Please use the following docstring template: - -```py -"""! -@package dir.example - -@brief Short example package description - -Classes: - - example::ExampleClass - -(C) 2012 by the GRASS Development Team - -This program is free software under the GNU General Public License -(>=v2). Read the file COPYING that comes with GRASS for details. - -@author First Author <first somewhere.com> -@author Second Author <second somewhere.com> -@author Some Other <third somewhere.com> (some particular change) -""" -``` - -## Documentation and comments - -Some information about docstrings: - -- always use """triple double quotes""" around docstrings -- there's no blank line either before or after the docstring -- add information on the parameters used by the function you have to use the - following format - - ```py - :param TYPE NAMEPARAM: explanation - ``` - - where TYPE is the type (bool, str, int) of parameter and it is optional; - NAMEPARAM is the name of parameter - -- add information about the return of function using - - ```py - :return: explanation - ``` - -- add reference to classes and function using - - ```py - :class:`CLASSNAME` - :func:`FUNCNAME` - ``` - -- add TODO in docstring as follow - - ```py - .. todo:: - information todo - ``` - - in similar way you can add warning and note. - -When using class Signal from `grass.pydispatch.signal`, write a short -description to as a constructor parameter and describe implementation details -in standard comments before the definition. Note the signal in each function -which is invoking it. - -## Writing the code - -Do not use print command unless you know what you are doing. - -Use `wx.ID_ANY` instead of `-1`. - -Use `GError`, `GWarning` and `GMessage` instead of `wx.MessageBox()` - -Do not use `grass.run_command()` or `grass.read_command()`. Use functions and -classes which use threads such as `RunCommand`. - -When using `AddGrowableCol` and/or `AddGrowableRow` with sizers, put it after -adding widgets into the sizer, not just after creating of the sizer (needed for -wxPython >= 2.9). - -For translatable strings use underscore: - -```py -_("User visible text") -``` - -The underscore function must be explicitly imported: - -```py -from core.utils import _ -``` - -## Testing - -## See also - -### Related submitting rules - -- [General notes](./general.md) general GRASS and git instructions -- [Python code](./python.md) Python library and scripts related instructions - which applies to wxGUI too if not stated otherwise -- [Documentation-related notes](./docs.md) user documentation of modules and GUI - -### GRASS GIS documentation - -- Sphinx Pages about how to develop wxGUI: - [​https://grass.osgeo.org/grass-stable/manuals/wxgui/](https://grass.osgeo.org/grass-stable/manuals/wxgui/) -- Wiki Pages about how to develop wxGUI: [​https://grasswiki.osgeo.org/wiki/WxGUI](https://grasswiki.osgeo.org/wiki/WxGUI) -- GRASS Trac wiki has pages about the state of wxGUI development: - [​https://trac.osgeo.org/grass/wiki/wxGUIDevelopment](https://trac.osgeo.org/grass/wiki/wxGUIDevelopment) -- GRASS Programming manual for C API and existing classes: - [​https://grass.osgeo.org/programming8/](https://grass.osgeo.org/programming8/) - -### External documentation - -- wxPython Style Guide: [​https://wiki.wxpython.org/wxPython\_Style\_Guide](https://wiki.wxpython.org/wxPython%20Style%20Guide)