diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 2b271e7a094..33c9cf82d4d 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -36,7 +36,7 @@ jobs: # renovate: datasource=pypi depName=bandit BANDIT_VERSION: "1.9.4" # renovate: datasource=pypi depName=ruff - RUFF_VERSION: "0.15.17" + RUFF_VERSION: "0.17.3" runs-on: ${{ matrix.os }} permissions: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 52aae79338a..6ae93656fce 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -53,7 +53,7 @@ repos: - id: detect-private-key - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.15.17 + rev: v0.17.3 hooks: # Run the linter. - id: ruff-check diff --git a/display/displaydrivers.md b/display/displaydrivers.md index 4b1b63c489e..e8708294a8b 100644 --- a/display/displaydrivers.md +++ b/display/displaydrivers.md @@ -35,14 +35,14 @@ import sys import grass.script as gs from grass.script import task as gtask -os.environ['GRASS_RENDER_IMMEDIATE'] = 'default' -os.environ['GRASS_RENDER_FILE'] = 'output.png' +os.environ["GRASS_RENDER_IMMEDIATE"] = "default" +os.environ["GRASS_RENDER_FILE"] = "output.png" cmd, dcmd = gtask.cmdstring_to_tuple(sys.argv[1]) -gs.run_command('d.text', text="Test of GRASS_RENDER_COMMAND redirection") +gs.run_command("d.text", text="Test of GRASS_RENDER_COMMAND redirection") -os.environ['GRASS_RENDER_FILE_READ'] = 'TRUE' +os.environ["GRASS_RENDER_FILE_READ"] = "TRUE" gs.run_command(cmd, **dcmd) ``` diff --git a/doc/development/style_guide.md b/doc/development/style_guide.md index 26568a90854..381705734c2 100644 --- a/doc/development/style_guide.md +++ b/doc/development/style_guide.md @@ -217,14 +217,14 @@ def func(arg1, arg2): Example: - >>> a=1 - >>> b=2 - >>> func(a,b) + >>> a = 1 + >>> b = 2 + >>> func(a, b) True """ if arg1 == arg2: - raise ValueError('arg1 must not be equal to arg2') + raise ValueError("arg1 must not be equal to arg2") return True ``` @@ -575,7 +575,9 @@ If different subprocesses need different regions, use different environments: ```python with gs.RegionManager(raster=input_raster, env=os.environ.copy()) as manager: - gs.run_command("r.slope.aspect", elevation=input_raster, slope=slope, env=manager.env) + gs.run_command( + "r.slope.aspect", elevation=input_raster, slope=slope, env=manager.env + ) ``` This approach makes the computational region completely safe for parallel @@ -587,7 +589,7 @@ If you can't use a context manager, you can use `gs.use_temp_region()` and ```python gs.use_temp_region() # From now on, use a separate region in the script. # Set the computational region with g.region as needed. -grass.run_command('g.region', raster='input') +grass.run_command("g.region", raster="input") gs.del_temp_region() # Original region applies now. ``` @@ -689,7 +691,6 @@ def remove(name): ) - def main(): temporary = gs.append_node_pid("tmp_mapcalc") atexit.register(remove, temporary) @@ -707,13 +708,13 @@ Use gs.findfile() when there is a need to test if a map exists. ```python # test for input raster map -result = gs.find_file(map_name, element='raster') -if not result['file']: +result = gs.find_file(map_name, element="raster") +if not result["file"]: gs.fatal(_("Raster map <{}> not found").format(map_name)) # test for input vector map -result = gs.find_file(map_name, element='vector') -if not result['file']: +result = gs.find_file(map_name, element="vector") +if not result["file"]: gs.fatal(_("Vector map <{}> not found").format(map_name)) ``` @@ -922,7 +923,7 @@ def main(): try: import pandas as pd # noqa: E402 except ModuleNotFoundError: - gs.fatal(_("Pandas library not installed")) + gs.fatal(_("Pandas library not installed")) ``` #### Tool name @@ -1011,9 +1012,9 @@ instead of constructing string from several parts (bad example): ```python # don't do this if ...: - maplabel = 'raster map' + maplabel = "raster map" else: - maplabel = '3D raster map' + maplabel = "3D raster map" win.SetLabel(_("Name for new {} to create").format(maplabel)) ``` @@ -1024,9 +1025,11 @@ string. The comment must start with GTC keyword and must be on a line before string: ```python -self.bwizard = wx.Button(..., +self.bwizard = wx.Button( + ..., # GTC New location - label = _("N&ew")) + label=_("N&ew"), +) # GTC %s will be replaced with name of current shell gs.message(_("Running through {}").format(shellname)) diff --git a/doc/development/testing.md b/doc/development/testing.md index 90ac17e38ae..0384c98cfe9 100644 --- a/doc/development/testing.md +++ b/doc/development/testing.md @@ -167,8 +167,7 @@ environment. Mark such a test so it is run on its own: ```python @pytest.mark.needs_solo_run -def test_something_which_changes_the_environment(xy_dataset_session): - ... +def test_something_which_changes_the_environment(xy_dataset_session): ... ``` ## More information diff --git a/doc/interfaces_overview.md b/doc/interfaces_overview.md index a932fe5edd1..0b141b04fb2 100644 --- a/doc/interfaces_overview.md +++ b/doc/interfaces_overview.md @@ -66,7 +66,6 @@ gs.create_project(path="path/to/my_project", epsg="3358") # Initialize the GRASS session with gs.setup.init("path/to/my_project") as session: - # Run GRASS tools tools = Tools(session=session) tools.r_import(input="/path/to/elevation.tif", output="elevation") diff --git a/doc/jupyter_intro.md b/doc/jupyter_intro.md index d1839ab372f..937f618739f 100644 --- a/doc/jupyter_intro.md +++ b/doc/jupyter_intro.md @@ -109,7 +109,7 @@ m.d_legend( at=(1, 50, 1, 8), title="Elevation (m)", border_color="none", - flags="bt" + flags="bt", ) # Add a scale bar to the map @@ -161,12 +161,11 @@ elevation_3dmap.render( perspective=10, height=5000, resolution_fine=1, - zexag=5 + zexag=5, +) +elevation_3dmap.overlay.d_legend( + raster="landuse", at=(0, 30, 87, 100), flags="b", border_color="none" ) -elevation_3dmap.overlay.d_legend(raster="landuse", - at=(0, 30, 87, 100), - flags="b", - border_color="none") elevation_3dmap.show() ``` @@ -184,10 +183,7 @@ maps and play a continuous loop. # Create a series of relief maps with different angles directions = [0, 90, 180, 270] for azimuth in directions: - tools.r_relief( - input="elevation", - output=f"relief_{azimuth}", - azimuth=azimuth) + tools.r_relief(input="elevation", output=f"relief_{azimuth}", azimuth=azimuth) m = gj.SeriesMap() m.add_rasters(f"relief_{azimuth}" for azimuth in directions) m.d_vect(map="roads") @@ -212,19 +208,16 @@ tools.g_region(n=226040, s=223780, e=639170, w=636190) tools.r_slope_aspect(elevation="elevation", dx="dx", dy="dy") # Compute overland flow tools.r_sim_water( - flags="t", - elevation="elevation", - dx="dx", - dy="dy", - depth="depth", - duration=30) + flags="t", elevation="elevation", dx="dx", dy="dy", depth="depth", duration=30 +) # Create a time series tools.t_create( output="depth", temporaltype="relative", title="Overland flow depth", - description="Overland flow depth") + description="Overland flow depth", +) # Register the time series maps = [ item["fullname"] @@ -243,11 +236,13 @@ flow_map.add_raster_series("depth", values="0.025-1.25") flow_map.d_vect(map="streets") # Add map features -flow_map.d_legend(raster="depth.30", - title="Depth [m]", - flags="bt", - border_color="none", - at=(1, 50, 0, 5)) +flow_map.d_legend( + raster="depth.30", + title="Depth [m]", + flags="bt", + border_color="none", + at=(1, 50, 0, 5), +) # Display the map flow_map.show() diff --git a/doc/migration_to_grass_tools_python_api.md b/doc/migration_to_grass_tools_python_api.md index 2612911bd6e..0f684c2e093 100644 --- a/doc/migration_to_grass_tools_python_api.md +++ b/doc/migration_to_grass_tools_python_api.md @@ -386,10 +386,7 @@ result = gs.list_strings("raster") Extract the *fullname* field from the JSON output: ```python -result = [ - item["fullname"] - for item in tools.g_list(type="raster", format="json") -] +result = [item["fullname"] for item in tools.g_list(type="raster", format="json")] ``` The *list_pairs* returns tuples: @@ -456,11 +453,7 @@ configure the *Tools* object accordingly. The *run_command* approach uses *errors="status"*: ```python -returncode = gs.run_command( - "r.mask.status", - flags="t", - errors="status" -) +returncode = gs.run_command("r.mask.status", flags="t", errors="status") # Returns: 1 (if no mask exists) ``` @@ -468,8 +461,8 @@ Configure the *Tools* object to ignore errors and always return result objects: ```python tools_with_returncode = Tools( - errors="ignore", - consistent_return_value=True, + errors="ignore", + consistent_return_value=True, ) result = tools_with_returncode.r_mask_status(flags="t") returncode = result.returncode @@ -630,27 +623,21 @@ import grass.script as gs with gs.setup.init("path/to/project") as session: # Import raster gs.run_command( - "r.import", - input="/path/to/elevation.tif", - output="elevation", - env=session.env + "r.import", input="/path/to/elevation.tif", output="elevation", env=session.env ) - + # Set region gs.run_command("g.region", raster="elevation", env=session.env) - + # Calculate slope gs.run_command( - "r.slope.aspect", - elevation="elevation", - slope="slope", - env=session.env + "r.slope.aspect", elevation="elevation", slope="slope", env=session.env ) - + # Get region info region_info = gs.region(env=session.env) print(f"Rows: {region_info['rows']}") - + # List rasters rasters = gs.list_strings("raster", env=session.env) print(f"Rasters: {rasters}") @@ -664,25 +651,22 @@ from grass.tools import Tools with gs.setup.init("path/to/project") as session: tools = Tools(session=session) - + # Import raster tools.r_import(input="/path/to/elevation.tif", output="elevation") - + # Set region tools.g_region(raster="elevation") - + # Calculate slope tools.r_slope_aspect(elevation="elevation", slope="slope") - + # Get region info region_info = tools.g_region(flags="p", format="json") print(f"Rows: {region_info['rows']}") - + # List rasters - rasters = [ - item["fullname"] - for item in tools.g_list(type="raster", format="json") - ] + rasters = [item["fullname"] for item in tools.g_list(type="raster", format="json")] print(f"Rasters: {rasters}") ``` diff --git a/doc/python_intro.md b/doc/python_intro.md index 5ae951a05a4..4af054d548d 100644 --- a/doc/python_intro.md +++ b/doc/python_intro.md @@ -44,7 +44,6 @@ gs.create_project(path="path/to/my_project", epsg="3358") # Initialize the GRASS session with gs.setup.init("path/to/my_project") as session: - # Run GRASS tools tools = Tools(session=session) tools.r_import(input="/path/to/elevation.tif", output="elevation") @@ -112,10 +111,7 @@ color_scheme = """ 80% #d95f0e 100% #993404 """ -tools.r_colors( - map="elevation", - rules=StringIO(color_scheme) -) +tools.r_colors(map="elevation", rules=StringIO(color_scheme)) ``` The methods will raise *CalledModuleError* if a tool fails. @@ -344,7 +340,7 @@ from grass.pygrass.gis import Mapset mapset = Mapset() # List all rasters in the mapset -rasters = mapset.glist(type='raster') +rasters = mapset.glist(type="raster") ``` For more details about the `gis` module, see the Full Documentation: @@ -385,7 +381,7 @@ from grass.pygrass.gis.region import Region region = Region() # Set the region from the elevation raster -region.from_rast('elevation') +region.from_rast("elevation") # Adjust the region by adding 100 map units # to the east and north @@ -445,8 +441,7 @@ To read all rows of the `elevation` raster: ```python from grass.pygrass import raster -with raster.RasterRow('elevation') as elev: - +with raster.RasterRow("elevation") as elev: # Get the total number of rows nrows = elev.info.rows print(f"Total Rows: {nrows}") @@ -462,13 +457,12 @@ raster, double it, and write the value back to a new raster `elevation_new`. from grass.pygrass import raster # Open the elevation raster in read mode -with raster.RasterRow('elevation') as elev: - +with raster.RasterRow("elevation") as elev: # Read a random row and column value = elev[5][10] # Open the new elevation raster in write mode - with raster.RasterRow('elevation_new', mode='w', mtype="FCELL") as new_elev: + with raster.RasterRow("elevation_new", mode="w", mtype="FCELL") as new_elev: # Sequentially iterate over the rows and columns for row_id, row in enumerate(elev, start=0): # When we reach the row and column we want to change @@ -510,12 +504,11 @@ to check if a vector map exists and print the mapset it is in. from grass.pygrass.vector import Vector # Check if the roads vector map exists -roads = Vector('roadsmajor') +roads = Vector("roadsmajor") if roads.exist(): mapset = roads.mapset print(f"The roads vector map exists in the {mapset} mapset") - ``` With the [VectorTopo](https://grass.osgeo.org/grass-stable/manuals/libpython/pygrass_vector.html#vectortopo-label) @@ -527,14 +520,13 @@ class in addition to read and write access. from grass.pygrass.vector import VectorTopo # Open the roads vector map as a VectorTopo object -with VectorTopo('roadsmajor') as roads: - +with VectorTopo("roadsmajor") as roads: # Get the first feature first_feature = roads.next() print(first_feature) # Get the number of nodes - roads.number_of('nodes') + roads.number_of("nodes") ``` #### Geometry and Attributes @@ -579,7 +571,7 @@ the attributes of the current feature. from grass.pygrass.vector import VectorTopo # Open the roads vector map in read mode -with VectorTopo('roadsmajor') as roads: +with VectorTopo("roadsmajor") as roads: # Read attribute the first feature read_feature = roads.read(1) # Prints the LINESTRING geometry @@ -597,23 +589,22 @@ Here is an example of how to write a new feature to the `roads` vector map. from grass.pygrass.vector import VectorTopo from grass.pygrass.vector.geometry import Line -with VectorTopo('roadsmajor', mode='rw') as roads: - +with VectorTopo("roadsmajor", mode="rw") as roads: # Create a new feature # The tuple is shorthand for a list of Point(x, y) new_geom = Line([(636981.33, 256517.60), (636983.10, 256526.59)]) - + # Get the last cat value (primary key) last_record = roads.read(-1) last_cat = last_record.cat # Create an empty feature from the last record new_dict = {key: None for key in last_record.attrs} - new_dict['cat'] = last_cat + 1 - new_dict['MAJORRDS_'] = 2.0 - new_dict['ROAD_NAME'] = 'New Road' - new_dict['MULTILINE'] = 'No' - new_dict['PROPYEAR'] = 2025 + new_dict["cat"] = last_cat + 1 + new_dict["MAJORRDS_"] = 2.0 + new_dict["ROAD_NAME"] = "New Road" + new_dict["MULTILINE"] = "No" + new_dict["PROPYEAR"] = 2025 # Write the new feature to the vector map roads.write(new_geom, new_dict) @@ -640,12 +631,12 @@ the line segment length is greater than 1000. from grass.pygrass.vector import VectorTopo # Open the roads vector map as a VectorTopo object -with VectorTopo('roadsmajor') as roads: +with VectorTopo("roadsmajor") as roads: # Iterate over each feature in the vector map - for feature in roads.viter('lines'): + for feature in roads.viter("lines"): # Check if the feature is a line and the length is greater than 1000 # And the ROAD_NAME attribute is 'NC-50' - if feature.length() > 1000 and feature.attrs['ROAD_NAME'] == 'NC-50': + if feature.length() > 1000 and feature.attrs["ROAD_NAME"] == "NC-50": print(feature) ``` @@ -665,7 +656,7 @@ import random from grass.pygrass.vector import VectorTopo from grass.pygrass.vector.geometry import Point -with VectorTopo('roadsmajor') as roads: +with VectorTopo("roadsmajor") as roads: # Get the extent of the roads vector map extent = roads.bbox() @@ -675,7 +666,7 @@ with VectorTopo('roadsmajor') as roads: random_point = Point(x, y) # Iterate over each feature in the vector map - for feature in roads.viter('lines'): + for feature in roads.viter("lines"): # Check if the random point is within a 5000 meters of the line line_distance = feature.distance(random_point) if line_distance.dist < 5000: @@ -694,7 +685,7 @@ class for more advanced operations. from grass.pygrass.vector import VectorTopo # Open the roads vector map as a VectorTopo object -roads = VectorTopo('roadsmajor') +roads = VectorTopo("roadsmajor") roads.open("r") # Query the vector map for all features where the @@ -702,7 +693,7 @@ roads.open("r") roads.table_to_dict(where="ROAD_NAME = 'NC-50'") sql_1 = roads.table.filters.get_sql() -# Query the vector map for the first 5 features where the +# Query the vector map for the first 5 features where the # ROAD_NAME attribute is 'NC-70' roads.table.filters.where("ROAD_NAME = 'NC-70'").limit(5) sql_2 = roads.table.filters.get_sql() @@ -789,11 +780,12 @@ color_scheme = """ 80% #d95f0e 100% #993404 """ -gs.write_command("r.colors", - map="elevation", - rules="-", # Read from stdin - stdin=color_scheme - ) +gs.write_command( + "r.colors", + map="elevation", + rules="-", # Read from stdin + stdin=color_scheme, +) ``` ### Tools as objects @@ -809,10 +801,7 @@ tool. from grass.pygrass.modules import Module slope_aspect_tool = Module( - "r.slope.aspect", - elevation='elevation', - slope='slope', - aspect='aspect' + "r.slope.aspect", elevation="elevation", slope="slope", aspect="aspect" ) ``` diff --git a/general/g.findfile/g.findfile.md b/general/g.findfile/g.findfile.md index 053362ac2dc..ab2d471c4a6 100644 --- a/general/g.findfile/g.findfile.md +++ b/general/g.findfile/g.findfile.md @@ -84,7 +84,7 @@ following code: ```python import grass.script as gs -gs.find_file('elevation', element = 'cell') +gs.find_file("elevation", element="cell") ``` Parsing JSON output: diff --git a/general/g.parser/g.parser.md b/general/g.parser/g.parser.md index ae4eca3d6ca..270283d9372 100644 --- a/general/g.parser/g.parser.md +++ b/general/g.parser/g.parser.md @@ -635,11 +635,13 @@ import sys import grass.script as gs + def main(): # put code here return 0 + if __name__ == "__main__": options, flags = gs.parser() sys.exit(main()) diff --git a/lib/init/grass.md b/lib/init/grass.md index 4a5fef16ae3..4bdaf2488bc 100644 --- a/lib/init/grass.md +++ b/lib/init/grass.md @@ -392,15 +392,15 @@ A very simple Python script ("test.py") may look like this: # import GRASS Python bindings (see also pygrass) import grass.script as gs -gs.message('Current GRASS environment:') +gs.message("Current GRASS environment:") print(gs.gisenv()) -gs.message('Available raster maps:') -for raster in gs.list_strings(type='raster'): +gs.message("Available raster maps:") +for raster in gs.list_strings(type="raster"): print(raster) -gs.message('Available vector maps:') -for vector in gs.list_strings(type='vector'): +gs.message("Available vector maps:") +for vector in gs.list_strings(type="vector"): print(vector) ``` diff --git a/man/mkdocs/docs/command_line_intro.md b/man/mkdocs/docs/command_line_intro.md index b2b10724d36..6f867795136 100644 --- a/man/mkdocs/docs/command_line_intro.md +++ b/man/mkdocs/docs/command_line_intro.md @@ -115,10 +115,10 @@ to export the aspect map as a PNG. ```python import grass.script as gs -gs.run_command('g.region', raster='elevation') -gs.run_command('r.slope.aspect', elevation='elevation', slope='slope', aspect='aspect') -gs.run_command('r.colors', map='aspect', color='aspect') -gs.run_command('r.out.png', input='aspect', output='aspect', overwrite=True) +gs.run_command("g.region", raster="elevation") +gs.run_command("r.slope.aspect", elevation="elevation", slope="slope", aspect="aspect") +gs.run_command("r.colors", map="aspect", color="aspect") +gs.run_command("r.out.png", input="aspect", output="aspect", overwrite=True) ``` Now execute the Python script. diff --git a/pyproject.toml b/pyproject.toml index 6ea5dfa580c..75add911fd6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -534,6 +534,8 @@ known-first-party = ["grass"] # Declare a custom aliases, checked with rule ICN001 "grass.script" = "gs" "grass.temporal" = "tgis" +# Ruff 0.17 added a default alias of dt for datetime; keep the existing import style. +datetime = "datetime" [tool.ruff.format] docstring-code-format = true diff --git a/raster/r.horizon/r.horizon.md b/raster/r.horizon/r.horizon.md index 3a47e6c99e0..f837c2074e5 100644 --- a/raster/r.horizon/r.horizon.md +++ b/raster/r.horizon/r.horizon.md @@ -196,12 +196,11 @@ We can plot horizon in polar coordinates using Matplotlib in Python: import numpy as np import matplotlib.pyplot as plt -horizon = np.genfromtxt('horizon.csv', delimiter=',') +horizon = np.genfromtxt("horizon.csv", delimiter=",") horizon = horizon[1:, :] ax = plt.subplot(111, polar=True) -bars = ax.plot(horizon[:, 0] / 180 * np.pi, - (90 - horizon[:, 1]) / 180 * np.pi) +bars = ax.plot(horizon[:, 0] / 180 * np.pi, (90 - horizon[:, 1]) / 180 * np.pi) # uncomment the 2 following lines when using -c flag # ax.set_theta_direction(-1) # ax.set_theta_zero_location('N') diff --git a/raster/r.mask.status/r.mask.status.md b/raster/r.mask.status/r.mask.status.md index f3f76622b42..971ebe912fe 100644 --- a/raster/r.mask.status/r.mask.status.md +++ b/raster/r.mask.status/r.mask.status.md @@ -32,6 +32,7 @@ In Python, use: ```python import grass.script as gs + gs.parse_command("r.mask.status", format="json") ``` diff --git a/raster/r.proj/r.proj.md b/raster/r.proj/r.proj.md index 587232f03f8..f5f8d9ea098 100644 --- a/raster/r.proj/r.proj.md +++ b/raster/r.proj/r.proj.md @@ -291,7 +291,7 @@ using python: ```python import grass.script as gs -# Run the r.proj command to print the input map's bounds in the current +# Run the r.proj command to print the input map's bounds in the current # projection using JSON output format bounds = gs.parse_command( "r.proj", diff --git a/raster/r.solute.transport/r.solute.transport.md b/raster/r.solute.transport/r.solute.transport.md index 1de4cf6bc25..209ff86e9ce 100644 --- a/raster/r.solute.transport/r.solute.transport.md +++ b/raster/r.solute.transport/r.solute.transport.md @@ -99,9 +99,14 @@ gs.message(_("Set the region")) # The area is 200m x 100m with a cell size of 1m x 1m gs.run_command("g.region", res=1, res3=1, t=10, b=0, n=100, s=0, w=0, e=200) gs.run_command("r.mapcalc", expression="phead = if(col() == 1 , 50, 40)") -gs.run_command("r.mapcalc", expression="phead = if(col() ==200 , 45 + row()/40, phead)") +gs.run_command( + "r.mapcalc", expression="phead = if(col() ==200 , 45 + row()/40, phead)" +) gs.run_command("r.mapcalc", expression="status = if(col() == 1 || col() == 200 , 2, 1)") -gs.run_command("r.mapcalc", expression="well = if((row() == 50 && col() == 175) || (row() == 10 && col() == 135) , -0.001, 0)") +gs.run_command( + "r.mapcalc", + expression="well = if((row() == 50 && col() == 175) || (row() == 10 && col() == 135) , -0.001, 0)", +) gs.run_command("r.mapcalc", expression="hydcond = 0.00005") gs.run_command("r.mapcalc", expression="recharge = 0") gs.run_command("r.mapcalc", expression="top_conf = 20") @@ -112,29 +117,80 @@ gs.run_command("r.mapcalc", expression="null = 0.0") gs.message(_("Compute a steady state groundwater flow")) -gs.run_command("r.gwflow", solver="cg", top="top_conf", bottom="bottom", phead="phead",\ - status="status", hc_x="hydcond", hc_y="hydcond", q="well", s="syield",\ - recharge="recharge", output="gwresult_conf", dt=8640000000000, type="confined") +gs.run_command( + "r.gwflow", + solver="cg", + top="top_conf", + bottom="bottom", + phead="phead", + status="status", + hc_x="hydcond", + hc_y="hydcond", + q="well", + s="syield", + recharge="recharge", + output="gwresult_conf", + dt=8640000000000, + type="confined", +) gs.message(_("generate the transport data")) -gs.run_command("r.mapcalc", expression="c = if(col() == 15 && row() == 75 , 500.0, 0.0)") +gs.run_command( + "r.mapcalc", expression="c = if(col() == 15 && row() == 75 , 500.0, 0.0)" +) gs.run_command("r.mapcalc", expression="cs = if(col() == 15 && row() == 75 , 0.0, 0.0)") -gs.run_command("r.mapcalc", expression="tstatus = if(col() == 1 || col() == 200 , 3, 1)") +gs.run_command( + "r.mapcalc", expression="tstatus = if(col() == 1 || col() == 200 , 3, 1)" +) gs.run_command("r.mapcalc", expression="diff = 0.0000001") gs.run_command("r.mapcalc", expression="R = 1.0") # Compute the initial state -gs.run_command("r.solute.transport", solver="bicgstab", top="top_conf",\ - bottom="bottom", phead="gwresult_conf", status="tstatus", hc_x="hydcond", hc_y="hydcond",\ - rd="R", cs="cs", q="well", nf="poros", output="stresult_conf_0", dt=3600, diff_x="diff",\ - diff_y="diff", c="c", al=0.1, at=0.01) +gs.run_command( + "r.solute.transport", + solver="bicgstab", + top="top_conf", + bottom="bottom", + phead="gwresult_conf", + status="tstatus", + hc_x="hydcond", + hc_y="hydcond", + rd="R", + cs="cs", + q="well", + nf="poros", + output="stresult_conf_0", + dt=3600, + diff_x="diff", + diff_y="diff", + c="c", + al=0.1, + at=0.01, +) # Compute the solute transport for 300 days in 10 day steps for dt in range(30): - gs.run_command("r.solute.transport", solver="bicgstab", top="top_conf",\ - bottom="bottom", phead="gwresult_conf", status="tstatus", hc_x="hydcond", hc_y="hydcond",\ - rd="R", cs="cs", q="well", nf="poros", output="stresult_conf_" + str(dt + 1), dt=864000, diff_x="diff",\ - diff_y="diff", c="stresult_conf_" + str(dt), al=0.1, at=0.01) + gs.run_command( + "r.solute.transport", + solver="bicgstab", + top="top_conf", + bottom="bottom", + phead="gwresult_conf", + status="tstatus", + hc_x="hydcond", + hc_y="hydcond", + rd="R", + cs="cs", + q="well", + nf="poros", + output="stresult_conf_" + str(dt + 1), + dt=864000, + diff_x="diff", + diff_y="diff", + c="stresult_conf_" + str(dt), + al=0.1, + at=0.01, + ) ``` ## SEE ALSO diff --git a/raster/r.stats/r.stats.md b/raster/r.stats/r.stats.md index 154faf87dd3..0bb54985ae4 100644 --- a/raster/r.stats/r.stats.md +++ b/raster/r.stats/r.stats.md @@ -103,7 +103,7 @@ in a single raster map: gs.run_command("g.region", raster="geology_30m") data = gs.parse_command("r.stats", flags="a", input="geology_30m", format="json") for record in data: - cat = record['categories'][0]['category'] + cat = record["categories"][0]["category"] print(f"Category {cat}: {record['count']} cells and {record['area'] / 1e6} km2") ``` @@ -180,7 +180,9 @@ category in multiple raster maps (suppress NULL data): import grass.script as gs gs.run_command("g.region", raster="towns") - data = gs.parse_command("r.stats", flags="nacp", input=["towns", "urban"], format="json") + data = gs.parse_command( + "r.stats", flags="nacp", input=["towns", "urban"], format="json" + ) for record in data: categories = [str(cat["category"]) for cat in record["categories"]] print(f"Categories {' and '.join(categories)}: {record['percent']:.2f} %") @@ -259,11 +261,14 @@ Number of intervals are given by **nsteps** option. import grass.script as gs gs.run_command("g.region", raster="elevation") - data = gs.parse_command("r.stats", flags="an", input="elevation", nsteps=5, sort="desc", format="json") + data = gs.parse_command( + "r.stats", flags="an", input="elevation", nsteps=5, sort="desc", format="json" + ) for record in data: - from_to = record['categories'][0]['range'] - print(f"Elevation {from_to['from']:.2f}-{from_to['to']:.2f}: {record['area'] / 1e6:.2f} km2") - + from_to = record["categories"][0]["range"] + print( + f"Elevation {from_to['from']:.2f}-{from_to['to']:.2f}: {record['area'] / 1e6:.2f} km2" + ) ``` Output: @@ -411,7 +416,12 @@ zipcode areas: gs.run_command("g.region", raster="zipcodes") # landuse/landcover, geology and zipcodes with category labels - data = gs.parse_command("r.stats", flags="c", input=["landclass96", "zipcodes", "geology_30m"], format="json") + data = gs.parse_command( + "r.stats", + flags="c", + input=["landclass96", "zipcodes", "geology_30m"], + format="json", + ) print(data[0]) ``` diff --git a/scripts/v.geometry/v.geometry.md b/scripts/v.geometry/v.geometry.md index 15890c24aac..3b572e57842 100644 --- a/scripts/v.geometry/v.geometry.md +++ b/scripts/v.geometry/v.geometry.md @@ -68,7 +68,9 @@ Consume metrics from Python: ```python import grass.script as gs - data = gs.parse_command("v.geometry", map="geology", metric="compactness", format="json") + data = gs.parse_command( + "v.geometry", map="geology", metric="compactness", format="json" + ) for record in data["records"]: print(record["category"], record["compactness"]) ``` diff --git a/temporal/t.rast.list/t.rast.list.md b/temporal/t.rast.list/t.rast.list.md index 7c9b0d22ca7..a572716f9a0 100644 --- a/temporal/t.rast.list/t.rast.list.md +++ b/temporal/t.rast.list/t.rast.list.md @@ -196,9 +196,7 @@ dataset [t.vect.list](t.vect.list.md#using-method-option) ```python result = json.loads( - gs.read_command( - "t.rast.list", input="tempmean_monthly", format="json" - ) + gs.read_command("t.rast.list", input="tempmean_monthly", format="json") ) for item in result["data"]: print(item["name"])