Просмотр исходного кода

Apply Black to all scripts (#1347)

This applies Black 20.8b1 to all Python modules in scripts
and adds an action which checks the formatting and produces diff if needed.

It modifies the .flake8 file so that Flake8 ignores an error which
is considered to be a false positive (PEP8 says 'in a slice the colon acts like a binary operator'
and thus suggests/allows spaces around it while Flake8 marks that as an error
as if it would be a colon in if or for.

Also change comments into docstrings in the g.bands test.
Vaclav Petras 4 лет назад
Родитель
Сommit
0d9e966dd2
100 измененных файлов с 7716 добавлено и 5988 удалено
  1. 35 0
      .github/workflows/black.yml
  2. 5 0
      scripts/.flake8
  3. 21 17
      scripts/d.correlate/d.correlate.py
  4. 85 50
      scripts/d.frame/d.frame.py
  5. 9 7
      scripts/d.out.file/d.out.file.py
  6. 144 129
      scripts/d.polar/d.polar.py
  7. 7 7
      scripts/d.polar/testsuite/test_d_polar.py
  8. 117 128
      scripts/d.rast.edit/d.rast.edit.py
  9. 34 34
      scripts/d.rast.leg/d.rast.leg.py
  10. 18 13
      scripts/d.redraw/d.redraw.py
  11. 7 6
      scripts/d.shade/d.shade.py
  12. 10 8
      scripts/d.to.rast/d.to.rast.py
  13. 9 7
      scripts/d.what.rast/d.what.rast.py
  14. 9 7
      scripts/d.what.vect/d.what.vect.py
  15. 25 17
      scripts/db.dropcolumn/db.dropcolumn.py
  16. 12 13
      scripts/db.dropcolumn/testsuite/test_db_dropcolumn.py
  17. 16 15
      scripts/db.droptable/db.droptable.py
  18. 9 9
      scripts/db.droptable/testsuite/test_db_droptable.py
  19. 55 35
      scripts/db.in.ogr/db.in.ogr.py
  20. 16 18
      scripts/db.in.ogr/testsuite/test_db_in_ogr.py
  21. 37 23
      scripts/db.out.ogr/db.out.ogr.py
  22. 21 19
      scripts/db.test/db.test.py
  23. 64 71
      scripts/db.univar/db.univar.py
  24. 17 15
      scripts/db.univar/testsuite/test_db_univar.py
  25. 9 9
      scripts/g.bands/g.bands.py
  26. 10 13
      scripts/g.bands/testsuite/test_g_bands.py
  27. 27 25
      scripts/g.extension.all/g.extension.all.py
  28. 703 601
      scripts/g.extension/g.extension.py
  29. 4 4
      scripts/g.extension/testsuite/data/sample_modules/r.plus.example/r.plus.example.py
  30. 41 24
      scripts/g.extension/testsuite/test_addons_modules.py
  31. 3 3
      scripts/g.extension/testsuite/test_addons_toolboxes.py
  32. 54 37
      scripts/g.manual/g.manual.py
  33. 72 59
      scripts/g.search.modules/g.search.modules.py
  34. 17 19
      scripts/g.search.modules/testsuite/test_g_search_modules.py
  35. 26 16
      scripts/i.band/i.band.py
  36. 10 9
      scripts/i.band/testsuite/test_i_band.py
  37. 49 37
      scripts/i.colors.enhance/i.colors.enhance.py
  38. 14 14
      scripts/i.image.mosaic/i.image.mosaic.py
  39. 71 53
      scripts/i.in.spotvgt/i.in.spotvgt.py
  40. 20 18
      scripts/i.oif/i.oif.py
  41. 422 237
      scripts/i.pansharpen/i.pansharpen.py
  42. 57 51
      scripts/i.spectral/i.spectral.py
  43. 205 62
      scripts/i.tasscap/i.tasscap.py
  44. 57 48
      scripts/m.proj/m.proj.py
  45. 70 53
      scripts/r.blend/r.blend.py
  46. 17 15
      scripts/r.blend/testsuite/test_r_blend.py
  47. 20 15
      scripts/r.blend/testsuite/test_r_blend_quoting.py
  48. 31 26
      scripts/r.buffer.lowmem/r.buffer.lowmem.py
  49. 73 56
      scripts/r.colors.stddev/r.colors.stddev.py
  50. 35 24
      scripts/r.drain/r.drain.py
  51. 334 169
      scripts/r.fillnulls/r.fillnulls.py
  52. 31 21
      scripts/r.fillnulls/testsuite/test_r_fillnulls.py
  53. 43 24
      scripts/r.grow/r.grow.py
  54. 25 22
      scripts/r.grow/testsuite/test_r_grow.py
  55. 12 12
      scripts/r.grow/testsuite/test_r_grow_quoting.py
  56. 196 127
      scripts/r.import/r.import.py
  57. 91 34
      scripts/r.import/testsuite/test_r_import.py
  58. 64 45
      scripts/r.in.aster/r.in.aster.py
  59. 45 40
      scripts/r.in.srtm/r.in.srtm.py
  60. 30 21
      scripts/r.in.wms/r.in.wms.py
  61. 1728 1724
      scripts/r.in.wms/srs.py
  62. 357 253
      scripts/r.in.wms/wms_base.py
  63. 173 147
      scripts/r.in.wms/wms_cap_parsers.py
  64. 474 352
      scripts/r.in.wms/wms_drv.py
  65. 46 33
      scripts/r.in.wms/wms_gdal_drv.py
  66. 11 11
      scripts/r.mapcalc.simple/r.mapcalc.simple.py
  67. 21 17
      scripts/r.mapcalc.simple/testsuite/test_rmapcalcsimple.py
  68. 85 49
      scripts/r.mask/r.mask.py
  69. 11 10
      scripts/r.mask/testsuite/test_r_mask.py
  70. 8 7
      scripts/r.out.xyz/r.out.xyz.py
  71. 9 7
      scripts/r.out.xyz/testsuite/test_r_out_xyz.py
  72. 52 39
      scripts/r.pack/r.pack.py
  73. 7 7
      scripts/r.pack/testsuite/test_r_pack.py
  74. 29 20
      scripts/r.plane/r.plane.py
  75. 15 9
      scripts/r.plane/testsuite/test_r_plane.py
  76. 76 59
      scripts/r.reclass.area/r.reclass.area.py
  77. 36 15
      scripts/r.reclass.area/testsuite/test_r_reclass_area.py
  78. 58 18
      scripts/r.reclass.area/testsuite/testrra.py
  79. 13 13
      scripts/r.rgb/r.rgb.py
  80. 13 10
      scripts/r.rgb/testsuite/test_r_rgb.py
  81. 33 27
      scripts/r.shade/r.shade.py
  82. 10 9
      scripts/r.shade/testsuite/test_r_shade.py
  83. 166 126
      scripts/r.tileset/r.tileset.py
  84. 10 6
      scripts/r.tileset/testsuite/test_r_tileset.py
  85. 87 60
      scripts/r.unpack/r.unpack.py
  86. 90 64
      scripts/r3.in.xyz/r3.in.xyz.py
  87. 9 7
      scripts/v.build.all/v.build.all.py
  88. 21 12
      scripts/v.centroids/testsuite/test_v_centroids.py
  89. 4 3
      scripts/v.centroids/v.centroids.py
  90. 56 27
      scripts/v.clip/testsuite/test_v_clip.py
  91. 62 34
      scripts/v.clip/v.clip.py
  92. 18 14
      scripts/v.db.addcolumn/testsuite/test_v_db_addcolumn.py
  93. 18 13
      scripts/v.db.addcolumn/v.db.addcolumn.py
  94. 12 11
      scripts/v.db.addtable/testsuite/test_v_db_addtable.py
  95. 49 32
      scripts/v.db.addtable/v.db.addtable.py
  96. 7 8
      scripts/v.db.dropcolumn/testsuite/test_v_db_dropcolumn.py
  97. 35 21
      scripts/v.db.dropcolumn/v.db.dropcolumn.py
  98. 27 18
      scripts/v.db.droprow/testsuite/test_v_db_droprow.py
  99. 10 5
      scripts/v.db.droprow/v.db.droprow.py
  100. 0 0
      scripts/v.db.droptable/testsuite/test_v_db_droptable.py

+ 35 - 0
.github/workflows/black.yml

@@ -0,0 +1,35 @@
+name: Python Black Formatting
+
+on:
+- push
+- pull_request
+
+jobs:
+
+  run-black:
+    name: ${{ matrix.directory }}
+    runs-on: ubuntu-20.04
+    strategy:
+      matrix:
+        directory:
+        - scripts
+      fail-fast: false
+
+    steps:
+
+    - uses: actions/checkout@v2
+
+    - name: Set up Python
+      uses: actions/setup-python@v2
+      with:
+        python-version: 3.8
+
+    - name: Install
+      run: |
+        python -m pip install --upgrade pip
+        pip install black==20.8b1
+
+    - name: Run Black
+      run: |
+        cd ${{ matrix.directory }}
+        black --check --diff .

+ 5 - 0
scripts/.flake8

@@ -28,6 +28,11 @@ ignore =
     W503, # line break before binary operator
     W504, # line break after binary operator
 
+# Ignores for Black compatibility
+# This is not to be removed unlike the ones in ignore.
+extend-ignore =
+    E203,  # whitespace before ':' (in a slice the colon acts like a binary operator)
+
 max-line-length = 88
 exclude =
     .git,

+ 21 - 17
scripts/d.correlate/d.correlate.py

@@ -34,7 +34,7 @@ from grass.exceptions import CalledModuleError
 
 
 def main():
-    layers = options['map'].split(',')
+    layers = options["map"].split(",")
 
     if len(layers) < 2:
         gcore.error(_("At least 2 maps are required"))
@@ -42,16 +42,17 @@ def main():
     tmpfile = gcore.tempfile()
 
     for map in layers:
-        if not gcore.find_file(map, element='cell')['file']:
+        if not gcore.find_file(map, element="cell")["file"]:
             gcore.fatal(_("Raster map <%s> not found") % map)
 
     try:
-        gcore.write_command('d.text', color='black', size=4, line=1,
-                            stdin="CORRELATION")
+        gcore.write_command(
+            "d.text", color="black", size=4, line=1, stdin="CORRELATION"
+        )
     except CalledModuleError:
         return 1
 
-    os.environ['GRASS_RENDER_FILE_READ'] = 'TRUE'
+    os.environ["GRASS_RENDER_FILE_READ"] = "TRUE"
 
     colors = "red black blue green gray violet".split()
     line = 2
@@ -63,19 +64,19 @@ def main():
                 color = colors[0]
                 colors = colors[1:]
                 colors.append(color)
-                gcore.write_command('d.text', color=color, size=4, line=line,
-                                    stdin="%s %s" % (i, j))
+                gcore.write_command(
+                    "d.text", color=color, size=4, line=line, stdin="%s %s" % (i, j)
+                )
                 line += 1
 
-                ofile = open(tmpfile, 'w')
-                gcore.run_command('r.stats', flags='cnA', input=(i, j),
-                                  stdout=ofile)
+                ofile = open(tmpfile, "w")
+                gcore.run_command("r.stats", flags="cnA", input=(i, j), stdout=ofile)
                 ofile.close()
 
-                ifile = open(tmpfile, 'r')
+                ifile = open(tmpfile, "r")
                 first = True
                 for l in ifile:
-                    f = l.rstrip('\r\n').split(' ')
+                    f = l.rstrip("\r\n").split(" ")
                     x = float(f[0])
                     y = float(f[1])
                     if first:
@@ -95,16 +96,18 @@ def main():
                 kx = 100.0 / (maxx - minx + 1)
                 ky = 100.0 / (maxy - miny + 1)
 
-                p = gcore.feed_command('d.graph', color=color)
+                p = gcore.feed_command("d.graph", color=color)
                 ofile = p.stdin
 
-                ifile = open(tmpfile, 'r')
+                ifile = open(tmpfile, "r")
                 for l in ifile:
-                    f = l.rstrip('\r\n').split(' ')
+                    f = l.rstrip("\r\n").split(" ")
                     x = float(f[0])
                     y = float(f[1])
-                    ofile.write(b"icon + 0.1 %f %f\n" % ((x - minx + 1) * kx,
-                                                        (y - miny + 1) * ky))
+                    ofile.write(
+                        b"icon + 0.1 %f %f\n"
+                        % ((x - minx + 1) * kx, (y - miny + 1) * ky)
+                    )
                 ifile.close()
 
                 ofile.close()
@@ -114,6 +117,7 @@ def main():
 
     return 0
 
+
 if __name__ == "__main__":
     options, flags = gcore.parser()
     sys.exit(main())

+ 85 - 50
scripts/d.frame/d.frame.py

@@ -68,22 +68,30 @@
 import os
 import sys
 
-from grass.script.core import fatal, parse_command, parser, read_command, run_command, warning
+from grass.script.core import (
+    fatal,
+    parse_command,
+    parser,
+    read_command,
+    run_command,
+    warning,
+)
 
 # check if monitor is running
 
 
 def check_monitor():
-    return read_command('d.mon', flags='p', quiet=True).strip()
+    return read_command("d.mon", flags="p", quiet=True).strip()
+
 
 # read monitor file and return list of lines
 # TODO: replace by d.info (see #2577)
 
 
-def read_monitor_file(monitor, ftype='env'):
+def read_monitor_file(monitor, ftype="env"):
     mfile = check_monitor_file(monitor, ftype)
     try:
-        fd = open(mfile, 'r')
+        fd = open(mfile, "r")
     except IOError as e:
         fatal(_("Unable to get monitor info. %s"), e)
 
@@ -95,30 +103,33 @@ def read_monitor_file(monitor, ftype='env'):
 
     return lines
 
+
 # check if monitor file exists
 
 
-def check_monitor_file(monitor, ftype='env'):
-    mfile = parse_command('d.mon', flags='g').get(ftype, None)
+def check_monitor_file(monitor, ftype="env"):
+    mfile = parse_command("d.mon", flags="g").get(ftype, None)
     if mfile is None or not os.path.isfile(mfile):
         fatal(_("Unable to get monitor info"))
 
     return mfile
 
+
 # write new monitor file
 
 
-def write_monitor_file(monitor, lines, ftype='env'):
+def write_monitor_file(monitor, lines, ftype="env"):
     mfile = check_monitor_file(monitor, ftype)
 
     try:
-        fd = open(mfile, 'w')
+        fd = open(mfile, "w")
     except IOError as e:
         fatal(_("Unable to get monitor info. %s"), e)
 
     fd.writelines(lines)
     fd.close()
 
+
 # remove all frames and erase screen
 
 
@@ -126,44 +137,47 @@ def erase(monitor):
     # remove frames
     lines = []
     for line in read_monitor_file(monitor):
-        if 'FRAME' not in line:
+        if "FRAME" not in line:
             lines.append(line)
 
     write_monitor_file(monitor, lines)
 
     # erase screen
-    run_command('d.erase')
+    run_command("d.erase")
+
 
 # find frame for given monitor
 
 
 def find_frame(monitor, frame):
     for line in read_monitor_file(monitor):
-        if 'FRAME' in line:
+        if "FRAME" in line:
             if get_frame_name(line) == frame:
                 return True
 
     return False
 
+
 # print frames name(s) to stdout
 
 
 def print_frames(monitor, current_only=False, full=False):
     for line in read_monitor_file(monitor):
-        if 'FRAME' not in line:
+        if "FRAME" not in line:
             continue
-        if current_only and line.startswith('#'):
+        if current_only and line.startswith("#"):
             continue
         sys.stdout.write(get_frame_name(line))
         if full:
-            sys.stdout.write(':' + line.split('=', 1)[1].rsplit('#', 1)[0])
-        sys.stdout.write('\n')
+            sys.stdout.write(":" + line.split("=", 1)[1].rsplit("#", 1)[0])
+        sys.stdout.write("\n")
+
 
 # get frame name from line
 
 
 def get_frame_name(line):
-    return line.rstrip('\n').rsplit('#', 1)[1].strip(' ')
+    return line.rstrip("\n").rsplit("#", 1)[1].strip(" ")
 
 
 def calculate_frame(frame, at, width, height):
@@ -191,18 +205,25 @@ def calculate_frame(frame, at, width, height):
     'GRASS_RENDER_FRAME=183,367,0,184 # test_truncating_bug\\n'
     """
     try:
-        b, t, l, r = list(map(float, at.split(',')))
+        b, t, l, r = list(map(float, at.split(",")))
     except:
         fatal(_("Invalid frame position: %s") % at)
 
-    top = round(height - (t / 100. * height))
-    bottom = round(height - (b / 100. * height))
-    left = round(l / 100. * width)
-    right = round(r / 100. * width)
+    top = round(height - (t / 100.0 * height))
+    bottom = round(height - (b / 100.0 * height))
+    left = round(l / 100.0 * width)
+    right = round(r / 100.0 * width)
 
     # %d for floats works like int() - truncates
-    return 'GRASS_RENDER_FRAME=%d,%d,%d,%d # %s%s' % \
-        (top, bottom, left, right, frame, '\n')
+    return "GRASS_RENDER_FRAME=%d,%d,%d,%d # %s%s" % (
+        top,
+        bottom,
+        left,
+        right,
+        frame,
+        "\n",
+    )
+
 
 # create new frame
 
@@ -213,10 +234,10 @@ def create_frame(monitor, frame, at, overwrite=False):
     width = height = -1
     for line in lines:
         try:
-            if 'WIDTH' in line:
-                width = int(line.split('=', 1)[1].rsplit(' ', 1)[0])
-            elif 'HEIGHT' in line:
-                height = int(line.split('=', 1)[1].rsplit(' ', 1)[0])
+            if "WIDTH" in line:
+                width = int(line.split("=", 1)[1].rsplit(" ", 1)[0])
+            elif "HEIGHT" in line:
+                height = int(line.split("=", 1)[1].rsplit(" ", 1)[0])
         except:
             pass
 
@@ -228,13 +249,14 @@ def create_frame(monitor, frame, at, overwrite=False):
     else:
         for idx in range(len(lines)):
             line = lines[idx]
-            if 'FRAME' not in line:
+            if "FRAME" not in line:
                 continue
             if get_frame_name(line) == frame:
                 lines[idx] = calculate_frame(frame, at, width, height)
 
     write_monitor_file(monitor, lines)
 
+
 # select existing frame
 
 
@@ -242,13 +264,13 @@ def select_frame(monitor, frame):
     lines = read_monitor_file(monitor)
     for idx in range(len(lines)):
         line = lines[idx]
-        if 'FRAME' not in line:
+        if "FRAME" not in line:
             continue
         if get_frame_name(line) == frame:
-            if line.startswith('#'):
-                lines[idx] = line.lstrip('# ')  # un-comment line
-        elif not line.startswith('#'):
-            lines[idx] = '# ' + line  # comment-line
+            if line.startswith("#"):
+                lines[idx] = line.lstrip("# ")  # un-comment line
+        elif not line.startswith("#"):
+            lines[idx] = "# " + line  # comment-line
 
     write_monitor_file(monitor, lines)
 
@@ -259,47 +281,60 @@ def main():
     if not monitor:
         fatal(_("No graphics device selected. Use d.mon to select graphics device."))
 
-    if flags['e']:
+    if flags["e"]:
         # remove frames and erase monitor and exit
         erase(monitor)
         return
 
-    if flags['p']:
+    if flags["p"]:
         # print current frame and exit
         print_frames(monitor, current_only=True)
         return
 
-    if flags['a']:
+    if flags["a"]:
         # print all frames including their position and exit
         print_frames(monitor, current_only=False, full=True)
         return
 
-    found = find_frame(monitor, options['frame'])
+    found = find_frame(monitor, options["frame"])
     if not found:
-        if not flags['c']:
-            fatal(_("Frame <%s> doesn't exist, exiting. "
-                    "To create a new frame use '-c' flag.") % options['frame'])
+        if not flags["c"]:
+            fatal(
+                _(
+                    "Frame <%s> doesn't exist, exiting. "
+                    "To create a new frame use '-c' flag."
+                )
+                % options["frame"]
+            )
         else:
-            if not options['at']:
+            if not options["at"]:
                 fatal(_("Required parameter <%s> not set") % "at")
             # create new frame if not exists
-            create_frame(monitor, options['frame'], options['at'])
+            create_frame(monitor, options["frame"], options["at"])
     else:
-        if os.getenv('GRASS_OVERWRITE', '0') == '1':
-            warning(_("Frame <%s> already exists and will be overwritten") % options['frame'])
-            create_frame(monitor, options['frame'], options['at'], overwrite=True)
+        if os.getenv("GRASS_OVERWRITE", "0") == "1":
+            warning(
+                _("Frame <%s> already exists and will be overwritten")
+                % options["frame"]
+            )
+            create_frame(monitor, options["frame"], options["at"], overwrite=True)
         else:
-            if options['at']:
+            if options["at"]:
                 warning(
-                    _("Frame <%s> already found. An existing frame can be overwritten by '%s' flag.") %
-                    (options['frame'], "--overwrite"))
+                    _(
+                        "Frame <%s> already found. An existing frame can be overwritten by '%s' flag."
+                    )
+                    % (options["frame"], "--overwrite")
+                )
 
     # select givenframe
-    select_frame(monitor, options['frame'])
+    select_frame(monitor, options["frame"])
+
 
 if __name__ == "__main__":
-    if len(sys.argv) == 2 and sys.argv[1] == '--doctest':
+    if len(sys.argv) == 2 and sys.argv[1] == "--doctest":
         import doctest
+
         sys.exit(doctest.testmod().failed)
     options, flags = parser()
     sys.exit(main())

+ 9 - 7
scripts/d.out.file/d.out.file.py

@@ -7,9 +7,9 @@
 # PURPOSE:	Script for exporting content of monitor to graphic file
 # COPYRIGHT: (C) 2014-2015 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.
+# 		This program is free software under the GNU General
+# 		Public License (>=v2). Read the file COPYING that
+# 		comes with GRASS for details.
 #
 #############################################################################
 
@@ -45,16 +45,18 @@ from grass.script import core as gcore
 def main():
     options, flags = gcore.parser()
     gisenv = gcore.gisenv()
-    if 'MONITOR' in gisenv:
-        cmd_file = gcore.parse_command('d.mon', flags='g')['cmd']
-        dout_cmd = 'd.out.file'
+    if "MONITOR" in gisenv:
+        cmd_file = gcore.parse_command("d.mon", flags="g")["cmd"]
+        dout_cmd = "d.out.file"
         for param, val in options.items():
             if val:
                 dout_cmd += " {param}={val}".format(param=param, val=val)
         with open(cmd_file, "a") as file_:
             file_.write(dout_cmd)
     else:
-        gcore.fatal(_("No graphics device selected. Use d.mon to select graphics device."))
+        gcore.fatal(
+            _("No graphics device selected. Use d.mon to select graphics device.")
+        )
 
 
 if __name__ == "__main__":

+ 144 - 129
scripts/d.polar/d.polar.py

@@ -53,24 +53,24 @@ from grass.script import core as gcore
 
 
 def raster_map_required(name):
-    if not gcore.find_file(name, 'cell')['file']:
+    if not gcore.find_file(name, "cell")["file"]:
         gcore.fatal(_("Raster map <%s> not found") % name)
 
 
 def cleanup():
     try_remove(tmp)
-    for f in glob.glob(tmp + '_*'):
+    for f in glob.glob(tmp + "_*"):
         try_remove(f)
 
 
 def plot_xgraph():
-    newline = ['\n']
-    p = gcore.Popen(['xgraph'], stdin=gcore.PIPE)
+    newline = ["\n"]
+    p = gcore.Popen(["xgraph"], stdin=gcore.PIPE)
     for point in sine_cosine_replic + newline + outercircle + newline + vector:
         if isinstance(point, tuple):
             p.stdin.write(gcore.encode("%f %f\n" % point))
         else:
-            p.stdin.write(gcore.encode(point + '\n'))
+            p.stdin.write(gcore.encode(point + "\n"))
     p.stdin.close()
     p.wait()
 
@@ -78,7 +78,7 @@ def plot_xgraph():
 def plot_dgraph():
     # use d.info and d.frame to create a square frame in the center of the
     # window.
-    s = gcore.read_command('d.info', flags='d')
+    s = gcore.read_command("d.info", flags="d")
     f = s.split()
     frame_width = float(f[2])
     frame_height = float(f[3])
@@ -94,26 +94,32 @@ def plot_dgraph():
     fb = frame_height - dy
 
     tenv = os.environ.copy()
-    tenv['GRASS_RENDER_FRAME'] = '%f,%f,%f,%f' % (ft, fb, fl, fr)
+    tenv["GRASS_RENDER_FRAME"] = "%f,%f,%f,%f" % (ft, fb, fl, fr)
 
     # polyline calculations
     ring = 0.95
     scaleval = ring * totalvalidnumber / totalnumber
 
     sine_cosine_replic_normalized = [
-        ((scaleval * p[0] / maxradius + 1) * 50,
-         (scaleval * p[1] / maxradius + 1) * 50)
-        for p in sine_cosine_replic if isinstance(p, tuple)]
+        ((scaleval * p[0] / maxradius + 1) * 50, (scaleval * p[1] / maxradius + 1) * 50)
+        for p in sine_cosine_replic
+        if isinstance(p, tuple)
+    ]
 
     # create circle
-    circle = [(50 * (1 + ring * math.sin(math.radians(i))),
-               50 * (1 + ring * math.cos(math.radians(i))))
-              for i in range(0, 361)]
+    circle = [
+        (
+            50 * (1 + ring * math.sin(math.radians(i))),
+            50 * (1 + ring * math.cos(math.radians(i))),
+        )
+        for i in range(0, 361)
+    ]
 
     # trend vector
-    vect = [((scaleval * p[0] / maxradius + 1) * 50,
-             (scaleval * p[1] / maxradius + 1) * 50)
-            for p in vector[1:]]
+    vect = [
+        ((scaleval * p[0] / maxradius + 1) * 50, (scaleval * p[1] / maxradius + 1) * 50)
+        for p in vector[1:]
+    ]
 
     # Possible TODOs:
     # To fill data area with color, use BOTH d.graph's polyline and polygon commands.
@@ -121,61 +127,69 @@ def plot_dgraph():
     # (not a bug).
 
     # plot it!
-    lines = [
-        # draw circle
-        #   mandatory when drawing proportional to non-square frame
-        "color 180:255:180",
-        "polyline"] + circle + [
-        # draw axes
-        "color 180:180:180",
-        "width 0",
-        "move 0 50",
-        "draw 100 50",
-        "move 50 0",
-        "draw 50 100",
-
-        # draw the goods
-        "color red",
-        "width 0",
-        "polyline"] + sine_cosine_replic_normalized + [
-        # draw vector
-        "color blue",
-        "width 3",
-        "polyline"] + vect + [
-
-        # draw compass text
-        "color black",
-        "width 2",
-        "size 10 10",
-        "move 51 97",
-        "text N",
-        "move 51 1",
-        "text S",
-        "move 1 51",
-        "text W",
-        "move 97 51",
-        "text E",
-
-        # draw legend text
-        "width 0",
-        "size 10",
-        "color 0:180:0",
-        "move 0.5 96.5",
-        "text All data (incl. NULLs)",
-        "color red",
-        "move 0.5 93.5",
-        "text Real data angles",
-        "color blue",
-        "move 0.5 90.5",
-        "text Avg. direction"
-    ]
+    lines = (
+        [
+            # draw circle
+            #   mandatory when drawing proportional to non-square frame
+            "color 180:255:180",
+            "polyline",
+        ]
+        + circle
+        + [
+            # draw axes
+            "color 180:180:180",
+            "width 0",
+            "move 0 50",
+            "draw 100 50",
+            "move 50 0",
+            "draw 50 100",
+            # draw the goods
+            "color red",
+            "width 0",
+            "polyline",
+        ]
+        + sine_cosine_replic_normalized
+        + [
+            # draw vector
+            "color blue",
+            "width 3",
+            "polyline",
+        ]
+        + vect
+        + [
+            # draw compass text
+            "color black",
+            "width 2",
+            "size 10 10",
+            "move 51 97",
+            "text N",
+            "move 51 1",
+            "text S",
+            "move 1 51",
+            "text W",
+            "move 97 51",
+            "text E",
+            # draw legend text
+            "width 0",
+            "size 10",
+            "color 0:180:0",
+            "move 0.5 96.5",
+            "text All data (incl. NULLs)",
+            "color red",
+            "move 0.5 93.5",
+            "text Real data angles",
+            "color blue",
+            "move 0.5 90.5",
+            "text Avg. direction",
+        ]
+    )
 
-    p = gcore.feed_command('d.graph', env=tenv)
+    p = gcore.feed_command("d.graph", env=tenv)
     for point in lines:
         if isinstance(point, tuple):
             p.stdin.write(gcore.encode("%f %f\n" % point))
         else:
-            p.stdin.write(gcore.encode(point + '\n'))
+            p.stdin.write(gcore.encode(point + "\n"))
     p.stdin.close()
     p.wait()
 
@@ -226,18 +240,15 @@ def plot_eps(psout):
     averagedirectionlegendy = 1.85 * halfframe
 
     ##########
-    outf = open(psout, 'w')
+    outf = open(psout, "w")
 
-    prolog = os.path.join(
-        os.environ['GISBASE'],
-        'etc',
-        'd.polar',
-        'ps_defs.eps')
+    prolog = os.path.join(os.environ["GISBASE"], "etc", "d.polar", "ps_defs.eps")
     inf = open(prolog)
     shutil.copyfileobj(inf, outf)
     inf.close()
 
-    t = string.Template("""
+    t = string.Template(
+        """
 $EPSSCALE $EPSSCALE scale                           %% EPS-SCALE EPS-SCALE scale
 %%
 %% drawing axes
@@ -264,28 +275,28 @@ $DIAGRAMLINEWIDTH setlinewidth                          %% DIAGRAM-LINEWIDTH set
 newpath
                                         %% coordinates of rescaled, translated outer circle follow
                                         %% first point moveto, then lineto
-""")
+"""
+    )
     s = t.substitute(
         AXESLINEWIDTH=axeslinewidth,
         DIAGRAMFONTSIZE=diagramfontsize,
         DIAGRAMLINEWIDTH=diagramlinewidth,
         EPSSCALE=epsscale,
         HALFFRAME=halfframe,
-        HALFFRAME_2=halfframe_2
+        HALFFRAME_2=halfframe_2,
     )
     outf.write(s)
 
     sublength = len(outercircle) - 2
     (x, y) = outercircle[1]
-    outf.write(
-        "%.2f %.2f moveto\n" %
-        (x * scale + halfframe, y * scale + halfframe))
+    outf.write("%.2f %.2f moveto\n" % (x * scale + halfframe, y * scale + halfframe))
     for x, y in outercircle[2:]:
         outf.write(
-            "%.2f %.2f lineto\n" %
-            (x * scale + halfframe, y * scale + halfframe))
+            "%.2f %.2f lineto\n" % (x * scale + halfframe, y * scale + halfframe)
+        )
 
-    t = string.Template("""
+    t = string.Template(
+        """
 stroke
 
 %%
@@ -311,7 +322,8 @@ $DIAGRAMLINEWIDTH setlinewidth                          %% DIAGRAM-LINEWIDTH set
 newpath
                                         %% coordinates of rescaled, translated diagram follow
                                         %% first point moveto, then lineto
-""")
+"""
+    )
     s = t.substitute(
         AXESFONTSIZE=axesfontsize,
         DIAGRAMFONTSIZE=diagramfontsize,
@@ -327,21 +339,20 @@ newpath
         SOUTHYSHIFT=southyshift,
         WESTJUSTIFICATION=westjustification,
         WESTXSHIFT=westxshift,
-        WESTYSHIFT=westyshift
+        WESTYSHIFT=westyshift,
     )
     outf.write(s)
 
     sublength = len(sine_cosine_replic) - 2
     (x, y) = sine_cosine_replic[1]
-    outf.write(
-        "%.2f %.2f moveto\n" %
-        (x * scale + halfframe, y * scale + halfframe))
+    outf.write("%.2f %.2f moveto\n" % (x * scale + halfframe, y * scale + halfframe))
     for x, y in sine_cosine_replic[2:]:
         outf.write(
-            "%.2f %.2f lineto\n" %
-            (x * scale + halfframe, y * scale + halfframe))
+            "%.2f %.2f lineto\n" % (x * scale + halfframe, y * scale + halfframe)
+        )
 
-    t = string.Template("""
+    t = string.Template(
+        """
 stroke
 %%
 %% drawing average direction
@@ -353,21 +364,21 @@ $DIAGRAMLINEWIDTH setlinewidth                          %% DIAGRAM-LINEWIDTH set
 newpath
                                         %% coordinates of rescaled, translated average direction follow
                                         %% first point moveto, second lineto
-""")
+"""
+    )
     s = t.substitute(DIAGRAMLINEWIDTH=diagramlinewidth)
     outf.write(s)
 
     sublength = len(vector) - 2
     (x, y) = vector[1]
-    outf.write(
-        "%.2f %.2f moveto\n" %
-        (x * scale + halfframe, y * scale + halfframe))
+    outf.write("%.2f %.2f moveto\n" % (x * scale + halfframe, y * scale + halfframe))
     for x, y in vector[2:]:
         outf.write(
-            "%.2f %.2f lineto\n" %
-            (x * scale + halfframe, y * scale + halfframe))
+            "%.2f %.2f lineto\n" % (x * scale + halfframe, y * scale + halfframe)
+        )
 
-    t = string.Template("""
+    t = string.Template(
+        """
 stroke
 
 %%
@@ -385,7 +396,8 @@ col4                                    %% colDIAGRAM-COLOR
 col1                                    %% colAVERAGE-DIRECTION-COLOR
 %% Line below: (AVERAGE-DIRECTION-STRING) LEGENDS-X AVERAGE-DIRECTION-LEGEND-Y 4 just-string
 ($AVERAGEDIRECTIONSTRING) $LEGENDSX $AVERAGEDIRECTIONLEGENDY 4 just-string
-""")
+"""
+    )
     s = t.substitute(
         ALLDATALEGENDY=alldatalegendy,
         ALLDATASTRING=alldatastring,
@@ -393,7 +405,7 @@ col1                                    %% colAVERAGE-DIRECTION-COLOR
         AVERAGEDIRECTIONSTRING=averagedirectionstring,
         LEGENDSX=legendsx,
         REALDATALEGENDY=realdatalegendy,
-        REALDATASTRING=realdatastring
+        REALDATASTRING=realdatastring,
     )
     outf.write(s)
 
@@ -407,10 +419,10 @@ def main():
     global sine_cosine_replic, outercircle, vector
     global totalvalidnumber, totalnumber, maxradius
 
-    map = options['map']
-    undef = options['undef']
-    eps = options['output']
-    xgraph = flags['x']
+    map = options["map"]
+    undef = options["undef"]
+    eps = options["output"]
+    xgraph = flags["x"]
 
     tmp = gcore.tempfile()
 
@@ -419,28 +431,35 @@ def main():
 
     if eps:
         if os.sep in eps and not os.path.exists(os.path.dirname(eps)):
-            gcore.fatal(_("EPS output file path <{}>, doesn't exists. "
-                          "Set new output file path.".format(eps)))
+            gcore.fatal(
+                _(
+                    "EPS output file path <{}>, doesn't exists. "
+                    "Set new output file path.".format(eps)
+                )
+            )
         else:
-            eps = basename(eps, 'eps') + '.eps'
-        if not eps.endswith('.eps'):
-            eps += '.eps'
-        if os.path.exists(eps) and not os.getenv('GRASS_OVERWRITE'):
-            gcore.fatal(_("option <output>: <{}> exists. To overwrite, "
-                          "use the --overwrite flag.".format(eps)))
+            eps = basename(eps, "eps") + ".eps"
+        if not eps.endswith(".eps"):
+            eps += ".eps"
+        if os.path.exists(eps) and not os.getenv("GRASS_OVERWRITE"):
+            gcore.fatal(
+                _(
+                    "option <output>: <{}> exists. To overwrite, "
+                    "use the --overwrite flag.".format(eps)
+                )
+            )
 
     # check if we have xgraph (if no EPS output requested)
-    if xgraph and not gcore.find_program('xgraph'):
-        gcore.fatal(
-            _("xgraph required, please install first (www.xgraph.org)"))
+    if xgraph and not gcore.find_program("xgraph"):
+        gcore.fatal(_("xgraph required, please install first (www.xgraph.org)"))
 
     raster_map_required(map)
 
     #################################
     # this file contains everything:
     rawfile = tmp + "_raw"
-    rawf = open(rawfile, 'w')
-    gcore.run_command('r.stats', flags='1', input=map, stdout=rawf)
+    rawf = open(rawfile, "w")
+    gcore.run_command("r.stats", flags="1", input=map, stdout=rawf)
     rawf.close()
 
     rawf = open(rawfile)
@@ -449,8 +468,7 @@ def main():
         totalnumber += 1
     rawf.close()
 
-    gcore.message(
-        _("Calculating statistics for polar diagram... (be patient)"))
+    gcore.message(_("Calculating statistics for polar diagram... (be patient)"))
 
     # wipe out NULL data and undef data if defined by user
     # - generate degree binned to integer, eliminate NO DATA (NULL):
@@ -461,8 +479,8 @@ def main():
     sumsin = 0
     freq = {}
     for line in rawf:
-        line = line.rstrip('\r\n')
-        if line in ['*', undef]:
+        line = line.rstrip("\r\n")
+        if line in ["*", undef]:
             continue
         nvals += 1
         x = float(line)
@@ -528,17 +546,14 @@ def main():
 
     gcore.message(_("Average vector:"))
     gcore.message(
-        _("direction: %.1f degrees CCW from East") %
-        math.degrees(
-            math.atan2(
-                unitvector[1],
-                unitvector[0])))
+        _("direction: %.1f degrees CCW from East")
+        % math.degrees(math.atan2(unitvector[1], unitvector[0]))
+    )
     gcore.message(
-        _("magnitude: %.1f percent of fullscale") %
-        (100 *
-         math.hypot(
-             unitvector[0],
-             unitvector[1])))
+        _("magnitude: %.1f percent of fullscale")
+        % (100 * math.hypot(unitvector[0], unitvector[1]))
+    )
+
 
 if __name__ == "__main__":
     options, flags = gcore.parser()

+ 7 - 7
scripts/d.polar/testsuite/test_d_polar.py

@@ -14,30 +14,30 @@ import os
 class TestDPolar(TestCase):
     """Test d.polar script"""
 
-    mapName = 'aspect'
-    epsFile = 'polar.eps'
+    mapName = "aspect"
+    epsFile = "polar.eps"
 
     @classmethod
     def setUpClass(cls):
         """Set region."""
         cls.use_temp_region()
-        cls.runModule('g.region', raster=cls.mapName, flags='p')
+        cls.runModule("g.region", raster=cls.mapName, flags="p")
 
     @classmethod
     def tearDownClass(cls):
         """Remove temporary region"""
         cls.del_temp_region()
 
-        if (os.path.isfile(cls.epsFile)):
+        if os.path.isfile(cls.epsFile):
             os.remove(cls.epsFile)
 
     def test_d_polar(self):
         """EPS file test"""
-        module = SimpleModule('d.polar', map=self.mapName,
-                              output=self.epsFile)
+        module = SimpleModule("d.polar", map=self.mapName, output=self.epsFile)
         self.assertModule(module)
 
         self.assertFileExists(filename=self.epsFile)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 117 - 128
scripts/d.rast.edit/d.rast.edit.py

@@ -80,6 +80,7 @@ import atexit
 import grass.script as grass
 
 from grass.script.setup import set_gui_path
+
 set_gui_path()
 
 try:
@@ -89,38 +90,38 @@ except ImportError:
     if __name__ == "__main__":
         if len(sys.argv) == 2:
             arg = sys.argv[1]
-            if arg[0:2] == '--' or arg in ["help", "-help"]:
+            if arg[0:2] == "--" or arg in ["help", "-help"]:
                 grass.parser()
     # Either we didn't call g.parser, or it returned
     # At this point, there's nothing to be done except re-raise the exception
     raise
 
 wind_keys = {
-    'north': ('n', float),
-    'south': ('s', float),
-    'east': ('e', float),
-    'west': ('w', float),
-    'nsres': ('nsres', float),
-    'ewres': ('ewres', float),
-    'rows': ('rows', int),
-    'cols': ('cols', int),
+    "north": ("n", float),
+    "south": ("s", float),
+    "east": ("e", float),
+    "west": ("w", float),
+    "nsres": ("nsres", float),
+    "ewres": ("ewres", float),
+    "rows": ("rows", int),
+    "cols": ("cols", int),
 }
 
-gray12_bits = b'\x00\x00\x22\x22\x00\x00\x88\x88\x00\x00\x22\x22\x00\x00\x88\x88\x00\x00\x22\x22\x00\x00\x88\x88\x00\x00\x22\x22\x00\x00\x88\x88'
+gray12_bits = b"\x00\x00\x22\x22\x00\x00\x88\x88\x00\x00\x22\x22\x00\x00\x88\x88\x00\x00\x22\x22\x00\x00\x88\x88\x00\x00\x22\x22\x00\x00\x88\x88"
 
 
 def run(cmd, **kwargs):
     grass.run_command(cmd, quiet=True, **kwargs)
 
+
 def wxGUI():
     class OverviewCanvas(wx.ScrolledWindow):
-
         def __init__(self, app, parent):
             wx.ScrolledWindow.__init__(self, parent)
             self.app = app
 
-            self.width = app.total['cols']
-            self.height = app.total['rows']
+            self.width = app.total["cols"]
+            self.height = app.total["rows"]
 
             self.SetVirtualSize((self.width, self.height))
             self.SetScrollRate(1, 1)
@@ -130,7 +131,7 @@ def wxGUI():
             self.Bind(wx.EVT_LEFT_UP, self.OnMouse)
             self.Bind(wx.EVT_PAINT, self.OnPaint)
 
-            run('r.out.ppm', input=app.inmap, output=app.tempfile)
+            run("r.out.ppm", input=app.inmap, output=app.tempfile)
 
             self.image = wx.Bitmap(wx.Image(app.tempfile))
             grass.try_remove(app.tempfile)
@@ -151,8 +152,8 @@ def wxGUI():
             dc.Blit(0, 0, self.width, self.height, src, 0, 0)
             src.SelectObjectAsSource(wx.NullBitmap)
 
-            dc.SetPen(wx.Pen('red', style=wx.LONG_DASH))
-            dc.SetBrush(wx.Brush('black', style=wx.TRANSPARENT))
+            dc.SetPen(wx.Pen("red", style=wx.LONG_DASH))
+            dc.SetBrush(wx.Brush("black", style=wx.TRANSPARENT))
             dc.DrawRectangle(x0, y0, dx, dy)
             dc.SetBrush(wx.NullBrush)
             dc.SetPen(wx.NullPen)
@@ -173,15 +174,9 @@ def wxGUI():
             self.app.force_window()
             self.Refresh()
 
-
     class OverviewWindow(wx.Frame):
-
         def __init__(self, app):
-            wx.Frame.__init__(
-                self,
-                None,
-                title="d.rast.edit overview (%s)" %
-                app.inmap)
+            wx.Frame.__init__(self, None, title="d.rast.edit overview (%s)" % app.inmap)
             self.app = app
 
             self.canvas = OverviewCanvas(app, parent=self)
@@ -191,9 +186,7 @@ def wxGUI():
         def OnClose(self, ev):
             self.app.finalize()
 
-
     class Canvas(wx.ScrolledWindow):
-
         def __init__(self, app, parent):
             wx.ScrolledWindow.__init__(self, parent)
             self.app = app
@@ -244,18 +237,18 @@ def wxGUI():
 
             val = self.app.values[r][c]
             if val is None:
-                fill = 'black'
+                fill = "black"
                 stipple = self.gray12
             else:
                 fill = self.app.get_color(val)
                 stipple = None
 
             if r == self.row and c == self.col:
-                outline = 'red'
+                outline = "red"
             elif self.app.changed[r][c]:
-                outline = 'white'
+                outline = "white"
             else:
-                outline = 'black'
+                outline = "black"
 
             dc.SetPen(wx.Pen(outline))
 
@@ -278,7 +271,7 @@ def wxGUI():
             if not self.app.angles:
                 return
 
-            if self.app.angles[r][c] == '*':
+            if self.app.angles[r][c] == "*":
                 return
 
             cx = (x0 + x1) / 2
@@ -298,9 +291,9 @@ def wxGUI():
 
             r, g, b, a = wx.Colour(fill).Get()
             if r + g + b > 384:
-                line = 'black'
+                line = "black"
             else:
-                line = 'white'
+                line = "white"
 
             dc.SetPen(wx.Pen(line))
             dc.DrawLine(x0, y0, x1, y1)
@@ -361,9 +354,7 @@ def wxGUI():
             (x, y) = self.CalcScrolledPosition(x, y)
             self.RefreshRect((x, y, self.size, self.size))
 
-
     class ColorPanel(Panel):
-
         def __init__(self, **kwargs):
             Panel.__init__(self, **kwargs)
             self.stipple = wx.Bitmap(bits=gray12_bits, width=16, height=16)
@@ -380,23 +371,21 @@ def wxGUI():
             if not dc:
                 dc = ClientDC(self)
 
-            brush = wx.Brush('black', style=wx.STIPPLE)
+            brush = wx.Brush("black", style=wx.STIPPLE)
             brush.SetStipple(self.stipple)
             dc.SetBackground(brush)
             dc.Clear()
             dc.SetBackground(wx.NullBrush)
 
         def SetNullBackgroundColour(self):
-            Panel.SetBackgroundColour(self, 'gray')
+            Panel.SetBackgroundColour(self, "gray")
             self.null_bg = True
 
         def SetBackgroundColour(self, color):
             Panel.SetBackgroundColour(self, color)
             self.null_bg = False
 
-
     class MainWindow(wx.Frame):
-
         def __init__(self, app):
             wx.Frame.__init__(self, None, title="d.rast.edit (%s)" % app.inmap)
             self.app = app
@@ -420,14 +409,14 @@ def wxGUI():
 
             tools = wx.BoxSizer(wx.HORIZONTAL)
 
-            l = wx.StaticText(parent=self, label='New Value:')
+            l = wx.StaticText(parent=self, label="New Value:")
             tools.Add(l, flag=wx.ALIGN_CENTER_VERTICAL)
             tools.AddSpacer(5)
 
             self.newval = wx.TextCtrl(parent=self, style=wx.TE_PROCESS_ENTER)
             tools.Add(self.newval, flag=wx.ALIGN_CENTER_VERTICAL)
 
-            l = wx.StaticText(parent=self, label='Color:')
+            l = wx.StaticText(parent=self, label="Color:")
             tools.Add(l, flag=wx.ALIGN_CENTER_VERTICAL)
             tools.AddSpacer(5)
 
@@ -456,30 +445,28 @@ def wxGUI():
 
         def OnReturn(self, ev):
             self.app.brush = self.newval.GetValue()
-            if self.app.brush != '*' and self.app.brush.strip('0123456789') != '':
-                self.app.brush = '*'
+            if self.app.brush != "*" and self.app.brush.strip("0123456789") != "":
+                self.app.brush = "*"
             self.brush_update()
 
         def update_status(self):
-            for i, key in enumerate(['row', 'col', 'x', 'y', 'value', 'aspect']):
+            for i, key in enumerate(["row", "col", "x", "y", "value", "aspect"]):
                 s = "%s%s: %s" % (key[0].upper(), key[1:], self.app.status[key])
                 self.status.SetStatusText(s, i)
 
         def clear_status(self):
             for key in self.status:
-                self.status[key] = ''
+                self.status[key] = ""
 
         def brush_update(self):
             self.newval.ChangeValue(self.app.brush)
-            if self.app.brush == '*':
+            if self.app.brush == "*":
                 self.color.SetNullBackgroundColour()
             else:
                 self.color.SetBackgroundColour(self.app.get_color(self.app.brush))
             self.color.Refresh()
 
-
     class Application(wx.App):
-
         def __init__(self, options):
             self.options = options
             wx.App.__init__(self)
@@ -487,31 +474,31 @@ def wxGUI():
         def initialize(self):
             grass.use_temp_region()
 
-            run('g.region', raster=self.inmap)
+            run("g.region", raster=self.inmap)
 
             reg = grass.region()
             for k, f in wind_keys.values():
                 self.total[k] = (f)(reg[k])
 
-            if self.cols > self.total['cols']:
-                self.cols = self.total['cols']
-            if self.rows > self.total['rows']:
-                self.rows = self.total['rows']
+            if self.cols > self.total["cols"]:
+                self.cols = self.total["cols"]
+            if self.rows > self.total["rows"]:
+                self.rows = self.total["rows"]
 
             tempbase = grass.tempfile()
             grass.try_remove(tempbase)
 
-            self.tempfile = tempbase + '.ppm'
-            self.tempmap = 'tmp.d.rast.edit'
+            self.tempfile = tempbase + ".ppm"
+            self.tempmap = "tmp.d.rast.edit"
 
             atexit.register(self.cleanup)
 
-            run('g.copy', raster=(self.inmap, self.outmap), overwrite=True)
-            run('r.colors', map=self.outmap, rast=self.inmap)
+            run("g.copy", raster=(self.inmap, self.outmap), overwrite=True)
+            run("r.colors", map=self.outmap, rast=self.inmap)
 
         def cleanup(self):
             grass.try_remove(self.tempfile)
-            run('g.remove', flags='f', type='raster', name=self.tempmap)
+            run("g.remove", flags="f", type="raster", name=self.tempmap)
 
         def finalize(self):
             self.save_map()
@@ -519,48 +506,46 @@ def wxGUI():
 
         def save_map(self):
             p = grass.feed_command(
-                'r.in.ascii',
-                input='-',
-                output=self.tempmap,
-                quiet=True,
-                overwrite=True)
+                "r.in.ascii", input="-", output=self.tempmap, quiet=True, overwrite=True
+            )
             outf = p.stdin
-            outf.write(grass.encode("north: %f\n" % self.wind['n']))
-            outf.write(grass.encode("south: %f\n" % self.wind['s']))
-            outf.write(grass.encode("east: %f\n" % self.wind['e']))
-            outf.write(grass.encode("west: %f\n" % self.wind['w']))
-            outf.write(grass.encode("rows: %d\n" % self.wind['rows']))
-            outf.write(grass.encode("cols: %d\n" % self.wind['cols']))
+            outf.write(grass.encode("north: %f\n" % self.wind["n"]))
+            outf.write(grass.encode("south: %f\n" % self.wind["s"]))
+            outf.write(grass.encode("east: %f\n" % self.wind["e"]))
+            outf.write(grass.encode("west: %f\n" % self.wind["w"]))
+            outf.write(grass.encode("rows: %d\n" % self.wind["rows"]))
+            outf.write(grass.encode("cols: %d\n" % self.wind["cols"]))
             outf.write(grass.encode("null: *\n"))
 
-            for row in range(self.wind['rows']):
-                for col in range(self.wind['cols']):
+            for row in range(self.wind["rows"]):
+                for col in range(self.wind["cols"]):
                     if col > 0:
                         outf.write(grass.encode(" "))
                     val = self.values[row][col]
                     if val and self.changed[row][col]:
                         outf.write(grass.encode("%s" % val))
                     else:
-                        outf.write(grass.encode('*'))
+                        outf.write(grass.encode("*"))
                 outf.write(grass.encode("\n"))
 
             outf.close()
             p.wait()
 
-            run('g.region', raster=self.inmap)
-            run('r.patch',
-                input=(self.tempmap,
-                       self.outmap),
+            run("g.region", raster=self.inmap)
+            run(
+                "r.patch",
+                input=(self.tempmap, self.outmap),
                 output=self.outmap,
-                overwrite=True)
-            run('r.colors', map=self.outmap, rast=self.inmap)
-            run('g.remove', flags='f', type='raster', name=self.tempmap)
+                overwrite=True,
+            )
+            run("r.colors", map=self.outmap, rast=self.inmap)
+            run("g.remove", flags="f", type="raster", name=self.tempmap)
 
         def read_header(self, infile):
             wind = {}
             for i in range(6):
-                line = grass.decode(infile.readline()).rstrip('\r\n')
-                f = line.split(':')
+                line = grass.decode(infile.readline()).rstrip("\r\n")
+                f = line.split(":")
                 key = f[0]
                 val = f[1].strip()
                 (k, f) = wind_keys[key]
@@ -569,15 +554,15 @@ def wxGUI():
 
         def read_data(self, infile):
             values = []
-            for row in range(self.wind['rows']):
-                line = grass.decode(infile.readline()).rstrip('\r\n')
+            for row in range(self.wind["rows"]):
+                line = grass.decode(infile.readline()).rstrip("\r\n")
                 values.append(line.split())
             return values
 
         def load_map(self):
-            run('g.region', **self.wind)
+            run("g.region", **self.wind)
 
-            p = grass.pipe_command('r.out.ascii', input=self.inmap, quiet=True)
+            p = grass.pipe_command("r.out.ascii", input=self.inmap, quiet=True)
             self.wind = self.read_header(p.stdout)
             self.values = self.read_data(p.stdout)
             self.changed = [[False for c in row] for row in self.values]
@@ -585,12 +570,12 @@ def wxGUI():
 
             self.clear_changes()
 
-            run('r.out.ppm', input=self.inmap, output=self.tempfile)
+            run("r.out.ppm", input=self.inmap, output=self.tempfile)
             colorimg = wx.Image(self.tempfile)
             grass.try_remove(self.tempfile)
 
-            for row in range(self.wind['rows']):
-                for col in range(self.wind['cols']):
+            for row in range(self.wind["rows"]):
+                for col in range(self.wind["cols"]):
                     val = self.values[row][col]
                     if val in self.colors:
                         continue
@@ -606,14 +591,14 @@ def wxGUI():
             if not self.aspect:
                 return
 
-            p = grass.pipe_command('r.out.ascii', input=self.aspect, quiet=True)
+            p = grass.pipe_command("r.out.ascii", input=self.aspect, quiet=True)
             self.read_header(p.stdout)
             self.angles = self.read_data(p.stdout)
             p.wait()
 
         def clear_changes(self):
-            for row in range(self.wind['rows']):
-                for col in range(self.wind['cols']):
+            for row in range(self.wind["rows"]):
+                for col in range(self.wind["cols"]):
                     self.changed[row][col] = 0
 
         def update_window(self):
@@ -622,12 +607,12 @@ def wxGUI():
             x1 = x0 + self.cols
             y1 = y0 + self.rows
 
-            self.wind['n'] = self.total['n'] - y0 * self.total['nsres']
-            self.wind['s'] = self.total['n'] - y1 * self.total['nsres']
-            self.wind['w'] = self.total['w'] + x0 * self.total['ewres']
-            self.wind['e'] = self.total['w'] + x1 * self.total['ewres']
-            self.wind['rows'] = self.rows
-            self.wind['cols'] = self.cols
+            self.wind["n"] = self.total["n"] - y0 * self.total["nsres"]
+            self.wind["s"] = self.total["n"] - y1 * self.total["nsres"]
+            self.wind["w"] = self.total["w"] + x0 * self.total["ewres"]
+            self.wind["e"] = self.total["w"] + x1 * self.total["ewres"]
+            self.wind["rows"] = self.rows
+            self.wind["cols"] = self.cols
 
         def change_window(self):
             wait = wx.BusyCursor()
@@ -641,30 +626,34 @@ def wxGUI():
         def force_window(self):
             if self.origin_x < 0:
                 self.origin_x = 0
-            if self.origin_x > self.total['cols'] - self.cols:
-                self.origin_x = self.total['cols'] - self.cols
+            if self.origin_x > self.total["cols"] - self.cols:
+                self.origin_x = self.total["cols"] - self.cols
             if self.origin_y < 0:
                 self.origin_y = 0
-            if self.origin_y > self.total['rows'] - self.rows:
-                self.origin_y = self.total['rows'] - self.rows
+            if self.origin_y > self.total["rows"] - self.rows:
+                self.origin_y = self.total["rows"] - self.rows
 
         def update_status(self, row, col):
-            self.status['row'] = row
-            self.status['col'] = col
-            self.status['x'] = self.wind[
-                'e'] + (col + 0.5) * (self.wind['e'] - self.wind['w']) / self.wind['cols']
-            self.status['y'] = self.wind[
-                'n'] - (row + 0.5) * (self.wind['n'] - self.wind['s']) / self.wind['rows']
-            self.status['value'] = self.values[row][col]
+            self.status["row"] = row
+            self.status["col"] = col
+            self.status["x"] = (
+                self.wind["e"]
+                + (col + 0.5) * (self.wind["e"] - self.wind["w"]) / self.wind["cols"]
+            )
+            self.status["y"] = (
+                self.wind["n"]
+                - (row + 0.5) * (self.wind["n"] - self.wind["s"]) / self.wind["rows"]
+            )
+            self.status["value"] = self.values[row][col]
             if self.angles:
-                self.status['aspect'] = self.angles[row][col]
+                self.status["aspect"] = self.angles[row][col]
 
         def force_color(self, val):
-            run('g.region', rows=1, cols=1)
-            run('r.mapcalc', expression="%s = %d" % (self.tempmap, val))
-            run('r.colors', map=self.tempmap, rast=self.inmap)
-            run('r.out.ppm', input=self.tempmap, out=self.tempfile)
-            run('g.remove', flags='f', type='raster', name=self.tempmap)
+            run("g.region", rows=1, cols=1)
+            run("r.mapcalc", expression="%s = %d" % (self.tempmap, val))
+            run("r.colors", map=self.tempmap, rast=self.inmap)
+            run("r.out.ppm", input=self.tempmap, out=self.tempfile)
+            run("g.remove", flags="f", type="raster", name=self.tempmap)
 
             tempimg = wx.Image(self.tempfile)
             grass.try_remove(self.tempfile)
@@ -694,29 +683,29 @@ def wxGUI():
             self.overview.Show()
 
         def OnInit(self):
-            self.outmap = self.options['output']
-            self.inmap = self.options['input']
-            self.aspect = self.options['aspect']
-            self.width = int(self.options['width'])
-            self.height = int(self.options['height'])
-            self.size = int(self.options['size'])
-            self.rows = int(self.options['rows'])
-            self.cols = int(self.options['cols'])
+            self.outmap = self.options["output"]
+            self.inmap = self.options["input"]
+            self.aspect = self.options["aspect"]
+            self.width = int(self.options["width"])
+            self.height = int(self.options["height"])
+            self.size = int(self.options["size"])
+            self.rows = int(self.options["rows"])
+            self.cols = int(self.options["cols"])
 
             self.status = {
-                'row': '',
-                'col': '',
-                'x': '',
-                'y': '',
-                'value': '',
-                'aspect': ''
+                "row": "",
+                "col": "",
+                "x": "",
+                "y": "",
+                "value": "",
+                "aspect": "",
             }
 
             self.values = None
             self.changed = None
             self.angles = None
             self.colors = {}
-            self.brush = '*'
+            self.brush = "*"
             self.origin_x = 0
             self.origin_y = 0
             self.wind = {}

+ 34 - 34
scripts/d.rast.leg/d.rast.leg.py

@@ -78,51 +78,52 @@ def make_frame(f, b, t, l, r):
     rb = fb + b * (ft - fb)
     rl = fl + l * (fr - fl)
     rr = fl + r * (fr - fl)
-    s = '%f,%f,%f,%f' % (rt, rb, rl, rr)
-    os.environ['GRASS_RENDER_FRAME'] = s
+    s = "%f,%f,%f,%f" % (rt, rb, rl, rr)
+    os.environ["GRASS_RENDER_FRAME"] = s
 
 
 def main():
-    map = options['map']
-    nlines = options['lines']
-    rast = options['raster']
-    omit = flags['n']
-    flip = flags['f']
-    smooth = flags['s']
+    map = options["map"]
+    nlines = options["lines"]
+    rast = options["raster"]
+    omit = flags["n"]
+    flip = flags["f"]
+    smooth = flags["s"]
 
     # for -n flag of d.legend
-    if not grass.find_file(map)['file']:
+    if not grass.find_file(map)["file"]:
         grass.fatal(_("Raster map <%s> not found") % map)
 
     # for rast=
-    if rast and not grass.find_file(rast)['file']:
+    if rast and not grass.find_file(rast)["file"]:
         grass.fatal(_("Raster map <%s> not found") % rast)
 
-    s = grass.read_command('d.info', flags='f')
+    s = grass.read_command("d.info", flags="f")
     if not s:
         sys.exit(1)
 
     # fixes trunk r64459
-    s = s.split(':')[1]
+    s = s.split(":")[1]
     f = tuple([float(x) for x in s.split()])
 
-    grass.run_command('d.erase')
-    os.environ['GRASS_RENDER_FILE_READ'] = 'TRUE'
+    grass.run_command("d.erase")
+    os.environ["GRASS_RENDER_FILE_READ"] = "TRUE"
 
     # draw title
 
     # set vertical divide at 65 instead of 80 if real labels in cats/ file??
     make_frame(f, 90, 100, 70, 100)
     # use map name without mapset suffix
-    mapname = map.split('@')[0]
-    grass.run_command('d.text', color='black', size=5, at='5,97', align='cl',
-                      text=mapname)
+    mapname = map.split("@")[0]
+    grass.run_command(
+        "d.text", color="black", size=5, at="5,97", align="cl", text=mapname
+    )
 
     # draw legend
 
     # set legend vertical position and size based on number of categories
-    cats = grass.read_command('r.describe', map=map, flags='1n')
-    ncats = len(cats.strip().split('\n'))
+    cats = grass.read_command("r.describe", map=map, flags="1n")
+    ncats = len(cats.strip().split("\n"))
 
     # Only need to adjust legend size if number of categories is between 1 and 10
     if ncats < 2:
@@ -130,7 +131,7 @@ def main():
     if ncats > 10:
         ncats = 10
 
-    VSpacing = (100 - (ncats * 10) + 10)
+    VSpacing = 100 - (ncats * 10) + 10
 
     if not nlines:
         nlines = None
@@ -141,33 +142,32 @@ def main():
         lmap = map
 
     kv = grass.raster_info(map=lmap)
-    if kv['datatype'] == 'CELL':
+    if kv["datatype"] == "CELL":
         leg_at = None
     else:
-        leg_at = '%f,95,5,10' % VSpacing
+        leg_at = "%f,95,5,10" % VSpacing
 
-# checking for histogram causes more problems than it solves
-#    histfiledir = grass.find_file(lmap, 'cell_misc')['file']
-#    has_hist = os.path.isfile(os.path.join(histfiledir, 'histogram'))
+    # checking for histogram causes more problems than it solves
+    #    histfiledir = grass.find_file(lmap, 'cell_misc')['file']
+    #    has_hist = os.path.isfile(os.path.join(histfiledir, 'histogram'))
 
-    lflags = ''
+    lflags = ""
     if flip:
-        lflags += 'f'
+        lflags += "f"
     if omit:
-        lflags += 'n'
+        lflags += "n"
     if smooth:
-        lflags += 's'
+        lflags += "s"
 
-#    if has_hist or omit:
-#        lflags += 'n'
+    #    if has_hist or omit:
+    #        lflags += 'n'
 
     make_frame(f, 0, 90, 70, 100)
-    grass.run_command('d.legend', flags=lflags, raster=lmap, lines=nlines,
-                      at=leg_at)
+    grass.run_command("d.legend", flags=lflags, raster=lmap, lines=nlines, at=leg_at)
 
     # draw map
     make_frame(f, 0, 100, 0, 70)
-    grass.run_command('d.rast', map=map)
+    grass.run_command("d.rast", map=map)
 
 
 if __name__ == "__main__":

+ 18 - 13
scripts/d.redraw/d.redraw.py

@@ -7,9 +7,9 @@
 # PURPOSE:	Redraws the content of currently selected monitor
 # COPYRIGHT:	(C) 2011-2015 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.
+# 		This program is free software under the GNU General
+# 		Public License (>=v2). Read the file COPYING that
+# 		comes with GRASS for details.
 #
 #############################################################################
 
@@ -28,27 +28,30 @@ from grass.script.utils import split
 
 
 def main():
-    mon = grass.gisenv().get('MONITOR', None)
+    mon = grass.gisenv().get("MONITOR", None)
     if not mon:
-        grass.fatal(_("No graphics device selected. Use d.mon to select graphics device."))
+        grass.fatal(
+            _("No graphics device selected. Use d.mon to select graphics device.")
+        )
 
-    monCmd = grass.parse_command('d.mon', flags='g').get('cmd', None)
+    monCmd = grass.parse_command("d.mon", flags="g").get("cmd", None)
     if not monCmd or not os.path.isfile(monCmd):
         grass.fatal(_("Unable to open file '%s'") % monCmd)
 
     try:
-        fd = open(monCmd, 'r')
+        fd = open(monCmd, "r")
         cmdList = fd.readlines()
 
-        grass.run_command('d.erase')
+        grass.run_command("d.erase")
 
         for cmd in cmdList:
-            if cmd.startswith('#'):
+            if cmd.startswith("#"):
                 continue
             grass.call(split(cmd))
     except IOError as e:
-        grass.fatal(_("Unable to open file '%s' for reading. Details: %s") %
-                    (monCmd, e))
+        grass.fatal(
+            _("Unable to open file '%s' for reading. Details: %s") % (monCmd, e)
+        )
 
     fd.close()
 
@@ -57,11 +60,13 @@ def main():
         fd = open(monCmd, "w")
         fd.writelines(cmdList)
     except IOError as e:
-        grass.fatal(_("Unable to open file '%s' for writing. Details: %s") %
-                    (monCmd, e))
+        grass.fatal(
+            _("Unable to open file '%s' for writing. Details: %s") % (monCmd, e)
+        )
 
     return 0
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     sys.exit(main())

+ 7 - 6
scripts/d.shade/d.shade.py

@@ -47,15 +47,16 @@ from grass.exceptions import CalledModuleError
 def main():
     options, unused = gcore.parser()
 
-    drape_map = options['color']
-    relief_map = options['shade']
-    brighten = options['brighten']
+    drape_map = options["color"]
+    relief_map = options["shade"]
+    brighten = options["brighten"]
 
     try:
-        gcore.run_command('d.his', hue=drape_map, intensity=relief_map,
-                          brighten=brighten)
+        gcore.run_command(
+            "d.his", hue=drape_map, intensity=relief_map, brighten=brighten
+        )
     except CalledModuleError:
-        gcore.fatal(_("Module %s failed. Check the above error messages.") % 'd.his')
+        gcore.fatal(_("Module %s failed. Check the above error messages.") % "d.his")
 
 
 if __name__ == "__main__":

+ 10 - 8
scripts/d.to.rast/d.to.rast.py

@@ -7,9 +7,9 @@
 # PURPOSE:	 Script for exporting content of monitor to raster map
 # COPYRIGHT: (C) 2014-2015 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.
+# 		This program is free software under the GNU General
+# 		Public License (>=v2). Read the file COPYING that
+# 		comes with GRASS for details.
 #
 #############################################################################
 
@@ -29,18 +29,20 @@ from grass.script import core as gcore
 def main():
     options, flags = gcore.parser()
     gisenv = gcore.gisenv()
-    if 'MONITOR' in gisenv:
-        cmd_file = gcore.parse_command('d.mon', flags='g')['cmd']
-        d_cmd = 'd.to.rast'
+    if "MONITOR" in gisenv:
+        cmd_file = gcore.parse_command("d.mon", flags="g")["cmd"]
+        d_cmd = "d.to.rast"
         for param, val in options.items():
             if val:
                 d_cmd += " {param}={val}".format(param=param, val=val)
         if gcore.overwrite():
-            d_cmd += ' --overwrite'
+            d_cmd += " --overwrite"
         with open(cmd_file, "a") as file_:
             file_.write(d_cmd)
     else:
-        gcore.fatal(_("No graphics device selected. Use d.mon to select graphics device."))
+        gcore.fatal(
+            _("No graphics device selected. Use d.mon to select graphics device.")
+        )
 
 
 if __name__ == "__main__":

+ 9 - 7
scripts/d.what.rast/d.what.rast.py

@@ -7,9 +7,9 @@
 # PURPOSE:   Script for querying raster maps in d.mon
 # COPYRIGHT: (C) 2014-2015 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.
+# 		This program is free software under the GNU General
+# 		Public License (>=v2). Read the file COPYING that
+# 		comes with GRASS for details.
 #
 #############################################################################
 
@@ -29,18 +29,20 @@ from grass.script import core as gcore
 def main():
     options, flags = gcore.parser()
     gisenv = gcore.gisenv()
-    if 'MONITOR' in gisenv:
-        cmd_file = gcore.parse_command('d.mon', flags='g').get('cmd', None)
+    if "MONITOR" in gisenv:
+        cmd_file = gcore.parse_command("d.mon", flags="g").get("cmd", None)
         if not cmd_file:
             gcore.fatal(_("Unable to open file '%s'") % cmd_file)
-        dout_cmd = 'd.what.rast'
+        dout_cmd = "d.what.rast"
         for param, val in options.items():
             if val:
                 dout_cmd += " {param}={val}".format(param=param, val=val)
         with open(cmd_file, "a") as file_:
             file_.write(dout_cmd)
     else:
-        gcore.fatal(_("No graphics device selected. Use d.mon to select graphics device."))
+        gcore.fatal(
+            _("No graphics device selected. Use d.mon to select graphics device.")
+        )
 
 
 if __name__ == "__main__":

+ 9 - 7
scripts/d.what.vect/d.what.vect.py

@@ -7,9 +7,9 @@
 # PURPOSE:	 Script for querying vector maps in d.mon
 # COPYRIGHT: (C) 2014 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.
+# 		This program is free software under the GNU General
+# 		Public License (>=v2). Read the file COPYING that
+# 		comes with GRASS for details.
 #
 #############################################################################
 
@@ -29,18 +29,20 @@ from grass.script import core as gcore
 def main():
     options, flags = gcore.parser()
     gisenv = gcore.gisenv()
-    if 'MONITOR' in gisenv:
-        cmd_file = gcore.parse_command('d.mon', flags='g').get('cmd', None)
+    if "MONITOR" in gisenv:
+        cmd_file = gcore.parse_command("d.mon", flags="g").get("cmd", None)
         if not cmd_file:
             gcore.fatal(_("Unable to open file '%s'") % cmd_file)
-        dout_cmd = 'd.what.vect'
+        dout_cmd = "d.what.vect"
         for param, val in options.items():
             if val:
                 dout_cmd += " {param}={val}".format(param=param, val=val)
         with open(cmd_file, "a") as file_:
             file_.write(dout_cmd)
     else:
-        gcore.fatal(_("No graphics device selected. Use d.mon to select graphics device."))
+        gcore.fatal(
+            _("No graphics device selected. Use d.mon to select graphics device.")
+        )
 
 
 if __name__ == "__main__":

+ 25 - 17
scripts/db.dropcolumn/db.dropcolumn.py

@@ -43,34 +43,40 @@ import grass.script as gscript
 
 
 def main():
-    table = options['table']
-    column = options['column']
-    force = flags['f']
+    table = options["table"]
+    column = options["column"]
+    force = flags["f"]
 
     # check if DB parameters are set, and if not set them.
-    gscript.run_command('db.connect', flags='c')
+    gscript.run_command("db.connect", flags="c")
 
     kv = gscript.db_connection()
-    database = kv['database']
-    driver = kv['driver']
+    database = kv["database"]
+    driver = kv["driver"]
     # schema needed for PG?
 
     if force:
         gscript.message(_("Forcing ..."))
 
     if column == "cat":
-        gscript.warning(_("Deleting <%s> column which may be needed to keep "
-                          "table connected to a vector map") % column)
-
-    cols = [f[0] for f in gscript.db_describe(table)['cols']]
+        gscript.warning(
+            _(
+                "Deleting <%s> column which may be needed to keep "
+                "table connected to a vector map"
+            )
+            % column
+        )
+
+    cols = [f[0] for f in gscript.db_describe(table)["cols"]]
     if column not in cols:
         gscript.fatal(_("Column <%s> not found in table") % column)
 
     if not force:
         gscript.message(_("Column <%s> would be deleted.") % column)
         gscript.message("")
-        gscript.message(_("You must use the force flag (-f) to actually "
-                          "remove it. Exiting."))
+        gscript.message(
+            _("You must use the force flag (-f) to actually " "remove it. Exiting.")
+        )
         return 0
 
     if driver == "sqlite":
@@ -78,7 +84,7 @@ def main():
         # http://www.sqlite.org/faq.html#q13
         colnames = []
         coltypes = []
-        for f in gscript.db_describe(table)['cols']:
+        for f in gscript.db_describe(table)["cols"]:
             if f[0] != column:
                 colnames.append(f[0])
                 coltypes.append("%s %s" % (f[0], f[1]))
@@ -94,21 +100,23 @@ def main():
             "CREATE TABLE ${table}(${coldef})",
             "INSERT INTO ${table} SELECT ${colnames} FROM ${table}_backup",
             "DROP TABLE ${table}_backup",
-            "COMMIT"
+            "COMMIT",
         ]
-        tmpl = string.Template(';\n'.join(cmds))
+        tmpl = string.Template(";\n".join(cmds))
         sql = tmpl.substitute(table=table, coldef=coltypes, colnames=colnames)
     else:
         sql = "ALTER TABLE %s DROP COLUMN %s" % (table, column)
 
     try:
-        gscript.write_command('db.execute', input='-', database=database,
-                              driver=driver, stdin=sql)
+        gscript.write_command(
+            "db.execute", input="-", database=database, driver=driver, stdin=sql
+        )
     except CalledModuleError:
         gscript.fatal(_("Cannot continue (problem deleting column)"))
 
     return 0
 
+
 if __name__ == "__main__":
     options, flags = gscript.parser()
     sys.exit(main())

+ 12 - 13
scripts/db.dropcolumn/testsuite/test_db_dropcolumn.py

@@ -15,40 +15,39 @@ from grass.script.utils import decode
 class TestDbDropColumn(TestCase):
     """Test db.dropcolumn script"""
 
-    mapName = 'myroads'
-    colName = 'SHAPE_LEN'
+    mapName = "myroads"
+    colName = "SHAPE_LEN"
 
     @classmethod
     def setUpClass(cls):
         """Copy vector."""
-        run_command('g.copy', vector='roadsmajor,myroads')
+        run_command("g.copy", vector="roadsmajor,myroads")
 
     @classmethod
     def tearDownClass(cls):
         """Remove copied vector"""
-        run_command('g.remove', type='vector', name=cls.mapName,
-                    flags='f')
+        run_command("g.remove", type="vector", name=cls.mapName, flags="f")
 
     def test_drop_column_check(self):
         """Drop column check, the column should still be in the table"""
-        module = SimpleModule('db.dropcolumn', table=self.mapName,
-                              column=self.colName)
+        module = SimpleModule("db.dropcolumn", table=self.mapName, column=self.colName)
         self.assertModule(module)
 
-        m = SimpleModule('db.columns', table=self.mapName)
+        m = SimpleModule("db.columns", table=self.mapName)
         self.assertModule(m)
         self.assertRegexpMatches(decode(m.outputs.stdout), self.colName)
 
     def test_drop_column_with_force(self):
         """Drop column with force, the column should not be in the table"""
-        module = SimpleModule('db.dropcolumn', table=self.mapName,
-                              column=self.colName,
-                              flags='f')
+        module = SimpleModule(
+            "db.dropcolumn", table=self.mapName, column=self.colName, flags="f"
+        )
         self.assertModule(module)
 
-        m = SimpleModule('db.columns', table=self.mapName)
+        m = SimpleModule("db.columns", table=self.mapName)
         self.assertModule(m)
         self.assertNotRegexpMatches(decode(m.outputs.stdout), self.colName)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 16 - 15
scripts/db.droptable/db.droptable.py

@@ -48,22 +48,22 @@ from grass.script.utils import encode
 
 
 def main():
-    table = options['table']
-    force = flags['f']
+    table = options["table"]
+    force = flags["f"]
 
-    if not options['driver'] or not options['database']:
+    if not options["driver"] or not options["database"]:
         # check if DB parameters are set, and if not set them.
-        grass.run_command('db.connect', flags='c', quiet=True)
+        grass.run_command("db.connect", flags="c", quiet=True)
 
     kv = grass.db_connection()
-    if options['database']:
-        database = options['database']
+    if options["database"]:
+        database = options["database"]
     else:
-        database = kv['database']
-    if options['driver']:
-        driver = options['driver']
+        database = kv["database"]
+    if options["driver"]:
+        driver = options["driver"]
     else:
-        driver = kv['driver']
+        driver = kv["driver"]
     # schema needed for PG?
 
     if force:
@@ -71,14 +71,15 @@ def main():
 
     # check if table exists
     if not grass.db_table_exist(table):
-        grass.warning(_("Table <%s> not found in database <%s>") %
-                       (table, database))
+        grass.warning(_("Table <%s> not found in database <%s>") % (table, database))
         sys.exit(0)
 
     # check if table is used somewhere (connected to vector map)
     used = grass.db.db_table_in_vector(table)
     if used:
-        grass.warning(_("Deleting table <%s> which is attached to following map(s):") % table)
+        grass.warning(
+            _("Deleting table <%s> which is attached to following map(s):") % table
+        )
         for vect in used:
             grass.warning("%s" % vect)
 
@@ -88,14 +89,14 @@ def main():
         grass.message(_("You must use the force flag to actually remove it. Exiting."))
         sys.exit(0)
 
-    p = grass.feed_command('db.execute', input='-', database=database,
-                           driver=driver)
+    p = grass.feed_command("db.execute", input="-", database=database, driver=driver)
     p.stdin.write(encode("DROP TABLE " + table))
     p.stdin.close()
     p.wait()
     if p.returncode != 0:
         grass.fatal(_("Cannot continue (problem deleting table)."))
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     main()

+ 9 - 9
scripts/db.droptable/testsuite/test_db_droptable.py

@@ -15,36 +15,36 @@ from grass.script.utils import decode
 class TestDbDropTable(TestCase):
     """Test db.droptable script"""
 
-    mapName = 'myroads'
+    mapName = "myroads"
 
     @classmethod
     def setUpClass(cls):
         """Copy vector."""
-        run_command('g.copy', vector='roadsmajor,myroads')
+        run_command("g.copy", vector="roadsmajor,myroads")
 
     @classmethod
     def tearDownClass(cls):
         """Remove copied vector"""
-        run_command('g.remove', type='vector', name=cls.mapName,
-                    flags='f')
+        run_command("g.remove", type="vector", name=cls.mapName, flags="f")
 
     def test_drop_table_check(self):
         """Drop table check, the column should still be in the table"""
-        module = SimpleModule('db.droptable', table=self.mapName)
+        module = SimpleModule("db.droptable", table=self.mapName)
         self.assertModule(module)
 
-        m = SimpleModule('db.tables', flags='p')
+        m = SimpleModule("db.tables", flags="p")
         self.assertModule(m)
         self.assertRegexpMatches(decode(m.outputs.stdout), self.mapName)
 
     def test_drop_table_with_force(self):
         """Drop table with force, the column should not be in the table"""
-        module = SimpleModule('db.droptable', table=self.mapName, flags='f')
+        module = SimpleModule("db.droptable", table=self.mapName, flags="f")
         self.assertModule(module)
 
-        m = SimpleModule('db.tables', flags='p')
+        m = SimpleModule("db.tables", flags="p")
         self.assertModule(m)
         self.assertNotRegexpMatches(decode(m.outputs.stdout), self.mapName)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 55 - 35
scripts/db.in.ogr/db.in.ogr.py

@@ -65,37 +65,39 @@ from grass.exceptions import CalledModuleError
 
 
 def main():
-    input = options['input']
-    db_table = options['db_table']
-    output = options['output']
-    key = options['key']
+    input = options["input"]
+    db_table = options["db_table"]
+    output = options["output"]
+    key = options["key"]
 
-    mapset = grass.gisenv()['MAPSET']
+    mapset = grass.gisenv()["MAPSET"]
 
     if db_table:
         input = db_table
 
     if not output:
-        tmpname = input.replace('.', '_')
+        tmpname = input.replace(".", "_")
         output = grass.basename(tmpname)
 
     # check if table exists
     try:
-        nuldev = open(os.devnull, 'w+')
-        s = grass.read_command('db.tables', flags='p', quiet=True, stderr=nuldev)
+        nuldev = open(os.devnull, "w+")
+        s = grass.read_command("db.tables", flags="p", quiet=True, stderr=nuldev)
         nuldev.close()
     except CalledModuleError:
         # check connection parameters, set if uninitialized
-        grass.read_command('db.connect', flags='c')
-        s = grass.read_command('db.tables', flags='p', quiet=True)
+        grass.read_command("db.connect", flags="c")
+        s = grass.read_command("db.tables", flags="p", quiet=True)
 
     for l in decode(s).splitlines():
         if l == output:
             if grass.overwrite():
-                grass.warning(_("Table <%s> already exists and will be "
-                                "overwritten") % output)
-                grass.write_command('db.execute', input='-',
-                                    stdin="DROP TABLE %s" % output)
+                grass.warning(
+                    _("Table <%s> already exists and will be " "overwritten") % output
+                )
+                grass.write_command(
+                    "db.execute", input="-", stdin="DROP TABLE %s" % output
+                )
                 break
             else:
                 grass.fatal(_("Table <%s> already exists") % output)
@@ -104,48 +106,66 @@ def main():
     layer = db_table if db_table else None
 
     vopts = {}
-    if options['encoding']:
-        vopts['encoding'] = options['encoding']
+    if options["encoding"]:
+        vopts["encoding"] = options["encoding"]
 
     try:
-        grass.run_command('v.in.ogr', flags='o', input=input, output=output,
-                          layer=layer, quiet=True, **vopts)
+        grass.run_command(
+            "v.in.ogr",
+            flags="o",
+            input=input,
+            output=output,
+            layer=layer,
+            quiet=True,
+            **vopts
+        )
     except CalledModuleError:
         if db_table:
-            grass.fatal(
-                _("Input table <%s> not found or not readable") %
-                input)
+            grass.fatal(_("Input table <%s> not found or not readable") % input)
         else:
             grass.fatal(_("Input DSN <%s> not found or not readable") % input)
 
     # rename ID col if requested from cat to new name
     if key:
-        grass.write_command('db.execute', quiet=True, input='-',
-                            stdin="ALTER TABLE %s ADD COLUMN %s integer" %
-                                  (output, key))
-        grass.write_command('db.execute', quiet=True, input='-',
-                            stdin="UPDATE %s SET %s=cat" % (output, key))
+        grass.write_command(
+            "db.execute",
+            quiet=True,
+            input="-",
+            stdin="ALTER TABLE %s ADD COLUMN %s integer" % (output, key),
+        )
+        grass.write_command(
+            "db.execute",
+            quiet=True,
+            input="-",
+            stdin="UPDATE %s SET %s=cat" % (output, key),
+        )
 
     # ... and immediately drop the empty geometry
-    vectfile = grass.find_file(output, element='vector', mapset=mapset)['file']
+    vectfile = grass.find_file(output, element="vector", mapset=mapset)["file"]
     if not vectfile:
         grass.fatal(_("Something went wrong. Should not happen"))
     else:
         # remove the vector part
-        grass.run_command('v.db.connect', quiet=True, map=output, layer='1',
-                          flags='d')
-        grass.run_command('g.remove', flags='f', quiet=True, type='vector',
-                          name=output)
+        grass.run_command("v.db.connect", quiet=True, map=output, layer="1", flags="d")
+        grass.run_command("g.remove", flags="f", quiet=True, type="vector", name=output)
 
     # get rid of superfluous auto-added cat column (and cat_ if present)
-    nuldev = open(os.devnull, 'w+')
-    grass.run_command('db.dropcolumn', quiet=True, flags='f', table=output,
-                      column='cat', stdout=nuldev, stderr=nuldev)
+    nuldev = open(os.devnull, "w+")
+    grass.run_command(
+        "db.dropcolumn",
+        quiet=True,
+        flags="f",
+        table=output,
+        column="cat",
+        stdout=nuldev,
+        stderr=nuldev,
+    )
     nuldev.close()
 
-    records = grass.db_describe(output)['nrows']
+    records = grass.db_describe(output)["nrows"]
     grass.message(_("Imported table <%s> with %d rows") % (output, records))
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     main()

+ 16 - 18
scripts/db.in.ogr/testsuite/test_db_in_ogr.py

@@ -17,47 +17,45 @@ import os
 class TestDbInOgr(TestCase):
     """Test db.in.ogr script"""
 
-    csvFile = 'sample_data.csv'
-    dbfFile = 'sample_data.dbf'
-    tableName1 = 'sample_table1'
-    tableName2 = 'sample_table2'
+    csvFile = "sample_data.csv"
+    dbfFile = "sample_data.dbf"
+    tableName1 = "sample_table1"
+    tableName2 = "sample_table2"
 
     @classmethod
     def setUpClass(cls):
         """Create temporary files. Remove if the tables already exists."""
-        cls.runModule('db.out.ogr', input='geology', output=cls.csvFile)
-        cls.runModule('db.out.ogr', input='geology', output=cls.dbfFile,
-                      format='DBF')
-        cls.runModule('db.droptable', table=cls.tableName1, flags='f')
-        cls.runModule('db.droptable', table=cls.tableName2, flags='f')
+        cls.runModule("db.out.ogr", input="geology", output=cls.csvFile)
+        cls.runModule("db.out.ogr", input="geology", output=cls.dbfFile, format="DBF")
+        cls.runModule("db.droptable", table=cls.tableName1, flags="f")
+        cls.runModule("db.droptable", table=cls.tableName2, flags="f")
 
     @classmethod
     def tearDownClass(cls):
         """Remove the created files and the created table"""
         os.remove(cls.csvFile)
         os.remove(cls.dbfFile)
-        cls.runModule('db.droptable', table=cls.tableName1, flags='f')
-        cls.runModule('db.droptable', table=cls.tableName2, flags='f')
+        cls.runModule("db.droptable", table=cls.tableName1, flags="f")
+        cls.runModule("db.droptable", table=cls.tableName2, flags="f")
 
     def test_import_csv_file(self):
         """import csv table"""
-        module = SimpleModule('db.in.ogr', input=self.csvFile,
-                              output=self.tableName1)
+        module = SimpleModule("db.in.ogr", input=self.csvFile, output=self.tableName1)
         self.assertModule(module)
 
-        m = SimpleModule('db.tables', flags='p')
+        m = SimpleModule("db.tables", flags="p")
         self.assertModule(m)
         self.assertRegexpMatches(decode(m.outputs.stdout), self.tableName1)
 
     def test_import_dbf_file(self):
         """import dbf table"""
-        module = SimpleModule('db.in.ogr', input=self.dbfFile,
-                              output=self.tableName2)
+        module = SimpleModule("db.in.ogr", input=self.dbfFile, output=self.tableName2)
         self.assertModule(module)
 
-        m = SimpleModule('db.tables', flags='p')
+        m = SimpleModule("db.tables", flags="p")
         self.assertModule(m)
         self.assertRegexpMatches(decode(m.outputs.stdout), self.tableName2)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 37 - 23
scripts/db.out.ogr/db.out.ogr.py

@@ -63,59 +63,73 @@ from grass.exceptions import CalledModuleError
 
 
 def main():
-    input = options['input']
-    layer = options['layer']
-    format = options['format']
-    output = options['output']
-    table = options['table']
+    input = options["input"]
+    layer = options["layer"]
+    format = options["format"]
+    output = options["output"]
+    table = options["table"]
 
-    if format.lower() == 'dbf':
+    if format.lower() == "dbf":
         format = "ESRI_Shapefile"
 
-    if format.lower() == 'csv':
-        olayer = basename(output, 'csv')
+    if format.lower() == "csv":
+        olayer = basename(output, "csv")
     else:
         olayer = None
 
     # is there a simpler way of testing for --overwrite?
-    dbffile = input + '.dbf'
+    dbffile = input + ".dbf"
     if os.path.exists(dbffile) and not gcore.overwrite():
         gcore.fatal(_("File <%s> already exists") % dbffile)
 
     if olayer:
         try:
-            gcore.run_command('v.out.ogr', quiet=True, input=input,
-                              layer=layer, output=output, format=format,
-                              type='point,line,area', olayer=olayer)
+            gcore.run_command(
+                "v.out.ogr",
+                quiet=True,
+                input=input,
+                layer=layer,
+                output=output,
+                format=format,
+                type="point,line,area",
+                olayer=olayer,
+            )
         except CalledModuleError:
-            gcore.fatal(_("Module <%s> failed") % 'v.out.ogr')
+            gcore.fatal(_("Module <%s> failed") % "v.out.ogr")
 
     else:
         try:
-            gcore.run_command('v.out.ogr', quiet=True, input=input,
-                              layer=layer, output=output,
-                              format=format, type='point,line,area')
+            gcore.run_command(
+                "v.out.ogr",
+                quiet=True,
+                input=input,
+                layer=layer,
+                output=output,
+                format=format,
+                type="point,line,area",
+            )
         except CalledModuleError:
-            gcore.fatal(_("Module <%s> failed") % 'v.out.ogr')
+            gcore.fatal(_("Module <%s> failed") % "v.out.ogr")
 
     if format == "ESRI_Shapefile":
-        exts = ['shp', 'shx', 'prj']
-        if output.endswith('.dbf'):
-            outname = basename(output, 'dbf')
+        exts = ["shp", "shx", "prj"]
+        if output.endswith(".dbf"):
+            outname = basename(output, "dbf")
             for ext in exts:
                 try_remove("%s.%s" % (outname, ext))
-            outname += '.dbf'
+            outname += ".dbf"
         else:
             for ext in exts:
                 try_remove(os.path.join(output, "%s.%s" % (input, ext)))
             outname = os.path.join(output, input + ".dbf")
-    elif format.lower() == 'csv':
-        outname = output + '.csv'
+    elif format.lower() == "csv":
+        outname = output + ".csv"
     else:
         outname = input
 
     gcore.message(_("Exported table <%s>") % outname)
 
+
 if __name__ == "__main__":
     options, flags = gcore.parser()
     main()

+ 21 - 19
scripts/db.test/db.test.py

@@ -7,9 +7,9 @@
 # PURPOSE:	Test database driver
 # COPYRIGHT:	(C) 2004-2014 by the GRASS Development Team
 #
-#		This program is free software under the GNU General Public
-#		License (version 2). Read the file COPYING that comes with GRASS
-#		for details.
+# 		This program is free software under the GNU General Public
+# 		License (version 2). Read the file COPYING that comes with GRASS
+# 		for details.
 #
 #############################################################################
 
@@ -35,34 +35,35 @@ from grass.exceptions import CalledModuleError
 
 
 def main():
-    test_file = options['test']
+    test_file = options["test"]
 
     expected = gcore.tempfile()
     result = gcore.tempfile()
 
     dbconn = grassdb.db_connection()
-    gcore.message(_("Using DB driver: %s") % dbconn['driver'])
+    gcore.message(_("Using DB driver: %s") % dbconn["driver"])
 
-    infile = os.path.join(os.environ['GISBASE'], 'etc', 'db.test', test_file)
+    infile = os.path.join(os.environ["GISBASE"], "etc", "db.test", test_file)
     inf = open(infile)
 
     while True:
         type = inf.readline()
         if not type:
             break
-        type = type.rstrip('\r\n')
+        type = type.rstrip("\r\n")
 
-        sql = inf.readline().rstrip('\r\n')
-        sys.stdout.write(sql + '\n')
+        sql = inf.readline().rstrip("\r\n")
+        sys.stdout.write(sql + "\n")
 
         # Copy expected result to temp file
         try:
-            if type == 'X':
-                gcore.write_command('db.execute', input='-', stdin=sql + '\n')
+            if type == "X":
+                gcore.write_command("db.execute", input="-", stdin=sql + "\n")
             else:
-                resf = open(result, 'w')
-                gcore.write_command('db.select', input='-', flags='c',
-                                    stdin=sql + '\n', stdout=resf)
+                resf = open(result, "w")
+                gcore.write_command(
+                    "db.select", input="-", flags="c", stdin=sql + "\n", stdout=resf
+                )
                 resf.close()
 
         except CalledModuleError:
@@ -70,20 +71,21 @@ def main():
         else:
             gcore.message(_("EXECUTE: OK"))
 
-        expf = open(expected, 'w')
+        expf = open(expected, "w")
         while True:
-            res = inf.readline().rstrip('\r\n')
+            res = inf.readline().rstrip("\r\n")
             if not res:
                 break
-            expf.write(res + '\n')
+            expf.write(res + "\n")
         expf.close()
 
-        if type == 'S':
-            if gcore.call(['diff', result, expected]) != 0:
+        if type == "S":
+            if gcore.call(["diff", result, expected]) != 0:
                 gcore.error("RESULT: ******** ERROR ********")
             else:
                 gcore.message(_("RESULT: OK"))
 
+
 if __name__ == "__main__":
     options, flags = gcore.parser()
     main()

+ 64 - 71
scripts/db.univar/db.univar.py

@@ -10,9 +10,9 @@
 #               Based on r.univar.sh by Markus Neteler
 # COPYRIGHT:	(C) 2005, 2007, 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.
+# 		This program is free software under the GNU General Public
+# 		License (>=v2). Read the file COPYING that comes with GRASS
+# 		for details.
 #
 #############################################################################
 
@@ -63,25 +63,25 @@ import grass.script as gscript
 
 
 def cleanup():
-    for ext in ['', '.sort']:
+    for ext in ["", ".sort"]:
         gscript.try_remove(tmp + ext)
 
 
 def sortfile(infile, outfile):
-    inf = open(infile, 'r')
-    outf = open(outfile, 'w')
+    inf = open(infile, "r")
+    outf = open(outfile, "w")
 
-    if gscript.find_program('sort', '--help'):
-        gscript.run_command('sort', flags='n', stdin=inf, stdout=outf)
+    if gscript.find_program("sort", "--help"):
+        gscript.run_command("sort", flags="n", stdin=inf, stdout=outf)
     else:
         # FIXME: we need a large-file sorting function
         gscript.warning(_("'sort' not found: sorting in memory"))
         lines = inf.readlines()
         for i in range(len(lines)):
-            lines[i] = float(lines[i].rstrip('\r\n'))
+            lines[i] = float(lines[i].rstrip("\r\n"))
         lines.sort()
         for line in lines:
-            outf.write(str(line) + '\n')
+            outf.write(str(line) + "\n")
 
     inf.close()
     outf.close()
@@ -91,32 +91,33 @@ def main():
     global tmp
     tmp = gscript.tempfile()
 
-    extend = flags['e']
-    shellstyle = flags['g']
-    table = options['table']
-    column = options['column']
-    database = options['database']
-    driver = options['driver']
-    where = options['where']
-    perc = options['percentile']
+    extend = flags["e"]
+    shellstyle = flags["g"]
+    table = options["table"]
+    column = options["column"]
+    database = options["database"]
+    driver = options["driver"]
+    where = options["where"]
+    perc = options["percentile"]
 
-    perc = [float(p) for p in perc.split(',')]
+    perc = [float(p) for p in perc.split(",")]
 
     desc_table = gscript.db_describe(table, database=database, driver=driver)
     if not desc_table:
         gscript.fatal(_("Unable to describe table <%s>") % table)
     found = False
-    for cname, ctype, cwidth in desc_table['cols']:
+    for cname, ctype, cwidth in desc_table["cols"]:
         if cname == column:
             found = True
-            if ctype not in ('INTEGER', 'DOUBLE PRECISION'):
+            if ctype not in ("INTEGER", "DOUBLE PRECISION"):
                 gscript.fatal(_("Column <%s> is not numeric") % cname)
     if not found:
         gscript.fatal(_("Column <%s> not found in table <%s>") % (column, table))
 
     if not shellstyle:
-        gscript.verbose(_("Calculation for column <%s> of table <%s>..."
-                          ) % (column, table))
+        gscript.verbose(
+            _("Calculation for column <%s> of table <%s>...") % (column, table)
+        )
         gscript.message(_("Reading column values..."))
 
     sql = "SELECT %s FROM %s" % (column, table)
@@ -129,15 +130,21 @@ def main():
     if not driver:
         driver = None
 
-    tmpf = open(tmp, 'w')
-    gscript.run_command('db.select', flags='c', table=table,
-                        database=database, driver=driver, sql=sql,
-                        stdout=tmpf)
+    tmpf = open(tmp, "w")
+    gscript.run_command(
+        "db.select",
+        flags="c",
+        table=table,
+        database=database,
+        driver=driver,
+        sql=sql,
+        stdout=tmpf,
+    )
     tmpf.close()
 
     # check if result is empty
     tmpf = open(tmp)
-    if tmpf.read(1) == '':
+    if tmpf.read(1) == "":
         gscript.fatal(_("Table <%s> contains no data.") % table)
         tmpf.close()
 
@@ -154,9 +161,9 @@ def main():
 
     tmpf = open(tmp)
     for line in tmpf:
-        if len(line.rstrip('\r\n')) == 0:
+        if len(line.rstrip("\r\n")) == 0:
             continue
-        x = float(line.rstrip('\r\n'))
+        x = float(line.rstrip("\r\n"))
         N += 1
         sum += x
         sum2 += x * x
@@ -174,18 +181,16 @@ def main():
         sys.stdout.write("Maximum: %.15g\n" % maxv)
         sys.stdout.write("Range: %.15g\n" % (maxv - minv))
         sys.stdout.write("Mean: %.15g\n" % (sum / N))
-        sys.stdout.write(
-            "Arithmetic mean of absolute values: %.15g\n" %
-            (sum3 / N))
+        sys.stdout.write("Arithmetic mean of absolute values: %.15g\n" % (sum3 / N))
         if not ((sum2 - sum * sum / N) / N) < 0:
             sys.stdout.write("Variance: %.15g\n" % ((sum2 - sum * sum / N) / N))
             sys.stdout.write(
-                "Standard deviation: %.15g\n" %
-                (math.sqrt((sum2 - sum * sum / N) / N)))
+                "Standard deviation: %.15g\n" % (math.sqrt((sum2 - sum * sum / N) / N))
+            )
             sys.stdout.write(
-                "Coefficient of variation: %.15g\n" %
-                ((math.sqrt((sum2 - sum * sum / N) / N)) /
-                 (math.sqrt(sum * sum) / N)))
+                "Coefficient of variation: %.15g\n"
+                % ((math.sqrt((sum2 - sum * sum / N) / N)) / (math.sqrt(sum * sum) / N))
+            )
         else:
             sys.stdout.write("Variance: 0\n")
             sys.stdout.write("Standard deviation: 0\n")
@@ -200,14 +205,11 @@ def main():
         sys.stdout.write("mean_abs=%.15g\n" % (sum3 / N))
         if not ((sum2 - sum * sum / N) / N) < 0:
             sys.stdout.write("variance=%.15g\n" % ((sum2 - sum * sum / N) / N))
+            sys.stdout.write("stddev=%.15g\n" % (math.sqrt((sum2 - sum * sum / N) / N)))
             sys.stdout.write(
-                "stddev=%.15g\n" %
-                (math.sqrt(
-                    (sum2 - sum * sum / N) / N)))
-            sys.stdout.write(
-                "coeff_var=%.15g\n" %
-                ((math.sqrt((sum2 - sum * sum / N) / N)) /
-                 (math.sqrt(sum * sum) / N)))
+                "coeff_var=%.15g\n"
+                % ((math.sqrt((sum2 - sum * sum / N) / N)) / (math.sqrt(sum * sum) / N))
+            )
         else:
             sys.stdout.write("variance=0\n")
             sys.stdout.write("stddev=0\n")
@@ -221,7 +223,7 @@ def main():
     sortfile(tmp, tmp + ".sort")
 
     odd = N % 2
-    eostr = ['even', 'odd'][odd]
+    eostr = ["even", "odd"][odd]
 
     q25pos = round(N * 0.25)
     if q25pos == 0:
@@ -246,16 +248,16 @@ def main():
     l = 1
     for line in inf:
         if l == q25pos:
-            q25 = float(line.rstrip('\r\n'))
+            q25 = float(line.rstrip("\r\n"))
         if l == q50apos:
-            q50a = float(line.rstrip('\r\n'))
+            q50a = float(line.rstrip("\r\n"))
         if l == q50bpos:
-            q50b = float(line.rstrip('\r\n'))
+            q50b = float(line.rstrip("\r\n"))
         if l == q75pos:
-            q75 = float(line.rstrip('\r\n'))
+            q75 = float(line.rstrip("\r\n"))
         for i in range(len(ppos)):
             if l == ppos[i]:
-                pval[i] = float(line.rstrip('\r\n'))
+                pval[i] = float(line.rstrip("\r\n"))
         l += 1
 
     q50 = (q50a + q50b) / 2
@@ -268,41 +270,32 @@ def main():
             if perc[i] == int(perc[i]):  # integer
                 if int(perc[i]) % 10 == 1 and int(perc[i]) != 11:
                     sys.stdout.write(
-                        "%dst Percentile: %.15g\n" %
-                        (int(
-                            perc[i]),
-                            pval[i]))
+                        "%dst Percentile: %.15g\n" % (int(perc[i]), pval[i])
+                    )
                 elif int(perc[i]) % 10 == 2 and int(perc[i]) != 12:
                     sys.stdout.write(
-                        "%dnd Percentile: %.15g\n" %
-                        (int(
-                            perc[i]),
-                            pval[i]))
+                        "%dnd Percentile: %.15g\n" % (int(perc[i]), pval[i])
+                    )
                 elif int(perc[i]) % 10 == 3 and int(perc[i]) != 13:
                     sys.stdout.write(
-                        "%drd Percentile: %.15g\n" %
-                        (int(
-                            perc[i]),
-                            pval[i]))
+                        "%drd Percentile: %.15g\n" % (int(perc[i]), pval[i])
+                    )
                 else:
                     sys.stdout.write(
-                        "%dth Percentile: %.15g\n" %
-                        (int(
-                            perc[i]),
-                            pval[i]))
+                        "%dth Percentile: %.15g\n" % (int(perc[i]), pval[i])
+                    )
             else:
-                sys.stdout.write(
-                    "%.15g Percentile: %.15g\n" %
-                    (perc[i], pval[i]))
+                sys.stdout.write("%.15g Percentile: %.15g\n" % (perc[i], pval[i]))
     else:
         sys.stdout.write("first_quartile=%.15g\n" % q25)
         sys.stdout.write("median=%.15g\n" % q50)
         sys.stdout.write("third_quartile=%.15g\n" % q75)
         for i in range(len(perc)):
             percstr = "%.15g" % perc[i]
-            percstr = percstr.replace('.', '_')
+            percstr = percstr.replace(".", "_")
             sys.stdout.write("percentile_%s=%.15g\n" % (percstr, pval[i]))
 
+
 if __name__ == "__main__":
     options, flags = gscript.parser()
     atexit.register(cleanup)

+ 17 - 15
scripts/db.univar/testsuite/test_db_univar.py

@@ -14,35 +14,37 @@ from grass.script.core import run_command
 class TestDbUnivar(TestCase):
     """Test db.univar script"""
 
-    columnName = 'heights'
-    mapName = 'samples'
+    columnName = "heights"
+    mapName = "samples"
 
     @classmethod
     def setUpClass(cls):
         """Use temp region"""
         cls.use_temp_region()
-        cls.runModule('g.region', raster='elevation', flags='p')
+        cls.runModule("g.region", raster="elevation", flags="p")
 
     @classmethod
     def tearDownClass(cls):
         """Remove temporary region"""
-        cls.runModule('g.remove', flags='f', type='raster', name='elevation')
+        cls.runModule("g.remove", flags="f", type="raster", name="elevation")
         cls.del_temp_region()
 
-        run_command('v.db.droptable', map='samples', flags='f')
+        run_command("v.db.droptable", map="samples", flags="f")
 
     def test_calculate(self):
         """run db.univar"""
-        run_command('v.random', output=self.mapName, n=100, overwrite='True')
-        run_command('v.db.addtable', map=self.mapName,
-                    column="heights double precision")
-        run_command('v.what.rast', map=self.mapName, raster='elevation',
-                    column=self.columnName)
-        run_command('v.db.select', map=self.mapName)
-
-        module = SimpleModule('db.univar', table=self.mapName,
-                              column=self.columnName)
+        run_command("v.random", output=self.mapName, n=100, overwrite="True")
+        run_command(
+            "v.db.addtable", map=self.mapName, column="heights double precision"
+        )
+        run_command(
+            "v.what.rast", map=self.mapName, raster="elevation", column=self.columnName
+        )
+        run_command("v.db.select", map=self.mapName)
+
+        module = SimpleModule("db.univar", table=self.mapName, column=self.columnName)
         self.assertModule(module)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 9 - 9
scripts/g.bands/g.bands.py

@@ -47,22 +47,23 @@ import sys
 
 import grass.script as gs
 
+
 def main():
     from grass.bandref import BandReferenceReader, BandReferenceReaderError
 
     band = None
     kwargs = {}
-    if ',' in options['pattern']:
+    if "," in options["pattern"]:
         gs.fatal("Multiple values not supported")
-    if '_' in options['pattern']:
+    if "_" in options["pattern"]:
         # full band identifier specified
-        kwargs['shortcut'], kwargs['band'] = options['pattern'].split('_')
+        kwargs["shortcut"], kwargs["band"] = options["pattern"].split("_")
     else:
         # pattern
-        kwargs['shortcut'] = options['pattern']
-    kwargs['extended'] = flags['e']
+        kwargs["shortcut"] = options["pattern"]
+    kwargs["extended"] = flags["e"]
 
-    if options['operation'] == 'print':
+    if options["operation"] == "print":
         try:
             reader = BandReferenceReader()
             reader.print_info(**kwargs)
@@ -71,9 +72,8 @@ def main():
 
     return 0
 
+
 if __name__ == "__main__":
     options, flags = gs.parser()
 
-    sys.exit(
-        main()
-    )
+    sys.exit(main())

+ 10 - 13
scripts/g.bands/testsuite/test_g_bands.py

@@ -4,39 +4,36 @@ from grass.gunittest.case import TestCase
 from grass.gunittest.main import test
 from grass.gunittest.gmodules import call_module
 
+
 class TestBandsSystemDefined(TestCase):
     @staticmethod
     def _number_of_bands(**kwargs):
-        gbands = call_module('g.bands', **kwargs)
+        gbands = call_module("g.bands", **kwargs)
         return len(gbands.rstrip(os.linesep).split(os.linesep))
 
     def test_number_system_defined(self):
-        # test number of valid band identifiers
-        #
+        """Test number of valid band identifiers"""
         # get number of valid band identifiers by g.bands
         nbands = self._number_of_bands()
 
         # get number of valid band identifiers by Bands lib
         from grass.bandref import BandReferenceReader
-        nbands_ref = len(BandReferenceReader().get_bands())
 
+        nbands_ref = len(BandReferenceReader().get_bands())
         self.assertEqual(nbands, nbands_ref)
 
     def test_number_s2(self):
-        # test number of S2 band identifiers (hardcoded, no changes expected)
-        #
-        nbands = self._number_of_bands(pattern='S2')
-
+        """Test number of S2 band identifiers (hardcoded, no changes expected)"""
+        nbands = self._number_of_bands(pattern="S2")
         self.assertEqual(nbands, 13)
 
-
     def test_number_s2_1(self):
-        # test if S2_1 is defined (lower + upper case)
-        #
-        band = 'S2_1'
+        """Test if S2_1 is defined (lower + upper case)"""
+        band = "S2_1"
         for iband in [band, band.upper()]:
             nbands = self._number_of_bands(pattern=iband)
             self.assertEqual(nbands, 1)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 27 - 25
scripts/g.extension.all/g.extension.all.py

@@ -49,15 +49,15 @@ from grass.exceptions import CalledModuleError
 
 
 def get_extensions():
-    addon_base = os.getenv('GRASS_ADDON_BASE')
+    addon_base = os.getenv("GRASS_ADDON_BASE")
     if not addon_base:
         gscript.fatal(_("%s not defined") % "GRASS_ADDON_BASE")
-    fXML = os.path.join(addon_base, 'modules.xml')
+    fXML = os.path.join(addon_base, "modules.xml")
     if not os.path.exists(fXML):
         return []
 
     # read XML file
-    fo = open(fXML, 'r')
+    fo = open(fXML, "r")
     try:
         tree = etree.fromstring(fo.read())
     except Exception as e:
@@ -67,24 +67,22 @@ def get_extensions():
 
     fo.close()
 
-    libgis_rev = gscript.version()['libgis_revision']
+    libgis_rev = gscript.version()["libgis_revision"]
     ret = list()
-    for tnode in tree.findall('task'):
-        gnode = tnode.find('libgis')
-        if gnode is not None and \
-                gnode.get('revision', '') != libgis_rev:
-            ret.append(tnode.get('name'))
+    for tnode in tree.findall("task"):
+        gnode = tnode.find("libgis")
+        if gnode is not None and gnode.get("revision", "") != libgis_rev:
+            ret.append(tnode.get("name"))
 
     return ret
 
 
 def main():
-    remove = options['operation'] == 'remove'
-    if remove or flags['f']:
+    remove = options["operation"] == "remove"
+    if remove or flags["f"]:
         extensions = gscript.read_command(
-            'g.extension',
-            quiet=True,
-            flags='a').splitlines()
+            "g.extension", quiet=True, flags="a"
+        ).splitlines()
     else:
         extensions = get_extensions()
 
@@ -93,37 +91,41 @@ def main():
             gscript.info(_("No extension found. Nothing to remove."))
         else:
             gscript.info(
-                _("Nothing to rebuild. Rebuilding process can be forced with -f flag."))
+                _("Nothing to rebuild. Rebuilding process can be forced with -f flag.")
+            )
         return 0
 
-    if remove and not flags['f']:
+    if remove and not flags["f"]:
         gscript.message(_("List of extensions to be removed:"))
         print(os.linesep.join(extensions))
         gscript.message(
-            _("You must use the force flag (-f) to actually remove them. Exiting."))
+            _("You must use the force flag (-f) to actually remove them. Exiting.")
+        )
         return 0
 
     for ext in extensions:
-        gscript.message('-' * 60)
+        gscript.message("-" * 60)
         if remove:
             gscript.message(_("Removing extension <%s>...") % ext)
         else:
             gscript.message(_("Reinstalling extension <%s>...") % ext)
-        gscript.message('-' * 60)
+        gscript.message("-" * 60)
         if remove:
-            operation = 'remove'
-            operation_flags = 'f'
+            operation = "remove"
+            operation_flags = "f"
         else:
-            operation = 'add'
-            operation_flags = ''
+            operation = "add"
+            operation_flags = ""
         try:
-            gscript.run_command('g.extension', flags=operation_flags,
-                                extension=ext, operation=operation)
+            gscript.run_command(
+                "g.extension", flags=operation_flags, extension=ext, operation=operation
+            )
         except CalledModuleError:
             gscript.error(_("Unable to process extension:%s") % ext)
 
     return 0
 
+
 if __name__ == "__main__":
     options, flags = gscript.parser()
     sys.exit(main())

Разница между файлами не показана из-за своего большого размера
+ 703 - 601
scripts/g.extension/g.extension.py


+ 4 - 4
scripts/g.extension/testsuite/data/sample_modules/r.plus.example/r.plus.example.py

@@ -23,11 +23,11 @@ import grass.script as gs
 
 def main():
     options, flags = gs.parser()
-    araster = options['araster']
-    braster = options['braster']
-    output = options['output']
+    araster = options["araster"]
+    braster = options["braster"]
+    output = options["output"]
 
-    gs.mapcalc('{r} = {a} + {b}'.format(r=output, a=araster, b=braster))
+    gs.mapcalc("{r} = {a} + {b}".format(r=output, a=araster, b=braster))
 
     return 0
 

+ 41 - 24
scripts/g.extension/testsuite/test_addons_modules.py

@@ -44,16 +44,18 @@ v.in.redwg
 v.neighborhoodmatrix
 v.transects
 wx.metadata
-""".replace('\n', os.linesep)
+""".replace(
+    "\n", os.linesep
+)
 
 
 class TestModulesMetadata(TestCase):
 
-    url = 'file://' + os.path.abspath('data')
+    url = "file://" + os.path.abspath("data")
 
     def test_listing(self):
         """List individual extensions/modules/addons"""
-        module = SimpleModule('g.extension', flags='l', url=self.url)
+        module = SimpleModule("g.extension", flags="l", url=self.url)
         self.assertModule(module)
         stdout = decode(module.outputs.stdout)
         self.assertMultiLineEqual(stdout, MODULES_OUTPUT)
@@ -61,13 +63,13 @@ class TestModulesMetadata(TestCase):
 
 class TestModulesFromDifferentSources(TestCase):
 
-    url = 'file://' + os.path.abspath('data/sample_modules')
-    path = os.path.join('data', 'sample_modules')
-    install_prefix = 'gextension_test_install_path'
+    url = "file://" + os.path.abspath("data/sample_modules")
+    path = os.path.join("data", "sample_modules")
+    install_prefix = "gextension_test_install_path"
     # TODO: this is wrong for MS Win
     files = [
-        os.path.join(install_prefix, 'scripts', 'r.plus.example'),
-        os.path.join(install_prefix, 'docs', 'html', 'r.plus.example.html'),
+        os.path.join(install_prefix, "scripts", "r.plus.example"),
+        os.path.join(install_prefix, "docs", "html", "r.plus.example.html"),
     ]
     # to create archives from the source, the following was used:
     # zip r.plus.example.zip r.plus.example/*
@@ -80,8 +82,11 @@ class TestModulesFromDifferentSources(TestCase):
         if os.path.exists(self.install_prefix):
             files = os.listdir(self.install_prefix)
             if files:
-                RuntimeError("Install prefix path '{}' contains files {}"
-                             .format(self.install_prefix, files))
+                RuntimeError(
+                    "Install prefix path '{}' contains files {}".format(
+                        self.install_prefix, files
+                    )
+                )
 
     def tearDown(self):
         """Remove created files"""
@@ -89,38 +94,50 @@ class TestModulesFromDifferentSources(TestCase):
 
     def test_directory_install(self):
         """Test installing extension from directory"""
-        self.assertModule('g.extension', extension='r.plus.example',
-                          url=os.path.join(self.path, 'r.plus.example'),
-                          prefix=self.install_prefix)
+        self.assertModule(
+            "g.extension",
+            extension="r.plus.example",
+            url=os.path.join(self.path, "r.plus.example"),
+            prefix=self.install_prefix,
+        )
         # TODO: this is wrong for MS Win
         for file in self.files:
             self.assertFileExists(file)
 
     def test_targz_install(self):
         """Test installing extension from local .tar.gz"""
-        self.assertModule('g.extension', extension='r.plus.example',
-                          url=os.path.join(self.path,
-                                           'r.plus.example.tar.gz'),
-                          prefix=self.install_prefix)
+        self.assertModule(
+            "g.extension",
+            extension="r.plus.example",
+            url=os.path.join(self.path, "r.plus.example.tar.gz"),
+            prefix=self.install_prefix,
+        )
         for file in self.files:
             self.assertFileExists(file)
 
     def test_remote_targz_without_dir_install(self):
         """Test installing extension from (remote) .tar.gz without main dir"""
-        self.assertModule('g.extension', extension='r.plus.example',
-                          url=self.url + '/' + 'r.plus.example_sep.tar.gz',
-                          prefix=self.install_prefix, verbose=True)
+        self.assertModule(
+            "g.extension",
+            extension="r.plus.example",
+            url=self.url + "/" + "r.plus.example_sep.tar.gz",
+            prefix=self.install_prefix,
+            verbose=True,
+        )
         for file in self.files:
             self.assertFileExists(file)
 
     def test_remote_zip_install(self):
         """Test installing extension from .zip specified by URL (local)"""
-        self.assertModule('g.extension', extension='r.plus.example',
-                          url=self.url + '/' + 'r.plus.example.zip',
-                          prefix=self.install_prefix)
+        self.assertModule(
+            "g.extension",
+            extension="r.plus.example",
+            url=self.url + "/" + "r.plus.example.zip",
+            prefix=self.install_prefix,
+        )
         for file in self.files:
             self.assertFileExists(os.path.join(file))
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     test()

+ 3 - 3
scripts/g.extension/testsuite/test_addons_toolboxes.py

@@ -38,15 +38,15 @@ mcda (MC)
 
 class TestToolboxesMetadata(TestCase):
 
-    url = 'file://' + os.path.abspath('data')
+    url = "file://" + os.path.abspath("data")
 
     def test_listing(self):
         """List toolboxes and their content"""
-        module = SimpleModule('g.extension', flags='lt', url=self.url)
+        module = SimpleModule("g.extension", flags="lt", url=self.url)
         self.assertModule(module)
         stdout = module.outputs.stdout
         self.assertMultiLineEqual(stdout, FULL_TOOLBOXES_OUTPUT)
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     test()

+ 54 - 37
scripts/g.manual/g.manual.py

@@ -62,49 +62,65 @@ from grass.script import core as grass
 
 
 def start_browser(entry):
-    if browser and \
-       browser not in ('xdg-open', 'start') and \
-       not grass.find_program(browser):
+    if (
+        browser
+        and browser not in ("xdg-open", "start")
+        and not grass.find_program(browser)
+    ):
         grass.fatal(_("Browser '%s' not found") % browser)
 
-    if flags['o']:
-        major, minor, patch = grass.version()['version'].split('.')
-        url_path = 'https://grass.osgeo.org/grass%s%s/manuals/%s.html' % (major, minor, entry)
+    if flags["o"]:
+        major, minor, patch = grass.version()["version"].split(".")
+        url_path = "https://grass.osgeo.org/grass%s%s/manuals/%s.html" % (
+            major,
+            minor,
+            entry,
+        )
         if urlopen(url_path).getcode() != 200:
-            url_path = 'https://grass.osgeo.org/grass%s%s/manuals/addons/%s.html' % (
-                major, minor, entry)
+            url_path = "https://grass.osgeo.org/grass%s%s/manuals/addons/%s.html" % (
+                major,
+                minor,
+                entry,
+            )
     else:
-        path = os.path.join(gisbase, 'docs', 'html', entry + '.html')
-        if not os.path.exists(path) and os.getenv('GRASS_ADDON_BASE'):
-            path = os.path.join(os.getenv('GRASS_ADDON_BASE'), 'docs', 'html', entry + '.html')
+        path = os.path.join(gisbase, "docs", "html", entry + ".html")
+        if not os.path.exists(path) and os.getenv("GRASS_ADDON_BASE"):
+            path = os.path.join(
+                os.getenv("GRASS_ADDON_BASE"), "docs", "html", entry + ".html"
+            )
 
         if not os.path.exists(path):
             grass.fatal(_("No HTML manual page entry for '%s'") % entry)
 
-        url_path = 'file://' + path
+        url_path = "file://" + path
 
-    if browser and browser not in ('xdg-open', 'start'):
+    if browser and browser not in ("xdg-open", "start"):
         webbrowser.register(browser_name, None)
 
-    grass.verbose(_("Starting browser '%(browser)s' for manual"
-                    " entry '%(entry)s'...") %
-                  dict(browser=browser_name, entry=entry))
+    grass.verbose(
+        _("Starting browser '%(browser)s' for manual" " entry '%(entry)s'...")
+        % dict(browser=browser_name, entry=entry)
+    )
 
     try:
         webbrowser.open(url_path)
     except:
-        grass.fatal(_("Error starting browser '%(browser)s' for HTML file"
-                      " '%(path)s'") % dict(browser=browser, path=path))
+        grass.fatal(
+            _("Error starting browser '%(browser)s' for HTML file" " '%(path)s'")
+            % dict(browser=browser, path=path)
+        )
 
 
 def start_man(entry):
-    path = os.path.join(gisbase, 'docs', 'man', 'man1', entry + '.1')
-    if not os.path.exists(path) and os.getenv('GRASS_ADDON_BASE'):
-        path = os.path.join(os.getenv('GRASS_ADDON_BASE'), 'docs', 'man', 'man1', entry + '.1')
+    path = os.path.join(gisbase, "docs", "man", "man1", entry + ".1")
+    if not os.path.exists(path) and os.getenv("GRASS_ADDON_BASE"):
+        path = os.path.join(
+            os.getenv("GRASS_ADDON_BASE"), "docs", "man", "man1", entry + ".1"
+        )
 
-    for ext in ['', '.gz', '.bz2']:
+    for ext in ["", ".gz", ".bz2"]:
         if os.path.exists(path + ext):
-            os.execlp('man', 'man', path + ext)
+            os.execlp("man", "man", path + ext)
             grass.fatal(_("Error starting 'man' for '%s'") % path)
     grass.fatal(_("No manual page entry for '%s'") % entry)
 
@@ -112,30 +128,30 @@ def start_man(entry):
 def main():
     global gisbase, browser, browser_name
 
-    if flags['i'] and flags['t']:
-        grass.fatal(_("Flags -%c and -%c are mutually exclusive") % ('i', 't'))
+    if flags["i"] and flags["t"]:
+        grass.fatal(_("Flags -%c and -%c are mutually exclusive") % ("i", "t"))
 
     special = None
-    if flags['i']:
-        special = 'index'
-    elif flags['t']:
-        special = 'topics'
+    if flags["i"]:
+        special = "index"
+    elif flags["t"]:
+        special = "topics"
 
-    if flags['m']:
+    if flags["m"]:
         start = start_man
     else:
         start = start_browser
 
-    entry = options['entry']
-    gisbase = os.environ['GISBASE']
-    browser = os.getenv('GRASS_HTML_BROWSER', '')
+    entry = options["entry"]
+    gisbase = os.environ["GISBASE"]
+    browser = os.getenv("GRASS_HTML_BROWSER", "")
 
-    if sys.platform == 'darwin':
+    if sys.platform == "darwin":
         # hack for MacOSX
-        browser_name = os.getenv('GRASS_HTML_BROWSER_MACOSX', '..').split('.')[2]
-    elif sys.platform == 'cygwin':
+        browser_name = os.getenv("GRASS_HTML_BROWSER_MACOSX", "..").split(".")[2]
+    elif sys.platform == "cygwin":
         # hack for Cygwin
-        browser_name = basename(browser, 'exe')
+        browser_name = basename(browser, "exe")
     else:
         browser_name = basename(browser)
 
@@ -148,6 +164,7 @@ def main():
 
     return 0
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     sys.exit(main())

+ 72 - 59
scripts/g.search.modules/g.search.modules.py

@@ -6,9 +6,9 @@
 # PURPOSE:	g.search.modules in grass modules using keywords
 # COPYRIGHT:	(C) 2015-2019 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.
+# 		This program is free software under the GNU General
+# 		Public License (>=v2). Read the file COPYING that
+# 		comes with GRASS for details.
 #
 #############################################################################
 
@@ -80,24 +80,24 @@ COLORIZE = False
 
 def main():
     global COLORIZE
-    AND = flags['a']
-    NOT = flags['n']
-    manpages = flags['m']
-    exact_keywords = flags['k']
+    AND = flags["a"]
+    NOT = flags["n"]
+    manpages = flags["m"]
+    exact_keywords = flags["k"]
     out_format = None
-    if flags['g']:
-        out_format = 'shell'
-    elif flags['j']:
-        out_format = 'json'
+    if flags["g"]:
+        out_format = "shell"
+    elif flags["j"]:
+        out_format = "json"
     else:
-        COLORIZE = flags['c']
+        COLORIZE = flags["c"]
 
     keywords = None
-    if options['keyword']:
+    if options["keyword"]:
         if exact_keywords:
-            keywords = options['keyword'].split(',')
+            keywords = options["keyword"].split(",")
         else:
-            keywords = options['keyword'].lower().split(',')
+            keywords = options["keyword"].lower().split(",")
     else:
         NOT = None
 
@@ -126,10 +126,10 @@ def print_results(data, out_format=None):
     if not out_format:
         _print_results(data)
 
-    elif out_format == 'shell':
+    elif out_format == "shell":
         _print_results_shell(data)
 
-    elif out_format == 'json':
+    elif out_format == "json":
         _print_results_json(data)
 
 
@@ -137,14 +137,15 @@ def _print_results_shell(data):
     """Print just the name attribute"""
 
     for item in data:
-        print(item['name'])
+        print(item["name"])
 
 
 def _print_results_json(data):
     """Print JSON output"""
 
     import json
-    print(json.dumps(data, sort_keys=True, indent=4, separators=(',', ': ')))
+
+    print(json.dumps(data, sort_keys=True, indent=4, separators=(",", ": ")))
 
 
 def _print_results(data):
@@ -152,11 +153,15 @@ def _print_results(data):
     import textwrap
 
     for item in data:
-        print('\n{0}'.format(colorize(item['name'], attrs=['bold'])))
-        for attr in item['attributes']:
-            out = '{0}: {1}'.format(attr, item['attributes'][attr])
-            out = textwrap.wrap(out, width=79, initial_indent=4 * ' ',
-                                subsequent_indent=4 * ' ' + len(attr) * ' ' + '  ')
+        print("\n{0}".format(colorize(item["name"], attrs=["bold"])))
+        for attr in item["attributes"]:
+            out = "{0}: {1}".format(attr, item["attributes"][attr])
+            out = textwrap.wrap(
+                out,
+                width=79,
+                initial_indent=4 * " ",
+                subsequent_indent=4 * " " + len(attr) * " " + "  ",
+            )
             for line in out:
                 print(line)
 
@@ -176,6 +181,7 @@ def colorize(text, attrs=None, pattern=None):
         except ImportError:
             grass.fatal(_("Cannot colorize, python-termcolor is not installed"))
     else:
+
         def colored(pattern, attrs):
             return pattern
 
@@ -185,8 +191,9 @@ def colorize(text, attrs=None, pattern=None):
         return colored(text, attrs=attrs)
 
 
-def _search_module(keywords=None, logical_and=False, invert=False, manpages=False,
-                   exact_keywords=False):
+def _search_module(
+    keywords=None, logical_and=False, invert=False, manpages=False, exact_keywords=False
+):
     """Search modules by given keywords
 
     :param list.<str> keywords: list of keywords
@@ -196,38 +203,38 @@ def _search_module(keywords=None, logical_and=False, invert=False, manpages=Fals
     """
 
     WXGUIDIR = os.path.join(os.getenv("GISBASE"), "gui", "wxpython")
-    filename = os.path.join(WXGUIDIR, 'xml', 'module_items.xml')
-    menudata_file = open(filename, 'r')
+    filename = os.path.join(WXGUIDIR, "xml", "module_items.xml")
+    menudata_file = open(filename, "r")
 
     menudata = etree.parse(menudata_file)
     menudata_file.close()
 
-    items = menudata.findall('module-item')
+    items = menudata.findall("module-item")
 
     # add installed addons to modules list
     if os.getenv("GRASS_ADDON_BASE"):
-        filename_addons = os.path.join(os.getenv("GRASS_ADDON_BASE"), 'modules.xml')
+        filename_addons = os.path.join(os.getenv("GRASS_ADDON_BASE"), "modules.xml")
         if os.path.isfile(filename_addons):
-            addon_menudata_file = open(filename_addons, 'r')
+            addon_menudata_file = open(filename_addons, "r")
             addon_menudata = etree.parse(addon_menudata_file)
             addon_menudata_file.close()
-            addon_items = addon_menudata.findall('task')
+            addon_items = addon_menudata.findall("task")
             items.extend(addon_items)
 
     # add system-wide installed addons to modules list
-    filename_addons_s = os.path.join(os.getenv("GISBASE"), 'modules.xml')
+    filename_addons_s = os.path.join(os.getenv("GISBASE"), "modules.xml")
     if os.path.isfile(filename_addons_s):
-        addon_menudata_file_s = open(filename_addons_s, 'r')
+        addon_menudata_file_s = open(filename_addons_s, "r")
         addon_menudata_s = etree.parse(addon_menudata_file_s)
         addon_menudata_file_s.close()
-        addon_items_s = addon_menudata_s.findall('task')
+        addon_items_s = addon_menudata_s.findall("task")
         items.extend(addon_items_s)
 
     found_modules = []
     for item in items:
-        name = item.attrib['name']
-        description = item.find('description').text
-        module_keywords = item.find('keywords').text
+        name = item.attrib["name"]
+        description = item.find("description").text
+        module_keywords = item.find("keywords").text
 
         if not keywords:
             # list all modules
@@ -244,8 +251,9 @@ def _search_module(keywords=None, logical_and=False, invert=False, manpages=Fals
                 if exact_keywords:
                     keyword_found = _exact_search(keyword, module_keywords)
                 else:
-                    keyword_found = _basic_search(keyword, name, description,
-                                                  module_keywords)
+                    keyword_found = _basic_search(
+                        keyword, name, description, module_keywords
+                    )
 
                 # meta-modules (i.sentinel, r.modis, ...) do not have descriptions
                 # and keywords, but they have a manpage
@@ -259,26 +267,28 @@ def _search_module(keywords=None, logical_and=False, invert=False, manpages=Fals
                     else:
                         found = [True]
 
-                    description = colorize(description,
-                                           attrs=['underline'],
-                                           pattern=keyword)
-                    module_keywords = colorize(module_keywords,
-                                               attrs=['underline'],
-                                               pattern=keyword)
+                    description = colorize(
+                        description, attrs=["underline"], pattern=keyword
+                    )
+                    module_keywords = colorize(
+                        module_keywords, attrs=["underline"], pattern=keyword
+                    )
 
         add = False not in found
         if invert:
             add = not add
         if add:
-            found_modules.append({
-                'name': name,
-                'attributes': {
-                    'keywords': module_keywords,
-                    'description': description
+            found_modules.append(
+                {
+                    "name": name,
+                    "attributes": {
+                        "keywords": module_keywords,
+                        "description": description,
+                    },
                 }
-            })
+            )
 
-    return sorted(found_modules, key=lambda k: k['name'])
+    return sorted(found_modules, key=lambda k: k["name"])
 
 
 def _basic_search(pattern, name, description, module_keywords):
@@ -287,10 +297,12 @@ def _basic_search(pattern, name, description, module_keywords):
     This lowercases the strings before searching in them, so the pattern
     string should be lowercased too.
     """
-    if (name and description and module_keywords):
-        if name.lower().find(pattern) > -1 or\
-           description.lower().find(pattern) > -1 or\
-           module_keywords.lower().find(pattern) > -1:
+    if name and description and module_keywords:
+        if (
+            name.lower().find(pattern) > -1
+            or description.lower().find(pattern) > -1
+            or module_keywords.lower().find(pattern) > -1
+        ):
             return True
         else:
             return False
@@ -304,7 +316,7 @@ def _exact_search(keyword, module_keywords):
     :param keyword: exact keyword to find in the list (not lowercased)
     :param module_keywords: comma separated list of keywords
     """
-    module_keywords = module_keywords.split(',')
+    module_keywords = module_keywords.split(",")
     for current in module_keywords:
         if keyword == current:
             return True
@@ -313,13 +325,14 @@ def _exact_search(keyword, module_keywords):
 
 def _manpage_search(pattern, name):
     try:
-        manpage = grass.read_command('g.manual', flags='m', entry=name)
+        manpage = grass.read_command("g.manual", flags="m", entry=name)
     except CalledModuleError:
         # in case man page is missing
         return False
 
     return manpage.lower().find(pattern) > -1
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     sys.exit(main())

+ 17 - 19
scripts/g.search.modules/testsuite/test_g_search_modules.py

@@ -27,52 +27,50 @@ except ImportError:
 
 
 class TestSearchModule(TestCase):
-
     def test_all_output(self):
-        module = SimpleModule('g.search.modules', flags="g")
+        module = SimpleModule("g.search.modules", flags="g")
         self.assertModule(module)
         stdout = decode(module.outputs.stdout).split()
         # we expect at least 100 hits since we search for all modules
-        assert(len(stdout) > 100)
+        assert len(stdout) > 100
 
     def test_terminal_output(self):
         """ """
-        module = SimpleModule('g.search.modules', keyword="water")
+        module = SimpleModule("g.search.modules", keyword="water")
         self.assertModule(module)
         stdout = decode(module.outputs.stdout)
-        self.assertEqual(stdout.split()[0], 'r.basins.fill')
+        self.assertEqual(stdout.split()[0], "r.basins.fill")
 
     def test_json_output(self):
         import json
-        module = SimpleModule('g.search.modules', keyword="water", flags="j")
+
+        module = SimpleModule("g.search.modules", keyword="water", flags="j")
         self.assertModule(module)
         stdout = json.loads(decode(module.outputs.stdout))
-        self.assertEqual(len(stdout), 6, 'Six modules found')
-        self.assertEqual(stdout[3]['name'], 'r.water.outlet', 'r.water.outlet')
-        self.assertTrue('keywords' in stdout[3]['attributes'])
+        self.assertEqual(len(stdout), 6, "Six modules found")
+        self.assertEqual(stdout[3]["name"], "r.water.outlet", "r.water.outlet")
+        self.assertTrue("keywords" in stdout[3]["attributes"])
 
     def test_shell_output(self):
-        module = SimpleModule('g.search.modules', keyword="water", flags="g")
+        module = SimpleModule("g.search.modules", keyword="water", flags="g")
         self.assertModule(module)
         stdout = decode(module.outputs.stdout).split()
         self.assertEqual(len(stdout), 6)
-        self.assertEqual(stdout[3], 'r.water.outlet')
+        self.assertEqual(stdout[3], "r.water.outlet")
 
-    @unittest.skipUnless(has_termcolor,
-                         "not supported in this library version")
+    @unittest.skipUnless(has_termcolor, "not supported in this library version")
     def test_colored_terminal(self):
-        module = SimpleModule('g.search.modules', keyword="water", flags="c")
+        module = SimpleModule("g.search.modules", keyword="water", flags="c")
         self.assertModule(module)
         stdout = decode(module.outputs.stdout).split()
-        self.assertEqual(stdout[0],
-                         termcolor.colored('r.basins.fill',
-                                           attrs=['bold']))
+        self.assertEqual(stdout[0], termcolor.colored("r.basins.fill", attrs=["bold"]))
 
     def test_manual_pages(self):
-        module = SimpleModule('g.search.modules', keyword="kapri", flags="gm")
+        module = SimpleModule("g.search.modules", keyword="kapri", flags="gm")
         self.assertModule(module)
         stdout = decode(module.outputs.stdout).split()
         self.assertEqual(len(stdout), 2)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 26 - 16
scripts/i.band/i.band.py

@@ -47,6 +47,7 @@ import sys
 import grass.script as gs
 from grass.exceptions import GrassError, OpenError
 
+
 def print_map_band_reference(name, band_reader):
     """Print band reference information assigned to a single raster map
 
@@ -58,13 +59,14 @@ def print_map_band_reference(name, band_reader):
         with RasterRow(name) as rast:
             band_ref = rast.info.band_reference
             if band_ref:
-                shortcut, band = band_ref.split('_')
+                shortcut, band = band_ref.split("_")
                 band_reader.print_info(shortcut, band)
             else:
                 gs.info(_("No band reference assigned to <{}>").format(name))
     except OpenError as e:
         gs.error(_("Map <{}> not found").format(name))
 
+
 def manage_map_band_reference(name, band_ref):
     """Manage band reference assigned to a single raster map
 
@@ -78,11 +80,16 @@ def manage_map_band_reference(name, band_ref):
     try:
         with RasterRow(name) as rast:
             if band_ref:
-                gs.debug(_("Band reference <{}> assigned to raster map <{}>").format(
-                    band_ref, name), 1)
+                gs.debug(
+                    _("Band reference <{}> assigned to raster map <{}>").format(
+                        band_ref, name
+                    ),
+                    1,
+                )
             else:
-                gs.debug(_("Band reference dissociated from raster map <{}>").format(
-                    name), 1)
+                gs.debug(
+                    _("Band reference dissociated from raster map <{}>").format(name), 1
+                )
             try:
                 rast.info.band_reference = band_ref
             except GrassError as e:
@@ -94,21 +101,25 @@ def manage_map_band_reference(name, band_ref):
 
     return 0
 
+
 def main():
-    maps = options['map'].split(',')
-    if options['operation'] == 'add':
-        if not options['band']:
-            gs.fatal(_("Operation {}: required parameter <{}> not set").format(
-                options['operation'], 'band')
+    maps = options["map"].split(",")
+    if options["operation"] == "add":
+        if not options["band"]:
+            gs.fatal(
+                _("Operation {}: required parameter <{}> not set").format(
+                    options["operation"], "band"
+                )
             )
-        bands = options['band'].split(',')
+        bands = options["band"].split(",")
         if len(bands) > 1 and len(bands) != len(maps):
             gs.fatal(_("Number of maps differs from number of bands"))
     else:
         bands = [None]
 
-    if options['operation'] == 'print':
+    if options["operation"] == "print":
         from grass.bandref import BandReferenceReader
+
         band_reader = BandReferenceReader()
     else:
         band_reader = None
@@ -116,7 +127,7 @@ def main():
     ret = 0
     for i in range(len(maps)):
         band_ref = bands[i] if multi_bands else bands[0]
-        if options['operation'] == 'print':
+        if options["operation"] == "print":
             print_map_band_reference(maps[i], band_reader)
         else:
             if manage_map_band_reference(maps[i], band_ref) != 0:
@@ -124,9 +135,8 @@ def main():
 
     return ret
 
+
 if __name__ == "__main__":
     options, flags = gs.parser()
 
-    sys.exit(
-        main()
-    )
+    sys.exit(main())

+ 10 - 9
scripts/i.band/testsuite/test_i_band.py

@@ -4,6 +4,7 @@ from grass.gunittest.gmodules import SimpleModule, call_module
 
 from grass.pygrass.raster import RasterRow
 
+
 class TestBandsSystemDefined(TestCase):
     # note that full NC dataset is needed
     raster_map = "lsat7_2002_10"
@@ -17,28 +18,28 @@ class TestBandsSystemDefined(TestCase):
 
     def test_band_ref_assign_not_current_mapset(self):
         # it is assumed that we are not in PERMANENT mapset
-        module = SimpleModule('i.band', map=self.raster_map + '@PERMANENT',
-                              band=self.band_ref)
+        module = SimpleModule(
+            "i.band", map=self.raster_map + "@PERMANENT", band=self.band_ref
+        )
         self.assertModuleFail(module)
 
     def test_band_ref_assign(self):
-        # copy raster map to the current mapset
-        call_module('g.copy',
-                    raster='{m}@PERMANENT,{m}'.format(m=self.raster_map))
+        # Copy raster map to the current mapset
+        call_module("g.copy", raster="{m}@PERMANENT,{m}".format(m=self.raster_map))
 
-        module = SimpleModule('i.band', map=self.raster_map,
-                              band=self.band_ref)
+        module = SimpleModule("i.band", map=self.raster_map, band=self.band_ref)
         self.assertModule(module)
 
         # check also using pygrass
         self.assertEqual(self.read_band_ref(), self.band_ref)
 
     def test_band_ref_dissociate(self):
-        module = SimpleModule('i.band', operation='remove' , map=self.raster_map)
+        module = SimpleModule("i.band", operation="remove", map=self.raster_map)
         self.assertModule(module)
 
         # check also using pygrass
         self.assertEqual(self.read_band_ref(), None)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 49 - 37
scripts/i.colors.enhance/i.colors.enhance.py

@@ -5,7 +5,7 @@
 # MODULE:	i.colors.enhance (former i.landsat.rgb)
 #
 # AUTHOR(S):	Markus Neteler, original author
-#		Hamish Bowman, scripting enhancements
+# 		Hamish Bowman, scripting enhancements
 #               Converted to Python by Glynn Clements
 #
 # PURPOSE:      create pretty RGBs: the trick is to remove outliers
@@ -13,9 +13,9 @@
 #
 # COPYRIGHT:	(C) 2006, 2008, 2012-2014 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.
+# 		This program is free software under the GNU General Public
+# 		License (>=v2). Read the file COPYING that comes with GRASS
+# 		for details.
 #
 # TODO: implement better brightness control
 #############################################################################
@@ -74,6 +74,7 @@ import grass.script as gscript
 try:
     # new for python 2.6, in 2.5 it may be easy_install'd.
     import multiprocessing as mp
+
     do_mp = True
 except:
     do_mp = False
@@ -83,15 +84,15 @@ def get_percentile(map, percentiles):
     # todo: generalize for any list length
     val1 = percentiles[0]
     val2 = percentiles[1]
-    values = '%s,%s' % (val1, val2)
+    values = "%s,%s" % (val1, val2)
 
-    s = gscript.read_command('r.quantile', input=map,
-                             percentiles=values, quiet=True)
+    s = gscript.read_command("r.quantile", input=map, percentiles=values, quiet=True)
 
-    val_str1 = s.splitlines()[0].split(':')[2]
-    val_str2 = s.splitlines()[1].split(':')[2]
+    val_str1 = s.splitlines()[0].split(":")[2]
+    val_str2 = s.splitlines()[1].split(":")[2]
     return (float(val_str1), float(val_str2))
 
+
 # wrapper to handle multiprocesses communications back to the parent
 
 
@@ -103,36 +104,36 @@ def get_percentile_mp(map, percentiles, conn):
     output_pipe, input_pipe = conn
     input_pipe.close()
     result = get_percentile(map, percentiles)
-    gscript.debug('child (%s) (%.1f, %.1f)' % (map, result[0], result[1]))
+    gscript.debug("child (%s) (%.1f, %.1f)" % (map, result[0], result[1]))
     output_pipe.send(result)
     output_pipe.close()
 
 
 def set_colors(map, v0, v1):
-    rules = ''.join(["0% black\n", "%f black\n" % v0,
-                     "%f white\n" % v1, "100% white\n"])
-    gscript.write_command('r.colors', map=map, rules='-', stdin=rules,
-                          quiet=True)
+    rules = "".join(
+        ["0% black\n", "%f black\n" % v0, "%f white\n" % v1, "100% white\n"]
+    )
+    gscript.write_command("r.colors", map=map, rules="-", stdin=rules, quiet=True)
 
 
 def main():
-    red = options['red']
-    green = options['green']
-    blue = options['blue']
-    brightness = options['strength']
-    full = flags['f']
-    preserve = flags['p']
-    reset = flags['r']
+    red = options["red"]
+    green = options["green"]
+    blue = options["blue"]
+    brightness = options["strength"]
+    full = flags["f"]
+    preserve = flags["p"]
+    reset = flags["r"]
 
     global do_mp
 
-    if flags['s']:
+    if flags["s"]:
         do_mp = False
 
     check = True
     for m in [red, green, blue]:
         ex = gscript.find_file(m)
-        if ex['name'] == '':
+        if ex["name"] == "":
             check = False
             gscript.warning("Raster map <{}> not found ".format(m))
     if not check:
@@ -143,12 +144,12 @@ def main():
 
     if full:
         for i in [red, green, blue]:
-            gscript.run_command('r.colors', map=i, color='grey', quiet=True)
+            gscript.run_command("r.colors", map=i, color="grey", quiet=True)
         sys.exit(0)
 
     if reset:
         for i in [red, green, blue]:
-            gscript.run_command('r.colors', map=i, color='grey255', quiet=True)
+            gscript.run_command("r.colors", map=i, color="grey255", quiet=True)
         sys.exit(0)
 
     if not preserve:
@@ -159,9 +160,14 @@ def main():
             conn = {}
             for i in [red, green, blue]:
                 conn[i] = mp.Pipe()
-                proc[i] = mp.Process(target=get_percentile_mp,
-                                     args=(i, ['2', brightness],
-                                           conn[i],))
+                proc[i] = mp.Process(
+                    target=get_percentile_mp,
+                    args=(
+                        i,
+                        ["2", brightness],
+                        conn[i],
+                    ),
+                )
                 proc[i].start()
             gscript.percent(1, 2, 1)
 
@@ -169,7 +175,7 @@ def main():
             for i in [red, green, blue]:
                 output_pipe, input_pipe = conn[i]
                 (v0, v1) = input_pipe.recv()
-                gscript.debug('parent (%s) (%.1f, %.1f)' % (i, v0, v1))
+                gscript.debug("parent (%s) (%.1f, %.1f)" % (i, v0, v1))
                 input_pipe.close()
                 proc[i].join()
                 set_colors(i, v0, v1)
@@ -177,7 +183,7 @@ def main():
         else:
             for i in [red, green, blue]:
                 gscript.message(_("Processing..."))
-                (v0, v1) = get_percentile(i, ['2', brightness])
+                (v0, v1) = get_percentile(i, ["2", brightness])
                 gscript.debug("<%s>:  min=%f   max=%f" % (i, v0, v1))
                 set_colors(i, v0, v1)
 
@@ -192,9 +198,14 @@ def main():
             conn = {}
             for i in [red, green, blue]:
                 conn[i] = mp.Pipe()
-                proc[i] = mp.Process(target=get_percentile_mp,
-                                     args=(i, ['2', brightness],
-                                           conn[i],))
+                proc[i] = mp.Process(
+                    target=get_percentile_mp,
+                    args=(
+                        i,
+                        ["2", brightness],
+                        conn[i],
+                    ),
+                )
                 proc[i].start()
             gscript.percent(1, 2, 1)
 
@@ -202,7 +213,7 @@ def main():
             for i in [red, green, blue]:
                 output_pipe, input_pipe = conn[i]
                 (v0, v1) = input_pipe.recv()
-                gscript.debug('parent (%s) (%.1f, %.1f)' % (i, v0, v1))
+                gscript.debug("parent (%s) (%.1f, %.1f)" % (i, v0, v1))
                 input_pipe.close()
                 proc[i].join()
                 all_min = min(all_min, v0)
@@ -211,7 +222,7 @@ def main():
         else:
             for i in [red, green, blue]:
                 gscript.message(_("Processing..."))
-                (v0, v1) = get_percentile(i, ['2', brightness])
+                (v0, v1) = get_percentile(i, ["2", brightness])
                 gscript.debug("<%s>:  min=%f   max=%f" % (i, v0, v1))
                 all_min = min(all_min, v0)
                 all_max = max(all_max, v1)
@@ -221,11 +232,12 @@ def main():
             set_colors(i, all_min, all_max)
 
     # write cmd history:
-    mapset = gscript.gisenv()['MAPSET']
+    mapset = gscript.gisenv()["MAPSET"]
     for i in [red, green, blue]:
-        if gscript.find_file(i)['mapset'] == mapset:
+        if gscript.find_file(i)["mapset"] == mapset:
             gscript.raster_history(i)
 
+
 if __name__ == "__main__":
     options, flags = gscript.parser()
     main()

+ 14 - 14
scripts/i.image.mosaic/i.image.mosaic.py

@@ -19,7 +19,7 @@
 #       - fix color table length (currently only 256 cols supported, make
 #         flexible)
 #            [done for 2 maps]
-#--------------------------------------------------
+# --------------------------------------------------
 
 
 # %module
@@ -38,19 +38,19 @@ import grass.script as gscript
 
 
 def copy_colors(fh, map, offset):
-    p = gscript.pipe_command('r.colors.out', map=map)
+    p = gscript.pipe_command("r.colors.out", map=map)
     for line in p.stdout:
-        f = gscript.decode(line).rstrip('\r\n').split(' ')
+        f = gscript.decode(line).rstrip("\r\n").split(" ")
         if offset:
-            if f[0] in ['nv', 'default']:
+            if f[0] in ["nv", "default"]:
                 continue
             f[0] = str(float(f[0]) + offset)
-        fh.write(gscript.encode(' '.join(f) + '\n'))
+        fh.write(gscript.encode(" ".join(f) + "\n"))
     p.wait()
 
 
 def get_limit(map):
-    return gscript.raster_info(map)['max']
+    return gscript.raster_info(map)["max"]
 
 
 def make_expression(i, count):
@@ -62,11 +62,11 @@ def make_expression(i, count):
 
 
 def main():
-    images = options['input'].split(',')
-    output = options['output']
+    images = options["input"].split(",")
+    output = options["output"]
 
     count = len(images)
-    msg = _('Do not forget to set region properly to cover all images.')
+    msg = _("Do not forget to set region properly to cover all images.")
     gscript.warning(msg)
 
     offset = 0
@@ -74,17 +74,16 @@ def main():
     parms = {}
     for n, img in enumerate(images):
         offsets.append(offset)
-        parms['image%d' % (n + 1)] = img
-        parms['offset%d' % (n + 1)] = offset
+        parms["image%d" % (n + 1)] = img
+        parms["offset%d" % (n + 1)] = offset
         offset += get_limit(img) + 1
 
     gscript.message(_("Mosaicing %d images...") % count)
 
-    gscript.mapcalc("$output = " + make_expression(1, count),
-                    output=output, **parms)
+    gscript.mapcalc("$output = " + make_expression(1, count), output=output, **parms)
 
     # modify the color table:
-    p = gscript.feed_command('r.colors', map=output, rules='-')
+    p = gscript.feed_command("r.colors", map=output, rules="-")
     for img, offset in zip(images, offsets):
         print(img, offset)
         copy_colors(p.stdin, img, offset)
@@ -96,6 +95,7 @@ def main():
     # write cmd history:
     gscript.raster_history(output)
 
+
 if __name__ == "__main__":
     options, flags = gscript.parser()
     main()

+ 71 - 53
scripts/i.in.spotvgt/i.in.spotvgt.py

@@ -76,19 +76,19 @@ def create_VRT_file(projfile, vrtfile, infile):
     fh = open(projfile)
     kv = {}
     for l in fh:
-        f = l.rstrip('\r\n').split()
+        f = l.rstrip("\r\n").split()
         if f < 2:
             continue
         kv[f[0]] = f[1]
     fh.close()
 
-    north_center = kv['CARTO_UPPER_LEFT_Y']
+    north_center = kv["CARTO_UPPER_LEFT_Y"]
     # south_center = kv['CARTO_LOWER_LEFT_Y']
     # east_center = kv['CARTO_UPPER_RIGHT_X']
-    west_center = kv['CARTO_UPPER_LEFT_X']
-    map_proj_res = kv['MAP_PROJ_RESOLUTION']
-    xsize = kv['IMAGE_UPPER_RIGHT_COL']
-    ysize = kv['IMAGE_LOWER_RIGHT_ROW']
+    west_center = kv["CARTO_UPPER_LEFT_X"]
+    map_proj_res = kv["MAP_PROJ_RESOLUTION"]
+    xsize = kv["IMAGE_UPPER_RIGHT_COL"]
+    ysize = kv["IMAGE_LOWER_RIGHT_ROW"]
 
     resolution = float(map_proj_res)
     north_corner = float(north_center) + resolution / 2
@@ -97,10 +97,15 @@ def create_VRT_file(projfile, vrtfile, infile):
     west_corner = float(west_center) - resolution / 2
 
     t = string.Template(vrt)
-    s = t.substitute(NORTHCORNER=north_corner, WESTCORNER=west_corner,
-                     XSIZE=xsize, YSIZE=ysize, RESOLUTION=map_proj_res,
-                     FILENAME=infile)
-    outf = open(vrtfile, 'w')
+    s = t.substitute(
+        NORTHCORNER=north_corner,
+        WESTCORNER=west_corner,
+        XSIZE=xsize,
+        YSIZE=ysize,
+        RESOLUTION=map_proj_res,
+        FILENAME=infile,
+    )
+    outf = open(vrtfile, "w")
     outf.write(s)
     outf.close()
 
@@ -114,14 +119,15 @@ def cleanup():
 def main():
     global vrtfile, tmpfile
 
-    infile = options['input']
-    rast = options['output']
-    also = flags['a']
+    infile = options["input"]
+    rast = options["output"]
+    also = flags["a"]
 
     # check for gdalinfo (just to check if installation is complete)
-    if not gscript.find_program('gdalinfo', '--help'):
-        gscript.fatal(_("'gdalinfo' not found, install GDAL tools first "
-                        "(http://www.gdal.org)"))
+    if not gscript.find_program("gdalinfo", "--help"):
+        gscript.fatal(
+            _("'gdalinfo' not found, install GDAL tools first " "(http://www.gdal.org)")
+        )
 
     pid = str(os.getpid())
     tmpfile = gscript.tempfile()
@@ -129,23 +135,23 @@ def main():
     # let's go
 
     spotdir = os.path.dirname(infile)
-    spotname = gscript.basename(infile, 'hdf')
+    spotname = gscript.basename(infile, "hdf")
 
     if rast:
         name = rast
     else:
         name = spotname
 
-    if not gscript.overwrite() and gscript.find_file(name)['file']:
+    if not gscript.overwrite() and gscript.find_file(name)["file"]:
         gscript.fatal(_("<%s> already exists. Aborting.") % name)
 
     # still a ZIP file?  (is this portable?? see the r.in.srtm script for
     # ideas)
-    if infile.lower().endswith('.zip'):
+    if infile.lower().endswith(".zip"):
         gscript.fatal(_("Please extract %s before import.") % infile)
 
     try:
-        p = gscript.Popen(['file', '-ib', infile], stdout=gscript.PIPE)
+        p = gscript.Popen(["file", "-ib", infile], stdout=gscript.PIPE)
         s = p.communicate()[0]
         if s == "application/x-zip":
             gscript.fatal(_("Please extract %s before import.") % infile)
@@ -155,7 +161,7 @@ def main():
     # create VRT header for NDVI
 
     projfile = os.path.join(spotdir, "0001_LOG.TXT")
-    vrtfile = tmpfile + '.vrt'
+    vrtfile = tmpfile + ".vrt"
 
     # first process the NDVI:
     gscript.try_remove(vrtfile)
@@ -164,7 +170,7 @@ def main():
     # let's import the NDVI map...
     gscript.message(_("Importing SPOT VGT NDVI map..."))
     try:
-        gscript.run_command('r.in.gdal', input=vrtfile, output=name)
+        gscript.run_command("r.in.gdal", input=vrtfile, output=name)
     except CalledModuleError:
         gscript.fatal(_("An error occurred. Stop."))
 
@@ -183,20 +189,19 @@ def main():
     # switch to a temporary region
     gscript.use_temp_region()
 
-    gscript.run_command('g.region', raster=name, quiet=True)
+    gscript.run_command("g.region", raster=name, quiet=True)
 
     gscript.message(_("Remapping digital numbers to NDVI..."))
     tmpname = "%s_%s" % (name, pid)
     gscript.mapcalc("$tmpname = 0.004 * $name - 0.1", tmpname=tmpname, name=name)
-    gscript.run_command('g.remove', type='raster', name=name, quiet=True,
-                        flags='f')
-    gscript.run_command('g.rename', raster=(tmpname, name), quiet=True)
+    gscript.run_command("g.remove", type="raster", name=name, quiet=True, flags="f")
+    gscript.run_command("g.rename", raster=(tmpname, name), quiet=True)
 
     # write cmd history:
     gscript.raster_history(name)
 
     # apply color table:
-    gscript.run_command('r.colors', map=name, color='ndvi', quiet=True)
+    gscript.run_command("r.colors", map=name, color="ndvi", quiet=True)
 
     ##########################
     # second, optionally process the SM quality map:
@@ -229,45 +234,57 @@ def main():
     if also:
         gscript.message(_("Importing SPOT VGT NDVI quality map..."))
         gscript.try_remove(vrtfile)
-        qname = spotname.replace('NDV', 'SM')
+        qname = spotname.replace("NDV", "SM")
         qfile = os.path.join(spotdir, qname)
         create_VRT_file(projfile, vrtfile, qfile)
 
         # let's import the SM quality map...
-        smfile = name + '.sm'
+        smfile = name + ".sm"
         try:
-            gscript.run_command('r.in.gdal', input=vrtfile, output=smfile)
+            gscript.run_command("r.in.gdal", input=vrtfile, output=smfile)
         except CalledModuleError:
             gscript.fatal(_("An error occurred. Stop."))
 
         # some of the possible values:
-        rules = [r + '\n' for r in ['8 50 50 50',
-                                    '11 70 70 70',
-                                    '12 90 90 90',
-                                    '60 grey',
-                                    '155 blue',
-                                    '232 violet',
-                                    '235 red',
-                                    '236 brown',
-                                    '248 orange',
-                                    '251 yellow',
-                                    '252 green']]
-        gscript.write_command('r.colors', map=smfile, rules='-', stdin=rules)
-
-        gscript.message(_("Imported SPOT VEGETATION SM quality map <%s>.") %
-                        smfile)
-        gscript.message(_("Note: A snow map can be extracted by category "
-                          "252 (d.rast %s cat=252)") % smfile)
+        rules = [
+            r + "\n"
+            for r in [
+                "8 50 50 50",
+                "11 70 70 70",
+                "12 90 90 90",
+                "60 grey",
+                "155 blue",
+                "232 violet",
+                "235 red",
+                "236 brown",
+                "248 orange",
+                "251 yellow",
+                "252 green",
+            ]
+        ]
+        gscript.write_command("r.colors", map=smfile, rules="-", stdin=rules)
+
+        gscript.message(_("Imported SPOT VEGETATION SM quality map <%s>.") % smfile)
+        gscript.message(
+            _(
+                "Note: A snow map can be extracted by category "
+                "252 (d.rast %s cat=252)"
+            )
+            % smfile
+        )
         gscript.message("")
         gscript.message(_("Filtering NDVI map by Status Map quality layer..."))
 
         filtfile = "%s_filt" % name
-        gscript.mapcalc("$filtfile = if($smfile % 4 == 3 || "
-                        "($smfile / 16) % 16 == 0, null(), $name)",
-                        filtfile=filtfile, smfile=smfile, name=name)
-        gscript.run_command('r.colors', map=filtfile, color='ndvi', quiet=True)
-        gscript.message(_("Filtered SPOT VEGETATION NDVI map <%s>.") %
-                        filtfile)
+        gscript.mapcalc(
+            "$filtfile = if($smfile % 4 == 3 || "
+            "($smfile / 16) % 16 == 0, null(), $name)",
+            filtfile=filtfile,
+            smfile=smfile,
+            name=name,
+        )
+        gscript.run_command("r.colors", map=filtfile, color="ndvi", quiet=True)
+        gscript.message(_("Filtered SPOT VEGETATION NDVI map <%s>.") % filtfile)
 
         # write cmd history:
         gscript.raster_history(smfile)
@@ -275,6 +292,7 @@ def main():
 
     gscript.message(_("Done."))
 
+
 if __name__ == "__main__":
     options, flags = gscript.parser()
     atexit.register(cleanup)

+ 20 - 18
scripts/i.oif/i.oif.py

@@ -47,8 +47,7 @@ from grass.script import core as grass
 
 
 def oifcalc(sdev, corr, k1, k2, k3):
-    grass.debug(_("Calculating OIF for combination: %s, %s, %s" % (k1, k2,
-                                                                   k3)), 1)
+    grass.debug(_("Calculating OIF for combination: %s, %s, %s" % (k1, k2, k3)), 1)
     # calculate SUM of Stddeviations:
     ssdev = [sdev[k1], sdev[k2], sdev[k3]]
     numer = sum(ssdev)
@@ -71,14 +70,14 @@ def perms(bands):
 
 
 def main():
-    shell = flags['g']
-    serial = flags['s']
-    bands = options['input'].split(',')
+    shell = flags["g"]
+    serial = flags["s"]
+    bands = options["input"].split(",")
 
     if len(bands) < 4:
         grass.fatal(_("At least four input maps required"))
 
-    output = options['output']
+    output = options["output"]
     # calculate the Stddev for TM bands
     grass.message(_("Calculating standard deviations for all bands..."))
     stddev = {}
@@ -86,9 +85,9 @@ def main():
     if serial:
         for band in bands:
             grass.verbose("band %d" % band)
-            s = grass.read_command('r.univar', flags='g', map=band)
+            s = grass.read_command("r.univar", flags="g", map=band)
             kv = parse_key_val(s)
-            stddev[band] = float(kv['stddev'])
+            stddev[band] = float(kv["stddev"])
     else:
         # run all bands in parallel
         if "WORKERS" in os.environ:
@@ -101,7 +100,7 @@ def main():
         # spawn jobs in the background
         n = 0
         for band in bands:
-            proc[band] = grass.pipe_command('r.univar', flags='g', map=band)
+            proc[band] = grass.pipe_command("r.univar", flags="g", map=band)
             if n % workers == 0:
                 # wait for the ones launched so far to finish
                 for bandp in bands[:n]:
@@ -116,20 +115,21 @@ def main():
                 pout[band] = proc[band].communicate()[0]
             proc[band].wait()
 
-    # parse the results
+        # parse the results
         for band in bands:
             kv = parse_key_val(pout[band])
-            stddev[band] = float(kv['stddev'])
+            stddev[band] = float(kv["stddev"])
 
     grass.message(_("Calculating Correlation Matrix..."))
     correlation = {}
-    s = grass.read_command('r.covar', flags='r', map=[band for band in bands],
-                           quiet=True)
+    s = grass.read_command(
+        "r.covar", flags="r", map=[band for band in bands], quiet=True
+    )
 
     # We need to skip the first line, since r.covar prints the number of values
     lines = s.splitlines()
     for i, row in zip(bands, lines[1:]):
-        for j, cell in zip(bands, row.split(' ')):
+        for j, cell in zip(bands, row.split(" ")):
             correlation[i, j] = float(cell)
 
     # Calculate all combinations
@@ -140,23 +140,25 @@ def main():
         oif.append((oifcalc(stddev, correlation, *p), p))
     oif.sort(reverse=True)
 
-    grass.verbose(_("The Optimum Index Factor analysis result "
-                    "(best combination shown first):"))
+    grass.verbose(
+        _("The Optimum Index Factor analysis result " "(best combination shown first):")
+    )
 
     if shell:
         fmt = "%s,%s,%s:%.4f\n"
     else:
         fmt = "%s, %s, %s:  %.4f\n"
 
-    if not output or output == '-':
+    if not output or output == "-":
         for v, p in oif:
             sys.stdout.write(fmt % (p + (v,)))
     else:
-        outf = open(output, 'w')
+        outf = open(output, "w")
         for v, p in oif:
             outf.write(fmt % (p + (v,)))
         outf.close()
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     main()

+ 422 - 237
scripts/i.pansharpen/i.pansharpen.py

@@ -16,9 +16,9 @@
 #
 # COPYRIGHT:	(C) 2002-2019 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.
+# 		This program is free software under the GNU General Public
+# 		License (>=v2). Read the file COPYING that comes with GRASS
+# 		for details.
 #
 # REFERENCES:
 #   Roller, N.E.G. and Cox, S., 1980. Comparison of Landsat MSS and merged MSS/RBV
@@ -96,6 +96,7 @@ import os
 
 try:
     import numpy as np
+
     hasNumPy = True
 except ImportError:
     hasNumPy = False
@@ -107,16 +108,16 @@ def main():
     if not hasNumPy:
         grass.fatal(_("Required dependency NumPy not found. Exiting."))
 
-    sharpen   = options['method']  # sharpening algorithm
-    ms1_orig  = options['blue']  # blue channel
-    ms2_orig  = options['green']  # green channel
-    ms3_orig  = options['red']  # red channel
-    pan_orig  = options['pan']  # high res pan channel
-    out       = options['output']  # prefix for output RGB maps
-    bits      = options['bitdepth'] # bit depth of image channels
-    bladjust  = flags['l']  # adjust blue channel
-    sproc     = flags['s']  # serial processing
-    rescale   = flags['r'] # rescale to spread pixel values to entire 0-255 range
+    sharpen = options["method"]  # sharpening algorithm
+    ms1_orig = options["blue"]  # blue channel
+    ms2_orig = options["green"]  # green channel
+    ms3_orig = options["red"]  # red channel
+    pan_orig = options["pan"]  # high res pan channel
+    out = options["output"]  # prefix for output RGB maps
+    bits = options["bitdepth"]  # bit depth of image channels
+    bladjust = flags["l"]  # adjust blue channel
+    sproc = flags["s"]  # serial processing
+    rescale = flags["r"]  # rescale to spread pixel values to entire 0-255 range
 
     # Checking bit depth
     bits = float(bits)
@@ -124,46 +125,84 @@ def main():
         grass.warning(_("Bit depth is outside acceptable range"))
         return
 
-    outb = grass.core.find_file('%s_blue' % out)
-    outg = grass.core.find_file('%s_green' % out)
-    outr = grass.core.find_file('%s_red' % out)
-
-    if (outb['name'] != '' or outg['name'] != '' or outr['name'] != '') and not grass.overwrite():
-        grass.warning(_('Maps with selected output prefix names already exist.'
-                        ' Delete them or use overwrite flag'))
+    outb = grass.core.find_file("%s_blue" % out)
+    outg = grass.core.find_file("%s_green" % out)
+    outr = grass.core.find_file("%s_red" % out)
+
+    if (
+        outb["name"] != "" or outg["name"] != "" or outr["name"] != ""
+    ) and not grass.overwrite():
+        grass.warning(
+            _(
+                "Maps with selected output prefix names already exist."
+                " Delete them or use overwrite flag"
+            )
+        )
         return
 
     pid = str(os.getpid())
 
     # convert input image channels to 8 bit for processing
-    ms1 = 'tmp%s_ms1' % pid
-    ms2 = 'tmp%s_ms2' % pid
-    ms3 = 'tmp%s_ms3' % pid
-    pan = 'tmp%s_pan' % pid
+    ms1 = "tmp%s_ms1" % pid
+    ms2 = "tmp%s_ms2" % pid
+    ms3 = "tmp%s_ms3" % pid
+    pan = "tmp%s_pan" % pid
 
     if not rescale:
         if bits == 8:
             grass.message(_("Using 8bit image channels"))
             if sproc:
                 # serial processing
-                grass.run_command('g.copy', raster='%s,%s' % (ms1_orig, ms1),
-                                   quiet=True, overwrite=True)
-                grass.run_command('g.copy', raster='%s,%s' % (ms2_orig, ms2),
-                                   quiet=True, overwrite=True)
-                grass.run_command('g.copy', raster='%s,%s' % (ms3_orig, ms3),
-                                   quiet=True, overwrite=True)
-                grass.run_command('g.copy', raster='%s,%s' % (pan_orig, pan),
-                                   quiet=True, overwrite=True)
+                grass.run_command(
+                    "g.copy",
+                    raster="%s,%s" % (ms1_orig, ms1),
+                    quiet=True,
+                    overwrite=True,
+                )
+                grass.run_command(
+                    "g.copy",
+                    raster="%s,%s" % (ms2_orig, ms2),
+                    quiet=True,
+                    overwrite=True,
+                )
+                grass.run_command(
+                    "g.copy",
+                    raster="%s,%s" % (ms3_orig, ms3),
+                    quiet=True,
+                    overwrite=True,
+                )
+                grass.run_command(
+                    "g.copy",
+                    raster="%s,%s" % (pan_orig, pan),
+                    quiet=True,
+                    overwrite=True,
+                )
             else:
                 # parallel processing
-                pb = grass.start_command('g.copy', raster='%s,%s' % (ms1_orig, ms1),
-                                       quiet=True, overwrite=True)
-                pg = grass.start_command('g.copy', raster='%s,%s' % (ms2_orig, ms2),
-                                       quiet=True, overwrite=True)
-                pr = grass.start_command('g.copy', raster='%s,%s' % (ms3_orig, ms3),
-                                       quiet=True, overwrite=True)
-                pp = grass.start_command('g.copy', raster='%s,%s' % (pan_orig, pan),
-                                       quiet=True, overwrite=True)
+                pb = grass.start_command(
+                    "g.copy",
+                    raster="%s,%s" % (ms1_orig, ms1),
+                    quiet=True,
+                    overwrite=True,
+                )
+                pg = grass.start_command(
+                    "g.copy",
+                    raster="%s,%s" % (ms2_orig, ms2),
+                    quiet=True,
+                    overwrite=True,
+                )
+                pr = grass.start_command(
+                    "g.copy",
+                    raster="%s,%s" % (ms3_orig, ms3),
+                    quiet=True,
+                    overwrite=True,
+                )
+                pp = grass.start_command(
+                    "g.copy",
+                    raster="%s,%s" % (pan_orig, pan),
+                    quiet=True,
+                    overwrite=True,
+                )
 
                 pb.wait()
                 pg.wait()
@@ -175,25 +214,81 @@ def main():
             maxval = pow(2, bits) - 1
             if sproc:
                 # serial processing
-                grass.run_command('r.rescale', input=ms1_orig, from_='0,%f' % maxval,
-                                   output=ms1, to='0,255', quiet=True, overwrite=True)
-                grass.run_command('r.rescale', input=ms2_orig, from_='0,%f' % maxval,
-                                   output=ms2, to='0,255', quiet=True, overwrite=True)
-                grass.run_command('r.rescale', input=ms3_orig, from_='0,%f' % maxval,
-                                   output=ms3, to='0,255', quiet=True, overwrite=True)
-                grass.run_command('r.rescale', input=pan_orig, from_='0,%f' % maxval,
-                                   output=pan, to='0,255', quiet=True, overwrite=True)
+                grass.run_command(
+                    "r.rescale",
+                    input=ms1_orig,
+                    from_="0,%f" % maxval,
+                    output=ms1,
+                    to="0,255",
+                    quiet=True,
+                    overwrite=True,
+                )
+                grass.run_command(
+                    "r.rescale",
+                    input=ms2_orig,
+                    from_="0,%f" % maxval,
+                    output=ms2,
+                    to="0,255",
+                    quiet=True,
+                    overwrite=True,
+                )
+                grass.run_command(
+                    "r.rescale",
+                    input=ms3_orig,
+                    from_="0,%f" % maxval,
+                    output=ms3,
+                    to="0,255",
+                    quiet=True,
+                    overwrite=True,
+                )
+                grass.run_command(
+                    "r.rescale",
+                    input=pan_orig,
+                    from_="0,%f" % maxval,
+                    output=pan,
+                    to="0,255",
+                    quiet=True,
+                    overwrite=True,
+                )
 
             else:
                 # parallel processing
-                pb = grass.start_command('r.rescale', input=ms1_orig, from_='0,%f' % maxval,
-                                       output=ms1, to='0,255', quiet=True, overwrite=True)
-                pg = grass.start_command('r.rescale', input=ms2_orig, from_='0,%f' % maxval,
-                                       output=ms2, to='0,255', quiet=True, overwrite=True)
-                pr = grass.start_command('r.rescale', input=ms3_orig, from_='0,%f' % maxval,
-                                       output=ms3, to='0,255', quiet=True, overwrite=True)
-                pp = grass.start_command('r.rescale', input=pan_orig, from_='0,%f' % maxval,
-                                       output=pan, to='0,255', quiet=True, overwrite=True)
+                pb = grass.start_command(
+                    "r.rescale",
+                    input=ms1_orig,
+                    from_="0,%f" % maxval,
+                    output=ms1,
+                    to="0,255",
+                    quiet=True,
+                    overwrite=True,
+                )
+                pg = grass.start_command(
+                    "r.rescale",
+                    input=ms2_orig,
+                    from_="0,%f" % maxval,
+                    output=ms2,
+                    to="0,255",
+                    quiet=True,
+                    overwrite=True,
+                )
+                pr = grass.start_command(
+                    "r.rescale",
+                    input=ms3_orig,
+                    from_="0,%f" % maxval,
+                    output=ms3,
+                    to="0,255",
+                    quiet=True,
+                    overwrite=True,
+                )
+                pp = grass.start_command(
+                    "r.rescale",
+                    input=pan_orig,
+                    from_="0,%f" % maxval,
+                    output=pan,
+                    to="0,255",
+                    quiet=True,
+                    overwrite=True,
+                )
 
                 pb.wait()
                 pg.wait()
@@ -203,53 +298,108 @@ def main():
     else:
         grass.message(_("Rescaling image chanels to 8bit for processing"))
 
-        min_ms1 = int(grass.raster_info(ms1_orig)['min'])
-        max_ms1 = int(grass.raster_info(ms1_orig)['max'])
-        min_ms2 = int(grass.raster_info(ms2_orig)['min'])
-        max_ms2 = int(grass.raster_info(ms2_orig)['max'])
-        min_ms3 = int(grass.raster_info(ms3_orig)['min'])
-        max_ms3 = int(grass.raster_info(ms3_orig)['max'])
-        min_pan = int(grass.raster_info(pan_orig)['min'])
-        max_pan = int(grass.raster_info(pan_orig)['max'])
+        min_ms1 = int(grass.raster_info(ms1_orig)["min"])
+        max_ms1 = int(grass.raster_info(ms1_orig)["max"])
+        min_ms2 = int(grass.raster_info(ms2_orig)["min"])
+        max_ms2 = int(grass.raster_info(ms2_orig)["max"])
+        min_ms3 = int(grass.raster_info(ms3_orig)["min"])
+        max_ms3 = int(grass.raster_info(ms3_orig)["max"])
+        min_pan = int(grass.raster_info(pan_orig)["min"])
+        max_pan = int(grass.raster_info(pan_orig)["max"])
 
         maxval = pow(2, bits) - 1
         if sproc:
             # serial processing
-            grass.run_command('r.rescale', input=ms1_orig, from_='%f,%f' % (min_ms1, max_ms1),
-                               output=ms1, to='0,255', quiet=True, overwrite=True)
-            grass.run_command('r.rescale', input=ms2_orig, from_='%f,%f' % (min_ms2, max_ms2),
-                               output=ms2, to='0,255', quiet=True, overwrite=True)
-            grass.run_command('r.rescale', input=ms3_orig, from_='%f,%f' % (min_ms3, max_ms3),
-                               output=ms3, to='0,255', quiet=True, overwrite=True)
-            grass.run_command('r.rescale', input=pan_orig, from_='%f,%f' % (min_pan, max_pan),
-                               output=pan, to='0,255', quiet=True, overwrite=True)
+            grass.run_command(
+                "r.rescale",
+                input=ms1_orig,
+                from_="%f,%f" % (min_ms1, max_ms1),
+                output=ms1,
+                to="0,255",
+                quiet=True,
+                overwrite=True,
+            )
+            grass.run_command(
+                "r.rescale",
+                input=ms2_orig,
+                from_="%f,%f" % (min_ms2, max_ms2),
+                output=ms2,
+                to="0,255",
+                quiet=True,
+                overwrite=True,
+            )
+            grass.run_command(
+                "r.rescale",
+                input=ms3_orig,
+                from_="%f,%f" % (min_ms3, max_ms3),
+                output=ms3,
+                to="0,255",
+                quiet=True,
+                overwrite=True,
+            )
+            grass.run_command(
+                "r.rescale",
+                input=pan_orig,
+                from_="%f,%f" % (min_pan, max_pan),
+                output=pan,
+                to="0,255",
+                quiet=True,
+                overwrite=True,
+            )
 
         else:
             # parallel processing
-            pb = grass.start_command('r.rescale', input=ms1_orig, from_='%f,%f' % (min_ms1, max_ms1),
-                                   output=ms1, to='0,255', quiet=True, overwrite=True)
-            pg = grass.start_command('r.rescale', input=ms2_orig, from_='%f,%f' % (min_ms2, max_ms2),
-                                   output=ms2, to='0,255', quiet=True, overwrite=True)
-            pr = grass.start_command('r.rescale', input=ms3_orig, from_='%f,%f' % (min_ms3, max_ms3),
-                                   output=ms3, to='0,255', quiet=True, overwrite=True)
-            pp = grass.start_command('r.rescale', input=pan_orig, from_='%f,%f' % (min_pan, max_pan),
-                                   output=pan, to='0,255', quiet=True, overwrite=True)
+            pb = grass.start_command(
+                "r.rescale",
+                input=ms1_orig,
+                from_="%f,%f" % (min_ms1, max_ms1),
+                output=ms1,
+                to="0,255",
+                quiet=True,
+                overwrite=True,
+            )
+            pg = grass.start_command(
+                "r.rescale",
+                input=ms2_orig,
+                from_="%f,%f" % (min_ms2, max_ms2),
+                output=ms2,
+                to="0,255",
+                quiet=True,
+                overwrite=True,
+            )
+            pr = grass.start_command(
+                "r.rescale",
+                input=ms3_orig,
+                from_="%f,%f" % (min_ms3, max_ms3),
+                output=ms3,
+                to="0,255",
+                quiet=True,
+                overwrite=True,
+            )
+            pp = grass.start_command(
+                "r.rescale",
+                input=pan_orig,
+                from_="%f,%f" % (min_pan, max_pan),
+                output=pan,
+                to="0,255",
+                quiet=True,
+                overwrite=True,
+            )
 
             pb.wait()
             pg.wait()
             pr.wait()
             pp.wait()
 
-
     # get PAN resolution:
     kv = grass.raster_info(map=pan)
-    nsres = kv['nsres']
-    ewres = kv['ewres']
+    nsres = kv["nsres"]
+    ewres = kv["ewres"]
     panres = (nsres + ewres) / 2
 
     # clone current region
     grass.use_temp_region()
-    grass.run_command('g.region', res=panres, align=pan)
+    grass.run_command("g.region", res=panres, align=pan)
 
     # Select sharpening method
     grass.message(_("Performing pan sharpening with hi res pan image: %f" % panres))
@@ -265,89 +415,109 @@ def main():
 
     # equalized grey scales give best contrast
     grass.message(_("setting pan-sharpened channels to equalized grey scale"))
-    for ch in ['red', 'green', 'blue']:
-        grass.run_command('r.colors', quiet=True, map="%s_%s" % (out, ch),
-                          flags="e", color='grey')
+    for ch in ["red", "green", "blue"]:
+        grass.run_command(
+            "r.colors", quiet=True, map="%s_%s" % (out, ch), flags="e", color="grey"
+        )
 
     # Landsat too blue-ish because panchromatic band less sensitive to blue
     # light, so output blue channed can be modified
     if bladjust:
         grass.message(_("Adjusting blue channel color table..."))
-        blue_colors = ['0 0 0 0\n5% 0 0 0\n67% 255 255 255\n100% 255 255 255']
+        blue_colors = ["0 0 0 0\n5% 0 0 0\n67% 255 255 255\n100% 255 255 255"]
         # these previous colors are way too blue for landsat
         # blue_colors = ['0 0 0 0\n10% 0 0 0\n20% 200 200 200\n40% 230 230 230\n67% 255 255 255\n100% 255 255 255']
-        bc = grass.feed_command('r.colors', quiet = True, map = "%s_blue" % out, rules = "-")
-        bc.stdin.write(grass.encode('\n'.join(blue_colors)))
+        bc = grass.feed_command("r.colors", quiet=True, map="%s_blue" % out, rules="-")
+        bc.stdin.write(grass.encode("\n".join(blue_colors)))
         bc.stdin.close()
 
     # output notice
     grass.verbose(_("The following pan-sharpened output maps have been generated:"))
-    for ch in ['red', 'green', 'blue']:
+    for ch in ["red", "green", "blue"]:
         grass.verbose(_("%s_%s") % (out, ch))
 
     grass.verbose(_("To visualize output, run: g.region -p raster=%s_red" % out))
     grass.verbose(_("d.rgb r=%s_red g=%s_green b=%s_blue" % (out, out, out)))
-    grass.verbose(_("If desired, combine channels into a single RGB map with 'r.composite'."))
+    grass.verbose(
+        _("If desired, combine channels into a single RGB map with 'r.composite'.")
+    )
     grass.verbose(_("Channel colors can be rebalanced using i.colors.enhance."))
 
     # write cmd history:
-    for ch in ['red', 'green', 'blue']:
+    for ch in ["red", "green", "blue"]:
         grass.raster_history("%s_%s" % (out, ch))
 
     # create a group with the three outputs
-    #grass.run_command('i.group', group=out,
+    # grass.run_command('i.group', group=out,
     #                  input="{n}_red,{n}_blue,{n}_green".format(n=out))
 
     # Cleanup
     grass.message(_("cleaning up temp files"))
     try:
-        grass.run_command('g.remove', flags="f", type="raster",
-                           pattern="tmp%s*" % pid, quiet=True)
+        grass.run_command(
+            "g.remove", flags="f", type="raster", pattern="tmp%s*" % pid, quiet=True
+        )
     except:
         ""
 
+
 def brovey(pan, ms1, ms2, ms3, out, pid, sproc):
     grass.verbose(_("Using Brovey algorithm"))
 
     # pan/intensity histogram matching using linear regression
     grass.message(_("Pan channel/intensity histogram matching using linear regression"))
-    outname = 'tmp%s_pan1' % pid
+    outname = "tmp%s_pan1" % pid
     panmatch1 = matchhist(pan, ms1, outname)
 
-    outname = 'tmp%s_pan2' % pid
+    outname = "tmp%s_pan2" % pid
     panmatch2 = matchhist(pan, ms2, outname)
 
-    outname = 'tmp%s_pan3' % pid
+    outname = "tmp%s_pan3" % pid
     panmatch3 = matchhist(pan, ms3, outname)
 
-    outr = '%s_red' % out
-    outg = '%s_green' % out
-    outb = '%s_blue' % out
+    outr = "%s_red" % out
+    outg = "%s_green" % out
+    outb = "%s_blue" % out
 
     # calculate brovey transformation
     grass.message(_("Calculating Brovey transformation..."))
 
     if sproc:
         # serial processing
-        e = '''eval(k = "$ms1" + "$ms2" + "$ms3")
+        e = """eval(k = "$ms1" + "$ms2" + "$ms3")
             "$outr" = 1 * round("$ms3" * "$panmatch3" / k)
             "$outg" = 1 * round("$ms2" * "$panmatch2" / k)
-            "$outb" = 1 * round("$ms1" * "$panmatch1" / k)'''
-        grass.mapcalc(e, outr=outr, outg=outg, outb=outb,
-                      panmatch1=panmatch1, panmatch2=panmatch2,
-                      panmatch3=panmatch3, ms1=ms1, ms2=ms2, ms3=ms3,
-                      overwrite=True)
+            "$outb" = 1 * round("$ms1" * "$panmatch1" / k)"""
+        grass.mapcalc(
+            e,
+            outr=outr,
+            outg=outg,
+            outb=outb,
+            panmatch1=panmatch1,
+            panmatch2=panmatch2,
+            panmatch3=panmatch3,
+            ms1=ms1,
+            ms2=ms2,
+            ms3=ms3,
+            overwrite=True,
+        )
     else:
         # parallel processing
-        pb = grass.mapcalc_start('%s_blue = 1 * round((%s * %s) / (%s + %s + %s))' %
-                                 (out, ms1, panmatch1, ms1, ms2, ms3),
-                                 overwrite=True)
-        pg = grass.mapcalc_start('%s_green = 1 * round((%s * %s) / (%s + %s + %s))' %
-                                 (out, ms2, panmatch2, ms1, ms2, ms3),
-                                 overwrite=True)
-        pr = grass.mapcalc_start('%s_red = 1 * round((%s * %s) / (%s + %s + %s))' %
-                                 (out, ms3, panmatch3, ms1, ms2, ms3),
-                                 overwrite=True)
+        pb = grass.mapcalc_start(
+            "%s_blue = 1 * round((%s * %s) / (%s + %s + %s))"
+            % (out, ms1, panmatch1, ms1, ms2, ms3),
+            overwrite=True,
+        )
+        pg = grass.mapcalc_start(
+            "%s_green = 1 * round((%s * %s) / (%s + %s + %s))"
+            % (out, ms2, panmatch2, ms1, ms2, ms3),
+            overwrite=True,
+        )
+        pr = grass.mapcalc_start(
+            "%s_red = 1 * round((%s * %s) / (%s + %s + %s))"
+            % (out, ms3, panmatch3, ms1, ms2, ms3),
+            overwrite=True,
+        )
 
         pb.wait(), pg.wait(), pr.wait()
         try:
@@ -357,22 +527,31 @@ def brovey(pan, ms1, ms2, ms3, out, pid, sproc):
 
     # Cleanup
     try:
-        grass.run_command('g.remove', flags='f', quiet=True, type='raster',
-                          name='%s,%s,%s' % (panmatch1, panmatch2, panmatch3))
+        grass.run_command(
+            "g.remove",
+            flags="f",
+            quiet=True,
+            type="raster",
+            name="%s,%s,%s" % (panmatch1, panmatch2, panmatch3),
+        )
     except:
         ""
 
+
 def ihs(pan, ms1, ms2, ms3, out, pid, sproc):
     grass.verbose(_("Using IHS<->RGB algorithm"))
     # transform RGB channels into IHS color space
     grass.message(_("Transforming to IHS color space..."))
-    grass.run_command('i.rgb.his', overwrite=True,
-                      red=ms3,
-                      green=ms2,
-                      blue=ms1,
-                      hue="tmp%s_hue" % pid,
-                      intensity="tmp%s_int" % pid,
-                      saturation="tmp%s_sat" % pid)
+    grass.run_command(
+        "i.rgb.his",
+        overwrite=True,
+        red=ms3,
+        green=ms2,
+        blue=ms1,
+        hue="tmp%s_hue" % pid,
+        intensity="tmp%s_int" % pid,
+        saturation="tmp%s_sat" % pid,
+    )
 
     # pan/intensity histogram matching using linear regression
     target = "tmp%s_int" % pid
@@ -381,45 +560,54 @@ def ihs(pan, ms1, ms2, ms3, out, pid, sproc):
 
     # substitute pan for intensity channel and transform back to RGB color space
     grass.message(_("Transforming back to RGB color space and sharpening..."))
-    grass.run_command('i.his.rgb', overwrite=True,
-                      hue="tmp%s_hue" % pid,
-                      intensity="%s" % panmatch,
-                      saturation="tmp%s_sat" % pid,
-                      red="%s_red" % out,
-                      green="%s_green" % out,
-                      blue="%s_blue" % out)
+    grass.run_command(
+        "i.his.rgb",
+        overwrite=True,
+        hue="tmp%s_hue" % pid,
+        intensity="%s" % panmatch,
+        saturation="tmp%s_sat" % pid,
+        red="%s_red" % out,
+        green="%s_green" % out,
+        blue="%s_blue" % out,
+    )
 
     # Cleanup
     try:
-        grass.run_command('g.remove', flags='f', quiet=True, type='raster',
-                          name=panmatch)
+        grass.run_command(
+            "g.remove", flags="f", quiet=True, type="raster", name=panmatch
+        )
     except:
         ""
 
+
 def pca(pan, ms1, ms2, ms3, out, pid, sproc):
 
     grass.verbose(_("Using PCA/inverse PCA algorithm"))
     grass.message(_("Creating PCA images and calculating eigenvectors..."))
 
     # initial PCA with RGB channels
-    pca_out = grass.read_command('i.pca', quiet=True, rescale='0,0',
-                                 input='%s,%s,%s' % (ms1, ms2, ms3),
-                                 output='tmp%s.pca' % pid)
+    pca_out = grass.read_command(
+        "i.pca",
+        quiet=True,
+        rescale="0,0",
+        input="%s,%s,%s" % (ms1, ms2, ms3),
+        output="tmp%s.pca" % pid,
+    )
     if len(pca_out) < 1:
         grass.fatal(_("Input has no data. Check region settings."))
 
     b1evect = []
     b2evect = []
     b3evect = []
-    for l in pca_out.replace('(', ',').replace(')', ',').splitlines():
-        b1evect.append(float(l.split(',')[1]))
-        b2evect.append(float(l.split(',')[2]))
-        b3evect.append(float(l.split(',')[3]))
+    for l in pca_out.replace("(", ",").replace(")", ",").splitlines():
+        b1evect.append(float(l.split(",")[1]))
+        b2evect.append(float(l.split(",")[2]))
+        b3evect.append(float(l.split(",")[3]))
 
     # inverse PCA with hi res pan channel substituted for principal component 1
-    pca1 = 'tmp%s.pca.1' % pid
-    pca2 = 'tmp%s.pca.2' % pid
-    pca3 = 'tmp%s.pca.3' % pid
+    pca1 = "tmp%s.pca.1" % pid
+    pca2 = "tmp%s.pca.2" % pid
+    pca3 = "tmp%s.pca.3" % pid
     b1evect1 = b1evect[0]
     b1evect2 = b1evect[1]
     b1evect3 = b1evect[2]
@@ -431,97 +619,87 @@ def pca(pan, ms1, ms2, ms3, out, pid, sproc):
     b3evect3 = b3evect[2]
 
     # Histogram matching
-    outname = 'tmp%s_pan1' % pid
+    outname = "tmp%s_pan1" % pid
     panmatch1 = matchhist(pan, ms1, outname)
 
-    outname = 'tmp%s_pan2' % pid
+    outname = "tmp%s_pan2" % pid
     panmatch2 = matchhist(pan, ms2, outname)
 
-    outname = 'tmp%s_pan3' % pid
+    outname = "tmp%s_pan3" % pid
     panmatch3 = matchhist(pan, ms3, outname)
 
     grass.message(_("Performing inverse PCA ..."))
 
     # Get mean value of each channel
-    stats1 = grass.parse_command("r.univar", map=ms1, flags='g',
-                                 parse=(grass.parse_key_val,
-                                        {'sep': '='}))
-    stats2 = grass.parse_command("r.univar", map=ms2, flags='g',
-                                 parse=(grass.parse_key_val,
-                                        {'sep': '='}))
-    stats3 = grass.parse_command("r.univar", map=ms3, flags='g',
-                                 parse=(grass.parse_key_val,
-                                        {'sep': '='}))
-
-    b1mean = float(stats1['mean'])
-    b2mean = float(stats2['mean'])
-    b3mean = float(stats3['mean'])
+    stats1 = grass.parse_command(
+        "r.univar", map=ms1, flags="g", parse=(grass.parse_key_val, {"sep": "="})
+    )
+    stats2 = grass.parse_command(
+        "r.univar", map=ms2, flags="g", parse=(grass.parse_key_val, {"sep": "="})
+    )
+    stats3 = grass.parse_command(
+        "r.univar", map=ms3, flags="g", parse=(grass.parse_key_val, {"sep": "="})
+    )
+
+    b1mean = float(stats1["mean"])
+    b2mean = float(stats2["mean"])
+    b3mean = float(stats3["mean"])
 
     if sproc:
         # serial processing
-        outr = '%s_red' % out
-        outg = '%s_green' % out
-        outb = '%s_blue' % out
+        outr = "%s_red" % out
+        outg = "%s_green" % out
+        outb = "%s_blue" % out
 
         cmd1 = "$outb = 1 * round(($panmatch1 * $b1evect1) + ($pca2 * $b1evect2) + ($pca3 * $b1evect3) + $b1mean)"
         cmd2 = "$outg = 1 * round(($panmatch2 * $b2evect1) + ($pca2 * $b2evect2) + ($pca3 * $b2evect3) + $b2mean)"
         cmd3 = "$outr = 1 * round(($panmatch3 * $b3evect1) + ($pca2 * $b3evect2) + ($pca3 * $b3evect3) + $b3mean)"
 
-        cmd = '\n'.join([cmd1, cmd2, cmd3])
-
-        grass.mapcalc(cmd, outb=outb, outg=outg, outr=outr,
-                      panmatch1=panmatch1,
-                      panmatch2=panmatch2,
-                      panmatch3=panmatch3,
-                      pca2=pca2,
-                      pca3=pca3,
-                      b1evect1=b1evect1,
-                      b2evect1=b2evect1,
-                      b3evect1=b3evect1,
-                      b1evect2=b1evect2,
-                      b2evect2=b2evect2,
-                      b3evect2=b3evect2,
-                      b1evect3=b1evect3,
-                      b2evect3=b2evect3,
-                      b3evect3=b3evect3,
-                      b1mean=b1mean,
-                      b2mean=b2mean,
-                      b3mean=b3mean,
-                      overwrite=True)
+        cmd = "\n".join([cmd1, cmd2, cmd3])
+
+        grass.mapcalc(
+            cmd,
+            outb=outb,
+            outg=outg,
+            outr=outr,
+            panmatch1=panmatch1,
+            panmatch2=panmatch2,
+            panmatch3=panmatch3,
+            pca2=pca2,
+            pca3=pca3,
+            b1evect1=b1evect1,
+            b2evect1=b2evect1,
+            b3evect1=b3evect1,
+            b1evect2=b1evect2,
+            b2evect2=b2evect2,
+            b3evect2=b3evect2,
+            b1evect3=b1evect3,
+            b2evect3=b2evect3,
+            b3evect3=b3evect3,
+            b1mean=b1mean,
+            b2mean=b2mean,
+            b3mean=b3mean,
+            overwrite=True,
+        )
     else:
         # parallel processing
-        pb = grass.mapcalc_start('%s_blue = 1 * round((%s * %f) + (%s * %f) + (%s * %f) + %f)'
-                                 % (out,
-                                    panmatch1,
-                                    b1evect1,
-                                    pca2,
-                                    b1evect2,
-                                    pca3,
-                                    b1evect3,
-                                    b1mean),
-                                 overwrite=True)
-
-        pg = grass.mapcalc_start('%s_green = 1 * round((%s * %f) + (%s * %f) + (%s * %f) + %f)'
-                                 % (out,
-                                    panmatch2,
-                                    b2evect1,
-                                    pca2,
-                                    b2evect2,
-                                    pca3,
-                                    b2evect3,
-                                    b2mean),
-                                 overwrite=True)
-
-        pr = grass.mapcalc_start('%s_red = 1 * round((%s * %f) + (%s * %f) + (%s * %f) + %f)'
-                                 % (out,
-                                    panmatch3,
-                                    b3evect1,
-                                    pca2,
-                                    b3evect2,
-                                    pca3,
-                                    b3evect3,
-                                    b3mean),
-                                 overwrite=True)
+        pb = grass.mapcalc_start(
+            "%s_blue = 1 * round((%s * %f) + (%s * %f) + (%s * %f) + %f)"
+            % (out, panmatch1, b1evect1, pca2, b1evect2, pca3, b1evect3, b1mean),
+            overwrite=True,
+        )
+
+        pg = grass.mapcalc_start(
+            "%s_green = 1 * round((%s * %f) + (%s * %f) + (%s * %f) + %f)"
+            % (out, panmatch2, b2evect1, pca2, b2evect2, pca3, b2evect3, b2mean),
+            overwrite=True,
+        )
+
+        pr = grass.mapcalc_start(
+            "%s_red = 1 * round((%s * %f) + (%s * %f) + (%s * %f) + %f)"
+            % (out, panmatch3, b3evect1, pca2, b3evect2, pca3, b3evect3, b3mean),
+            overwrite=True,
+        )
 
         pb.wait(), pg.wait(), pr.wait()
         try:
@@ -530,16 +708,22 @@ def pca(pan, ms1, ms2, ms3, out, pid, sproc):
             ""
 
     # Cleanup
-    grass.run_command('g.remove', flags='f', quiet=True, type='raster',
-                      name='%s,%s,%s' % (panmatch1, panmatch2, panmatch3))
+    grass.run_command(
+        "g.remove",
+        flags="f",
+        quiet=True,
+        type="raster",
+        name="%s,%s,%s" % (panmatch1, panmatch2, panmatch3),
+    )
+
 
 def matchhist(original, target, matched):
     # pan/intensity histogram matching using numpy arrays
     grass.message(_("Histogram matching..."))
 
     # input images
-    original = original.split('@')[0]
-    target = target.split('@')[0]
+    original = original.split("@")[0]
+    target = target.split("@")[0]
     images = [original, target]
 
     # create a dictionary to hold arrays for each image
@@ -547,14 +731,13 @@ def matchhist(original, target, matched):
 
     for img in images:
         # calculate number of cells for each grey value for for each image
-        stats_out = grass.pipe_command('r.stats', flags='cin', input=img,
-                                       sep=':')
-        stats = grass.decode(stats_out.communicate()[0]).split('\n')[:-1]
-        stats_dict = dict(s.split(':', 1) for s in stats)
+        stats_out = grass.pipe_command("r.stats", flags="cin", input=img, sep=":")
+        stats = grass.decode(stats_out.communicate()[0]).split("\n")[:-1]
+        stats_dict = dict(s.split(":", 1) for s in stats)
         total_cells = 0  # total non-null cells
         for j in stats_dict:
             stats_dict[j] = int(stats_dict[j])
-            if j != '*':
+            if j != "*":
                 total_cells += stats_dict[j]
 
         if total_cells < 1:
@@ -564,8 +747,10 @@ def matchhist(original, target, matched):
         #   cumulative distribution function (CDF) for each grey value.
         #   Grey value is the integer (i4) and cdf is float (f4).
 
-        arrays[img] = np.zeros((256, ), dtype=('i4,f4'))
-        cum_cells = 0  # cumulative total of cells for sum of current and all lower grey values
+        arrays[img] = np.zeros((256,), dtype=("i4,f4"))
+        cum_cells = (
+            0  # cumulative total of cells for sum of current and all lower grey values
+        )
 
         for n in range(0, 256):
             if str(n) in stats_dict:
@@ -583,7 +768,7 @@ def matchhist(original, target, matched):
             arrays[img][n] = (n, cdf)
 
     # open file for reclass rules
-    outfile = open(grass.tempfile(), 'w')
+    outfile = open(grass.tempfile(), "w")
 
     for i in arrays[original]:
         # for each grey value and corresponding cdf value in original, find the
@@ -610,15 +795,14 @@ def matchhist(original, target, matched):
     outfile.close()
 
     # create reclass of target from reclass rules file
-    result = grass.core.find_file(matched, element='cell')
-    if result['fullname']:
-        grass.run_command('g.remove', flags='f', quiet=True, type='raster',
-                          name=matched)
-        grass.run_command('r.reclass', input=original, out=matched,
-                          rules=outfile.name)
+    result = grass.core.find_file(matched, element="cell")
+    if result["fullname"]:
+        grass.run_command(
+            "g.remove", flags="f", quiet=True, type="raster", name=matched
+        )
+        grass.run_command("r.reclass", input=original, out=matched, rules=outfile.name)
     else:
-        grass.run_command('r.reclass', input=original, out=matched,
-                          rules=outfile.name)
+        grass.run_command("r.reclass", input=original, out=matched, rules=outfile.name)
 
     # Cleanup
     # remove the rules file
@@ -627,6 +811,7 @@ def matchhist(original, target, matched):
     # return reclass of target with histogram that matches original
     return matched
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     main()

+ 57 - 51
scripts/i.spectral/i.spectral.py

@@ -89,7 +89,7 @@ def cleanup():
 
 
 def write2textf(what, output):
-    outf = open(output, 'w')
+    outf = open(output, "w")
     i = 0
     for row in enumerate(what):
         i = i + 1
@@ -101,8 +101,8 @@ def draw_gnuplot(what, xlabels, output, img_format, coord_legend):
     xrange = 0
 
     for i, row in enumerate(what):
-        outfile = os.path.join(tmp_dir, 'data_%d' % i)
-        outf = open(outfile, 'w')
+        outfile = os.path.join(tmp_dir, "data_%d" % i)
+        outf = open(outfile, "w")
         xrange = max(xrange, len(row) - 2)
         for j, val in enumerate(row[3:]):
             outf.write("%d %s\n" % (j + 1, val))
@@ -111,19 +111,16 @@ def draw_gnuplot(what, xlabels, output, img_format, coord_legend):
     # build gnuplot script
     lines = []
     if output:
-        if img_format == 'png':
+        if img_format == "png":
             term_opts = "png truecolor large size 825,550"
-        elif img_format == 'eps':
+        elif img_format == "eps":
             term_opts = "postscript eps color solid size 6,4"
-        elif img_format == 'svg':
+        elif img_format == "svg":
             term_opts = "svg size 825,550 dynamic solid"
         else:
             gcore.fatal(_("Programmer error (%s)") % img_format)
 
-        lines += [
-            "set term " + term_opts,
-            "set output '%s'" % output
-        ]
+        lines += ["set term " + term_opts, "set output '%s'" % output]
 
     lines += [
         "set xtics (%s)" % xlabels,
@@ -134,78 +131,83 @@ def draw_gnuplot(what, xlabels, output, img_format, coord_legend):
         "set xlabel 'Bands'",
         "set xtics rotate by -40",
         "set ylabel 'DN Value'",
-        "set style data lines"
+        "set style data lines",
     ]
 
     cmd = []
     for i, row in enumerate(what):
         if not coord_legend:
-            title = 'Pick ' + str(i + 1)
+            title = "Pick " + str(i + 1)
         else:
             title = str(tuple(row[0:2]))
 
-        x_datafile = os.path.join(tmp_dir, 'data_%d' % i)
+        x_datafile = os.path.join(tmp_dir, "data_%d" % i)
         cmd.append(" '%s' title '%s'" % (x_datafile, title))
 
-    cmd = ','.join(cmd)
-    cmd = ' '.join(['plot', cmd, "with linespoints pt 779"])
+    cmd = ",".join(cmd)
+    cmd = " ".join(["plot", cmd, "with linespoints pt 779"])
     lines.append(cmd)
 
-    plotfile = os.path.join(tmp_dir, 'spectrum.gnuplot')
-    plotf = open(plotfile, 'w')
+    plotfile = os.path.join(tmp_dir, "spectrum.gnuplot")
+    plotf = open(plotfile, "w")
     for line in lines:
-        plotf.write(line + '\n')
+        plotf.write(line + "\n")
     plotf.close()
 
     if output:
-        gcore.call(['gnuplot', plotfile])
+        gcore.call(["gnuplot", plotfile])
     else:
-        gcore.call(['gnuplot', '-persist', plotfile])
+        gcore.call(["gnuplot", "-persist", plotfile])
 
 
 def draw_linegraph(what):
     yfiles = []
 
-    xfile = os.path.join(tmp_dir, 'data_x')
+    xfile = os.path.join(tmp_dir, "data_x")
 
-    xf = open(xfile, 'w')
+    xf = open(xfile, "w")
     for j, val in enumerate(what[0][3:]):
         xf.write("%d\n" % (j + 1))
     xf.close()
 
     for i, row in enumerate(what):
-        yfile = os.path.join(tmp_dir, 'data_y_%d' % i)
-        yf = open(yfile, 'w')
+        yfile = os.path.join(tmp_dir, "data_y_%d" % i)
+        yf = open(yfile, "w")
         for j, val in enumerate(row[3:]):
             yf.write("%s\n" % val)
         yf.close()
         yfiles.append(yfile)
 
-    sienna = '#%02x%02x%02x' % (160, 82, 45)
-    coral = '#%02x%02x%02x' % (255, 127, 80)
-    gp_colors = ['red', 'green', 'blue', 'magenta', 'cyan', sienna, 'orange',
-                 coral]
+    sienna = "#%02x%02x%02x" % (160, 82, 45)
+    coral = "#%02x%02x%02x" % (255, 127, 80)
+    gp_colors = ["red", "green", "blue", "magenta", "cyan", sienna, "orange", coral]
 
     colors = gp_colors
     while len(what) > len(colors):
         colors += gp_colors
-    colors = colors[0:len(what)]
+    colors = colors[0 : len(what)]
 
-    gcore.run_command('d.linegraph', x_file=xfile, y_file=yfiles,
-                      y_color=colors, title=_("Spectral signatures"),
-                      x_title=_("Bands"), y_title=_("DN Value"))
+    gcore.run_command(
+        "d.linegraph",
+        x_file=xfile,
+        y_file=yfiles,
+        y_color=colors,
+        title=_("Spectral signatures"),
+        x_title=_("Bands"),
+        y_title=_("DN Value"),
+    )
 
 
 def main():
-    group = options['group']
-    subgroup = options['subgroup']
-    raster = options['raster']
-    output = options['output']
-    coords = options['coordinates']
-    img_fmt = options['format']
-    coord_legend = flags['c']
-    gnuplot = flags['g']
-    textfile = flags['t']
+    group = options["group"]
+    subgroup = options["subgroup"]
+    raster = options["raster"]
+    output = options["output"]
+    coords = options["coordinates"]
+    img_fmt = options["format"]
+    coord_legend = flags["c"]
+    gnuplot = flags["g"]
+    textfile = flags["t"]
 
     global tmp_dir
     tmp_dir = gcore.tempdir()
@@ -221,35 +223,38 @@ def main():
         gcore.fatal(_("Writing to text file requires output=filename"))
 
     # check if gnuplot is present
-    if gnuplot and not gcore.find_program('gnuplot', '-V'):
+    if gnuplot and not gcore.find_program("gnuplot", "-V"):
         gcore.fatal(_("gnuplot required, please install first"))
 
     # get data from group listing and set the x-axis labels
     if group:
         # Parse the group list output
         if subgroup:
-            s = gcore.read_command('i.group', flags='g', group=group, subgroup=subgroup, quiet=True)
+            s = gcore.read_command(
+                "i.group", flags="g", group=group, subgroup=subgroup, quiet=True
+            )
         else:
-            s = gcore.read_command('i.group', flags='g', group=group, quiet=True)
+            s = gcore.read_command("i.group", flags="g", group=group, quiet=True)
         rastermaps = s.splitlines()
     else:
         # get data from list of files and set the x-axis labels
-        rastermaps = raster.split(',')
+        rastermaps = raster.split(",")
 
     xlabels = ["'%s' %d" % (n, i + 1) for i, n in enumerate(rastermaps)]
-    xlabels = ','.join(xlabels)
+    xlabels = ",".join(xlabels)
 
     # get y-data for gnuplot-data file
     what = []
-    s = gcore.read_command('r.what', map=rastermaps, coordinates=coords,
-                           null='0', quiet=True)
+    s = gcore.read_command(
+        "r.what", map=rastermaps, coordinates=coords, null="0", quiet=True
+    )
     if len(s) == 0:
-        gcore.fatal(_('No data returned from query'))
+        gcore.fatal(_("No data returned from query"))
 
     for l in s.splitlines():
-        f = l.split('|')
+        f = l.split("|")
         for i, v in enumerate(f):
-            if v in ['', '*']:
+            if v in ["", "*"]:
                 f[i] = 0
             else:
                 f[i] = float(v)
@@ -263,6 +268,7 @@ def main():
     else:
         draw_linegraph(what)
 
+
 if __name__ == "__main__":
     options, flags = gcore.parser()
     atexit.register(cleanup)

+ 205 - 62
scripts/i.tasscap/i.tasscap.py

@@ -11,9 +11,9 @@
 # PURPOSE:	At-satellite reflectance based tasseled cap transformation.
 # COPYRIGHT:	(C) 1997-2014 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.
+# 		This program is free software under the GNU General Public
+# 		License (>=v2). Read the file COPYING that comes with GRASS
+# 		for details.
 #
 #############################################################################
 # References:
@@ -91,35 +91,136 @@ import grass.script as grass
 # Worldview-2: B1 ... B8 (PAN not used)
 #
 ## entries: 1. Brightness, 2. Greeness, 3. Wetness and shadows, 4. Haze
-parms = [[(0.3037, 0.2793, 0.4743, 0.5585, 0.5082, 0.1863),  # Landsat TM4
-          (-0.2848, -0.2435, -0.5435, 0.7243, 0.0840, -0.1800),
-          (0.1509, 0.1973, 0.3279, 0.3406, -0.7112, -0.4572)],
-         [(0.2909, 0.2493, 0.4806, 0.5568, 0.4438, 0.1706, 10.3695),  # Landsat TM5
-          (-0.2728, -0.2174, -0.5508, 0.7221, 0.0733, -0.1648, -0.7310),
-          (0.1446, 0.1761, 0.3322, 0.3396, -0.6210, -0.4186, -3.3828),
-          (0.8461, -0.0731, -0.4640, -0.0032, -0.0492, -0.0119, 0.7879)],
-         [(0.3561, 0.3972, 0.3904, 0.6966, 0.2286, 0.1596),  # Landsat TM7
-          (-0.3344, -0.3544, -0.4556, 0.6966, -0.0242, -0.2630),
-          (0.2626, 0.2141, 0.0926, 0.0656, -0.7629, -0.5388),
-          (0.0805, -0.0498, 0.1950, -0.1327, 0.5752, -0.7775)],
-         [(0.3029, 0.2786, 0.4733, 0.5599, 0.5080, 0.1872),  # Landsat OLI
-          (-0.2941, -0.2430, -0.5424, 0.7276, 0.0713, -0.1608),
-          (0.1511, 0.1973, 0.3283, 0.3407, -0.7117, -0.4559),
-          (-0.8239, 0.0849, 0.4396, -0.0580, 0.2013, -0.2773)],
-         [(0.4395, 0.5945, 0.2460, 0.3918, 0.3506, 0.2136, 0.2678),  # MODIS
-          (-0.4064, 0.5129, -0.2744, -0.2893, 0.4882, -0.0036, -0.4169),
-          (0.1147, 0.2489, 0.2408, 0.3132, -0.3122, -0.6416, -0.5087)],
-         [(0.0356, 0.0822, 0.1360, 0.2611, 0.2964, 0.3338, 0.3877, 0.3895, 0.0949, 0.0009, 0.3882, 0.1366, 0.4750), # Sentinel-2
-          (-0.0635, -0.1128, -0.1680, -0.3480, -0.3303, 0.0852, 0.3302, 0.3165, 0.0467, -0.0009, -0.4578, -0.4064, 0.3625),
-          (0.0649, 0.1363, 0.2802, 0.3072, 0.5288, 0.1379, -0.0001, -0.0807, -0.0302, 0.0003, -0.4064, -0.5602, -0.1389)],
-         [(-0.060436,0.012147,0.125846,0.313039,0.412175,0.482758,-0.160654,0.673510), # WV-2
-          (-0.140110,-0.206224,-0.215854,-0.314441,-0.410892,0.095786,0.600549,0.503672),
-          (-0.270951,-0.317080,-0.317263,-0.242544,-0.256463,-0.096550,-0.742535,0.202430),
-          (0.546979,0.392244,0.232894,-0.151027,-0.540102,0.327952,-0.243740,0.106010)]]
+parms = [
+    [
+        (0.3037, 0.2793, 0.4743, 0.5585, 0.5082, 0.1863),  # Landsat TM4
+        (-0.2848, -0.2435, -0.5435, 0.7243, 0.0840, -0.1800),
+        (0.1509, 0.1973, 0.3279, 0.3406, -0.7112, -0.4572),
+    ],
+    [
+        (0.2909, 0.2493, 0.4806, 0.5568, 0.4438, 0.1706, 10.3695),  # Landsat TM5
+        (-0.2728, -0.2174, -0.5508, 0.7221, 0.0733, -0.1648, -0.7310),
+        (0.1446, 0.1761, 0.3322, 0.3396, -0.6210, -0.4186, -3.3828),
+        (0.8461, -0.0731, -0.4640, -0.0032, -0.0492, -0.0119, 0.7879),
+    ],
+    [
+        (0.3561, 0.3972, 0.3904, 0.6966, 0.2286, 0.1596),  # Landsat TM7
+        (-0.3344, -0.3544, -0.4556, 0.6966, -0.0242, -0.2630),
+        (0.2626, 0.2141, 0.0926, 0.0656, -0.7629, -0.5388),
+        (0.0805, -0.0498, 0.1950, -0.1327, 0.5752, -0.7775),
+    ],
+    [
+        (0.3029, 0.2786, 0.4733, 0.5599, 0.5080, 0.1872),  # Landsat OLI
+        (-0.2941, -0.2430, -0.5424, 0.7276, 0.0713, -0.1608),
+        (0.1511, 0.1973, 0.3283, 0.3407, -0.7117, -0.4559),
+        (-0.8239, 0.0849, 0.4396, -0.0580, 0.2013, -0.2773),
+    ],
+    [
+        (0.4395, 0.5945, 0.2460, 0.3918, 0.3506, 0.2136, 0.2678),  # MODIS
+        (-0.4064, 0.5129, -0.2744, -0.2893, 0.4882, -0.0036, -0.4169),
+        (0.1147, 0.2489, 0.2408, 0.3132, -0.3122, -0.6416, -0.5087),
+    ],
+    [
+        (
+            0.0356,
+            0.0822,
+            0.1360,
+            0.2611,
+            0.2964,
+            0.3338,
+            0.3877,
+            0.3895,
+            0.0949,
+            0.0009,
+            0.3882,
+            0.1366,
+            0.4750,
+        ),  # Sentinel-2
+        (
+            -0.0635,
+            -0.1128,
+            -0.1680,
+            -0.3480,
+            -0.3303,
+            0.0852,
+            0.3302,
+            0.3165,
+            0.0467,
+            -0.0009,
+            -0.4578,
+            -0.4064,
+            0.3625,
+        ),
+        (
+            0.0649,
+            0.1363,
+            0.2802,
+            0.3072,
+            0.5288,
+            0.1379,
+            -0.0001,
+            -0.0807,
+            -0.0302,
+            0.0003,
+            -0.4064,
+            -0.5602,
+            -0.1389,
+        ),
+    ],
+    [
+        (
+            -0.060436,
+            0.012147,
+            0.125846,
+            0.313039,
+            0.412175,
+            0.482758,
+            -0.160654,
+            0.673510,
+        ),  # WV-2
+        (
+            -0.140110,
+            -0.206224,
+            -0.215854,
+            -0.314441,
+            -0.410892,
+            0.095786,
+            0.600549,
+            0.503672,
+        ),
+        (
+            -0.270951,
+            -0.317080,
+            -0.317263,
+            -0.242544,
+            -0.256463,
+            -0.096550,
+            -0.742535,
+            0.202430,
+        ),
+        (
+            0.546979,
+            0.392244,
+            0.232894,
+            -0.151027,
+            -0.540102,
+            0.327952,
+            -0.243740,
+            0.106010,
+        ),
+    ],
+]
 
 # satellite information
-satellites = ['landsat4_tm', 'landsat5_tm', 'landsat7_etm', 'landsat8_oli',
-              'modis', 'sentinel2', 'worldview2']
+satellites = [
+    "landsat4_tm",
+    "landsat5_tm",
+    "landsat7_etm",
+    "landsat8_oli",
+    "modis",
+    "sentinel2",
+    "worldview2",
+]
 used_bands = [6, 6, 6, 6, 7, 13, 8]
 
 # components information
@@ -131,45 +232,81 @@ def calc1bands6(out, bands, k1, k2, k3, k4, k5, k6, k0=0):
     """
     Tasseled cap transformation equation for Landsat bands
     """
-    equation = ('$out = $k1 * $in1band + $k2 * $in2band + $k3 * $in3band + '
-                '$k4 * $in4band + $k5 * $in5band + $k6 * $in6band + $k0')
-    grass.mapcalc(equation, out=out, k1=k1, k2=k2, k3=k3, k4=k4, k5=k5,
-                  k6=k6, k0=k0, **bands)
+    equation = (
+        "$out = $k1 * $in1band + $k2 * $in2band + $k3 * $in3band + "
+        "$k4 * $in4band + $k5 * $in5band + $k6 * $in6band + $k0"
+    )
+    grass.mapcalc(
+        equation, out=out, k1=k1, k2=k2, k3=k3, k4=k4, k5=k5, k6=k6, k0=k0, **bands
+    )
 
 
 def calc1bands7(out, bands, k1, k2, k3, k4, k5, k6, k7):
     """
     Tasseled cap transformation equation for MODIS bands
     """
-    equation = ('$out = $k1 * $in1band + $k2 * $in2band + $k3 * $in3band + '
-                '$k4 * $in4band + $k5 * $in5band + $k6 * $in6band + $k7 * '
-                '$in7band')
-    grass.mapcalc(equation, out=out, k1=k1, k2=k2, k3=k3, k4=k4, k5=k5, k6=k6,
-                  k7=k7, **bands)
+    equation = (
+        "$out = $k1 * $in1band + $k2 * $in2band + $k3 * $in3band + "
+        "$k4 * $in4band + $k5 * $in5band + $k6 * $in6band + $k7 * "
+        "$in7band"
+    )
+    grass.mapcalc(
+        equation, out=out, k1=k1, k2=k2, k3=k3, k4=k4, k5=k5, k6=k6, k7=k7, **bands
+    )
 
 
 def calc1bands8(out, bands, k1, k2, k3, k4, k5, k6, k7, k8):
     """
     Tasseled cap transformation equation for Worldview-2 bands
     """
-    equation = ('$out = $k1 * $in1band + $k2 * $in2band + $k3 * $in3band + '
-                '$k4 * $in4band + $k5 * $in5band + $k6 * $in6band + $k7 * '
-                '$in7band + $k8 * $in8band')
-    grass.mapcalc(equation, out=out, k1=k1, k2=k2, k3=k3, k4=k4, k5=k5, k6=k6,
-                  k7=k7, k8=k8, **bands)
+    equation = (
+        "$out = $k1 * $in1band + $k2 * $in2band + $k3 * $in3band + "
+        "$k4 * $in4band + $k5 * $in5band + $k6 * $in6band + $k7 * "
+        "$in7band + $k8 * $in8band"
+    )
+    grass.mapcalc(
+        equation,
+        out=out,
+        k1=k1,
+        k2=k2,
+        k3=k3,
+        k4=k4,
+        k5=k5,
+        k6=k6,
+        k7=k7,
+        k8=k8,
+        **bands
+    )
 
 
 def calc1bands13(out, bands, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13):
     """
     Tasseled cap transformation equation for Sentinel-2 bands
     """
-    equation = ('$out = $k1 * $in1band + $k2 * $in2band + $k3 * $in3band + '
-                '$k4 * $in4band + $k5 * $in5band + $k6 * $in6band + $k7 * '
-                '$in7band + $k8 * $in8band + $k9 * $in9band + $k10 * $in10band + '
-                '$k11 * $in11band + $k12 * $in12band + $k13 * $in13band')
-    grass.mapcalc(equation, out=out, k1=k1, k2=k2, k3=k3, k4=k4, k5=k5, k6=k6,
-                  k7=k7, k8=k8, k9=k9, k10=k10, k11=k11, k12=k12, k13=k13,
-                  **bands)
+    equation = (
+        "$out = $k1 * $in1band + $k2 * $in2band + $k3 * $in3band + "
+        "$k4 * $in4band + $k5 * $in5band + $k6 * $in6band + $k7 * "
+        "$in7band + $k8 * $in8band + $k9 * $in9band + $k10 * $in10band + "
+        "$k11 * $in11band + $k12 * $in12band + $k13 * $in13band"
+    )
+    grass.mapcalc(
+        equation,
+        out=out,
+        k1=k1,
+        k2=k2,
+        k3=k3,
+        k4=k4,
+        k5=k5,
+        k6=k6,
+        k7=k7,
+        k8=k8,
+        k9=k9,
+        k10=k10,
+        k11=k11,
+        k12=k12,
+        k13=k13,
+        **bands
+    )
 
 
 def calcN(outpre, bands, satel):
@@ -190,35 +327,41 @@ def calcN(outpre, bands, satel):
 
         # use combination function suitable for used number of bands
         eval("calc1bands%d(out, bands, *p)" % bands_num)
-        grass.run_command('r.colors', map=out, color='grey', quiet=True)
+        grass.run_command("r.colors", map=out, color="grey", quiet=True)
 
 
 def main():
     options, flags = grass.parser()
-    satellite = options['sensor']
-    output_basename = options['output']
-    inputs = options['input'].split(',')
+    satellite = options["sensor"]
+    output_basename = options["output"]
+    inputs = options["input"].split(",")
     num_of_bands = used_bands[satellites.index(satellite)]
     if len(inputs) != num_of_bands:
-        grass.fatal(_("The number of input raster maps (bands) should be %s") % num_of_bands)
+        grass.fatal(
+            _("The number of input raster maps (bands) should be %s") % num_of_bands
+        )
 
     bands = {}
     for i, band in enumerate(inputs):
         band_num = i + 1
-        bands['in' + str(band_num) + 'band'] = band
+        bands["in" + str(band_num) + "band"] = band
     grass.debug(bands, 1)
 
     # core tasseled cap components computation
     calcN(output_basename, bands, satellite)
 
     # assign "Data Description" field in all four component maps
-    num_comp=len(parms[satellites.index(satellite)])
-    for i in range(0,num_comp):
-        comp=names[i]
-        grass.run_command('r.support', map="%s.%d" % (output_basename, i + 1),
-                          description="Tasseled Cap %d: %s" % (i + 1, comp))
+    num_comp = len(parms[satellites.index(satellite)])
+    for i in range(0, num_comp):
+        comp = names[i]
+        grass.run_command(
+            "r.support",
+            map="%s.%d" % (output_basename, i + 1),
+            description="Tasseled Cap %d: %s" % (i + 1, comp),
+        )
 
     grass.message(_("Tasseled Cap components calculated"))
 
+
 if __name__ == "__main__":
     main()

+ 57 - 48
scripts/m.proj/m.proj.py

@@ -106,7 +106,6 @@ from grass.script import core as gcore
 
 
 class TrThread(threading.Thread):
-
     def __init__(self, ifs, inf, outf):
         threading.Thread.__init__(self)
         self.ifs = ifs
@@ -118,7 +117,7 @@ class TrThread(threading.Thread):
             line = self.inf.readline()
             if not line:
                 break
-            line = line.replace(self.ifs, ' ')
+            line = line.replace(self.ifs, " ")
             line = encode(line)
             self.outf.write(line)
             self.outf.flush()
@@ -127,31 +126,34 @@ class TrThread(threading.Thread):
 
 
 def main():
-    coords = options['coordinates']
-    input = options['input']
-    output = options['output']
-    fs = options['separator']
-    proj_in = options['proj_in']
-    proj_out = options['proj_out']
-    ll_in = flags['i']
-    ll_out = flags['o']
-    decimal = flags['d']
-    copy_input = flags['e']
-    include_header = flags['c']
+    coords = options["coordinates"]
+    input = options["input"]
+    output = options["output"]
+    fs = options["separator"]
+    proj_in = options["proj_in"]
+    proj_out = options["proj_out"]
+    ll_in = flags["i"]
+    ll_out = flags["o"]
+    decimal = flags["d"]
+    copy_input = flags["e"]
+    include_header = flags["c"]
 
     # check for cs2cs
-    if not gcore.find_program('cs2cs'):
-        gcore.fatal(_(
-            "cs2cs program not found, install PROJ first: \
-            https://proj.org"))
+    if not gcore.find_program("cs2cs"):
+        gcore.fatal(
+            _(
+                "cs2cs program not found, install PROJ first: \
+            https://proj.org"
+            )
+        )
 
     # parse field separator
     # FIXME: input_x,y needs to split on multiple whitespace between them
-    if fs == ',':
-        ifs = ofs = ','
+    if fs == ",":
+        ifs = ofs = ","
     else:
         try:
-            ifs, ofs = fs.split(',')
+            ifs, ofs = fs.split(",")
         except ValueError:
             ifs = ofs = fs
 
@@ -159,30 +161,29 @@ def main():
     ofs = separator(ofs)
 
     # set up projection params
-    s = gcore.read_command("g.proj", flags='j')
+    s = gcore.read_command("g.proj", flags="j")
     kv = parse_key_val(s)
-    if "XY location" in kv['+proj'] and (ll_in or ll_out):
+    if "XY location" in kv["+proj"] and (ll_in or ll_out):
         gcore.fatal(_("Unable to project to or from a XY location"))
 
     in_proj = None
 
     if ll_in:
         in_proj = "+proj=longlat +datum=WGS84"
-        gcore.verbose(
-            "Assuming LL WGS84 as input, current projection as output ")
+        gcore.verbose("Assuming LL WGS84 as input, current projection as output ")
 
     if ll_out:
-        in_proj = gcore.read_command('g.proj', flags='jf')
+        in_proj = gcore.read_command("g.proj", flags="jf")
 
     if proj_in:
-        if '+' in proj_in:
+        if "+" in proj_in:
             in_proj = proj_in
         else:
             gcore.fatal(_("Invalid PROJ.4 input specification"))
 
     if not in_proj:
         gcore.verbose("Assuming current location as input")
-        in_proj = gcore.read_command('g.proj', flags='jf')
+        in_proj = gcore.read_command("g.proj", flags="jf")
 
     in_proj = in_proj.strip()
     gcore.verbose("Input parameters: '%s'" % in_proj)
@@ -191,14 +192,13 @@ def main():
 
     if ll_out:
         out_proj = "+proj=longlat +datum=WGS84"
-        gcore.verbose(
-            "Assuming current projection as input, LL WGS84 as output ")
+        gcore.verbose("Assuming current projection as input, LL WGS84 as output ")
 
     if ll_in:
-        out_proj = gcore.read_command('g.proj', flags='jf')
+        out_proj = gcore.read_command("g.proj", flags="jf")
 
     if proj_out:
-        if '+' in proj_out:
+        if "+" in proj_out:
             out_proj = proj_out
         else:
             gcore.fatal(_("Invalid PROJ.4 output specification"))
@@ -210,14 +210,14 @@ def main():
 
     # set up input file
     if coords:
-        x, y = coords.split(',')
+        x, y = coords.split(",")
         tmpfile = gcore.tempfile()
         fd = open(tmpfile, "w")
         fd.write("%s%s%s\n" % (x, ifs, y))
         fd.close()
         inf = open(tmpfile)
     else:
-        if input == '-':
+        if input == "-":
             infile = None
             inf = sys.stdin
         else:
@@ -233,7 +233,7 @@ def main():
         outf = sys.stdout
     else:
         outfile = output
-        outf = open(outfile, 'w')
+        outf = open(outfile, "w")
         gcore.debug("output file=[%s]" % outfile)
 
     # set up output style
@@ -250,8 +250,7 @@ def main():
     # Convert cs2cs DMS format to GRASS DMS format:
     #   cs2cs | sed -e 's/d/:/g' -e "s/'/:/g"  -e 's/"//g'
 
-    cmd = ['cs2cs'] + copyinp + outfmt + \
-        in_proj.split() + ['+to'] + out_proj.split()
+    cmd = ["cs2cs"] + copyinp + outfmt + in_proj.split() + ["+to"] + out_proj.split()
 
     p = gcore.Popen(cmd, stdin=gcore.PIPE, stdout=gcore.PIPE)
 
@@ -263,29 +262,39 @@ def main():
             outf.write("x%sy%sz\n" % (ofs, ofs))
         for line in p.stdout:
             try:
-                xy, z = decode(line).split(' ', 1)
-                x, y = xy.split('\t')
+                xy, z = decode(line).split(" ", 1)
+                x, y = xy.split("\t")
             except ValueError:
                 gcore.fatal(line)
 
-            outf.write('%s%s%s%s%s\n' %
-                       (x.strip(), ofs, y.strip(), ofs, z.strip()))
+            outf.write("%s%s%s%s%s\n" % (x.strip(), ofs, y.strip(), ofs, z.strip()))
     else:
         if include_header:
             outf.write("input_x%sinput_y%sx%sy%sz\n" % (ofs, ofs, ofs, ofs))
         for line in p.stdout:
-            inXYZ, x, rest = decode(line).split('\t')
-            inX, inY = inXYZ.split(' ')[:2]
-            y, z = rest.split(' ', 1)
-            outf.write('%s%s%s%s%s%s%s%s%s\n' %
-                       (inX.strip(), ofs, inY.strip(), ofs, x.strip(),
-                        ofs, y.strip(), ofs, z.strip()))
+            inXYZ, x, rest = decode(line).split("\t")
+            inX, inY = inXYZ.split(" ")[:2]
+            y, z = rest.split(" ", 1)
+            outf.write(
+                "%s%s%s%s%s%s%s%s%s\n"
+                % (
+                    inX.strip(),
+                    ofs,
+                    inY.strip(),
+                    ofs,
+                    x.strip(),
+                    ofs,
+                    y.strip(),
+                    ofs,
+                    z.strip(),
+                )
+            )
 
     p.wait()
 
     if p.returncode != 0:
-        gcore.warning(_(
-            "Projection transform probably failed, please investigate"))
+        gcore.warning(_("Projection transform probably failed, please investigate"))
+
 
 if __name__ == "__main__":
     options, flags = gcore.parser()

+ 70 - 53
scripts/r.blend/r.blend.py

@@ -8,9 +8,9 @@
 # PURPOSE:	To redraw current displayed maps to 24 bit PNG output
 # COPYRIGHT:	(C) 2004-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.
+# 		This program is free software under the GNU General Public
+# 		License (>=v2). Read the file COPYING that comes with GRASS
+# 		for details.
 #
 #############################################################################
 
@@ -49,17 +49,17 @@ import grass.script as gscript
 
 
 def main():
-    first = options['first']
-    second = options['second']
-    output = options['output']
-    percent = options['percent']
+    first = options["first"]
+    second = options["second"]
+    output = options["output"]
+    percent = options["percent"]
 
-    mapset = gscript.gisenv()['MAPSET']
+    mapset = gscript.gisenv()["MAPSET"]
 
     if not gscript.overwrite():
-        for ch in ['r', 'g', 'b']:
-            map = '%s.%s' % (output, ch)
-            if gscript.find_file(map, element='cell', mapset=mapset)['file']:
+        for ch in ["r", "g", "b"]:
+            map = "%s.%s" % (output, ch)
+            if gscript.find_file(map, element="cell", mapset=mapset)["file"]:
                 gscript.fatal(_("Raster map <%s> already exists.") % map)
 
     percent = float(percent)
@@ -70,50 +70,67 @@ def main():
 
     gscript.message(_("Calculating the three component maps..."))
 
-    template = string.Template('$$output.$ch = '
-                               'if(isnull("$$first"), $ch#"$$second", '
-                               'if(isnull("$$second"), $ch#"$$first", '
-                               '$$frac1 * $ch#"$$first" + '
-                               '$$frac2 * $ch#"$$second"))')
-    cmd = [template.substitute(ch=ch) for ch in ['r', 'g', 'b']]
-    cmd = ';'.join(cmd)
-
-    gscript.mapcalc(cmd, output=output, first=first, second=second,
-                    frac1=frac1, frac2=frac2)
-
-    for ch in ['r', 'g', 'b']:
+    template = string.Template(
+        "$$output.$ch = "
+        'if(isnull("$$first"), $ch#"$$second", '
+        'if(isnull("$$second"), $ch#"$$first", '
+        '$$frac1 * $ch#"$$first" + '
+        '$$frac2 * $ch#"$$second"))'
+    )
+    cmd = [template.substitute(ch=ch) for ch in ["r", "g", "b"]]
+    cmd = ";".join(cmd)
+
+    gscript.mapcalc(
+        cmd, output=output, first=first, second=second, frac1=frac1, frac2=frac2
+    )
+
+    for ch in ["r", "g", "b"]:
         map = "%s.%s" % (output, ch)
-        gscript.run_command('r.colors', map=map, color='grey255')
-        gscript.run_command('r.support', map=map, history="",
-                            title="Color blend of %s and %s" % (first, second),
-                            description="generated by r.blend")
-        gscript.run_command('r.support', map=map,
-                            history="r.blend %s channel." % ch)
-        gscript.run_command('r.support', map=map,
-                            history="  %d%% of %s, %d%% of %s" %
-                                    (percent, first, perc_inv, second))
-        gscript.run_command('r.support', map=map, history="")
-        gscript.run_command('r.support', map=map, history=os.environ['CMDLINE'])
-
-    if flags['c']:
-        gscript.run_command('r.composite', r='%s.r' % output,
-                            g='%s.g' % output, b='%s.b' % output,
-                            output=output)
-
-        gscript.run_command('r.support', map=output, history="",
-                            title="Color blend of %s and %s" % (first, second),
-                            description="generated by r.blend")
-        gscript.run_command('r.support', map=output,
-                            history="  %d%% of %s, %d%% of %s" %
-                                    (percent, first, perc_inv, second))
-        gscript.run_command('r.support', map=output, history="")
-        gscript.run_command('r.support', map=output,
-                            history=os.environ['CMDLINE'])
+        gscript.run_command("r.colors", map=map, color="grey255")
+        gscript.run_command(
+            "r.support",
+            map=map,
+            history="",
+            title="Color blend of %s and %s" % (first, second),
+            description="generated by r.blend",
+        )
+        gscript.run_command("r.support", map=map, history="r.blend %s channel." % ch)
+        gscript.run_command(
+            "r.support",
+            map=map,
+            history="  %d%% of %s, %d%% of %s" % (percent, first, perc_inv, second),
+        )
+        gscript.run_command("r.support", map=map, history="")
+        gscript.run_command("r.support", map=map, history=os.environ["CMDLINE"])
+
+    if flags["c"]:
+        gscript.run_command(
+            "r.composite",
+            r="%s.r" % output,
+            g="%s.g" % output,
+            b="%s.b" % output,
+            output=output,
+        )
+
+        gscript.run_command(
+            "r.support",
+            map=output,
+            history="",
+            title="Color blend of %s and %s" % (first, second),
+            description="generated by r.blend",
+        )
+        gscript.run_command(
+            "r.support",
+            map=output,
+            history="  %d%% of %s, %d%% of %s" % (percent, first, perc_inv, second),
+        )
+        gscript.run_command("r.support", map=output, history="")
+        gscript.run_command("r.support", map=output, history=os.environ["CMDLINE"])
     else:
-        gscript.message(_("Done. Use the following command to visualize "
-                          "the result:"))
-        gscript.message(_("d.rgb r=%s.r g=%s.g b=%s.b") %
-                        (output, output, output))
+        gscript.message(
+            _("Done. Use the following command to visualize " "the result:")
+        )
+        gscript.message(_("d.rgb r=%s.r g=%s.g b=%s.b") % (output, output, output))
 
 
 if __name__ == "__main__":

+ 17 - 15
scripts/r.blend/testsuite/test_r_blend.py

@@ -13,35 +13,37 @@ from grass.script.core import run_command
 class TestRBlend(TestCase):
     """Test r.blend script"""
 
-    map1 = 'aspect'
-    map2 = 'elevation'
-    temp1 = 'elev_shade_blend.r'
-    temp2 = 'elev_shade_blend.g'
-    temp3 = 'elev_shade_blend.b'
+    map1 = "aspect"
+    map2 = "elevation"
+    temp1 = "elev_shade_blend.r"
+    temp2 = "elev_shade_blend.g"
+    temp3 = "elev_shade_blend.b"
 
     @classmethod
     def setUpClass(cls):
         """Create maps in a small region."""
         cls.use_temp_region()
-        cls.runModule('g.region', raster=cls.map1, flags='p')
-        run_command('d.mon', start='png')
+        cls.runModule("g.region", raster=cls.map1, flags="p")
+        run_command("d.mon", start="png")
 
     @classmethod
     def tearDownClass(cls):
         """Remove temporary region"""
-        cls.runModule('g.remove', flags='f', type='raster',
-                      name=(cls.temp1, cls.temp2, cls.temp3))
+        cls.runModule(
+            "g.remove", flags="f", type="raster", name=(cls.temp1, cls.temp2, cls.temp3)
+        )
         cls.del_temp_region()
-        run_command('d.mon', stop='png')
+        run_command("d.mon", stop="png")
 
     def test_blend(self):
         """blends color test"""
-        module = SimpleModule('r.blend', first=self.map1, second=self.map2,
-                              output='elev_shade_blend')
+        module = SimpleModule(
+            "r.blend", first=self.map1, second=self.map2, output="elev_shade_blend"
+        )
         self.assertModule(module)
 
-        run_command('d.rgb', red=self.temp1, green=self.temp2,
-                    blue=self.temp3)
+        run_command("d.rgb", red=self.temp1, green=self.temp2, blue=self.temp3)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 20 - 15
scripts/r.blend/testsuite/test_r_blend_quoting.py

@@ -15,15 +15,15 @@ from grass.gunittest.utils import silent_rmtree
 class TestRBlend(TestCase):
     """Test r.blend script"""
 
-    map1 = 'elevation'
-    map2 = 'aspect'
-    temp1 = 'elev_shade_blend.r'
-    temp2 = 'elev_shade_blend.g'
-    temp3 = 'elev_shade_blend.b'
+    map1 = "elevation"
+    map2 = "aspect"
+    temp1 = "elev_shade_blend.r"
+    temp2 = "elev_shade_blend.g"
+    temp3 = "elev_shade_blend.b"
     mapsets_to_remove = []
     # mapset with a name is also a valid mathematical expression
     mapset_name = "1234-56-78"
-    gisenv = SimpleModule('g.gisenv', get='MAPSET')
+    gisenv = SimpleModule("g.gisenv", get="MAPSET")
     TestCase.runModule(gisenv, expecting_stdout=True)
     old_mapset = gisenv.outputs.stdout.strip()
 
@@ -33,20 +33,21 @@ class TestRBlend(TestCase):
         # create a mapset with a name is also a valid mathematical expression
         cls.runModule("g.mapset", flags="c", mapset=cls.mapset_name)
         cls.mapsets_to_remove.append(cls.mapset_name)
-        run_command('g.copy', raster=cls.map1 + '@PERMANENT,' + cls.map1)
-        cls.runModule('g.region', raster=cls.map1, flags='p')
+        run_command("g.copy", raster=cls.map1 + "@PERMANENT," + cls.map1)
+        cls.runModule("g.region", raster=cls.map1, flags="p")
 
     @classmethod
     def tearDownClass(cls):
         """Remove temporary data"""
-        gisenv = SimpleModule('g.gisenv', get='GISDBASE')
+        gisenv = SimpleModule("g.gisenv", get="GISDBASE")
         cls.runModule(gisenv, expecting_stdout=True)
         gisdbase = gisenv.outputs.stdout.strip()
-        gisenv = SimpleModule('g.gisenv', get='LOCATION_NAME')
+        gisenv = SimpleModule("g.gisenv", get="LOCATION_NAME")
         cls.runModule(gisenv, expecting_stdout=True)
         location = gisenv.outputs.stdout.strip()
-        cls.runModule('g.remove', flags='f', type='raster',
-                      name=(cls.temp1, cls.temp2, cls.temp3))
+        cls.runModule(
+            "g.remove", flags="f", type="raster", name=(cls.temp1, cls.temp2, cls.temp3)
+        )
         cls.runModule("g.mapset", mapset=cls.old_mapset)
         for mapset_name in cls.mapsets_to_remove:
             mapset_path = os.path.join(gisdbase, location, mapset_name)
@@ -56,10 +57,14 @@ class TestRBlend(TestCase):
         """blends test with special mapset name"""
 
         # should not lead to syntax error, unexpected INTEGER, expecting VARNAME or NAME
-        module = SimpleModule('r.blend', first=self.map2, second=self.map1 + '@' + self.mapset_name,
-                              output='elev_shade_blend')
+        module = SimpleModule(
+            "r.blend",
+            first=self.map2,
+            second=self.map1 + "@" + self.mapset_name,
+            output="elev_shade_blend",
+        )
         self.assertModule(module)
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     test()

+ 31 - 26
scripts/r.buffer.lowmem/r.buffer.lowmem.py

@@ -48,55 +48,60 @@ from grass.script.utils import encode
 
 
 scales = {
-    'meters': 1.0,
-    'kilometers': 1000.0,
-    'feet': 0.3048,
-    'miles': 1609.344,
-    'nautmiles': 1852.0
+    "meters": 1.0,
+    "kilometers": 1000.0,
+    "feet": 0.3048,
+    "miles": 1609.344,
+    "nautmiles": 1852.0,
 }
 
 # what to do in case of user break:
 
 
 def cleanup():
-    if grass.find_file(temp_src)['file']:
-        grass.run_command('g.remove', quiet=True, flags='fb', type='raster', name=temp_src)
-    if grass.find_file(temp_dist)['file']:
-        grass.run_command('g.remove', quiet=True, flags='fb', type='raster', name=temp_dist)
+    if grass.find_file(temp_src)["file"]:
+        grass.run_command(
+            "g.remove", quiet=True, flags="fb", type="raster", name=temp_src
+        )
+    if grass.find_file(temp_dist)["file"]:
+        grass.run_command(
+            "g.remove", quiet=True, flags="fb", type="raster", name=temp_dist
+        )
 
 
 def main():
     global temp_dist, temp_src
 
-    input = options['input']
-    output = options['output']
-    distances = options['distances']
-    units = options['units']
-    zero = flags['z']
+    input = options["input"]
+    output = options["output"]
+    distances = options["distances"]
+    units = options["units"]
+    zero = flags["z"]
 
     tmp = str(os.getpid())
     temp_dist = "r.buffer.tmp.%s.dist" % tmp
     temp_src = "r.buffer.tmp.%s.src" % tmp
 
     # check if input file exists
-    if not grass.find_file(input)['file']:
+    if not grass.find_file(input)["file"]:
         grass.fatal(_("Raster map <%s> not found") % input)
 
     scale = scales[units]
 
-    distances = distances.split(',')
+    distances = distances.split(",")
     distances1 = [scale * float(d) for d in distances]
     distances2 = [d * d for d in distances1]
 
-    s = grass.read_command("g.proj", flags='j')
+    s = grass.read_command("g.proj", flags="j")
     kv = grass.parse_key_val(s)
-    if kv['+proj'] == 'longlat':
-        metric = 'geodesic'
+    if kv["+proj"] == "longlat":
+        metric = "geodesic"
     else:
-        metric = 'squared'
+        metric = "squared"
 
-    grass.run_command('r.grow.distance', input=input, metric=metric,
-                      distance=temp_dist, flags='m')
+    grass.run_command(
+        "r.grow.distance", input=input, metric=metric, distance=temp_dist, flags="m"
+    )
 
     if zero:
         exp = "$temp_src = if($input == 0,null(),1)"
@@ -107,7 +112,7 @@ def main():
     grass.mapcalc(exp, temp_src=temp_src, input=input)
 
     exp = "$output = if(!isnull($input),$input,%s)"
-    if metric == 'squared':
+    if metric == "squared":
         for n, dist2 in enumerate(distances2):
             exp %= "if($dist <= %f,%d,%%s)" % (dist2, n + 2)
     else:
@@ -118,8 +123,7 @@ def main():
     grass.message(_("Extracting buffers (2/2)..."))
     grass.mapcalc(exp, output=output, input=temp_src, dist=temp_dist)
 
-    p = grass.feed_command('r.category', map=output,
-                           separator=':', rules='-')
+    p = grass.feed_command("r.category", map=output, separator=":", rules="-")
     msg = "1:distances calculated from these locations\n"
     p.stdin.write(encode(msg))
     d0 = "0"
@@ -130,11 +134,12 @@ def main():
     p.stdin.close()
     p.wait()
 
-    grass.run_command('r.colors', map=output, color='rainbow')
+    grass.run_command("r.colors", map=output, color="rainbow")
 
     # write cmd history:
     grass.raster_history(output)
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     atexit.register(cleanup)

+ 73 - 56
scripts/r.colors.stddev/r.colors.stddev.py

@@ -43,32 +43,37 @@ def z(n):
 
 def cleanup():
     if tmpmap:
-        gscript.run_command('g.remove', flags='f', type='raster',
-                            name=tmpmap, quiet=True)
+        gscript.run_command(
+            "g.remove", flags="f", type="raster", name=tmpmap, quiet=True
+        )
 
 
 def main():
     global tmpmap
     tmpmap = None
 
-    map = options['map']
-    zero = flags['z']
-    bands = flags['b']
+    map = options["map"]
+    zero = flags["z"]
+    bands = flags["b"]
 
     if not zero:
-        s = gscript.read_command('r.univar', flags='g', map=map)
+        s = gscript.read_command("r.univar", flags="g", map=map)
         kv = gscript.parse_key_val(decode(s))
         global mean, stddev
-        mean = float(kv['mean'])
-        stddev = float(kv['stddev'])
+        mean = float(kv["mean"])
+        stddev = float(kv["stddev"])
 
         if not bands:
             # smooth free floating blue/white/red
-            rules = '\n'.join(["0% blue",
-                               "%f blue" % z(-2),
-                               "%f white" % mean,
-                               "%f red" % z(+2),
-                               "100% red"])
+            rules = "\n".join(
+                [
+                    "0% blue",
+                    "%f blue" % z(-2),
+                    "%f white" % mean,
+                    "%f red" % z(+2),
+                    "100% red",
+                ]
+            )
         else:
             # banded free floating  black/red/yellow/green/yellow/red/black
 
@@ -77,66 +82,78 @@ def main():
             # EOF
 
             # >3 S.D. outliers colored black so they show up in d.histogram w/ white background
-            rules = '\n'.join(["0% black",
-                               "%f black" % z(-3),
-                               "%f red" % z(-3),
-                               "%f red" % z(-2),
-                               "%f yellow" % z(-2),
-                               "%f yellow" % z(-1),
-                               "%f green" % z(-1),
-                               "%f green" % z(+1),
-                               "%f yellow" % z(+1),
-                               "%f yellow" % z(+2),
-                               "%f red" % z(+2),
-                               "%f red" % z(+3),
-                               "%f black" % z(+3),
-                               "100% black"])
+            rules = "\n".join(
+                [
+                    "0% black",
+                    "%f black" % z(-3),
+                    "%f red" % z(-3),
+                    "%f red" % z(-2),
+                    "%f yellow" % z(-2),
+                    "%f yellow" % z(-1),
+                    "%f green" % z(-1),
+                    "%f green" % z(+1),
+                    "%f yellow" % z(+1),
+                    "%f yellow" % z(+2),
+                    "%f red" % z(+2),
+                    "%f red" % z(+3),
+                    "%f black" % z(+3),
+                    "100% black",
+                ]
+            )
     else:
         tmpmap = "r_col_stdev_abs_%d" % os.getpid()
         gscript.mapcalc("$tmp = abs($map)", tmp=tmpmap, map=map)
 
         # data centered on 0  (e.g. map of deviations)
         info = gscript.raster_info(tmpmap)
-        maxv = info['max']
+        maxv = info["max"]
 
         # current r.univar truncates percentage to the base integer
-        s = gscript.read_command('r.univar', flags='eg', map=map,
-                                 percentile=[95.45,
-                                             68.2689,
-                                             99.7300])
+        s = gscript.read_command(
+            "r.univar", flags="eg", map=map, percentile=[95.45, 68.2689, 99.7300]
+        )
         kv = gscript.parse_key_val(decode(s))
 
-        stddev1 = float(kv['percentile_68_2689'])
-        stddev2 = float(kv['percentile_95_45'])
-        stddev3 = float(kv['percentile_99_73'])
+        stddev1 = float(kv["percentile_68_2689"])
+        stddev2 = float(kv["percentile_95_45"])
+        stddev3 = float(kv["percentile_99_73"])
 
         if not bands:
             # zero centered smooth blue/white/red
-            rules = '\n'.join(["%f blue" % -maxv,
-                               "%f blue" % -stddev2,
-                               "0 white",
-                               "%f red" % stddev2,
-                               "%f red" % maxv])
+            rules = "\n".join(
+                [
+                    "%f blue" % -maxv,
+                    "%f blue" % -stddev2,
+                    "0 white",
+                    "%f red" % stddev2,
+                    "%f red" % maxv,
+                ]
+            )
         else:
             # zero centered banded  black/red/yellow/green/yellow/red/black
 
             # >3 S.D. outliers colored black so they show up in d.histogram w/ white background
-            rules = '\n'.join(["%f black" % -maxv,
-                               "%f black" % -stddev3,
-                               "%f red" % -stddev3,
-                               "%f red" % -stddev2,
-                               "%f yellow" % -stddev2,
-                               "%f yellow" % -stddev1,
-                               "%f green" % -stddev1,
-                               "%f green" % stddev1,
-                               "%f yellow" % stddev1,
-                               "%f yellow" % stddev2,
-                               "%f red" % stddev2,
-                               "%f red" % stddev3,
-                               "%f black" % stddev3,
-                               "%f black" % maxv, ])
-
-    gscript.write_command('r.colors', map=map, rules='-', stdin=rules)
+            rules = "\n".join(
+                [
+                    "%f black" % -maxv,
+                    "%f black" % -stddev3,
+                    "%f red" % -stddev3,
+                    "%f red" % -stddev2,
+                    "%f yellow" % -stddev2,
+                    "%f yellow" % -stddev1,
+                    "%f green" % -stddev1,
+                    "%f green" % stddev1,
+                    "%f yellow" % stddev1,
+                    "%f yellow" % stddev2,
+                    "%f red" % stddev2,
+                    "%f red" % stddev3,
+                    "%f black" % stddev3,
+                    "%f black" % maxv,
+                ]
+            )
+
+    gscript.write_command("r.colors", map=map, rules="-", stdin=rules)
+
 
 if __name__ == "__main__":
     options, flags = gscript.parser()

+ 35 - 24
scripts/r.drain/r.drain.py

@@ -119,18 +119,20 @@ def cleanup():
     """Delete temporary direction map."""
     if tmp_maps:
         try:
-            grass.run_command("g.remove", flags='f', quiet=True, type='raster', name=tmp_maps)
+            grass.run_command(
+                "g.remove", flags="f", quiet=True, type="raster", name=tmp_maps
+            )
         except:
             pass
 
 
 def main():
-    valmap = options['input']
-    dirmap = options['direction']
-    rpathmap = options['output']
-    vpathmap = options['drain']
-    start_coords = options['start_coordinates']
-    start_pnts = options['start_points']
+    valmap = options["input"]
+    dirmap = options["direction"]
+    rpathmap = options["output"]
+    vpathmap = options["drain"]
+    start_coords = options["start_coordinates"]
+    start_pnts = options["start_points"]
 
     global tmp_maps
     tmp_maps = False
@@ -141,36 +143,45 @@ def main():
         dirmap = "%s_tmp_%d" % (valmap, os.getpid())
         fill_map = "%s_fill_%d" % (valmap, os.getpid())
         area_map = "%s_area_%d" % (valmap, os.getpid())
-        tmp_maps = dirmap + ',' + fill_map + ',' + area_map
-        grass.run_command("r.fill.dir", input=valmap, output=fill_map, direction=dirmap, areas=area_map, flags='f', format='grass')
+        tmp_maps = dirmap + "," + fill_map + "," + area_map
+        grass.run_command(
+            "r.fill.dir",
+            input=valmap,
+            output=fill_map,
+            direction=dirmap,
+            areas=area_map,
+            flags="f",
+            format="grass",
+        )
 
     # create args for r.path
     kwargs = {}
-    kwargs['input'] = dirmap
-    if flags['c'] or flags['a']:
-        kwargs['values'] = valmap
-    kwargs['format'] = 'degree'
+    kwargs["input"] = dirmap
+    if flags["c"] or flags["a"]:
+        kwargs["values"] = valmap
+    kwargs["format"] = "degree"
     if start_coords:
-        kwargs['start_coordinates'] = start_coords
+        kwargs["start_coordinates"] = start_coords
     if start_pnts:
-        kwargs['start_points'] = start_pnts
+        kwargs["start_points"] = start_pnts
     if rpathmap:
-        kwargs['raster_path'] = rpathmap
+        kwargs["raster_path"] = rpathmap
     if vpathmap:
-        kwargs['vector_path'] = vpathmap
+        kwargs["vector_path"] = vpathmap
 
-    pathflags = ''
-    if flags['c']:
-        pathflags += 'c'
-    if flags['a']:
-        pathflags += 'a'
-    if flags['n']:
-        pathflags += 'n'
+    pathflags = ""
+    if flags["c"]:
+        pathflags += "c"
+    if flags["a"]:
+        pathflags += "a"
+    if flags["n"]:
+        pathflags += "n"
 
     grass.run_command("r.path", flags=pathflags, **kwargs)
 
     return 0
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     sys.exit(main())

+ 334 - 169
scripts/r.fillnulls/r.fillnulls.py

@@ -119,35 +119,43 @@ mapset = None
 def cleanup():
     # delete internal mask and any TMP files:
     if len(tmp_vmaps) > 0:
-        grass.run_command('g.remove', quiet=True, flags='fb', type='vector', name=tmp_vmaps)
+        grass.run_command(
+            "g.remove", quiet=True, flags="fb", type="vector", name=tmp_vmaps
+        )
     if len(tmp_rmaps) > 0:
-        grass.run_command('g.remove', quiet=True, flags='fb', type='raster', name=tmp_rmaps)
+        grass.run_command(
+            "g.remove", quiet=True, flags="fb", type="raster", name=tmp_rmaps
+        )
     if usermask and mapset:
-        if grass.find_file(usermask, mapset=mapset)['file']:
-            grass.run_command('g.rename', quiet=True, raster=(usermask, 'MASK'), overwrite=True)
+        if grass.find_file(usermask, mapset=mapset)["file"]:
+            grass.run_command(
+                "g.rename", quiet=True, raster=(usermask, "MASK"), overwrite=True
+            )
 
 
 def main():
     global usermask, mapset, tmp_rmaps, tmp_vmaps
 
-    input = options['input']
-    output = options['output']
-    tension = options['tension']
-    smooth = options['smooth']
-    method = options['method']
-    edge = int(options['edge'])
-    segmax = int(options['segmax'])
-    npmin = int(options['npmin'])
-    lambda_ = float(options['lambda'])
-    memory = options['memory']
+    input = options["input"]
+    output = options["output"]
+    tension = options["tension"]
+    smooth = options["smooth"]
+    method = options["method"]
+    edge = int(options["edge"])
+    segmax = int(options["segmax"])
+    npmin = int(options["npmin"])
+    lambda_ = float(options["lambda"])
+    memory = options["memory"]
     quiet = True  # FIXME
-    mapset = grass.gisenv()['MAPSET']
+    mapset = grass.gisenv()["MAPSET"]
     unique = str(os.getpid())  # Shouldn't we use temp name?
-    prefix = 'r_fillnulls_%s_' % unique
-    failed_list = list()  # a list of failed holes. Caused by issues with v.surf.rst. Connected with #1813
+    prefix = "r_fillnulls_%s_" % unique
+    failed_list = (
+        list()
+    )  # a list of failed holes. Caused by issues with v.surf.rst. Connected with #1813
 
     # check if input file exists
-    if not grass.find_file(input)['file']:
+    if not grass.find_file(input)["file"]:
         grass.fatal(_("Raster map <%s> not found") % input)
 
     # save original region
@@ -156,22 +164,22 @@ def main():
     # check if a MASK is already present
     # and remove it to not interfere with NULL lookup part
     # as we don't fill MASKed parts!
-    if grass.find_file('MASK', mapset=mapset)['file']:
+    if grass.find_file("MASK", mapset=mapset)["file"]:
         usermask = "usermask_mask." + unique
         grass.message(_("A user raster mask (MASK) is present. Saving it..."))
-        grass.run_command('g.rename', quiet=quiet, raster=('MASK', usermask))
+        grass.run_command("g.rename", quiet=quiet, raster=("MASK", usermask))
 
     # check if method is rst to use v.surf.rst
-    if method == 'rst':
+    if method == "rst":
         # idea: filter all NULLS and grow that area(s) by 3 pixel, then
         # interpolate from these surrounding 3 pixel edge
-        filling = prefix + 'filled'
+        filling = prefix + "filled"
 
         grass.use_temp_region()
-        grass.run_command('g.region', align=input, quiet=quiet)
+        grass.run_command("g.region", align=input, quiet=quiet)
         region = grass.region()
-        ns_res = region['nsres']
-        ew_res = region['ewres']
+        ns_res = region["nsres"]
+        ew_res = region["ewres"]
 
         grass.message(_("Using RST interpolation..."))
         grass.message(_("Locating and isolating NULL areas..."))
@@ -179,77 +187,111 @@ def main():
         # creating binary (0/1) map
         if usermask:
             grass.message(_("Skipping masked raster parts"))
-            grass.mapcalc("$tmp1 = if(isnull(\"$input\") && !($mask == 0 || isnull($mask)),1,null())",
-                          tmp1=prefix + 'nulls', input=input, mask=usermask)
+            grass.mapcalc(
+                '$tmp1 = if(isnull("$input") && !($mask == 0 || isnull($mask)),1,null())',
+                tmp1=prefix + "nulls",
+                input=input,
+                mask=usermask,
+            )
         else:
-            grass.mapcalc("$tmp1 = if(isnull(\"$input\"),1,null())",
-                          tmp1=prefix + 'nulls', input=input)
-        tmp_rmaps.append(prefix + 'nulls')
+            grass.mapcalc(
+                '$tmp1 = if(isnull("$input"),1,null())',
+                tmp1=prefix + "nulls",
+                input=input,
+            )
+        tmp_rmaps.append(prefix + "nulls")
 
         # restoring user's mask, if present
         # to ignore MASKed original values
         if usermask:
             grass.message(_("Restoring user mask (MASK)..."))
             try:
-                grass.run_command('g.rename', quiet=quiet, raster=(usermask, 'MASK'))
+                grass.run_command("g.rename", quiet=quiet, raster=(usermask, "MASK"))
             except CalledModuleError:
                 grass.warning(_("Failed to restore user MASK!"))
             usermask = None
 
         # grow identified holes by X pixels
         grass.message(_("Growing NULL areas"))
-        tmp_rmaps.append(prefix + 'grown')
+        tmp_rmaps.append(prefix + "grown")
         try:
-            grass.run_command('r.grow', input=prefix + 'nulls',
-                              radius=edge + 0.01, old=1, new=1,
-                              out=prefix + 'grown', quiet=quiet)
+            grass.run_command(
+                "r.grow",
+                input=prefix + "nulls",
+                radius=edge + 0.01,
+                old=1,
+                new=1,
+                out=prefix + "grown",
+                quiet=quiet,
+            )
         except CalledModuleError:
-            grass.fatal(_("abandoned. Removing temporary map, restoring "
-                          "user mask if needed:"))
+            grass.fatal(
+                _(
+                    "abandoned. Removing temporary map, restoring "
+                    "user mask if needed:"
+                )
+            )
 
         # assign unique IDs to each hole or hole system (holes closer than edge distance)
         grass.message(_("Assigning IDs to NULL areas"))
-        tmp_rmaps.append(prefix + 'clumped')
+        tmp_rmaps.append(prefix + "clumped")
         try:
             grass.run_command(
-                'r.clump',
-                input=prefix +
-                'grown',
-                output=prefix +
-                'clumped',
-                quiet=quiet)
+                "r.clump",
+                input=prefix + "grown",
+                output=prefix + "clumped",
+                quiet=quiet,
+            )
         except CalledModuleError:
-            grass.fatal(_("abandoned. Removing temporary map, restoring "
-                          "user mask if needed:"))
+            grass.fatal(
+                _(
+                    "abandoned. Removing temporary map, restoring "
+                    "user mask if needed:"
+                )
+            )
 
         # get a list of unique hole cat's
-        grass.mapcalc("$out = if(isnull($inp), null(), $clumped)",
-                      out=prefix + 'holes', inp=prefix + 'nulls', clumped=prefix + 'clumped')
-        tmp_rmaps.append(prefix + 'holes')
+        grass.mapcalc(
+            "$out = if(isnull($inp), null(), $clumped)",
+            out=prefix + "holes",
+            inp=prefix + "nulls",
+            clumped=prefix + "clumped",
+        )
+        tmp_rmaps.append(prefix + "holes")
 
         # use new IDs to identify holes
         try:
-            grass.run_command('r.to.vect', flags='v',
-                              input=prefix + 'holes', output=prefix + 'holes',
-                              type='area', quiet=quiet)
+            grass.run_command(
+                "r.to.vect",
+                flags="v",
+                input=prefix + "holes",
+                output=prefix + "holes",
+                type="area",
+                quiet=quiet,
+            )
         except:
-            grass.fatal(_("abandoned. Removing temporary maps, restoring "
-                          "user mask if needed:"))
-        tmp_vmaps.append(prefix + 'holes')
+            grass.fatal(
+                _(
+                    "abandoned. Removing temporary maps, restoring "
+                    "user mask if needed:"
+                )
+            )
+        tmp_vmaps.append(prefix + "holes")
 
         # get a list of unique hole cat's
         cats_file_name = grass.tempfile(False)
         grass.run_command(
-            'v.db.select',
-            flags='c',
-            map=prefix + 'holes',
-            columns='cat',
+            "v.db.select",
+            flags="c",
+            map=prefix + "holes",
+            columns="cat",
             file=cats_file_name,
-            quiet=quiet)
+            quiet=quiet,
+        )
         cat_list = list()
         cats_file = open(cats_file_name)
         for line in cats_file:
-            cat_list.append(line.rstrip('\n'))
+            cat_list.append(line.rstrip("\n"))
         cats_file.close()
         os.remove(cats_file_name)
 
@@ -261,46 +303,74 @@ def main():
         first = True
         hole_n = 1
         for cat in cat_list:
-            holename = prefix + 'hole_' + cat
+            holename = prefix + "hole_" + cat
             # GTC Hole is a NULL area in a raster map
             grass.message(_("Filling hole %s of %s") % (hole_n, len(cat_list)))
             hole_n = hole_n + 1
             # cut out only CAT hole for processing
             try:
-                grass.run_command('v.extract', input=prefix + 'holes',
-                                  output=holename + '_pol',
-                                  cats=cat, quiet=quiet)
+                grass.run_command(
+                    "v.extract",
+                    input=prefix + "holes",
+                    output=holename + "_pol",
+                    cats=cat,
+                    quiet=quiet,
+                )
             except CalledModuleError:
-                grass.fatal(_("abandoned. Removing temporary maps, restoring "
-                              "user mask if needed:"))
-            tmp_vmaps.append(holename + '_pol')
+                grass.fatal(
+                    _(
+                        "abandoned. Removing temporary maps, restoring "
+                        "user mask if needed:"
+                    )
+                )
+            tmp_vmaps.append(holename + "_pol")
 
             # zoom to specific hole with a buffer of two cells around the hole to
             # remove rest of data
             try:
-                grass.run_command('g.region',
-                                  vector=holename + '_pol', align=input,
-                                  w='w-%d' % (edge * 2 * ew_res),
-                                  e='e+%d' % (edge * 2 * ew_res),
-                                  n='n+%d' % (edge * 2 * ns_res),
-                                  s='s-%d' % (edge * 2 * ns_res),
-                                  quiet=quiet)
+                grass.run_command(
+                    "g.region",
+                    vector=holename + "_pol",
+                    align=input,
+                    w="w-%d" % (edge * 2 * ew_res),
+                    e="e+%d" % (edge * 2 * ew_res),
+                    n="n+%d" % (edge * 2 * ns_res),
+                    s="s-%d" % (edge * 2 * ns_res),
+                    quiet=quiet,
+                )
             except CalledModuleError:
-                grass.fatal(_("abandoned. Removing temporary maps, restoring "
-                              "user mask if needed:"))
+                grass.fatal(
+                    _(
+                        "abandoned. Removing temporary maps, restoring "
+                        "user mask if needed:"
+                    )
+                )
 
             # remove temporary map to not overfill disk
             try:
-                grass.run_command('g.remove', flags='fb', type='vector',
-                                  name=holename + '_pol', quiet=quiet)
+                grass.run_command(
+                    "g.remove",
+                    flags="fb",
+                    type="vector",
+                    name=holename + "_pol",
+                    quiet=quiet,
+                )
             except CalledModuleError:
-                grass.fatal(_("abandoned. Removing temporary maps, restoring "
-                              "user mask if needed:"))
-            tmp_vmaps.remove(holename + '_pol')
+                grass.fatal(
+                    _(
+                        "abandoned. Removing temporary maps, restoring "
+                        "user mask if needed:"
+                    )
+                )
+            tmp_vmaps.remove(holename + "_pol")
 
             # copy only data around hole
-            grass.mapcalc("$out = if($inp == $catn, $inp, null())",
-                          out=holename, inp=prefix + 'holes', catn=cat)
+            grass.mapcalc(
+                "$out = if($inp == $catn, $inp, null())",
+                out=holename,
+                inp=prefix + "holes",
+                catn=cat,
+            )
             tmp_rmaps.append(holename)
 
             # If here loop is split into two, next part of loop can be run in parallel
@@ -308,31 +378,54 @@ def main():
             # Downside - on large maps such approach causes large disk usage
 
             # grow hole border to get it's edge area
-            tmp_rmaps.append(holename + '_grown')
+            tmp_rmaps.append(holename + "_grown")
             try:
-                grass.run_command('r.grow', input=holename, radius=edge + 0.01,
-                                  old=-1, out=holename + '_grown', quiet=quiet)
+                grass.run_command(
+                    "r.grow",
+                    input=holename,
+                    radius=edge + 0.01,
+                    old=-1,
+                    out=holename + "_grown",
+                    quiet=quiet,
+                )
             except CalledModuleError:
-                grass.fatal(_("abandoned. Removing temporary map, restoring "
-                              "user mask if needed:"))
+                grass.fatal(
+                    _(
+                        "abandoned. Removing temporary map, restoring "
+                        "user mask if needed:"
+                    )
+                )
 
             # no idea why r.grow old=-1 doesn't replace existing values with NULL
-            grass.mapcalc("$out = if($inp == -1, null(), \"$dem\")",
-                          out=holename + '_edges', inp=holename + '_grown', dem=input)
-            tmp_rmaps.append(holename + '_edges')
+            grass.mapcalc(
+                '$out = if($inp == -1, null(), "$dem")',
+                out=holename + "_edges",
+                inp=holename + "_grown",
+                dem=input,
+            )
+            tmp_rmaps.append(holename + "_edges")
 
             # convert to points for interpolation
             tmp_vmaps.append(holename)
             try:
-                grass.run_command('r.to.vect',
-                                  input=holename + '_edges', output=holename,
-                                  type='point', flags='z', quiet=quiet)
+                grass.run_command(
+                    "r.to.vect",
+                    input=holename + "_edges",
+                    output=holename,
+                    type="point",
+                    flags="z",
+                    quiet=quiet,
+                )
             except CalledModuleError:
-                grass.fatal(_("abandoned. Removing temporary maps, restoring "
-                              "user mask if needed:"))
+                grass.fatal(
+                    _(
+                        "abandoned. Removing temporary maps, restoring "
+                        "user mask if needed:"
+                    )
+                )
 
             # count number of points to control segmax parameter for interpolation:
-            pointsnumber = grass.vector_info_topo(map=holename)['points']
+            pointsnumber = grass.vector_info_topo(map=holename)["points"]
             grass.verbose(_("Interpolating %d points") % pointsnumber)
 
             if pointsnumber < 2:
@@ -349,169 +442,238 @@ def main():
                 use_segmax = segmax
 
             # launch v.surf.rst
-            tmp_rmaps.append(holename + '_dem')
+            tmp_rmaps.append(holename + "_dem")
             try:
-                grass.run_command('v.surf.rst', quiet=quiet,
-                                  input=holename, elev=holename + '_dem',
-                                  tension=tension, smooth=smooth,
-                                  segmax=use_segmax, npmin=use_npmin)
+                grass.run_command(
+                    "v.surf.rst",
+                    quiet=quiet,
+                    input=holename,
+                    elev=holename + "_dem",
+                    tension=tension,
+                    smooth=smooth,
+                    segmax=use_segmax,
+                    npmin=use_npmin,
+                )
             except CalledModuleError:
                 # GTC Hole is NULL area in a raster map
                 grass.fatal(_("Failed to fill hole %s") % cat)
 
             # v.surf.rst sometimes fails with exit code 0
             # related bug #1813
-            if not grass.find_file(holename + '_dem')['file']:
+            if not grass.find_file(holename + "_dem")["file"]:
                 try:
                     tmp_rmaps.remove(holename)
-                    tmp_rmaps.remove(holename + '_grown')
-                    tmp_rmaps.remove(holename + '_edges')
-                    tmp_rmaps.remove(holename + '_dem')
+                    tmp_rmaps.remove(holename + "_grown")
+                    tmp_rmaps.remove(holename + "_edges")
+                    tmp_rmaps.remove(holename + "_dem")
                     tmp_vmaps.remove(holename)
                 except:
                     pass
                 grass.warning(
-                    _("Filling has failed silently. Leaving temporary maps "
-                      "with prefix <%s> for debugging.") %
-                    holename)
+                    _(
+                        "Filling has failed silently. Leaving temporary maps "
+                        "with prefix <%s> for debugging."
+                    )
+                    % holename
+                )
                 failed_list.append(holename)
                 continue
 
             # append hole result to interpolated version later used to patch into original DEM
             if first:
                 tmp_rmaps.append(filling)
-                grass.run_command('g.region', align=input, raster=holename + '_dem', quiet=quiet)
-                grass.mapcalc("$out = if(isnull($inp), null(), $dem)",
-                              out=filling, inp=holename, dem=holename + '_dem')
+                grass.run_command(
+                    "g.region", align=input, raster=holename + "_dem", quiet=quiet
+                )
+                grass.mapcalc(
+                    "$out = if(isnull($inp), null(), $dem)",
+                    out=filling,
+                    inp=holename,
+                    dem=holename + "_dem",
+                )
                 first = False
             else:
-                tmp_rmaps.append(filling + '_tmp')
+                tmp_rmaps.append(filling + "_tmp")
                 grass.run_command(
-                    'g.region', align=input, raster=(
-                        filling, holename + '_dem'), quiet=quiet)
+                    "g.region",
+                    align=input,
+                    raster=(filling, holename + "_dem"),
+                    quiet=quiet,
+                )
                 grass.mapcalc(
                     "$out = if(isnull($inp), if(isnull($fill), null(), $fill), $dem)",
-                    out=filling + '_tmp',
+                    out=filling + "_tmp",
                     inp=holename,
-                    dem=holename + '_dem',
-                    fill=filling)
+                    dem=holename + "_dem",
+                    fill=filling,
+                )
                 try:
-                    grass.run_command('g.rename',
-                                      raster=(filling + '_tmp', filling),
-                                      overwrite=True, quiet=quiet)
+                    grass.run_command(
+                        "g.rename",
+                        raster=(filling + "_tmp", filling),
+                        overwrite=True,
+                        quiet=quiet,
+                    )
                 except CalledModuleError:
                     grass.fatal(
-                        _("abandoned. Removing temporary maps, restoring user "
-                          "mask if needed:"))
+                        _(
+                            "abandoned. Removing temporary maps, restoring user "
+                            "mask if needed:"
+                        )
+                    )
                 # this map has been removed. No need for later cleanup.
-                tmp_rmaps.remove(filling + '_tmp')
+                tmp_rmaps.remove(filling + "_tmp")
 
             # remove temporary maps to not overfill disk
             try:
                 tmp_rmaps.remove(holename)
-                tmp_rmaps.remove(holename + '_grown')
-                tmp_rmaps.remove(holename + '_edges')
-                tmp_rmaps.remove(holename + '_dem')
+                tmp_rmaps.remove(holename + "_grown")
+                tmp_rmaps.remove(holename + "_edges")
+                tmp_rmaps.remove(holename + "_dem")
             except:
                 pass
             try:
-                grass.run_command('g.remove', quiet=quiet,
-                                  flags='fb', type='raster',
-                                  name=(holename,
-                                        holename + '_grown',
-                                        holename + '_edges',
-                                        holename + '_dem'))
+                grass.run_command(
+                    "g.remove",
+                    quiet=quiet,
+                    flags="fb",
+                    type="raster",
+                    name=(
+                        holename,
+                        holename + "_grown",
+                        holename + "_edges",
+                        holename + "_dem",
+                    ),
+                )
             except CalledModuleError:
-                grass.fatal(_("abandoned. Removing temporary maps, restoring "
-                              "user mask if needed:"))
+                grass.fatal(
+                    _(
+                        "abandoned. Removing temporary maps, restoring "
+                        "user mask if needed:"
+                    )
+                )
             try:
                 tmp_vmaps.remove(holename)
             except:
                 pass
             try:
-                grass.run_command('g.remove', quiet=quiet, flags='fb',
-                                  type='vector', name=holename)
+                grass.run_command(
+                    "g.remove", quiet=quiet, flags="fb", type="vector", name=holename
+                )
             except CalledModuleError:
-                grass.fatal(_("abandoned. Removing temporary maps, restoring user mask if needed:"))
+                grass.fatal(
+                    _(
+                        "abandoned. Removing temporary maps, restoring user mask if needed:"
+                    )
+                )
 
     # check if method is different from rst to use r.resamp.bspline
-    if method != 'rst':
+    if method != "rst":
         grass.message(_("Using %s bspline interpolation") % method)
 
         # clone current region
         grass.use_temp_region()
-        grass.run_command('g.region', align=input)
+        grass.run_command("g.region", align=input)
 
         reg = grass.region()
         # launch r.resamp.bspline
-        tmp_rmaps.append(prefix + 'filled')
+        tmp_rmaps.append(prefix + "filled")
         # If there are no NULL cells, r.resamp.bslpine call
         # will end with an error although for our needs it's fine
         # Only problem - this state must be read from stderr
         new_env = dict(os.environ)
-        new_env['LC_ALL'] = 'C'
+        new_env["LC_ALL"] = "C"
         if usermask:
             try:
                 p = grass.core.start_command(
-                    'r.resamp.bspline',
+                    "r.resamp.bspline",
                     input=input,
                     mask=usermask,
-                    output=prefix + 'filled',
+                    output=prefix + "filled",
                     method=method,
-                    ew_step=3 * reg['ewres'],
-                    ns_step=3 * reg['nsres'],
+                    ew_step=3 * reg["ewres"],
+                    ns_step=3 * reg["nsres"],
                     lambda_=lambda_,
                     memory=memory,
-                    flags='n',
+                    flags="n",
                     stderr=subprocess.PIPE,
-                    env=new_env)
+                    env=new_env,
+                )
                 stderr = grass.decode(p.communicate()[1])
                 if "No NULL cells found" in stderr:
-                    grass.run_command('g.copy', raster='%s,%sfilled' % (input, prefix), overwrite=True)
+                    grass.run_command(
+                        "g.copy", raster="%s,%sfilled" % (input, prefix), overwrite=True
+                    )
                     p.returncode = 0
-                    grass.warning(_("Input map <%s> has no holes. Copying to output without modification.") % (input,))
+                    grass.warning(
+                        _(
+                            "Input map <%s> has no holes. Copying to output without modification."
+                        )
+                        % (input,)
+                    )
             except CalledModuleError as e:
-                grass.fatal(_("Failure during bspline interpolation. Error message: %s") % stderr)
+                grass.fatal(
+                    _("Failure during bspline interpolation. Error message: %s")
+                    % stderr
+                )
         else:
             try:
                 p = grass.core.start_command(
-                    'r.resamp.bspline',
+                    "r.resamp.bspline",
                     input=input,
-                    output=prefix + 'filled',
+                    output=prefix + "filled",
                     method=method,
-                    ew_step=3 * reg['ewres'],
-                    ns_step=3 * reg['nsres'],
+                    ew_step=3 * reg["ewres"],
+                    ns_step=3 * reg["nsres"],
                     lambda_=lambda_,
                     memory=memory,
-                    flags='n',
+                    flags="n",
                     stderr=subprocess.PIPE,
-                    env=new_env)
+                    env=new_env,
+                )
                 stderr = grass.decode(p.communicate()[1])
                 if "No NULL cells found" in stderr:
-                    grass.run_command('g.copy', raster='%s,%sfilled' % (input, prefix), overwrite=True)
+                    grass.run_command(
+                        "g.copy", raster="%s,%sfilled" % (input, prefix), overwrite=True
+                    )
                     p.returncode = 0
-                    grass.warning(_("Input map <%s> has no holes. Copying to output without modification.") % (input,))
+                    grass.warning(
+                        _(
+                            "Input map <%s> has no holes. Copying to output without modification."
+                        )
+                        % (input,)
+                    )
             except CalledModuleError as e:
-                grass.fatal(_("Failure during bspline interpolation. Error message: %s") % stderr)
+                grass.fatal(
+                    _("Failure during bspline interpolation. Error message: %s")
+                    % stderr
+                )
 
     # restoring user's mask, if present:
     if usermask:
         grass.message(_("Restoring user mask (MASK)..."))
         try:
-            grass.run_command('g.rename', quiet=quiet, raster=(usermask, 'MASK'))
+            grass.run_command("g.rename", quiet=quiet, raster=(usermask, "MASK"))
         except CalledModuleError:
             grass.warning(_("Failed to restore user MASK!"))
         usermask = None
 
     # set region to original extents, align to input
-    grass.run_command('g.region', n=reg_org['n'], s=reg_org['s'],
-                      e=reg_org['e'], w=reg_org['w'], align=input)
+    grass.run_command(
+        "g.region",
+        n=reg_org["n"],
+        s=reg_org["s"],
+        e=reg_org["e"],
+        w=reg_org["w"],
+        align=input,
+    )
 
     # patch orig and fill map
     grass.message(_("Patching fill data into NULL areas..."))
     # we can use --o here as g.parser already checks on startup
-    grass.run_command('r.patch', input=(input, prefix + 'filled'),
-                      output=output, overwrite=True)
+    grass.run_command(
+        "r.patch", input=(input, prefix + "filled"), output=output, overwrite=True
+    )
 
     # restore the real region
     grass.del_temp_region()
@@ -523,11 +685,14 @@ def main():
 
     if len(failed_list) > 0:
         grass.warning(
-            _("Following holes where not filled. Temporary maps with are left "
-              "in place to allow examination of unfilled holes"))
+            _(
+                "Following holes where not filled. Temporary maps with are left "
+                "in place to allow examination of unfilled holes"
+            )
+        )
         outlist = failed_list[0]
         for hole in failed_list[1:]:
-            outlist = ', ' + outlist
+            outlist = ", " + outlist
         grass.message(outlist)
 
     grass.message(_("Done."))

+ 31 - 21
scripts/r.fillnulls/testsuite/test_r_fillnulls.py

@@ -14,41 +14,51 @@ from grass.script.core import run_command
 class TestRFillNulls(TestCase):
     """Test r.fillnulls script"""
 
-    module = 'r.fillnulls'
-    mapName = 'elevation'
-    expression = 'elevation_filt = if(elevation > 130, \
-    null(), elevation)'
-    mapNameCalc = 'elevation_filt'
-    mapComplete = 'elevation_complete'
-    values = 'null_cells=0'
+    module = "r.fillnulls"
+    mapName = "elevation"
+    expression = "elevation_filt = if(elevation > 130, null(), elevation)"
+    mapNameCalc = "elevation_filt"
+    mapComplete = "elevation_complete"
+    values = "null_cells=0"
 
     def setUp(self):
         """Create maps in a small region."""
         self.use_temp_region()
-        self.runModule('g.region', res=200, raster=self.mapName, flags='ap')
-        run_command('r.mapcalc', expression=self.expression)
+        self.runModule("g.region", res=200, raster=self.mapName, flags="ap")
+        run_command("r.mapcalc", expression=self.expression)
 
     def tearDown(self):
         """Remove temporary region"""
-        self.runModule('g.remove', flags='f', type='raster',
-                       name=(self.mapNameCalc, self.mapComplete))
+        self.runModule(
+            "g.remove",
+            flags="f",
+            type="raster",
+            name=(self.mapNameCalc, self.mapComplete),
+        )
         self.del_temp_region()
 
     def test_rst(self):
-        module = SimpleModule(self.module, input=self.mapNameCalc,
-                              output=self.mapComplete, segmax=1200,
-                              npmin=100, tension=150)
+        module = SimpleModule(
+            self.module,
+            input=self.mapNameCalc,
+            output=self.mapComplete,
+            segmax=1200,
+            npmin=100,
+            tension=150,
+        )
         self.assertModule(module)
-        self.assertRasterFitsUnivar(raster=self.mapComplete,
-                                    reference=self.values)
+        self.assertRasterFitsUnivar(raster=self.mapComplete, reference=self.values)
 
     def test_bspline(self):
-        module = SimpleModule(self.module, input=self.mapNameCalc,
-                              output=self.mapComplete, method='bicubic')
+        module = SimpleModule(
+            self.module,
+            input=self.mapNameCalc,
+            output=self.mapComplete,
+            method="bicubic",
+        )
         self.assertModule(module)
-        self.assertRasterFitsUnivar(raster=self.mapComplete,
-                                    reference=self.values)
+        self.assertRasterFitsUnivar(raster=self.mapComplete, reference=self.values)
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     test()

+ 43 - 24
scripts/r.grow/r.grow.py

@@ -72,19 +72,18 @@ from grass.exceptions import CalledModuleError
 def cleanup():
     for map in [temp_dist, temp_val]:
         if map:
-            grass.run_command('g.remove', flags='fb', quiet=True,
-                              type='rast', name=map)
+            grass.run_command("g.remove", flags="fb", quiet=True, type="rast", name=map)
 
 
 def main():
     global temp_dist, temp_val
 
-    input = options['input']
-    radius = float(options['radius'])
-    metric = options['metric']
-    old = options['old']
-    new = options['new']
-    mapunits = flags['m']
+    input = options["input"]
+    radius = float(options["radius"])
+    metric = options["metric"]
+    old = options["old"]
+    new = options["new"]
+    mapunits = flags["m"]
 
     tmp = str(os.getpid())
 
@@ -95,33 +94,33 @@ def main():
         shrink = True
         radius = -radius
 
-    if new == '' and not shrink:
+    if new == "" and not shrink:
         temp_val = "r.grow.tmp.%s.val" % tmp
         new = '"%s"' % temp_val
     else:
         temp_val = None
 
-    if old == '':
+    if old == "":
         old = '"%s"' % input
 
     if not mapunits:
         kv = grass.region()
-        scale = math.sqrt(float(kv['nsres']) * float(kv['ewres']))
+        scale = math.sqrt(float(kv["nsres"]) * float(kv["ewres"]))
         radius *= scale
 
-    if metric == 'euclidean':
-        metric = 'squared'
+    if metric == "euclidean":
+        metric = "squared"
         radius = radius * radius
 
     # check if input file exists
-    if not grass.find_file(input)['file']:
+    if not grass.find_file(input)["file"]:
         grass.fatal(_("Raster map <%s> not found") % input)
 
     # Workaround for r.mapcalc bug #3475
     # Mapcalc will fail if output is a fully qualified map name
-    out_name = options['output'].split('@')
+    out_name = options["output"].split("@")
     if len(out_name) == 2:
-        if out_name[1] != grass.gisenv()['MAPSET']:
+        if out_name[1] != grass.gisenv()["MAPSET"]:
             grass.fatal(_("Output can be written only to the current mapset"))
         output = out_name[0]
     else:
@@ -129,28 +128,48 @@ def main():
 
     if not shrink:
         try:
-            grass.run_command('r.grow.distance', input=input, metric=metric,
-                              distance=temp_dist, value=temp_val)
+            grass.run_command(
+                "r.grow.distance",
+                input=input,
+                metric=metric,
+                distance=temp_dist,
+                value=temp_val,
+            )
         except CalledModuleError:
             grass.fatal(_("Growing failed. Removing temporary maps."))
 
         grass.mapcalc(
             '$output = if(!isnull("$input"),$old,if($dist < $radius,$new,null()))',
-            output=output, input=input, radius=radius,
-            old=old, new=new, dist=temp_dist)
+            output=output,
+            input=input,
+            radius=radius,
+            old=old,
+            new=new,
+            dist=temp_dist,
+        )
     else:
         # shrink
         try:
-            grass.run_command('r.grow.distance', input=input, metric=metric,
-                              distance=temp_dist, value=temp_val, flags='n')
+            grass.run_command(
+                "r.grow.distance",
+                input=input,
+                metric=metric,
+                distance=temp_dist,
+                value=temp_val,
+                flags="n",
+            )
         except CalledModuleError:
             grass.fatal(_("Shrinking failed. Removing temporary maps."))
 
         grass.mapcalc(
             "$output = if(isnull($dist), $old, if($dist < $radius,null(),$old))",
-            output=output, radius=radius, old=old, dist=temp_dist)
+            output=output,
+            radius=radius,
+            old=old,
+            dist=temp_dist,
+        )
 
-    grass.run_command('r.colors', map=output, raster=input)
+    grass.run_command("r.colors", map=output, raster=input)
 
     # write cmd history:
     grass.raster_history(output)

+ 25 - 22
scripts/r.grow/testsuite/test_r_grow.py

@@ -13,53 +13,56 @@ from grass.script.core import run_command
 class TestRGrow(TestCase):
     """Test r.grow script"""
 
-    mapName = 'lakes'
-    mapGrownOutput = 'lakes_grown_100m'
-    mapShrunkOutput = 'lakes_shrunk_100m'
-    mapNoNULL = 'elevation'
-    mapShrunkNoNULL = 'elevation_shrunk'
+    mapName = "lakes"
+    mapGrownOutput = "lakes_grown_100m"
+    mapShrunkOutput = "lakes_shrunk_100m"
+    mapNoNULL = "elevation"
+    mapShrunkNoNULL = "elevation_shrunk"
 
     @classmethod
     def setUpClass(cls):
         """Create maps in a small region."""
         cls.use_temp_region()
-        cls.runModule('g.region', raster=cls.mapName, flags='p')
+        cls.runModule("g.region", raster=cls.mapName, flags="p")
 
     @classmethod
     def tearDownClass(cls):
         """Remove temporary region"""
-        cls.runModule('g.remove', flags='f', type='raster',
-                      name=(cls.mapGrownOutput,
-                            cls.mapShrunkOutput,
-                            cls.mapShrunkNoNULL))
+        cls.runModule(
+            "g.remove",
+            flags="f",
+            type="raster",
+            name=(cls.mapGrownOutput, cls.mapShrunkOutput, cls.mapShrunkNoNULL),
+        )
         cls.del_temp_region()
 
     def test_grow(self):
         """Grow test"""
-        module = SimpleModule('r.grow', input=self.mapName,
-                              output=self.mapGrownOutput,
-                              radius=10)
+        module = SimpleModule(
+            "r.grow", input=self.mapName, output=self.mapGrownOutput, radius=10
+        )
         self.assertModule(module)
 
     def test_shrink(self):
         """Shrink test"""
-        module = SimpleModule('r.grow', input=self.mapName,
-                              output=self.mapShrunkOutput,
-                              radius=-10)
+        module = SimpleModule(
+            "r.grow", input=self.mapName, output=self.mapShrunkOutput, radius=-10
+        )
         self.assertModule(module)
 
     def test_shrink_null(self):
         """Shrinking of map without NULL values
         Based on https://github.com/OSGeo/grass/pull/343"""
-        shrinked_string = '56-156'
-        shrinked = SimpleModule('r.grow', input=self.mapNoNULL,
-                              output=self.mapShrunkNoNULL,
-                              radius=-10)
+        shrinked_string = "56-156"
+        shrinked = SimpleModule(
+            "r.grow", input=self.mapNoNULL, output=self.mapShrunkNoNULL, radius=-10
+        )
         self.assertModule(shrinked)
 
-        shrined_range = SimpleModule('r.describe', flags='i', _map=self.mapShrunkNoNULL)
+        shrined_range = SimpleModule("r.describe", flags="i", _map=self.mapShrunkNoNULL)
         self.runModule(shrined_range)
         self.assertLooksLike(shrinked_string, str(shrined_range.outputs.stdout).strip())
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 12 - 12
scripts/r.grow/testsuite/test_r_grow_quoting.py

@@ -15,12 +15,12 @@ from grass.gunittest.utils import silent_rmtree
 class TestRGrow(TestCase):
     """Test r.grow script"""
 
-    map1 = 'elevation'
-    temp1 = 'grown'
+    map1 = "elevation"
+    temp1 = "grown"
     mapsets_to_remove = []
     # mapset with a name is also a valid mathematical expression
     mapset_name = "1234-56-78"
-    gisenv = SimpleModule('g.gisenv', get='MAPSET')
+    gisenv = SimpleModule("g.gisenv", get="MAPSET")
     TestCase.runModule(gisenv, expecting_stdout=True)
     old_mapset = gisenv.outputs.stdout.strip()
 
@@ -30,20 +30,19 @@ class TestRGrow(TestCase):
         # create a mapset with a name is also a valid mathematical expression
         cls.runModule("g.mapset", flags="c", mapset=cls.mapset_name)
         cls.mapsets_to_remove.append(cls.mapset_name)
-        run_command('g.copy', raster=cls.map1 + '@PERMANENT,' + cls.map1)
-        cls.runModule('g.region', raster=cls.map1, flags='p')
+        run_command("g.copy", raster=cls.map1 + "@PERMANENT," + cls.map1)
+        cls.runModule("g.region", raster=cls.map1, flags="p")
 
     @classmethod
     def tearDownClass(cls):
         """Remove temporary data"""
-        gisenv = SimpleModule('g.gisenv', get='GISDBASE')
+        gisenv = SimpleModule("g.gisenv", get="GISDBASE")
         cls.runModule(gisenv, expecting_stdout=True)
         gisdbase = gisenv.outputs.stdout.strip()
-        gisenv = SimpleModule('g.gisenv', get='LOCATION_NAME')
+        gisenv = SimpleModule("g.gisenv", get="LOCATION_NAME")
         cls.runModule(gisenv, expecting_stdout=True)
         location = gisenv.outputs.stdout.strip()
-        cls.runModule('g.remove', flags='f', type='raster',
-                      name=(cls.temp1, ))
+        cls.runModule("g.remove", flags="f", type="raster", name=(cls.temp1,))
         cls.runModule("g.mapset", mapset=cls.old_mapset)
         for mapset_name in cls.mapsets_to_remove:
             mapset_path = os.path.join(gisdbase, location, mapset_name)
@@ -53,10 +52,11 @@ class TestRGrow(TestCase):
         """grows test with special mapset name"""
 
         # should not lead to syntax error, unexpected INTEGER, expecting VARNAME or NAME
-        module = SimpleModule('r.grow', input=self.map1 + '@' + self.mapset_name,
-                              output=self.temp1)
+        module = SimpleModule(
+            "r.grow", input=self.map1 + "@" + self.mapset_name, output=self.temp1
+        )
         self.assertModule(module)
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     test()

+ 196 - 127
scripts/r.import/r.import.py

@@ -135,18 +135,22 @@ def cleanup():
         grass.try_rmdir(os.path.join(GISDBASE, TMPLOC))
     if SRCGISRC:
         grass.try_remove(SRCGISRC)
-    if TMP_REG_NAME and grass.find_file(name=TMP_REG_NAME, element='vector',
-                                        mapset=grass.gisenv()['MAPSET'])['fullname']:
-        grass.run_command('g.remove', type='vector', name=TMP_REG_NAME,
-                          flags='f', quiet=True)
+    if (
+        TMP_REG_NAME
+        and grass.find_file(
+            name=TMP_REG_NAME, element="vector", mapset=grass.gisenv()["MAPSET"]
+        )["fullname"]
+    ):
+        grass.run_command(
+            "g.remove", type="vector", name=TMP_REG_NAME, flags="f", quiet=True
+        )
 
 
 def is_projection_matching(GDALdatasource):
     """Returns True if current location projection
     matches dataset projection, otherwise False"""
     try:
-        grass.run_command('r.in.gdal', input=GDALdatasource, flags='j',
-                          quiet=True)
+        grass.run_command("r.in.gdal", input=GDALdatasource, flags="j", quiet=True)
         return True
     except CalledModuleError:
         return False
@@ -155,255 +159,320 @@ def is_projection_matching(GDALdatasource):
 def main():
     global TMPLOC, SRCGISRC, GISDBASE, TMP_REG_NAME
 
-    GDALdatasource = options['input']
-    output = options['output']
-    method = options['resample']
-    memory = options['memory']
-    bands = options['band']
-    tgtres = options['resolution']
+    GDALdatasource = options["input"]
+    output = options["output"]
+    method = options["resample"]
+    memory = options["memory"]
+    bands = options["band"]
+    tgtres = options["resolution"]
     title = options["title"]
-    if flags['e'] and not output:
-        output = 'rimport_tmp'  # will be removed with the entire tmp location
-    if options['resolution_value']:
-        if tgtres != 'value':
-            grass.fatal(_("To set custom resolution value, select 'value' in resolution option"))
-        tgtres_value = float(options['resolution_value'])
+    if flags["e"] and not output:
+        output = "rimport_tmp"  # will be removed with the entire tmp location
+    if options["resolution_value"]:
+        if tgtres != "value":
+            grass.fatal(
+                _("To set custom resolution value, select 'value' in resolution option")
+            )
+        tgtres_value = float(options["resolution_value"])
         if tgtres_value <= 0:
             grass.fatal(_("Resolution value can't be smaller than 0"))
-    elif tgtres == 'value':
+    elif tgtres == "value":
         grass.fatal(
-            _("Please provide the resolution for the imported dataset or change to 'estimated' resolution"))
+            _(
+                "Please provide the resolution for the imported dataset or change to 'estimated' resolution"
+            )
+        )
 
     # try r.in.gdal directly first
-    additional_flags = 'l' if flags['l'] else ''
-    if flags['o']:
-        additional_flags += 'o'
-    region_flag = ''
-    if options['extent'] == 'region':
-        region_flag += 'r'
-    if flags['o'] or is_projection_matching(GDALdatasource):
-        parameters = dict(input=GDALdatasource, output=output,
-                          memory=memory, flags='ak' + additional_flags + region_flag)
+    additional_flags = "l" if flags["l"] else ""
+    if flags["o"]:
+        additional_flags += "o"
+    region_flag = ""
+    if options["extent"] == "region":
+        region_flag += "r"
+    if flags["o"] or is_projection_matching(GDALdatasource):
+        parameters = dict(
+            input=GDALdatasource,
+            output=output,
+            memory=memory,
+            flags="ak" + additional_flags + region_flag,
+        )
         if bands:
-            parameters['band'] = bands
+            parameters["band"] = bands
         try:
-            grass.run_command('r.in.gdal', **parameters)
+            grass.run_command("r.in.gdal", **parameters)
             grass.verbose(
-                _("Input <%s> successfully imported without reprojection") %
-                GDALdatasource)
+                _("Input <%s> successfully imported without reprojection")
+                % GDALdatasource
+            )
             return 0
         except CalledModuleError as e:
             grass.fatal(_("Unable to import GDAL dataset <%s>") % GDALdatasource)
 
     grassenv = grass.gisenv()
-    tgtloc = grassenv['LOCATION_NAME']
+    tgtloc = grassenv["LOCATION_NAME"]
 
     # make sure target is not xy
-    if grass.parse_command('g.proj', flags='g')['name'] == 'xy_location_unprojected':
+    if grass.parse_command("g.proj", flags="g")["name"] == "xy_location_unprojected":
         grass.fatal(
-            _("Coordinate reference system not available for current location <%s>") %
-            tgtloc)
+            _("Coordinate reference system not available for current location <%s>")
+            % tgtloc
+        )
 
-    tgtmapset = grassenv['MAPSET']
-    GISDBASE = grassenv['GISDBASE']
+    tgtmapset = grassenv["MAPSET"]
+    GISDBASE = grassenv["GISDBASE"]
 
     TMPLOC = grass.append_node_pid("tmp_r_import_location")
     TMP_REG_NAME = grass.append_node_pid("tmp_r_import_region")
 
-    SRCGISRC, src_env = grass.create_environment(GISDBASE, TMPLOC, 'PERMANENT')
+    SRCGISRC, src_env = grass.create_environment(GISDBASE, TMPLOC, "PERMANENT")
 
     # create temp location from input without import
     grass.verbose(_("Creating temporary location for <%s>...") % GDALdatasource)
     # creating a new location with r.in.gdal requires a sanitized env
     env = os.environ.copy()
     env = grass.sanitize_mapset_environment(env)
-    parameters = dict(input=GDALdatasource, output=output,
-                      memory=memory, flags='c', title=title,
-                      location=TMPLOC, quiet=True)
+    parameters = dict(
+        input=GDALdatasource,
+        output=output,
+        memory=memory,
+        flags="c",
+        title=title,
+        location=TMPLOC,
+        quiet=True,
+    )
     if bands:
-        parameters['band'] = bands
+        parameters["band"] = bands
     try:
-        grass.run_command('r.in.gdal', env=env, **parameters)
+        grass.run_command("r.in.gdal", env=env, **parameters)
     except CalledModuleError:
         grass.fatal(_("Unable to read GDAL dataset <%s>") % GDALdatasource)
 
     # prepare to set region in temp location
-    if 'r' in region_flag:
+    if "r" in region_flag:
         tgtregion = TMP_REG_NAME
-        grass.run_command('v.in.region', output=tgtregion, flags='d')
+        grass.run_command("v.in.region", output=tgtregion, flags="d")
 
     # switch to temp location
 
     # print projection at verbose level
-    grass.verbose(grass.read_command('g.proj', flags='p', env=src_env).rstrip(os.linesep))
+    grass.verbose(
+        grass.read_command("g.proj", flags="p", env=src_env).rstrip(os.linesep)
+    )
 
     # make sure input is not xy
-    if grass.parse_command('g.proj', flags='g', env=src_env)['name'] == 'xy_location_unprojected':
-        grass.fatal(_("Coordinate reference system not available for input <%s>") % GDALdatasource)
+    if (
+        grass.parse_command("g.proj", flags="g", env=src_env)["name"]
+        == "xy_location_unprojected"
+    ):
+        grass.fatal(
+            _("Coordinate reference system not available for input <%s>")
+            % GDALdatasource
+        )
 
     # import into temp location
     grass.verbose(_("Importing <%s> to temporary location...") % GDALdatasource)
-    parameters = dict(input=GDALdatasource, output=output,
-                      memory=memory, flags='ak' + additional_flags)
+    parameters = dict(
+        input=GDALdatasource,
+        output=output,
+        memory=memory,
+        flags="ak" + additional_flags,
+    )
     if bands:
-        parameters['band'] = bands
-    if 'r' in region_flag:
-        grass.run_command('v.proj', location=tgtloc, mapset=tgtmapset,
-                          input=tgtregion, output=tgtregion, env=src_env)
-        grass.run_command('g.region', vector=tgtregion, env=src_env)
-        parameters['flags'] = parameters['flags'] + region_flag
+        parameters["band"] = bands
+    if "r" in region_flag:
+        grass.run_command(
+            "v.proj",
+            location=tgtloc,
+            mapset=tgtmapset,
+            input=tgtregion,
+            output=tgtregion,
+            env=src_env,
+        )
+        grass.run_command("g.region", vector=tgtregion, env=src_env)
+        parameters["flags"] = parameters["flags"] + region_flag
     try:
-        grass.run_command('r.in.gdal', env=src_env, **parameters)
+        grass.run_command("r.in.gdal", env=src_env, **parameters)
     except CalledModuleError:
         grass.fatal(_("Unable to import GDAL dataset <%s>") % GDALdatasource)
 
-    outfiles = grass.list_grouped('raster', env=src_env)['PERMANENT']
+    outfiles = grass.list_grouped("raster", env=src_env)["PERMANENT"]
 
     # is output a group?
     group = False
-    path = os.path.join(GISDBASE, TMPLOC, 'group', output)
+    path = os.path.join(GISDBASE, TMPLOC, "group", output)
     if os.path.exists(path):
         group = True
-        path = os.path.join(GISDBASE, TMPLOC, 'group', output, 'POINTS')
+        path = os.path.join(GISDBASE, TMPLOC, "group", output, "POINTS")
         if os.path.exists(path):
             grass.fatal(_("Input contains GCPs, rectification is required"))
 
-    if 'r' in region_flag:
-        grass.run_command('g.remove', type="vector", flags="f",
-                          name=tgtregion, env=src_env)
+    if "r" in region_flag:
+        grass.run_command(
+            "g.remove", type="vector", flags="f", name=tgtregion, env=src_env
+        )
 
     # switch to target location
-    if 'r' in region_flag:
-        grass.run_command('g.remove', type="vector", flags="f",
-                          name=tgtregion)
+    if "r" in region_flag:
+        grass.run_command("g.remove", type="vector", flags="f", name=tgtregion)
 
     region = grass.region()
 
     rflags = None
-    if flags['n']:
-        rflags = 'n'
+    if flags["n"]:
+        rflags = "n"
 
     vreg = TMP_REG_NAME
 
     for outfile in outfiles:
 
-        n = region['n']
-        s = region['s']
-        e = region['e']
-        w = region['w']
+        n = region["n"]
+        s = region["s"]
+        e = region["e"]
+        w = region["w"]
 
         env = os.environ.copy()
-        if options['extent'] == 'input':
+        if options["extent"] == "input":
             # r.proj -g
             try:
-                tgtextents = grass.read_command('r.proj', location=TMPLOC,
-                                                mapset='PERMANENT',
-                                                input=outfile, flags='g',
-                                                memory=memory, quiet=True)
+                tgtextents = grass.read_command(
+                    "r.proj",
+                    location=TMPLOC,
+                    mapset="PERMANENT",
+                    input=outfile,
+                    flags="g",
+                    memory=memory,
+                    quiet=True,
+                )
             except CalledModuleError:
                 grass.fatal(_("Unable to get reprojected map extent"))
             try:
-                srcregion = grass.parse_key_val(tgtextents, val_type=float, vsep=' ')
-                n = srcregion['n']
-                s = srcregion['s']
-                e = srcregion['e']
-                w = srcregion['w']
+                srcregion = grass.parse_key_val(tgtextents, val_type=float, vsep=" ")
+                n = srcregion["n"]
+                s = srcregion["s"]
+                e = srcregion["e"]
+                w = srcregion["w"]
             except ValueError:  # import into latlong, expect 53:39:06.894826N
-                srcregion = grass.parse_key_val(tgtextents, vsep=' ')
-                n = grass.float_or_dms(srcregion['n'][:-1]) * \
-                    (-1 if srcregion['n'][-1] == 'S' else 1)
-                s = grass.float_or_dms(srcregion['s'][:-1]) * \
-                    (-1 if srcregion['s'][-1] == 'S' else 1)
-                e = grass.float_or_dms(srcregion['e'][:-1]) * \
-                    (-1 if srcregion['e'][-1] == 'W' else 1)
-                w = grass.float_or_dms(srcregion['w'][:-1]) * \
-                    (-1 if srcregion['w'][-1] == 'W' else 1)
-
-            env['GRASS_REGION'] = grass.region_env(n=n, s=s, e=e, w=w)
+                srcregion = grass.parse_key_val(tgtextents, vsep=" ")
+                n = grass.float_or_dms(srcregion["n"][:-1]) * (
+                    -1 if srcregion["n"][-1] == "S" else 1
+                )
+                s = grass.float_or_dms(srcregion["s"][:-1]) * (
+                    -1 if srcregion["s"][-1] == "S" else 1
+                )
+                e = grass.float_or_dms(srcregion["e"][:-1]) * (
+                    -1 if srcregion["e"][-1] == "W" else 1
+                )
+                w = grass.float_or_dms(srcregion["w"][:-1]) * (
+                    -1 if srcregion["w"][-1] == "W" else 1
+                )
+
+            env["GRASS_REGION"] = grass.region_env(n=n, s=s, e=e, w=w)
 
         # v.in.region in tgt
-        grass.run_command('v.in.region', output=vreg, quiet=True, env=env)
+        grass.run_command("v.in.region", output=vreg, quiet=True, env=env)
 
         # reproject to src
         # switch to temp location
         try:
-            grass.run_command('v.proj', input=vreg, output=vreg,
-                              location=tgtloc, mapset=tgtmapset,
-                              quiet=True, env=src_env)
+            grass.run_command(
+                "v.proj",
+                input=vreg,
+                output=vreg,
+                location=tgtloc,
+                mapset=tgtmapset,
+                quiet=True,
+                env=src_env,
+            )
             # test if v.proj created a valid area
-            if grass.vector_info_topo(vreg, env=src_env)['areas'] != 1:
+            if grass.vector_info_topo(vreg, env=src_env)["areas"] != 1:
                 grass.fatal(_("Please check the 'extent' parameter"))
         except CalledModuleError:
             grass.fatal(_("Unable to reproject to source location"))
 
         # set region from region vector
-        grass.run_command('g.region', raster=outfile, env=src_env)
-        grass.run_command('g.region', vector=vreg, env=src_env)
+        grass.run_command("g.region", raster=outfile, env=src_env)
+        grass.run_command("g.region", vector=vreg, env=src_env)
         # align to first band
-        grass.run_command('g.region', align=outfile, env=src_env)
+        grass.run_command("g.region", align=outfile, env=src_env)
         # get number of cells
-        cells = grass.region(env=src_env)['cells']
+        cells = grass.region(env=src_env)["cells"]
 
         estres = math.sqrt((n - s) * (e - w) / cells)
         # remove from source location for multi bands import
-        grass.run_command('g.remove', type='vector', name=vreg,
-                          flags='f', quiet=True, env=src_env)
+        grass.run_command(
+            "g.remove", type="vector", name=vreg, flags="f", quiet=True, env=src_env
+        )
 
         # switch to target location
-        grass.run_command('g.remove', type='vector', name=vreg,
-                          flags='f', quiet=True)
+        grass.run_command("g.remove", type="vector", name=vreg, flags="f", quiet=True)
 
         grass.message(
             _("Estimated target resolution for input band <{out}>: {res}").format(
-                out=outfile, res=estres))
-        if flags['e']:
+                out=outfile, res=estres
+            )
+        )
+        if flags["e"]:
             continue
 
         env = os.environ.copy()
 
-        if options['extent'] == 'input':
-            env['GRASS_REGION'] = grass.region_env(n=n, s=s, e=e, w=w)
+        if options["extent"] == "input":
+            env["GRASS_REGION"] = grass.region_env(n=n, s=s, e=e, w=w)
 
         res = None
-        if tgtres == 'estimated':
+        if tgtres == "estimated":
             res = estres
-        elif tgtres == 'value':
+        elif tgtres == "value":
             res = tgtres_value
             grass.message(
                 _("Using given resolution for input band <{out}>: {res}").format(
-                    out=outfile, res=res))
+                    out=outfile, res=res
+                )
+            )
             # align to requested resolution
-            env['GRASS_REGION'] = grass.region_env(res=res, flags='a', env=env)
+            env["GRASS_REGION"] = grass.region_env(res=res, flags="a", env=env)
         else:
             curr_reg = grass.region()
-            grass.message(_("Using current region resolution for input band "
-                            "<{out}>: nsres={ns}, ewres={ew}").format(out=outfile, ns=curr_reg['nsres'],
-                                                                      ew=curr_reg['ewres']))
+            grass.message(
+                _(
+                    "Using current region resolution for input band "
+                    "<{out}>: nsres={ns}, ewres={ew}"
+                ).format(out=outfile, ns=curr_reg["nsres"], ew=curr_reg["ewres"])
+            )
 
         # r.proj
         grass.message(_("Reprojecting <%s>...") % outfile)
         try:
-            grass.run_command('r.proj', location=TMPLOC,
-                              mapset='PERMANENT', input=outfile,
-                              method=method, resolution=res,
-                              memory=memory, flags=rflags, quiet=True,
-                              env=env)
+            grass.run_command(
+                "r.proj",
+                location=TMPLOC,
+                mapset="PERMANENT",
+                input=outfile,
+                method=method,
+                resolution=res,
+                memory=memory,
+                flags=rflags,
+                quiet=True,
+                env=env,
+            )
         except CalledModuleError:
             grass.fatal(_("Unable to to reproject raster <%s>") % outfile)
 
-        if grass.raster_info(outfile)['min'] is None:
+        if grass.raster_info(outfile)["min"] is None:
             grass.fatal(_("The reprojected raster <%s> is empty") % outfile)
 
-    if flags['e']:
+    if flags["e"]:
         return 0
 
     if group:
-        grass.run_command('i.group', group=output, input=','.join(outfiles))
+        grass.run_command("i.group", group=output, input=",".join(outfiles))
 
     # TODO: write metadata with r.support
 
     return 0
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     atexit.register(cleanup)

+ 91 - 34
scripts/r.import/testsuite/test_r_import.py

@@ -8,69 +8,126 @@ import grass.script as gs
 
 class TestRImportRegion(TestCase):
 
-    imported = 'test_r_import_imported'
+    imported = "test_r_import_imported"
 
     @classmethod
     def setUpClass(cls):
-        cls.runModule('g.region', raster='elevation')
+        cls.runModule("g.region", raster="elevation")
 
     def tearDown(cls):
         """Remove imported map after each test method"""
-        cls.runModule('g.remove', flags='f', type='raster',
-                      name=cls.imported)
+        cls.runModule("g.remove", flags="f", type="raster", name=cls.imported)
 
     def test_import_estimate(self):
         """Test e flag"""
-        self.assertModule('r.import', input='data/data2.asc', output=self.imported,
-                          resample='nearest', flags='e')
+        self.assertModule(
+            "r.import",
+            input="data/data2.asc",
+            output=self.imported,
+            resample="nearest",
+            flags="e",
+        )
         self.assertRasterDoesNotExist(name=self.imported)
 
     def test_import_same_proj_tif(self):
         """Import tif in same proj, default params"""
-        self.assertModule('r.import', input='data/data1.tif', output=self.imported,
-                          resample='bilinear')
-        reference = dict(north=223490, south=223390, east=636820, west=636710,
-                         nsres=10, ewres=10, datatype='FCELL')
-        self.assertRasterFitsInfo(raster=self.imported, reference=reference, precision=1e-6)
+        self.assertModule(
+            "r.import",
+            input="data/data1.tif",
+            output=self.imported,
+            resample="bilinear",
+        )
+        reference = dict(
+            north=223490,
+            south=223390,
+            east=636820,
+            west=636710,
+            nsres=10,
+            ewres=10,
+            datatype="FCELL",
+        )
+        self.assertRasterFitsInfo(
+            raster=self.imported, reference=reference, precision=1e-6
+        )
 
     def test_import_asc_custom_res(self):
         """Import ASC in different projection, with specified resolution"""
-        self.assertModule('r.import', input='data/data2.asc', output=self.imported,
-                          resample='nearest', resolution='value', resolution_value=30)
-        reference = dict(rows=3, cols=4,
-                         nsres=30, ewres=30, datatype='CELL')
-        self.assertRasterFitsInfo(raster=self.imported, reference=reference, precision=1.1)
+        self.assertModule(
+            "r.import",
+            input="data/data2.asc",
+            output=self.imported,
+            resample="nearest",
+            resolution="value",
+            resolution_value=30,
+        )
+        reference = dict(rows=3, cols=4, nsres=30, ewres=30, datatype="CELL")
+        self.assertRasterFitsInfo(
+            raster=self.imported, reference=reference, precision=1.1
+        )
 
     def test_import_asc_region_extent(self):
         """Import ASC in different projection in specified region"""
-        self.runModule('g.region', raster='elevation', n=223655, s=223600)
-        self.assertModule('r.import', input='data/data2.asc', output=self.imported,
-                          resample='nearest', extent='region', resolution='region')
+        self.runModule("g.region", raster="elevation", n=223655, s=223600)
+        self.assertModule(
+            "r.import",
+            input="data/data2.asc",
+            output=self.imported,
+            resample="nearest",
+            extent="region",
+            resolution="region",
+        )
         reference = dict(north=223655, south=223600)
-        self.assertRasterFitsInfo(raster=self.imported, reference=reference, precision=1e-6)
+        self.assertRasterFitsInfo(
+            raster=self.imported, reference=reference, precision=1e-6
+        )
 
     def test_import_use_temp_region(self):
         """Import in specified region with use_temp_region activated"""
-        self.runModule('g.region', raster='elevation', n=223660, s=223600)
+        self.runModule("g.region", raster="elevation", n=223660, s=223600)
         gs.use_temp_region()
-        self.runModule('g.region', raster='elevation', n=223630, s=223600)
-        self.assertModule('r.import', input='data/data2.asc', output=self.imported,
-                          resample='nearest', extent='region', resolution='region')
+        self.runModule("g.region", raster="elevation", n=223630, s=223600)
+        self.assertModule(
+            "r.import",
+            input="data/data2.asc",
+            output=self.imported,
+            resample="nearest",
+            extent="region",
+            resolution="region",
+        )
         reference = dict(north=223630, south=223600, nsres=10, ewres=10)
-        self.assertRasterFitsInfo(raster=self.imported, reference=reference, precision=1e-6)
-
-        self.runModule('g.region', raster='elevation', s=223390, n=223450)
-        self.assertModule('r.import', input='data/data1.tif', output=self.imported,
-                          resample='bilinear', extent='region', overwrite=True)
+        self.assertRasterFitsInfo(
+            raster=self.imported, reference=reference, precision=1e-6
+        )
+
+        self.runModule("g.region", raster="elevation", s=223390, n=223450)
+        self.assertModule(
+            "r.import",
+            input="data/data1.tif",
+            output=self.imported,
+            resample="bilinear",
+            extent="region",
+            overwrite=True,
+        )
         reference = dict(south=223390, north=223450, nsres=10, ewres=10)
-        self.assertRasterFitsInfo(raster=self.imported, reference=reference, precision=1e-6)
+        self.assertRasterFitsInfo(
+            raster=self.imported, reference=reference, precision=1e-6
+        )
 
         gs.del_temp_region()
-        self.assertModule('r.import', input='data/data2.asc', output=self.imported,
-                          resample='nearest', extent='region', resolution='region', overwrite=True)
+        self.assertModule(
+            "r.import",
+            input="data/data2.asc",
+            output=self.imported,
+            resample="nearest",
+            extent="region",
+            resolution="region",
+            overwrite=True,
+        )
         reference = dict(north=223660, south=223600, nsres=10, ewres=10)
-        self.assertRasterFitsInfo(raster=self.imported, reference=reference, precision=1e-6)
+        self.assertRasterFitsInfo(
+            raster=self.imported, reference=reference, precision=1e-6
+        )
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     test()

+ 64 - 45
scripts/r.in.aster/r.in.aster.py

@@ -56,69 +56,87 @@ import platform
 import grass.script as grass
 
 bands = {
-    'L1A': {
-        '1': "VNIR_Band1:ImageData",
-        '2': "VNIR_Band2:ImageData",
-        '3n': "VNIR_Band3N:ImageData",
-        '3b': "VNIR_Band3B:ImageData",
-        '4': "SWIR_Band4:ImageData",
-        '5': "SWIR_Band5:ImageData",
-        '6': "SWIR_Band6:ImageData",
-        '7': "SWIR_Band7:ImageData",
-        '8': "SWIR_Band8:ImageData",
-        '9': "SWIR_Band9:ImageData",
-        '10': "TIR_Band10:ImageData",
-        '11': "TIR_Band11:ImageData",
-        '12': "TIR_Band12:ImageData",
-        '13': "TIR_Band13:ImageData",
-        '14': "TIR_Band14:ImageData"
+    "L1A": {
+        "1": "VNIR_Band1:ImageData",
+        "2": "VNIR_Band2:ImageData",
+        "3n": "VNIR_Band3N:ImageData",
+        "3b": "VNIR_Band3B:ImageData",
+        "4": "SWIR_Band4:ImageData",
+        "5": "SWIR_Band5:ImageData",
+        "6": "SWIR_Band6:ImageData",
+        "7": "SWIR_Band7:ImageData",
+        "8": "SWIR_Band8:ImageData",
+        "9": "SWIR_Band9:ImageData",
+        "10": "TIR_Band10:ImageData",
+        "11": "TIR_Band11:ImageData",
+        "12": "TIR_Band12:ImageData",
+        "13": "TIR_Band13:ImageData",
+        "14": "TIR_Band14:ImageData",
+    },
+    "L1B": {
+        "1": "VNIR_Swath:ImageData1",
+        "2": "VNIR_Swath:ImageData2",
+        "3n": "VNIR_Swath:ImageData3N",
+        "3b": "VNIR_Swath:ImageData3B",
+        "4": "SWIR_Swath:ImageData4",
+        "5": "SWIR_Swath:ImageData5",
+        "6": "SWIR_Swath:ImageData6",
+        "7": "SWIR_Swath:ImageData7",
+        "8": "SWIR_Swath:ImageData8",
+        "9": "SWIR_Swath:ImageData9",
+        "10": "TIR_Swath:ImageData10",
+        "11": "TIR_Swath:ImageData11",
+        "12": "TIR_Swath:ImageData12",
+        "13": "TIR_Swath:ImageData13",
+        "14": "TIR_Swath:ImageData14",
     },
-    'L1B': {
-        '1': "VNIR_Swath:ImageData1",
-        '2': "VNIR_Swath:ImageData2",
-        '3n': "VNIR_Swath:ImageData3N",
-        '3b': "VNIR_Swath:ImageData3B",
-        '4': "SWIR_Swath:ImageData4",
-        '5': "SWIR_Swath:ImageData5",
-        '6': "SWIR_Swath:ImageData6",
-        '7': "SWIR_Swath:ImageData7",
-        '8': "SWIR_Swath:ImageData8",
-        '9': "SWIR_Swath:ImageData9",
-        '10': "TIR_Swath:ImageData10",
-        '11': "TIR_Swath:ImageData11",
-        '12': "TIR_Swath:ImageData12",
-        '13': "TIR_Swath:ImageData13",
-        '14': "TIR_Swath:ImageData14"
-    }
 }
 
 
 def main():
-    input = options['input']
-    proctype = options['proctype']
-    output = options['output']
-    band = options['band']
+    input = options["input"]
+    proctype = options["proctype"]
+    output = options["output"]
+    band = options["band"]
 
     # check whether gdalwarp is in path and executable
-    if not grass.find_program('gdalwarp', '--help'):
+    if not grass.find_program("gdalwarp", "--help"):
         grass.fatal(_("gdalwarp is not in the path and executable"))
 
     # create temporary file to hold gdalwarp output before importing to GRASS
-    tempfile = grass.read_command("g.tempfile", pid=os.getpid()).strip() + '.tif'
+    tempfile = grass.read_command("g.tempfile", pid=os.getpid()).strip() + ".tif"
 
     # get projection information for current GRASS location
-    proj = grass.read_command('g.proj', flags='jf').strip()
+    proj = grass.read_command("g.proj", flags="jf").strip()
 
     # currently only runs in projected location
     if "XY location" in proj:
-        grass.fatal(_("This module needs to be run in a projected location (found: %s)") % proj)
+        grass.fatal(
+            _("This module needs to be run in a projected location (found: %s)") % proj
+        )
 
     # process list of bands
-    allbands = ['1', '2', '3n', '3b', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14']
-    if band == 'all':
+    allbands = [
+        "1",
+        "2",
+        "3n",
+        "3b",
+        "4",
+        "5",
+        "6",
+        "7",
+        "8",
+        "9",
+        "10",
+        "11",
+        "12",
+        "13",
+        "14",
+    ]
+    if band == "all":
         bandlist = allbands
     else:
-        bandlist = band.split(',')
+        bandlist = band.split(",")
 
     # initialize datasets for L1A and L1B
     if proctype in ["L1A", "L1B"]:
@@ -128,7 +146,7 @@ def main():
                 srcfile = "HDF4_EOS:EOS_SWATH:%s:%s" % (input, dataset)
                 import_aster(proj, srcfile, tempfile, output, band)
             else:
-                grass.fatal(_('band %s is not an available Terra/ASTER band') % band)
+                grass.fatal(_("band %s is not an available Terra/ASTER band") % band)
     elif proctype == "DEM":
         srcfile = input
         import_aster(proj, srcfile, tempfile, output, "DEM")
@@ -164,6 +182,7 @@ def import_aster(proj, srcfile, tempfile, output, band):
     # write cmd history
     grass.raster_history(outfile)
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     main()

+ 45 - 40
scripts/r.in.srtm/r.in.srtm.py

@@ -11,9 +11,9 @@
 #
 # COPYRIGHT:	(C) 2004, 2006 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.
+# 		This program is free software under the GNU General Public
+# 		License (>=v2). Read the file COPYING that comes with GRASS
+# 		for details.
 #
 # Dec 2004: merged with srtm_generate_hdr.sh (M. Neteler)
 #           corrections and refinement (W. Kyngesburye)
@@ -38,14 +38,14 @@
 #  the lower left pixel, which in the case of SRTM-1 data will be about
 #  30 meters in extent."
 #
-#- SRTM 90 Tiles are 1 degree by 1 degree
-#- SRTM filename coordinates are said to be the *center* of the LL pixel.
+# - SRTM 90 Tiles are 1 degree by 1 degree
+# - SRTM filename coordinates are said to be the *center* of the LL pixel.
 #       N51E10 -> lower left cell center
 #
-#- BIL uses *center* of the UL (!) pixel:
+# - BIL uses *center* of the UL (!) pixel:
 #      http://downloads.esri.com/support/whitepapers/other_/eximgav.pdf
 #
-#- GDAL uses *corners* of pixels for its coordinates.
+# - GDAL uses *corners* of pixels for its coordinates.
 #
 # NOTE: Even, if small difference: SRTM is referenced to EGM96, not WGS84 ellps
 # http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm96/intpt.html
@@ -121,13 +121,16 @@ XDIM 0.000833333333333
 YDIM 0.000833333333333
 """
 
-proj = ''.join([
-    'GEOGCS[',
-    '"wgs84",',
-    'DATUM["WGS_1984",SPHEROID["wgs84",6378137,298.257223563],TOWGS84[0.000000,0.000000,0.000000]],',
-    'PRIMEM["Greenwich",0],',
-    'UNIT["degree",0.0174532925199433]',
-    ']'])
+proj = "".join(
+    [
+        "GEOGCS[",
+        '"wgs84",',
+        'DATUM["WGS_1984",SPHEROID["wgs84",6378137,298.257223563],TOWGS84[0.000000,0.000000,0.000000]],',
+        'PRIMEM["Greenwich",0],',
+        'UNIT["degree",0.0174532925199433]',
+        "]",
+    ]
+)
 
 import os
 import shutil
@@ -139,9 +142,9 @@ import zipfile as zfile
 def cleanup():
     if not in_temp:
         return
-    for ext in ['.bil', '.hdr', '.prj', '.hgt.zip']:
+    for ext in [".bil", ".hdr", ".prj", ".hgt.zip"]:
         grass.try_remove(tile + ext)
-    os.chdir('..')
+    os.chdir("..")
     grass.try_rmdir(tmpdir)
 
 
@@ -153,19 +156,19 @@ def main():
     # to support SRTM water body
     swbd = False
 
-    input = options['input']
-    output = options['output']
-    one = flags['1']
+    input = options["input"]
+    output = options["output"]
+    one = flags["1"]
 
     # are we in LatLong location?
-    s = grass.read_command("g.proj", flags='j')
+    s = grass.read_command("g.proj", flags="j")
     kv = grass.parse_key_val(s)
-    if '+proj' not in kv.keys() or kv['+proj'] != 'longlat':
+    if "+proj" not in kv.keys() or kv["+proj"] != "longlat":
         grass.fatal(_("This module only operates in LatLong locations"))
 
     # use these from now on:
     infile = input
-    while infile[-4:].lower() in ['.hgt', '.zip', '.raw']:
+    while infile[-4:].lower() in [".hgt", ".zip", ".raw"]:
         infile = infile[:-4]
     (fdir, tile) = os.path.split(infile)
 
@@ -174,10 +177,10 @@ def main():
     else:
         tileout = output
 
-    if '.hgt' in input:
-        suff = '.hgt'
+    if ".hgt" in input:
+        suff = ".hgt"
     else:
-        suff = '.raw'
+        suff = ".raw"
         swbd = True
 
     zipfile = "{im}{su}.zip".format(im=infile, su=suff)
@@ -200,18 +203,17 @@ def main():
     grass.try_remove(tmpdir)
     os.mkdir(tmpdir)
     if is_zip:
-        shutil.copyfile(zipfile, os.path.join(tmpdir,
-                                              "{im}{su}.zip".format(im=tile,
-                                                                    su=suff)))
+        shutil.copyfile(
+            zipfile, os.path.join(tmpdir, "{im}{su}.zip".format(im=tile, su=suff))
+        )
     else:
-        shutil.copyfile(hgtfile, os.path.join(tmpdir,
-                                              "{im}{su}".format(im=tile[:7],
-                                                                su=suff)))
+        shutil.copyfile(
+            hgtfile, os.path.join(tmpdir, "{im}{su}".format(im=tile[:7], su=suff))
+        )
     # change to temporary directory
     os.chdir(tmpdir)
     in_temp = True
 
-
     zipfile = "{im}{su}.zip".format(im=tile, su=suff)
     hgtfile = "{im}{su}".format(im=tile[:7], su=suff)
 
@@ -221,7 +223,7 @@ def main():
         # unzip & rename data file:
         grass.message(_("Extracting '%s'...") % infile)
         try:
-            zf=zfile.ZipFile(zipfile)
+            zf = zfile.ZipFile(zipfile)
             zf.extractall()
         except:
             grass.fatal(_("Unable to unzip file."))
@@ -257,31 +259,34 @@ def main():
         tmpl = tmpl1sec
 
     header = tmpl % (ulxmap, ulymap)
-    hdrfile = tile + '.hdr'
-    outf = open(hdrfile, 'w')
+    hdrfile = tile + ".hdr"
+    outf = open(hdrfile, "w")
     outf.write(header)
     outf.close()
 
     # create prj file: To be precise, we would need EGS96! But who really cares...
-    prjfile = tile + '.prj'
-    outf = open(prjfile, 'w')
+    prjfile = tile + ".prj"
+    outf = open(prjfile, "w")
     outf.write(proj)
     outf.close()
 
     try:
-        grass.run_command('r.in.gdal', input=bilfile, out=tileout)
+        grass.run_command("r.in.gdal", input=bilfile, out=tileout)
     except:
         grass.fatal(_("Unable to import data"))
 
     # nice color table
     if not swbd:
-        grass.run_command('r.colors', map=tileout, color='srtm')
+        grass.run_command("r.colors", map=tileout, color="srtm")
 
     # write cmd history:
     grass.raster_history(tileout)
 
     grass.message(_("Done: generated map ") + tileout)
-    grass.message(_("(Note: Holes in the data can be closed with 'r.fillnulls' using splines)"))
+    grass.message(
+        _("(Note: Holes in the data can be closed with 'r.fillnulls' using splines)")
+    )
+
 
 if __name__ == "__main__":
     options, flags = grass.parser()

+ 30 - 21
scripts/r.in.wms/r.in.wms.py

@@ -196,7 +196,8 @@ This program is free software under the GNU General Public License
 
 import os
 import sys
-sys.path.insert(1, os.path.join(os.path.dirname(sys.path[0]), 'etc', 'r.in.wms'))
+
+sys.path.insert(1, os.path.join(os.path.dirname(sys.path[0]), "etc", "r.in.wms"))
 
 import grass.script as grass
 from grass.script.utils import decode
@@ -206,19 +207,18 @@ def GetRegionParams(opt_region):
 
     # set region
     if opt_region:
-        reg_spl = opt_region.strip().split('@', 1)
-        reg_mapset = '.'
+        reg_spl = opt_region.strip().split("@", 1)
+        reg_mapset = "."
         if len(reg_spl) > 1:
             reg_mapset = reg_spl[1]
 
-        if not grass.find_file(name=reg_spl[0], element='windows', mapset=reg_mapset)['name']:
+        if not grass.find_file(name=reg_spl[0], element="windows", mapset=reg_mapset)[
+            "name"
+        ]:
             grass.fatal(_("Region <%s> not found") % opt_region)
 
     if opt_region:
-        s = grass.read_command('g.region',
-                               quiet=True,
-                               flags='ug',
-                               region=opt_region)
+        s = grass.read_command("g.region", quiet=True, flags="ug", region=opt_region)
         region_params = grass.parse_key_val(decode(s), val_type=float)
     else:
         region_params = grass.region()
@@ -228,35 +228,44 @@ def GetRegionParams(opt_region):
 
 def main():
 
-    if 'GRASS' in options['driver']:
+    if "GRASS" in options["driver"]:
         grass.debug("Using GRASS driver")
         from wms_drv import WMSDrv
+
         wms = WMSDrv()
-    elif 'GDAL' in options['driver']:
+    elif "GDAL" in options["driver"]:
         grass.debug("Using GDAL WMS driver")
         from wms_gdal_drv import WMSGdalDrv
+
         wms = WMSGdalDrv()
 
-    if flags['c']:
+    if flags["c"]:
         wms.GetCapabilities(options)
     else:
         from wms_base import GRASSImporter
+
         # set proxy
-        if options['proxy'] and options['proxy_user_pw']:
-            wms.setProxy(options['proxy'], options['proxy_user_pw'])
-        if options['proxy']:
-            wms.setProxy(options['proxy'])
-            if 'GRASS' in options['driver']:
-                grass.warning(_("The proxy will be ignored by the choosen GRASS driver. It is only used with the GDAL driver."))
-
-        options['region'] = GetRegionParams(options['region'])
+        if options["proxy"] and options["proxy_user_pw"]:
+            wms.setProxy(options["proxy"], options["proxy_user_pw"])
+        if options["proxy"]:
+            wms.setProxy(options["proxy"])
+            if "GRASS" in options["driver"]:
+                grass.warning(
+                    _(
+                        "The proxy will be ignored by the choosen GRASS driver. It is only used with the GDAL driver."
+                    )
+                )
+
+        options["region"] = GetRegionParams(options["region"])
         fetched_map = wms.GetMap(options, flags)
 
         grass.message(_("Importing raster map into GRASS..."))
         if not fetched_map:
-            grass.warning(_("Nothing to import.\nNo data has been downloaded from wms server."))
+            grass.warning(
+                _("Nothing to import.\nNo data has been downloaded from wms server.")
+            )
             return
-        importer = GRASSImporter(options['output'], (not flags['b']))
+        importer = GRASSImporter(options["output"], (not flags["b"]))
         importer.ImportMapIntoGRASS(fetched_map)
 
     return 0

Разница между файлами не показана из-за своего большого размера
+ 1728 - 1724
scripts/r.in.wms/srs.py


+ 357 - 253
scripts/r.in.wms/wms_base.py

@@ -33,13 +33,12 @@ from grass.exceptions import CalledModuleError
 
 
 class WMSBase(object):
-
     def __init__(self):
         # these variables are information for destructor
         self.temp_files_to_cleanup = []
 
         self.params = {}
-        self.tile_size = {'bbox': None}
+        self.tile_size = {"bbox": None}
 
         self.temp_map = None
         self.temp_warpmap = None
@@ -53,116 +52,125 @@ class WMSBase(object):
             grass.try_remove(temp_file)
 
     def _debug(self, fn, msg):
-        grass.debug("%s.%s: %s" %
-                    (self.__class__.__name__, fn, msg))
+        grass.debug("%s.%s: %s" % (self.__class__.__name__, fn, msg))
 
     def _initializeParameters(self, options, flags):
         self._debug("_initialize_parameters", "started")
 
         # initialization of module parameters (options, flags)
-        self.params['driver'] = options['driver']
+        self.params["driver"] = options["driver"]
         drv_info = WMSDriversInfo()
 
-        driver_props = drv_info.GetDrvProperties(options['driver'])
+        driver_props = drv_info.GetDrvProperties(options["driver"])
         self._checkIgnoeredParams(options, flags, driver_props)
 
-        self.params['capfile'] = options['capfile'].strip()
+        self.params["capfile"] = options["capfile"].strip()
 
-        for key in ['url', 'layers', 'styles', 'method']:
+        for key in ["url", "layers", "styles", "method"]:
             self.params[key] = options[key].strip()
 
         self.flags = flags
 
-        if self.flags['o']:
-            self.params['transparent'] = 'FALSE'
+        if self.flags["o"]:
+            self.params["transparent"] = "FALSE"
         else:
-            self.params['transparent'] = 'TRUE'
+            self.params["transparent"] = "TRUE"
 
-        for key in ['password', 'username', 'urlparams']:
+        for key in ["password", "username", "urlparams"]:
             self.params[key] = options[key]
 
-        if (self.params ['password'] and self.params ['username'] == '') or \
-           (self.params['password'] == '' and self.params['username']):
-            grass.fatal(_("Please insert both %s and %s parameters or none of them." %
-                          ('password', 'username')))
-
-        self.params['bgcolor'] = options['bgcolor'].strip()
-
-        if options['format'] == "jpeg" and \
-           'format' not in driver_props['ignored_params']:
-            if not flags['o'] and \
-                    'WMS' in self.params['driver']:
+        if (self.params["password"] and self.params["username"] == "") or (
+            self.params["password"] == "" and self.params["username"]
+        ):
+            grass.fatal(
+                _(
+                    "Please insert both %s and %s parameters or none of them."
+                    % ("password", "username")
+                )
+            )
+
+        self.params["bgcolor"] = options["bgcolor"].strip()
+
+        if (
+            options["format"] == "jpeg"
+            and "format" not in driver_props["ignored_params"]
+        ):
+            if not flags["o"] and "WMS" in self.params["driver"]:
                 grass.warning(_("JPEG format does not support transparency"))
 
-        self.params['format'] = drv_info.GetFormat(options['format'])
-        if not self.params['format']:
-            self.params['format'] = self.params['format']
+        self.params["format"] = drv_info.GetFormat(options["format"])
+        if not self.params["format"]:
+            self.params["format"] = self.params["format"]
 
         # TODO: get srs from Tile Service file in OnEarth_GRASS driver
-        self.params['srs'] = int(options['srs'])
-        if self.params['srs'] <= 0 and 'srs' not in driver_props['ignored_params']:
-            grass.fatal(_("Invalid EPSG code %d") % self.params['srs'])
-
-        self.params['wms_version'] = options['wms_version']
-        if "CRS" in GetSRSParamVal(self.params['srs']) and self.params['wms_version'] == "1.1.1":
-            self.params['wms_version'] = "1.3.0"
+        self.params["srs"] = int(options["srs"])
+        if self.params["srs"] <= 0 and "srs" not in driver_props["ignored_params"]:
+            grass.fatal(_("Invalid EPSG code %d") % self.params["srs"])
+
+        self.params["wms_version"] = options["wms_version"]
+        if (
+            "CRS" in GetSRSParamVal(self.params["srs"])
+            and self.params["wms_version"] == "1.1.1"
+        ):
+            self.params["wms_version"] = "1.3.0"
             grass.warning(
-                _("WMS version <1.3.0> will be used, because version <1.1.1> does not support <%s>projection") %
-                GetSRSParamVal(
-                    self.params['srs']))
-
-        if self.params['wms_version'] == "1.3.0":
-            self.params['proj_name'] = "CRS"
+                _(
+                    "WMS version <1.3.0> will be used, because version <1.1.1> does not support <%s>projection"
+                )
+                % GetSRSParamVal(self.params["srs"])
+            )
+
+        if self.params["wms_version"] == "1.3.0":
+            self.params["proj_name"] = "CRS"
         else:
-            self.params['proj_name'] = "SRS"
+            self.params["proj_name"] = "SRS"
 
         # read projection info
-        self.proj_location = grass.read_command('g.proj',
-                                                flags='jf').rstrip('\n')
+        self.proj_location = grass.read_command("g.proj", flags="jf").rstrip("\n")
         self.proj_location = self._modifyProj(self.proj_location)
 
-        self.source_epsg = str(GetEpsg(self.params['srs']))
+        self.source_epsg = str(GetEpsg(self.params["srs"]))
         self.target_epsg = None
-        target_crs = grass.parse_command('g.proj', flags='g', delimiter = '=')
-        if 'epsg' in target_crs.keys():
-            self.target_epsg = target_crs['epsg']
+        target_crs = grass.parse_command("g.proj", flags="g", delimiter="=")
+        if "epsg" in target_crs.keys():
+            self.target_epsg = target_crs["epsg"]
             if self.source_epsg != self.target_epsg:
-                grass.warning(_("SRS differences: WMS source EPSG %s != location EPSG %s (use srs=%s to adjust)") %
-                              (self.source_epsg, self.target_epsg, self.target_epsg))
-
-        self.proj_srs = grass.read_command('g.proj',
-                                           flags='jf',
-                                           epsg=str(GetEpsg(self.params['srs'])))
-        self.proj_srs = self.proj_srs.rstrip('\n')
+                grass.warning(
+                    _(
+                        "SRS differences: WMS source EPSG %s != location EPSG %s (use srs=%s to adjust)"
+                    )
+                    % (self.source_epsg, self.target_epsg, self.target_epsg)
+                )
+
+        self.proj_srs = grass.read_command(
+            "g.proj", flags="jf", epsg=str(GetEpsg(self.params["srs"]))
+        )
+        self.proj_srs = self.proj_srs.rstrip("\n")
 
         self.proj_srs = self._modifyProj(self.proj_srs)
 
         if not self.proj_srs or not self.proj_location:
             grass.fatal(_("Unable to get projection info"))
 
-        self.region = options['region']
+        self.region = options["region"]
 
         min_tile_size = 100
-        maxcols = int(options['maxcols'])
+        maxcols = int(options["maxcols"])
         if maxcols <= min_tile_size:
             grass.fatal(_("Maxcols must be greater than 100"))
 
-        maxrows = int(options['maxrows'])
+        maxrows = int(options["maxrows"])
         if maxrows <= min_tile_size:
             grass.fatal(_("Maxrows must be greater than 100"))
 
         # setting optimal tile size according to maxcols and maxrows constraint
         # and region cols and rows
-        self.tile_size['cols'] = int(
-            self.region['cols'] /
-            ceil(
-                self.region['cols'] /
-                float(maxcols)))
-        self.tile_size['rows'] = int(
-            self.region['rows'] /
-            ceil(
-                self.region['rows'] /
-                float(maxrows)))
+        self.tile_size["cols"] = int(
+            self.region["cols"] / ceil(self.region["cols"] / float(maxcols))
+        )
+        self.tile_size["rows"] = int(
+            self.region["rows"] / ceil(self.region["rows"] / float(maxrows))
+        )
 
         # default format for GDAL library
         self.gdal_drv_format = "GTiff"
@@ -173,8 +181,8 @@ class WMSBase(object):
         """!Modify proj.4 string for usage in this module"""
 
         # add +wktext parameter to avoid droping of +nadgrids parameter (if presented) in gdalwarp
-        if '+nadgrids=' in proj and ' +wktext' not in proj:
-            proj += ' +wktext'
+        if "+nadgrids=" in proj and " +wktext" not in proj:
+            proj += " +wktext"
 
         return proj
 
@@ -182,28 +190,38 @@ class WMSBase(object):
         """!Write warnings for set parameters and flags, which chosen driver does not use."""
 
         not_relevant_params = []
-        for i_param in driver_props['ignored_params']:
+        for i_param in driver_props["ignored_params"]:
 
-            if i_param in options and \
-               options[i_param] and \
-               i_param not in ['srs', 'wms_version', 'format']:  # params with default value
-                not_relevant_params.append('<' + i_param + '>')
+            if (
+                i_param in options
+                and options[i_param]
+                and i_param not in ["srs", "wms_version", "format"]
+            ):  # params with default value
+                not_relevant_params.append("<" + i_param + ">")
 
         if len(not_relevant_params) > 0:
-            grass.warning(_("These parameter are ignored: %s\n\
-                             %s driver does not support the parameters." %
-                            (','.join(not_relevant_params), options['driver'])))
+            grass.warning(
+                _(
+                    "These parameter are ignored: %s\n\
+                             %s driver does not support the parameters."
+                    % (",".join(not_relevant_params), options["driver"])
+                )
+            )
 
         not_relevant_flags = []
-        for i_flag in driver_props['ignored_flags']:
+        for i_flag in driver_props["ignored_flags"]:
 
             if flags[i_flag]:
-                not_relevant_flags.append('<' + i_flag + '>')
+                not_relevant_flags.append("<" + i_flag + ">")
 
         if len(not_relevant_flags) > 0:
-            grass.warning(_("These flags are ignored: %s\n\
-                             %s driver does not support the flags." %
-                            (','.join(not_relevant_flags), options['driver'])))
+            grass.warning(
+                _(
+                    "These flags are ignored: %s\n\
+                             %s driver does not support the flags."
+                    % (",".join(not_relevant_flags), options["driver"])
+                )
+            )
 
     def GetMap(self, options, flags):
         """!Download data from WMS server."""
@@ -221,54 +239,60 @@ class WMSBase(object):
         return self.temp_warpmap
 
     def _fetchCapabilities(self, options):
-        """!Download capabilities from WMS server
-        """
-        cap_url = options['url'].strip()
+        """!Download capabilities from WMS server"""
+        cap_url = options["url"].strip()
 
         if "?" in cap_url:
             cap_url += "&"
         else:
             cap_url += "?"
 
-        if 'WMTS' in options['driver']:
+        if "WMTS" in options["driver"]:
             cap_url += "SERVICE=WMTS&REQUEST=GetCapabilities&VERSION=1.0.0"
-        elif 'OnEarth' in options['driver']:
+        elif "OnEarth" in options["driver"]:
             cap_url += "REQUEST=GetTileService"
         else:
-            cap_url += "SERVICE=WMS&REQUEST=GetCapabilities&VERSION=" + options['wms_version']
+            cap_url += (
+                "SERVICE=WMS&REQUEST=GetCapabilities&VERSION=" + options["wms_version"]
+            )
 
-        if options['urlparams']:
-            cap_url += "&" + options['urlparams']
+        if options["urlparams"]:
+            cap_url += "&" + options["urlparams"]
 
-        grass.debug('Fetching capabilities file.\n%s' % cap_url)
+        grass.debug("Fetching capabilities file.\n%s" % cap_url)
 
         try:
-            cap = self._fetchDataFromServer(cap_url, options['username'], options['password'])
+            cap = self._fetchDataFromServer(
+                cap_url, options["username"], options["password"]
+            )
         except (IOError, HTTPException) as e:
             if isinstance(e, HTTPError) and e.code == 401:
                 grass.fatal(
-                    _("Authorization failed to <%s> when fetching capabilities") %
-                    options['url'])
+                    _("Authorization failed to <%s> when fetching capabilities")
+                    % options["url"]
+                )
             else:
                 msg = _("Unable to fetch capabilities from <{0}>. Reason: ").format(
-                    options['url'])
+                    options["url"]
+                )
 
-                if hasattr(e, 'reason'):
-                    msg += '{0}'.format(e.reason)
+                if hasattr(e, "reason"):
+                    msg += "{0}".format(e.reason)
                 else:
-                    msg += '{0}'.format(e)
+                    msg += "{0}".format(e)
 
                 grass.fatal(msg)
 
-        grass.debug('Fetching capabilities OK')
+        grass.debug("Fetching capabilities OK")
         return grass.decode(cap.read())
 
     def _fetchDataFromServer(self, url, username=None, password=None):
-        """!Fetch data from server
-        """
+        """!Fetch data from server"""
         request = Request(url)
         if username and password:
-            base64string = base64.encodestring('%s:%s' % (username, password)).replace('\n', '')
+            base64string = base64.encodestring("%s:%s" % (username, password)).replace(
+                "\n", ""
+            )
             request.add_header("Authorization", "Basic %s" % base64string)
 
         try:
@@ -277,10 +301,9 @@ class WMSBase(object):
             grass.fatal("%s" % error)
 
     def GetCapabilities(self, options):
-        """!Get capabilities from WMS server
-        """
+        """!Get capabilities from WMS server"""
         cap = self._fetchCapabilities(options)
-        capfile_output = options['capfile_output'].strip()
+        capfile_output = options["capfile_output"].strip()
 
         # save to file
         if capfile_output:
@@ -289,17 +312,18 @@ class WMSBase(object):
                     temp.write(cap)
                 return
             except IOError as error:
-                grass.fatal(_("Unable to open file '%s'.\n%s\n" % (capfile_output, error)))
+                grass.fatal(
+                    _("Unable to open file '%s'.\n%s\n" % (capfile_output, error))
+                )
 
         # print to output
         print(cap)
 
     def _computeBbox(self):
-        """!Get region extent for WMS query (bbox)
-        """
+        """!Get region extent for WMS query (bbox)"""
         self._debug("_computeBbox", "started")
 
-        bbox_region_items = {'maxy': 'n', 'miny': 's', 'maxx': 'e', 'minx': 'w'}
+        bbox_region_items = {"maxy": "n", "miny": "s", "maxx": "e", "minx": "w"}
         bbox = {}
 
         if self.proj_srs == self.proj_location:  # TODO: do it better
@@ -317,25 +341,36 @@ class WMSBase(object):
             temp_region = self._tempfile()
 
             try:
-                temp_region_opened = open(temp_region, 'w')
-                temp_region_opened.write("%f %f\n%f %f\n%f %f\n%f %f\n" %
-                                         (self.region['e'], self.region['n'],
-                                          self.region['w'], self.region['n'],
-                                          self.region['w'], self.region['s'],
-                                          self.region['e'], self.region['s']))
+                temp_region_opened = open(temp_region, "w")
+                temp_region_opened.write(
+                    "%f %f\n%f %f\n%f %f\n%f %f\n"
+                    % (
+                        self.region["e"],
+                        self.region["n"],
+                        self.region["w"],
+                        self.region["n"],
+                        self.region["w"],
+                        self.region["s"],
+                        self.region["e"],
+                        self.region["s"],
+                    )
+                )
             except IOError:
                 grass.fatal(_("Unable to write data into tempfile"))
             finally:
                 temp_region_opened.close()
 
-            points = grass.read_command('m.proj', flags='d',
-                                        proj_out=self.proj_srs,
-                                        proj_in=self.proj_location,
-                                        input=temp_region,
-                                        quiet=True)  # TODO: stdin
+            points = grass.read_command(
+                "m.proj",
+                flags="d",
+                proj_out=self.proj_srs,
+                proj_in=self.proj_location,
+                input=temp_region,
+                quiet=True,
+            )  # TODO: stdin
             grass.try_remove(temp_region)
             if not points:
-                grass.fatal(_("Unable to determine region, %s failed") % 'm.proj')
+                grass.fatal(_("Unable to determine region, %s failed") % "m.proj")
 
             points = points.splitlines()
             if len(points) != 4:
@@ -345,23 +380,23 @@ class WMSBase(object):
                 try:
                     point = list(map(float, point.split("|")))
                 except ValueError:
-                    grass.fatal(_('Reprojection of region using m.proj failed.'))
-                if not bbox['maxy']:
-                    bbox['maxy'] = point[1]
-                    bbox['miny'] = point[1]
-                    bbox['maxx'] = point[0]
-                    bbox['minx'] = point[0]
+                    grass.fatal(_("Reprojection of region using m.proj failed."))
+                if not bbox["maxy"]:
+                    bbox["maxy"] = point[1]
+                    bbox["miny"] = point[1]
+                    bbox["maxx"] = point[0]
+                    bbox["minx"] = point[0]
                     continue
 
-                if bbox['maxy'] < point[1]:
-                    bbox['maxy'] = point[1]
-                elif bbox['miny'] > point[1]:
-                    bbox['miny'] = point[1]
+                if bbox["maxy"] < point[1]:
+                    bbox["maxy"] = point[1]
+                elif bbox["miny"] > point[1]:
+                    bbox["miny"] = point[1]
 
-                if bbox['maxx'] < point[0]:
-                    bbox['maxx'] = point[0]
-                elif bbox['minx'] > point[0]:
-                    bbox['minx'] = point[0]
+                if bbox["maxx"] < point[0]:
+                    bbox["maxx"] = point[0]
+                elif bbox["minx"] > point[0]:
+                    bbox["minx"] = point[0]
 
         self._debug("_computeBbox", "finished -> %s" % bbox)
 
@@ -372,56 +407,79 @@ class WMSBase(object):
         return bbox
 
     def _reprojectMap(self):
-        """!Reproject data  using gdalwarp if needed
-        """
+        """!Reproject data  using gdalwarp if needed"""
         # reprojection of raster
         do_reproject = True
-        if self.source_epsg is not None and self.target_epsg is not None \
-            and self.source_epsg == self.target_epsg:
+        if (
+            self.source_epsg is not None
+            and self.target_epsg is not None
+            and self.source_epsg == self.target_epsg
+        ):
             do_reproject = False
         # TODO: correctly compare source and target crs
         if do_reproject and self.proj_srs == self.proj_location:
             do_reproject = False
         if do_reproject:
             grass.message(_("Reprojecting raster..."))
-            self.temp_warpmap = grass.tempfile() + '.tif'
+            self.temp_warpmap = grass.tempfile() + ".tif"
 
-            if int(os.getenv('GRASS_VERBOSE', '2')) <= 2:
-                nuldev = open(os.devnull, 'w+')
+            if int(os.getenv("GRASS_VERBOSE", "2")) <= 2:
+                nuldev = open(os.devnull, "w+")
             else:
                 nuldev = None
 
-            if self.params['method'] == "nearest":
+            if self.params["method"] == "nearest":
                 gdal_method = "near"
-            elif self.params['method'] == "linear":
+            elif self.params["method"] == "linear":
                 gdal_method = "bilinear"
             else:
-                gdal_method = self.params['method']
+                gdal_method = self.params["method"]
 
             # RGB rasters - alpha layer is added for cropping edges of projected raster
             try:
                 if self.temp_map_bands_num == 3:
-                    ps = grass.Popen(['gdalwarp',
-                                      '-s_srs', '%s' % self.proj_srs,
-                                      '-t_srs', '%s' % self.proj_location,
-                                      '-r', gdal_method, '-dstalpha',
-                                      self.temp_map, self.temp_warpmap], stdout=nuldev)
+                    ps = grass.Popen(
+                        [
+                            "gdalwarp",
+                            "-s_srs",
+                            "%s" % self.proj_srs,
+                            "-t_srs",
+                            "%s" % self.proj_location,
+                            "-r",
+                            gdal_method,
+                            "-dstalpha",
+                            self.temp_map,
+                            self.temp_warpmap,
+                        ],
+                        stdout=nuldev,
+                    )
                 # RGBA rasters
                 else:
-                    ps = grass.Popen(['gdalwarp',
-                                      '-s_srs', '%s' % self.proj_srs,
-                                      '-t_srs', '%s' % self.proj_location,
-                                      '-r', gdal_method,
-                                      self.temp_map, self.temp_warpmap], stdout=nuldev)
+                    ps = grass.Popen(
+                        [
+                            "gdalwarp",
+                            "-s_srs",
+                            "%s" % self.proj_srs,
+                            "-t_srs",
+                            "%s" % self.proj_location,
+                            "-r",
+                            gdal_method,
+                            self.temp_map,
+                            self.temp_warpmap,
+                        ],
+                        stdout=nuldev,
+                    )
                 ps.wait()
             except OSError as e:
-                grass.fatal('%s \nThis can be caused by missing %s utility. ' % (e, 'gdalwarp'))
+                grass.fatal(
+                    "%s \nThis can be caused by missing %s utility. " % (e, "gdalwarp")
+                )
 
             if nuldev:
                 nuldev.close()
 
             if ps.returncode != 0:
-                grass.fatal(_('%s failed') % 'gdalwarp')
+                grass.fatal(_("%s failed") % "gdalwarp")
             grass.try_remove(self.temp_map)
         # raster projection is same as projection of location
         else:
@@ -447,7 +505,6 @@ class WMSBase(object):
 
 
 class GRASSImporter:
-
     def __init__(self, opt_output, cleanup_bands):
 
         self.cleanup_mask = False
@@ -462,143 +519,181 @@ class GRASSImporter:
 
         # check names of temporary rasters, which module may create
         maps = []
-        for suffix in ('.red', '.green', '.blue', '.alpha', self.original_mask_suffix):
+        for suffix in (".red", ".green", ".blue", ".alpha", self.original_mask_suffix):
             rast = self.opt_output + suffix
-            if grass.find_file(rast, element='cell', mapset='.')['file']:
+            if grass.find_file(rast, element="cell", mapset=".")["file"]:
                 maps.append(rast)
 
         if len(maps) != 0:
-            grass.fatal(_("Please change output name, or change names of these rasters: %s, "
-                          "module needs to create this temporary maps during execution.") % ",".join(maps))
+            grass.fatal(
+                _(
+                    "Please change output name, or change names of these rasters: %s, "
+                    "module needs to create this temporary maps during execution."
+                )
+                % ",".join(maps)
+            )
 
     def __del__(self):
         # removes temporary mask, used for import transparent or warped temp_map
         if self.cleanup_mask:
             # clear temporary mask, which was set by module
             try:
-                grass.run_command('r.mask', quiet=True, flags='r')
+                grass.run_command("r.mask", quiet=True, flags="r")
             except CalledModuleError:
-                grass.fatal(_('%s failed') % 'r.mask')
+                grass.fatal(_("%s failed") % "r.mask")
 
             # restore original mask, if exists
-            if grass.find_file(self.opt_output + self.original_mask_suffix,
-                               element='cell', mapset='.')['name']:
+            if grass.find_file(
+                self.opt_output + self.original_mask_suffix, element="cell", mapset="."
+            )["name"]:
                 try:
                     mask_copy = self.opt_output + self.original_mask_suffix
-                    grass.run_command('g.copy', quiet=True,
-                                      raster=mask_copy + ',MASK')
+                    grass.run_command("g.copy", quiet=True, raster=mask_copy + ",MASK")
                 except CalledModuleError:
-                    grass.fatal(_('%s failed') % 'g.copy')
+                    grass.fatal(_("%s failed") % "g.copy")
 
         # remove temporary created rasters
         maps = []
-        rast = self.opt_output + '.alpha'
-        if grass.find_file(rast, element='cell', mapset='.')['file']:
+        rast = self.opt_output + ".alpha"
+        if grass.find_file(rast, element="cell", mapset=".")["file"]:
             maps.append(rast)
 
         if self.cleanup_bands:
-            for suffix in ('.red', '.green', '.blue', self.original_mask_suffix):
+            for suffix in (".red", ".green", ".blue", self.original_mask_suffix):
                 rast = self.opt_output + suffix
-                if grass.find_file(rast, element='cell', mapset='.')['file']:
+                if grass.find_file(rast, element="cell", mapset=".")["file"]:
                     maps.append(rast)
 
         if maps:
-            grass.run_command('g.remove',
-                              quiet=True,
-                              flags='fb',
-                              type='raster',
-                              name=','.join(maps))
+            grass.run_command(
+                "g.remove", quiet=True, flags="fb", type="raster", name=",".join(maps)
+            )
 
         # delete environmental variable which overrides region
-        if 'GRASS_REGION' in os.environ.keys():
-            os.environ.pop('GRASS_REGION')
+        if "GRASS_REGION" in os.environ.keys():
+            os.environ.pop("GRASS_REGION")
 
-        maplist = grass.read_command('g.list', type = 'raster',
-                                     pattern = '%s*' % (self.opt_output),
-                                     mapset = '.', separator = ',').rstrip('\n')
+        maplist = grass.read_command(
+            "g.list",
+            type="raster",
+            pattern="%s*" % (self.opt_output),
+            mapset=".",
+            separator=",",
+        ).rstrip("\n")
 
         if len(maplist) == 0:
-            grass.fatal(_('WMS import failed, nothing imported'))
+            grass.fatal(_("WMS import failed, nothing imported"))
         else:
-            for raster in maplist.split(','):
-                grass.raster_history(raster, overwrite = True)
-                grass.run_command('r.support', map=raster, description='generated by r.in.wms')
-                grass.message(_('<%s> created.') % raster)
-
+            for raster in maplist.split(","):
+                grass.raster_history(raster, overwrite=True)
+                grass.run_command(
+                    "r.support", map=raster, description="generated by r.in.wms"
+                )
+                grass.message(_("<%s> created.") % raster)
 
     def ImportMapIntoGRASS(self, raster):
-        """!Import raster into GRASS.
-        """
+        """!Import raster into GRASS."""
         # importing temp_map into GRASS
         try:
             # do not use -o flag !
-            grass.run_command('r.in.gdal', flags='o',
-                              quiet=True, overwrite=True,
-                              input=raster, output=self.opt_output)
+            grass.run_command(
+                "r.in.gdal",
+                flags="o",
+                quiet=True,
+                overwrite=True,
+                input=raster,
+                output=self.opt_output,
+            )
         except CalledModuleError:
-            grass.fatal(_('%s failed') % 'r.in.gdal')
+            grass.fatal(_("%s failed") % "r.in.gdal")
 
         # information for destructor to cleanup temp_layers, created
         # with r.in.gdal
 
         # setting region for full extend of imported raster
-        if grass.find_file(self.opt_output + '.red', element='cell', mapset='.')['file']:
-            region_map = self.opt_output + '.red'
+        if grass.find_file(self.opt_output + ".red", element="cell", mapset=".")[
+            "file"
+        ]:
+            region_map = self.opt_output + ".red"
         else:
             region_map = self.opt_output
-        os.environ['GRASS_REGION'] = grass.region_env(rast=region_map)
+        os.environ["GRASS_REGION"] = grass.region_env(rast=region_map)
 
         # mask created from alpha layer, which describes real extend
         # of warped layer (may not be a rectangle), also mask contains
         # transparent parts of raster
-        if grass.find_file(self.opt_output + '.alpha', element='cell', mapset='.')['name']:
+        if grass.find_file(self.opt_output + ".alpha", element="cell", mapset=".")[
+            "name"
+        ]:
             # saving current mask (if exists) into temp raster
-            if grass.find_file('MASK', element='cell', mapset='.')['name']:
+            if grass.find_file("MASK", element="cell", mapset=".")["name"]:
                 try:
                     mask_copy = self.opt_output + self.original_mask_suffix
-                    grass.run_command('g.copy', quiet=True,
-                                      raster='MASK,' + mask_copy)
+                    grass.run_command("g.copy", quiet=True, raster="MASK," + mask_copy)
                 except CalledModuleError:
-                    grass.fatal(_('%s failed') % 'g.copy')
+                    grass.fatal(_("%s failed") % "g.copy")
 
             # info for destructor
             self.cleanup_mask = True
             try:
-                grass.run_command('r.mask',
-                                  quiet=True, overwrite=True,
-                                  maskcats="0",
-                                  flags='i',
-                                  raster=self.opt_output + '.alpha')
+                grass.run_command(
+                    "r.mask",
+                    quiet=True,
+                    overwrite=True,
+                    maskcats="0",
+                    flags="i",
+                    raster=self.opt_output + ".alpha",
+                )
             except CalledModuleError:
-                grass.fatal(_('%s failed') % 'r.mask')
+                grass.fatal(_("%s failed") % "r.mask")
 
             if not self.cleanup_bands:
                 # use the MASK to set NULL vlues
-                for suffix in ('.red', '.green', '.blue'):
+                for suffix in (".red", ".green", ".blue"):
                     rast = self.opt_output + suffix
-                    if grass.find_file(rast, element='cell', mapset='.')['file']:
-                        grass.run_command('g.rename', rast='%s,%s' % (rast, rast + '_null'), quiet = True)
-                        grass.run_command('r.mapcalc', expression = '%s = %s' % (rast, rast + '_null'), quiet = True)
-                        grass.run_command('g.remove', type='raster', name='%s' % (rast + '_null'), flags = 'f', quiet = True)
+                    if grass.find_file(rast, element="cell", mapset=".")["file"]:
+                        grass.run_command(
+                            "g.rename",
+                            rast="%s,%s" % (rast, rast + "_null"),
+                            quiet=True,
+                        )
+                        grass.run_command(
+                            "r.mapcalc",
+                            expression="%s = %s" % (rast, rast + "_null"),
+                            quiet=True,
+                        )
+                        grass.run_command(
+                            "g.remove",
+                            type="raster",
+                            name="%s" % (rast + "_null"),
+                            flags="f",
+                            quiet=True,
+                        )
 
         # TODO one band + alpha band?
-        if grass.find_file(self.opt_output + '.red', element='cell', mapset='.')['file'] and self.cleanup_bands:
+        if (
+            grass.find_file(self.opt_output + ".red", element="cell", mapset=".")[
+                "file"
+            ]
+            and self.cleanup_bands
+        ):
             try:
-                grass.run_command('r.composite',
-                                  quiet=True, overwrite=True,
-                                  red=self.opt_output + '.red',
-                                  green=self.opt_output + '.green',
-                                  blue=self.opt_output + '.blue',
-                                  output=self.opt_output)
+                grass.run_command(
+                    "r.composite",
+                    quiet=True,
+                    overwrite=True,
+                    red=self.opt_output + ".red",
+                    green=self.opt_output + ".green",
+                    blue=self.opt_output + ".blue",
+                    output=self.opt_output,
+                )
             except CalledModuleError:
-                grass.fatal(_('%s failed') % 'r.composite')
+                grass.fatal(_("%s failed") % "r.composite")
 
 
 class WMSDriversInfo:
-
     def __init__(self):
-        """!Provides information about driver parameters.
-        """
+        """!Provides information about driver parameters."""
 
         # format labels
         self.f_labels = ["geotiff", "tiff", "png", "jpeg", "gif", "png8"]
@@ -610,70 +705,80 @@ class WMSDriversInfo:
             "image/png",
             "image/jpeg",
             "image/gif",
-            "image/png8"]
+            "image/png8",
+        ]
 
         self.srs = ("epsg", "ogc")
 
     def GetDrvProperties(self, driver):
-        """!Get information about driver parameters.
-        """
-        if driver == 'WMS_GDAL':
+        """!Get information about driver parameters."""
+        if driver == "WMS_GDAL":
             return self._GDALDrvProperties()
-        if 'WMS' in driver:
+        if "WMS" in driver:
             return self._WMSProperties()
-        if 'WMTS' in driver:
+        if "WMTS" in driver:
             return self._WMTSProperties()
-        if 'OnEarth' in driver:
+        if "OnEarth" in driver:
             return self._OnEarthProperties()
 
     def _OnEarthProperties(self):
 
         props = {}
-        props['ignored_flags'] = ['o']
-        props['ignored_params'] = ['bgcolor', 'styles', 'capfile_output',
-                                   'format', 'srs', 'wms_version']
-        props['req_multiple_layers'] = False
+        props["ignored_flags"] = ["o"]
+        props["ignored_params"] = [
+            "bgcolor",
+            "styles",
+            "capfile_output",
+            "format",
+            "srs",
+            "wms_version",
+        ]
+        props["req_multiple_layers"] = False
 
         return props
 
     def _WMSProperties(self):
 
         props = {}
-        props['ignored_params'] = ['capfile']
-        props['ignored_flags'] = []
-        props['req_multiple_layers'] = True
+        props["ignored_params"] = ["capfile"]
+        props["ignored_flags"] = []
+        props["req_multiple_layers"] = True
 
         return props
 
     def _WMTSProperties(self):
 
         props = {}
-        props['ignored_flags'] = ['o']
-        props['ignored_params'] = ['urlparams', 'bgcolor', 'wms_version']
-        props['req_multiple_layers'] = False
+        props["ignored_flags"] = ["o"]
+        props["ignored_params"] = ["urlparams", "bgcolor", "wms_version"]
+        props["req_multiple_layers"] = False
 
         return props
 
     def _GDALDrvProperties(self):
 
         props = {}
-        props['ignored_flags'] = []
-        props['ignored_params'] = ['urlparams', 'bgcolor', 'capfile', 'capfile_output',
-                                   'username', 'password']
-        props['req_multiple_layers'] = True
+        props["ignored_flags"] = []
+        props["ignored_params"] = [
+            "urlparams",
+            "bgcolor",
+            "capfile",
+            "capfile_output",
+            "username",
+            "password",
+        ]
+        props["req_multiple_layers"] = True
 
         return props
 
     def GetFormatLabel(self, format):
-        """!Convert format request form to value in parameter 'format'.
-        """
+        """!Convert format request form to value in parameter 'format'."""
         if format in self.formats:
             return self.f_labels[self.formats.index(format)]
         return None
 
     def GetFormat(self, label):
-        """!Convert value in parameter 'format' to format request form.
-        """
+        """!Convert value in parameter 'format' to format request form."""
         if label in self.f_labels:
             return self.formats[self.f_labels.index(label)]
         return None
@@ -688,8 +793,7 @@ class WMSDriversInfo:
 
 # TODO move to utils?
 def GetSRSParamVal(srs):
-    """!Decides whether to use CRS or EPSG prefix according to srs number.
-    """
+    """!Decides whether to use CRS or EPSG prefix according to srs number."""
 
     if srs in [84, 83, 27]:
         return "OGC:CRS{}".format(srs)
@@ -699,8 +803,8 @@ def GetSRSParamVal(srs):
 
 def GetEpsg(srs):
     """
-     @return EPSG number
-             If srs is CRS number, return EPSG number which corresponds to CRS number.
+    @return EPSG number
+            If srs is CRS number, return EPSG number which corresponds to CRS number.
     """
     if srs == 84:
         return 4326

+ 173 - 147
scripts/r.in.wms/wms_cap_parsers.py

@@ -28,17 +28,15 @@ import grass.script as grass
 
 
 class BaseCapabilitiesTree(etree.ElementTree):
-
     def __init__(self, cap_file):
-        """!Initialize xml.etree.ElementTree
-        """
+        """!Initialize xml.etree.ElementTree"""
         is_file = False
         try:
             xml = pathlib.Path(cap_file)
             if xml.exists():
                 is_file = True
         except OSError as exc:
-            if exc.errno == 36: # file name too long
+            if exc.errno == 36:  # file name too long
                 pass
             else:
                 raise
@@ -48,7 +46,9 @@ class BaseCapabilitiesTree(etree.ElementTree):
             except ParseError:
                 raise ParseError(_("Unable to parse XML file"))
             except IOError as error:
-                raise ParseError(_("Unable to open XML file '%s'.\n%s\n" % (cap_file, error)))
+                raise ParseError(
+                    _("Unable to open XML file '%s'.\n%s\n" % (cap_file, error))
+                )
         else:
             try:
                 etree.ElementTree.__init__(self, element=etree.fromstring(cap_file))
@@ -60,10 +60,8 @@ class BaseCapabilitiesTree(etree.ElementTree):
 
 
 class WMSXMLNsHandler:
-
     def __init__(self, caps):
-        """!Handle XML namespaces according to WMS version of capabilities.
-        """
+        """!Handle XML namespaces according to WMS version of capabilities."""
         self.namespace = "{http://www.opengis.net/wms}"
 
         if caps.getroot().find("Service") is not None:
@@ -71,19 +69,22 @@ class WMSXMLNsHandler:
         elif caps.getroot().find(self.namespace + "Service") is not None:
             self.use_ns = True
         else:
-            raise ParseError(_("Unable to parse capabilities file.\n\
-                                Tag <%s> was not found.") % "Service")
+            raise ParseError(
+                _(
+                    "Unable to parse capabilities file.\n\
+                                Tag <%s> was not found."
+                )
+                % "Service"
+            )
 
     def Ns(self, tag_name):
-        """!Add namespace to tag_name according to version
-        """
+        """!Add namespace to tag_name according to version"""
         if self.use_ns:
             tag_name = self.namespace + tag_name
         return tag_name
 
 
 class WMSCapabilitiesTree(BaseCapabilitiesTree):
-
     def __init__(self, cap_file, force_version=None):
         """!Parses WMS capabilities file.
             If the capabilities file cannot be parsed if it raises xml.etree.ElementTree.ParseError.
@@ -99,11 +100,12 @@ class WMSCapabilitiesTree(BaseCapabilitiesTree):
         BaseCapabilitiesTree.__init__(self, cap_file)
         self.xml_ns = WMSXMLNsHandler(self)
 
-        grass.debug('Checking WMS capabilities tree.', 4)
+        grass.debug("Checking WMS capabilities tree.", 4)
 
         if "version" not in self.getroot().attrib:
-            raise ParseError(_("Missing version attribute root node "
-                               "in Capabilities XML file"))
+            raise ParseError(
+                _("Missing version attribute root node " "in Capabilities XML file")
+            )
         else:
             wms_version = self.getroot().attrib["version"]
 
@@ -114,7 +116,9 @@ class WMSCapabilitiesTree(BaseCapabilitiesTree):
 
         if force_version is not None:
             if wms_version != force_version:
-                raise ParseError(_("WMS server does not support '%s' version.") % wms_version)
+                raise ParseError(
+                    _("WMS server does not support '%s' version.") % wms_version
+                )
 
         capability = self._find(self.getroot(), "Capability")
         root_layer = self._find(capability, "Layer")
@@ -122,18 +126,16 @@ class WMSCapabilitiesTree(BaseCapabilitiesTree):
         self._checkFormats(capability)
         self._checkLayerTree(root_layer)
 
-        grass.debug('Check of WMS capabilities tree was finished.', 4)
+        grass.debug("Check of WMS capabilities tree was finished.", 4)
 
     def _checkFormats(self, capability):
-        """!Check if format element is defined.
-        """
+        """!Check if format element is defined."""
         request = self._find(capability, "Request")
         get_map = self._find(request, "GetMap")
         formats = self._findall(get_map, "Format")
 
     def _checkLayerTree(self, parent_layer, first=True):
-        """!Recursively check layer tree and manage inheritance in the tree
-        """
+        """!Recursively check layer tree and manage inheritance in the tree"""
         if first:
             self._initLayer(parent_layer, None)
 
@@ -150,11 +152,13 @@ class WMSCapabilitiesTree(BaseCapabilitiesTree):
         @param parent_layer - <Layer> element which is inherited from
         """
         if parent_layer is not None:
-            replaced_elements = [["EX_GeographicBoundingBox", "replace"],
-                                 ["Attribution", "replace"],
-                                 ["MinScaleDenominator", "replace"],
-                                 ["MaxScaleDenominator", "replace"],
-                                 ["AuthorityURL", "add"]]
+            replaced_elements = [
+                ["EX_GeographicBoundingBox", "replace"],
+                ["Attribution", "replace"],
+                ["MinScaleDenominator", "replace"],
+                ["MaxScaleDenominator", "replace"],
+                ["AuthorityURL", "add"],
+            ]
 
             for element in replaced_elements:
                 elems = layer.findall(self.xml_ns.Ns(element[0]))
@@ -163,25 +167,35 @@ class WMSCapabilitiesTree(BaseCapabilitiesTree):
                     for e in parent_layer.findall(self.xml_ns.Ns(element[0])):
                         layer.append(e)
 
-            inh_arguments = ["queryable", "cascaded", "opaque",
-                             "noSubsets", "fixedWidth", "fixedHeight"]
+            inh_arguments = [
+                "queryable",
+                "cascaded",
+                "opaque",
+                "noSubsets",
+                "fixedWidth",
+                "fixedHeight",
+            ]
 
             for attr in parent_layer.attrib:
                 if attr not in layer.attrib and attr in inh_arguments:
                     layer.attrib[attr] = parent_layer.attrib[attr]
 
             self._inhNotSame(self.proj_tag, "element_content", layer, parent_layer)
-            self._inhNotSame("BoundingBox", "attribute", layer, parent_layer, self.proj_tag)
+            self._inhNotSame(
+                "BoundingBox", "attribute", layer, parent_layer, self.proj_tag
+            )
 
             # remove invalid Styles
-            styles = layer.findall(self.xml_ns.Ns('Style'))
+            styles = layer.findall(self.xml_ns.Ns("Style"))
             for s in styles:
-                s_name = s.find(self.xml_ns.Ns('Name'))
+                s_name = s.find(self.xml_ns.Ns("Name"))
                 if s_name is None or not s_name.text:
-                    grass.debug('Removed invalid <Style> element.', 4)
+                    grass.debug("Removed invalid <Style> element.", 4)
                     layer.remove(s)
 
-            self._inhNotSame("Style", "child_element_content", layer, parent_layer, "Name")
+            self._inhNotSame(
+                "Style", "child_element_content", layer, parent_layer, "Name"
+            )
             self._inhNotSame("Dimension", "attribute", layer, parent_layer, "name")
 
     def _inhNotSame(self, element_name, cmp_type, layer, parent_layer, add_arg=None):
@@ -233,8 +247,7 @@ class WMSCapabilitiesTree(BaseCapabilitiesTree):
                     if cmp is not None:
                         cmp_text = cmp.text
 
-                if cmp_text is None or \
-                   cmp_text.lower() == parent_cmp_text.lower():
+                if cmp_text is None or cmp_text.lower() == parent_cmp_text.lower():
                     is_there = True
                     break
 
@@ -243,56 +256,60 @@ class WMSCapabilitiesTree(BaseCapabilitiesTree):
 
     def _find(self, etreeElement, tag):
         """!Find child element.
-            If the element is not found it raises xml.etree.ElementTree.ParseError.
+        If the element is not found it raises xml.etree.ElementTree.ParseError.
         """
         res = etreeElement.find(self.xml_ns.Ns(tag))
 
         if res is None:
-            raise ParseError(_("Unable to parse capabilities file. \n\
-                                Tag <%s> was not found.") % tag)
+            raise ParseError(
+                _(
+                    "Unable to parse capabilities file. \n\
+                                Tag <%s> was not found."
+                )
+                % tag
+            )
 
         return res
 
     def _findall(self, etreeElement, tag):
         """!Find all children element.
-            If no element is found it raises xml.etree.ElementTree.ParseError.
+        If no element is found it raises xml.etree.ElementTree.ParseError.
         """
         res = etreeElement.findall(self.xml_ns.Ns(tag))
 
         if not res:
-            raise ParseError(_("Unable to parse capabilities file. \n\
-                                Tag <%s> was not found.") % tag)
+            raise ParseError(
+                _(
+                    "Unable to parse capabilities file. \n\
+                                Tag <%s> was not found."
+                )
+                % tag
+            )
 
         return res
 
     def getprojtag(self):
-        """!Return projection tag according to version of capabilities (CRS/SRS).
-        """
+        """!Return projection tag according to version of capabilities (CRS/SRS)."""
         return self.proj_tag
 
     def getxmlnshandler(self):
-        """!Return WMSXMLNsHandler object.
-        """
+        """!Return WMSXMLNsHandler object."""
         return self.xml_ns
 
 
 class WMTSXMLNsHandler:
-    """!Handle XML namespaces which are used in WMTS capabilities file.
-    """
+    """!Handle XML namespaces which are used in WMTS capabilities file."""
 
     def NsWmts(self, tag):
-        """!Add namespace.
-        """
+        """!Add namespace."""
         return "{http://www.opengis.net/wmts/1.0}" + tag
 
     def NsOws(self, tag):
-        """!Add namespace.
-        """
+        """!Add namespace."""
         return "{http://www.opengis.net/ows/1.1}" + tag
 
 
 class WMTSCapabilitiesTree(BaseCapabilitiesTree):
-
     def __init__(self, cap_file):
         """!Parses WMTS capabilities file.
             If the capabilities file cannot be parsed it raises xml.etree.ElementTree.ParseError.
@@ -305,61 +322,59 @@ class WMTSCapabilitiesTree(BaseCapabilitiesTree):
         BaseCapabilitiesTree.__init__(self, cap_file)
         self.xml_ns = WMTSXMLNsHandler()
 
-        grass.debug('Checking WMTS capabilities tree.', 4)
+        grass.debug("Checking WMTS capabilities tree.", 4)
 
-        contents = self._find(self.getroot(), 'Contents', self.xml_ns.NsWmts)
+        contents = self._find(self.getroot(), "Contents", self.xml_ns.NsWmts)
 
-        tile_mat_sets = self._findall(contents, 'TileMatrixSet', self.xml_ns.NsWmts)
+        tile_mat_sets = self._findall(contents, "TileMatrixSet", self.xml_ns.NsWmts)
 
         for mat_set in tile_mat_sets:
             if not self._checkMatSet(mat_set):
-                grass.debug('Removed invalid <TileMatrixSet> element.', 4)
+                grass.debug("Removed invalid <TileMatrixSet> element.", 4)
                 contents.remove(mat_set)
 
         # are there any <TileMatrixSet> elements after the check
-        self._findall(contents, 'TileMatrixSet', self.xml_ns.NsWmts)
+        self._findall(contents, "TileMatrixSet", self.xml_ns.NsWmts)
 
-        layers = self._findall(contents, 'Layer', self.xml_ns.NsWmts)
+        layers = self._findall(contents, "Layer", self.xml_ns.NsWmts)
         for l in layers:
             if not self._checkLayer(l):
-                grass.debug('Removed invalid <Layer> element.', 4)
+                grass.debug("Removed invalid <Layer> element.", 4)
                 contents.remove(l)
 
         # are there any <Layer> elements after the check
-        self._findall(contents, 'Layer', self.xml_ns.NsWmts)
+        self._findall(contents, "Layer", self.xml_ns.NsWmts)
 
-        grass.debug('Check of WMTS capabilities tree was finished.', 4)
+        grass.debug("Check of WMTS capabilities tree was finished.", 4)
 
     def _checkMatSet(self, mat_set):
-        """!Check <TileMatrixSet>.
-        """
-        mat_set_id = mat_set.find(self.xml_ns.NsOws('Identifier'))
+        """!Check <TileMatrixSet>."""
+        mat_set_id = mat_set.find(self.xml_ns.NsOws("Identifier"))
         if mat_set_id is None or not mat_set_id.text:
             return False
 
-        mat_set_srs = mat_set.find(self.xml_ns.NsOws('SupportedCRS'))
-        if mat_set_srs is None or \
-           not mat_set_srs.text:
+        mat_set_srs = mat_set.find(self.xml_ns.NsOws("SupportedCRS"))
+        if mat_set_srs is None or not mat_set_srs.text:
             return False
 
-        tile_mats = mat_set.findall(self.xml_ns.NsWmts('TileMatrix'))
+        tile_mats = mat_set.findall(self.xml_ns.NsWmts("TileMatrix"))
         if not tile_mats:
             return False
 
         for t_mat in tile_mats:
             if not self._checkMat(t_mat):
-                grass.debug('Removed invalid <TileMatrix> element.', 4)
+                grass.debug("Removed invalid <TileMatrix> element.", 4)
                 mat_set.remove(t_mat)
 
-        tile_mats = mat_set.findall(self.xml_ns.NsWmts('TileMatrix'))
+        tile_mats = mat_set.findall(self.xml_ns.NsWmts("TileMatrix"))
         if not tile_mats:
             return False
 
         return True
 
     def _checkMat(self, t_mat):
-        """!Check <TileMatrix>.
-        """
+        """!Check <TileMatrix>."""
+
         def _checkElement(t_mat, e, func):
             element = t_mat.find(self.xml_ns.NsWmts(e))
             if element is None or not element.text:
@@ -374,21 +389,23 @@ class WMTSCapabilitiesTree(BaseCapabilitiesTree):
                 return False
             return True
 
-        for e, func in [['ScaleDenominator', float],
-                        ['TileWidth', int],
-                        ['TileHeight', int]]:
+        for e, func in [
+            ["ScaleDenominator", float],
+            ["TileWidth", int],
+            ["TileHeight", int],
+        ]:
             if not _checkElement(t_mat, e, func):
                 return False
 
-        tile_mat_id = t_mat.find(self.xml_ns.NsOws('Identifier'))
+        tile_mat_id = t_mat.find(self.xml_ns.NsOws("Identifier"))
         if tile_mat_id is None or not tile_mat_id.text:
             return False
 
-        tl_str = t_mat.find(self.xml_ns.NsWmts('TopLeftCorner'))
+        tl_str = t_mat.find(self.xml_ns.NsWmts("TopLeftCorner"))
         if tl_str is None or not tl_str.text:
             return False
 
-        tl = tl_str.text.split(' ')
+        tl = tl_str.text.split(" ")
         if len(tl) < 2:
             return False
 
@@ -400,45 +417,43 @@ class WMTSCapabilitiesTree(BaseCapabilitiesTree):
         return True
 
     def _checkLayer(self, layer):
-        """!Check <Layer> element.
-        """
-        layer_id = layer.find(self.xml_ns.NsOws('Identifier'))
+        """!Check <Layer> element."""
+        layer_id = layer.find(self.xml_ns.NsOws("Identifier"))
         if layer_id is None or not layer_id.text:
             return False
 
-        mat_set_links = layer.findall(self.xml_ns.NsWmts('TileMatrixSetLink'))
+        mat_set_links = layer.findall(self.xml_ns.NsWmts("TileMatrixSetLink"))
         if not mat_set_links:
             return False
 
-        styles = layer.findall(self.xml_ns.NsWmts('Style'))
+        styles = layer.findall(self.xml_ns.NsWmts("Style"))
         if not styles:
             return False
 
         for s in styles:
-            s_name = s.find(self.xml_ns.NsOws('Identifier'))
+            s_name = s.find(self.xml_ns.NsOws("Identifier"))
             if s_name is None or not s_name.text:
-                grass.debug('Removed invalid <Style> element.', 4)
+                grass.debug("Removed invalid <Style> element.", 4)
                 layer.remove(s_name)
 
-        contents = self.getroot().find(self.xml_ns.NsWmts('Contents'))
-        mat_sets = contents.findall(self.xml_ns.NsWmts('TileMatrixSet'))
+        contents = self.getroot().find(self.xml_ns.NsWmts("Contents"))
+        mat_sets = contents.findall(self.xml_ns.NsWmts("TileMatrixSet"))
 
         for link in mat_set_links:
             # <TileMatrixSetLink> does not point to existing  <TileMatrixSet>
             if not self._checkMatSetLink(link, mat_sets):
-                grass.debug('Removed invalid <TileMatrixSetLink> element.', 4)
+                grass.debug("Removed invalid <TileMatrixSetLink> element.", 4)
                 layer.remove(link)
 
         return True
 
     def _checkMatSetLink(self, link, mat_sets):
-        """!Check <TileMatrixSetLink> element.
-        """
-        mat_set_link_id = link.find(self.xml_ns.NsWmts('TileMatrixSet')).text
+        """!Check <TileMatrixSetLink> element."""
+        mat_set_link_id = link.find(self.xml_ns.NsWmts("TileMatrixSet")).text
         found = False
 
         for mat_set in mat_sets:
-            mat_set_id = mat_set.find(self.xml_ns.NsOws('Identifier')).text
+            mat_set_id = mat_set.find(self.xml_ns.NsOws("Identifier")).text
 
             if mat_set_id != mat_set_link_id:
                 continue
@@ -446,20 +461,24 @@ class WMTSCapabilitiesTree(BaseCapabilitiesTree):
             # the link points to existing <TileMatrixSet>
             found = True
 
-            tile_mat_set_limits = link.find(self.xml_ns.NsWmts('TileMatrixSetLimits'))
+            tile_mat_set_limits = link.find(self.xml_ns.NsWmts("TileMatrixSetLimits"))
             if tile_mat_set_limits is None:
                 continue
 
-            tile_mat_limits = tile_mat_set_limits.findall(self.xml_ns.NsWmts('TileMatrixLimits'))
+            tile_mat_limits = tile_mat_set_limits.findall(
+                self.xml_ns.NsWmts("TileMatrixLimits")
+            )
             for limit in tile_mat_limits:
                 if not self._checkMatSetLimit(limit):
-                    grass.debug('Removed invalid <TileMatrixLimits> element.', 4)
+                    grass.debug("Removed invalid <TileMatrixLimits> element.", 4)
                     tile_mat_limits.remove(limit)
 
             # are there any <TileMatrixLimits> elements after the check
-            tile_mat_limits = tile_mat_set_limits.findall(self.xml_ns.NsWmts('TileMatrixLimits'))
+            tile_mat_limits = tile_mat_set_limits.findall(
+                self.xml_ns.NsWmts("TileMatrixLimits")
+            )
             if not tile_mat_limits:
-                grass.debug('Removed invalid <TileMatrixSetLimits> element.', 4)
+                grass.debug("Removed invalid <TileMatrixSetLimits> element.", 4)
                 link.remove(tile_mat_set_limits)
 
         if not found:
@@ -468,13 +487,12 @@ class WMTSCapabilitiesTree(BaseCapabilitiesTree):
         return True
 
     def _checkMatSetLimit(self, limit):
-        """!Check <TileMatrixLimits> element.
-        """
-        limit_tile_mat = limit.find(self.xml_ns.NsWmts('TileMatrix'))
+        """!Check <TileMatrixLimits> element."""
+        limit_tile_mat = limit.find(self.xml_ns.NsWmts("TileMatrix"))
         if limit_tile_mat is None or not limit_tile_mat.text:
             return False
 
-        for i in ['MinTileRow', 'MaxTileRow', 'MinTileCol', 'MaxTileCol']:
+        for i in ["MinTileRow", "MaxTileRow", "MinTileCol", "MaxTileCol"]:
             i_tag = limit.find(self.xml_ns.NsWmts(i))
             if i_tag is None:
                 return False
@@ -486,7 +504,7 @@ class WMTSCapabilitiesTree(BaseCapabilitiesTree):
 
     def _find(self, etreeElement, tag, ns=None):
         """!Find child element.
-            If the element is not found it raises xml.etree.ElementTree.ParseError.
+        If the element is not found it raises xml.etree.ElementTree.ParseError.
         """
         if not ns:
             res = etreeElement.find(tag)
@@ -494,14 +512,19 @@ class WMTSCapabilitiesTree(BaseCapabilitiesTree):
             res = etreeElement.find(ns(tag))
 
         if res is None:
-            raise ParseError(_("Unable to parse capabilities file. \n\
-                                Tag '%s' was not found.") % tag)
+            raise ParseError(
+                _(
+                    "Unable to parse capabilities file. \n\
+                                Tag '%s' was not found."
+                )
+                % tag
+            )
 
         return res
 
     def _findall(self, etreeElement, tag, ns=None):
         """!Find all children element.
-            If no element is found it raises xml.etree.ElementTree.ParseError.
+        If no element is found it raises xml.etree.ElementTree.ParseError.
         """
         if not ns:
             res = etreeElement.findall(tag)
@@ -509,19 +532,22 @@ class WMTSCapabilitiesTree(BaseCapabilitiesTree):
             res = etreeElement.findall(ns(tag))
 
         if not res:
-            raise ParseError(_("Unable to parse capabilities file. \n\
-                                Tag '%s' was not found.") % tag)
+            raise ParseError(
+                _(
+                    "Unable to parse capabilities file. \n\
+                                Tag '%s' was not found."
+                )
+                % tag
+            )
 
         return res
 
     def getxmlnshandler(self):
-        """!Return WMTSXMLNsHandler object.
-        """
+        """!Return WMTSXMLNsHandler object."""
         return self.xml_ns
 
 
 class OnEarthCapabilitiesTree(BaseCapabilitiesTree):
-
     def __init__(self, cap_file):
         """!Parse NASA OnEarth tile service file.
             If the file cannot be parsed it raises xml.etree.ElementTree.ParseError.
@@ -533,54 +559,57 @@ class OnEarthCapabilitiesTree(BaseCapabilitiesTree):
         """
         BaseCapabilitiesTree.__init__(self, cap_file)
 
-        grass.debug('Checking OnEarth capabilities tree.', 4)
+        grass.debug("Checking OnEarth capabilities tree.", 4)
 
         self._checkLayerTree(self.getroot())
 
-        grass.debug('Check if OnEarth capabilities tree was finished.', 4)
+        grass.debug("Check if OnEarth capabilities tree was finished.", 4)
 
     def _checkLayerTree(self, parent_layer, first=True):
-        """!Recursively check layer tree.
-        """
+        """!Recursively check layer tree."""
         if first:
-            tiled_patterns = self._find(parent_layer, 'TiledPatterns')
-            layers = tiled_patterns.findall('TiledGroup')
-            layers += tiled_patterns.findall('TiledGroups')
+            tiled_patterns = self._find(parent_layer, "TiledPatterns")
+            layers = tiled_patterns.findall("TiledGroup")
+            layers += tiled_patterns.findall("TiledGroups")
             parent_layer = tiled_patterns
         else:
-            layers = parent_layer.findall('TiledGroup')
-            layers += parent_layer.findall('TiledGroups')
+            layers = parent_layer.findall("TiledGroup")
+            layers += parent_layer.findall("TiledGroups")
 
         for l in layers:
             if not self._checkLayer(l):
-                grass.debug(('Removed invalid <%s> element.' % l.tag), 4)
+                grass.debug(("Removed invalid <%s> element." % l.tag), 4)
                 parent_layer.remove(l)
-            if l.tag == 'TiledGroups':
+            if l.tag == "TiledGroups":
                 self._checkLayerTree(l, False)
 
     def _find(self, etreeElement, tag):
         """!Find child element.
-            If the element is not found it raises xml.etree.ElementTree.ParseError.
+        If the element is not found it raises xml.etree.ElementTree.ParseError.
         """
         res = etreeElement.find(tag)
 
         if res is None:
-            raise  ParseError(_("Unable to parse tile service file. \n\
-                                 Tag <%s> was not found.") % tag)
+            raise ParseError(
+                _(
+                    "Unable to parse tile service file. \n\
+                                 Tag <%s> was not found."
+                )
+                % tag
+            )
 
         return res
 
     def _checkLayer(self, layer):
-        """!Check <TiledGroup>/<TiledGroups> elements.
-        """
-        if layer.tag == 'TiledGroups':
+        """!Check <TiledGroup>/<TiledGroups> elements."""
+        if layer.tag == "TiledGroups":
             return True
 
-        name = layer.find('Name')
+        name = layer.find("Name")
         if name is None or not name.text:
             return False
 
-        t_patts = layer.findall('TilePattern')
+        t_patts = layer.findall("TilePattern")
 
         for patt in t_patts:
             urls = self._getUrls(patt)
@@ -590,46 +619,44 @@ class OnEarthCapabilitiesTree(BaseCapabilitiesTree):
 
             # check if there are any valid urls
             if not urls:
-                grass.debug('<TilePattern>  was removed. It has no valid url.', 4)
+                grass.debug("<TilePattern>  was removed. It has no valid url.", 4)
                 layer.remove(patt)
-            patt.text = '\n'.join(urls)
+            patt.text = "\n".join(urls)
 
-        t_patts = layer.findall('TilePattern')
+        t_patts = layer.findall("TilePattern")
         if not t_patts:
             return False
 
         return True
 
     def _getUrls(self, tile_pattern):
-        """!Get all urls from tile pattern.
-        """
+        """!Get all urls from tile pattern."""
         urls = []
         if tile_pattern.text is not None:
-            tile_patt_lines = tile_pattern.text.split('\n')
+            tile_patt_lines = tile_pattern.text.split("\n")
 
             for line in tile_patt_lines:
-                if 'request=GetMap' in line:
+                if "request=GetMap" in line:
                     urls.append(line.strip())
         return urls
 
     def gettilepatternurldata(self, url):
-        """!Parse url string in Tile Pattern.
-        """
+        """!Parse url string in Tile Pattern."""
         par_url = bbox = width = height = None
 
         bbox_idxs = self.geturlparamidxs(url, "bbox=")
         if bbox_idxs is None:
             return None
 
-        par_url = [url[:bbox_idxs[0] - 1], url[bbox_idxs[1]:]]
+        par_url = [url[: bbox_idxs[0] - 1], url[bbox_idxs[1] :]]
 
-        bbox = url[bbox_idxs[0] + len('bbox='): bbox_idxs[1]]
-        bbox_list = bbox.split(',')
+        bbox = url[bbox_idxs[0] + len("bbox=") : bbox_idxs[1]]
+        bbox_list = bbox.split(",")
         if len(bbox_list) < 4:
             return None
 
         try:
-            bbox = list(map(float, bbox.split(',')))
+            bbox = list(map(float, bbox.split(",")))
         except ValueError:
             return None
 
@@ -638,7 +665,7 @@ class OnEarthCapabilitiesTree(BaseCapabilitiesTree):
             return None
 
         try:
-            width = int(url[width_idxs[0] + len('width='): width_idxs[1]])
+            width = int(url[width_idxs[0] + len("width=") : width_idxs[1]])
         except ValueError:
             return None
 
@@ -647,7 +674,7 @@ class OnEarthCapabilitiesTree(BaseCapabilitiesTree):
             return None
 
         try:
-            height = int(url[height_idxs[0] + len('height='): height_idxs[1]])
+            height = int(url[height_idxs[0] + len("height=") : height_idxs[1]])
         except ValueError:
             return None
 
@@ -657,8 +684,7 @@ class OnEarthCapabilitiesTree(BaseCapabilitiesTree):
         return par_url, bbox, width, height
 
     def geturlparamidxs(self, params_str, param_key):
-        """!Find start and end index of parameter and it's value in url string
-        """
+        """!Find start and end index of parameter and it's value in url string"""
         start_i = params_str.lower().find(param_key)
         if start_i < 0:
             return None

Разница между файлами не показана из-за своего большого размера
+ 474 - 352
scripts/r.in.wms/wms_drv.py


+ 46 - 33
scripts/r.in.wms/wms_gdal_drv.py

@@ -18,28 +18,30 @@ import grass.script as grass
 try:
     from osgeo import gdal
 except:
-    grass.fatal(_("Unable to load GDAL Python bindings (requires package 'python-gdal' being installed)"))
+    grass.fatal(
+        _(
+            "Unable to load GDAL Python bindings (requires package 'python-gdal' being installed)"
+        )
+    )
 
 import xml.etree.ElementTree as etree
 
 from wms_base import WMSBase, GetSRSParamVal
 
 
-class NullDevice():
-
+class NullDevice:
     def write(self, s):
         pass
 
 
 class WMSGdalDrv(WMSBase):
-
     def __init__(self):
         super(WMSGdalDrv, self).__init__()
         self.proxy = None
         self.proxy_user_pw = None
 
     def setProxy(self, proxy, proxy_user_pw=None):
-        """ Set the HTTP proxy and its user and password
+        """Set the HTTP proxy and its user and password
 
         @input proxy HTTP proxy with [IP address]:[port]
         @input proxy_user_pw with [user name]:[password]
@@ -60,45 +62,45 @@ class WMSGdalDrv(WMSBase):
         service.set("name", "WMS")
 
         version = etree.SubElement(service, "Version")
-        version.text = self.params['wms_version']
+        version.text = self.params["wms_version"]
 
         server_url = etree.SubElement(service, "ServerUrl")
-        server_url.text = self.params['url']
+        server_url.text = self.params["url"]
 
-        srs = etree.SubElement(service, self.params['proj_name'])
-        srs.text = GetSRSParamVal(self.params['srs'])
+        srs = etree.SubElement(service, self.params["proj_name"])
+        srs.text = GetSRSParamVal(self.params["srs"])
 
         image_format = etree.SubElement(service, "ImageFormat")
-        image_format.text = self.params['format']
+        image_format.text = self.params["format"]
 
         image_format = etree.SubElement(service, "Transparent")
-        image_format.text = self.params['transparent']
+        image_format.text = self.params["transparent"]
 
         layers = etree.SubElement(service, "Layers")
-        layers.text = self.params['layers']
+        layers.text = self.params["layers"]
 
         styles = etree.SubElement(service, "Styles")
-        styles.text = self.params['styles']
+        styles.text = self.params["styles"]
 
         data_window = etree.SubElement(gdal_wms, "DataWindow")
 
         upper_left_x = etree.SubElement(data_window, "UpperLeftX")
-        upper_left_x.text = str(self.bbox['minx'])
+        upper_left_x.text = str(self.bbox["minx"])
 
         upper_left_y = etree.SubElement(data_window, "UpperLeftY")
-        upper_left_y.text = str(self.bbox['maxy'])
+        upper_left_y.text = str(self.bbox["maxy"])
 
         lower_right_x = etree.SubElement(data_window, "LowerRightX")
-        lower_right_x.text = str(self.bbox['maxx'])
+        lower_right_x.text = str(self.bbox["maxx"])
 
         lower_right_y = etree.SubElement(data_window, "LowerRightY")
-        lower_right_y.text = str(self.bbox['miny'])
+        lower_right_y.text = str(self.bbox["miny"])
 
         size_x = etree.SubElement(data_window, "SizeX")
-        size_x.text = str(self.region['cols'])
+        size_x.text = str(self.region["cols"])
 
         size_y = etree.SubElement(data_window, "SizeY")
-        size_y.text = str(self.region['rows'])
+        size_y.text = str(self.region["rows"])
 
         # RGB + alpha
         self.temp_map_bands_num = 4
@@ -106,14 +108,17 @@ class WMSGdalDrv(WMSBase):
         block_size_x.text = str(self.temp_map_bands_num)
 
         block_size_x = etree.SubElement(gdal_wms, "BlockSizeX")
-        block_size_x.text = str(self.tile_size['cols'])
+        block_size_x.text = str(self.tile_size["cols"])
 
         block_size_y = etree.SubElement(gdal_wms, "BlockSizeY")
-        block_size_y.text = str(self.tile_size['rows'])
+        block_size_y.text = str(self.tile_size["rows"])
 
-        if self.params['username'] and self.params['password']:
+        if self.params["username"] and self.params["password"]:
             user_password = etree.SubElement(gdal_wms, "UserPwd")
-            user_password.text = "%s:%s" % (self.params['username'], self.params['password'])
+            user_password.text = "%s:%s" % (
+                self.params["username"],
+                self.params["password"],
+            )
 
         xml_file = self._tempfile()
 
@@ -132,11 +137,15 @@ class WMSGdalDrv(WMSBase):
 
         # GDAL WMS driver does not flip geographic coordinates
         # according to WMS standard 1.3.0.
-        if ("+proj=latlong" in self.proj_srs or
-                "+proj=longlat" in self.proj_srs) and \
-                self.params['wms_version'] == "1.3.0":
-            grass.warning(_("If module will not be able to fetch the data in this " +
-                            "geographic projection, \n try 'WMS_GRASS' driver or use WMS version 1.1.1."))
+        if (
+            "+proj=latlong" in self.proj_srs or "+proj=longlat" in self.proj_srs
+        ) and self.params["wms_version"] == "1.3.0":
+            grass.warning(
+                _(
+                    "If module will not be able to fetch the data in this "
+                    + "geographic projection, \n try 'WMS_GRASS' driver or use WMS version 1.1.1."
+                )
+            )
 
         self._debug("_download", "started")
         temp_map = self._tempfile()
@@ -149,9 +158,9 @@ class WMSGdalDrv(WMSBase):
         file.close()
 
         if self.proxy:
-            gdal.SetConfigOption('GDAL_HTTP_PROXY', str(self.proxy))
+            gdal.SetConfigOption("GDAL_HTTP_PROXY", str(self.proxy))
         if self.proxy_user_pw:
-            gdal.SetConfigOption('GDAL_HTTP_PROXYUSERPWD', str(self.proxy_user_pw))
+            gdal.SetConfigOption("GDAL_HTTP_PROXYUSERPWD", str(self.proxy_user_pw))
         wms_dataset = gdal.Open(xml_file, gdal.GA_ReadOnly)
         grass.try_remove(xml_file)
         if wms_dataset is None:
@@ -164,9 +173,13 @@ class WMSGdalDrv(WMSBase):
             grass.fatal(_("Unable to find %s driver" % format))
 
         metadata = driver.GetMetadata()
-        if gdal.DCAP_CREATECOPY not in metadata or \
-           metadata[gdal.DCAP_CREATECOPY] == 'NO':
-            grass.fatal(_('Driver %s supports CreateCopy() method.') % self.gdal_drv_name)
+        if (
+            gdal.DCAP_CREATECOPY not in metadata
+            or metadata[gdal.DCAP_CREATECOPY] == "NO"
+        ):
+            grass.fatal(
+                _("Driver %s supports CreateCopy() method.") % self.gdal_drv_name
+            )
 
         self._debug("_download", "calling GDAL CreateCopy...")
 

+ 11 - 11
scripts/r.mapcalc.simple/r.mapcalc.simple.py

@@ -102,23 +102,23 @@ def name_quote(name):
 
 def main():
     options, flags = gs.parser()
-    expr = options['expression']
+    expr = options["expression"]
     if not expr:
         gs.fatal(_("The expression is an empty string"))
-    output = options['output']
-    quote = flags['q']
+    output = options["output"]
+    quote = flags["q"]
     re_flags = 0
-    if flags['c']:
+    if flags["c"]:
         re_flags = re.IGNORECASE
 
     if quote:
         output = name_quote(output)
 
     seed = None
-    if options['seed']:
-        seed = options['seed']
-    elif flags['s']:
-        seed = 'auto'
+    if options["seed"]:
+        seed = options["seed"]
+    elif flags["s"]:
+        seed = "auto"
 
     variables = []
     for key in "ABCDEF":
@@ -129,15 +129,15 @@ def main():
             variables.append((key, name))
 
     for key, name in variables:
-        find = r'([^a-zA-Z0-9]|^){key}([^a-zA-Z0-9]|$)'.format(key=key)
-        replace = r'\1{}\2'.format(name)
+        find = r"([^a-zA-Z0-9]|^){key}([^a-zA-Z0-9]|$)".format(key=key)
+        replace = r"\1{}\2".format(name)
         # we need to do the substitution twice because we are matching
         # also the char before and after which fails when there is only
         # one char between the two usages of the same var (e.g. A*A)
         expr = re.sub(find, replace, expr, flags=re_flags)
         expr = re.sub(find, replace, expr, flags=re_flags)
 
-    expr = '{lhs} = {rhs}'.format(lhs=output, rhs=expr)
+    expr = "{lhs} = {rhs}".format(lhs=output, rhs=expr)
     gs.verbose(_("Expression: {}").format(expr))
     gs.mapcalc(expr, seed=seed)
     # g.message -e "Calculating $GIS_OPT_OUTFILE. Try expert mode."

+ 21 - 17
scripts/r.mapcalc.simple/testsuite/test_rmapcalcsimple.py

@@ -10,40 +10,44 @@ Licence:    This program is free software under the GNU General Public
 """
 from grass.gunittest.case import TestCase
 
-class TestReport(TestCase):
 
+class TestReport(TestCase):
     @classmethod
     def setUpClass(cls):
         """Use temporary region settings"""
-        map_input = 'elevation'
+        map_input = "elevation"
         cls.runModule("g.region", raster=map_input)
         cls.use_temp_region()
 
     @classmethod
     def tearDownClass(cls):
-        map_output1 = 'test1'
-        map_output2 = 'test2'
-        cls.runModule("g.remove", flags='f', type='raster', name=map_output1)
-        cls.runModule("g.remove", flags='f', type='raster', name=map_output2)
+        map_output1 = "test1"
+        map_output2 = "test2"
+        cls.runModule("g.remove", flags="f", type="raster", name=map_output1)
+        cls.runModule("g.remove", flags="f", type="raster", name=map_output2)
         cls.del_temp_region()
 
     def test_rmapcalcsimple(self):
         """Testing r.mapcalc.simple"""
-        map_input = 'elevation'
-        map_output1 = 'test1'
-        map_output2 = 'test2'
+        map_input = "elevation"
+        map_output1 = "test1"
+        map_output2 = "test2"
 
         # test 1
-        self.assertModule('r.mapcalc.simple', expression='0', output=map_output1)
-        self.assertRasterMinMax(map=map_output1, refmin=0, refmax=0,
-                                msg="Result must be 0 for all pixels")
+        self.assertModule("r.mapcalc.simple", expression="0", output=map_output1)
+        self.assertRasterMinMax(
+            map=map_output1, refmin=0, refmax=0, msg="Result must be 0 for all pixels"
+        )
 
         # test 2
-        formula='if(%s > 2000, 1, 0)' % map_input # expected to be 0
-        self.assertModule('r.mapcalc.simple', expression=formula, output=map_output2)
-        self.assertRasterMinMax(map=map_output2, refmin=0, refmax=0,
-                                msg="Result must be 0 for all pixels")
+        formula = "if(%s > 2000, 1, 0)" % map_input  # expected to be 0
+        self.assertModule("r.mapcalc.simple", expression=formula, output=map_output2)
+        self.assertRasterMinMax(
+            map=map_output2, refmin=0, refmax=0, msg="Result must be 0 for all pixels"
+        )
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     from grass.gunittest.main import test
+
     test()

+ 85 - 49
scripts/r.mask/r.mask.py

@@ -79,38 +79,40 @@ from grass.exceptions import CalledModuleError
 
 def cleanup():
     if tmp:
-        grass.run_command('g.remove', flags='f', type='raster',
-                          name=tmp, quiet=True)
+        grass.run_command("g.remove", flags="f", type="raster", name=tmp, quiet=True)
     if tmp_hull:
-        grass.run_command('g.remove', flags='f', type='vector',
-                          name=tmp_hull, quiet=True)
+        grass.run_command(
+            "g.remove", flags="f", type="vector", name=tmp_hull, quiet=True
+        )
 
 
 def main():
-    raster = options['raster']
-    maskcats = options['maskcats']
-    vector = options['vector']
-    layer = options['layer']
-    cats = options['cats']
-    where = options['where']
-    remove = flags['r']
-    invert = flags['i']
+    raster = options["raster"]
+    maskcats = options["maskcats"]
+    vector = options["vector"]
+    layer = options["layer"]
+    cats = options["cats"]
+    where = options["where"]
+    remove = flags["r"]
+    invert = flags["i"]
 
     if not remove and not raster and not vector:
         grass.fatal(_("Either parameter <raster> or parameter <vector> is required"))
 
-    mapset = grass.gisenv()['MAPSET']
-    exists = bool(grass.find_file('MASK', element='cell', mapset=mapset)['file'])
+    mapset = grass.gisenv()["MAPSET"]
+    exists = bool(grass.find_file("MASK", element="cell", mapset=mapset)["file"])
 
     if remove:
         # -> remove
         if exists:
-            if sys.platform == 'win32':
-                grass.run_command('g.remove', flags='if', quiet=True,
-                                  type='raster', name='MASK')
+            if sys.platform == "win32":
+                grass.run_command(
+                    "g.remove", flags="if", quiet=True, type="raster", name="MASK"
+                )
             else:
-                grass.run_command('g.remove', flags='f', quiet=True,
-                                  type='raster', name='MASK')
+                grass.run_command(
+                    "g.remove", flags="f", quiet=True, type="raster", name="MASK"
+                )
             grass.message(_("Raster MASK removed"))
         else:
             grass.fatal(_("No existing MASK to remove"))
@@ -118,34 +120,41 @@ def main():
         # -> create
         if exists:
             if not grass.overwrite():
-                grass.fatal(_("MASK already found in current mapset. Delete first or overwrite."))
+                grass.fatal(
+                    _(
+                        "MASK already found in current mapset. Delete first or overwrite."
+                    )
+                )
             else:
                 grass.warning(_("MASK already exists and will be overwritten"))
-                grass.run_command('g.remove', flags='f', quiet=True,
-                                  type='raster', name='MASK')
+                grass.run_command(
+                    "g.remove", flags="f", quiet=True, type="raster", name="MASK"
+                )
 
         if raster:
             # check if input raster exists
-            if not grass.find_file(raster)['file']:
+            if not grass.find_file(raster)["file"]:
                 grass.fatal(_("Raster map <%s> not found") % raster)
 
-            if maskcats != '*' and not remove:
-                if grass.raster_info(raster)['datatype'] != "CELL":
-                    grass.fatal(_("The raster map <%s> must be integer (CELL type) "
-                                  " in order to use the 'maskcats' parameter") % raster)
+            if maskcats != "*" and not remove:
+                if grass.raster_info(raster)["datatype"] != "CELL":
+                    grass.fatal(
+                        _(
+                            "The raster map <%s> must be integer (CELL type) "
+                            " in order to use the 'maskcats' parameter"
+                        )
+                        % raster
+                    )
 
             p = grass.feed_command(
-                'r.reclass',
-                input=raster,
-                output='MASK',
-                overwrite=True,
-                rules='-')
+                "r.reclass", input=raster, output="MASK", overwrite=True, rules="-"
+            )
             res = "%s = 1" % maskcats
             p.stdin.write(encode(res))
             p.stdin.close()
             p.wait()
         elif vector:
-            vector_name = grass.find_file(vector, 'vector')['fullname']
+            vector_name = grass.find_file(vector, "vector")["fullname"]
             if not vector_name:
                 grass.fatal(_("Vector map <%s> not found") % vector)
 
@@ -155,44 +164,71 @@ def main():
             if len(where) == 0:
                 where = None
 
-            if grass.vector_info_topo(vector_name)['areas'] < 1:
-                grass.warning(_("No area found in vector map <%s>. "
-                                "Creating a convex hull for MASK.") % vector_name)
+            if grass.vector_info_topo(vector_name)["areas"] < 1:
+                grass.warning(
+                    _(
+                        "No area found in vector map <%s>. "
+                        "Creating a convex hull for MASK."
+                    )
+                    % vector_name
+                )
                 global tmp_hull
                 tmp_hull = "tmp_hull_%d" % os.getpid()
                 to_rast_input = tmp_hull
                 # force 'flat' convex hull for 3D vector maps
                 try:
-                    grass.run_command('v.hull', flags='f', quiet=True,
-                                      input=vector_name, output=tmp_hull,
-                                      layer=layer, cats=cats, where=where)
+                    grass.run_command(
+                        "v.hull",
+                        flags="f",
+                        quiet=True,
+                        input=vector_name,
+                        output=tmp_hull,
+                        layer=layer,
+                        cats=cats,
+                        where=where,
+                    )
                 except CalledModuleError:
                     grass.fatal(
-                        _("Unable to create a convex hull for vector map <%s>") %
-                        vector_name)
+                        _("Unable to create a convex hull for vector map <%s>")
+                        % vector_name
+                    )
             else:
                 to_rast_input = vector_name
 
             env = os.environ.copy()
             if grass.verbosity() > 1:
-                env['GRASS_VERBOSE'] = '1'
-            grass.run_command('v.to.rast', input=to_rast_input, layer=layer,
-                              output='MASK', use='val', val='1',
-                              type='area', cats=cats, where=where, env=env)
+                env["GRASS_VERBOSE"] = "1"
+            grass.run_command(
+                "v.to.rast",
+                input=to_rast_input,
+                layer=layer,
+                output="MASK",
+                use="val",
+                val="1",
+                type="area",
+                cats=cats,
+                where=where,
+                env=env,
+            )
 
         if invert:
             global tmp
             tmp = "r_mask_%d" % os.getpid()
-            grass.run_command('g.rename', raster=('MASK', tmp), quiet=True)
+            grass.run_command("g.rename", raster=("MASK", tmp), quiet=True)
             grass.message(_("Creating inverted raster MASK..."))
             grass.mapcalc("MASK = if(isnull($tmp), 1, null())", tmp=tmp)
             grass.verbose(_("Inverted raster MASK created"))
         else:
             grass.verbose(_("Raster MASK created"))
 
-        grass.message(_("All subsequent raster operations will be limited to "
-                        "the MASK area. Removing or renaming raster map named "
-                        "'MASK' will restore raster operations to normal."))
+        grass.message(
+            _(
+                "All subsequent raster operations will be limited to "
+                "the MASK area. Removing or renaming raster map named "
+                "'MASK' will restore raster operations to normal."
+            )
+        )
+
 
 if __name__ == "__main__":
     options, flags = grass.parser()

+ 11 - 10
scripts/r.mask/testsuite/test_r_mask.py

@@ -12,31 +12,32 @@ from grass.gunittest.gmodules import SimpleModule
 class TestRMask(TestCase):
     """Test r.mask script"""
 
-    mapName = 'lakes'
-    mapNameOther = 'elevation'
-    values = 'min=56.8785\nmax=134.87'
+    mapName = "lakes"
+    mapNameOther = "elevation"
+    values = "min=56.8785\nmax=134.87"
 
     @classmethod
     def setUpClass(cls):
         """Create maps in a small region."""
         cls.use_temp_region()
-        cls.runModule('g.region', raster=cls.mapName, flags='p')
+        cls.runModule("g.region", raster=cls.mapName, flags="p")
 
     @classmethod
     def tearDownClass(cls):
         """Remove temporary region. Remove mask"""
         cls.del_temp_region()
 
-        cls.runModule('r.mask', flags='r')
+        cls.runModule("r.mask", flags="r")
 
     def test_mask(self):
         """Mask test"""
-        module = SimpleModule('r.mask', raster=self.mapName)
+        module = SimpleModule("r.mask", raster=self.mapName)
         self.assertModule(module)
 
-        self.assertRasterFitsUnivar(raster=self.mapNameOther,
-                                    reference=self.values,
-                                    precision=5)
+        self.assertRasterFitsUnivar(
+            raster=self.mapNameOther, reference=self.values, precision=5
+        )
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 8 - 7
scripts/r.out.xyz/r.out.xyz.py

@@ -45,16 +45,16 @@ from grass.exceptions import CalledModuleError
 
 def main():
     # if no output filename, output to stdout
-    output = options['output']
-    donodata = flags['i']
+    output = options["output"]
+    donodata = flags["i"]
 
     if donodata:
-        statsflags="1g"
+        statsflags = "1g"
     else:
-        statsflags="1gn"
-    parameters = dict(flags=statsflags,
-                      input=options['input'],
-                      separator=options['separator'])
+        statsflags = "1gn"
+    parameters = dict(
+        flags=statsflags, input=options["input"], separator=options["separator"]
+    )
     if output:
         parameters.update(output=output)
 
@@ -65,6 +65,7 @@ def main():
         ret = 1
     sys.exit(ret)
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     main()

+ 9 - 7
scripts/r.out.xyz/testsuite/test_r_out_xyz.py

@@ -14,30 +14,32 @@ import os
 class TestROutXyz(TestCase):
     """Test r.out.xyz script"""
 
-    mapName = 'elev_lid792_1m'
-    csvFile = 'elev_lid792_1m.csv'
+    mapName = "elev_lid792_1m"
+    csvFile = "elev_lid792_1m.csv"
 
     @classmethod
     def setUpClass(cls):
         """Create maps in a small region."""
         cls.use_temp_region()
-        cls.runModule('g.region', raster=cls.mapName, flags='p')
+        cls.runModule("g.region", raster=cls.mapName, flags="p")
 
     @classmethod
     def tearDownClass(cls):
         """Remove temporary region"""
         cls.del_temp_region()
 
-        if (os.path.isfile(cls.csvFile)):
+        if os.path.isfile(cls.csvFile):
             os.remove(cls.csvFile)
 
     def test_r_out_xyz(self):
         """ASCII text file test"""
-        module = SimpleModule('r.out.xyz', input=self.mapName,
-                              output=self.csvFile, separator=",")
+        module = SimpleModule(
+            "r.out.xyz", input=self.mapName, output=self.csvFile, separator=","
+        )
         self.assertModule(module)
 
         self.assertFileExists(filename=self.csvFile)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 52 - 39
scripts/r.pack/r.pack.py

@@ -7,9 +7,9 @@
 # PURPOSE:	Pack up a raster map, collect raster map elements => gzip
 # COPYRIGHT:	(C) 2004-2013 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.
+# 		This program is free software under the GNU General
+# 		Public License (>=v2). Read the file COPYING that
+# 		comes with GRASS for details.
 #
 #############################################################################
 
@@ -46,14 +46,14 @@ def cleanup():
 
 
 def main():
-    infile = options['input']
-    compression_off = flags['c']
+    infile = options["input"]
+    compression_off = flags["c"]
     mapset = None
-    if '@' in infile:
-        infile, mapset = infile.split('@')
+    if "@" in infile:
+        infile, mapset = infile.split("@")
 
-    if options['output']:
-        outfile_path, outfile_base = os.path.split(os.path.abspath(options['output']))
+    if options["output"]:
+        outfile_path, outfile_base = os.path.split(os.path.abspath(options["output"]))
     else:
         outfile_path, outfile_base = os.path.split(os.path.abspath(infile + ".pack"))
 
@@ -63,57 +63,67 @@ def main():
     tmp = grass.tempdir()
     tmp_dir = os.path.join(tmp, infile)
     os.mkdir(tmp_dir)
-    grass.debug('tmp_dir = %s' % tmp_dir)
+    grass.debug("tmp_dir = %s" % tmp_dir)
 
-    gfile = grass.find_file(name=infile, element='cell', mapset=mapset)
-    if not gfile['name']:
+    gfile = grass.find_file(name=infile, element="cell", mapset=mapset)
+    if not gfile["name"]:
         grass.fatal(_("Raster map <%s> not found") % infile)
 
     if os.path.exists(outfile):
-        if os.getenv('GRASS_OVERWRITE'):
-            grass.warning(_("Pack file <%s> already exists and will be overwritten") % outfile)
+        if os.getenv("GRASS_OVERWRITE"):
+            grass.warning(
+                _("Pack file <%s> already exists and will be overwritten") % outfile
+            )
             try_remove(outfile)
         else:
             grass.fatal(_("option <output>: <%s> exists.") % outfile)
 
-    grass.message(_("Packing <%s> to <%s>...") % (gfile['fullname'], outfile))
-    basedir = os.path.sep.join(os.path.normpath(gfile['file']).split(os.path.sep)[:-2])
+    grass.message(_("Packing <%s> to <%s>...") % (gfile["fullname"], outfile))
+    basedir = os.path.sep.join(os.path.normpath(gfile["file"]).split(os.path.sep)[:-2])
     olddir = os.getcwd()
 
     # copy elements
-    info = grass.parse_command('r.info', flags='e', map=infile)
+    info = grass.parse_command("r.info", flags="e", map=infile)
     vrt_files = {}
-    if info['maptype'] == 'virtual':
+    if info["maptype"] == "virtual":
         map_file = grass.find_file(
-            name=infile, element='cell_misc',
+            name=infile,
+            element="cell_misc",
         )
-        if map_file['file']:
-            vrt = os.path.join(map_file['file'], 'vrt')
+        if map_file["file"]:
+            vrt = os.path.join(map_file["file"], "vrt")
             if os.path.exists(vrt):
-                with open(vrt, 'r') as f:
+                with open(vrt, "r") as f:
                     for r in f.readlines():
-                        map, mapset = r.split('@')
+                        map, mapset = r.split("@")
                         map_basedir = os.path.sep.join(
-                            os.path.normpath(
-                                map_file['file'],
-                            ).split(os.path.sep)[:-2],
+                            os.path.normpath(map_file["file"],).split(
+                                os.path.sep
+                            )[:-2],
                         )
                         vrt_files[map] = map_basedir
 
     for element in [
-            'cats', 'cell', 'cellhd', 'cell_misc', 'colr', 'fcell',
-            'hist',
+        "cats",
+        "cell",
+        "cellhd",
+        "cell_misc",
+        "colr",
+        "fcell",
+        "hist",
     ]:
         path = os.path.join(basedir, element, infile)
         if os.path.exists(path):
-            grass.debug('copying %s' % path)
+            grass.debug("copying %s" % path)
             if os.path.isfile(path):
                 shutil.copyfile(
-                    path, os.path.join(tmp_dir, element),
+                    path,
+                    os.path.join(tmp_dir, element),
                 )
             else:
                 shutil.copytree(
-                    path, os.path.join(tmp_dir, element),
+                    path,
+                    os.path.join(tmp_dir, element),
                 )
 
         # Copy vrt files
@@ -127,11 +137,13 @@ def main():
                     grass.debug("copying vrt file {}".format(path))
                     if os.path.isfile(path):
                         shutil.copyfile(
-                            path, os.path.join(f_tmp_dir, element),
+                            path,
+                            os.path.join(f_tmp_dir, element),
                         )
                     else:
                         shutil.copytree(
-                            path, os.path.join(f_tmp_dir, element),
+                            path,
+                            os.path.join(f_tmp_dir, element),
                         )
 
     if not os.listdir(tmp_dir):
@@ -140,18 +152,19 @@ def main():
     # copy projection info
     # (would prefer to use g.proj*, but this way is 5.3 and 5.7 compat)
     gisenv = grass.gisenv()
-    for support in ['INFO', 'UNITS', 'EPSG']:
-        path = os.path.join(gisenv['GISDBASE'], gisenv['LOCATION_NAME'],
-                            'PERMANENT', 'PROJ_' + support)
+    for support in ["INFO", "UNITS", "EPSG"]:
+        path = os.path.join(
+            gisenv["GISDBASE"], gisenv["LOCATION_NAME"], "PERMANENT", "PROJ_" + support
+        )
         if os.path.exists(path):
-            shutil.copyfile(path, os.path.join(tmp_dir, 'PROJ_' + support))
+            shutil.copyfile(path, os.path.join(tmp_dir, "PROJ_" + support))
 
     # pack it all up
     os.chdir(tmp)
     if compression_off:
-        tar = tarfile.TarFile.open(name=outfile_base, mode='w:')
+        tar = tarfile.TarFile.open(name=outfile_base, mode="w:")
     else:
-        tar = tarfile.TarFile.open(name=outfile_base, mode='w:gz')
+        tar = tarfile.TarFile.open(name=outfile_base, mode="w:gz")
     tar.add(infile, recursive=True)
     if vrt_files:
         for f in vrt_files.keys():

+ 7 - 7
scripts/r.pack/testsuite/test_r_pack.py

@@ -14,30 +14,30 @@ import os
 class TestRPack(TestCase):
     """Test r.pack script"""
 
-    mapName = 'aspect'
-    outFile = 'aspect.pack'
+    mapName = "aspect"
+    outFile = "aspect.pack"
 
     @classmethod
     def setUpClass(cls):
         """Create maps in a small region."""
         cls.use_temp_region()
-        cls.runModule('g.region', raster=cls.mapName, flags='p')
+        cls.runModule("g.region", raster=cls.mapName, flags="p")
 
     @classmethod
     def tearDownClass(cls):
         """Remove temporary region. Delete output file"""
         cls.del_temp_region()
 
-        if (os.path.isfile(cls.outFile)):
+        if os.path.isfile(cls.outFile):
             os.remove(cls.outFile)
 
     def test_r_pack(self):
         """Create a pack file test"""
-        module = SimpleModule('r.pack', input=self.mapName,
-                              output=self.outFile)
+        module = SimpleModule("r.pack", input=self.mapName, output=self.outFile)
         self.assertModule(module)
 
         self.assertFileExists(filename=self.outFile)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 29 - 20
scripts/r.plane/r.plane.py

@@ -11,9 +11,9 @@
 # PURPOSE:	Creates a raster plane map from user specified inclination and azimuth
 # COPYRIGHT:	(C) 2004-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.
+# 		This program is free software under the GNU General Public
+# 		License (>=v2). Read the file COPYING that comes with GRASS
+# 		for details.
 #
 #############################################################################
 
@@ -69,20 +69,20 @@ import grass.script as gscript
 
 
 def main():
-    name = options['output']
-    type = options['type']
-    dip = float(options['dip'])
-    az = float(options['azimuth'])
+    name = options["output"]
+    type = options["type"]
+    dip = float(options["dip"])
+    az = float(options["azimuth"])
     try:
-        ea = float(options['easting'])
-        no = float(options['northing'])
+        ea = float(options["easting"])
+        no = float(options["northing"])
     except ValueError:
         try:
-            ea = float(gscript.utils.float_or_dms(options['easting']))
-            no = float(gscript.utils.float_or_dms(options['northing']))
+            ea = float(gscript.utils.float_or_dms(options["easting"]))
+            no = float(gscript.utils.float_or_dms(options["northing"]))
         except:
             gscript.fatal(_("Input coordinates seems to be invalid"))
-    el = float(options['elevation'])
+    el = float(options["elevation"])
 
     # reg = gscript.region()
 
@@ -115,18 +115,27 @@ def main():
         round = ""
         dtype = "double"
 
-    gscript.mapcalc("$name = $type($round(x() * $kx + y() * $ky + $kz))",
-                    name=name, type=dtype, round=round, kx=kx, ky=ky, kz=kz)
+    gscript.mapcalc(
+        "$name = $type($round(x() * $kx + y() * $ky + $kz))",
+        name=name,
+        type=dtype,
+        round=round,
+        kx=kx,
+        ky=ky,
+        kz=kz,
+    )
 
-    gscript.run_command('r.support', map=name, history='')
+    gscript.run_command("r.support", map=name, history="")
     gscript.raster_history(name)
 
     gscript.message(_("Done."))
-    t = string.Template("Raster map <$name> generated by r.plane "
-                        "at point $ea E, $no N, elevation $el with dip = $dip"
-                        " degrees and aspect = $az degrees ccw from north.")
-    gscript.message(t.substitute(name=name, ea=ea, no=no, el=el, dip=dip,
-                                 az=az))
+    t = string.Template(
+        "Raster map <$name> generated by r.plane "
+        "at point $ea E, $no N, elevation $el with dip = $dip"
+        " degrees and aspect = $az degrees ccw from north."
+    )
+    gscript.message(t.substitute(name=name, ea=ea, no=no, el=el, dip=dip, az=az))
+
 
 if __name__ == "__main__":
     options, flags = gscript.parser()

+ 15 - 9
scripts/r.plane/testsuite/test_r_plane.py

@@ -12,30 +12,36 @@ from grass.gunittest.gmodules import SimpleModule
 class TestRPlane(TestCase):
     """Test r.plane script"""
 
-    mapName = 'elevation'
-    mapOutput = 'myplane45'
+    mapName = "elevation"
+    mapOutput = "myplane45"
 
     @classmethod
     def setUpClass(cls):
         """Create maps in a small region."""
         cls.use_temp_region()
-        cls.runModule('g.region', raster=cls.mapName, flags='p')
+        cls.runModule("g.region", raster=cls.mapName, flags="p")
 
     @classmethod
     def tearDownClass(cls):
         """Remove temporary region"""
-        cls.runModule('g.remove', flags='f', type='raster',
-                      name=cls.mapOutput)
+        cls.runModule("g.remove", flags="f", type="raster", name=cls.mapOutput)
         cls.del_temp_region()
 
     def test_creates_raster_plane_map(self):
         """Create a tilted plane raster map test"""
-        module = SimpleModule('r.plane', output=self.mapOutput, dip=45,
-                              easting=527500.0, northing=165000.0,
-                              elevation=1000, type='FCELL')
+        module = SimpleModule(
+            "r.plane",
+            output=self.mapOutput,
+            dip=45,
+            easting=527500.0,
+            northing=165000.0,
+            elevation=1000,
+            type="FCELL",
+        )
         self.assertModule(module)
 
         self.assertRasterExists(self.mapOutput)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 76 - 59
scripts/r.reclass.area/r.reclass.area.py

@@ -89,15 +89,15 @@ def reclass(inf, outf, lim, clump, diag, les):
     clumped = clump
     diagonal = diag
 
-    s = grass.read_command("g.region", flags='p')
+    s = grass.read_command("g.region", flags="p")
     s = decode(s)
-    kv = grass.parse_key_val(s, sep=':')
-    s = kv['projection'].strip().split()
-    if s == '0':
+    kv = grass.parse_key_val(s, sep=":")
+    s = kv["projection"].strip().split()
+    if s == "0":
         grass.fatal(_("xy-locations are not supported"))
         grass.fatal(_("Need projected data with grids in meters"))
 
-    if not grass.find_file(infile)['name']:
+    if not grass.find_file(infile)["name"]:
         grass.fatal(_("Raster map <%s> not found") % infile)
 
     if clumped and diagonal:
@@ -106,41 +106,49 @@ def reclass(inf, outf, lim, clump, diag, les):
     if clumped:
         clumpfile = infile
     else:
-        clumpfile = "%s.clump.%s" % (infile.split('@')[0], outfile)
+        clumpfile = "%s.clump.%s" % (infile.split("@")[0], outfile)
         TMPRAST.append(clumpfile)
 
         if not grass.overwrite():
-            if grass.find_file(clumpfile)['name']:
+            if grass.find_file(clumpfile)["name"]:
                 grass.fatal(_("Temporary raster map <%s> exists") % clumpfile)
         if diagonal:
-            grass.message(_("Generating a clumped raster file including "
-                            "diagonal neighbors..."))
-            grass.run_command('r.clump', flags='d', input=infile,
-                              output=clumpfile)
+            grass.message(
+                _("Generating a clumped raster file including " "diagonal neighbors...")
+            )
+            grass.run_command("r.clump", flags="d", input=infile, output=clumpfile)
         else:
             grass.message(_("Generating a clumped raster file ..."))
-            grass.run_command('r.clump', input=infile, output=clumpfile)
+            grass.run_command("r.clump", input=infile, output=clumpfile)
 
     if lesser:
-        grass.message(_("Generating a reclass map with area size less than "
-                        "or equal to %f hectares...") % limit)
+        grass.message(
+            _(
+                "Generating a reclass map with area size less than "
+                "or equal to %f hectares..."
+            )
+            % limit
+        )
     else:
-        grass.message(_("Generating a reclass map with area size greater "
-                        "than or equal to %f hectares...") % limit)
-
-    recfile = outfile + '.recl'
+        grass.message(
+            _(
+                "Generating a reclass map with area size greater "
+                "than or equal to %f hectares..."
+            )
+            % limit
+        )
+
+    recfile = outfile + ".recl"
     TMPRAST.append(recfile)
 
-    sflags = 'aln'
-    if grass.raster_info(infile)['datatype'] in ('FCELL', 'DCELL'):
-        sflags += 'i'
-    p1 = grass.pipe_command('r.stats', flags=sflags, input=(clumpfile, infile),
-                            sep=';')
-    p2 = grass.feed_command('r.reclass', input=clumpfile, output=recfile,
-                            rules='-')
-    rules = ''
+    sflags = "aln"
+    if grass.raster_info(infile)["datatype"] in ("FCELL", "DCELL"):
+        sflags += "i"
+    p1 = grass.pipe_command("r.stats", flags=sflags, input=(clumpfile, infile), sep=";")
+    p2 = grass.feed_command("r.reclass", input=clumpfile, output=recfile, rules="-")
+    rules = ""
     for line in p1.stdout:
-        f = decode(line).rstrip(os.linesep).split(';')
+        f = decode(line).rstrip(os.linesep).split(";")
         if len(f) < 5:
             continue
         hectares = float(f[4]) * 0.0001
@@ -157,11 +165,15 @@ def reclass(inf, outf, lim, clump, diag, les):
     p2.wait()
     if p2.returncode != 0:
         if lesser:
-            grass.fatal(_("No areas of size less than or equal to %f "
-                          "hectares found.") % limit)
+            grass.fatal(
+                _("No areas of size less than or equal to %f " "hectares found.")
+                % limit
+            )
         else:
-            grass.fatal(_("No areas of size greater than or equal to %f "
-                          "hectares found.") % limit)
+            grass.fatal(
+                _("No areas of size greater than or equal to %f " "hectares found.")
+                % limit
+            )
     grass.mapcalc("$outfile = $recfile", outfile=outfile, recfile=recfile)
 
 
@@ -173,47 +185,49 @@ def rmarea(infile, outfile, thresh, coef):
     # transform user input from hectares to meters because currently v.clean
     # rmarea accept only meters as threshold
     thresh = thresh * 10000.0
-    vectfile = "%s_vect_%s" % (infile.split('@')[0], outfile)
+    vectfile = "%s_vect_%s" % (infile.split("@")[0], outfile)
     TMPRAST.append(vectfile)
-    grass.run_command('r.to.vect', input=infile, output=vectfile, type='area')
-    cleanfile = "%s_clean_%s" % (infile.split('@')[0], outfile)
+    grass.run_command("r.to.vect", input=infile, output=vectfile, type="area")
+    cleanfile = "%s_clean_%s" % (infile.split("@")[0], outfile)
     TMPRAST.append(cleanfile)
-    grass.run_command('v.clean', input=vectfile, output=cleanfile,
-                      tool='rmarea', threshold=thresh)
+    grass.run_command(
+        "v.clean", input=vectfile, output=cleanfile, tool="rmarea", threshold=thresh
+    )
 
-    grass.run_command('v.to.rast', input=cleanfile, output=outfile,
-                      use='attr', attrcolumn='value')
+    grass.run_command(
+        "v.to.rast", input=cleanfile, output=outfile, use="attr", attrcolumn="value"
+    )
 
 
 def main():
-    infile = options['input']
-    value = options['value']
-    mode = options['mode']
-    outfile = options['output']
+    infile = options["input"]
+    value = options["value"]
+    mode = options["mode"]
+    outfile = options["output"]
     global method
-    method = options['method']
-    clumped = flags['c']
-    diagonal = flags['d']
+    method = options["method"]
+    clumped = flags["c"]
+    diagonal = flags["d"]
 
     # check for unsupported locations
-    in_proj = grass.parse_command('g.proj', flags='g')
-    if in_proj['unit'].lower() == 'degree':
+    in_proj = grass.parse_command("g.proj", flags="g")
+    if in_proj["unit"].lower() == "degree":
         grass.fatal(_("Latitude-longitude locations are not supported"))
-    if in_proj['name'].lower() == 'xy_location_unprojected':
+    if in_proj["name"].lower() == "xy_location_unprojected":
         grass.fatal(_("xy-locations are not supported"))
 
     # check lesser and greater parameters
     limit = float(value)
-    if mode == 'greater' and method == 'rmarea':
+    if mode == "greater" and method == "rmarea":
         grass.fatal(_("You have to specify mode='lesser' with method='rmarea'"))
 
-    if not grass.find_file(infile)['name']:
+    if not grass.find_file(infile)["name"]:
         grass.fatal(_("Raster map <%s> not found") % infile)
 
-    if method == 'reclass':
-        reclass(infile, outfile, limit, clumped, diagonal, mode == 'lesser')
-    elif method == 'rmarea':
-        rmarea(infile, outfile, limit, in_proj['meters'])
+    if method == "reclass":
+        reclass(infile, outfile, limit, clumped, diagonal, mode == "lesser")
+    elif method == "rmarea":
+        rmarea(infile, outfile, limit, in_proj["meters"])
 
     grass.message(_("Generating output raster map <%s>...") % outfile)
 
@@ -222,12 +236,15 @@ def cleanup():
     """!Delete temporary maps"""
     TMPRAST.reverse()  # reclassed map first
     for mapp in TMPRAST:
-        if method == 'rmarea':
-            grass.run_command("g.remove", flags='f', type='vector', name=mapp,
-                              quiet=True)
+        if method == "rmarea":
+            grass.run_command(
+                "g.remove", flags="f", type="vector", name=mapp, quiet=True
+            )
         else:
-            grass.run_command("g.remove", flags='f', type='raster', name=mapp,
-                              quiet=True)
+            grass.run_command(
+                "g.remove", flags="f", type="raster", name=mapp, quiet=True
+            )
+
 
 if __name__ == "__main__":
     options, flags = grass.parser()

+ 36 - 15
scripts/r.reclass.area/testsuite/test_r_reclass_area.py

@@ -14,34 +14,55 @@ from grass.gunittest.main import test
 
 
 class TestReclassArea(TestCase):
-    input = 'geology_30m'
-    output = 'reclassarea'
-    value = '20'
+    input = "geology_30m"
+    output = "reclassarea"
+    value = "20"
 
     @classmethod
     def setUpClass(cls):
         cls.use_temp_region()
-        cls.runModule('g.region', raster=cls.input)
+        cls.runModule("g.region", raster=cls.input)
 
     @classmethod
     def tearDownClass(cls):
         cls.del_temp_region()
-        cls.runModule('g.remove', type='raster', flags='f', name=cls.output + 'Greater')
-        cls.runModule('g.remove', type='raster', flags='f', name=cls.output + 'Lesser')
+        cls.runModule("g.remove", type="raster", flags="f", name=cls.output + "Greater")
+        cls.runModule("g.remove", type="raster", flags="f", name=cls.output + "Lesser")
 
     def test_reclassaeaGreater(self):
         """Testing r.reclass.area with greater"""
-        self.assertModule('r.reclass.area', input=self.input, output=self.output + 'Greater',
-                          value=self.value, mode='greater', method='reclass')
-        self.assertRasterMinMax(map=self.output + 'Greater', refmin=200, refmax=1000,
-                                msg="Range of data: min = 200  max = 1000")
+        self.assertModule(
+            "r.reclass.area",
+            input=self.input,
+            output=self.output + "Greater",
+            value=self.value,
+            mode="greater",
+            method="reclass",
+        )
+        self.assertRasterMinMax(
+            map=self.output + "Greater",
+            refmin=200,
+            refmax=1000,
+            msg="Range of data: min = 200  max = 1000",
+        )
 
     def test_reclassareaLesser(self):
         """Testing r.reclass.area with lesser"""
-        self.assertModule('r.reclass.area', input=self.input, output=self.output + 'Lesser',
-                          value=self.value, mode='lesser', method='reclass')
-        self.assertRasterMinMax(map=self.output + 'Lesser', refmin=900, refmax=1000,
-                                msg="Range of data: min = 900  max = 1000")
+        self.assertModule(
+            "r.reclass.area",
+            input=self.input,
+            output=self.output + "Lesser",
+            value=self.value,
+            mode="lesser",
+            method="reclass",
+        )
+        self.assertRasterMinMax(
+            map=self.output + "Lesser",
+            refmin=900,
+            refmax=1000,
+            msg="Range of data: min = 900  max = 1000",
+        )
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 58 - 18
scripts/r.reclass.area/testsuite/testrra.py

@@ -11,50 +11,90 @@ Licence:    This program is free software under the GNU General Public
 from grass.gunittest.case import TestCase
 from grass.gunittest.main import test
 
+
 class Testrr(TestCase):
-    input='zipcodes'
-    output='rraoutput'
+    input = "zipcodes"
+    output = "rraoutput"
 
     @classmethod
     def setUpClass(cls):
         cls.use_temp_region()
-        cls.runModule('g.region', raster=cls.input)
+        cls.runModule("g.region", raster=cls.input)
 
     @classmethod
     def tearDownClass(cls):
         cls.del_temp_region()
 
     def tearDown(cls):
-        cls.runModule('g.remove', type='raster', flags='f', name=cls.output)
+        cls.runModule("g.remove", type="raster", flags="f", name=cls.output)
 
     def test_flag_c(self):
         """Testing flag c"""
-        string="""min=27603
+        string = """min=27603
         max=27607
         cells=2025000"""
-        self.assertModule('r.reclass.area', input=self.input, output=self.output, value=2000, mode="greater", flags='c')
-        self.assertRasterFitsUnivar(self.output,
-                                    reference=string, precision=2)
+        self.assertModule(
+            "r.reclass.area",
+            input=self.input,
+            output=self.output,
+            value=2000,
+            mode="greater",
+            flags="c",
+        )
+        self.assertRasterFitsUnivar(self.output, reference=string, precision=2)
 
     def test_flag_d(self):
         """Testing flag d"""
-        self.assertModule('r.reclass.area', input=self.input, output=self.output, value=2000, mode="lesser", flags='d')
-        self.assertRasterMinMax(map=self.output, refmin=27511, refmax=27610,
-                                msg="Output Map in degrees must be between 27511 and 27610")
+        self.assertModule(
+            "r.reclass.area",
+            input=self.input,
+            output=self.output,
+            value=2000,
+            mode="lesser",
+            flags="d",
+        )
+        self.assertRasterMinMax(
+            map=self.output,
+            refmin=27511,
+            refmax=27610,
+            msg="Output Map in degrees must be between 27511 and 27610",
+        )
 
     def test_module_output(self):
         """Testing Module without flags"""
-        self.assertModule('r.reclass.area', input=self.input, output=self.output, value=2000, mode="greater")
-        self.assertRasterMinMax(map=self.output, refmin=27603, refmax=27607,
-                                msg="Output Map in degrees must be between 27603 and 27607")
+        self.assertModule(
+            "r.reclass.area",
+            input=self.input,
+            output=self.output,
+            value=2000,
+            mode="greater",
+        )
+        self.assertRasterMinMax(
+            map=self.output,
+            refmin=27603,
+            refmax=27607,
+            msg="Output Map in degrees must be between 27603 and 27607",
+        )
 
     def test_method_rmarea(self):
         """Testing Module without flags"""
-        self.assertModule('r.reclass.area', input=self.input, output=self.output, value=2000, mode="lesser", method="rmarea")
-        self.assertRasterMinMax(map=self.output, refmin=27603, refmax=27607,
-                                msg="Output Map in degrees must be between 27603 and 27607")
+        self.assertModule(
+            "r.reclass.area",
+            input=self.input,
+            output=self.output,
+            value=2000,
+            mode="lesser",
+            method="rmarea",
+        )
+        self.assertRasterMinMax(
+            map=self.output,
+            refmin=27603,
+            refmax=27607,
+            msg="Output Map in degrees must be between 27603 and 27607",
+        )
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     from grass.gunittest.main import test
+
     test()

+ 13 - 13
scripts/r.rgb/r.rgb.py

@@ -7,9 +7,9 @@
 # PURPOSE:	Split a raster map into red, green and blue maps
 # COPYRIGHT:	(C) 2009 Glynn Clements 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.
+# 		This program is free software under the GNU General Public
+# 		License (>=v2). Read the file COPYING that comes with GRASS
+# 		for details.
 #
 #############################################################################
 
@@ -46,30 +46,30 @@ import grass.script as gscript
 
 def main():
     options, unused = gscript.parser()
-    input = options['input']
-    red = options['red']
-    green = options['green']
-    blue = options['blue']
+    input = options["input"]
+    red = options["red"]
+    green = options["green"]
+    blue = options["blue"]
 
-    if not gscript.find_file(input)['file']:
+    if not gscript.find_file(input)["file"]:
         gscript.fatal(_("Raster map <%s> not found") % input)
 
     expressions = []
     maps = []
     if red:
-        expressions.append('%s = r#${input}' % red)
+        expressions.append("%s = r#${input}" % red)
         maps.append(red)
     if green:
-        expressions.append('%s = g#${input}' % green)
+        expressions.append("%s = g#${input}" % green)
         maps.append(green)
     if blue:
-        expressions.append('%s = b#${input}' % blue)
+        expressions.append("%s = b#${input}" % blue)
         maps.append(blue)
-    expr = ';'.join(expressions)
+    expr = ";".join(expressions)
     gscript.mapcalc(expr, input=input)
 
     for name in maps:
-        gscript.run_command('r.colors', map=name, color='grey255')
+        gscript.run_command("r.colors", map=name, color="grey255")
         gscript.raster_history(name)
 
 

+ 13 - 10
scripts/r.rgb/testsuite/test_r_rgb.py

@@ -12,33 +12,36 @@ from grass.gunittest.gmodules import SimpleModule
 class TestRRGB(TestCase):
     """Test r.rgb script"""
 
-    mapName = 'elevation'
-    red = 'elevation.r'
-    green = 'elevation.g'
-    blue = 'elevation.b'
+    mapName = "elevation"
+    red = "elevation.r"
+    green = "elevation.g"
+    blue = "elevation.b"
 
     @classmethod
     def setUpClass(cls):
         """Create maps in a small region."""
         cls.use_temp_region()
-        cls.runModule('g.region', raster=cls.mapName, flags='p')
+        cls.runModule("g.region", raster=cls.mapName, flags="p")
 
     @classmethod
     def tearDownClass(cls):
         """Remove temporary region"""
-        cls.runModule('g.remove', flags='f', type='raster',
-                      name=(cls.red, cls.green, cls.blue))
+        cls.runModule(
+            "g.remove", flags="f", type="raster", name=(cls.red, cls.green, cls.blue)
+        )
         cls.del_temp_region()
 
     def test_rgb_maps(self):
         """Generates rgb maps from a raster map test"""
-        module = SimpleModule('r.rgb', input=self.mapName, red=self.red,
-                              green=self.green, blue=self.blue)
+        module = SimpleModule(
+            "r.rgb", input=self.mapName, red=self.red, green=self.green, blue=self.blue
+        )
         self.assertModule(module)
 
         self.assertRasterExists(self.red)
         self.assertRasterExists(self.green)
         self.assertRasterExists(self.blue)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 33 - 27
scripts/r.shade/r.shade.py

@@ -70,58 +70,64 @@ from grass.exceptions import CalledModuleError
 
 def remove(maps):
     """Remove raster maps"""
-    gcore.run_command('g.remove', flags='f', quiet=True,
-                      type='rast', name=maps)
+    gcore.run_command("g.remove", flags="f", quiet=True, type="rast", name=maps)
 
 
 def main():
     options, flags = gcore.parser()
 
-    drape_map = options['color']
-    relief_map = options['shade']
-    brighten = int(options['brighten'])
-    output_map = options['output']
-    bgcolor = options['bgcolor']
+    drape_map = options["color"]
+    relief_map = options["shade"]
+    brighten = int(options["brighten"])
+    output_map = options["output"]
+    bgcolor = options["bgcolor"]
 
     rhis_extra_args = {}
     if bgcolor:
-        rhis_extra_args['bgcolor'] = bgcolor
-    if flags['c']:
-        rhis_extra_args['flags'] = 'c'
+        rhis_extra_args["bgcolor"] = bgcolor
+    if flags["c"]:
+        rhis_extra_args["flags"] = "c"
 
     to_remove = []
     try:
-        unique_name = 'tmp__rshade_%d' % os.getpid()
-        tmp_base = '%s_drape' % unique_name
-        tmp_r = tmp_base + '.r'
-        tmp_g = tmp_base + '.g'
-        tmp_b = tmp_base + '.b'
+        unique_name = "tmp__rshade_%d" % os.getpid()
+        tmp_base = "%s_drape" % unique_name
+        tmp_r = tmp_base + ".r"
+        tmp_g = tmp_base + ".g"
+        tmp_b = tmp_base + ".b"
 
         if brighten:
             # steps taken from r.his manual page
             # how much they are similar with d.shade/d.his is unknown
             # perhaps even without brightness, there can be some differences
             # comparing to d.shade
-            relief_map_tmp = '%s_relief' % unique_name
+            relief_map_tmp = "%s_relief" % unique_name
             # convert [-99, -99] to [0.01, 1.99]
-            brighten = 1 + brighten / 100.
-            grast.mapcalc('{n} = {c} * #{o}'.format(
-                n=relief_map_tmp, o=relief_map, c=brighten))
-            gcore.run_command('r.colors', map=relief_map_tmp, color='grey255')
+            brighten = 1 + brighten / 100.0
+            grast.mapcalc(
+                "{n} = {c} * #{o}".format(n=relief_map_tmp, o=relief_map, c=brighten)
+            )
+            gcore.run_command("r.colors", map=relief_map_tmp, color="grey255")
             relief_map = relief_map_tmp
             to_remove.append(relief_map_tmp)
-        gcore.run_command('r.his', hue=drape_map, intensity=relief_map,
-                          red=tmp_r, green=tmp_g, blue=tmp_b,
-                          **rhis_extra_args)
+        gcore.run_command(
+            "r.his",
+            hue=drape_map,
+            intensity=relief_map,
+            red=tmp_r,
+            green=tmp_g,
+            blue=tmp_b,
+            **rhis_extra_args
+        )
         to_remove.extend([tmp_r, tmp_g, tmp_b])
-        gcore.run_command('r.composite', red=tmp_r, green=tmp_g,
-                          blue=tmp_b, output=output_map)
+        gcore.run_command(
+            "r.composite", red=tmp_r, green=tmp_g, blue=tmp_b, output=output_map
+        )
         remove(to_remove)  # who knows if finally is called when exit
     except CalledModuleError as error:
         remove(to_remove)
         # TODO: implement module name to CalledModuleError
-        gcore.fatal(_("Module %s failed. Check the above error messages.") %
-                    error.cmd)
+        gcore.fatal(_("Module %s failed. Check the above error messages.") % error.cmd)
 
 
 if __name__ == "__main__":

+ 10 - 9
scripts/r.shade/testsuite/test_r_shade.py

@@ -12,30 +12,31 @@ from grass.gunittest.gmodules import SimpleModule
 class TestRShade(TestCase):
     """Test r.shade script"""
 
-    mapName = 'aspect'
-    color = 'elevation'
-    outputMap = 'elevation_aspect_shaded'
+    mapName = "aspect"
+    color = "elevation"
+    outputMap = "elevation_aspect_shaded"
 
     @classmethod
     def setUpClass(cls):
         """Create maps in a small region."""
         cls.use_temp_region()
-        cls.runModule('g.region', raster=cls.mapName, flags='p')
+        cls.runModule("g.region", raster=cls.mapName, flags="p")
 
     @classmethod
     def tearDownClass(cls):
         """Remove temporary region"""
-        cls.runModule('g.remove', flags='f', type='raster',
-                      name=cls.outputMap)
+        cls.runModule("g.remove", flags="f", type="raster", name=cls.outputMap)
         cls.del_temp_region()
 
     def test_shade_map(self):
         """Generates a color raster map over shaded relief map test"""
-        module = SimpleModule('r.shade', shade=self.mapName, color=self.color,
-                              output=self.outputMap)
+        module = SimpleModule(
+            "r.shade", shade=self.mapName, color=self.color, output=self.outputMap
+        )
         self.assertModule(module)
 
         self.assertRasterExists(self.outputMap)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 166 - 126
scripts/r.tileset/r.tileset.py

@@ -121,10 +121,10 @@ from grass.exceptions import CalledModuleError
 def bboxToPoints(bbox):
     """Make points that are the corners of a bounding box"""
     points = []
-    points.append((bbox['w'], bbox['s']))
-    points.append((bbox['w'], bbox['n']))
-    points.append((bbox['e'], bbox['n']))
-    points.append((bbox['e'], bbox['s']))
+    points.append((bbox["w"], bbox["s"]))
+    points.append((bbox["w"], bbox["n"]))
+    points.append((bbox["e"], bbox["n"]))
+    points.append((bbox["e"], bbox["s"]))
 
     return points
 
@@ -147,10 +147,10 @@ def pointsToBbox(points):
         if max_y < point[1]:
             max_y = point[1]
 
-    bbox['n'] = max_y
-    bbox['s'] = min_y
-    bbox['w'] = min_x
-    bbox['e'] = max_x
+    bbox["n"] = max_y
+    bbox["s"] = min_y
+    bbox["w"] = min_x
+    bbox["e"] = max_x
 
     return bbox
 
@@ -160,26 +160,28 @@ def project(file, source, dest):
     errors = 0
     points = []
     try:
-        ret = gcore.read_command('m.proj',
-                                 quiet=True,
-                                 flags='d',
-                                 proj_in=source['proj'],
-                                 proj_out=dest['proj'],
-                                 sep=';',
-                                 input=file)
+        ret = gcore.read_command(
+            "m.proj",
+            quiet=True,
+            flags="d",
+            proj_in=source["proj"],
+            proj_out=dest["proj"],
+            sep=";",
+            input=file,
+        )
         ret = decode(ret)
     except CalledModuleError:
-        gcore.fatal(cs2cs + ' failed')
+        gcore.fatal(cs2cs + " failed")
 
     if not ret:
-        gcore.fatal(cs2cs + ' failed')
+        gcore.fatal(cs2cs + " failed")
 
     for line in ret.splitlines():
         if "*" in line:
             errors += 1
         else:
-            p_x2, p_y2, p_z2 = list(map(float, line.split(';')))
-            points.append((p_x2 / dest['scale'], p_y2 / dest['scale']))
+            p_x2, p_y2, p_z2 = list(map(float, line.split(";")))
+            points.append((p_x2 / dest["scale"], p_y2 / dest["scale"]))
 
     return points, errors
 
@@ -190,8 +192,9 @@ def projectPoints(points, source, dest):
 
     input = tempfile.NamedTemporaryFile(mode="wt")
     for point in points:
-        input.file.write('%f;%f\n' % (point[0] * source['scale'],
-                                      point[1] * source['scale']))
+        input.file.write(
+            "%f;%f\n" % (point[0] * source["scale"], point[1] * source["scale"])
+        )
     input.file.flush()
 
     dest_points, errors = project(input.name, source, dest)
@@ -212,21 +215,23 @@ def sideLengths(points, xmetric, ymetric):
         sl_d = math.sqrt(sl_x * sl_x + sl_y * sl_y)
         ret.append(sl_d)
 
-    return {'x': (ret[1], ret[3]), 'y': (ret[0], ret[2])}
+    return {"x": (ret[1], ret[3]), "y": (ret[0], ret[2])}
 
 
 def bboxesIntersect(bbox_1, bbox_2):
     """Determine if two bounding boxes intersect"""
-    bi_a1 = (bbox_1['w'], bbox_1['s'])
-    bi_a2 = (bbox_1['e'], bbox_1['n'])
-    bi_b1 = (bbox_2['w'], bbox_2['s'])
-    bi_b2 = (bbox_2['e'], bbox_2['n'])
+    bi_a1 = (bbox_1["w"], bbox_1["s"])
+    bi_a2 = (bbox_1["e"], bbox_1["n"])
+    bi_b1 = (bbox_2["w"], bbox_2["s"])
+    bi_b2 = (bbox_2["e"], bbox_2["n"])
     cin = [False, False]
     for i in (0, 1):
-        if (bi_a1[i] <= bi_b1[i] and bi_a2[i] >= bi_b1[i]) or \
-           (bi_a1[i] <= bi_b1[i] and bi_a2[i] >= bi_b2[i]) or \
-           (bi_b1[i] <= bi_a1[i] and bi_b2[i] >= bi_a1[i]) or \
-           (bi_b1[i] <= bi_a1[i] and bi_b2[i] >= bi_a2[i]):
+        if (
+            (bi_a1[i] <= bi_b1[i] and bi_a2[i] >= bi_b1[i])
+            or (bi_a1[i] <= bi_b1[i] and bi_a2[i] >= bi_b2[i])
+            or (bi_b1[i] <= bi_a1[i] and bi_b2[i] >= bi_a1[i])
+            or (bi_b1[i] <= bi_a1[i] and bi_b2[i] >= bi_a2[i])
+        ):
             cin[i] = True
 
     if cin[0] and cin[1]:
@@ -237,93 +242,95 @@ def bboxesIntersect(bbox_1, bbox_2):
 
 def main():
     # Take into account those extra pixels we'll be a addin'
-    max_cols = int(options['maxcols']) - int(options['overlap'])
-    max_rows = int(options['maxrows']) - int(options['overlap'])
+    max_cols = int(options["maxcols"]) - int(options["overlap"])
+    max_rows = int(options["maxrows"]) - int(options["overlap"])
 
     if max_cols == 0:
-        gcore.fatal(_("It is not possible to set 'maxcols=%s' and "
-                      "'overlap=%s'. Please set maxcols>overlap" %
-                      (options['maxcols'], options['overlap'])))
+        gcore.fatal(
+            _(
+                "It is not possible to set 'maxcols=%s' and "
+                "'overlap=%s'. Please set maxcols>overlap"
+                % (options["maxcols"], options["overlap"])
+            )
+        )
     elif max_rows == 0:
-        gcore.fatal(_("It is not possible to set 'maxrows=%s' and "
-                      "'overlap=%s'. Please set maxrows>overlap" %
-                      (options['maxrows'], options['overlap'])))
+        gcore.fatal(
+            _(
+                "It is not possible to set 'maxrows=%s' and "
+                "'overlap=%s'. Please set maxrows>overlap"
+                % (options["maxrows"], options["overlap"])
+            )
+        )
     # destination projection
-    if not options['destproj']:
-        dest_proj = gcore.read_command('g.proj',
-                                       quiet=True,
-                                       flags='jf')
-        dest_proj = decode(dest_proj).rstrip('\n')
+    if not options["destproj"]:
+        dest_proj = gcore.read_command("g.proj", quiet=True, flags="jf")
+        dest_proj = decode(dest_proj).rstrip("\n")
         if not dest_proj:
-            gcore.fatal(_('g.proj failed'))
+            gcore.fatal(_("g.proj failed"))
     else:
-        dest_proj = options['destproj']
+        dest_proj = options["destproj"]
     gcore.debug("Getting destination projection -> '%s'" % dest_proj)
 
     # projection scale
-    if not options['destscale']:
-        ret = gcore.parse_command('g.proj',
-                                  quiet=True,
-                                  flags='j')
+    if not options["destscale"]:
+        ret = gcore.parse_command("g.proj", quiet=True, flags="j")
         if not ret:
-            gcore.fatal(_('g.proj failed'))
+            gcore.fatal(_("g.proj failed"))
 
-        if '+to_meter' in ret:
-            dest_scale = ret['+to_meter'].strip()
+        if "+to_meter" in ret:
+            dest_scale = ret["+to_meter"].strip()
         else:
-            gcore.warning(
-                _("Scale (%s) not found, assuming '1'") %
-                '+to_meter')
-            dest_scale = '1'
+            gcore.warning(_("Scale (%s) not found, assuming '1'") % "+to_meter")
+            dest_scale = "1"
     else:
-        dest_scale = options['destscale']
-    gcore.debug('Getting destination projection scale -> %s' % dest_scale)
+        dest_scale = options["destscale"]
+    gcore.debug("Getting destination projection scale -> %s" % dest_scale)
 
     # set up the projections
-    srs_source = {'proj': options['sourceproj'],
-                  'scale': float(options['sourcescale'])}
-    srs_dest = {'proj': dest_proj, 'scale': float(dest_scale)}
-
-    if options['region']:
-        gcore.run_command('g.region',
-                          quiet=True,
-                          region=options['region'])
+    srs_source = {"proj": options["sourceproj"], "scale": float(options["sourcescale"])}
+    srs_dest = {"proj": dest_proj, "scale": float(dest_scale)}
+
+    if options["region"]:
+        gcore.run_command("g.region", quiet=True, region=options["region"])
     dest_bbox = gcore.region()
-    gcore.debug('Getting destination region')
+    gcore.debug("Getting destination region")
 
     # output field separator
-    fs = separator(options['separator'])
+    fs = separator(options["separator"])
 
     # project the destination region into the source:
-    gcore.verbose('Projecting destination region into source...')
+    gcore.verbose("Projecting destination region into source...")
     dest_bbox_points = bboxToPoints(dest_bbox)
 
-    dest_bbox_source_points, errors_dest = projectPoints(dest_bbox_points,
-                                                         source=srs_dest,
-                                                         dest=srs_source)
+    dest_bbox_source_points, errors_dest = projectPoints(
+        dest_bbox_points, source=srs_dest, dest=srs_source
+    )
 
     if len(dest_bbox_source_points) == 0:
-        gcore.fatal(_("There are no tiles available. Probably the output "
-                      "projection system it is not compatible with the "
-                      "projection of the current location"))
+        gcore.fatal(
+            _(
+                "There are no tiles available. Probably the output "
+                "projection system it is not compatible with the "
+                "projection of the current location"
+            )
+        )
 
     source_bbox = pointsToBbox(dest_bbox_source_points)
 
-    gcore.verbose('Projecting source bounding box into destination...')
+    gcore.verbose("Projecting source bounding box into destination...")
 
     source_bbox_points = bboxToPoints(source_bbox)
 
-    source_bbox_dest_points, errors_source = projectPoints(source_bbox_points,
-                                                           source=srs_source,
-                                                           dest=srs_dest)
+    source_bbox_dest_points, errors_source = projectPoints(
+        source_bbox_points, source=srs_source, dest=srs_dest
+    )
 
-    x_metric = 1 / dest_bbox['ewres']
-    y_metric = 1 / dest_bbox['nsres']
+    x_metric = 1 / dest_bbox["ewres"]
+    y_metric = 1 / dest_bbox["nsres"]
 
-    gcore.verbose('Computing length of sides of source bounding box...')
+    gcore.verbose("Computing length of sides of source bounding box...")
 
-    source_bbox_dest_lengths = sideLengths(source_bbox_dest_points,
-                                           x_metric, y_metric)
+    source_bbox_dest_lengths = sideLengths(source_bbox_dest_points, x_metric, y_metric)
 
     # Find the skewedness of the two directions.
     # Define it to be greater than one
@@ -340,8 +347,8 @@ def main():
     # points later.
 
     bigger = []
-    bigger.append(max(source_bbox_dest_lengths['x']))
-    bigger.append(max(source_bbox_dest_lengths['y']))
+    bigger.append(max(source_bbox_dest_lengths["x"]))
+    bigger.append(max(source_bbox_dest_lengths["y"]))
     maxdim = (max_cols, max_rows)
 
     # Compute the number and size of tiles to use in each direction
@@ -350,7 +357,7 @@ def main():
     # I'm going to make the numbers all simpler and add this extra cell to
     # every tile.
 
-    gcore.message(_('Computing tiling...'))
+    gcore.message(_("Computing tiling..."))
     tiles = [-1, -1]
     tile_base_size = [-1, -1]
     tiles_extra_1 = [-1, -1]
@@ -369,65 +376,98 @@ def main():
             tile_size[i] = tile_base_size[i] + 1
         tileset_size[i] = int(tile_size[i] * tiles[i])
         # Add overlap to tiles (doesn't effect tileset_size
-        tile_size_overlap[i] = tile_size[i] + int(options['overlap'])
+        tile_size_overlap[i] = tile_size[i] + int(options["overlap"])
 
-    gcore.verbose("There will be %d by %d tiles each %d by %d cells" %
-                  (tiles[0], tiles[1], tile_size[0], tile_size[1]))
+    gcore.verbose(
+        "There will be %d by %d tiles each %d by %d cells"
+        % (tiles[0], tiles[1], tile_size[0], tile_size[1])
+    )
 
     ximax = tiles[0]
     yimax = tiles[1]
 
-    min_x = source_bbox['w']
-    min_y = source_bbox['s']
-    max_x = source_bbox['e']
-    max_y = source_bbox['n']
-    span_x = (max_x - min_x)
-    span_y = (max_y - min_y)
+    min_x = source_bbox["w"]
+    min_y = source_bbox["s"]
+    max_x = source_bbox["e"]
+    max_y = source_bbox["n"]
+    span_x = max_x - min_x
+    span_y = max_y - min_y
 
     xi = 0
-    tile_bbox = {'w': -1, 's': -1, 'e': -1, 'n': -1}
+    tile_bbox = {"w": -1, "s": -1, "e": -1, "n": -1}
 
     if errors_dest > 0:
-        gcore.warning(_("During computation %i tiles could not be created" %
-                        errors_dest))
+        gcore.warning(
+            _("During computation %i tiles could not be created" % errors_dest)
+        )
 
     while xi < ximax:
-        tile_bbox['w'] = float(
-            min_x) + (float(xi) * float(tile_size[0]) / float(tileset_size[0])) * float(span_x)
-        tile_bbox['e'] = float(min_x) + (float(xi + 1) * float(tile_size_overlap[0]
-                                                               ) / float(tileset_size[0])) * float(span_x)
+        tile_bbox["w"] = float(min_x) + (
+            float(xi) * float(tile_size[0]) / float(tileset_size[0])
+        ) * float(span_x)
+        tile_bbox["e"] = float(min_x) + (
+            float(xi + 1) * float(tile_size_overlap[0]) / float(tileset_size[0])
+        ) * float(span_x)
         yi = 0
         while yi < yimax:
-            tile_bbox['s'] = float(
-                min_y) + (float(yi) * float(tile_size[1]) / float(tileset_size[1])) * float(span_y)
-            tile_bbox['n'] = float(min_y) + (
-                float(yi + 1) * float(tile_size_overlap[1]) /
-                float(tileset_size[1])) * float(span_y)
+            tile_bbox["s"] = float(min_y) + (
+                float(yi) * float(tile_size[1]) / float(tileset_size[1])
+            ) * float(span_y)
+            tile_bbox["n"] = float(min_y) + (
+                float(yi + 1) * float(tile_size_overlap[1]) / float(tileset_size[1])
+            ) * float(span_y)
             tile_bbox_points = bboxToPoints(tile_bbox)
-            tile_dest_bbox_points, errors = projectPoints(tile_bbox_points,
-                                                          source=srs_source,
-                                                          dest=srs_dest)
+            tile_dest_bbox_points, errors = projectPoints(
+                tile_bbox_points, source=srs_source, dest=srs_dest
+            )
             tile_dest_bbox = pointsToBbox(tile_dest_bbox_points)
             if bboxesIntersect(tile_dest_bbox, dest_bbox):
-                if flags['w']:
-                    print("bbox=%s,%s,%s,%s&width=%s&height=%s" %
-                          (tile_bbox['w'], tile_bbox['s'], tile_bbox['e'],
-                           tile_bbox['n'], tile_size_overlap[0],
-                           tile_size_overlap[1]))
-                elif flags['g']:
-                    print("w=%s;s=%s;e=%s;n=%s;cols=%s;rows=%s" %
-                          (tile_bbox['w'], tile_bbox['s'], tile_bbox['e'],
-                           tile_bbox['n'], tile_size_overlap[0],
-                           tile_size_overlap[1]))
+                if flags["w"]:
+                    print(
+                        "bbox=%s,%s,%s,%s&width=%s&height=%s"
+                        % (
+                            tile_bbox["w"],
+                            tile_bbox["s"],
+                            tile_bbox["e"],
+                            tile_bbox["n"],
+                            tile_size_overlap[0],
+                            tile_size_overlap[1],
+                        )
+                    )
+                elif flags["g"]:
+                    print(
+                        "w=%s;s=%s;e=%s;n=%s;cols=%s;rows=%s"
+                        % (
+                            tile_bbox["w"],
+                            tile_bbox["s"],
+                            tile_bbox["e"],
+                            tile_bbox["n"],
+                            tile_size_overlap[0],
+                            tile_size_overlap[1],
+                        )
+                    )
                 else:
-                    print("%s%s%s%s%s%s%s%s%s%s%s" %
-                          (tile_bbox['w'], fs, tile_bbox['s'], fs,
-                           tile_bbox['e'], fs, tile_bbox['n'], fs,
-                           tile_size_overlap[0], fs, tile_size_overlap[1]))
+                    print(
+                        "%s%s%s%s%s%s%s%s%s%s%s"
+                        % (
+                            tile_bbox["w"],
+                            fs,
+                            tile_bbox["s"],
+                            fs,
+                            tile_bbox["e"],
+                            fs,
+                            tile_bbox["n"],
+                            fs,
+                            tile_size_overlap[0],
+                            fs,
+                            tile_size_overlap[1],
+                        )
+                    )
             yi += 1
         xi += 1
 
+
 if __name__ == "__main__":
-    cs2cs = 'cs2cs'
+    cs2cs = "cs2cs"
     options, flags = gcore.parser()
     sys.exit(main())

+ 10 - 6
scripts/r.tileset/testsuite/test_r_tileset.py

@@ -15,19 +15,21 @@ import os
 output = """\
 -78.77462049|35.6875073|-78.60830318|35.74855834|1506|678
 -78.77462049|35.74855834|-78.60830318|35.80960938|1506|678
-""".replace('\n', os.linesep)
+""".replace(
+    "\n", os.linesep
+)
 
 
 class TestRTileset(TestCase):
     """Test r.tileset script"""
 
-    mapName = 'elevation'
+    mapName = "elevation"
 
     @classmethod
     def setUpClass(cls):
         """Use temporary region settings"""
         cls.use_temp_region()
-        cls.runModule('g.region', raster=cls.mapName, flags='p')
+        cls.runModule("g.region", raster=cls.mapName, flags="p")
 
     @classmethod
     def tearDownClass(cls):
@@ -36,11 +38,13 @@ class TestRTileset(TestCase):
 
     def test_tiling(self):
         """Produce tiling test"""
-        module = SimpleModule('r.tileset', sourceproj='+init=epsg:4326',
-                              maxrows=1024, maxcols=2048)
+        module = SimpleModule(
+            "r.tileset", sourceproj="+init=epsg:4326", maxrows=1024, maxcols=2048
+        )
         self.assertModule(module)
 
         self.assertMultiLineEqual(decode(module.outputs.stdout), output)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 87 - 60
scripts/r.unpack/r.unpack.py

@@ -7,9 +7,9 @@
 # PURPOSE:	Unpack up a raster map packed with r.pack
 # COPYRIGHT:	(C) 2010-2017 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.
+# 		This program is free software under the GNU General
+# 		Public License (>=v2). Read the file COPYING that
+# 		comes with GRASS for details.
 #
 #############################################################################
 
@@ -55,36 +55,35 @@ def cleanup():
 
 
 def main():
-    infile = options['input']
+    infile = options["input"]
 
     global tmp_dir
     tmp_dir = grass.tempdir()
-    grass.debug('tmp_dir = {tmpdir}'.format(tmpdir=tmp_dir))
+    grass.debug("tmp_dir = {tmpdir}".format(tmpdir=tmp_dir))
 
     if not os.path.exists(infile):
-        grass.fatal(_('File {name} not found.'.format(name=infile)))
+        grass.fatal(_("File {name} not found.".format(name=infile)))
 
     gisenv = grass.gisenv()
-    mset_dir = os.path.join(gisenv['GISDBASE'],
-                            gisenv['LOCATION_NAME'],
-                            gisenv['MAPSET'])
+    mset_dir = os.path.join(
+        gisenv["GISDBASE"], gisenv["LOCATION_NAME"], gisenv["MAPSET"]
+    )
     input_base = os.path.basename(infile)
     shutil.copyfile(infile, os.path.join(tmp_dir, input_base))
     os.chdir(tmp_dir)
-    tar = tarfile.TarFile.open(name=input_base, mode='r')
+    tar = tarfile.TarFile.open(name=input_base, mode="r")
     try:
         data_names = [
-            tarinfo.name for tarinfo in tar.getmembers()
-            if '/' not in tarinfo.name
+            tarinfo.name for tarinfo in tar.getmembers() if "/" not in tarinfo.name
         ]
     except:
         grass.fatal(_("Pack file unreadable"))
 
-    if flags['p']:
+    if flags["p"]:
         # print proj info and exit
         try:
-            for fname in ['PROJ_INFO', 'PROJ_UNITS']:
-                f = tar.extractfile('{}/{}'.format(data_names[0], fname))
+            for fname in ["PROJ_INFO", "PROJ_UNITS"]:
+                f = tar.extractfile("{}/{}".format(data_names[0], fname))
                 sys.stdout.write(f.read().decode())
         except KeyError:
             grass.fatal(_("Pack file unreadable: file '{}' missing".format(fname)))
@@ -92,77 +91,103 @@ def main():
 
         return 0
 
-    if options['output']:
-        map_name = options['output']
+    if options["output"]:
+        map_name = options["output"]
     else:
-        map_name = data_names[0].split('@')[0]
+        map_name = data_names[0].split("@")[0]
 
-    gfile = grass.find_file(name=map_name, element='cell', mapset='.')
-    if gfile['file']:
-        if os.environ.get('GRASS_OVERWRITE', '0') != '1':
-            grass.fatal(_('Raster map <{name}> already exists'.format(name=map_name)))
+    gfile = grass.find_file(name=map_name, element="cell", mapset=".")
+    if gfile["file"]:
+        if os.environ.get("GRASS_OVERWRITE", "0") != "1":
+            grass.fatal(_("Raster map <{name}> already exists".format(name=map_name)))
         else:
             grass.warning(
-                _('Raster map <{name}> already exists and will be overwritten'.format(name=map_name)))
+                _(
+                    "Raster map <{name}> already exists and will be overwritten".format(
+                        name=map_name
+                    )
+                )
+            )
 
     # extract data
     tar.extractall()
     tar.close()
     os.chdir(data_names[0])
 
-    if os.path.exists('cell'):
+    if os.path.exists("cell"):
         pass
-    elif os.path.exists('coor'):
-        grass.fatal(_('This GRASS GIS pack file contains vector data. Use '
-                      'v.unpack to unpack <{name}>'.format(name=map_name)))
+    elif os.path.exists("coor"):
+        grass.fatal(
+            _(
+                "This GRASS GIS pack file contains vector data. Use "
+                "v.unpack to unpack <{name}>".format(name=map_name)
+            )
+        )
     else:
         grass.fatal(_("Pack file unreadable"))
 
     # check projection compatibility in a rather crappy way
 
-    if flags['o']:
-        grass.warning(_("Overriding projection check (using current location's projection)."))
+    if flags["o"]:
+        grass.warning(
+            _("Overriding projection check (using current location's projection).")
+        )
 
     else:
 
         diff_result_1 = diff_result_2 = None
 
-        proj_info_file_1 = 'PROJ_INFO'
-        proj_info_file_2 = os.path.join(mset_dir, '..', 'PERMANENT', 'PROJ_INFO')
+        proj_info_file_1 = "PROJ_INFO"
+        proj_info_file_2 = os.path.join(mset_dir, "..", "PERMANENT", "PROJ_INFO")
 
         skip_projection_check = False
         if not os.path.exists(proj_info_file_1):
             if os.path.exists(proj_info_file_2):
                 grass.fatal(
-                    _("PROJ_INFO file is missing, unpack raster map in XY (unprojected) location."))
+                    _(
+                        "PROJ_INFO file is missing, unpack raster map in XY (unprojected) location."
+                    )
+                )
             skip_projection_check = True  # XY location
 
         if not skip_projection_check:
-            if not grass.compare_key_value_text_files(filename_a=proj_info_file_1,
-                                                      filename_b=proj_info_file_2,
-                                                      proj=True):
+            if not grass.compare_key_value_text_files(
+                filename_a=proj_info_file_1, filename_b=proj_info_file_2, proj=True
+            ):
                 diff_result_1 = diff_files(proj_info_file_1, proj_info_file_2)
 
-            proj_units_file_1 = 'PROJ_UNITS'
-            proj_units_file_2 = os.path.join(mset_dir, '..', 'PERMANENT', 'PROJ_UNITS')
+            proj_units_file_1 = "PROJ_UNITS"
+            proj_units_file_2 = os.path.join(mset_dir, "..", "PERMANENT", "PROJ_UNITS")
 
-            if not grass.compare_key_value_text_files(filename_a=proj_units_file_1,
-                                                      filename_b=proj_units_file_2,
-                                                      units=True):
+            if not grass.compare_key_value_text_files(
+                filename_a=proj_units_file_1, filename_b=proj_units_file_2, units=True
+            ):
                 diff_result_2 = diff_files(proj_units_file_1, proj_units_file_2)
 
             if diff_result_1 or diff_result_2:
 
                 if diff_result_1:
-                    grass.warning(_("Difference between PROJ_INFO file of packed map "
-                                    "and of current location:\n{diff}").format(diff=''.join(diff_result_1)))
+                    grass.warning(
+                        _(
+                            "Difference between PROJ_INFO file of packed map "
+                            "and of current location:\n{diff}"
+                        ).format(diff="".join(diff_result_1))
+                    )
                 if diff_result_2:
-                    grass.warning(_("Difference between PROJ_UNITS file of packed map "
-                                    "and of current location:\n{diff}").format(diff=''.join(diff_result_2)))
-                grass.fatal(_("Projection of dataset does not appear to match current location."
-                              " In case of no significant differences in the projection definitions,"
-                              " use the -o flag to ignore them and use"
-                              " current location definition."))
+                    grass.warning(
+                        _(
+                            "Difference between PROJ_UNITS file of packed map "
+                            "and of current location:\n{diff}"
+                        ).format(diff="".join(diff_result_2))
+                    )
+                grass.fatal(
+                    _(
+                        "Projection of dataset does not appear to match current location."
+                        " In case of no significant differences in the projection definitions,"
+                        " use the -o flag to ignore them and use"
+                        " current location definition."
+                    )
+                )
 
     maps = []
     vrt_file = None
@@ -171,10 +196,7 @@ def main():
         if index > 0:
             map_name = data
 
-        for element in [
-                'cats', 'cell', 'cellhd', 'cell_misc', 'colr', 'fcell',
-                'hist'
-        ]:
+        for element in ["cats", "cell", "cellhd", "cell_misc", "colr", "fcell", "hist"]:
             src_path = os.path.join(tmp_dir, data, element)
             if not os.path.exists(src_path):
                 continue
@@ -183,36 +205,41 @@ def main():
             if not os.path.exists(path):
                 os.mkdir(path)
 
-            if element == 'cell_misc':
+            if element == "cell_misc":
                 if index > 0:
                     maps.append(
                         "{map_name}@{mapset}".format(
-                            map_name=map_name, mapset=gisenv['MAPSET'],
+                            map_name=map_name,
+                            mapset=gisenv["MAPSET"],
                         ),
                     )
 
                 path = os.path.join(
-                    mset_dir, element, map_name,
+                    mset_dir,
+                    element,
+                    map_name,
                 )
                 if index == 0:
-                    vrt_file = os.path.join(path, 'vrt')
+                    vrt_file = os.path.join(path, "vrt")
 
                 if os.path.exists(path):
                     shutil.rmtree(path)
                 shutil.copytree(src_path, path)
             else:
                 shutil.copyfile(
-                    src_path, os.path.join(mset_dir, element, map_name),
+                    src_path,
+                    os.path.join(mset_dir, element, map_name),
                 )
 
     # Update vrt file
     if maps:
         if vrt_file and os.path.exists(vrt_file):
-            files = '\n'.join(maps)
-            with open(vrt_file, 'w') as f:
+            files = "\n".join(maps)
+            with open(vrt_file, "w") as f:
                 f.write(files)
 
-    grass.message(_('Raster map <{name}> unpacked'.format(name=map_name)))
+    grass.message(_("Raster map <{name}> unpacked".format(name=map_name)))
+
 
 if __name__ == "__main__":
     options, flags = grass.parser()

+ 90 - 64
scripts/r3.in.xyz/r3.in.xyz.py

@@ -4,19 +4,19 @@
 # MODULE:       r3.in.xyz
 # AUTHOR:       M. Hamish Bowman, Dunedin, New Zealand
 # PURPOSE:      Run r.in.xyz in a loop for various z-levels and construct
-#		a 3D raster. Unlike r.in.xyz, reading from stdin and z-scaling
-#		won't work.
+# 		a 3D raster. Unlike r.in.xyz, reading from stdin and z-scaling
+# 		won't work.
 #
 # COPYRIGHT:    (c) 2011-2012 Hamish Bowman, and the GRASS Development Team
-#		Port of r3.in.xyz(.sh) for GRASS 6.4.
+# 		Port of r3.in.xyz(.sh) for GRASS 6.4.
 #               This program is free software under the GNU General Public
 #               License (>=v2). Read the file COPYING that comes with GRASS
 #               for details.
 #
-#		This program is distributed in the hope that it will be useful,
-#		but WITHOUT ANY WARRANTY; without even the implied warranty of
-#		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#		GNU General Public License for more details.
+# 		This program is distributed in the hope that it will be useful,
+# 		but WITHOUT ANY WARRANTY; without even the implied warranty of
+# 		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# 		GNU General Public License for more details.
 #
 #############################################################################
 
@@ -176,30 +176,34 @@ from grass.exceptions import CalledModuleError
 
 
 def cleanup():
-    grass.run_command('g.remove', flags='f',
-                      type="rast", pattern='tmp.r3xyz.%d.*' % os.getpid(),
-                      quiet=True)
+    grass.run_command(
+        "g.remove",
+        flags="f",
+        type="rast",
+        pattern="tmp.r3xyz.%d.*" % os.getpid(),
+        quiet=True,
+    )
 
 
 def main():
-    infile = options['input']
-    output = options['output']
-    method = options['method']
-    dtype = options['type']
-    fs = options['separator']
-    x = options['x']
-    y = options['y']
-    z = options['z']
-    value_column = options['value_column']
-    vrange = options['vrange']
-    vscale = options['vscale']
-    percent = options['percent']
-    pth = options['pth']
-    trim = options['trim']
-    workers = int(options['workers'])
-    scan_only = flags['s']
-    shell_style = flags['g']
-    ignore_broken = flags['i']
+    infile = options["input"]
+    output = options["output"]
+    method = options["method"]
+    dtype = options["type"]
+    fs = options["separator"]
+    x = options["x"]
+    y = options["y"]
+    z = options["z"]
+    value_column = options["value_column"]
+    vrange = options["vrange"]
+    vscale = options["vscale"]
+    percent = options["percent"]
+    pth = options["pth"]
+    trim = options["trim"]
+    workers = int(options["workers"])
+    scan_only = flags["s"]
+    shell_style = flags["g"]
+    ignore_broken = flags["i"]
 
     if workers == 1 and "WORKERS" in os.environ:
         workers = int(os.environ["WORKERS"])
@@ -209,41 +213,51 @@ def main():
 
     addl_opts = {}
     if pth:
-        addl_opts['pth'] = '%s' % pth
+        addl_opts["pth"] = "%s" % pth
     if trim:
-        addl_opts['trim'] = '%s' % trim
+        addl_opts["trim"] = "%s" % trim
     if value_column:
-        addl_opts['value_column'] = '%s' % value_column
+        addl_opts["value_column"] = "%s" % value_column
     if vrange:
-        addl_opts['vrange'] = '%s' % vrange
+        addl_opts["vrange"] = "%s" % vrange
     if vscale:
-        addl_opts['vscale'] = '%s' % vscale
+        addl_opts["vscale"] = "%s" % vscale
     if ignore_broken:
-        addl_opts['flags'] = 'i'
+        addl_opts["flags"] = "i"
 
     if scan_only or shell_style:
         if shell_style:
-            doShell = 'g'
+            doShell = "g"
         else:
-            doShell = ''
-        grass.run_command('r.in.xyz', flags='s' + doShell, input=infile,
-                          output='dummy', sep=fs, x=x, y=y, z=z,
-                          **addl_opts)
+            doShell = ""
+        grass.run_command(
+            "r.in.xyz",
+            flags="s" + doShell,
+            input=infile,
+            output="dummy",
+            sep=fs,
+            x=x,
+            y=y,
+            z=z,
+            **addl_opts
+        )
         sys.exit()
 
-    if dtype == 'float':
-        data_type = 'FCELL'
+    if dtype == "float":
+        data_type = "FCELL"
     else:
-        data_type = 'DCELL'
+        data_type = "DCELL"
 
     region = grass.region(region3d=True)
 
-    if region['nsres'] != region['nsres3'] or region['ewres'] != region['ewres3']:
-        grass.run_command('g.region', flags='3p')
+    if region["nsres"] != region["nsres3"] or region["ewres"] != region["ewres3"]:
+        grass.run_command("g.region", flags="3p")
         grass.fatal(_("The 2D and 3D region settings are different. Can not continue."))
 
-    grass.verbose(_("Region bottom=%.15g  top=%.15g  vertical_cell_res=%.15g  (%d depths)")
-                  % (region['b'], region['t'], region['tbres'], region['depths']))
+    grass.verbose(
+        _("Region bottom=%.15g  top=%.15g  vertical_cell_res=%.15g  (%d depths)")
+        % (region["b"], region["t"], region["tbres"], region["depths"])
+    )
 
     grass.verbose(_("Creating slices ..."))
 
@@ -260,28 +274,39 @@ def main():
     proc = {}
     pout = {}
 
-    depths = list(range(1, 1 + region['depths']))
+    depths = list(range(1, 1 + region["depths"]))
 
     for i in depths:
-        tmp_layer_name = 'tmp.r3xyz.%d.%s' % (os.getpid(), '%05d' % i)
+        tmp_layer_name = "tmp.r3xyz.%d.%s" % (os.getpid(), "%05d" % i)
 
-        zrange_min = region['b'] + (region['tbres'] * (i - 1))
+        zrange_min = region["b"] + (region["tbres"] * (i - 1))
 
-        if i < region['depths']:
-            zrange_max = region['b'] + (region['tbres'] * i) - eps
+        if i < region["depths"]:
+            zrange_max = region["b"] + (region["tbres"] * i) - eps
         else:
-            zrange_max = region['b'] + (region['tbres'] * i)
+            zrange_max = region["b"] + (region["tbres"] * i)
 
         # spawn depth layer import job in the background
-        #grass.debug("slice %d, <%s>  %% %d" % (band, image[band], band % workers))
-        grass.message(_("Processing horizontal slice %d of %d [%.15g,%.15g) ...")
-                      % (i, region['depths'], zrange_min, zrange_max))
-
-        proc[i] = grass.start_command('r.in.xyz', input=infile, output=tmp_layer_name,
-                                      sep=fs, method=method, x=x, y=y, z=z,
-                                      percent=percent, type=data_type,
-                                      zrange='%.15g,%.15g' % (zrange_min, zrange_max),
-                                      **addl_opts)
+        # grass.debug("slice %d, <%s>  %% %d" % (band, image[band], band % workers))
+        grass.message(
+            _("Processing horizontal slice %d of %d [%.15g,%.15g) ...")
+            % (i, region["depths"], zrange_min, zrange_max)
+        )
+
+        proc[i] = grass.start_command(
+            "r.in.xyz",
+            input=infile,
+            output=tmp_layer_name,
+            sep=fs,
+            method=method,
+            x=x,
+            y=y,
+            z=z,
+            percent=percent,
+            type=data_type,
+            zrange="%.15g,%.15g" % (zrange_min, zrange_max),
+            **addl_opts
+        )
 
         grass.debug("i=%d, %%=%d  (workers=%d)" % (i, i % workers, workers))
         # print sys.getsizeof(proc)  # sizeof(proc array)  [not so big]
@@ -304,12 +329,13 @@ def main():
     grass.verbose(_("Assembling 3D cube ..."))
 
     # input order: lower most strata first
-    slices = grass.read_command('g.list', type='raster', sep=',',
-                                pattern='tmp.r3xyz.%d.*' % os.getpid()).rstrip(os.linesep)
+    slices = grass.read_command(
+        "g.list", type="raster", sep=",", pattern="tmp.r3xyz.%d.*" % os.getpid()
+    ).rstrip(os.linesep)
     grass.debug(slices)
 
     try:
-        grass.run_command('r.to.rast3', input=slices, output=output)
+        grass.run_command("r.to.rast3", input=slices, output=output)
     except CalledModuleError:
         grass.message(_("Done. 3D raster map <%s> created.") % output)
 

+ 9 - 7
scripts/v.build.all/v.build.all.py

@@ -6,9 +6,9 @@
 # PURPOSE:	Build all vectors in current mapset
 # COPYRIGHT:	(C) 2004, 2008-2009 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.
+# 		This program is free software under the GNU General Public
+# 		License (>=v2). Read the file COPYING that comes with GRASS
+# 		for details.
 #
 #############################################################################
 
@@ -25,10 +25,10 @@ from grass.exceptions import CalledModuleError
 
 def main():
     env = grass.gisenv()
-    mapset = env['MAPSET']
+    mapset = env["MAPSET"]
     ret = 0
 
-    vectors = grass.list_grouped('vect')[mapset]
+    vectors = grass.list_grouped("vect")[mapset]
     num_vectors = len(vectors)
 
     if grass.verbosity() < 2:
@@ -39,8 +39,10 @@ def main():
     i = 1
     for vect in vectors:
         map = "%s@%s" % (vect, mapset)
-        grass.message(_("%s\nBuilding topology for vector map <%s> (%d of %d)...\n%s") %
-                      ('-' * 80, map, i, num_vectors, '-' * 80))
+        grass.message(
+            _("%s\nBuilding topology for vector map <%s> (%d of %d)...\n%s")
+            % ("-" * 80, map, i, num_vectors, "-" * 80)
+        )
         grass.verbose(_("v.build map=%s") % map)
         try:
             grass.run_command("v.build", map=map, quiet=quiet)

+ 21 - 12
scripts/v.centroids/testsuite/test_v_centroids.py

@@ -11,30 +11,39 @@ from grass.gunittest.gmodules import SimpleModule
 
 class TestVCentroids(TestCase):
     """Test v.centroids script"""
-    mapName = 'busroute11'
-    outRouteMap = 'busroute11_boundary'
-    fromType = 'line'
-    toType = 'boundary'
-    outAreaMap = 'busroute11_area'
+
+    mapName = "busroute11"
+    outRouteMap = "busroute11_boundary"
+    fromType = "line"
+    toType = "boundary"
+    outAreaMap = "busroute11_area"
 
     @classmethod
     def setUpClass(cls):
         """Create an area from a closed line"""
-        cls.runModule('v.type', input=cls.mapName, output=cls.outRouteMap,
-                      from_type=cls.fromType, to_type=cls.toType)
+        cls.runModule(
+            "v.type",
+            input=cls.mapName,
+            output=cls.outRouteMap,
+            from_type=cls.fromType,
+            to_type=cls.toType,
+        )
 
     @classmethod
     def tearDownClass(cls):
         """Remove the generated maps"""
-        cls.runModule('g.remove', flags='f', type='vector',
-                      name=(cls.outRouteMap, cls.outAreaMap))
+        cls.runModule(
+            "g.remove", flags="f", type="vector", name=(cls.outRouteMap, cls.outAreaMap)
+        )
 
     def test_area(self):
         """Adds missing centroids to closed boundaries test"""
-        module = SimpleModule('v.centroids', input=self.outRouteMap,
-                              output=self.outAreaMap)
+        module = SimpleModule(
+            "v.centroids", input=self.outRouteMap, output=self.outAreaMap
+        )
         self.assertModule(module)
         self.assertVectorExists(self.outAreaMap)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 4 - 3
scripts/v.centroids/v.centroids.py

@@ -54,15 +54,16 @@ import grass.script as gscript
 
 
 def main():
-    if options['option'] == 'add':
-        num_bound = gscript.vector_info_topo(map=options['input'])['boundaries']
+    if options["option"] == "add":
+        num_bound = gscript.vector_info_topo(map=options["input"])["boundaries"]
         if num_bound == 0:
             gscript.fatal(_("Input vector map contains no boundaries."))
 
-        gscript.run_command("v.category", type='area', **options)
+        gscript.run_command("v.category", type="area", **options)
 
     sys.exit(0)
 
+
 if __name__ == "__main__":
     options, flags = gscript.parser()
     main()

+ 56 - 27
scripts/v.clip/testsuite/test_v_clip.py

@@ -15,73 +15,102 @@ import os
 from grass.gunittest.case import TestCase
 from grass.gunittest.main import test
 
+
 class TestClipling(TestCase):
-    inpclip = 'zipcodes'
-    inpoint = 'hospitals'
-    inlines = 'roadsmajor'
-    inpoly = 'geology'
-    outreg = 'hospreg'
-    outclip = 'hospzip'
-    outline = 'roadsgarner'
-    outpoly = 'geogarner'
-    outdiss = 'geodiss'
-    garner = 'garner'
+    inpclip = "zipcodes"
+    inpoint = "hospitals"
+    inlines = "roadsmajor"
+    inpoly = "geology"
+    outreg = "hospreg"
+    outclip = "hospzip"
+    outline = "roadsgarner"
+    outpoly = "geogarner"
+    outdiss = "geodiss"
+    garner = "garner"
 
     @classmethod
     def setUpClass(cls):
         """Ensures expected computational region and generated data"""
         cls.use_temp_region()
-        cls.runModule('g.region', vector=cls.inpclip)
-        cls.runModule('v.extract', input=cls.inpclip, output=cls.garner,
-                      where="ZIPNAME = '{na}'".format(na=cls.garner.upper()))
+        cls.runModule("g.region", vector=cls.inpclip)
+        cls.runModule(
+            "v.extract",
+            input=cls.inpclip,
+            output=cls.garner,
+            where="ZIPNAME = '{na}'".format(na=cls.garner.upper()),
+        )
 
     @classmethod
     def tearDownClass(cls):
         """Remove the temporary region and generated data"""
-        cls.runModule('g.remove', flags='f', type='vector',
-                      name=(cls.outclip, cls.outreg, cls.garner, cls.outline,
-                            cls.outpoly, cls.outdiss))
+        cls.runModule(
+            "g.remove",
+            flags="f",
+            type="vector",
+            name=(
+                cls.outclip,
+                cls.outreg,
+                cls.garner,
+                cls.outline,
+                cls.outpoly,
+                cls.outdiss,
+            ),
+        )
         cls.del_temp_region()
 
     def test_points(self):
         """Test clipping points"""
-        self.assertModule('v.clip', input=self.inpoint, clip=self.inpclip,
-                          output=self.outclip)
+        self.assertModule(
+            "v.clip", input=self.inpoint, clip=self.inpclip, output=self.outclip
+        )
         self.assertVectorExists(self.outclip)
         topology = dict(points=8)
         self.assertVectorFitsTopoInfo(self.outclip, topology)
 
     def test_region(self):
         """Test clipping point by region"""
-        self.assertModule('v.clip', input=self.inpoint, clip=self.inpclip,
-                          output=self.outreg, flags='r')
+        self.assertModule(
+            "v.clip",
+            input=self.inpoint,
+            clip=self.inpclip,
+            output=self.outreg,
+            flags="r",
+        )
         self.assertVectorExists(self.outreg)
         topology = dict(points=13)
         self.assertVectorFitsTopoInfo(self.outreg, topology)
 
     def test_lines(self):
         """Test clipping lines"""
-        self.assertModule('v.clip', input=self.inlines, clip=self.garner,
-                          output=self.outline)
+        self.assertModule(
+            "v.clip", input=self.inlines, clip=self.garner, output=self.outline
+        )
         self.assertVectorExists(self.outline)
         topology = dict(lines=13, nodes=16)
         self.assertVectorFitsTopoInfo(self.outline, topology)
 
     def test_poly(self):
         """Test clipping polygon without dissolve"""
-        self.assertModule('v.clip', input=self.inpoly, clip=self.inpclip,
-                          output=self.outpoly)
+        self.assertModule(
+            "v.clip", input=self.inpoly, clip=self.inpclip, output=self.outpoly
+        )
         self.assertVectorExists(self.outpoly)
         topology = dict(areas=275)
         self.assertVectorFitsTopoInfo(self.outpoly, topology)
 
     def test_poly_diss(self):
         """Test clipping polygon without dissolve"""
-        self.assertModule('v.clip', input=self.inpoly, clip=self.inpclip,
-                          output=self.outdiss, flags='d')
+        self.assertModule(
+            "v.clip",
+            input=self.inpoly,
+            clip=self.inpclip,
+            output=self.outdiss,
+            flags="d",
+        )
         self.assertVectorExists(self.outdiss)
         topology = dict(areas=276)
         self.assertVectorFitsTopoInfo(self.outdiss, topology)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 62 - 34
scripts/v.clip/v.clip.py

@@ -66,26 +66,32 @@ TMP = []
 def cleanup():
     for name in TMP:
         try:
-            grass.run_command('g.remove', flags='f',
-                              type='vector', name=name, quiet=True)
+            grass.run_command(
+                "g.remove", flags="f", type="vector", name=name, quiet=True
+            )
 
         except CalledModuleError as e:
-            grass.fatal(_("Deleting of temporary layer failed. "
-                          "Check above error messages and "
-                          "see following details:\n%s") % e)
+            grass.fatal(
+                _(
+                    "Deleting of temporary layer failed. "
+                    "Check above error messages and "
+                    "see following details:\n%s"
+                )
+                % e
+            )
 
 
 def section_message(msg):
-    grass.message('{delim}\n{msg}\n{delim}'.format(msg=msg, delim='-' * 80))
+    grass.message("{delim}\n{msg}\n{delim}".format(msg=msg, delim="-" * 80))
 
 
 def main():
-    input_map = opt['input']
-    clip_map = opt['clip']
-    output_map = opt['output']
+    input_map = opt["input"]
+    clip_map = opt["clip"]
+    output_map = opt["output"]
 
-    flag_dissolve = flg['d']
-    flag_region = flg['r']
+    flag_dissolve = flg["d"]
+    flag_region = flg["r"]
 
     # ======================================== #
     # ========== INPUT MAP TOPOLOGY ========== #
@@ -93,12 +99,12 @@ def main():
     vinfo = grass.vector_info_topo(input_map)
 
     # ==== only points ==== #
-    if (vinfo['points'] > 0 and vinfo['lines'] == 0 and vinfo['areas'] == 0):
+    if vinfo["points"] > 0 and vinfo["lines"] == 0 and vinfo["areas"] == 0:
 
         # ==================================== #
         # ========== CLIP BY REGION ========== #
         # ==================================== #
-        if (flag_region):
+        if flag_region:
             clip_by_region(input_map, output_map, clip_select)
 
         # ================================== #
@@ -112,20 +118,22 @@ def main():
     # ==== lines, areas, lines + areas ==== #
     # ==== points + areas, points + lines, points + areas + lines ==== #
     else:
-        if (vinfo['points'] > 0):
-            grass.warning("Input map contains multiple geometry, "
-                          "only lines and areas will be clipped.")
+        if vinfo["points"] > 0:
+            grass.warning(
+                "Input map contains multiple geometry, "
+                "only lines and areas will be clipped."
+            )
 
         # ==================================== #
         # ========== CLIP BY REGION ========== #
         # ==================================== #
-        if (flag_region):
+        if flag_region:
             clip_by_region(input_map, output_map, clip_overlay)
 
         # ===================================================== #
         # ========== CLIP WITHOUT DISSOLVED CLIP MAP ========== #
         # ===================================================== #
-        elif (flag_dissolve):
+        elif flag_dissolve:
             section_message("Clipping without dissolved clip map.")
             clip_overlay(input_map, clip_map, output_map)
 
@@ -136,12 +144,11 @@ def main():
             section_message("Default clipping with dissolved clip map.")
 
             # setup temporary map
-            temp_clip_map = '%s_%s' % ("temp", str(os.getpid()))
+            temp_clip_map = "%s_%s" % ("temp", str(os.getpid()))
             TMP.append(temp_clip_map)
 
             # dissolve clip_map
-            grass.run_command('v.dissolve', input=clip_map,
-                              output=temp_clip_map)
+            grass.run_command("v.dissolve", input=clip_map, output=temp_clip_map)
 
             # perform clipping
             clip_overlay(input_map, temp_clip_map, output_map)
@@ -150,7 +157,7 @@ def main():
     # ========== OUTPUT MAP TOPOLOGY========== #
     # ======================================== #
     vinfo = grass.vector_info_topo(output_map)
-    if vinfo['primitives'] == 0:
+    if vinfo["primitives"] == 0:
         grass.warning("Output map is empty.")
 
     return 0
@@ -162,11 +169,11 @@ def clip_by_region(input_map, output_map, clip_fn):
     section_message("Clipping by region.")
 
     # setup temporary map
-    temp_region_map = '%s_%s' % ("temp", str(os.getpid()))
+    temp_region_map = "%s_%s" % ("temp", str(os.getpid()))
     TMP.append(temp_region_map)
 
     # create a map covering current computational region
-    grass.run_command('v.in.region', output=temp_region_map)
+    grass.run_command("v.in.region", output=temp_region_map)
 
     # perform clipping
     clip_fn(input_map, temp_region_map, output_map)
@@ -174,23 +181,44 @@ def clip_by_region(input_map, output_map, clip_fn):
 
 def clip_overlay(input_data, clip_data, out_data):
     try:
-        grass.run_command('v.overlay', ainput=input_data, binput=clip_data,
-                          operator='and', output=out_data, olayer='0,1,0')
+        grass.run_command(
+            "v.overlay",
+            ainput=input_data,
+            binput=clip_data,
+            operator="and",
+            output=out_data,
+            olayer="0,1,0",
+        )
     except CalledModuleError as e:
-        grass.fatal(_("Clipping steps failed."
-                      " Check above error messages and"
-                      " see following details:\n%s") % e)
+        grass.fatal(
+            _(
+                "Clipping steps failed."
+                " Check above error messages and"
+                " see following details:\n%s"
+            )
+            % e
+        )
 
 
 def clip_select(input_data, clip_data, out_data):
     try:
-        grass.run_command('v.select', ainput=input_data, binput=clip_data,
-                          output=out_data, operator='overlap')
+        grass.run_command(
+            "v.select",
+            ainput=input_data,
+            binput=clip_data,
+            output=out_data,
+            operator="overlap",
+        )
 
     except CalledModuleError as e:
-        grass.fatal(_("Clipping steps failed."
-                      " Check above error messages and"
-                      " see following details:\n%s") % e)
+        grass.fatal(
+            _(
+                "Clipping steps failed."
+                " Check above error messages and"
+                " see following details:\n%s"
+            )
+            % e
+        )
 
 
 if __name__ == "__main__":

+ 18 - 14
scripts/v.db.addcolumn/testsuite/test_v_db_addcolumn.py

@@ -18,35 +18,39 @@ class TestVDbAddColumn(TestCase):
     @classmethod
     def setUpClass(cls):
         """Copy vector."""
-        run_command('g.copy', vector='roadsmajor,myroads')
+        run_command("g.copy", vector="roadsmajor,myroads")
 
     @classmethod
     def tearDownClass(cls):
         """Remove copied vector"""
-        run_command('g.remove', type='vector', name='myroads',
-                    flags='f')
+        run_command("g.remove", type="vector", name="myroads", flags="f")
 
     def test_add_single_column_check(self):
         """Add column to the attribute table"""
-        module = SimpleModule('v.db.addcolumn', map='myroads',
-                              columns='slope double precision')
+        module = SimpleModule(
+            "v.db.addcolumn", map="myroads", columns="slope double precision"
+        )
         self.assertModule(module)
 
-        m = SimpleModule('v.info', map='myroads', flags='c')
+        m = SimpleModule("v.info", map="myroads", flags="c")
         self.assertModule(m)
-        self.assertRegexpMatches(decode(m.outputs.stdout), 'slope')
+        self.assertRegexpMatches(decode(m.outputs.stdout), "slope")
 
     def test_add_two_columns_check(self):
         """Add two column to the attribute table"""
-        module = SimpleModule('v.db.addcolumn', map='myroads',
-                              columns='slope_2 double precision, \
-                              myname varchar(15)')
+        module = SimpleModule(
+            "v.db.addcolumn",
+            map="myroads",
+            columns="slope_2 double precision, \
+                              myname varchar(15)",
+        )
         self.assertModule(module)
 
-        m = SimpleModule('v.info', map='myroads', flags='c')
+        m = SimpleModule("v.info", map="myroads", flags="c")
         self.assertModule(m)
-        self.assertRegexpMatches(decode(m.outputs.stdout), 'slope_2')
-        self.assertRegexpMatches(decode(m.outputs.stdout), 'myname')
+        self.assertRegexpMatches(decode(m.outputs.stdout), "slope_2")
+        self.assertRegexpMatches(decode(m.outputs.stdout), "myname")
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 18 - 13
scripts/v.db.addcolumn/v.db.addcolumn.py

@@ -45,14 +45,14 @@ from grass.script.utils import encode
 
 
 def main():
-    map = options['map']
-    layer = options['layer']
-    columns = options['columns']
-    columns = [col.strip() for col in columns.split(',')]
+    map = options["map"]
+    layer = options["layer"]
+    columns = options["columns"]
+    columns = [col.strip() for col in columns.split(",")]
 
     # does map exist in CURRENT mapset?
-    mapset = grass.gisenv()['MAPSET']
-    exists = bool(grass.find_file(map, element='vector', mapset=mapset)['file'])
+    mapset = grass.gisenv()["MAPSET"]
+    exists = bool(grass.find_file(map, element="vector", mapset=mapset)["file"])
 
     if not exists:
         grass.fatal(_("Vector map <%s> not found in current mapset") % map)
@@ -61,23 +61,27 @@ def main():
         f = grass.vector_db(map)[int(layer)]
     except KeyError:
         grass.fatal(
-            _("There is no table connected to this map. Run v.db.connect or v.db.addtable first."))
+            _(
+                "There is no table connected to this map. Run v.db.connect or v.db.addtable first."
+            )
+        )
 
-    table = f['table']
-    database = f['database']
-    driver = f['driver']
+    table = f["table"]
+    database = f["database"]
+    driver = f["driver"]
     column_existing = grass.vector_columns(map, int(layer)).keys()
 
     for col in columns:
         if not col:
             grass.fatal(_("There is an empty column. Did you leave a trailing comma?"))
-        col_name = col.split(' ')[0].strip()
+        col_name = col.split(" ")[0].strip()
         if col_name in column_existing:
             grass.error(_("Column <%s> is already in the table. Skipping.") % col_name)
             continue
         grass.verbose(_("Adding column <%s> to the table") % col_name)
-        p = grass.feed_command('db.execute', input='-',
-                               database=database, driver=driver)
+        p = grass.feed_command(
+            "db.execute", input="-", database=database, driver=driver
+        )
         res = "ALTER TABLE {} ADD COLUMN {}".format(table, col)
         p.stdin.write(encode(res))
         grass.debug(res)
@@ -88,6 +92,7 @@ def main():
     # write cmd history:
     grass.vector_history(map)
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     main()

+ 12 - 11
scripts/v.db.addtable/testsuite/test_v_db_addtable.py

@@ -18,29 +18,30 @@ class TestVDbAddTable(TestCase):
     @classmethod
     def setUpClass(cls):
         """Copy vector."""
-        run_command('g.copy', vector='roadsmajor,myroads')
+        run_command("g.copy", vector="roadsmajor,myroads")
 
     @classmethod
     def tearDownClass(cls):
         """Remove copied vector"""
-        run_command('g.remove', type='vector', name='myroads',
-                    flags='f')
+        run_command("g.remove", type="vector", name="myroads", flags="f")
 
     def test_add_single_columned_table_check(self):
         """Add a new attribute table with single column to layer 2"""
-        module = SimpleModule('v.db.addtable', map='myroads',
-                              columns='slope double precision', layer=2)
+        module = SimpleModule(
+            "v.db.addtable", map="myroads", columns="slope double precision", layer=2
+        )
         self.assertModule(module)
 
-        run_command('v.db.connect', flags='p', map='myroads')
+        run_command("v.db.connect", flags="p", map="myroads")
 
-        m = SimpleModule('v.info', map='myroads', flags='c')
+        m = SimpleModule("v.info", map="myroads", flags="c")
         self.assertModule(m)
-        self.assertNotRegexpMatches(decode(m.outputs.stdout), 'slope')
+        self.assertNotRegexpMatches(decode(m.outputs.stdout), "slope")
 
-        m = SimpleModule('v.info', map='myroads', flags='c', layer=2)
+        m = SimpleModule("v.info", map="myroads", flags="c", layer=2)
         self.assertModule(m)
-        self.assertRegexpMatches(decode(m.outputs.stdout), 'slope')
+        self.assertRegexpMatches(decode(m.outputs.stdout), "slope")
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 49 - 32
scripts/v.db.addtable/v.db.addtable.py

@@ -61,44 +61,45 @@ from grass.exceptions import CalledModuleError
 
 
 def main():
-    vector = options['map']
-    table = options['table']
-    layer = options['layer']
-    columns = options['columns']
-    key = options['key']
+    vector = options["map"]
+    table = options["table"]
+    layer = options["layer"]
+    columns = options["columns"]
+    key = options["key"]
 
     # does map exist in CURRENT mapset?
-    mapset = grass.gisenv()['MAPSET']
-    if not grass.find_file(vector, element='vector', mapset=mapset)['file']:
+    mapset = grass.gisenv()["MAPSET"]
+    if not grass.find_file(vector, element="vector", mapset=mapset)["file"]:
         grass.fatal(_("Vector map <%s> not found in current mapset") % vector)
 
-    map_name = vector.split('@')[0]
+    map_name = vector.split("@")[0]
 
     if not table:
-        if layer == '1':
+        if layer == "1":
             grass.verbose(_("Using vector map name as table name: <%s>") % map_name)
             table = map_name
         else:
             # to avoid tables with identical names on higher layers
             table = "%s_%s" % (map_name, layer)
             grass.verbose(
-                _("Using vector map name extended by layer number as table name: <%s>") %
-                table)
+                _("Using vector map name extended by layer number as table name: <%s>")
+                % table
+            )
     else:
         grass.verbose(_("Using user specified table name: %s") % table)
 
     # check if DB parameters are set, and if not set them.
-    grass.run_command('db.connect', flags='c', quiet=True)
+    grass.run_command("db.connect", flags="c", quiet=True)
     grass.verbose(_("Creating new DB connection based on default mapset settings..."))
     kv = grass.db_connection()
-    database = kv['database']
-    driver = kv['driver']
-    schema = kv['schema']
+    database = kv["database"]
+    driver = kv["driver"]
+    schema = kv["schema"]
 
-    database2 = database.replace('$MAP/', map_name + '/')
+    database2 = database.replace("$MAP/", map_name + "/")
 
     # maybe there is already a table linked to the selected layer?
-    nuldev = open(os.devnull, 'w')
+    nuldev = open(os.devnull, "w")
     try:
         grass.vector_db(map_name, stderr=nuldev)[int(layer)]
         grass.fatal(_("There is already a table linked to layer <%s>") % layer)
@@ -106,8 +107,9 @@ def main():
         pass
 
     # maybe there is already a table with that name?
-    tables = grass.read_command('db.tables', flags='p', database=database2, driver=driver,
-                                stderr=nuldev)
+    tables = grass.read_command(
+        "db.tables", flags="p", database=database2, driver=driver, stderr=nuldev
+    )
     tables = decode(tables)
 
     if table not in tables.splitlines():
@@ -115,7 +117,7 @@ def main():
         column_def = []
         if columns:
             column_def = []
-            for x in ' '.join(columns.split()).split(','):
+            for x in " ".join(columns.split()).split(","):
                 colname = x.lower().split()[0]
                 if colname in colnames:
                     grass.fatal(_("Duplicate column name '%s' not allowed") % colname)
@@ -125,46 +127,61 @@ def main():
         # if not existing, create it:
         if key not in colnames:
             column_def.insert(0, "%s integer" % key)
-        column_def = ','.join(column_def)
+        column_def = ",".join(column_def)
 
         grass.verbose(_("Creating table with columns (%s)...") % column_def)
 
         sql = "CREATE TABLE %s (%s)" % (table, column_def)
         try:
-            grass.run_command('db.execute',
-                              database=database2, driver=driver, sql=sql)
+            grass.run_command("db.execute", database=database2, driver=driver, sql=sql)
         except CalledModuleError:
             grass.fatal(_("Unable to create table <%s>") % table)
 
     # connect the map to the DB:
     if schema:
-        table = '{schema}.{table}'.format(schema=schema, table=table)
+        table = "{schema}.{table}".format(schema=schema, table=table)
     grass.verbose(_("Connecting new table to vector map <%s>...") % map_name)
-    grass.run_command('v.db.connect', quiet=True,
-                      map=map_name, database=database, driver=driver,
-                      layer=layer, table=table, key=key)
+    grass.run_command(
+        "v.db.connect",
+        quiet=True,
+        map=map_name,
+        database=database,
+        driver=driver,
+        layer=layer,
+        table=table,
+        key=key,
+    )
 
     # finally we have to add cats into the attribute DB to make
     # modules such as v.what.rast happy: (creates new row for each
     # vector line):
     try:
-        grass.run_command('v.to.db', overwrite=True, map=map_name, layer=layer,
-                          option='cat', column=key, qlayer=layer)
+        grass.run_command(
+            "v.to.db",
+            overwrite=True,
+            map=map_name,
+            layer=layer,
+            option="cat",
+            column=key,
+            qlayer=layer,
+        )
     except CalledModuleError:
         # remove link
-        grass.run_command('v.db.connect', quiet=True, flags='d',
-                          map=map_name, layer=layer)
+        grass.run_command(
+            "v.db.connect", quiet=True, flags="d", map=map_name, layer=layer
+        )
         return 1
 
     grass.verbose(_("Current attribute table links:"))
     if grass.verbosity() > 2:
-        grass.run_command('v.db.connect', flags='p', map=map_name)
+        grass.run_command("v.db.connect", flags="p", map=map_name)
 
     # write cmd history:
     grass.vector_history(map_name)
 
     return 0
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     sys.exit(main())

+ 7 - 8
scripts/v.db.dropcolumn/testsuite/test_v_db_dropcolumn.py

@@ -18,23 +18,22 @@ class TestVDbDropColumn(TestCase):
     @classmethod
     def setUpClass(cls):
         """Copy vector."""
-        run_command('g.copy', vector='roadsmajor,myroads')
+        run_command("g.copy", vector="roadsmajor,myroads")
 
     @classmethod
     def tearDownClass(cls):
         """Remove copied vector"""
-        run_command('g.remove', type='vector', name='myroads',
-                    flags='f')
+        run_command("g.remove", type="vector", name="myroads", flags="f")
 
     def test_drop_single_column_check(self):
         """Drop column to the attribute table"""
-        module = SimpleModule('v.db.dropcolumn', map='myroads',
-                              columns='SHAPE_LEN')
+        module = SimpleModule("v.db.dropcolumn", map="myroads", columns="SHAPE_LEN")
         self.assertModule(module)
 
-        m = SimpleModule('v.info', map='myroads', flags='c')
+        m = SimpleModule("v.info", map="myroads", flags="c")
         self.assertModule(m)
-        self.assertNotRegexpMatches(decode(m.outputs.stdout), 'SHAPE_LEN')
+        self.assertNotRegexpMatches(decode(m.outputs.stdout), "SHAPE_LEN")
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 35 - 21
scripts/v.db.dropcolumn/v.db.dropcolumn.py

@@ -43,35 +43,45 @@ from grass.exceptions import CalledModuleError
 
 
 def main():
-    map = options['map']
-    layer = options['layer']
-    columns = options['columns'].split(',')
+    map = options["map"]
+    layer = options["layer"]
+    columns = options["columns"].split(",")
 
-    mapset = grass.gisenv()['MAPSET']
+    mapset = grass.gisenv()["MAPSET"]
 
     # does map exist in CURRENT mapset?
-    if not grass.find_file(map, element='vector', mapset=mapset)['file']:
+    if not grass.find_file(map, element="vector", mapset=mapset)["file"]:
         grass.fatal(_("Vector map <%s> not found in current mapset") % map)
 
     f = grass.vector_layer_db(map, layer)
 
-    table = f['table']
-    keycol = f['key']
-    database = f['database']
-    driver = f['driver']
+    table = f["table"]
+    keycol = f["key"]
+    database = f["database"]
+    driver = f["driver"]
 
     if not table:
-        grass.fatal(_("There is no table connected to the input vector map. "
-                      "Unable to delete any column. Exiting."))
+        grass.fatal(
+            _(
+                "There is no table connected to the input vector map. "
+                "Unable to delete any column. Exiting."
+            )
+        )
 
     if keycol in columns:
-        grass.fatal(_("Unable to delete <%s> column as it is needed to keep table <%s> "
-                      "connected to the input vector map <%s>") %
-                    (keycol, table, map))
+        grass.fatal(
+            _(
+                "Unable to delete <%s> column as it is needed to keep table <%s> "
+                "connected to the input vector map <%s>"
+            )
+            % (keycol, table, map)
+        )
 
     for column in columns:
         if column not in grass.vector_columns(map, layer):
-            grass.warning(_("Column <%s> not found in table <%s>. Skipped") % (column, table))
+            grass.warning(
+                _("Column <%s> not found in table <%s>. Skipped") % (column, table)
+            )
             continue
 
         if driver == "sqlite":
@@ -79,7 +89,7 @@ def main():
             # http://www.sqlite.org/faq.html#q11
             colnames = []
             coltypes = []
-            for f in grass.db_describe(table, database=database, driver=driver)['cols']:
+            for f in grass.db_describe(table, database=database, driver=driver)["cols"]:
                 if f[0] == column:
                     continue
                 colnames.append(f[0])
@@ -102,22 +112,26 @@ def main():
                 "INSERT INTO ${table} SELECT ${colnames} FROM ${table}_backup",
                 "CREATE UNIQUE INDEX ${table}_cat ON ${table} (${keycol} )",
                 "DROP TABLE ${table}_backup",
-                "COMMIT"
+                "COMMIT",
             ]
-            tmpl = string.Template(';\n'.join(cmds))
-            sql = tmpl.substitute(table=table, coldef=coltypes, colnames=colnames, keycol=keycol)
+            tmpl = string.Template(";\n".join(cmds))
+            sql = tmpl.substitute(
+                table=table, coldef=coltypes, colnames=colnames, keycol=keycol
+            )
         else:
             sql = "ALTER TABLE %s DROP COLUMN %s" % (table, column)
 
         try:
-            grass.write_command('db.execute', input='-', database=database, driver=driver,
-                                stdin=sql)
+            grass.write_command(
+                "db.execute", input="-", database=database, driver=driver, stdin=sql
+            )
         except CalledModuleError:
             grass.fatal(_("Deleting column failed"))
 
     # write cmd history:
     grass.vector_history(map)
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     main()

+ 27 - 18
scripts/v.db.droprow/testsuite/test_v_db_droprow.py

@@ -15,39 +15,48 @@ from grass.script.utils import decode
 class TestVDbDropRow(TestCase):
     """Test v.db.droprow script"""
 
-    mapName = 'elevation'
-    inputMap = 'rand5k_elev'
-    outputMap = 'rand5k_elev_filt'
-    values = 'min=56.12\nmax=155.157'
+    mapName = "elevation"
+    inputMap = "rand5k_elev"
+    outputMap = "rand5k_elev_filt"
+    values = "min=56.12\nmax=155.157"
 
     @classmethod
     def setUpClass(cls):
         """Create maps in a small region."""
         cls.use_temp_region()
-        cls.runModule('g.region', raster=cls.mapName, flags='p')
+        cls.runModule("g.region", raster=cls.mapName, flags="p")
 
     @classmethod
     def tearDownClass(cls):
         """Remove temporary region"""
         cls.del_temp_region()
 
-        cls.runModule('g.remove', flags='f', type='vector',
-                      name=(cls.inputMap, cls.outputMap))
+        cls.runModule(
+            "g.remove", flags="f", type="vector", name=(cls.inputMap, cls.outputMap)
+        )
 
     def test_drop_row_check(self):
         """Drop vector object from a vector map"""
-        run_command('v.random', output=self.inputMap, n=5000)
-        run_command('v.db.addtable', map=self.inputMap,
-                    column="elevation double precision")
-        run_command('v.what.rast', map=self.inputMap,
-                    raster=self.mapName, column=self.mapName)
-
-        module = SimpleModule('v.db.droprow', input=self.inputMap,
-                              output=self.outputMap, where='elevation IS NULL')
+        run_command("v.random", output=self.inputMap, n=5000)
+        run_command(
+            "v.db.addtable", map=self.inputMap, column="elevation double precision"
+        )
+        run_command(
+            "v.what.rast", map=self.inputMap, raster=self.mapName, column=self.mapName
+        )
+
+        module = SimpleModule(
+            "v.db.droprow",
+            input=self.inputMap,
+            output=self.outputMap,
+            where="elevation IS NULL",
+        )
         self.assertModule(module)
 
-        self.assertVectorFitsUnivar(map=self.outputMap, column='elevation',
-                                    reference=self.values, precision=5)
+        self.assertVectorFitsUnivar(
+            map=self.outputMap, column="elevation", reference=self.values, precision=5
+        )
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     test()

+ 10 - 5
scripts/v.db.droprow/v.db.droprow.py

@@ -43,18 +43,23 @@ from grass.exceptions import CalledModuleError
 def main():
     # delete vectors via reverse selection
     try:
-        grass.run_command('v.extract',
-                          flags='r',
-                          input=options['input'], layer=options['layer'],
-                          output=options['output'], where=options['where'])
+        grass.run_command(
+            "v.extract",
+            flags="r",
+            input=options["input"],
+            layer=options["layer"],
+            output=options["output"],
+            where=options["where"],
+        )
     except CalledModuleError:
         return 1
 
     # write cmd history:
-    grass.vector_history(map=options['output'])
+    grass.vector_history(map=options["output"])
 
     return 0
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     sys.exit(main())

+ 0 - 0
scripts/v.db.droptable/testsuite/test_v_db_droptable.py


Некоторые файлы не были показаны из-за большого количества измененных файлов