From 9bbfd6bd65554d989f5bbbcd968946c0ebcd339b Mon Sep 17 00:00:00 2001 From: ymdatta Date: Fri, 6 Sep 2024 21:35:45 -0400 Subject: [PATCH 001/209] ps.map: Initialize variable before using it in conditional (#4286) --- ps/ps.map/ps_header.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ps/ps.map/ps_header.c b/ps/ps.map/ps_header.c index fd7eb996588..9a454824d9b 100644 --- a/ps/ps.map/ps_header.c +++ b/ps/ps.map/ps_header.c @@ -16,7 +16,7 @@ extern int rotate_plot; int write_PS_header(void) { struct Categories cats; - int cats_ok; + int cats_ok = 0; if (PS.do_raster) cats_ok = Rast_read_cats(PS.cell_name, PS.cell_mapset, &cats) >= 0; From 102bc38d16df035dbb0b4caf0f16e7fda0d12273 Mon Sep 17 00:00:00 2001 From: Makiko Shukunobe Date: Fri, 6 Sep 2024 21:47:24 -0400 Subject: [PATCH 002/209] checks: Flake8 F841 fixes in the scripts directory part 2 (#4241) * Fix F841 problems in `scripts` directory * Update `.flake8` with fixes for F841 * Remove unused lines based on reviewed suggestions --- .flake8 | 8 ++++---- scripts/r.semantic.label/r.semantic.label.py | 4 ++-- scripts/v.import/v.import.py | 2 -- scripts/v.report/v.report.py | 3 --- scripts/v.unpack/v.unpack.py | 4 ---- 5 files changed, 6 insertions(+), 15 deletions(-) diff --git a/.flake8 b/.flake8 index 18cea9165ce..47fa3239a24 100644 --- a/.flake8 +++ b/.flake8 @@ -158,12 +158,12 @@ per-file-ignores = scripts/r.in.wms/wms_cap_parsers.py: F841 scripts/r.in.wms/wms_drv.py: E402, E722 scripts/r.in.wms/srs.py: E722 - scripts/r.semantic.label/r.semantic.label.py: F841, E501 - scripts/v.report/v.report.py: F841, E721 + scripts/r.semantic.label/r.semantic.label.py: E501 + scripts/v.report/v.report.py: E721 scripts/db.out.ogr/db.out.ogr.py: F841 scripts/g.extension/g.extension.py: F841, E722, E501 - scripts/v.unpack/v.unpack.py: F841, E722, E501 - scripts/v.import/v.import.py: F841, E722, E501 + scripts/v.unpack/v.unpack.py: E722, E501 + scripts/v.import/v.import.py: E722, E501 scripts/db.univar/db.univar.py: E501 scripts/d.frame/d.frame.py: E722 scripts/i.pansharpen/i.pansharpen.py: E722, E501 diff --git a/scripts/r.semantic.label/r.semantic.label.py b/scripts/r.semantic.label/r.semantic.label.py index 53239772117..f3c26320ae3 100644 --- a/scripts/r.semantic.label/r.semantic.label.py +++ b/scripts/r.semantic.label/r.semantic.label.py @@ -62,7 +62,7 @@ def print_map_semantic_label(name, label_reader): label_reader.print_info(semantic_label=semantic_label) else: gs.info(_("No semantic label assigned to <{}>").format(name)) - except OpenError as e: + except OpenError: gs.error(_("Map <{}> not found").format(name)) @@ -94,7 +94,7 @@ def manage_map_semantic_label(name, semantic_label): except GrassError as e: gs.error(_("Unable to assign/dissociate semantic label. {}").format(e)) return 1 - except OpenError as e: + except OpenError: gs.error(_("Map <{}> not found in current mapset").format(name)) return 1 diff --git a/scripts/v.import/v.import.py b/scripts/v.import/v.import.py index 42e5952c76f..4f579c4bf45 100755 --- a/scripts/v.import/v.import.py +++ b/scripts/v.import/v.import.py @@ -257,8 +257,6 @@ def main(): f.write("GUI: text\n") f.close() - tgtsrs = gs.read_command("g.proj", flags="j", quiet=True) - # create temp location from input without import gs.verbose(_("Creating temporary project for <%s>...") % OGRdatasource) try: diff --git a/scripts/v.report/v.report.py b/scripts/v.report/v.report.py index 8da23bbaf91..18752a697cb 100755 --- a/scripts/v.report/v.report.py +++ b/scripts/v.report/v.report.py @@ -216,9 +216,6 @@ def main(): if not flags["c"]: sys.stdout.write(fs.join(colnames + extracolnames) + "\n") - # make and print the table: - numcols = len(colnames) + len(extracolnames) - # calculate percents if requested if units == "percent" and option != "coor": # calculate total value diff --git a/scripts/v.unpack/v.unpack.py b/scripts/v.unpack/v.unpack.py index af430f98829..0507e9eb400 100644 --- a/scripts/v.unpack/v.unpack.py +++ b/scripts/v.unpack/v.unpack.py @@ -215,10 +215,6 @@ def main(): # the db connection in the output mapset dbconn = grassdb.db_connection(force=True) todb = dbconn["database"] - # return all tables - list_fromtable = grass.read_command( - "db.tables", driver="sqlite", database=fromdb - ).splitlines() # return the list of old connection for extract layer number and key dbln = open(os.path.join(new_dir, "dbln"), "r") From 39e1e11fe8349260ba5bfd3794a2e917675cfeb3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 7 Sep 2024 02:53:01 +0000 Subject: [PATCH 003/209] CI(deps): Update alpine:3.20 Docker digest to beefdbd (#4287) --- docker/alpine/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index dfd840263e9..a099617759c 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.20@sha256:0a4eaa0eecf5f8c050e5bba433f58c052be7587ee8af3e8b3910ef9ab5fbe9f5 as common +FROM alpine:3.20@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d as common # Based on: # https://github.com/mundialis/docker-grass-gis/blob/master/Dockerfile From 83ee14690fdd465cd082a8289c5895e9bfc5c732 Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Sat, 7 Sep 2024 14:03:11 -0400 Subject: [PATCH 004/209] grass.app: Move ISIS integration to the library (#4169) Path setup for ISIS was lost in GIS variable setup. This moves it to the library, where other paths and integrations are initialized. The variables are left as is, without further testing. --- lib/init/grass.py | 14 -------------- python/grass/app/runtime.py | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/lib/init/grass.py b/lib/init/grass.py index 87a69f5ef65..82c1ee4a812 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -1073,20 +1073,6 @@ def load_env(grass_env_file): # create a new environment variable os.environ[k] = v - # Allow for mixed ISIS-GRASS Environment - if os.getenv("ISISROOT"): - isis = os.getenv("ISISROOT") - os.environ["ISIS_LIB"] = isis + os.sep + "lib" - os.environ["ISIS_3RDPARTY"] = isis + os.sep + "3rdParty" + os.sep + "lib" - os.environ["QT_PLUGIN_PATH"] = isis + os.sep + "3rdParty" + os.sep + "plugins" - # os.environ['ISIS3DATA'] = isis + "$ISIS3DATA" - libpath = os.getenv("LD_LIBRARY_PATH", "") - isislibpath = os.getenv("ISIS_LIB") - isis3rdparty = os.getenv("ISIS_3RDPARTY") - os.environ["LD_LIBRARY_PATH"] = ( - libpath + os.pathsep + isislibpath + os.pathsep + isis3rdparty - ) - def install_notranslation(): # If locale is not supported, _ function might be missing diff --git a/python/grass/app/runtime.py b/python/grass/app/runtime.py index 5da00bae0df..3f3805c9dfd 100644 --- a/python/grass/app/runtime.py +++ b/python/grass/app/runtime.py @@ -129,6 +129,7 @@ def set_paths(install_path, grass_config_dir, ld_library_path_variable_name): # retrieving second time, but now it is always set addon_base = os.getenv("GRASS_ADDON_BASE") set_man_path(install_path=install_path, addon_base=addon_base, env=os.environ) + set_isis() def set_man_path(install_path, addon_base, env): @@ -274,6 +275,25 @@ def set_browser(install_path): os.environ["GRASS_HTML_BROWSER"] = browser +def set_isis(): + """Enable a mixed ISIS-GRASS environment + + ISIS is Integrated Software for Imagers and Spectrometers by USGS. + """ + if os.getenv("ISISROOT"): + isis = os.getenv("ISISROOT") + os.environ["ISIS_LIB"] = isis + os.sep + "lib" + os.environ["ISIS_3RDPARTY"] = isis + os.sep + "3rdParty" + os.sep + "lib" + os.environ["QT_PLUGIN_PATH"] = isis + os.sep + "3rdParty" + os.sep + "plugins" + # os.environ['ISIS3DATA'] = isis + "$ISIS3DATA" + libpath = os.getenv("LD_LIBRARY_PATH", "") + isislibpath = os.getenv("ISIS_LIB") + isis3rdparty = os.getenv("ISIS_3RDPARTY") + os.environ["LD_LIBRARY_PATH"] = ( + libpath + os.pathsep + isislibpath + os.pathsep + isis3rdparty + ) + + def ensure_home(): """Set HOME if not set on MS Windows""" if WINDOWS and not os.getenv("HOME"): From 98e3fe1f4119329fb9533e7623ea1533ccc009af Mon Sep 17 00:00:00 2001 From: ymdatta Date: Sat, 7 Sep 2024 14:03:49 -0400 Subject: [PATCH 005/209] r.out.png: reset file pointer to NULL after fclose (#4220) This patch continues the work from 917ba58. It's a good practice to immediately reset the file pointer once we do fclose on it, as it prevents using/closing descriptor allocated to another file in the future execution paths. Signed-off-by: Mohan Yelugoti --- raster/r.out.png/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/raster/r.out.png/main.c b/raster/r.out.png/main.c index 4d3895e5d9f..68bcc09ffef 100644 --- a/raster/r.out.png/main.c +++ b/raster/r.out.png/main.c @@ -369,8 +369,10 @@ int main(int argc, char *argv[]) /* G_free (info_ptr); */ png_destroy_write_struct(&png_ptr, &info_ptr); /* al 11/2000 */ - if (fp) + if (fp) { fclose(fp); + fp = NULL; + } if (wld_flag->answer) { if (do_stdout) From d7f4977a2443f48ea64a1df0d633eab24bdfff92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sun, 8 Sep 2024 16:09:48 -0400 Subject: [PATCH 006/209] grass.temporal.stds_export: Use pathlib Path.read_text and Path.write_text (#4293) --- python/grass/temporal/stds_export.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/python/grass/temporal/stds_export.py b/python/grass/temporal/stds_export.py index f2fdd7ca9bf..70dbdcada0f 100644 --- a/python/grass/temporal/stds_export.py +++ b/python/grass/temporal/stds_export.py @@ -29,6 +29,7 @@ import shutil import tarfile import tempfile +from pathlib import Path import grass.script as gs from grass.exceptions import CalledModuleError @@ -402,9 +403,7 @@ def export_stds( # Write projection and metadata proj = gs.read_command("g.proj", flags="j") - proj_file = open(proj_file_name, "w") - proj_file.write(proj) - proj_file.close() + Path(proj_file_name).write_text(proj) init_file = open(init_file_name, "w") # Create the init string @@ -431,9 +430,7 @@ def export_stds( init_file.close() metadata = gs.read_command("t.info", type=type_, input=sp.get_id()) - metadata_file = open(metadata_file_name, "w") - metadata_file.write(metadata) - metadata_file.close() + Path(metadata_file_name).write_text(metadata) read_file = open(read_file_name, "w") if type_ == "strds": From 57cb4d91b3b45d6df75c380969d773d798654da4 Mon Sep 17 00:00:00 2001 From: Makiko Shukunobe Date: Mon, 9 Sep 2024 12:03:56 -0400 Subject: [PATCH 007/209] checks: flake8 F841 (local variable assigned to but never used) fixes in scripts directory part 1 (#4238) --- .flake8 | 4 +--- scripts/d.polar/d.polar.py | 9 --------- scripts/r.in.wms/wms_cap_parsers.py | 2 +- scripts/r.in.wms/wms_gdal_drv.py | 1 - 4 files changed, 2 insertions(+), 14 deletions(-) diff --git a/.flake8 b/.flake8 index 47fa3239a24..8a4bf960bf5 100644 --- a/.flake8 +++ b/.flake8 @@ -153,9 +153,7 @@ per-file-ignores = python/grass/*/*/__init__.py: F401, F403 python/grass/*/*/*/__init__.py: F401, F403 # E402 module level import not at top of file - scripts/d.polar/d.polar.py: F841 - scripts/r.in.wms/wms_gdal_drv.py: F841, E722 - scripts/r.in.wms/wms_cap_parsers.py: F841 + scripts/r.in.wms/wms_gdal_drv.py: E722 scripts/r.in.wms/wms_drv.py: E402, E722 scripts/r.in.wms/srs.py: E722 scripts/r.semantic.label/r.semantic.label.py: E501 diff --git a/scripts/d.polar/d.polar.py b/scripts/d.polar/d.polar.py index 4ef578d5676..f592dd89b63 100755 --- a/scripts/d.polar/d.polar.py +++ b/scripts/d.polar/d.polar.py @@ -202,7 +202,6 @@ def plot_eps(psout): epsscale = 0.1 frameallowance = 1.1 halfframe = 3000 - center = (halfframe, halfframe) scale = halfframe / (outerradius * frameallowance) diagramlinewidth = halfframe / 400 @@ -211,11 +210,6 @@ def plot_eps(psout): diagramfontsize = halfframe / 20 halfframe_2 = halfframe * 2 - averagedirectioncolor = 1 # (blue) - diagramcolor = 4 # (red) - circlecolor = 2 # (green) - axescolor = 0 # (black) - northjustification = 2 eastjustification = 6 southjustification = 8 @@ -287,7 +281,6 @@ def plot_eps(psout): ) outf.write(s) - sublength = len(outercircle) - 2 (x, y) = outercircle[1] outf.write("%.2f %.2f moveto\n" % (x * scale + halfframe, y * scale + halfframe)) for x, y in outercircle[2:]: @@ -343,7 +336,6 @@ def plot_eps(psout): ) 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)) for x, y in sine_cosine_replic[2:]: @@ -369,7 +361,6 @@ def plot_eps(psout): 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)) for x, y in vector[2:]: diff --git a/scripts/r.in.wms/wms_cap_parsers.py b/scripts/r.in.wms/wms_cap_parsers.py index f9b0f7095fb..5483be0979f 100644 --- a/scripts/r.in.wms/wms_cap_parsers.py +++ b/scripts/r.in.wms/wms_cap_parsers.py @@ -131,7 +131,7 @@ def _checkFormats(self, capability): """!Check if format element is defined.""" request = self._find(capability, "Request") get_map = self._find(request, "GetMap") - formats = self._findall(get_map, "Format") + self._findall(get_map, "Format") def _checkLayerTree(self, parent_layer, first=True): """!Recursively check layer tree and manage inheritance in the tree""" diff --git a/scripts/r.in.wms/wms_gdal_drv.py b/scripts/r.in.wms/wms_gdal_drv.py index 6d30f5817f3..d17bac11eee 100644 --- a/scripts/r.in.wms/wms_gdal_drv.py +++ b/scripts/r.in.wms/wms_gdal_drv.py @@ -60,7 +60,6 @@ def _createXML(self): gdal_wms = ET.Element("GDAL_WMS") service = ET.SubElement(gdal_wms, "Service") - name = ET.Element("name") service.set("name", "WMS") version = ET.SubElement(service, "Version") From 7c6c12bf98f5bf405372ee692b880d8b295c2177 Mon Sep 17 00:00:00 2001 From: ymdatta Date: Mon, 9 Sep 2024 12:07:01 -0400 Subject: [PATCH 008/209] v.external: Check for valid list before passing to qsort (#4280) Currently, if 'HAVE_OGR' macro is defined, as part of execution, we order all formats by name using qsort. But, list containing all formats is assigned based on a conditional and if the conditional fails, it can be NULL. Behavior of qsort is undefined when a NULL ptr is passed as array argument. To avoid getting into that situation, check if the array is NULL before performing qsort on it. This issue was found using cppcheck tool. Signed-off-by: Mohan Yelugoti --- vector/v.external/list.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vector/v.external/list.c b/vector/v.external/list.c index 900aede55ab..6c94ea69deb 100644 --- a/vector/v.external/list.c +++ b/vector/v.external/list.c @@ -64,7 +64,8 @@ char **format_list(int *count, size_t *len) } /* order formats by name */ - qsort(list, *count, sizeof(char *), cmp); + if (list) + qsort(list, *count, sizeof(char *), cmp); #endif #if defined HAVE_POSTGRES && !defined HAVE_OGR list = G_realloc(list, ((*count) + 1) * sizeof(char *)); From b1c8d10e0870005ff87344a37eb4438f9daa5420 Mon Sep 17 00:00:00 2001 From: Ondrej Pesek Date: Mon, 9 Sep 2024 19:34:45 +0200 Subject: [PATCH 009/209] wxGUI/gmodeler: dialogs code refactoring (#3816) * g.gui.gmodeler: start refactoring * assign results from _getLabel() directly instead of using intermediate vars * do not run Getlabel() if not needed * VariableListCtrl: simplify (no need to run one loop twice) --- gui/wxpython/gmodeler/dialogs.py | 77 ++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/gui/wxpython/gmodeler/dialogs.py b/gui/wxpython/gmodeler/dialogs.py index 0b4038b7b50..7cd7cbd1147 100644 --- a/gui/wxpython/gmodeler/dialogs.py +++ b/gui/wxpython/gmodeler/dialogs.py @@ -56,17 +56,10 @@ def __init__(self, parent, shape, title=_("Data properties")): self.parent = parent self.shape = shape - label, etype = self._getLabel() - self.etype = etype + label, self.etype = self._getLabel() SimpleDialog.__init__(self, parent, title) - self.element = Select( - parent=self.panel, - type=self.shape.GetPrompt(), - validator=SimpleValidator(callback=self.ValidatorCallback), - ) - if shape.GetValue(): - self.element.SetValue(shape.GetValue()) + self.element = self._createElementControl(shape) self.Bind(wx.EVT_BUTTON, self.OnOK, self.btnOK) self.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel) @@ -86,6 +79,18 @@ def __init__(self, parent, shape, title=_("Data properties")): self._layout() self.SetMinSize(self.GetSize()) + def _createElementControl(self, shape): + """Create Select element and set its value.""" + element = Select( + parent=self.panel, + type=self.shape.GetPrompt(), + validator=SimpleValidator(callback=self.ValidatorCallback), + ) + if shape.GetValue(): + element.SetValue(shape.GetValue()) + + return element + def _getLabel(self): etype = False prompt = self.shape.GetPrompt() @@ -549,6 +554,11 @@ def GetCondition(self): """Get loop condition""" return self.condText.GetValue() + def SetSizes(self): + """Set default and minimal size.""" + self.SetMinSize(self.GetSize()) + self.SetSize((500, 400)) + class ModelLoopDialog(ModelItemDialog): """Loop properties dialog""" @@ -573,8 +583,7 @@ def __init__( self.btnSeries.Bind(wx.EVT_BUTTON, self.OnSeries) self._layout() - self.SetMinSize(self.GetSize()) - self.SetSize((500, 400)) + self.SetSizes() def _layout(self): """Do layout""" @@ -664,8 +673,7 @@ def __init__( self.itemListElse.Populate(self.parent.GetModel().GetItems()) self._layout() - self.SetMinSize(self.GetSize()) - self.SetSize((500, 400)) + self.SetSizes() def _layout(self): """Do layout""" @@ -745,21 +753,27 @@ def __init__( listmix.ListCtrlAutoWidthMixin.__init__(self) listmix.TextEditMixin.__init__(self) - i = 0 - for col in columns: - self.InsertColumn(i, col) - self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER) - i += 1 + self.InsertColumns(columns) self.itemDataMap = {} # requested by sorter self.itemCount = 0 + self.BindButtons() + + def BindButtons(self): + """Bind signals to buttons.""" self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit) self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnEndEdit) self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick) self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightUp) # wxMSW self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) # wxGTK + def InsertColumns(self, columns): + """INsert columns and set their width.""" + for i, col in enumerate(columns): + self.InsertColumn(i, col) + self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER) + def OnBeginEdit(self, event): """Editing of item started""" column = event.GetColumn() @@ -799,7 +813,7 @@ def GetData(self): def Populate(self, data): """Populate the list""" - self.itemDataMap = {} + self.DeleteAllItems() i = 0 for name, values in data.items(): self.itemDataMap[i] = [ @@ -808,20 +822,16 @@ def Populate(self, data): values.get("value", ""), values.get("description", ""), ] - i += 1 - - self.itemCount = len(self.itemDataMap.keys()) - self.DeleteAllItems() - i = 0 - for name, vtype, value, desc in self.itemDataMap.values(): index = self.InsertItem(i, name) self.SetItem(index, 0, name) - self.SetItem(index, 1, vtype) - self.SetItem(index, 2, value) - self.SetItem(index, 3, desc) + self.SetItem(index, 1, values["type"]) + self.SetItem(index, 2, values.get("value", "")) + self.SetItem(index, 3, values.get("description", "")) self.SetItemData(index, i) i += 1 + self.itemCount = len(data) + def Append(self, name, vtype, value, desc): """Append new item to the list @@ -1140,11 +1150,12 @@ def OnBeginEdit(self, event): def OnCheckItem(self, index, flag): """Item checked/unchecked""" - name = self.GetLabel() - if name == "IfBlockList" and self.window: - self.window.OnCheckItemIf(index, flag) - elif name == "ElseBlockList" and self.window: - self.window.OnCheckItemElse(index, flag) + if self.window: + name = self.GetLabel() + if name == "IfBlockList": + self.window.OnCheckItemIf(index, flag) + elif name == "ElseBlockList": + self.window.OnCheckItemElse(index, flag) def GetItems(self): """Get list of selected actions""" From cc2797c9f85afb4efb512fb755d902ecf780477f Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Mon, 9 Sep 2024 14:38:18 -0400 Subject: [PATCH 010/209] r.univar: fix MASK check with nprocs > 1 (#4297) --- raster/r.univar/r.univar_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/raster/r.univar/r.univar_main.c b/raster/r.univar/r.univar_main.c index 84550a87347..805acfff27b 100644 --- a/raster/r.univar/r.univar_main.c +++ b/raster/r.univar/r.univar_main.c @@ -192,6 +192,10 @@ int main(int argc, char *argv[]) sscanf(param.nprocs->answer, "%d", &nprocs); if (nprocs < 1) G_fatal_error(_("<%d> is not valid number of nprocs."), nprocs); + if (nprocs > 1 && G_find_raster("MASK", G_mapset()) != NULL) { + G_warning(_("Parallel processing disabled due to active MASK.")); + nprocs = 1; + } #if defined(_OPENMP) omp_set_num_threads(nprocs); #else @@ -200,10 +204,6 @@ int main(int argc, char *argv[]) "threads setting.")); nprocs = 1; #endif - if (nprocs > 1 && G_find_raster("MASK", G_mapset()) != NULL) { - G_warning(_("Parallel processing disabled due to active MASK.")); - nprocs = 1; - } /* table field separator */ zone_info.sep = G_option_to_separator(param.separator); From 258752c774dc0412dd5ce9ff68088ee276c41e48 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 18:47:43 +0000 Subject: [PATCH 011/209] CI(deps): Update DeterminateSystems/nix-installer-action action to v14 (#4298) --- .github/workflows/test-nix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-nix.yml b/.github/workflows/test-nix.yml index a73ac835414..22fa4f0061f 100644 --- a/.github/workflows/test-nix.yml +++ b/.github/workflows/test-nix.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Install nix - uses: DeterminateSystems/nix-installer-action@ab6bcb2d5af0e904d04aea750e2089e9dc4cbfdd # v13 + uses: DeterminateSystems/nix-installer-action@da36cb69b1c3247ad7a1f931ebfd954a1105ef14 # v14 - name: Setup cachix uses: cachix/cachix-action@ad2ddac53f961de1989924296a1f236fcfbaa4fc # v15 From b9c19ab5475c7c24b617eb75adaf5851c69fec09 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:53:54 -0400 Subject: [PATCH 012/209] CI(deps): Update ruff to v0.6.4 (#4279) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * CI(deps): Update ruff to v0.6.4 * style: Fix List index lookup in `enumerate()` loop (PLR1736) in __writeNvizState * style: Fix Unnecessary lookup of dictionary value by key (PLR1733) in iscatt_core.py * style: Fix `enumerate` index is unused, use `for plane in constants` instead (FURB148) in __writeNvizState --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Edouard Choinière <27212526+echoix@users.noreply.github.com> --- .github/workflows/python-code-quality.yml | 2 +- .pre-commit-config.yaml | 2 +- gui/wxpython/core/workspace.py | 8 ++++---- gui/wxpython/iscatt/iscatt_core.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index caa530e3b39..17cce1c09aa 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.7.9" # renovate: datasource=pypi depName=ruff - RUFF_VERSION: "0.6.3" + RUFF_VERSION: "0.6.4" runs-on: ${{ matrix.os }} permissions: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f12fde12473..a5221f29efe 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: ) - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.6.3 + rev: v0.6.4 hooks: # Run the linter. - id: ruff diff --git a/gui/wxpython/core/workspace.py b/gui/wxpython/core/workspace.py index 7e5f85d6649..63f8b91cb89 100644 --- a/gui/wxpython/core/workspace.py +++ b/gui/wxpython/core/workspace.py @@ -1608,15 +1608,15 @@ def __writeNvizState(self, view, iview, light, constants): if constants: self.file.write("%s\n" % (" " * self.indent)) self.indent += 4 - for idx, plane in enumerate(constants): + for plane in constants: self.file.write("%s\n" % (" " * self.indent)) self.indent += 4 - self.__writeTagWithValue("height", constants[idx]["constant"]["value"]) + self.__writeTagWithValue("height", plane["constant"]["value"]) self.__writeTagWithValue( - "fine_resolution", constants[idx]["constant"]["resolution"] + "fine_resolution", plane["constant"]["resolution"] ) self.__writeTagWithValue( - "color", constants[idx]["constant"]["color"], format="s" + "color", plane["constant"]["color"], format="s" ) self.indent -= 4 self.file.write("%s\n" % (" " * self.indent)) diff --git a/gui/wxpython/iscatt/iscatt_core.py b/gui/wxpython/iscatt/iscatt_core.py index 97da83415e8..91ac00014a5 100644 --- a/gui/wxpython/iscatt/iscatt_core.py +++ b/gui/wxpython/iscatt/iscatt_core.py @@ -531,7 +531,7 @@ def SetData(self, cats): # if key is missing condition is always True (full scatter plor # is computed) if scatt_id in self.cats[cat_id]: - self.cats[cat_id][scatt_id]["np_vals"] = cats[cat_id][scatt_id][ + self.cats[cat_id][scatt_id]["np_vals"] = scatt_ids[scatt_id][ "np_vals" ] From 85efe798c6106a18d562799a64453787ebc5a63f Mon Sep 17 00:00:00 2001 From: ymdatta Date: Mon, 9 Sep 2024 17:03:03 -0400 Subject: [PATCH 013/209] v.out.ogr: Check for valid array before passing to qsort (#4278) Currently, filling list with GDAL driver names is based on a conditional and if the conditional fails, the list can be NULL. We pass this list to qsort to sort the names, but behavior of qsort with a NULL array is undefined. To avoid getting into this situation, check if the array is NULL before performing qsort on it. This issue was found using cppcheck tool. Signed-off-by: Mohan Yelugoti --- vector/v.out.ogr/list.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vector/v.out.ogr/list.c b/vector/v.out.ogr/list.c index 0df74cf5dac..2b80111de3e 100644 --- a/vector/v.out.ogr/list.c +++ b/vector/v.out.ogr/list.c @@ -43,7 +43,8 @@ char *OGR_list_write_drivers(void) len += strlen(buf) + 1; /* + ',' */ } - qsort(list, count, sizeof(char *), cmp); + if (list) + qsort(list, count, sizeof(char *), cmp); if (len > 0) { ret = G_malloc((len + 1) * sizeof(char)); /* \0 */ From 997624b5bfa4e8141d5b742367d51fef97273efb Mon Sep 17 00:00:00 2001 From: Chung-Yuan Liang <77927944+cyliang368@users.noreply.github.com> Date: Mon, 9 Sep 2024 20:31:43 -0400 Subject: [PATCH 014/209] r.proj: Create unit tests (#4225) * create unit tests for r.proj * change the source project * update the validation values according to the map in the project * remove shell cmd, update doc, modify precision --- raster/r.proj/testsuite/test_rproj.py | 186 ++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 raster/r.proj/testsuite/test_rproj.py diff --git a/raster/r.proj/testsuite/test_rproj.py b/raster/r.proj/testsuite/test_rproj.py new file mode 100644 index 00000000000..5f3834be881 --- /dev/null +++ b/raster/r.proj/testsuite/test_rproj.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python + +############################################################################## +# MODULE: r.proj +# +# AUTHOR(S): Chung-Yuan Liang +# +# PURPOSE: Unit tests for r.proj +# +# COPYRIGHT: (C) 2024 Chung-Yuan Liang 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. +############################################################################## + +from grass.gunittest.case import TestCase +from grass.gunittest.gmodules import call_module +import shutil + +raster_info = """north=35.8096296297222 +south=35.6874074075 +east=-78.608 +west=-78.7746666666667 +nsres=0.000740740740740727 +ewres=0.000666666666666686 +rows=165 +cols=250 +cells=41250""" + +src_project = "nc_spm_full_v2alpha2" +dst_project = "nc_latlong" + + +class TestRasterreport(TestCase): + input = "elevation" + + @classmethod + def setUpClass(cls): + cls.runModule("g.proj", project=dst_project, epsg="4326", flags="c") + cls.runModule("g.mapset", mapset="PERMANENT", project=dst_project) + + @classmethod + def tearDownClass(cls): + cls.runModule("g.mapset", mapset="PERMANENT", project=src_project) + dbase = call_module("g.gisenv", get="GISDBASE") + shutil.rmtree(f"{dbase}/{dst_project}") + + def run_rproj_test(self, method, statics): + """The main function to run r.proj check rsults according to the method + + Parameters + ---------- + method : str + The method to be used for r.proj + statics : str + The expected statics of the output raster + """ + output = method + ## Get the boundary and set up region for the projected map + stdout = call_module( + "r.proj", + project=src_project, + mapset="PERMANENT", + input=self.input, + method=method, + flags="g", + ) + settings = dict([line.split("=") for line in stdout.split()]) + + call_module( + "g.region", + n=settings["n"], + s=settings["s"], + e=settings["e"], + w=settings["w"], + rows=settings["rows"], + cols=settings["cols"], + flags="a", + res=1, + ) + + ## Project the map + self.assertModule( + "r.proj", + project=src_project, + mapset="PERMANENT", + input=self.input, + output=output, + method=method, + quiet=True, + ) + + ## Validate the output + self.assertRasterFitsUnivar(output, reference=statics, precision=1e-7) + self.assertRasterFitsInfo(output, reference=raster_info, precision=1e-7) + + def test_nearest(self): + """Testing method nearest""" + ## Set up variables and validation values + method = "nearest" + statics = """n=40930 + min=55.5787925720215 + max=156.038833618164 + mean=110.377538633405 + variance=412.751942806146""" + + self.run_rproj_test(method, statics) + + def test_bilinear(self): + """Testing method bilinear""" + ## Set up variables and validation values + method = "bilinear" + statics = """n=40845 + min=56.3932914733887 + max=156.053298950195 + mean=110.389074372679 + variance=411.487781666933""" + + self.run_rproj_test(method, statics) + + def test_bicubic(self): + """Testing method bicubic""" + ## Set up variables and validation values + method = "bicubic" + statics = """n=40677 + min=56.2407836914062 + max=156.061599731445 + mean=110.41701776258 + variance=411.382636894393""" + + self.run_rproj_test(method, statics) + + def test_lanczos(self): + """Testing method lanczos""" + ## Set up variables and validation values + method = "lanczos" + statics = """n=40585 + min=56.2350921630859 + max=156.066345214844 + mean=110.421826400841 + variance=411.6875834341575""" + + self.run_rproj_test(method, statics) + + def test_bilinear_f(self): + """Testing method bilinear_f""" + ## Set up variables and validation values + method = "bilinear_f" + statics = """n=40930 + min=55.5787925720215 + max=156.053298950195 + mean=110.376211041027 + variance=412.553041205029""" + + self.run_rproj_test(method, statics) + + def test_bicubic_f(self): + """Testing method bicubic_f""" + ## Set up variables and validation values + method = "bicubic_f" + statics = """n=40930 + min=55.5787925720215 + max=156.061599731445 + mean=110.375897704515 + variance=412.693308000461""" + + self.run_rproj_test(method, statics) + + def test_lanczos_f(self): + """Testing method lanczos_f""" + ## Set up variables and validation values + method = "lanczos_f" + statics = """n=40930 + min=55.5787925720215 + max=156.066345214844 + mean=110.375715222838 + variance=412.695433658258""" + + self.run_rproj_test(method, statics) + + +if __name__ == "__main__": + from grass.gunittest.main import test + + test() From a85c7b0b828152cd0e3aaa3f56d1b438bd137863 Mon Sep 17 00:00:00 2001 From: ymdatta Date: Tue, 10 Sep 2024 05:58:23 -0400 Subject: [PATCH 015/209] v.vol.rst: Initialize structure contents before passing it around (#4282) * v.vol.rst: Initialize structure contents before passing it around `skip_point` structure is not initialized when declared. This was found using cppcheck tool. Only when `cv` is true, `skip_point` contents are filled and the structure is used. cppcheck raised the issue when 'cv' is false. Technically, we don't need skip_point in such cases and not initializing it won't affect the execution. Nevertheless, it's a good practice to initialize structure contents at the time of declaration. Signed-off-by: Mohan Yelugoti * Use correct literal for double type Co-authored-by: Nicklas Larsson --------- Signed-off-by: Mohan Yelugoti Co-authored-by: Nicklas Larsson --- vector/v.vol.rst/user2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vector/v.vol.rst/user2.c b/vector/v.vol.rst/user2.c index 64f7b4a67f2..49a36d39175 100644 --- a/vector/v.vol.rst/user2.c +++ b/vector/v.vol.rst/user2.c @@ -92,6 +92,7 @@ int interp_call(struct octtree *root, struct octtree *tree) int skip_index, segtest; double xx, yy, zz /*, ww */; + skip_point.x = skip_point.y = skip_point.z = skip_point.w = 0.0; if (tree == NULL) return -1; if (tree->data == NULL) From 76507cc9ba7ad1259569bc0730592b4860c1a3b9 Mon Sep 17 00:00:00 2001 From: ymdatta Date: Tue, 10 Sep 2024 05:59:10 -0400 Subject: [PATCH 016/209] v.generalize: Initialize all of structure contents before using it (#4281) * v.generalize: Initialize all of structure contents before using it Currently, in `head` which is a `POINT_LIST` structure, we are only initializing the next pointer to NULL, but data present in the point substructure is not initialized which implies that it would be filled with random data. To avoid such scenario, initialize point coordinates to zero. This was found using cppcheck tool. Signed-off-by: Mohan Yelugoti * Use correct literal for double type Co-authored-by: Nicklas Larsson --------- Signed-off-by: Mohan Yelugoti Co-authored-by: Nicklas Larsson --- vector/v.generalize/smoothing.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vector/v.generalize/smoothing.c b/vector/v.generalize/smoothing.c index d5a817f8f2f..0b5d9a5e12f 100644 --- a/vector/v.generalize/smoothing.c +++ b/vector/v.generalize/smoothing.c @@ -422,6 +422,7 @@ int hermite(struct line_pnts *Points, double step, double angle_thresh, angle_thresh *= M_PI / 180.0; head.next = NULL; + head.p.x = head.p.y = head.p.z = 0.0; point = last = &head; if (!is_loop) { From adcdf28bb2ff1b4602bf7df898a8040ba1f1309e Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Tue, 10 Sep 2024 11:40:14 -0400 Subject: [PATCH 017/209] t.rast.accumulate: remove printing (#4301) --- temporal/t.rast.accumulate/t.rast.accumulate.py | 1 - 1 file changed, 1 deletion(-) diff --git a/temporal/t.rast.accumulate/t.rast.accumulate.py b/temporal/t.rast.accumulate/t.rast.accumulate.py index 3ad82fe9ed3..94344f2d9cc 100644 --- a/temporal/t.rast.accumulate/t.rast.accumulate.py +++ b/temporal/t.rast.accumulate/t.rast.accumulate.py @@ -483,7 +483,6 @@ def main(): if method: accmod.inputs["method"].value = method - print(accmod) accmod.run() if accmod.returncode != 0: From e4fdf904c32f90c96c038d4cb2c5f67e6cc0da81 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Wed, 11 Sep 2024 08:31:52 -0400 Subject: [PATCH 018/209] CI: Resolve flake8 issues in utils directory (#4303) * resolved flake8 in utils * updated .flake8 --------- Co-authored-by: Arohan Ajit --- .flake8 | 1 - utils/gitlog2changelog.py | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.flake8 b/.flake8 index 8a4bf960bf5..32021622d7d 100644 --- a/.flake8 +++ b/.flake8 @@ -21,7 +21,6 @@ per-file-ignores = # E741 ambiguous variable name 'l' __init__.py: F401, F403 lib/init/grass.py: E722, F821, F841 - utils/gitlog2changelog.py: E722, E712 man/build_check_rest.py: F403, F405 man/build_full_index_rest.py: F403, F405 man/parser_standard_options.py: F403, F405 diff --git a/utils/gitlog2changelog.py b/utils/gitlog2changelog.py index 2626321d6fb..758b142196b 100755 --- a/utils/gitlog2changelog.py +++ b/utils/gitlog2changelog.py @@ -66,8 +66,8 @@ author = authorList[1] author = author[0 : len(author) - 1] authorFound = True - except: - print("Could not parse authorList = '%s'" % (line)) + except Exception as e: + print(f"Could not parse authorList = '{line}'. Error: {e!s}") # Match the date line elif line.startswith("Date:"): @@ -76,8 +76,8 @@ date = dateList[1] date = date[0 : len(date) - 1] dateFound = True - except: - print("Could not parse dateList = '%s'" % (line)) + except Exception as e: + print(f"Could not parse dateList = '{line}'. Error: {e!s}") # The Fossil-IDs are ignored: elif line.startswith(" Fossil-ID:") or line.startswith(" [[SVN:"): continue From 569c730be0eb42de9f31eae1c8e78f7ee7cb7e92 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2024 17:17:11 -0400 Subject: [PATCH 019/209] CI(deps): Update docker/dockerfile Docker tag to v1.10 (#4305) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Dockerfile | 2 +- docker/ubuntu/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 23bf11ddf27..aba1df48a1d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1.9@sha256:fe40cf4e92cd0c467be2cfc30657a680ae2398318afd50b0c80585784c604f28 +# syntax=docker/dockerfile:1.10@sha256:865e5dd094beca432e8c0a1d5e1c465db5f998dca4e439981029b3b81fb39ed5 # Note: This file must be kept in sync in ./Dockerfile and ./docker/ubuntu/Dockerfile. # Changes to this file must be copied over to the other file. diff --git a/docker/ubuntu/Dockerfile b/docker/ubuntu/Dockerfile index 23bf11ddf27..aba1df48a1d 100644 --- a/docker/ubuntu/Dockerfile +++ b/docker/ubuntu/Dockerfile @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1.9@sha256:fe40cf4e92cd0c467be2cfc30657a680ae2398318afd50b0c80585784c604f28 +# syntax=docker/dockerfile:1.10@sha256:865e5dd094beca432e8c0a1d5e1c465db5f998dca4e439981029b3b81fb39ed5 # Note: This file must be kept in sync in ./Dockerfile and ./docker/ubuntu/Dockerfile. # Changes to this file must be copied over to the other file. From 5719ba6fd51158a88fb7ce1850a4651e61c7e344 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Wed, 11 Sep 2024 20:59:21 -0400 Subject: [PATCH 020/209] CI: Update .flake8 configuration and fix flake8 errors in lib/init/grass.py (#4289) * fixed flake8 errors in lib/init/grass.py * fixed flake8 details .flake8 --- .flake8 | 1 - lib/init/grass.py | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.flake8 b/.flake8 index 32021622d7d..5d3f2fca5d0 100644 --- a/.flake8 +++ b/.flake8 @@ -20,7 +20,6 @@ per-file-ignores = # F841 local variable assigned to but never used # E741 ambiguous variable name 'l' __init__.py: F401, F403 - lib/init/grass.py: E722, F821, F841 man/build_check_rest.py: F403, F405 man/build_full_index_rest.py: F403, F405 man/parser_standard_options.py: F403, F405 diff --git a/lib/init/grass.py b/lib/init/grass.py index 82c1ee4a812..5a62e65ac53 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -484,7 +484,7 @@ def create_gisrc(tmpdir, gisrcrc): if "UNKNOWN" in s: try_remove(gisrcrc) s = None - except: + except Exception: s = None # Copy the global grassrc file to the session grassrc file @@ -1162,7 +1162,7 @@ def set_language(grass_config_dir): encoding = "UTF-8" normalized = locale.normalize("%s.%s" % (language, encoding)) locale.setlocale(locale.LC_ALL, normalized) - except locale.Error as e: + except locale.Error: if language == "en": # A workaround for Python Issue30755 # https://bugs.python.org/issue30755 @@ -1188,7 +1188,7 @@ def set_language(grass_config_dir): # See bugs #3441 and #3423 try: locale.setlocale(locale.LC_ALL, "C.UTF-8") - except locale.Error as e: + except locale.Error: # All lost. Setting to C as much as possible. # We can not call locale.normalize on C as it # will transform it to en_US and we already know @@ -1571,7 +1571,7 @@ def say_hello(): revision = linerev.split(" ")[1] sys.stderr.write(" (" + revision + ")") - except: + except Exception: pass @@ -1937,7 +1937,7 @@ def print_params(params): try: revision = linerev.split(" ")[1] sys.stdout.write("%s\n" % revision[1:]) - except: + except Exception: sys.stdout.write("No SVN revision defined\n") elif arg == "version": sys.stdout.write("%s\n" % GRASS_VERSION) From dda0fb26bb4b62059cf3d7986227709cbecb279d Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Thu, 12 Sep 2024 08:22:54 -0400 Subject: [PATCH 021/209] lib/db: Fix copy into fixed size buffer issue in SQLite driver (#4255) * drivers: copy into fixed size buffer issue * Requested changes * without variable * Update db/drivers/sqlite/db.c Co-authored-by: Nicklas Larsson * Use Db statements --------- Co-authored-by: Nicklas Larsson --- db/drivers/sqlite/db.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/db/drivers/sqlite/db.c b/db/drivers/sqlite/db.c index 518ba6c978c..cd86e4648f6 100644 --- a/db/drivers/sqlite/db.c +++ b/db/drivers/sqlite/db.c @@ -78,7 +78,11 @@ int db__driver_open_database(dbHandle *handle) G_free_tokens(tokens); } else { - strcpy(name2, name); + if (G_strlcpy(name2, name, sizeof(name2)) >= sizeof(name2)) { + db_d_append_error(_("Database name <%s> is too long"), name); + db_d_report_error(); + return DB_FAILED; + } } G_debug(2, "name2 = '%s'", name2); @@ -114,11 +118,20 @@ int db__driver_open_database(dbHandle *handle) else { G_warning(_("The sqlite config option '%s' is not supported"), "SQLITE_CONFIG_URI"); - strcpy(name3, name2); + if (G_strlcpy(name3, name2, sizeof(name3)) >= sizeof(name3)) { + db_d_append_error(_("Database name <%s> is too long"), name2); + db_d_report_error(); + return DB_FAILED; + } + } + } + else { + if (G_strlcpy(name3, name2, sizeof(name3)) >= sizeof(name3)) { + db_d_append_error(_("Database name <%s> is too long"), name2); + db_d_report_error(); + return DB_FAILED; } } - else - strcpy(name3, name2); if (sqlite3_open(name3, &sqlite) != SQLITE_OK) { db_d_append_error("%s %s\n%s", _("Unable to open database:"), name3, (char *)sqlite3_errmsg(sqlite)); @@ -184,11 +197,20 @@ int db__driver_create_database(dbHandle *handle) else { G_warning(_("The sqlite config option '%s' is not supported"), "SQLITE_CONFIG_URI"); - strcpy(name2, name); + if (G_strlcpy(name2, name, sizeof(name2)) >= sizeof(name2)) { + db_d_append_error(_("Database name <%s> is too long"), name); + db_d_report_error(); + return DB_FAILED; + } + } + } + else { + if (G_strlcpy(name2, name, sizeof(name2)) >= sizeof(name2)) { + db_d_append_error(_("Database name <%s> is too long"), name); + db_d_report_error(); + return DB_FAILED; } } - else - strcpy(name2, name); if (sqlite3_open(name2, &sqlite) != SQLITE_OK) { db_d_append_error("%s %s\n%s", _("Unable to create database:"), name, (char *)sqlite3_errmsg(sqlite)); From 4d5184d5d59a4950ee3c608798b423775472394e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:37:17 +0000 Subject: [PATCH 022/209] CI(deps): Update peter-evans/create-pull-request action to v7.0.2 (#4311) --- .github/workflows/periodic_update.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/periodic_update.yml b/.github/workflows/periodic_update.yml index 346fd12e2d2..ce03bf8e281 100644 --- a/.github/workflows/periodic_update.yml +++ b/.github/workflows/periodic_update.yml @@ -33,7 +33,7 @@ jobs: run: git status --ignored - name: Create Pull Request id: cpr - uses: peter-evans/create-pull-request@8867c4aba1b742c39f8d0ba35429c2dfa4b6cb20 # v7.0.1 + uses: peter-evans/create-pull-request@d121e62763d8cc35b5fb1710e887d6e69a52d3a4 # v7.0.2 with: commit-message: "config.guess + config.sub: updated from http://git.savannah.gnu.org/cgit/config.git/plain/" branch: periodic/update-configure From 5de8682c5bdf122f832619926010abbc811395cc Mon Sep 17 00:00:00 2001 From: rohannallamadge Date: Thu, 12 Sep 2024 20:58:38 +0530 Subject: [PATCH 023/209] GUI: fix ColumnSorterMixin regression (#4310) * fixing TypeError ColumnSorterMixin #4277 * #4277 fix ColumnSorterMixin error --- gui/wxpython/gcp/manager.py | 2 +- gui/wxpython/image2target/ii2t_manager.py | 2 +- gui/wxpython/photo2image/ip2i_manager.py | 2 +- gui/wxpython/vnet/widgets.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gui/wxpython/gcp/manager.py b/gui/wxpython/gcp/manager.py index ac006a95cbf..749cbf79efb 100644 --- a/gui/wxpython/gcp/manager.py +++ b/gui/wxpython/gcp/manager.py @@ -1272,7 +1272,7 @@ def InitMapDisplay(self): # initialize column sorter self.itemDataMap = self.mapcoordlist ncols = self.list.GetColumnCount() - ColumnSorterMixin(self, ncols) + ColumnSorterMixin.__init__(self, ncols) # noqa: PLC2801, C2801 # init to ascending sort on first click self._colSortFlag = [1] * ncols diff --git a/gui/wxpython/image2target/ii2t_manager.py b/gui/wxpython/image2target/ii2t_manager.py index 4aec0eeba5e..17811ceceb1 100644 --- a/gui/wxpython/image2target/ii2t_manager.py +++ b/gui/wxpython/image2target/ii2t_manager.py @@ -1257,7 +1257,7 @@ def InitMapDisplay(self): # initialize column sorter self.itemDataMap = self.mapcoordlist ncols = self.list.GetColumnCount() - ColumnSorterMixin(self, ncols) + ColumnSorterMixin.__init__(self, ncols) # noqa: PLC2801, C2801 # init to ascending sort on first click self._colSortFlag = [1] * ncols diff --git a/gui/wxpython/photo2image/ip2i_manager.py b/gui/wxpython/photo2image/ip2i_manager.py index 2a9ae19d26a..f251a1fa36e 100644 --- a/gui/wxpython/photo2image/ip2i_manager.py +++ b/gui/wxpython/photo2image/ip2i_manager.py @@ -625,7 +625,7 @@ def InitMapDisplay(self): # initialize column sorter self.itemDataMap = self.mapcoordlist ncols = self.list.GetColumnCount() - ColumnSorterMixin(self, ncols) + ColumnSorterMixin.__init__(self, ncols) # noqa: PLC2801, C2801 # init to ascending sort on first click self._colSortFlag = [1] * ncols diff --git a/gui/wxpython/vnet/widgets.py b/gui/wxpython/vnet/widgets.py index 2690ba57ab4..12477cc93ea 100644 --- a/gui/wxpython/vnet/widgets.py +++ b/gui/wxpython/vnet/widgets.py @@ -133,7 +133,7 @@ def __init__( # initialize column sorter self.itemDataMap = [] ncols = self.GetColumnCount() - ColumnSorterMixin.__init__(self, ncols) + ColumnSorterMixin.__init__(self, ncols) # noqa: PLC2801, C2801 # init to ascending sort on first click self._colSortFlag = [1] * ncols From 8c23c2ea61ff96ab8d161dacf6102bcf73f49cda Mon Sep 17 00:00:00 2001 From: Makiko Shukunobe Date: Thu, 12 Sep 2024 11:49:18 -0400 Subject: [PATCH 024/209] Checks: flake8 F841 (local variable assigned to but never used) fixes in the temporal directory (#4229) --- .flake8 | 7 ++----- temporal/t.rast.what/t.rast.what.py | 1 - temporal/t.vect.algebra/t.vect.algebra.py | 1 - 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/.flake8 b/.flake8 index 5d3f2fca5d0..4afa5809c80 100644 --- a/.flake8 +++ b/.flake8 @@ -169,13 +169,10 @@ per-file-ignores = scripts/v.what.strds/v.what.strds.py: E722, E501 # Line too long (esp. module interface definitions) scripts/*/*.py: E501 - # local variable 'column' is assigned to but never used temporal/t.rast.to.vect/t.rast.to.vect.py: E501 - # local variable 'stdstype' is assigned to but never used - temporal/t.vect.algebra/t.vect.algebra.py: F841, E501 + temporal/t.vect.algebra/t.vect.algebra.py: E501 # ## used (##% key: r etc) - # local variable 'map_list' is assigned to but never used - temporal/t.rast.what/t.rast.what.py: E265, E266, F841, E501 + temporal/t.rast.what/t.rast.what.py: E265, E266, E501 # Line too long (esp. module interface definitions) temporal/*/*.py: E501 diff --git a/temporal/t.rast.what/t.rast.what.py b/temporal/t.rast.what/t.rast.what.py index 9fa4ad5d793..6a4efbb2b94 100755 --- a/temporal/t.rast.what/t.rast.what.py +++ b/temporal/t.rast.what/t.rast.what.py @@ -466,7 +466,6 @@ def one_point_per_col_output( for count in range(len(output_files)): file_name = output_files[count] gs.verbose(_("Transforming r.what output file %s" % (file_name))) - map_list = output_time_list[count] in_file = open(file_name, "r") lines = in_file.readlines() diff --git a/temporal/t.vect.algebra/t.vect.algebra.py b/temporal/t.vect.algebra/t.vect.algebra.py index 5da83398404..852df8c3afe 100644 --- a/temporal/t.vect.algebra/t.vect.algebra.py +++ b/temporal/t.vect.algebra/t.vect.algebra.py @@ -64,7 +64,6 @@ def main(): expression = options["expression"] basename = options["basename"] spatial = flags["s"] - stdstype = "stvds" # Check for PLY istallation try: From b7bcd066e99893a521019f3ef6a497163f304d9e Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Thu, 12 Sep 2024 12:59:10 -0400 Subject: [PATCH 025/209] CI: Fix Flake8 linter errors in man/ directory (#4292) * resolved some more flake8 warnings * fixed all man flake8 errors except buildhtml * Update .flake8 --------- Co-authored-by: Arohan Ajit --- .flake8 | 11 ----------- man/build_check.py | 2 +- man/build_check_rest.py | 2 +- man/build_class.py | 15 ++++++++++++++- man/build_class_rest.py | 14 +++++++++++++- man/build_full_index.py | 16 +++++++++++++++- man/build_full_index_rest.py | 15 ++++++++++++++- man/build_index.py | 9 ++++++++- man/build_index_rest.py | 9 ++++++++- man/build_keywords.py | 18 ++++++++++++------ man/build_topics.py | 16 ++++++++++++---- 11 files changed, 98 insertions(+), 29 deletions(-) diff --git a/.flake8 b/.flake8 index 4afa5809c80..3182812dd1d 100644 --- a/.flake8 +++ b/.flake8 @@ -20,17 +20,6 @@ per-file-ignores = # F841 local variable assigned to but never used # E741 ambiguous variable name 'l' __init__.py: F401, F403 - man/build_check_rest.py: F403, F405 - man/build_full_index_rest.py: F403, F405 - man/parser_standard_options.py: F403, F405 - man/build_class.py: F403, F405 - man/build_class_rest.py: F403, F405 - man/build_check.py: F403, F405 - man/build_full_index.py: F403, F405 - man/build_index.py: F403, F405 - man/build_index_rest.py: F403, F405 - man/build_keywords.py: F403, F405, E722 - man/build_topics.py: F403, F405, E722 man/build_html.py: E501 imagery/i.atcorr/create_iwave.py: F632, F821, W293 doc/python/raster_example_ctypes.py: F403, F405 diff --git a/man/build_check.py b/man/build_check.py index 6111a4dbe9f..9d9675fb7ac 100644 --- a/man/build_check.py +++ b/man/build_check.py @@ -9,7 +9,7 @@ import sys import os -from build_html import * +from build_html import html_dir, message_tmpl, html_files, read_file os.chdir(html_dir) diff --git a/man/build_check_rest.py b/man/build_check_rest.py index 159be8453db..f9868dfd697 100644 --- a/man/build_check_rest.py +++ b/man/build_check_rest.py @@ -9,7 +9,7 @@ import sys import os -from build_rest import * +from build_rest import rest_dir, message_tmpl, rest_files, read_file os.chdir(rest_dir) diff --git a/man/build_class.py b/man/build_class.py index 8300c62079f..564fb5c20e6 100644 --- a/man/build_class.py +++ b/man/build_class.py @@ -9,7 +9,20 @@ import sys import os -from build_html import * +from build_html import ( + html_dir, + write_html_header, + grass_version, + modclass_intro_tmpl, + modclass_tmpl, + to_title, + html_files, + check_for_desc_override, + get_desc, + desc2_tmpl, + write_html_footer, + replace_file, +) no_intro_page_classes = ["display", "general", "miscellaneous", "postscript"] diff --git a/man/build_class_rest.py b/man/build_class_rest.py index c1de3d623d0..05aec125d04 100644 --- a/man/build_class_rest.py +++ b/man/build_class_rest.py @@ -9,7 +9,19 @@ import sys import os -from build_rest import * +from build_rest import ( + rest_dir, + grass_version, + modclass_intro_tmpl, + modclass_tmpl, + desc2_tmpl, + write_rest_header, + write_rest_footer, + rest_files, + check_for_desc_override, + get_desc, + replace_file, +) os.chdir(rest_dir) diff --git a/man/build_full_index.py b/man/build_full_index.py index 76379787905..ead5167cbb1 100644 --- a/man/build_full_index.py +++ b/man/build_full_index.py @@ -9,7 +9,21 @@ import sys import os -from build_html import * +from build_html import ( + html_dir, + grass_version, + html_files, + write_html_header, + write_html_footer, + check_for_desc_override, + get_desc, + replace_file, + to_title, + full_index_header, + toc, + cmd2_tmpl, + desc1_tmpl, +) year = None if len(sys.argv) > 1: diff --git a/man/build_full_index_rest.py b/man/build_full_index_rest.py index 14167df0f84..26183505393 100644 --- a/man/build_full_index_rest.py +++ b/man/build_full_index_rest.py @@ -8,7 +8,20 @@ import os -from build_rest import * +from build_rest import ( + rest_dir, + rest_files, + write_rest_header, + grass_version, + full_index_header, + sections, + cmd2_tmpl, + check_for_desc_override, + get_desc, + desc1_tmpl, + write_rest_footer, + replace_file, +) os.chdir(rest_dir) diff --git a/man/build_index.py b/man/build_index.py index 5a01787afe3..12de7f01162 100644 --- a/man/build_index.py +++ b/man/build_index.py @@ -9,7 +9,14 @@ import sys import os -from build_html import * +from build_html import ( + html_dir, + grass_version, + write_html_header, + write_html_cmd_overview, + write_html_footer, + replace_file, +) os.chdir(html_dir) diff --git a/man/build_index_rest.py b/man/build_index_rest.py index 68463bbb753..b919042e4af 100644 --- a/man/build_index_rest.py +++ b/man/build_index_rest.py @@ -9,7 +9,14 @@ import os -from build_rest import * +from build_rest import ( + rest_dir, + grass_version, + write_rest_header, + write_rest_cmd_overview, + write_rest_footer, + replace_file, +) os.chdir(rest_dir) diff --git a/man/build_keywords.py b/man/build_keywords.py index 477c1a131ff..6070fad1a28 100644 --- a/man/build_keywords.py +++ b/man/build_keywords.py @@ -21,7 +21,13 @@ import os import sys import glob -from build_html import * +from build_html import ( + grass_version, + header1_tmpl, + headerkeywords_tmpl, + write_html_footer, +) + blacklist = [ "Display", @@ -81,17 +87,17 @@ def get_module_man_html_file_path(module): try: index_keys = lines.index("

KEYWORDS

\n") + 1 index_desc = lines.index("

NAME

\n") + 1 - except: + except Exception: continue try: keys = lines[index_keys].split(",") - except: + except Exception: continue for key in keys: key = key.strip() try: key = key.split(">")[1].split("<")[0] - except: + except Exception: pass if not key: sys.exit("Empty keyword from file %s line: %s" % (fname, lines[index_keys])) @@ -104,10 +110,10 @@ def get_module_man_html_file_path(module): for black in blacklist: try: del keywords[black] - except: + except Exception: try: del keywords[black.lower()] - except: + except Exception: continue for key in sorted(keywords.keys()): diff --git a/man/build_topics.py b/man/build_topics.py index bd0606d1aeb..be5f2962d2c 100644 --- a/man/build_topics.py +++ b/man/build_topics.py @@ -6,7 +6,15 @@ import os import sys import glob -from build_html import * +from build_html import ( + grass_version, + header1_tmpl, + headertopics_tmpl, + headerkey_tmpl, + desc1_tmpl, + moduletopics_tmpl, + write_html_footer, +) path = sys.argv[1] year = os.getenv("VERSION_DATE") @@ -24,16 +32,16 @@ try: index_keys = lines.index("

KEYWORDS

\n") + 1 index_desc = lines.index("

NAME

\n") + 1 - except: + except Exception: continue try: key = lines[index_keys].split(",")[1].strip().replace(" ", "_") key = key.split(">")[1].split("<")[0] - except: + except Exception: continue try: desc = lines[index_desc].split("-", 1)[1].strip() - except: + except Exception: desc.strip() if key not in keywords.keys(): keywords[key] = {} From 9aeabc14fe862f5b7dd10ea4ca831c123eeb737c Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Thu, 12 Sep 2024 16:04:01 -0400 Subject: [PATCH 026/209] contributing: update style guide for C (#4312) --- doc/development/style_guide.md | 137 ++++++++++++++++++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/doc/development/style_guide.md b/doc/development/style_guide.md index 8268114ad5d..8f1d5ab5245 100644 --- a/doc/development/style_guide.md +++ b/doc/development/style_guide.md @@ -75,7 +75,7 @@ flake8 --ignore=E203,E266,E501 --max-line-length=88 python_file.py C and C++ code is formatted with [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html). Contributions are -expected to be formatted with `clang-format` (currently with version 15+). The +expected to be formatted with `clang-format` (currently with version 18+). The most convenient method to install clang-format and format files is [using pre-commit](#using-pre-commit). @@ -92,6 +92,38 @@ If using pre-commit is not an option, for whatever reason, there is a helper script [grass_clang_format.sh](./utils/grass_clang_format.sh), which simplifies bulk reformatting. +#### Order of include headers + +In general, headers should be included in the order: + +1. Core system headers (stdio.h, ctype.h, ...) +2. Headers for non-core system components (X11, libraries). +3. GRASS headers (grass/gis.h, grass/glocale.h, ...) +4. Headers for the specific library/program (geodesic.h, ...) + +Each class of headers has an obligation to be compatible with those above it in +the list, but not those below it. The header groups should be alphabetically +sorted and separated by a newline. + +```c +#include +#include +#include + +#include +#include +#include + +#include "local_proto.h" +#include "mask.h" +``` + +#### Naming conventions + +Use function names which fulfill the official [GNU naming +convention](https://www.gnu.org/prep/standards/html_node/Names.html). Instead of +naming a function like: MyNewFunction() use snake case: my_new_function()`. + ### Using pre-commit It is highly recommended to install and use [pre-commit](https://pre-commit.com) @@ -652,6 +684,30 @@ standard tool output if it has one. ### Developing GRASS Addons +To streamline the development of a GRASS addon in python, you can use [this +template](https://github.com/OSGeo/grass-addon-cookiecutter) powered by +Cookiecutter. + +#### Copyright header + +Use the following header in your source code. + +```python +############################################################################## +# MODULE: r.foo +# +# AUTHOR(S): John Doe +# +# PURPOSE: Provide short description of module here... +# +# COPYRIGHT: (C) 2024 by John Doe and the GRASS Development Team +# +# This program is free software under the GNU General Public +# License (>=v2). Read the file COPYING that comes with GRASS +# for details. +############################################################################## +``` + #### Use Standard Options in Interface GRASS tools must use the GRASS parser to handle its command line parameters. To @@ -887,3 +943,82 @@ self.bwizard = wx.Button(..., # GTC %s will be replaced with name of current shell gs.message(_("Running through {}").format(shellname)) ``` + +### Developing C tools + +Refer to the [online GRASS Programmer's +Manual](​https://grass.osgeo.org/programming8/) or generate it with `make +htmldocs` or `make pdfdocs`. + +#### Use GRASS library functions + +Use the GRASS library functions, when available, instead of the standard C +functions. The reason for this is that the following functions ensure good +programming practice (e.g. always checking if memory was allocated) and/or +improves portability. + +- Memory management: `G_malloc()`, `G_calloc()`, `G_realloc()`, `G_free()` +- Environmental variables: `G_getenv()`, `G_setenv()`, `G_unsetenv()` +- File seek: `G_fseek()`, `G_ftell()` +- Printing: `G_asprintf()`, `G_vsaprintf()`, `G_vfaprintf()`, ... + +Please refer to [the programmers manual](https://grass.osgeo.org/programming8/) +for the proper use (e.g., determining if any casts are needed for arguments or +return values) of these library functions. They may perform a task slightly +different from their corresponding C library function, and thus, their use may +not be the same. + +#### Returning value of main function + +Tool exit status is defined as `EXIT_SUCCESS` or `EXIT_FAILURE` (declared in +`stdlib.h`), e.g. + +```c + { + ... + if (G_parser (argc, argv)) + exit (EXIT_FAILURE); + + ... + exit (EXIT_SUCCESS); + } +``` + +#### Messages and data output + +See rules for [messages in Python scripts](#messages) for proper usage of +`G_fatal_error()`, `G_warning()`, etc. Message output is not expected to be sent +to pipe or file. + +For data output redirected to pipe or file, please use `fprintf()` and specify +the stdout stream as follows: + +```c + fprintf(stdout, ...); + fflush(stdout); + + fflush(stdout) /* always required when using fprintf(stdout, ...). */ +``` + +#### Header section + +Add a header section to file main.c of your tool and make sure you include the +copyright. If you are modifying an existing file you may under no circumstances +remove prior copyright or licensing text that is not your own, even for a major +rewrite. If any original code or code that is in part derived from another's +original work remains, it must be properly cited. + +```c +/**************************************************************************** + * + * MODULE: g.foo + * AUTHOR(S): John Doe + * PURPOSE: Provide short description of module here... + * COPYRIGHT: (C) 2010 by John Doe, and the GRASS Development Team + * + * This program is free software under the GNU General Public + * License (>=v2). Read the COPYING file that comes with GRASS + * for details. + * + *****************************************************************************/ +``` From d77f4575f36c686005f0a786b0d13bf0542be7bb Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Thu, 12 Sep 2024 18:12:59 -0400 Subject: [PATCH 027/209] ps.map: Fix copy into fixed size buffer issue in do_scalebar.c (#4307) --- ps/ps.map/do_scalebar.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ps/ps.map/do_scalebar.c b/ps/ps.map/do_scalebar.c index a53325172f3..760a6825288 100644 --- a/ps/ps.map/do_scalebar.c +++ b/ps/ps.map/do_scalebar.c @@ -2,6 +2,7 @@ #include #include +#include #include #include "local_proto.h" #include "distance.h" @@ -182,17 +183,17 @@ int do_scalebar(void) /* draw units label */ if (sb.units == SB_UNITS_AUTO) - strcpy(num, G_database_unit_name(TRUE)); + (void)G_strlcpy(num, G_database_unit_name(TRUE), sizeof(num)); else if (sb.units == SB_UNITS_METERS) - strcpy(num, _("meters")); + (void)G_strlcpy(num, _("meters"), sizeof(num)); else if (sb.units == SB_UNITS_KM) - strcpy(num, _("kilometers")); + (void)G_strlcpy(num, _("kilometers"), sizeof(num)); else if (sb.units == SB_UNITS_FEET) - strcpy(num, _("feet")); + (void)G_strlcpy(num, _("feet"), sizeof(num)); else if (sb.units == SB_UNITS_MILES) - strcpy(num, _("miles")); + (void)G_strlcpy(num, _("miles"), sizeof(num)); else if (sb.units == SB_UNITS_NMILES) - strcpy(num, _("nautical miles")); + (void)G_strlcpy(num, _("nautical miles"), sizeof(num)); text_box_path(72.0 * (x + length / 2), 72.0 * (PS.page_height - (sb.y + 0.075)), CENTER, UPPER, num, From 2c1df9f89b308b6f0bb3df45763d92ff00c986a6 Mon Sep 17 00:00:00 2001 From: Martin Landa Date: Fri, 13 Sep 2024 13:13:33 +0200 Subject: [PATCH 028/209] GUI: gmodeler fix adding tool (#4309) * revert 2cf98da * fix regression introduced in f99780c --- gui/wxpython/gmodeler/model.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gui/wxpython/gmodeler/model.py b/gui/wxpython/gmodeler/model.py index b243f0beb5c..41fcfe6614f 100644 --- a/gui/wxpython/gmodeler/model.py +++ b/gui/wxpython/gmodeler/model.py @@ -941,8 +941,9 @@ def GetRelations(self, fdir=None): result = [] for rel in self.rels: - if fdir == "from" and rel.GetFrom() == self: - result.append(rel) + if fdir == "from": + if rel.GetFrom() == self: + result.append(rel) elif rel.GetTo() == self: result.append(rel) @@ -1577,7 +1578,7 @@ def _defineShape(self, width, height, x, y): :param width, height: dimension of the shape :param x, y: position of the shape """ - ogl.EllipseShape(self, width, height) + ogl.EllipseShape.__init__(self, width, height) # noqa: PLC2801, C2801 if self.parent.GetCanvas(): self.SetCanvas(self.parent.GetCanvas()) @@ -1592,7 +1593,7 @@ def _defineShape(self, width, height, x, y): :param width, height: dimension of the shape :param x, y: position of the shape """ - ogl.CompositeShape(self) + ogl.CompositeShape.__init__(self) # noqa: PLC2801, C2801 if self.parent.GetCanvas(): self.SetCanvas(self.parent.GetCanvas()) From cd5f1bd277c1beb7e5fdfa7f3b4db0caf26f6c51 Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Fri, 13 Sep 2024 14:00:45 +0200 Subject: [PATCH 029/209] lib/gis: Add portable G_strlcat function (#4304) Add wrapper function for strlcat(), using system function if available, otherwise uses implementation by Todd C. Miller originated from https://github.com/openbsd/src/blob/e291b8af02e5c2b53d7ddb1f0c9c0fd608b97d45/lib/libc/string/strlcat.c. G_strlcat() is a safer alternative to strcat(). --- configure | 17 +++++++- configure.ac | 3 ++ include/grass/config.h.in | 9 +++-- include/grass/defs/gis.h | 3 ++ lib/gis/strlcat.c | 84 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 lib/gis/strlcat.c diff --git a/configure b/configure index 7d8b9b1e5e7..bc60ae7c41c 100755 --- a/configure +++ b/configure @@ -765,8 +765,9 @@ SOCKLIB ICONVLIB DLLIB MATHLIB -HAVE_ASPRINTF HAVE_STRLCPY +HAVE_STRLCAT +HAVE_ASPRINTF DBMIEXTRALIB USE_X11 XTLIB @@ -8312,6 +8313,19 @@ then : fi + + +ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat" +if test "x$ac_cv_func_strlcat" = xyes +then : + printf "%s\n" "#define HAVE_STRLCAT 1" >>confdefs.h + +fi + + + +# Test if strlcpy exists +# This is a function part of *BSD libc (optionally available on Linux via libbsd) ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" if test "x$ac_cv_func_strlcpy" = xyes then : @@ -8320,6 +8334,7 @@ then : fi + # Test if mathlib needs -lm flag or is included with libc ac_fn_c_check_func "$LINENO" "atan" "ac_cv_func_atan" if test "x$ac_cv_func_atan" = xyes diff --git a/configure.ac b/configure.ac index 8ef6e1b9f7c..b38a2a5936c 100644 --- a/configure.ac +++ b/configure.ac @@ -595,6 +595,9 @@ AC_SUBST(DBMIEXTRALIB) AC_CHECK_FUNCS(asprintf) AC_SUBST(HAVE_ASPRINTF) +AC_CHECK_FUNCS(strlcat) +AC_SUBST(HAVE_STRLCAT) + # Test if strlcpy exists # This is a function part of *BSD libc (optionally available on Linux via libbsd) AC_CHECK_FUNCS(strlcpy) diff --git a/include/grass/config.h.in b/include/grass/config.h.in index f070b4ccc0d..95dc2bc034b 100644 --- a/include/grass/config.h.in +++ b/include/grass/config.h.in @@ -14,9 +14,6 @@ /* Define to 1 if you have the `asprintf' function. */ #undef HAVE_ASPRINTF -/* Define to 1 if you have the `strlcpy' function. */ -#undef HAVE_STRLCPY - /* Define to 1 if you have the header file. */ #undef HAVE_BZLIB_H @@ -239,6 +236,12 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H +/* Define to 1 if you have the `strlcat' function. */ +#undef HAVE_STRLCAT + +/* Define to 1 if you have the `strlcpy' function. */ +#undef HAVE_STRLCPY + /* Define to 1 if you have the header file. */ #undef HAVE_SVM_H diff --git a/include/grass/defs/gis.h b/include/grass/defs/gis.h index 4125a3aeed3..dc5ad2499f0 100644 --- a/include/grass/defs/gis.h +++ b/include/grass/defs/gis.h @@ -152,6 +152,9 @@ int G_vfaprintf(FILE *, const char *, va_list); int G_vsaprintf(char *, const char *, va_list); int G_vsnaprintf(char *, size_t, const char *, va_list); +/* strlcat.c */ +size_t G_strlcat(char *, const char *, size_t); + /* strlcpy.c */ size_t G_strlcpy(char *, const char *, size_t); diff --git a/lib/gis/strlcat.c b/lib/gis/strlcat.c new file mode 100644 index 00000000000..ed6c3887e72 --- /dev/null +++ b/lib/gis/strlcat.c @@ -0,0 +1,84 @@ +/*! + * \file lib/gis/strlcat.c + * + * \brief GIS Library - GRASS implementation of strlcat(). + * + * If available, G_strlcat() calls system strlcat(), otherwise it uses + * implementation by Todd C. Miller of OpenBSD. + * + * Addition to GRASS GIS by Nicklas Larsson, 2024 + * + * Original OpenBSD implementation notes: + * + * Copyright (c) 1998, 2015 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +/** + * \brief Size-bounded string concatenation + * + * Appends string src to the end of dst. It will append at most + * dstsize - strlen(dst) - 1 characters. It will then NUL-terminate, unless + * dstsize is 0 or the original dst string was longer than dstsize (in practice + * this should not happen as it means that either dstsize is incorrect or that + * dst is not a proper string). + * + * If the src and dst strings overlap, the behavior is undefined. + * This function is a safer alternative to strncat. + * + * \param[out] dst Pointer to the destination buffer. Must be a NUL-terminated + * C string. + * \param[in] src Pointer to the source string, which will be appended. Must + * be a NUL-terminated C string. + * \param[in] dsize The size of the destination buffer. + * + * \return The total length of the string src, which was attempted to be + * created (the initial length of dst plus the length of src, not + * including the terminating NUL character). If the return value + * is >= dsize, truncation occurred. + */ + +size_t G_strlcat(char *restrict dst, const char *restrict src, size_t dsize) +{ +#ifdef HAVE_STRLCAT + return strlcat(dst, src, dsize); +#else + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') + dst++; + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) + return (dlen + strlen(src)); + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; + + return (dlen + (src - osrc)); /* count does not include NUL */ +#endif +} From 7dbb49bc701c06a2c39b1d5a7b48e85b71b914c2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2024 17:25:31 +0000 Subject: [PATCH 030/209] CI(deps): Update github/codeql-action action to v3.26.7 (#4314) --- .github/workflows/codeql-analysis.yml | 4 ++-- .github/workflows/python-code-quality.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 05d4581b689..b4562dd75c8 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -56,7 +56,7 @@ jobs: if: ${{ matrix.language == 'c-cpp' }} - name: Initialize CodeQL - uses: github/codeql-action/init@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3.26.6 + uses: github/codeql-action/init@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -81,6 +81,6 @@ jobs: run: .github/workflows/build_ubuntu-22.04.sh "${HOME}/install" - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3.26.6 + uses: github/codeql-action/analyze@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 17cce1c09aa..f5810fbe7c2 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -135,7 +135,7 @@ jobs: path: bandit.sarif - name: Upload SARIF File into Security Tab - uses: github/codeql-action/upload-sarif@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3.26.6 + uses: github/codeql-action/upload-sarif@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7 with: sarif_file: bandit.sarif From d2f347782adee4f9a8f7e3a3c1dd48fd65884145 Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Fri, 13 Sep 2024 13:47:31 -0400 Subject: [PATCH 031/209] lib: Accept more newline styles in G_getl (#3853) Use G_getl2 in G_getl to have everywhere the same behavior of supporting all newlines. Originally, G_getl2 was created to keep the behavior of G_getl. However, now, we want G_getl2 behavior everywhere. Keeping G_getl2 for compatibility. Code can later be clean up to use only G_getl, probably at the time when G_getl2 is removed (v9). The new test fails without the change in the library for CRLF for G_getl, but passes with the change. CR fails because it is not supported by fgets used since 88090da (#3850), so expecting failure for CR. Return and argument types for ctypes fopen need to be set for the code to work everywhere reliably. --------- Co-authored-by: Nicklas Larsson --- lib/gis/getl.c | 16 ++--- lib/gis/testsuite/test_gis_lib_getl.py | 81 ++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 11 deletions(-) create mode 100644 lib/gis/testsuite/test_gis_lib_getl.py diff --git a/lib/gis/getl.c b/lib/gis/getl.c index 7daae816a70..34df9b04ad0 100644 --- a/lib/gis/getl.c +++ b/lib/gis/getl.c @@ -19,8 +19,7 @@ * \brief Gets a line of text from a file * * This routine runs fgets() to fetch a line of text from a file - * (advancing file pointer) and removes trailing newline. fgets() does - * not recognize '\\r' as an EOL and will read past * it. + * (advancing file pointer) and removes trailing newline. * * \param buf string buffer to receive read data * \param n maximum number of bytes to read @@ -28,23 +27,18 @@ * * \return 1 on success * \return 0 EOF + * + * \see G_getl2() */ int G_getl(char *buf, int n, FILE *fd) { - if (!fgets(buf, n, fd)) - return 0; - - for (; *buf && *buf != '\n'; buf++) - ; - *buf = 0; - - return 1; + return G_getl2(buf, n, fd); } /*! * \brief Gets a line of text from a file of any pedigree * - * This routine is like G_getl() but is more portable. It supports + * This routine supports * text files created on various platforms (UNIX, MacOS9, DOS), * i.e. \\n (\\012), \\r (\\015), and * \\r\\n (\\015\\012) style newlines. diff --git a/lib/gis/testsuite/test_gis_lib_getl.py b/lib/gis/testsuite/test_gis_lib_getl.py new file mode 100644 index 00000000000..98092955ab2 --- /dev/null +++ b/lib/gis/testsuite/test_gis_lib_getl.py @@ -0,0 +1,81 @@ +"""Test of gis library line reading functions + +@author Vaclav Petras +""" + +import ctypes +import pathlib +import platform +import unittest + +import grass.lib.gis as libgis +from grass.gunittest.case import TestCase +from grass.gunittest.main import test + + +class TestNewlinesWithGetlFunctions(TestCase): + """Test C functions G_getl() and G_getl2() from gis library""" + + @classmethod + def setUpClass(cls): + cls.libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("c")) + cls.libc.fopen.restype = ctypes.POINTER(libgis.FILE) + cls.libc.fopen.argtypes = [ctypes.c_char_p, ctypes.c_char_p] + cls.file_path = pathlib.Path("test.txt") + + def tearDown(self): + self.file_path.unlink() + + def read_lines_and_assert(self, get_line_function, newline): + """Write and read lines and then assert they are as expected""" + lines = ["Line 1", "Line 2", "Line 3"] + with open(self.file_path, mode="w", newline=newline) as stream: + for line in lines: + # Python text newline here. + # The specific newline is added by the stream. + stream.write(f"{line}\n") + + file_ptr = self.libc.fopen(str(self.file_path).encode("utf-8"), b"r") + if not file_ptr: + raise FileNotFoundError(f"Could not open file: {self.file_path}") + + try: + buffer_size = 50 + buffer = ctypes.create_string_buffer(buffer_size) + + for line in lines: + get_line_function(buffer, ctypes.sizeof(buffer), file_ptr) + result = buffer.value.decode("utf-8") if buffer else None + self.assertEqual(line, result) + finally: + self.libc.fclose(file_ptr) + + def test_getl_lf(self): + r"""Check G_getl() with LF (\n)""" + self.read_lines_and_assert(libgis.G_getl, "\n") + + @unittest.expectedFailure + def test_getl_cr(self): + r"""Check G_getl() with CR (\r)""" + self.read_lines_and_assert(libgis.G_getl, "\r") + + def test_getl_crlf(self): + r"""Check G_getl() with CRLF (\r\n)""" + self.read_lines_and_assert(libgis.G_getl, "\r\n") + + def test_getl2_lf(self): + r"""Check G_getl2() with LF (\n)""" + self.read_lines_and_assert(libgis.G_getl2, "\n") + + @unittest.expectedFailure + def test_getl2_cr(self): + r"""Check G_getl2() with CR (\r)""" + self.read_lines_and_assert(libgis.G_getl2, "\r") + + def test_getl2_crlf(self): + r"""Check G_getl2() with CRLF (\r\n)""" + self.read_lines_and_assert(libgis.G_getl2, "\r\n") + + +if __name__ == "__main__": + test() From 95da3efa40fec6dc6058479cadca524f79b34dcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 14 Sep 2024 10:34:03 -0400 Subject: [PATCH 032/209] style: Fix all flake8-gettext (INT) errors (INT001, INT002, INT003) (#4052) * style: Fix all flake8-gettext (INT) errors (INT001, INT002, INT003) Ruff rules: https://docs.astral.sh/ruff/rules/f-string-in-get-text-func-call/ https://docs.astral.sh/ruff/rules/format-in-get-text-func-call/ https://docs.astral.sh/ruff/rules/printf-in-get-text-func-call/ * Revert source string changes when unneeded. * Update univar_statistics.py Co-authored-by: Vaclav Petras * Update panels.py for Python script type string * Update pyedit.py to keep path keyword in changed string * Update univar_statistics.py to make already translated strings match again * Update pyedit.py * Update model.py --------- Co-authored-by: Vaclav Petras --- general/g.parser/test.py | 6 +- gui/wxpython/animation/dialogs.py | 6 +- gui/wxpython/animation/temporal_manager.py | 2 +- gui/wxpython/core/debug.py | 4 +- gui/wxpython/core/render.py | 2 +- gui/wxpython/gcp/manager.py | 9 +- gui/wxpython/gmodeler/model.py | 11 +-- gui/wxpython/gmodeler/panels.py | 28 +++--- gui/wxpython/gui_core/ghelp.py | 12 +-- gui/wxpython/gui_core/gselect.py | 68 ++++++------- gui/wxpython/gui_core/pyedit.py | 29 +++--- gui/wxpython/gui_core/pystc.py | 6 +- gui/wxpython/gui_core/query.py | 4 +- gui/wxpython/history/browser.py | 4 +- gui/wxpython/iclass/dialogs.py | 8 +- gui/wxpython/iclass/frame.py | 11 ++- gui/wxpython/iclass/plots.py | 9 +- gui/wxpython/image2target/ii2t_gis_set.py | 2 +- gui/wxpython/iscatt/controllers.py | 45 ++++----- gui/wxpython/iscatt/dialogs.py | 8 +- gui/wxpython/iscatt/frame.py | 2 +- gui/wxpython/iscatt/iscatt_core.py | 4 +- gui/wxpython/lmgr/frame.py | 4 +- gui/wxpython/lmgr/workspace.py | 5 +- gui/wxpython/location_wizard/dialogs.py | 4 +- gui/wxpython/location_wizard/wizard.py | 2 +- gui/wxpython/main_window/frame.py | 4 +- gui/wxpython/mapdisp/frame.py | 5 +- gui/wxpython/mapdisp/test_mapdisp.py | 2 +- gui/wxpython/mapwin/analysis.py | 6 +- gui/wxpython/rdigit/g.gui.rdigit.py | 13 +-- gui/wxpython/rlisetup/frame.py | 5 +- gui/wxpython/rlisetup/functions.py | 3 +- gui/wxpython/rlisetup/wizard.py | 4 +- gui/wxpython/startup/locdownload.py | 12 +-- gui/wxpython/timeline/frame.py | 2 +- gui/wxpython/tplot/frame.py | 19 ++-- gui/wxpython/vnet/vnet_data.py | 2 +- gui/wxpython/web_services/dialogs.py | 13 ++- gui/wxpython/web_services/widgets.py | 11 +-- gui/wxpython/wxgui.py | 8 +- lib/init/grass.py | 7 +- pyproject.toml | 96 ++---------------- python/grass/pygrass/raster/category.py | 2 +- python/grass/pygrass/vector/__init__.py | 4 +- python/grass/script/raster.py | 2 +- .../temporal/abstract_space_time_dataset.py | 2 +- python/grass/temporal/aggregation.py | 13 ++- .../grass/temporal/c_libraries_interface.py | 12 +-- python/grass/temporal/core.py | 25 ++--- python/grass/temporal/datetime_math.py | 2 +- python/grass/temporal/mapcalc.py | 99 +++++-------------- python/grass/temporal/space_time_datasets.py | 72 +++++--------- python/grass/temporal/stds_export.py | 17 ++-- python/grass/temporal/stds_import.py | 6 +- python/grass/temporal/temporal_algebra.py | 4 +- .../temporal/temporal_raster_base_algebra.py | 2 +- python/grass/temporal/univar_statistics.py | 9 +- scripts/d.polar/d.polar.py | 8 +- scripts/g.extension.all/g.extension.all.py | 34 +++---- scripts/g.extension/g.extension.py | 12 +-- scripts/i.oif/i.oif.py | 2 +- scripts/i.pansharpen/i.pansharpen.py | 6 +- scripts/i.spectral/i.spectral.py | 14 ++- scripts/r.in.wms/wms_base.py | 12 +-- scripts/r.in.wms/wms_cap_parsers.py | 2 +- scripts/r.in.wms/wms_drv.py | 2 +- scripts/r.in.wms/wms_gdal_drv.py | 2 +- scripts/r.pack/r.pack.py | 2 +- scripts/r.tileset/r.tileset.py | 6 +- scripts/r.unpack/r.unpack.py | 19 ++-- scripts/v.rast.stats/v.rast.stats.py | 12 +-- scripts/v.to.lines/v.to.lines.py | 2 +- scripts/v.unpack/v.unpack.py | 5 +- scripts/v.what.strds/v.what.strds.py | 16 +-- temporal/t.rast.accdetect/t.rast.accdetect.py | 2 +- .../t.rast.accumulate/t.rast.accumulate.py | 2 +- temporal/t.rast.export/t.rast.export.py | 4 +- temporal/t.rast.gapfill/t.rast.gapfill.py | 3 +- temporal/t.rast.list/t.rast.list.py | 22 ++++- temporal/t.rast.out.vtk/t.rast.out.vtk.py | 2 +- temporal/t.rast.series/t.rast.series.py | 4 +- temporal/t.rast.to.rast3/t.rast.to.rast3.py | 2 +- temporal/t.rast.what/t.rast.what.py | 22 ++--- temporal/t.remove/t.remove.py | 19 ++-- temporal/t.unregister/t.unregister.py | 8 +- .../t.vect.observe.strds.py | 12 +-- utils/mkhtml.py | 27 +++-- 88 files changed, 441 insertions(+), 622 deletions(-) diff --git a/general/g.parser/test.py b/general/g.parser/test.py index 3b56230eb14..8166b354a37 100755 --- a/general/g.parser/test.py +++ b/general/g.parser/test.py @@ -53,10 +53,10 @@ def main(): # test if parameter present: if option1: - gs.message(_("Value of option1 option: '%s'" % option1)) + gs.message(_("Value of option1 option: '%s'") % option1) - gs.message(_("Value of raster option: '%s'" % raster)) - gs.message(_("Value of vector option: '%s'" % vector)) + gs.message(_("Value of raster option: '%s'") % raster) + gs.message(_("Value of vector option: '%s'") % vector) # End of your main code here diff --git a/gui/wxpython/animation/dialogs.py b/gui/wxpython/animation/dialogs.py index 154bdc9fce6..3d70dbd2639 100644 --- a/gui/wxpython/animation/dialogs.py +++ b/gui/wxpython/animation/dialogs.py @@ -1565,9 +1565,9 @@ def _export_file_validation(self, filebrowsebtn, file_path, file_postfix): self.GetParent(), message=_( "Exported animation file <{file}> exists. " - "Do you want to overwrite it?".format( - file=file_path, - ), + "Do you want to overwrite it?" + ).format( + file=file_path, ), caption=_("Overwrite?"), style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, diff --git a/gui/wxpython/animation/temporal_manager.py b/gui/wxpython/animation/temporal_manager.py index 9f9eafd41d0..150eeab510f 100644 --- a/gui/wxpython/animation/temporal_manager.py +++ b/gui/wxpython/animation/temporal_manager.py @@ -342,7 +342,7 @@ def _gatherInformation(self, timeseries, etype, timeseriesList, infoDict): maps = sp.get_registered_maps_as_objects() if not sp.check_temporal_topology(maps): - raise GException(_("Topology of Space time dataset %s is invalid." % id)) + raise GException(_("Topology of Space time dataset %s is invalid.") % id) timeseriesList.append(id) infoDict[id] = {} diff --git a/gui/wxpython/core/debug.py b/gui/wxpython/core/debug.py index cf642d1df4c..b6c12a60b62 100644 --- a/gui/wxpython/core/debug.py +++ b/gui/wxpython/core/debug.py @@ -49,8 +49,8 @@ def SetLevel(self): sys.stderr.write( _( "WARNING: Ignoring unsupported wx debug level (must be >=0 and " - "<=5). {0}\n".format(e) - ) + "<=5). {0}\n" + ).format(e) ) def msg(self, level, message, *args): diff --git a/gui/wxpython/core/render.py b/gui/wxpython/core/render.py index 021f3aa6500..3095cb47fc8 100644 --- a/gui/wxpython/core/render.py +++ b/gui/wxpython/core/render.py @@ -706,7 +706,7 @@ def OnRenderDone(self, env): self._rendering = False if wx.IsBusy(): wx.EndBusyCursor() - raise GException(_("Rendering failed: %s" % msg)) + raise GException(_("Rendering failed: %s") % msg) stop = time.time() Debug.msg( diff --git a/gui/wxpython/gcp/manager.py b/gui/wxpython/gcp/manager.py index 749cbf79efb..696bc53609f 100644 --- a/gui/wxpython/gcp/manager.py +++ b/gui/wxpython/gcp/manager.py @@ -1785,11 +1785,10 @@ def _getOverWriteDialog(self, maptype, overwrite): return wx.MessageDialog( self.GetParent(), message=_( - "The {map_type} map {map_name} exists. " - "Do you want to overwrite?".format( - map_type=maptype, - map_name=map_name, - ), + "The {map_type} map {map_name} exists. Do you want to overwrite?" + ).format( + map_type=maptype, + map_name=map_name, ), caption=_("Overwrite?"), style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, diff --git a/gui/wxpython/gmodeler/model.py b/gui/wxpython/gmodeler/model.py index 41fcfe6614f..a609a1c8bd8 100644 --- a/gui/wxpython/gmodeler/model.py +++ b/gui/wxpython/gmodeler/model.py @@ -2819,12 +2819,11 @@ def _getPythonActionCmd(self, item, task, cmdIndent, variables={}): dlg = wx.MessageDialog( self.model.canvas, message=_( - f"Module {task.get_name()} in your model contains " - f"parameterized flags. actinia does not support " - f"parameterized flags. The following flags are therefore " - f"not being written in the generated json: " - f"{itemParameterizedFlags}" - ), + "Module {task_name} in your model contains " + "parameterized flags. Actinia does not support " + "parameterized flags. The following flags are therefore " + "not being written in the generated JSON: {flags}" + ).format(task_name=task.get_name(), flags=itemParameterizedFlags), caption=_("Warning"), style=wx.OK_DEFAULT | wx.ICON_WARNING, ) diff --git a/gui/wxpython/gmodeler/panels.py b/gui/wxpython/gmodeler/panels.py index 300220b9f7c..93ef770efe1 100644 --- a/gui/wxpython/gmodeler/panels.py +++ b/gui/wxpython/gmodeler/panels.py @@ -268,19 +268,15 @@ def OnPageChanged(self, event): if self.pythonPanel.IsModified(): self.SetStatusText( - _( - "{} script contains local modifications".format( - self.pythonPanel.body.script_type - ) + _("{} script contains local modifications").format( + self.pythonPanel.body.script_type ), 0, ) else: self.SetStatusText( - _( - "{} script is up-to-date".format( - self.pythonPanel.body.script_type - ) + _("{} script is up-to-date").format( + self.pythonPanel.body.script_type ), 0, ) @@ -1261,7 +1257,7 @@ def OnDeleteData(self, event): dlg = wx.MessageDialog( parent=self, - message=_("Do you want to permanently delete data?%s" % msg), + message=_("Do you want to permanently delete data?%s") % msg, caption=_("Delete intermediate data?"), style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, ) @@ -1645,9 +1641,7 @@ def _layout(self): bodySizer.Add(self.body, proportion=1, flag=wx.EXPAND | wx.ALL, border=3) btnSizer.Add( - StaticText( - parent=self, id=wx.ID_ANY, label="%s:" % _("Python script type") - ), + StaticText(parent=self, id=wx.ID_ANY, label=_("Python script type:")), flag=wx.ALIGN_CENTER_VERTICAL, ) btnSizer.Add(self.script_type_box, proportion=0, flag=wx.RIGHT, border=5) @@ -1676,7 +1670,7 @@ def GetScriptExt(self): return ext def SetWriteObject(self, script_type): - """Set correct self.write_object dependng on the script type. + """Set correct self.write_object depending on the script type. :param script_type: script type name as a string """ if script_type == "PyWPS": @@ -1704,8 +1698,8 @@ def RefreshScript(self): message=_( "{} script is locally modified. " "Refresh will discard all changes. " - "Do you really want to continue?".format(self.body.script_type) - ), + "Do you really want to continue?" + ).format(self.body.script_type), caption=_("Update"), style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION | wx.CENTRE, ) @@ -1835,7 +1829,7 @@ def OnChangeScriptType(self, event): if self.RefreshScript(): self.body.script_type = new_script_type self.parent.SetStatusText( - _("{} script is up-to-date".format(self.body.script_type)), + _("{} script is up-to-date").format(self.body.script_type), 0, ) @@ -1854,7 +1848,7 @@ def OnRefresh(self, event): """Refresh the script.""" if self.RefreshScript(): self.parent.SetStatusText( - _("{} script is up-to-date".format(self.body.script_type)), + _("{} script is up-to-date").format(self.body.script_type), 0, ) event.Skip() diff --git a/gui/wxpython/gui_core/ghelp.py b/gui/wxpython/gui_core/ghelp.py index 0602aeaea0c..93879998133 100644 --- a/gui/wxpython/gui_core/ghelp.py +++ b/gui/wxpython/gui_core/ghelp.py @@ -564,15 +564,15 @@ def _langString(self, k, v): """Return string for the status of translation""" allStr = "%s :" % k.upper() try: - allStr += _(" %d translated" % v["good"]) + allStr += _(" %d translated") % v["good"] except: pass try: - allStr += _(" %d fuzzy" % v["fuzzy"]) + allStr += _(" %d fuzzy") % v["fuzzy"] except: pass try: - allStr += _(" %d untranslated" % v["bad"]) + allStr += _(" %d untranslated") % v["bad"] except: pass return allStr @@ -584,7 +584,7 @@ def _langBox(self, par, k, v): langBox.Add(tkey) try: tgood = StaticText( - parent=par, id=wx.ID_ANY, label=_("%d translated" % v["good"]) + parent=par, id=wx.ID_ANY, label=_("%d translated") % v["good"] ) tgood.SetForegroundColour(wx.Colour(35, 142, 35)) langBox.Add(tgood) @@ -593,7 +593,7 @@ def _langBox(self, par, k, v): langBox.Add(tgood) try: tfuzzy = StaticText( - parent=par, id=wx.ID_ANY, label=_(" %d fuzzy" % v["fuzzy"]) + parent=par, id=wx.ID_ANY, label=_(" %d fuzzy") % v["fuzzy"] ) tfuzzy.SetForegroundColour(wx.Colour(255, 142, 0)) langBox.Add(tfuzzy) @@ -602,7 +602,7 @@ def _langBox(self, par, k, v): langBox.Add(tfuzzy) try: tbad = StaticText( - parent=par, id=wx.ID_ANY, label=_(" %d untranslated" % v["bad"]) + parent=par, id=wx.ID_ANY, label=_(" %d untranslated") % v["bad"] ) tbad.SetForegroundColour(wx.Colour(255, 0, 0)) langBox.Add(tbad) diff --git a/gui/wxpython/gui_core/gselect.py b/gui/wxpython/gui_core/gselect.py index 7dc51b75935..eae12085f92 100644 --- a/gui/wxpython/gui_core/gselect.py +++ b/gui/wxpython/gui_core/gselect.py @@ -921,7 +921,7 @@ def GetTable(self, layer): :param layer: vector layer number """ if layer not in self.layers: - raise GException(_("No table linked to layer <{}>.".format(layer))) + raise GException(_("No table linked to layer <{}>.").format(layer)) return self.layers[layer]["table"] def GetDbSettings(self, layer): @@ -2259,18 +2259,18 @@ def hasRastSameProjAsLocation(dsn, table=None): message=_( "Getting raster <{table}> SRID from PostgreSQL" " DB <{db}>, host <{host}> failed." - " {error}.".format( - table=table, - db=self._getPDDBConnectionParam( - dsn, - conn_param="dbname", - ), - host=self._getPDDBConnectionParam( - dsn, - conn_param="host", - ), - error=gs.utils.decode(error), + " {error}." + ).format( + table=table, + db=self._getPDDBConnectionParam( + dsn, + conn_param="dbname", ), + host=self._getPDDBConnectionParam( + dsn, + conn_param="host", + ), + error=gs.utils.decode(error), ), ) if ret: @@ -2522,17 +2522,17 @@ def _getPGDBtables(self, dsn): parent=self, message=_( "Getting list of tables from PostgreSQL DB <{db}>," - " host <{host}> failed. {error}.".format( - db=self._getPGDBConnectionParam( - dsn, - conn_param="dbname", - ), - host=self._getPGDBConnectionParam( - dsn, - conn_param="host", - ), - error=gs.utils.decode(error), + " host <{host}> failed. {error}." + ).format( + db=self._getPGDBConnectionParam( + dsn, + conn_param="dbname", ), + host=self._getPGDBConnectionParam( + dsn, + conn_param="host", + ), + error=gs.utils.decode(error), ), ) if ret: @@ -2614,17 +2614,17 @@ def _getPGDBRasters(self, dsn): message=_( "Getting list of tables columns data types" " from PostGIS DB <{db}>, host <{host}> failed." - " {error}.".format( - db=self._getPGDBConnectionParam( - dsn, - conn_param="dbname", - ), - host=self._getPGDBConnectionParam( - dsn, - conn_param="host", - ), - error=gs.utils.decode(error), + " {error}." + ).format( + db=self._getPGDBConnectionParam( + dsn, + conn_param="dbname", ), + host=self._getPGDBConnectionParam( + dsn, + conn_param="host", + ), + error=gs.utils.decode(error), ), ) if ret: @@ -2644,8 +2644,8 @@ def _getPGDBRasters(self, dsn): parent=self, message=_( "PostgreSQL DB <{psql}> program was not found." - " Please, install it.".format(psql=self._psql) - ), + " Please, install it." + ).format(psql=self._psql), ) Debug.msg(3, f"GdalSelect._getPGDBRasters(): return {rasters}") return rasters diff --git a/gui/wxpython/gui_core/pyedit.py b/gui/wxpython/gui_core/pyedit.py index 9fa75fa74c1..4974e0ce8f5 100644 --- a/gui/wxpython/gui_core/pyedit.py +++ b/gui/wxpython/gui_core/pyedit.py @@ -306,14 +306,14 @@ def _openFile(self, file_path): GError( message=_( "Permission denied <{}>. Please change file " - "permission for reading.".format(file_path) - ), + "permission for reading." + ).format(file_path), parent=self.guiparent, showTraceback=False, ) except OSError: GError( - message=_("Couldn't read file <{}>.".format(file_path)), + message=_("Couldn't read file <{}>.").format(file_path), parent=self.guiparent, ) @@ -333,20 +333,18 @@ def _writeFile(self, file_path, content, additional_err_message=""): GError( message=_( "Permission denied <{}>. Please change file " - "permission for writing.{}".format( - file_path, - additional_err_message, - ), + "permission for writing.{}" + ).format( + file_path, + additional_err_message, ), parent=self.guiparent, showTraceback=False, ) except OSError: GError( - message=_( - "Couldn't write file <{}>.{}".format( - file_path, additional_err_message - ), + message=_("Couldn't write file <{}>.{}").format( + file_path, additional_err_message ), parent=self.guiparent, ) @@ -359,7 +357,7 @@ def OnRun(self, event): file_is_written = self._writeFile( file_path=self.filename, content=self.body.GetText(), - additional_err_message=" Unable to launch Python script.", + additional_err_message=_(" Unable to launch Python script."), ) if file_is_written: mode = stat.S_IMODE(os.lstat(self.filename)[stat.ST_MODE]) @@ -369,7 +367,7 @@ def OnRun(self, event): file_is_written = self._writeFile( file_path=self.filename, content=self.body.GetText(), - additional_err_message=" Unable to launch Python script.", + additional_err_message=_(" Unable to launch Python script."), ) if file_is_written: # set executable file @@ -509,9 +507,8 @@ def OpenRecentFile(self, path, file_exists, file_history): if not file_exists: GError( _( - "File <{}> doesn't exist." - "It was probably moved or deleted.".format(path) - ), + "File <{path}> doesn't exist. It was probably moved or deleted." + ).format(path=path), parent=self.guiparent, ) return diff --git a/gui/wxpython/gui_core/pystc.py b/gui/wxpython/gui_core/pystc.py index a1dfc543320..33d5f03b5f9 100644 --- a/gui/wxpython/gui_core/pystc.py +++ b/gui/wxpython/gui_core/pystc.py @@ -262,10 +262,8 @@ def OnKeyPressed(self, event): self.modified = True if self.statusbar: self.statusbar.SetStatusText( - _( - "{} script contains local modifications".format( - self.script_type - ) + _("{} script contains local modifications").format( + self.script_type ), 0, ) diff --git a/gui/wxpython/gui_core/query.py b/gui/wxpython/gui_core/query.py index 6250095cb29..5e0f734fa6a 100644 --- a/gui/wxpython/gui_core/query.py +++ b/gui/wxpython/gui_core/query.py @@ -136,11 +136,11 @@ def ShowContextMenu(self, node): ) else: label1 = nodes[0].label - texts.append((_("Copy '%s'" % self._cutLabel(label1)), label1)) + texts.append((_("Copy '%s'") % self._cutLabel(label1), label1)) col1 = self._colNames[1] if nodes[0].data and col1 in nodes[0].data and nodes[0].data[col1]: label2 = nodes[0].data[col1] - texts.insert(0, (_("Copy '%s'" % self._cutLabel(label2)), label2)) + texts.insert(0, (_("Copy '%s'") % self._cutLabel(label2), label2)) texts.append((_("Copy line"), label1 + ": " + label2)) ids = [] diff --git a/gui/wxpython/history/browser.py b/gui/wxpython/history/browser.py index 6a31523d51f..422d6dcc9c2 100644 --- a/gui/wxpython/history/browser.py +++ b/gui/wxpython/history/browser.py @@ -60,7 +60,7 @@ def get_translated_value(key, value): exec_datetime = datetime.fromisoformat(value) return exec_datetime.strftime("%Y-%m-%d %H:%M:%S") elif key == "runtime": - return _("{} sec".format(value)) + return _("{} sec").format(value) elif key == "status": return _(value.capitalize()) elif key in {"mask2d", "mask3d"}: @@ -480,7 +480,7 @@ def OnCmdExportHistory(self, event): try: history.copy(history_path, target_path) self.showNotification.emit( - message=_("Command history saved to '{}'".format(target_path)) + message=_("Command history saved to '{}'").format(target_path) ) except OSError as e: GError(str(e)) diff --git a/gui/wxpython/iclass/dialogs.py b/gui/wxpython/iclass/dialogs.py index 8aaac14c4c8..322bfcf5721 100644 --- a/gui/wxpython/iclass/dialogs.py +++ b/gui/wxpython/iclass/dialogs.py @@ -835,10 +835,10 @@ def OnOK(self, event): qdlg = wx.MessageDialog( parent=self, message=_( - "Vector map <%s> already exists." - " Do you want to overwrite it?" % vName - ), - caption=_("Vector <%s> exists" % vName), + "Vector map <%s> already exists. Do you want to overwrite it?" + ) + % vName, + caption=_("Vector <%s> exists") % vName, style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION | wx.CENTRE, ) if qdlg.ShowModal() == wx.ID_YES: diff --git a/gui/wxpython/iclass/frame.py b/gui/wxpython/iclass/frame.py index 52af10d85e0..69c18780249 100644 --- a/gui/wxpython/iclass/frame.py +++ b/gui/wxpython/iclass/frame.py @@ -646,11 +646,14 @@ def _checkImportedTopo(self, vector): warning = "" if topo["areas"] == 0: - warning = _("No areas in vector map <%s>.\n" % vector) + warning = _("No areas in vector map <%s>.\n") % vector if topo["points"] or topo["lines"]: - warning += _( - "Vector map <%s> contains points or lines, " - "these features are ignored." % vector + warning += ( + _( + "Vector map <%s> contains points or lines, " + "these features are ignored." + ) + % vector ) return warning diff --git a/gui/wxpython/iclass/plots.py b/gui/wxpython/iclass/plots.py index 786fa920d17..510953bb5b1 100644 --- a/gui/wxpython/iclass/plots.py +++ b/gui/wxpython/iclass/plots.py @@ -88,9 +88,12 @@ def _createScatterPlotPanel(self): ) self.iscatt_panel.Hide() except ImportError as e: - self.scatt_error = _( - "Scatter plot functionality is disabled.\n\nReason: " - "Unable to import packages needed for scatter plot.\n%s" % e + self.scatt_error = ( + _( + "Scatter plot functionality is disabled.\n\nReason: " + "Unable to import packages needed for scatter plot.\n%s" + ) + % e ) wx.CallAfter(GError, self.scatt_error, showTraceback=False, parent=self) self.iscatt_panel = None diff --git a/gui/wxpython/image2target/ii2t_gis_set.py b/gui/wxpython/image2target/ii2t_gis_set.py index e3cb0257af1..0f51d969e93 100644 --- a/gui/wxpython/image2target/ii2t_gis_set.py +++ b/gui/wxpython/image2target/ii2t_gis_set.py @@ -547,7 +547,7 @@ def _readGisRC(self): key, val = line.split(":", 1) except ValueError as e: sys.stderr.write( - _("Invalid line in GISRC file (%s):%s\n" % (e, line)) + _("Invalid line in GISRC file (%s):%s\n") % (e, line) ) grassrc[key.strip()] = DecodeString(val.strip()) finally: diff --git a/gui/wxpython/iscatt/controllers.py b/gui/wxpython/iscatt/controllers.py index 38e61e34133..e8884f4f78b 100644 --- a/gui/wxpython/iscatt/controllers.py +++ b/gui/wxpython/iscatt/controllers.py @@ -234,8 +234,9 @@ def AddScattPlot(self): "Number of cells (rows*cols) <%d> in current region" "is higher than maximum limit <%d>.\n\n" "You can reduce number of cells in current region using " - " command." % (ncells, MAX_NCELLS) - ), + " command." + ) + % (ncells, MAX_NCELLS), ) ) return @@ -250,8 +251,8 @@ def AddScattPlot(self): "It can be done by command.\n\n" "Do you want to continue using " "Interactive Scatter Plot Tool with this region?" - % (ncells, WARN_NCELLS) - ), + ) + % (ncells, WARN_NCELLS), style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_WARNING, ) ret = dlg.ShowModal() @@ -318,11 +319,11 @@ def CheckBands(self, b_1, b_2): err = "" for b in [b_1_name, b_2_name]: if self.bands_info[b] is None: - err += _("Band <%s> is not CELL (integer) type.\n" % b) + err += _("Band <%s> is not CELL (integer) type.\n") % b if err: GMessage( parent=self.guiparent, - message=_("Scatter plot cannot be added.\n" + err), + message=_("Scatter plot cannot be added.\n") + err, ) return False @@ -334,14 +335,14 @@ def CheckBands(self, b_1, b_2): "Scatter plot cannot be added.\n" "Multiple of bands ranges <%s:%d * %s:%d = %d> " "is higher than maximum limit <%d>.\n" - % ( - b_1_name, - b_1_i["range"], - b_1_name, - b_2_i["range"], - mrange, - MAX_SCATT_SIZE, - ) + ) + % ( + b_1_name, + b_1_i["range"], + b_1_name, + b_2_i["range"], + mrange, + MAX_SCATT_SIZE, ), ) return False @@ -354,14 +355,14 @@ def CheckBands(self, b_1, b_2): "It is strongly advised to reduce range extend of bands" "(e. g. using r.rescale) below recommended threshold.\n\n" "Do you really want to add this scatter plot?" - % ( - b_1_name, - b_1_i["range"], - b_1_name, - b_2_i["range"], - mrange, - WARN_SCATT_SIZE, - ) + ) + % ( + b_1_name, + b_1_i["range"], + b_1_name, + b_2_i["range"], + mrange, + WARN_SCATT_SIZE, ), style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_WARNING, ) diff --git a/gui/wxpython/iscatt/dialogs.py b/gui/wxpython/iscatt/dialogs.py index 4129015e88d..3e2d7fa7a59 100644 --- a/gui/wxpython/iscatt/dialogs.py +++ b/gui/wxpython/iscatt/dialogs.py @@ -327,10 +327,10 @@ def OnOK(self, event): qdlg = wx.MessageDialog( parent=self, message=_( - "Raster map <%s> already exists." - " Do you want to overwrite it?" % rast_name - ), - caption=_("Raster <%s> exists" % rast_name), + "Raster map <%s> already exists. Do you want to overwrite it?" + ) + % rast_name, + caption=_("Raster <%s> exists") % rast_name, style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION | wx.CENTRE, ) if qdlg.ShowModal() == wx.ID_YES: diff --git a/gui/wxpython/iscatt/frame.py b/gui/wxpython/iscatt/frame.py index 6d87a90e273..45f50622d2f 100644 --- a/gui/wxpython/iscatt/frame.py +++ b/gui/wxpython/iscatt/frame.py @@ -681,7 +681,7 @@ def OnPopupOpacityLevel(self, event): name = cat_attrs["name"] dlg = SetOpacityDialog( - self, opacity=value, title=_("Change opacity of class <%s>" % name) + self, opacity=value, title=_("Change opacity of class <%s>") % name ) dlg.applyOpacity.connect( diff --git a/gui/wxpython/iscatt/iscatt_core.py b/gui/wxpython/iscatt/iscatt_core.py index 91ac00014a5..a881fab5845 100644 --- a/gui/wxpython/iscatt/iscatt_core.py +++ b/gui/wxpython/iscatt/iscatt_core.py @@ -295,7 +295,7 @@ def _rasterize(self, grass_region, layer, cat, out_rast): ) if ret != 0: - GException(_("v.build failed:\n%s" % msg)) + GException(_("v.build failed:\n%s") % msg) environs = os.environ.copy() environs["GRASS_REGION"] = grass_region["GRASS_REGION"] @@ -315,7 +315,7 @@ def _rasterize(self, grass_region, layer, cat, out_rast): ) if ret != 0: - GException(_("v.to.rast failed:\n%s" % msg)) + GException(_("v.to.rast failed:\n{messages}").format(messages=msg)) def _create_grass_region_env(self, bbox): r = self.an_data.GetRegion() diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index de06305086f..a17b168f747 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -1251,8 +1251,8 @@ def OnRunScript(self, event): "Do you want to set the permissions " "that allows you to run this script " "(note that you must be the owner of the file)?" - % os.path.basename(filename) - ), + ) + % os.path.basename(filename), caption=_("Set permission?"), style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, ) diff --git a/gui/wxpython/lmgr/workspace.py b/gui/wxpython/lmgr/workspace.py index febb3922dd7..bb40469fa56 100644 --- a/gui/wxpython/lmgr/workspace.py +++ b/gui/wxpython/lmgr/workspace.py @@ -548,9 +548,8 @@ def OpenRecentFile(self, path, file_exists, file_history): """ if not file_exists: GError( - _( - "File <{}> doesn't exist." - " It was probably moved or deleted.".format(path) + _("File <{}> doesn't exist. It was probably moved or deleted.").format( + path ), parent=self.lmgr, ) diff --git a/gui/wxpython/location_wizard/dialogs.py b/gui/wxpython/location_wizard/dialogs.py index 16325ddfbe1..079fca1f6d4 100644 --- a/gui/wxpython/location_wizard/dialogs.py +++ b/gui/wxpython/location_wizard/dialogs.py @@ -594,8 +594,8 @@ def __UpdateInfo(self): self.lcols.SetLabel(_("Cols: %d") % self.cols) self.lcells.SetLabel(_("Cells: %d") % self.cells) # 3D - self.ldepth.SetLabel(_("Depth: %d" % self.depth)) - self.lcells3.SetLabel(_("3D Cells: %d" % self.cells3)) + self.ldepth.SetLabel(_("Depth: %d") % self.depth) + self.lcells3.SetLabel(_("3D Cells: %d") % self.cells3) def OnSetButton(self, event=None): """Set default region""" diff --git a/gui/wxpython/location_wizard/wizard.py b/gui/wxpython/location_wizard/wizard.py index 155346b3467..7ba03ebee04 100644 --- a/gui/wxpython/location_wizard/wizard.py +++ b/gui/wxpython/location_wizard/wizard.py @@ -2723,7 +2723,7 @@ def OnWizFinished(self): if not self.filepage.georeffile or not os.path.isfile( self.filepage.georeffile ): - return _("File <%s> not found." % self.filepage.georeffile) + return _("File <%s> not found.") % self.filepage.georeffile grass.create_location( dbase=self.startpage.grassdatabase, diff --git a/gui/wxpython/main_window/frame.py b/gui/wxpython/main_window/frame.py index facb3f8195a..3b9b7f50261 100644 --- a/gui/wxpython/main_window/frame.py +++ b/gui/wxpython/main_window/frame.py @@ -1402,8 +1402,8 @@ def OnRunScript(self, event): "Do you want to set the permissions " "that allows you to run this script " "(note that you must be the owner of the file)?" - % os.path.basename(filename) - ), + ) + % os.path.basename(filename), caption=_("Set permission?"), style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, ) diff --git a/gui/wxpython/mapdisp/frame.py b/gui/wxpython/mapdisp/frame.py index 8cb8a51d407..0b948f63794 100644 --- a/gui/wxpython/mapdisp/frame.py +++ b/gui/wxpython/mapdisp/frame.py @@ -411,8 +411,9 @@ def AddNviz(self): message=_( "Unable to switch to 3D display mode.\nThe Nviz python extension " "was not found or loaded properly.\n" - "Switching back to 2D display mode.\n\nDetails: %s" % errorMsg - ), + "Switching back to 2D display mode.\n\nDetails: %s" + ) + % errorMsg, ) return diff --git a/gui/wxpython/mapdisp/test_mapdisp.py b/gui/wxpython/mapdisp/test_mapdisp.py index 7a61e196ba9..1494988fafb 100755 --- a/gui/wxpython/mapdisp/test_mapdisp.py +++ b/gui/wxpython/mapdisp/test_mapdisp.py @@ -356,7 +356,7 @@ def main(): tester.testMapWindowRlisetup(map_) else: # TODO: this should not happen but happens - gs.fatal(_("Unknown value %s of test parameter." % test)) + gs.fatal(_("Unknown value %s of test parameter.") % test) app.MainLoop() diff --git a/gui/wxpython/mapwin/analysis.py b/gui/wxpython/mapwin/analysis.py index 490a9d7e866..d0a7be1bc0c 100644 --- a/gui/wxpython/mapwin/analysis.py +++ b/gui/wxpython/mapwin/analysis.py @@ -262,11 +262,7 @@ def Start(self): self._useCtypes = True except ImportError as e: self._giface.WriteWarning( - _( - "Geodesic distance calculation " - "is not available.\n" - "Reason: %s" % e - ) + _("Geodesic distance calculation is not available.\nReason: %s") % e ) def MeasureDist(self, beginpt, endpt): diff --git a/gui/wxpython/rdigit/g.gui.rdigit.py b/gui/wxpython/rdigit/g.gui.rdigit.py index d740b1c3e78..ae8d9ed41d8 100755 --- a/gui/wxpython/rdigit/g.gui.rdigit.py +++ b/gui/wxpython/rdigit/g.gui.rdigit.py @@ -193,10 +193,8 @@ def OnMapCreated(self, name, ltype, add: bool | None = None): if not edit_map: gs.fatal( - _( - "Raster map <{}> not found in current mapset.".format( - options["edit"], - ), + _("Raster map <{}> not found in current mapset.").format( + options["edit"], ), ) else: @@ -209,11 +207,8 @@ def OnMapCreated(self, name, ltype, add: bool | None = None): )["fullname"] if not base_map: gs.fatal( - _( - "Base raster map <{}> not found in " - "current mapset.".format( - options["base"], - ), + _("Base raster map <{}> not found in current mapset.").format( + options["base"], ), ) kwargs["base_map"] = base_map diff --git a/gui/wxpython/rlisetup/frame.py b/gui/wxpython/rlisetup/frame.py index 00e35f66110..3905fa9b09d 100644 --- a/gui/wxpython/rlisetup/frame.py +++ b/gui/wxpython/rlisetup/frame.py @@ -40,9 +40,8 @@ def __init__( self.confilesBox = StaticBox( parent=self.panel, id=wx.ID_ANY, - label=_( - "View and modify the " - "configuration file '{name}'".format(name=self.confile) + label=_("View and modify the configuration file '{name}'").format( + name=self.confile ), ) self.textCtrl = TextCtrl( diff --git a/gui/wxpython/rlisetup/functions.py b/gui/wxpython/rlisetup/functions.py index 28f186fa396..2ce0b747dcd 100644 --- a/gui/wxpython/rlisetup/functions.py +++ b/gui/wxpython/rlisetup/functions.py @@ -153,8 +153,9 @@ def sampleAreaVector( "The raster map <%s> already exists." " Please remove or rename the maps " "with the prefix '%s' or select the " - "option to overwrite existing maps" % (rast_name, outpref) + "option to overwrite existing maps" ) + % (rast_name, outpref) ) return None convertFeature(vect, rast_name, cat, rast, layer, overwrite) diff --git a/gui/wxpython/rlisetup/wizard.py b/gui/wxpython/rlisetup/wizard.py index 54c6dbcd78a..4ecbb60e188 100644 --- a/gui/wxpython/rlisetup/wizard.py +++ b/gui/wxpython/rlisetup/wizard.py @@ -1859,8 +1859,8 @@ def newCat(self): "The raster map <%s> already exists." " Please remove or rename the maps " "with the prefix '%s' or select the " - "option to overwrite existing maps" % (self.outname, self.outpref) - ), + "option to overwrite existing maps" + ).format(self.outname, self.outpref), ) self.parent.wizard.ShowPage(self.parent.samplingareapage) return diff --git a/gui/wxpython/startup/locdownload.py b/gui/wxpython/startup/locdownload.py index f0a1ab13fd2..75eae560244 100644 --- a/gui/wxpython/startup/locdownload.py +++ b/gui/wxpython/startup/locdownload.py @@ -156,12 +156,12 @@ def reporthook(count, block_size, total_size): sys.stdout.write( _( "Download in progress, wait until it is finished " - "{0}%, {1} MB, {2} KB/s, {3:.0f} seconds passed".format( - percent, - progress_size / (1024 * 1024), - speed, - duration, - ), + "{0}%, {1} MB, {2} KB/s, {3:.0f} seconds passed" + ).format( + percent, + progress_size / (1024 * 1024), + speed, + duration, ), ) diff --git a/gui/wxpython/timeline/frame.py b/gui/wxpython/timeline/frame.py index f69dcc89aef..3982034619c 100644 --- a/gui/wxpython/timeline/frame.py +++ b/gui/wxpython/timeline/frame.py @@ -527,7 +527,7 @@ def _checkDatasets(self, datasets): elif len(indices) >= 2: dlg = wx.SingleChoiceDialog( self, - message=_("Please specify the space time dataset <%s>." % dataset), + message=_("Please specify the space time dataset <%s>.") % dataset, caption=_("Ambiguous dataset name"), choices=[ ( diff --git a/gui/wxpython/tplot/frame.py b/gui/wxpython/tplot/frame.py index 62147f54ad6..db21da4cd14 100755 --- a/gui/wxpython/tplot/frame.py +++ b/gui/wxpython/tplot/frame.py @@ -669,8 +669,8 @@ def _getSTVDData(self, timeseries): showTraceback=False, message=_( "No connection between vector map {vmap} " - "and layer {la}".format(vmap=row["name"], la=lay) - ), + "and layer {la}" + ).format(vmap=row["name"], la=lay), ) return vals = gs.vector_db_select( @@ -740,7 +740,7 @@ def _setLabels(self, x): if self.drawX != "": self.axes2d.set_xlabel(self.drawX) elif self.temporalType == "absolute": - self.axes2d.set_xlabel(_("Temporal resolution: %s" % x)) + self.axes2d.set_xlabel(_("Temporal resolution: %s") % x) else: self.axes2d.set_xlabel(_("Time [%s]") % self.unit) if self.drawY != "": @@ -917,8 +917,8 @@ def drawVCats(self): message=_( "Problem getting data from vector temporal" " dataset. Empty list of values for cat " - "{ca}.".format(ca=name_cat[1].replace("cat", "")) - ), + "{ca}." + ).format(ca=name_cat[1].replace("cat", "")), ) continue self.lookUp.AddDataset(yranges=ydata, xranges=xdata, datasetName=name) @@ -1007,9 +1007,8 @@ def OnRedraw(self, event=None): if os.path.exists(self.csvpath) and not self.overwrite: dlg = wx.MessageDialog( self, - _( - "{pa} already exists, do you want " - "to overwrite?".format(pa=self.csvpath) + _("{pa} already exists, do you want to overwrite?").format( + pa=self.csvpath ), _("File exists"), wx.OK | wx.CANCEL | wx.ICON_QUESTION, @@ -1185,7 +1184,7 @@ def _checkDatasets(self, datasets, typ): elif len(indices) >= 2: dlg = wx.SingleChoiceDialog( self, - message=_("Please specify the space time dataset <%s>." % dataset), + message=_("Please specify the space time dataset <%s>.") % dataset, caption=_("Ambiguous dataset name"), choices=[ ( @@ -1368,7 +1367,7 @@ def InfoFormat(timeData, values): text.append(_("Space time 3D raster dataset: %s") % key) text.extend( - (_("Value for {date} is {val}".format(date=val[0], val=val[1])), "\n") + (_("Value for {date} is {val}").format(date=val[0], val=val[1]), "\n") ) text.append(_("Press Del to dismiss.")) diff --git a/gui/wxpython/vnet/vnet_data.py b/gui/wxpython/vnet/vnet_data.py index a1332398a1e..6404fcac5c0 100644 --- a/gui/wxpython/vnet/vnet_data.py +++ b/gui/wxpython/vnet/vnet_data.py @@ -154,7 +154,7 @@ def InputsErrorMsgs( if flags["t"] and "turn_layer" not in relevant_params: GMessage( parent=self.guiparent, - message=_("Module <%s> does not support turns costs." % analysis), + message=_("Module <%s> does not support turns costs.") % analysis, ) return False diff --git a/gui/wxpython/web_services/dialogs.py b/gui/wxpython/web_services/dialogs.py index d67a2b34f7d..e47400cae70 100644 --- a/gui/wxpython/web_services/dialogs.py +++ b/gui/wxpython/web_services/dialogs.py @@ -331,7 +331,6 @@ def OnSettingsChanged(self, data): def OnClose(self, event): """Close the dialog""" - """Close dialog""" if not self.IsModal(): self.Destroy() event.Skip() @@ -378,7 +377,7 @@ def OnConnect(self, event): self.Fit() self.statusbar.SetStatusText( - _("Connecting to <%s>..." % self.server.GetValue().strip()) + _("Connecting to <$s>...") % self.server.GetValue().strip() ) # number of panels already connected @@ -464,14 +463,14 @@ def UpdateDialogAfterConnection(self): ) self._showWsPanel(self.web_service_sel[self.choose_ws_rb.GetSelection()]) self.statusbar.SetStatusText( - _("Connected to <%s>" % self.server.GetValue().strip()) + _("Connected to <%s>") % self.server.GetValue().strip() ) for btn in self.run_btns: btn.Enable(True) # no web service found on server else: self.statusbar.SetStatusText( - _("Unable to connect to <%s>" % self.server.GetValue().strip()) + _("Unable to connect to <%s>") % self.server.GetValue().strip() ) for btn in self.run_btns: btn.Enable(False) @@ -1029,7 +1028,7 @@ def OnSave(self, event): not self.overwrite.IsChecked() and gs.find_file(self.output, "cell", ".")["fullname"] ): - msg = _("Output map <%s> already exists" % self.output) + msg = _("Output map <%s> already exists") % self.output if msg: GMessage(parent=self, message=msg) @@ -1047,8 +1046,8 @@ def OnSave(self, event): if self.region_types["named"].GetValue(): if not gs.find_file(reg_spl[0], "windows", reg_mapset)["fullname"]: - msg = _( - "Region <%s> does not exist." % self.params["region"].GetValue() + msg = ( + _("Region <%s> does not exist.") % self.params["region"].GetValue() ) GWarning(parent=self, message=msg) return diff --git a/gui/wxpython/web_services/widgets.py b/gui/wxpython/web_services/widgets.py index 83fe7a5706c..3cb3af18068 100644 --- a/gui/wxpython/web_services/widgets.py +++ b/gui/wxpython/web_services/widgets.py @@ -538,10 +538,8 @@ def OnCapDownloadDone(self, event): if event.returncode != 0: if self.cmd_err_str: self.cmd_err_str = ( - _( - "Unable to download %s capabilities file\nfrom <%s>:\n" - % (self.ws.replace("_", " "), self.conn["url"]) - ) + _("Unable to download %s capabilities file\nfrom <%s>:\n") + % (self.ws.replace("_", " "), self.conn["url"]) + self.cmd_err_str ) self._postCapParsedEvt(error_msg=self.cmd_err_str) @@ -559,8 +557,9 @@ def _parseCapFile(self, cap_file): except (OSError, ParseError) as error: error_msg = _( "%s web service was not found in fetched capabilities file from " - "<%s>:\n%s\n" % (self.ws, self.conn["url"], str(error)) - ) + "<%s>:\n%s\n" + ) % (self.ws, self.conn["url"], str(error)) + if Debug.GetLevel() != 0: Debug.msg(1, error_msg) self._postCapParsedEvt(None) diff --git a/gui/wxpython/wxgui.py b/gui/wxpython/wxgui.py index 201eb0fe738..447821c6724 100644 --- a/gui/wxpython/wxgui.py +++ b/gui/wxpython/wxgui.py @@ -100,10 +100,10 @@ def show_main_gui(): warning( _( "Current version of wxPython {} is lower than " - "minimum required version {}".format( - wx.__version__, - ".".join(map(str, min_required_wx_version)), - ) + "minimum required version {}" + ).format( + wx.__version__, + ".".join(map(str, min_required_wx_version)), ) ) else: diff --git a/lib/init/grass.py b/lib/init/grass.py index 5a62e65ac53..28537f957b1 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -1314,16 +1314,17 @@ def lock_mapset(mapset_path, force_gislock_removal, user): "You can force launching GRASS using -f flag" " (note that you need permission for this operation)." " Have another look in the processor " - "manager just to be sure..." % {"user": user, "file": lockfile} - ) + "manager just to be sure..." + ) % {"user": user, "file": lockfile} + else: try_remove(lockfile) message( _( "%(user)s is currently running GRASS in selected mapset" " (file %(file)s found). Forcing to launch GRASS..." - % {"user": user, "file": lockfile} ) + % {"user": user, "file": lockfile} ) elif ret != 0: msg = ( diff --git a/pyproject.toml b/pyproject.toml index eb866cb0e08..f6d37ac3bea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -280,61 +280,19 @@ ignore = [ [tool.ruff.lint.per-file-ignores] # See https://docs.astral.sh/ruff/settings/#lint_per-file-ignores # "A005", # builtin-module-shadowing -# "INT002", # f-string-in-get-text-func-call -# "INT001", # format-in-get-text-func-call -# "INT003", # printf-in-get-text-func-call # "PLW0108", # unnecessary-lambda # Ignore `E402` (import violations) in all `__init__.py` files "*/testsuite/**.py" = ["PT009", "PT027"] "__init__.py" = ["E402"] -"general/g.parser/test.py" = ["INT003"] "gui/**" = ["PLW0108"] # See https://github.com/OSGeo/grass/issues/4124 -"gui/wxpython/animation/dialogs.py" = ["INT002"] -"gui/wxpython/animation/temporal_manager.py" = ["INT003"] -"gui/wxpython/core/debug.py" = ["INT002"] -"gui/wxpython/core/render.py" = ["INT003"] -"gui/wxpython/gcp/manager.py" = ["INT002"] -"gui/wxpython/gmodeler/model.py" = ["INT001"] -"gui/wxpython/gmodeler/panels.py" = ["INT002", "INT003"] -"gui/wxpython/gui_core/ghelp.py" = ["INT003"] -"gui/wxpython/gui_core/gselect.py" = ["INT002"] -"gui/wxpython/gui_core/pyedit.py" = ["INT002"] -"gui/wxpython/gui_core/pystc.py" = ["INT002"] -"gui/wxpython/gui_core/query.py" = ["INT003"] -"gui/wxpython/history/browser.py" = ["INT002"] -"gui/wxpython/iclass/dialogs.py" = ["INT003"] -"gui/wxpython/iclass/frame.py" = ["FLY002", "INT003"] -"gui/wxpython/iclass/plots.py" = ["INT003"] +"gui/wxpython/iclass/frame.py" = ["FLY002"] "gui/wxpython/iclass/statistics.py" = ["A005"] -"gui/wxpython/image2target/ii2t_gis_set.py" = ["INT003"] -"gui/wxpython/iscatt/controllers.py" = ["INT003"] -"gui/wxpython/iscatt/dialogs.py" = ["INT003"] -"gui/wxpython/iscatt/frame.py" = ["INT003"] -"gui/wxpython/iscatt/iscatt_core.py" = ["INT003"] "gui/wxpython/iscatt/plots.py" = ["PLW0108"] -"gui/wxpython/lmgr/frame.py" = ["INT003"] -"gui/wxpython/lmgr/workspace.py" = ["INT002"] -"gui/wxpython/location_wizard/dialogs.py" = ["INT003"] -"gui/wxpython/location_wizard/wizard.py" = ["INT003"] -"gui/wxpython/main_window/frame.py" = ["INT003"] -"gui/wxpython/mapdisp/frame.py" = ["INT003"] -"gui/wxpython/mapdisp/test_mapdisp.py" = ["INT003"] -"gui/wxpython/mapwin/analysis.py" = ["INT003"] "gui/wxpython/psmap/utils.py" = ["PGH004"] -"gui/wxpython/rdigit/g.gui.rdigit.py" = ["INT002"] -"gui/wxpython/rlisetup/frame.py" = ["INT002"] -"gui/wxpython/rlisetup/functions.py" = ["INT003"] -"gui/wxpython/rlisetup/wizard.py" = ["INT003"] -"gui/wxpython/startup/locdownload.py" = ["INT002"] -"gui/wxpython/timeline/frame.py" = ["FLY002", "INT003"] -"gui/wxpython/tplot/frame.py" = ["FLY002", "INT002", "INT003"] -"gui/wxpython/vnet/vnet_data.py" = ["INT003"] -"gui/wxpython/web_services/dialogs.py" = ["INT003"] -"gui/wxpython/web_services/widgets.py" = ["INT003"] -"gui/wxpython/wxgui.py" = ["INT002"] +"gui/wxpython/timeline/frame.py" = ["FLY002"] +"gui/wxpython/tplot/frame.py" = ["FLY002"] "gui/wxpython/wxplot/profile.py" = ["A005"] "lib/imagery/testsuite/test_imagery_sigsetfile.py" = ["FURB152"] -"lib/init/grass.py" = ["INT003"] "python/grass/__init__.py" = ["PYI056"] "python/grass/exp*/tests/grass_script_mapset_session_test.py" = ["SIM117"] "python/grass/exp*/tests/grass_script_tmp_mapset_session_test.py" = ["SIM117"] @@ -346,64 +304,22 @@ ignore = [ "python/grass/jupyter/testsuite/interactivemap_test.py" = ["PGH004"] "python/grass/jupyter/testsuite/map_test.py" = ["PGH004"] "python/grass/pydispatch/signal.py" = ["A005"] -"python/grass/pygrass/raster/category.py" = ["INT002"] -"python/grass/pygrass/vector/__init__.py" = ["INT003"] "python/grass/pygrass/vector/geometry.py" = ["PYI024"] "python/grass/pygrass/vector/sql.py" = ["FLY002"] "python/grass/pygrass/vector/testsuite/test_table.py" = ["PLW0108"] "python/grass/script/array.py" = ["A005"] -"python/grass/script/raster.py" = ["INT003"] -"python/grass/temporal/abstract_space_time_dataset.py" = ["INT003"] -"python/grass/temporal/aggregation.py" = ["INT003"] -"python/grass/temporal/c_libraries_interface.py" = ["INT003"] -"python/grass/temporal/core.py" = ["INT002", "INT003"] -"python/grass/temporal/datetime_math.py" = ["INT003"] -"python/grass/temporal/mapcalc.py" = ["INT003"] -"python/grass/temporal/space_time_datasets.py" = ["INT003"] -"python/grass/temporal/stds_export.py" = ["INT003"] -"python/grass/temporal/stds_import.py" = ["INT003"] -"python/grass/temporal/temporal_algebra.py" = ["INT003"] -"python/grass/temporal/temporal_raster_base_algebra.py" = ["INT003"] -"python/grass/temporal/univar_statistics.py" = ["INT002"] "raster3d/r3.flow/testsuite/r3flow_test.py" = ["FLY002"] "raster3d/r3.gradient/testsuite/r3gradient_test.py" = ["FLY002"] -"scripts/d.polar/d.polar.py" = ["FURB154", "INT002"] -"scripts/g.extension.all/g.extension.all.py" = ["INT002"] -"scripts/g.extension/g.extension.py" = ["INT002"] -"scripts/i.oif/i.oif.py" = ["INT003"] -"scripts/i.pansharpen/i.pansharpen.py" = ["FLY002", "INT003"] -"scripts/i.spectral/i.spectral.py" = ["FLY002", "INT002"] +"scripts/d.polar/d.polar.py" = ["FURB154"] +"scripts/i.pansharpen/i.pansharpen.py" = ["FLY002"] +"scripts/i.spectral/i.spectral.py" = ["FLY002"] "scripts/r.in.srtm/r.in.srtm.py" = ["FLY002"] -"scripts/r.in.wms/wms_base.py" = ["INT003"] -"scripts/r.in.wms/wms_cap_parsers.py" = ["INT003"] -"scripts/r.in.wms/wms_drv.py" = ["INT003"] -"scripts/r.in.wms/wms_gdal_drv.py" = ["INT003"] -"scripts/r.pack/r.pack.py" = ["INT003"] -"scripts/r.tileset/r.tileset.py" = ["INT003"] -"scripts/r.unpack/r.unpack.py" = ["INT002"] -"scripts/v.rast.stats/v.rast.stats.py" = ["INT002"] -"scripts/v.to.lines/v.to.lines.py" = ["INT003"] -"scripts/v.unpack/v.unpack.py" = ["INT002", "INT003"] -"scripts/v.what.strds/v.what.strds.py" = ["INT003"] -"temporal/t.rast.accdetect/t.rast.accdetect.py" = ["INT003"] -"temporal/t.rast.accumulate/t.rast.accumulate.py" = ["INT003"] "temporal/t.rast.algebra/testsu*/*_algebra_arithmetic.py" = ["FLY002"] -"temporal/t.rast.export/t.rast.export.py" = ["INT002"] -"temporal/t.rast.gapfill/t.rast.gapfill.py" = ["INT003"] -"temporal/t.rast.list/t.rast.list.py" = ["INT002"] -"temporal/t.rast.out.vtk/t.rast.out.vtk.py" = ["INT003"] -"temporal/t.rast.series/t.rast.series.py" = ["INT002"] -"temporal/t.rast.to.rast3/t.rast.to.rast3.py" = ["INT003"] -"temporal/t.rast.what/t.rast.what.py" = ["INT003"] "temporal/t.register/testsu*/*_raster_different_local.py" = ["FLY002"] "temporal/t.register/testsu*/*_raster_mapmetadata.py" = ["FLY002"] "temporal/t.register/testsuite/test_t_register_raster.py" = ["FLY002"] "temporal/t.register/testsuite/test_t_register_raster_file.py" = ["FLY002"] -"temporal/t.remove/t.remove.py" = ["INT002", "INT003"] -"temporal/t.unregister/t.unregister.py" = ["INT003"] -"temporal/t.vect.observe.strds/t.vect.observe.strds.py" = ["INT003"] "utils/generate_release_notes.py" = ["PGH004"] -"utils/mkhtml.py" = ["INT002"] "vector/v.fill.holes/examples.ipynb" = ["PTH201"] [tool.ruff.lint.flake8-import-conventions.extend-aliases] diff --git a/python/grass/pygrass/raster/category.py b/python/grass/pygrass/raster/category.py index 00381f91130..cfeb84ddde2 100644 --- a/python/grass/pygrass/raster/category.py +++ b/python/grass/pygrass/raster/category.py @@ -68,7 +68,7 @@ def _get_mtype(self): def _set_mtype(self, mtype): if mtype.upper() not in {"CELL", "FCELL", "DCELL"}: - raise ValueError(_("Raster type: {0} not supported".format(mtype))) + raise ValueError(_("Raster type: {0} not supported").format(mtype)) self._mtype = mtype self._gtype = RTYPE[self.mtype]["grass type"] diff --git a/python/grass/pygrass/vector/__init__.py b/python/grass/pygrass/vector/__init__.py index 6f29a167b2e..b5a24e8d9c1 100644 --- a/python/grass/pygrass/vector/__init__.py +++ b/python/grass/pygrass/vector/__init__.py @@ -855,7 +855,7 @@ def features_to_wkb_list(self, bbox=None, feature_type="point", field=1): if not barray: if error == -1: raise GrassError( - _("Unable to read line of feature %i" % (f_id)) + _("Unable to read line of feature %i") % (f_id) ) if error == -2: print("Empty feature %i" % (f_id)) @@ -947,7 +947,7 @@ def areas_to_wkb_list(self, bbox=None, field=1): self.c_mapinfo, a_id, ctypes.byref(size) ) if not barray: - raise GrassError(_("Unable to read area with id %i" % (a_id))) + raise GrassError(_("Unable to read area with id %i") % (a_id)) pcat = None c_ok = libvect.Vect_get_area_cats( diff --git a/python/grass/script/raster.py b/python/grass/script/raster.py index f9937902dab..32c0639b32f 100644 --- a/python/grass/script/raster.py +++ b/python/grass/script/raster.py @@ -65,8 +65,8 @@ def raster_history(map, overwrite=False, env=None): _( "Unable to write history for <%(map)s>. " "Raster map <%(map)s> not found in current mapset." - % {"map": map, "map": map} ) + % {"map": map, "map": map} ) return False diff --git a/python/grass/temporal/abstract_space_time_dataset.py b/python/grass/temporal/abstract_space_time_dataset.py index 515502ff3f1..cc68f92af2b 100644 --- a/python/grass/temporal/abstract_space_time_dataset.py +++ b/python/grass/temporal/abstract_space_time_dataset.py @@ -2025,7 +2025,7 @@ def shift(self, gran, dbif=None): ) if not check_granularity_string(gran, self.get_temporal_type()): - self.msgr.error(_("Wrong granularity format: %s" % (gran))) + self.msgr.error(_("Wrong granularity format: %s") % (gran)) return False dbif, connection_state_changed = init_dbif(dbif) diff --git a/python/grass/temporal/aggregation.py b/python/grass/temporal/aggregation.py index 1ea60eaeea1..354600855e0 100644 --- a/python/grass/temporal/aggregation.py +++ b/python/grass/temporal/aggregation.py @@ -154,16 +154,14 @@ def aggregate_raster_maps( _( "Raster map <%(name)s> is already in temporal " "database, use overwrite flag to overwrite" - % ({"name": new_map.get_name()}) ) + % ({"name": new_map.get_name()}) ) return msgr.verbose( - _( - "Computing aggregation of maps between %(st)s - %(end)s" - % {"st": str(start), "end": str(end)} - ) + _("Computing aggregation of maps between %(st)s - %(end)s") + % {"st": str(start), "end": str(end)} ) # Create the r.series input file @@ -356,8 +354,9 @@ def aggregate_by_topology( _( "Unable to perform aggregation. Output raster " "map <%(name)s> exists and overwrite flag was " - "not set" % ({"name": output_name}) + "not set" ) + % ({"name": output_name}) ) output_list.append(map_layer) @@ -380,8 +379,8 @@ def aggregate_by_topology( "reached (%i). The module r.series will " "be run with flag z, to avoid open " "files limit exceeding." - % (int(file_limit), len(aggregation_list)) ) + % (int(file_limit), len(aggregation_list)) ) mod(flags="z") process_queue.put(mod) diff --git a/python/grass/temporal/c_libraries_interface.py b/python/grass/temporal/c_libraries_interface.py index 6b67dfb9869..27e0ff62238 100644 --- a/python/grass/temporal/c_libraries_interface.py +++ b/python/grass/temporal/c_libraries_interface.py @@ -815,7 +815,7 @@ def _read_raster3d_info(name, mapset): ) if not g3map: - logging.error(_("Unable to open 3D raster map <%s>" % (name))) + logging.error(_("Unable to open 3D raster map <%s>"), (name)) return None maptype = libraster3d.Rast3d_file_type_map(g3map) @@ -830,7 +830,7 @@ def _read_raster3d_info(name, mapset): max = libgis.DCELL() ret = libraster3d.Rast3d_range_load(g3map) if not ret: - logging.error(_("Unable to load range of 3D raster map <%s>" % (name))) + logging.error(_("Unable to load range of 3D raster map <%s>"), (name)) return None libraster3d.Rast3d_range_min_max(g3map, byref(min), byref(max)) @@ -844,7 +844,7 @@ def _read_raster3d_info(name, mapset): kvp["max"] = float(max.value) if not libraster3d.Rast3d_close(g3map): - logging.error(_("Unable to close 3D raster map <%s>" % (name))) + logging.error(_("Unable to close 3D raster map <%s>"), (name)) return None return kvp @@ -887,10 +887,8 @@ def _read_vector_info(name, mapset): with_topo = False if libvector.Vect_open_old2(byref(Map), name, mapset, "1") < 1: logging.error( - _( - "Unable to open vector map <%s>" - % (libvector.Vect_get_full_name(byref(Map))) - ) + _("Unable to open vector map <%s>"), + (libvector.Vect_get_full_name(byref(Map))), ) return None diff --git a/python/grass/temporal/core.py b/python/grass/temporal/core.py index dc74bff151d..0448ff2371d 100644 --- a/python/grass/temporal/core.py +++ b/python/grass/temporal/core.py @@ -769,12 +769,12 @@ def init(raise_fatal_error=False, skip_db_version_check=False): "Temporal database version mismatch detected.\n{backup}" "Supported temporal database version is: {tdb}\n" "Your existing temporal database version: {ctdb}\n" - "Current temporal database info: {info}".format( - backup=backup_howto, - tdb=tgis_db_version, - ctdb=tgis_db_version_meta, - info=get_database_info_string(), - ) + "Current temporal database info: {info}" + ).format( + backup=backup_howto, + tdb=tgis_db_version, + ctdb=tgis_db_version_meta, + info=get_database_info_string(), ) if tgis_db_version_meta == 2 and tgis_db_version == 3: @@ -784,8 +784,8 @@ def init(raise_fatal_error=False, skip_db_version_check=False): msgr.fatal( _( "The format of your actual temporal database is " - "not supported any more. {m}".format(m=message) - ) + "not supported any more. {m}" + ).format(m=message) ) return @@ -862,7 +862,7 @@ def create_temporal_database(dbif): stvds_tables_sql = stds_tables_template_sql.replace("STDS", "stvds") str3ds_tables_sql = stds_tables_template_sql.replace("STDS", "str3ds") - msgr.message(_("Creating temporal database: %s" % (str(tgis_database_string)))) + msgr.message(_("Creating temporal database: %s") % (str(tgis_database_string))) if tgis_backend == "sqlite": # We need to create the sqlite3 database path if it does not exist @@ -875,8 +875,9 @@ def create_temporal_database(dbif): _( "Unable to create SQLite temporal database\n" "Exception: %s\nPlease use t.connect to set a " - "read- and writable temporal database path" % (e) + "read- and writable temporal database path" ) + % (e) ) # Set up the trigger that takes care of @@ -1502,7 +1503,7 @@ def execute(self, statement, args=None): except: if connected: self.close() - self.msgr.error(_("Unable to execute :\n %(sql)s" % {"sql": statement})) + self.msgr.error(_("Unable to execute :\n %(sql)s") % {"sql": statement}) raise if connected: @@ -1546,7 +1547,7 @@ def execute_transaction(self, statement, mapset=None): if connected: self.close() self.msgr.error( - _("Unable to execute transaction:\n %(sql)s" % {"sql": statement}) + _("Unable to execute transaction:\n %(sql)s") % {"sql": statement} ) raise diff --git a/python/grass/temporal/datetime_math.py b/python/grass/temporal/datetime_math.py index 9b680760775..1031582fe23 100644 --- a/python/grass/temporal/datetime_math.py +++ b/python/grass/temporal/datetime_math.py @@ -828,7 +828,7 @@ def check_datetime_string(time_string, use_dateutil=True): try: return datetime.strptime(time_string, time_format) except: - return _("Unable to parse time string: %s" % time_string) + return _("Unable to parse time string: %s") % time_string ############################################################################### diff --git a/python/grass/temporal/mapcalc.py b/python/grass/temporal/mapcalc.py index 5f29cd32747..8761e86160f 100644 --- a/python/grass/temporal/mapcalc.py +++ b/python/grass/temporal/mapcalc.py @@ -508,90 +508,72 @@ def _parse_start_operators(expr, is_time_absolute, current): if expr.find("start_year()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("start_*") - ) + _("The temporal operators <%s> support only absolute time.") + % ("start_*") ) expr = expr.replace("start_year()", str(start.year)) if expr.find("start_month()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("start_*") - ) + _("The temporal operators <%s> support only absolute time.") + % ("start_*") ) expr = expr.replace("start_month()", str(start.month)) if expr.find("start_week()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("start_*") - ) + _("The temporal operators <%s> support only absolute time.") + % ("start_*") ) expr = expr.replace("start_week()", str(start.isocalendar()[1])) if expr.find("start_day()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("start_*") - ) + _("The temporal operators <%s> support only absolute time.") + % ("start_*") ) expr = expr.replace("start_day()", str(start.day)) if expr.find("start_hour()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("start_*") - ) + _("The temporal operators <%s> support only absolute time.") + % ("start_*") ) expr = expr.replace("start_hour()", str(start.hour)) if expr.find("start_minute()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("start_*") - ) + _("The temporal operators <%s> support only absolute time.") + % ("start_*") ) expr = expr.replace("start_minute()", str(start.minute)) if expr.find("start_second()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("start_*") - ) + _("The temporal operators <%s> support only absolute time.") + % ("start_*") ) expr = expr.replace("start_second()", str(start.second)) if expr.find("start_dow()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("start_*") - ) + _("The temporal operators <%s> support only absolute time.") + % ("start_*") ) expr = expr.replace("start_dow()", str(start.isoweekday())) if expr.find("start_doy()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("start_*") - ) + _("The temporal operators <%s> support only absolute time.") + % ("start_*") ) year = datetime(start.year, 1, 1) delta = start - year @@ -628,10 +610,7 @@ def _parse_end_operators(expr, is_time_absolute, current): if expr.find("end_year()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("end_*") - ) + _("The temporal operators <%s> support only absolute time.") % ("end_*") ) if not end: expr = expr.replace("end_year()", "null()") @@ -641,10 +620,7 @@ def _parse_end_operators(expr, is_time_absolute, current): if expr.find("end_month()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("end_*") - ) + _("The temporal operators <%s> support only absolute time.") % ("end_*") ) if not end: expr = expr.replace("end_month()", "null()") @@ -654,10 +630,7 @@ def _parse_end_operators(expr, is_time_absolute, current): if expr.find("end_week()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("end_*") - ) + _("The temporal operators <%s> support only absolute time.") % ("end_*") ) if not end: expr = expr.replace("end_week()", "null()") @@ -667,10 +640,7 @@ def _parse_end_operators(expr, is_time_absolute, current): if expr.find("end_day()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("end_*") - ) + _("The temporal operators <%s> support only absolute time.") % ("end_*") ) if not end: expr = expr.replace("end_day()", "null()") @@ -680,10 +650,7 @@ def _parse_end_operators(expr, is_time_absolute, current): if expr.find("end_hour()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("end_*") - ) + _("The temporal operators <%s> support only absolute time.") % ("end_*") ) if not end: expr = expr.replace("end_hour()", "null()") @@ -693,10 +660,7 @@ def _parse_end_operators(expr, is_time_absolute, current): if expr.find("end_minute()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("end_*") - ) + _("The temporal operators <%s> support only absolute time.") % ("end_*") ) if not end: expr = expr.replace("end_minute()", "null()") @@ -706,10 +670,7 @@ def _parse_end_operators(expr, is_time_absolute, current): if expr.find("end_second()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("end_*") - ) + _("The temporal operators <%s> support only absolute time.") % ("end_*") ) if not end: expr = expr.replace("end_second()", "null()") @@ -719,10 +680,7 @@ def _parse_end_operators(expr, is_time_absolute, current): if expr.find("end_dow()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("end_*") - ) + _("The temporal operators <%s> support only absolute time.") % ("end_*") ) if not end: expr = expr.replace("end_dow()", "null()") @@ -732,10 +690,7 @@ def _parse_end_operators(expr, is_time_absolute, current): if expr.find("end_doy()") >= 0: if not is_time_absolute: msgr.fatal( - _( - "The temporal operators <%s> support only absolute " - "time." % ("end_*") - ) + _("The temporal operators <%s> support only absolute time.") % ("end_*") ) if not end: expr = expr.replace("end_doy()", "null()") diff --git a/python/grass/temporal/space_time_datasets.py b/python/grass/temporal/space_time_datasets.py index a73e03fff46..ec01bf45baa 100644 --- a/python/grass/temporal/space_time_datasets.py +++ b/python/grass/temporal/space_time_datasets.py @@ -288,10 +288,8 @@ def read_timestamp_from_grass(self): if check < 1: self.msgr.error( - _( - "Unable to read timestamp file " - "for raster map <%s>" % (self.get_map_id()) - ) + _("Unable to read timestamp file for raster map <%s>") + % (self.get_map_id()) ) return False @@ -316,19 +314,15 @@ def write_timestamp_to_grass(self): if check == -1: self.msgr.error( - _( - "Unable to create timestamp file " - "for raster map <%s>" % (self.get_map_id()) - ) + _("Unable to create timestamp file for raster map <%s>") + % (self.get_map_id()) ) return False if check == -2: self.msgr.error( - _( - "Invalid datetime in timestamp for raster map " - "<%s>" % (self.get_map_id()) - ) + _("Invalid datetime in timestamp for raster map <%s>") + % (self.get_map_id()) ) return False @@ -350,7 +344,7 @@ def remove_timestamp_from_grass(self): if check == -1: self.msgr.error( - _("Unable to remove timestamp for raster map <%s>" % (self.get_name())) + _("Unable to remove timestamp for raster map <%s>") % (self.get_name()) ) return False @@ -390,10 +384,8 @@ def write_semantic_label_to_grass(self): ) if check == -1: self.msgr.error( - _( - "Unable to write semantic label for raster map <%s>" - % (self.get_name()) - ) + _("Unable to write semantic label for raster map <%s>") + % (self.get_name()) ) return False @@ -741,10 +733,8 @@ def read_timestamp_from_grass(self): if check < 1: self.msgr.error( - _( - "Unable to read timestamp file " - "for 3D raster map <%s>" % (self.get_map_id()) - ) + _("Unable to read timestamp file for 3D raster map <%s>") + % (self.get_map_id()) ) return False @@ -769,19 +759,15 @@ def write_timestamp_to_grass(self): if check == -1: self.msgr.error( - _( - "Unable to create timestamp file " - "for 3D raster map <%s>" % (self.get_map_id()) - ) + _("Unable to create timestamp file for 3D raster map <%s>") + % (self.get_map_id()) ) return False if check == -2: self.msgr.error( - _( - "Invalid datetime in timestamp for 3D raster " - "map <%s>" % (self.get_map_id()) - ) + _("Invalid datetime in timestamp for 3D raster map <%s>") + % (self.get_map_id()) ) return False @@ -802,10 +788,7 @@ def remove_timestamp_from_grass(self): if check == -1: self.msgr.error( - _( - "Unable to remove timestamp for raster map " - "<%s>" % (self.get_name()) - ) + _("Unable to remove timestamp for raster map <%s>") % (self.get_name()) ) return False @@ -1091,10 +1074,8 @@ def read_timestamp_from_grass(self): if check < 1: self.msgr.error( - _( - "Unable to read timestamp file " - "for vector map <%s>" % (self.get_map_id()) - ) + _("Unable to read timestamp file for vector map <%s>") + % (self.get_map_id()) ) return False @@ -1120,19 +1101,15 @@ def write_timestamp_to_grass(self): if check == -1: self.msgr.error( - _( - "Unable to create timestamp file " - "for vector map <%s>" % (self.get_map_id()) - ) + _("Unable to create timestamp file for vector map <%s>") + % (self.get_map_id()) ) return False if check == -2: self.msgr.error( - _( - "Invalid datetime in timestamp for vector " - "map <%s>" % (self.get_map_id()) - ) + _("Invalid datetime in timestamp for vector map <%s>") + % (self.get_map_id()) ) return False @@ -1148,9 +1125,8 @@ def remove_timestamp_from_grass(self): if check == -1: self.msgr.error( - _( - "Unable to remove timestamp for vector " - "map <%s>" % (self.get_name()) + _("Unable to remove timestamp for vector map <%s>").format( + self.get_name() ) ) return False diff --git a/python/grass/temporal/stds_export.py b/python/grass/temporal/stds_export.py index 70dbdcada0f..ff2731b102a 100644 --- a/python/grass/temporal/stds_export.py +++ b/python/grass/temporal/stds_export.py @@ -127,7 +127,7 @@ def _export_raster_maps_as_gdal( except CalledModuleError: shutil.rmtree(new_cwd) tar.close() - gs.fatal(_("Unable to export raster map <%s>" % name)) + gs.fatal(_("Unable to export raster map <%s>") % name) tar.add(out_name) @@ -139,10 +139,7 @@ def _export_raster_maps_as_gdal( shutil.rmtree(new_cwd) tar.close() gs.fatal( - _( - "Unable to export color rules for raster " - "map <%s> r.out.gdal" % name - ) + _("Unable to export color rules for raster map <%s> r.out.gdal") % name ) tar.add(out_name) @@ -168,7 +165,7 @@ def _export_raster_maps(rows, tar, list_file, new_cwd, fs): except CalledModuleError: shutil.rmtree(new_cwd) tar.close() - gs.fatal(_("Unable to export raster map <%s> with r.pack" % name)) + gs.fatal(_("Unable to export raster map <%s> with r.pack") % name) tar.add(name + ".pack") @@ -201,7 +198,7 @@ def _export_vector_maps_as_gml(rows, tar, list_file, new_cwd, fs): except CalledModuleError: shutil.rmtree(new_cwd) tar.close() - gs.fatal(_("Unable to export vector map <%s> as GML with v.out.ogr" % name)) + gs.fatal(_("Unable to export vector map <%s> as GML with v.out.ogr") % name) tar.add(name + ".xml") tar.add(name + ".xsd") @@ -236,7 +233,7 @@ def _export_vector_maps_as_gpkg(rows, tar, list_file, new_cwd, fs): shutil.rmtree(new_cwd) tar.close() gs.fatal( - _("Unable to export vector map <%s> as GPKG with v.out.ogr" % name) + _("Unable to export vector map <%s> as GPKG with v.out.ogr") % name ) tar.add(name + ".gpkg") @@ -269,7 +266,7 @@ def _export_vector_maps(rows, tar, list_file, new_cwd, fs): except CalledModuleError: shutil.rmtree(new_cwd) tar.close() - gs.fatal(_("Unable to export vector map <%s> with v.pack" % name)) + gs.fatal(_("Unable to export vector map <%s> with v.pack") % name) tar.add(name + ".pack") @@ -295,7 +292,7 @@ def _export_raster3d_maps(rows, tar, list_file, new_cwd, fs): except CalledModuleError: shutil.rmtree(new_cwd) tar.close() - gs.fatal(_("Unable to export raster map <%s> with r3.pack" % name)) + gs.fatal(_("Unable to export raster map <%s> with r3.pack") % name) tar.add(name + ".pack") diff --git a/python/grass/temporal/stds_import.py b/python/grass/temporal/stds_import.py index 03810e49b89..ae587cadb0f 100644 --- a/python/grass/temporal/stds_import.py +++ b/python/grass/temporal/stds_import.py @@ -254,10 +254,8 @@ def import_stds( # Check for important files msgr = get_tgis_message_interface() msgr.message( - _( - "Checking validity of input file (size: %0.1f MB). Make take a while..." - % (os.path.getsize(input) / (1024 * 1024.0)) - ) + _("Checking validity of input file (size: %0.1f MB). Make take a while...") + % (os.path.getsize(input) / (1024 * 1024.0)) ) members = tar.getnames() # Make sure that the basenames of the files are used for comparison diff --git a/python/grass/temporal/temporal_algebra.py b/python/grass/temporal/temporal_algebra.py index 3736a15315a..1b9a126c635 100644 --- a/python/grass/temporal/temporal_algebra.py +++ b/python/grass/temporal/temporal_algebra.py @@ -1195,7 +1195,7 @@ def remove_maps(self): for key, value in map_names.items(): if value: - self.msgr.message(_("Removing un-needed or empty %s maps" % (key))) + self.msgr.message(_("Removing un-needed or empty %s maps") % (key)) self._remove_maps(value, key) def _remove_maps(self, namelist, map_type): @@ -2392,8 +2392,8 @@ def p_statement_assign(self, t): _( "The resulting space time dataset type <%(a)s> " "is different from the requested type <%(b)s>" - % ({"a": maps_stds_type, "b": self.stdstype}) ) + % ({"a": maps_stds_type, "b": self.stdstype}) ) else: map_type_2 = map_i.get_type() diff --git a/python/grass/temporal/temporal_raster_base_algebra.py b/python/grass/temporal/temporal_raster_base_algebra.py index 76517db30cc..3424110803f 100644 --- a/python/grass/temporal/temporal_raster_base_algebra.py +++ b/python/grass/temporal/temporal_raster_base_algebra.py @@ -873,7 +873,7 @@ def p_statement_assign(self, t): process_queue.put(m) else: - self.msgr.error(_("Error computing map <%s>" % map_i.get_id())) + self.msgr.error(_("Error computing map <%s>") % map_i.get_id()) count += 1 if self.dry_run is False: diff --git a/python/grass/temporal/univar_statistics.py b/python/grass/temporal/univar_statistics.py index 9bf29f74eba..96a9f65474d 100755 --- a/python/grass/temporal/univar_statistics.py +++ b/python/grass/temporal/univar_statistics.py @@ -65,12 +65,9 @@ def compute_univar_stats(registered_map_info, stats_module, fs, rast_region=Fals if not univar_stats: gs.warning( - _( - "Unable to get statistics for {voxel}raster map " - "<{rmap}>".format( - rmap=id, voxel="" if stats_module.name == "r.univar" else "3d " - ) - ) + _("Unable to get statistics for raster map <%s>") % id + if stats_module.name == "r.univar" + else _("Unable to get statistics for 3d raster map <%s>") % id ) return None eol = "" diff --git a/scripts/d.polar/d.polar.py b/scripts/d.polar/d.polar.py index f592dd89b63..915177e94d4 100755 --- a/scripts/d.polar/d.polar.py +++ b/scripts/d.polar/d.polar.py @@ -425,8 +425,8 @@ def main(): gcore.fatal( _( "EPS output file path <{}>, doesn't exists. " - "Set new output file path.".format(eps) - ) + "Set new output file path." + ).format(eps) ) else: eps = basename(eps, "eps") + ".eps" @@ -436,8 +436,8 @@ def main(): gcore.fatal( _( "option : <{}> exists. To overwrite, " - "use the --overwrite flag.".format(eps) - ) + "use the --overwrite flag." + ).format(eps) ) # check if we have xgraph (if no EPS output requested) diff --git a/scripts/g.extension.all/g.extension.all.py b/scripts/g.extension.all/g.extension.all.py index 026589cca10..7f0b36f4dc6 100644 --- a/scripts/g.extension.all/g.extension.all.py +++ b/scripts/g.extension.all/g.extension.all.py @@ -111,11 +111,11 @@ def download_modules_xml_file(url, response_format, *args, **kwargs): _( "Download file from <{url}>, " "return status code {code}, " - "{desc}".format( - url=url, - code=response.code, - desc=desc, - ), + "{desc}" + ).format( + url=url, + code=response.code, + desc=desc, ), ) if response_format not in response.getheader("Content-Type"): @@ -123,10 +123,10 @@ def download_modules_xml_file(url, response_format, *args, **kwargs): _( "Wrong file format downloaded. " "Check url <{url}>. Allowed file format is " - "{response_format}.".format( - url=url, - response_format=response_format, - ), + "{response_format}." + ).format( + url=url, + response_format=response_format, ), ) return response @@ -138,8 +138,8 @@ def download_modules_xml_file(url, response_format, *args, **kwargs): "The download of the modules.xml file " "from the server was not successful. " "File on the server <{url}> doesn't " - "exists.".format(url=url), - ), + "exists." + ).format(url=url), ) else: return download_modules_xml_file( @@ -148,11 +148,8 @@ def download_modules_xml_file(url, response_format, *args, **kwargs): ) except URLError: gs.fatal( - _( - "Download file from <{url}>, " - "failed. Check internet connection.".format( - url=url, - ), + _("Download file from <{url}>, failed. Check internet connection.").format( + url=url, ), ) @@ -199,9 +196,8 @@ def find_addon_name(addons): gs.warning( _( "The <{}> addon cannot be reinstalled. " - "Addon wasn't found among the official " - "addons.".format(addon) - ), + "Addon wasn't found among the official addons." + ).format(addon), ) return set(result) diff --git a/scripts/g.extension/g.extension.py b/scripts/g.extension/g.extension.py index 3b0c15c0bfc..bf8cd183135 100644 --- a/scripts/g.extension/g.extension.py +++ b/scripts/g.extension/g.extension.py @@ -541,10 +541,8 @@ def get_default_branch(full_url): organization, repository = url_parts.path.split("/")[1:3] except URLError: gs.fatal( - _( - "Cannot retrieve organization and repository from URL: <{}>.".format( - full_url - ) + _("Cannot retrieve organization and repository from URL: <{}>.").format( + full_url ) ) # Construct API call and retrieve default branch @@ -583,10 +581,8 @@ def etree_fromurl(url): _( "Download file from <{url}>," " failed. File is not on the server or" - " check your internet connection.".format( - url=url, - ), - ), + " check your internet connection." + ).format(url=url), ) return ET.fromstring(file_.read()) diff --git a/scripts/i.oif/i.oif.py b/scripts/i.oif/i.oif.py index cfee7890120..aea65197954 100755 --- a/scripts/i.oif/i.oif.py +++ b/scripts/i.oif/i.oif.py @@ -47,7 +47,7 @@ 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) diff --git a/scripts/i.pansharpen/i.pansharpen.py b/scripts/i.pansharpen/i.pansharpen.py index f344c5ac7fd..c62a53a536a 100755 --- a/scripts/i.pansharpen/i.pansharpen.py +++ b/scripts/i.pansharpen/i.pansharpen.py @@ -402,7 +402,7 @@ def main(): gs.run_command("g.region", res=panres, align=pan) # Select sharpening method - gs.message(_("Performing pan sharpening with hi res pan image: %f" % panres)) + gs.message(_("Performing pan sharpening with hi res pan image: %f") % panres) if sharpen == "brovey": brovey(pan, ms1, ms2, ms3, out, pid, sproc) elif sharpen == "ihs": @@ -437,8 +437,8 @@ def main(): for ch in ["red", "green", "blue"]: gs.verbose(_("%s_%s") % (out, ch)) - gs.verbose(_("To visualize output, run: g.region -p raster=%s_red" % out)) - gs.verbose(_("d.rgb r=%s_red g=%s_green b=%s_blue" % (out, out, out))) + gs.verbose(_("To visualize output, run: g.region -p raster=%s_red") % out) + gs.verbose(_("d.rgb r=%s_red g=%s_green b=%s_blue") % (out, out, out)) gs.verbose( _("If desired, combine channels into a single RGB map with 'r.composite'.") ) diff --git a/scripts/i.spectral/i.spectral.py b/scripts/i.spectral/i.spectral.py index d40c1076169..171eac7359c 100755 --- a/scripts/i.spectral/i.spectral.py +++ b/scripts/i.spectral/i.spectral.py @@ -197,8 +197,8 @@ def draw_linegraph(what): gcore.fatal( _( "Supported monitor isn't running. Please launch one of the" - " monitors {}.".format(", ".join(supported_monitors)) - ) + " monitors {}." + ).format(", ".join(supported_monitors)) ) selected_monitor = gcore.read_command("d.mon", flags="p", quiet=True).replace( "\n", "" @@ -207,17 +207,15 @@ def draw_linegraph(what): gcore.fatal( _( "Supported monitor isn't selected. Please select one of the" - " monitors {}.".format(", ".join(supported_monitors)) - ) + " monitors {}." + ).format(", ".join(supported_monitors)) ) with open(gcore.parse_command("d.mon", flags="g", quiet=True)["env"]) as f: for line in f: if "GRASS_RENDER_FILE=" in line: gcore.info( - _( - "{} monitor is used, output file {}".format( - selected_monitor.capitalize(), line.split("=")[-1] - ) + _("{} monitor is used, output file {}").format( + selected_monitor.capitalize(), line.split("=")[-1] ) ) break diff --git a/scripts/r.in.wms/wms_base.py b/scripts/r.in.wms/wms_base.py index a14e15dc786..234456f1518 100644 --- a/scripts/r.in.wms/wms_base.py +++ b/scripts/r.in.wms/wms_base.py @@ -78,10 +78,8 @@ def _initializeParameters(self, options, flags): self.params["password"] == "" and self.params["username"] ): gs.fatal( - _( - "Please insert both %s and %s parameters or none of them." - % ("password", "username") - ) + _("Please insert both %s and %s parameters or none of them.") + % ("password", "username") ) self.params["bgcolor"] = options["bgcolor"].strip() @@ -202,8 +200,8 @@ def _checkIgnoeredParams(self, options, flags, driver_props): _( "These parameter are ignored: %s\n\ %s driver does not support the parameters." - % (",".join(not_relevant_params), options["driver"]) ) + % (",".join(not_relevant_params), options["driver"]) ) not_relevant_flags = [] @@ -216,8 +214,8 @@ def _checkIgnoeredParams(self, options, flags, driver_props): _( "These flags are ignored: %s\n\ %s driver does not support the flags." - % (",".join(not_relevant_flags), options["driver"]) ) + % (",".join(not_relevant_flags), options["driver"]) ) def GetMap(self, options, flags): @@ -308,7 +306,7 @@ def GetCapabilities(self, options): Path(capfile_output).write_text(cap) return except OSError as error: - gs.fatal(_("Unable to open file '%s'.\n%s\n" % (capfile_output, error))) + gs.fatal(_("Unable to open file '%s'.\n%s\n") % (capfile_output, error)) # print to output print(cap) diff --git a/scripts/r.in.wms/wms_cap_parsers.py b/scripts/r.in.wms/wms_cap_parsers.py index 5483be0979f..56b1d0ce48c 100644 --- a/scripts/r.in.wms/wms_cap_parsers.py +++ b/scripts/r.in.wms/wms_cap_parsers.py @@ -45,7 +45,7 @@ def __init__(self, cap_file): raise ParseError(_("Unable to parse XML file")) except OSError as error: raise ParseError( - _("Unable to open XML file '%s'.\n%s\n" % (cap_file, error)) + _("Unable to open XML file '%s'.\n%s\n") % (cap_file, error) ) else: try: diff --git a/scripts/r.in.wms/wms_drv.py b/scripts/r.in.wms/wms_drv.py index 1e7a90e9938..186157ad6db 100644 --- a/scripts/r.in.wms/wms_drv.py +++ b/scripts/r.in.wms/wms_drv.py @@ -286,7 +286,7 @@ def _pct2rgb(self, src_filename, dst_filename): # open source file src_ds = gdal.Open(src_filename) if src_ds is None: - gs.fatal(_("Unable to open %s " % src_filename)) + gs.fatal(_("Unable to open %s ") % src_filename) src_band = src_ds.GetRasterBand(band_number) diff --git a/scripts/r.in.wms/wms_gdal_drv.py b/scripts/r.in.wms/wms_gdal_drv.py index d17bac11eee..69a49ca5429 100644 --- a/scripts/r.in.wms/wms_gdal_drv.py +++ b/scripts/r.in.wms/wms_gdal_drv.py @@ -172,7 +172,7 @@ def _download(self): driver = gdal.GetDriverByName(self.gdal_drv_format) if driver is None: - gs.fatal(_("Unable to find %s driver" % format)) + gs.fatal(_("Unable to find %s driver") % self.gdal_drv_format) metadata = driver.GetMetadata() if ( diff --git a/scripts/r.pack/r.pack.py b/scripts/r.pack/r.pack.py index cd7d6c39282..eb11547322c 100644 --- a/scripts/r.pack/r.pack.py +++ b/scripts/r.pack/r.pack.py @@ -180,7 +180,7 @@ def main(): os.chdir(olddir) - grass.verbose(_("Raster map saved to '%s'" % outfile)) + grass.verbose(_("Raster map saved to '%s'") % outfile) if __name__ == "__main__": diff --git a/scripts/r.tileset/r.tileset.py b/scripts/r.tileset/r.tileset.py index f5e7ab17b13..c3fba2c173e 100644 --- a/scripts/r.tileset/r.tileset.py +++ b/scripts/r.tileset/r.tileset.py @@ -246,16 +246,16 @@ def main(): _( "It is not possible to set 'maxcols=%s' and " "'overlap=%s'. Please set maxcols>overlap" - % (options["maxcols"], options["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"]) ) + % (options["maxrows"], options["overlap"]) ) # destination projection if not options["destproj"]: @@ -397,7 +397,7 @@ def main(): if errors_dest > 0: gcore.warning( - _("During computation %i tiles could not be created" % errors_dest) + _("During computation %i tiles could not be created") % errors_dest ) while xi < ximax: diff --git a/scripts/r.unpack/r.unpack.py b/scripts/r.unpack/r.unpack.py index 053ac96988b..575d465ebb5 100644 --- a/scripts/r.unpack/r.unpack.py +++ b/scripts/r.unpack/r.unpack.py @@ -63,7 +63,7 @@ def main(): 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( @@ -87,7 +87,7 @@ def main(): 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))) + grass.fatal(_("Pack file unreadable: file '{}' missing").format(fname)) tar.close() return 0 @@ -100,13 +100,11 @@ def main(): 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))) + 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 ) ) @@ -132,9 +130,10 @@ def main(): grass.fatal( _( "This GRASS GIS pack file contains vector data. Use " - "v.unpack to unpack <{name}>".format(name=map_name) - ) + "v.unpack to unpack <{name}>" + ).format(name=map_name) ) + else: grass.fatal(_("Pack file unreadable")) @@ -246,7 +245,7 @@ def main(): files = "\n".join(maps) Path(vrt_file).write_text(files) - grass.message(_("Raster map <{name}> unpacked".format(name=map_name))) + grass.message(_("Raster map <{name}> unpacked").format(name=map_name)) if __name__ == "__main__": diff --git a/scripts/v.rast.stats/v.rast.stats.py b/scripts/v.rast.stats/v.rast.stats.py index 1e1451f6b84..803fc8691ad 100644 --- a/scripts/v.rast.stats/v.rast.stats.py +++ b/scripts/v.rast.stats/v.rast.stats.py @@ -143,10 +143,8 @@ def main(): gs.fatal( _( "Number of raster maps ({0}) different from \ - number of column prefixes ({1})".format( - len(rasters), len(colprefixes) - ) - ) + number of column prefixes ({1})" + ).format(len(rasters), len(colprefixes)) ) vector = vs[0] @@ -340,10 +338,8 @@ def get_nr_of_categories( gs.warning( _( "Not all vector categories converted to raster. \ - Converted {0} of {1}.".format( - number, vect_cats_n - ) - ) + Converted {0} of {1}." + ).format(number, vect_cats_n) ) return number diff --git a/scripts/v.to.lines/v.to.lines.py b/scripts/v.to.lines/v.to.lines.py index bfcb2e45bc2..0630ad86401 100644 --- a/scripts/v.to.lines/v.to.lines.py +++ b/scripts/v.to.lines/v.to.lines.py @@ -189,7 +189,7 @@ def main(): gs.fatal(_("Error removing table from layer 1")) # TODO: when this except is happaning, it seems that never, so it seems wrong except Exception: - gs.warning(_("No table for layer %d" % 1)) + gs.warning(_("No table for layer %d") % 1) try: gs.run_command( "v.category", diff --git a/scripts/v.unpack/v.unpack.py b/scripts/v.unpack/v.unpack.py index 0507e9eb400..419e133b195 100644 --- a/scripts/v.unpack/v.unpack.py +++ b/scripts/v.unpack/v.unpack.py @@ -87,7 +87,7 @@ def main(): f = tar.extractfile(fname) sys.stdout.write(f.read().decode()) except KeyError: - grass.fatal(_("Pack file unreadable: file '{}' missing".format(fname))) + grass.fatal(_("Pack file unreadable: file '{}' missing").format(fname)) tar.close() return 0 @@ -139,8 +139,9 @@ def main(): grass.fatal( _( "This GRASS GIS pack file contains raster data. Use " - "r.unpack to unpack <%s>" % map_name + "r.unpack to unpack <%s>" ) + % map_name ) else: grass.fatal(_("Pack file unreadable")) diff --git a/scripts/v.what.strds/v.what.strds.py b/scripts/v.what.strds/v.what.strds.py index 2bd6cd72131..0e1bf893f98 100644 --- a/scripts/v.what.strds/v.what.strds.py +++ b/scripts/v.what.strds/v.what.strds.py @@ -169,13 +169,13 @@ def main(): "datasets must be equal\n<%(a)s> of type " "%(type_a)s do not match <%(b)s> of type " "%(type_b)s" - % { - "a": first_strds.get_id(), - "type_a": first_strds.get_temporal_type(), - "b": dataset.get_id(), - "type_b": dataset.get_temporal_type(), - } ) + % { + "a": first_strds.get_id(), + "type_a": first_strds.get_temporal_type(), + "b": dataset.get_id(), + "type_b": dataset.get_temporal_type(), + } ) mapmatrizes = tgis.sample_stds_by_stds_topology( @@ -227,7 +227,7 @@ def main(): pymap.open("r") except: dbif.close() - gs.fatal(_("Unable to create vector map <%s>" % output)) + gs.fatal(_("Unable to create vector map <%s>") % output) if len(pymap.dblinks) == 0: try: @@ -235,7 +235,7 @@ def main(): gs.run_command("v.db.addtable", map=output) except CalledModuleError: dbif.close() - gs.fatal(_("Unable to add table <%s> to vector map <%s>" % output)) + gs.fatal(_("Unable to add table <%s> to vector map <%s>") % output) if pymap.is_open(): pymap.close() diff --git a/temporal/t.rast.accdetect/t.rast.accdetect.py b/temporal/t.rast.accdetect/t.rast.accdetect.py index 887616f7a1c..1588b44d4b9 100644 --- a/temporal/t.rast.accdetect/t.rast.accdetect.py +++ b/temporal/t.rast.accdetect/t.rast.accdetect.py @@ -341,7 +341,7 @@ def main(): if len(input_maps) == 0: continue - gs.message(_("Processing cycle %s - %s" % (str(start), str(end)))) + gs.message(_("Processing cycle %s - %s") % (str(start), str(end))) count = compute_occurrence( occurrence_maps, diff --git a/temporal/t.rast.accumulate/t.rast.accumulate.py b/temporal/t.rast.accumulate/t.rast.accumulate.py index 94344f2d9cc..6fe067e02bc 100644 --- a/temporal/t.rast.accumulate/t.rast.accumulate.py +++ b/temporal/t.rast.accumulate/t.rast.accumulate.py @@ -323,7 +323,7 @@ def main(): where = "start_time >= '%s' AND start_time < '%s'" % (str(start), str(end)) input_maps = input_strds.get_registered_maps_as_objects(where=where, dbif=dbif) - gs.message(_("Processing cycle %s - %s" % (str(start), str(end)))) + gs.message(_("Processing cycle %s - %s") % (str(start), str(end))) if len(input_maps) == 0: continue diff --git a/temporal/t.rast.export/t.rast.export.py b/temporal/t.rast.export/t.rast.export.py index 675040bf5aa..fdf19541ee4 100755 --- a/temporal/t.rast.export/t.rast.export.py +++ b/temporal/t.rast.export/t.rast.export.py @@ -127,10 +127,10 @@ def main(): } if not directory or not os.path.exists(directory): - gs.fatal(_("Directory {} not found".format(directory))) + gs.fatal(_("Directory {} not found").format(directory)) if not os.access(directory, os.W_OK): - gs.fatal(_("Directory {} is not writable".format(directory))) + gs.fatal(_("Directory {} is not writable").format(directory)) if _type and _format in {"pack", "AAIGrid"}: gs.warning( diff --git a/temporal/t.rast.gapfill/t.rast.gapfill.py b/temporal/t.rast.gapfill/t.rast.gapfill.py index e2ffb149513..84395da6295 100755 --- a/temporal/t.rast.gapfill/t.rast.gapfill.py +++ b/temporal/t.rast.gapfill/t.rast.gapfill.py @@ -208,8 +208,9 @@ def main(): gs.fatal( _( "Map with name <%s> already exists. " - "Please use another base name." % (_id) + "Please use another base name." ) + % (_id) ) elif new_map.is_in_db(dbif): overwrite_flags[new_id] = True diff --git a/temporal/t.rast.list/t.rast.list.py b/temporal/t.rast.list/t.rast.list.py index 651bc69b956..0209d0aeee6 100755 --- a/temporal/t.rast.list/t.rast.list.py +++ b/temporal/t.rast.list/t.rast.list.py @@ -108,7 +108,13 @@ def message_option_value_excludes_option_value( return _( "Combining {option_name}={option_value} and " "{excluded_option_name}={excluded_option_value} is not allowed. {reason}" - ).format(**locals()) + ).format( + option_name=option_name, + option_value=option_value, + excluded_option_name=excluded_option_name, + excluded_option_value=excluded_option_value, + reason=reason, + ) def message_option_value_excludes_option( @@ -117,13 +123,23 @@ def message_option_value_excludes_option( return _( "The option {excluded_option_name} is not allowed with " "{option_name}={option_value}. {reason}" - ).format(**locals()) + ).format( + excluded_option_name=excluded_option_name, + option_name=option_name, + option_value=option_value, + reason=reason, + ) def message_option_value_excludes_flag(option_name, option_value, flag_name, reason): return _( "The flag -{flag_name} is not allowed with {option_name}={option_value}." - " {reason}".format(**locals()) + " {reason}" + ).format( + flag_name=flag_name, + option_name=option_name, + option_value=option_value, + reason=reason, ) diff --git a/temporal/t.rast.out.vtk/t.rast.out.vtk.py b/temporal/t.rast.out.vtk/t.rast.out.vtk.py index a042168499a..876770e4c4e 100755 --- a/temporal/t.rast.out.vtk/t.rast.out.vtk.py +++ b/temporal/t.rast.out.vtk/t.rast.out.vtk.py @@ -160,7 +160,7 @@ def main(): overwrite=gs.overwrite(), ) except CalledModuleError: - gs.fatal(_("Unable to export raster map <%s>" % map_name)) + gs.fatal(_("Unable to export raster map <%s>") % map_name) count += 1 diff --git a/temporal/t.rast.series/t.rast.series.py b/temporal/t.rast.series/t.rast.series.py index 074f35a00a0..57907f463e4 100755 --- a/temporal/t.rast.series/t.rast.series.py +++ b/temporal/t.rast.series/t.rast.series.py @@ -149,8 +149,8 @@ def main(): gs.warning( _( "Processing over {} maps: activating -z flag of r.series which " - "slows down processing.".format(max_files_open) - ) + "slows down processing." + ).format(max_files_open) ) flag += "z" if nulls: diff --git a/temporal/t.rast.to.rast3/t.rast.to.rast3.py b/temporal/t.rast.to.rast3/t.rast.to.rast3.py index e3bdd9567ad..7776d7426ee 100755 --- a/temporal/t.rast.to.rast3/t.rast.to.rast3.py +++ b/temporal/t.rast.to.rast3/t.rast.to.rast3.py @@ -162,7 +162,7 @@ def main(): overwrite=gs.overwrite(), ) except CalledModuleError: - gs.fatal(_("Unable to create 3D raster map <%s>" % output)) + gs.fatal(_("Unable to create 3D raster map <%s>") % output) gs.run_command("g.remove", flags="f", type="raster", name=null_map) diff --git a/temporal/t.rast.what/t.rast.what.py b/temporal/t.rast.what/t.rast.what.py index 6a4efbb2b94..39e63180abf 100755 --- a/temporal/t.rast.what/t.rast.what.py +++ b/temporal/t.rast.what/t.rast.what.py @@ -387,7 +387,7 @@ def one_point_per_row_output( for count in range(len(output_files)): file_name = output_files[count] - gs.verbose(_("Transforming r.what output file %s" % (file_name))) + gs.verbose(_("Transforming r.what output file %s") % (file_name)) map_list = output_time_list[count] in_file = open(file_name, "r") for line in in_file: @@ -465,7 +465,7 @@ def one_point_per_col_output( first = True for count in range(len(output_files)): file_name = output_files[count] - gs.verbose(_("Transforming r.what output file %s" % (file_name))) + gs.verbose(_("Transforming r.what output file %s") % (file_name)) in_file = open(file_name, "r") lines = in_file.readlines() @@ -607,7 +607,7 @@ def one_point_per_timerow_output( if write_header: out_file.write(header + "\n") - gs.verbose(_("Writing the output file <%s>" % (output))) + gs.verbose(_("Writing the output file <%s>") % (output)) for row in matrix: first = True for col in row: @@ -663,15 +663,13 @@ def process_loop( output_time_list.append(map_list) gs.verbose( - _( - "Process maps %(samp_start)i to %(samp_end)i (of %(total)i)" - % ( - { - "samp_start": count - len(map_names) + 1, - "samp_end": count, - "total": len(maps), - } - ) + _("Process maps %(samp_start)i to %(samp_end)i (of %(total)i)") + % ( + { + "samp_start": count - len(map_names) + 1, + "samp_end": count, + "total": len(maps), + } ) ) mod = copy.deepcopy(r_what) diff --git a/temporal/t.remove/t.remove.py b/temporal/t.remove/t.remove.py index fd32f8972d5..b5c1164cef4 100755 --- a/temporal/t.remove/t.remove.py +++ b/temporal/t.remove/t.remove.py @@ -127,22 +127,25 @@ def main(): sp = tgis.open_old_stds(name, type, dbif) if not force: gs.message( - _("{stds}: {gid}".format(stds=sp.get_type().upper(), gid=sp.get_id())) + _("{stds}: {gid}").format(stds=sp.get_type().upper(), gid=sp.get_id()) ) if recursive or clean: if not force: if recursive: - msg = ( + msg = _( "The following maps of {stds} {gid} will be " "unregistered from temporal database:" ) elif clean: - msg = ( + msg = _( "The following maps of {stds} {gid} will be " "unregistered from temporal database and removed " "from spatial database:" ) - gs.message(_(msg.format(stds=sp.get_type(), gid=sp.get_id()))) + + if recursive or clean: + gs.message(msg.format(stds=sp.get_type(), gid=sp.get_id())) + maps = sp.get_registered_maps_as_objects(dbif=dbif) map_statement = "" count = 1 @@ -150,10 +153,10 @@ def main(): for map in maps: map.select(dbif) # We may have multiple layer for a single map, hence we need - # to avoid multiple deletation of the same map, + # to avoid multiple deletions of the same map, # but the database entries are still present and must be removed if not force: - gs.message(_("- %s" % map.get_name())) + gs.message(_("- %s") % map.get_name()) continue if clean and force: if map.get_name() not in name_list: @@ -190,8 +193,8 @@ def main(): gs.message( _( "Nothing removed. You must use the force flag (-{flag}) to actually " - "remove them.".format(flag="f") - ) + "remove them." + ).format(flag="f") ) else: # Execute the collected SQL statenents diff --git a/temporal/t.unregister/t.unregister.py b/temporal/t.unregister/t.unregister.py index e7e234320c0..7aef44ed12b 100755 --- a/temporal/t.unregister/t.unregister.py +++ b/temporal/t.unregister/t.unregister.py @@ -154,10 +154,8 @@ def main(): statement += map.delete(dbif=dbif, update=False, execute=False) else: gs.warning( - _( - "Unable to find %s map <%s> in temporal database" - % (map.get_type(), map.get_id()) - ) + _("Unable to find %s map <%s> in temporal database") + % (map.get_type(), map.get_id()) ) count += 1 @@ -170,7 +168,7 @@ def main(): # Update space time datasets if input: - gs.message(_("Unregister maps from space time dataset <%s>" % (input))) + gs.message(_("Unregister maps from space time dataset <%s>") % (input)) else: gs.message(_("Unregister maps from the temporal database")) diff --git a/temporal/t.vect.observe.strds/t.vect.observe.strds.py b/temporal/t.vect.observe.strds/t.vect.observe.strds.py index 8b3850fb2ef..9c60a3d026c 100755 --- a/temporal/t.vect.observe.strds/t.vect.observe.strds.py +++ b/temporal/t.vect.observe.strds/t.vect.observe.strds.py @@ -152,13 +152,13 @@ def main(): "Temporal type of space time raster datasets must be equal\n" "<%(a)s> of type %(type_a)s do not match <%(b)s> of type " "%(type_b)s" - % { - "a": first_strds.get_id(), - "type_a": first_strds.get_temporal_type(), - "b": dataset.get_id(), - "type_b": dataset.get_temporal_type(), - } ) + % { + "a": first_strds.get_id(), + "type_a": first_strds.get_temporal_type(), + "b": dataset.get_id(), + "type_b": dataset.get_temporal_type(), + } ) mapmatrizes = tgis.sample_stds_by_stds_topology( diff --git a/utils/mkhtml.py b/utils/mkhtml.py index 210e83b3fd6..d36ea78663d 100644 --- a/utils/mkhtml.py +++ b/utils/mkhtml.py @@ -164,12 +164,11 @@ def download_git_commit(url, response_format, *args, **kwargs): desc = HTTP_STATUS_CODES[index].description gs.fatal( _( - "Download commit from <{url}>, return status code " - "{code}, {desc}".format( - url=url, - code=response.code, - desc=desc, - ), + "Download commit from <{url}>, return status code {code}, {desc}" + ).format( + url=url, + code=response.code, + desc=desc, ), ) if response_format not in response.getheader("Content-Type"): @@ -177,10 +176,10 @@ def download_git_commit(url, response_format, *args, **kwargs): _( "Wrong downloaded commit file format. " "Check url <{url}>. Allowed file format is " - "{response_format}.".format( - url=url, - response_format=response_format, - ), + "{response_format}." + ).format( + url=url, + response_format=response_format, ), ) return response @@ -190,16 +189,16 @@ def download_git_commit(url, response_format, *args, **kwargs): "The download of the commit from the GitHub API " "server wasn't successful, <{}>. Commit and commit " "date will not be included in the <{}> addon html manual " - "page.".format(err.msg, pgm) - ), + "page." + ).format(err.msg, pgm), ) except URLError: gs.warning( _( "Download file from <{url}>, failed. Check internet " "connection. Commit and commit date will not be included " - "in the <{pgm}> addon manual page.".format(url=url, pgm=pgm) - ), + "in the <{pgm}> addon manual page." + ).format(url=url, pgm=pgm), ) From 1a893014aa15e616715828f0d97306e7bf847d16 Mon Sep 17 00:00:00 2001 From: Mohan Yelugoti Date: Sun, 15 Sep 2024 14:25:29 -0400 Subject: [PATCH 033/209] v.in.dwg: Avoid using same variable as parameter and destination in sprintf (#4262) v.in.dwg: Avoid using same variable as parameter and dest in sprintf Currently, one instance of sprintf has the same variable as parameter and destination in sprintf. This scenario leads to undefined behavior in C. Modify the code to: 1. Write initial error string using snprintf() onto the buffer. Using snprintf() makes sure that we stay within the buffer size and avoid overflow errors. 2. Use snprintf() again to write another error string at the end of previous error string in the same buffer. We again use snprintf() to make sure we are not overflowing the buffer with data. Signed-off-by: Mohan Yelugoti --- vector/v.in.dwg/main.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/vector/v.in.dwg/main.c b/vector/v.in.dwg/main.c index e21602ecb90..cc7b9a217b1 100644 --- a/vector/v.in.dwg/main.c +++ b/vector/v.in.dwg/main.c @@ -66,7 +66,8 @@ int main(int argc, char *argv[]) struct GModule *module; struct Option *out_opt, *in_opt; struct Flag *z_flag, *circle_flag, *l_flag, *int_flag; - char buf[2000]; + const size_t BUFSIZE = 2000; + char buf[BUFSIZE]; /* DWG */ char path[2000]; @@ -135,10 +136,13 @@ int main(int argc, char *argv[]) /* Init OpenDWG */ sprintf(path, "%s/etc/adinit.dat", G_gisbase()); if (!adInitAd2(path, &initerror)) { - sprintf(buf, _("Unable to initialize OpenDWG Toolkit, error: %d: %s."), - initerror, adErrorStr(initerror)); + snprintf(buf, BUFSIZE, + _("Unable to initialize OpenDWG Toolkit, error: %d: %s."), + initerror, adErrorStr(initerror)); + size_t buflen = strlen(buf); if (initerror == AD_UNABLE_TO_OPEN_INIT_FILE) - sprintf(buf, _("%s Cannot open %s"), buf, path); + snprintf(buf + buflen, BUFSIZE - buflen, _(" Cannot open %s"), + path); G_fatal_error(buf); } adSetupDwgRead(); From 213f024ac4fc6275ad565688c7706a611c8ce56a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Mon, 16 Sep 2024 02:13:26 -0400 Subject: [PATCH 034/209] CI(macOS): Use micromamba-shell for steps to load PATH changes (#4325) Fixes problems with loading environment variables and path on the newest GitHub Actions macOS 20240911.3 runner image, that makes all builds fail. * CI(macOS): Use micromamba-shell for build and install * CI(macOS): Use micromamba-shell for printing versions * CI(macOS): Use micromamba-shell for pytest and gunittest --- .github/workflows/macos.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index eb99b6ff7a7..b74b2b042c9 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -59,17 +59,17 @@ jobs: - name: Create installation directory run: mkdir $HOME/install - name: Build and install - shell: bash -l {0} + shell: micromamba-shell {0} run: source ./.github/workflows/macos_install.sh $HOME/install - name: Add the bin directory to PATH run: echo "$HOME/install/bin" >> $GITHUB_PATH - name: Check installed version if: ${{ !cancelled() }} - shell: bash -l {0} + shell: micromamba-shell {0} run: source ./.github/workflows/print_versions.sh - name: Run pytest with multiple workers in parallel - shell: bash -el {0} + shell: micromamba-shell {0} run: | export PYTHONPATH=$(grass --config python_path):$PYTHONPATH export LD_LIBRARY_PATH=$(grass --config path)/lib:$LD_LIBRARY_PATH @@ -78,7 +78,7 @@ jobs: -ra . \ -m 'not needs_solo_run' - name: Run pytest with a single worker (for tests marked with needs_solo_run) - shell: bash -el {0} + shell: micromamba-shell {0} run: | export PYTHONPATH=$(grass --config python_path):$PYTHONPATH export LD_LIBRARY_PATH=$(grass --config path)/lib:$LD_LIBRARY_PATH @@ -87,7 +87,7 @@ jobs: -m 'needs_solo_run' - name: Run gunittest tests - shell: bash -el {0} + shell: micromamba-shell {0} run: | grass --tmp-project XY --exec \ g.download.project url=${{ env.SampleData }} path=$HOME From 63a80f5c198a48ecf741a9bb97d6d37106651f12 Mon Sep 17 00:00:00 2001 From: Mohan Yelugoti Date: Mon, 16 Sep 2024 02:22:55 -0400 Subject: [PATCH 035/209] lib/linkm: Change non-returning internal function types to void (#4318) --- lib/linkm/test/try.c | 6 +++--- lib/linkm/test/try2.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/linkm/test/try.c b/lib/linkm/test/try.c index 4f2a431e003..3b71b6f684a 100644 --- a/lib/linkm/test/try.c +++ b/lib/linkm/test/try.c @@ -61,7 +61,7 @@ int main(int argc, char *argv[]) exit(0); } -int add_link_rev(struct link *List, struct link *link) +void add_link_rev(struct link *List, struct link *link) { struct link *p; @@ -70,7 +70,7 @@ int add_link_rev(struct link *List, struct link *link) link->next = p; } -int add_link(struct link *List, struct link *link) +void add_link(struct link *List, struct link *link) { struct link *p; @@ -81,7 +81,7 @@ int add_link(struct link *List, struct link *link) link->next = NULL; } -int dumplist(struct link *List) +void dumplist(struct link *List) { struct link *p; diff --git a/lib/linkm/test/try2.c b/lib/linkm/test/try2.c index ad226826795..7eb153f16f3 100644 --- a/lib/linkm/test/try2.c +++ b/lib/linkm/test/try2.c @@ -63,7 +63,7 @@ int main(int argc, char *argv[]) exit(0); } -int add_link_rev(struct link *List, struct link *link) +void add_link_rev(struct link *List, struct link *link) { struct link *p; @@ -72,7 +72,7 @@ int add_link_rev(struct link *List, struct link *link) link->next = p; } -int add_link(struct link *List, struct link *link) +void add_link(struct link *List, struct link *link) { struct link *p; @@ -83,7 +83,7 @@ int add_link(struct link *List, struct link *link) link->next = NULL; } -int dumplist(struct link *List) +void dumplist(struct link *List) { struct link *p; From d0f1634cfe08ed6adda7ce2513d363898bf5b347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Mon, 16 Sep 2024 03:55:03 -0400 Subject: [PATCH 036/209] CI(OSGeo4W): Add -pipe to CFLAGS and CXXFLAGS to reduce build time (#4326) With the current GitHub Hosted runners, the build step time is reduced by about 2 minutes, down to about 8min30 instead of about 10min30, for the couple builds I observed --- .github/workflows/osgeo4w.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/osgeo4w.yml b/.github/workflows/osgeo4w.yml index 2f17427b05d..2b92c254238 100644 --- a/.github/workflows/osgeo4w.yml +++ b/.github/workflows/osgeo4w.yml @@ -66,7 +66,10 @@ jobs: - name: Compile GRASS GIS shell: msys2 {0} - run: .github/workflows/build_osgeo4w.sh + run: | + export CFLAGS="${CFLAGS} -pipe" + export CXXFLAGS="${CXXFLAGS} -pipe" + .github/workflows/build_osgeo4w.sh - name: Print installed versions if: always() From 3dbe2d7f3ae980c1aefa5c376c11c58ad3724ea5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:48:39 +0000 Subject: [PATCH 037/209] CI(deps): Update peter-evans/create-pull-request action to v7.0.3 (#4327) --- .github/workflows/periodic_update.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/periodic_update.yml b/.github/workflows/periodic_update.yml index ce03bf8e281..7b8c08b5b70 100644 --- a/.github/workflows/periodic_update.yml +++ b/.github/workflows/periodic_update.yml @@ -33,7 +33,7 @@ jobs: run: git status --ignored - name: Create Pull Request id: cpr - uses: peter-evans/create-pull-request@d121e62763d8cc35b5fb1710e887d6e69a52d3a4 # v7.0.2 + uses: peter-evans/create-pull-request@6cd32fd93684475c31847837f87bb135d40a2b79 # v7.0.3 with: commit-message: "config.guess + config.sub: updated from http://git.savannah.gnu.org/cgit/config.git/plain/" branch: periodic/update-configure From 560340a9c01414469996b3f94d60406d1297e2c5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 09:33:53 -0400 Subject: [PATCH 038/209] CI(deps): Update ruff to v0.6.5 (#4315) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * CI(deps): Update ruff to v0.6.5 * style: Fix FURB188: Prefer `removeprefix` over conditionally replacing with slice. Ruff rule: https://docs.astral.sh/ruff/rules/slice-to-remove-prefix-or-suffix/ This is a new rule introduced in ruff 0.6.5 --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Edouard Choinière <27212526+echoix@users.noreply.github.com> --- .github/workflows/python-code-quality.yml | 2 +- .pre-commit-config.yaml | 2 +- man/parser_standard_options.py | 3 +-- python/grass/gunittest/reporters.py | 6 ++---- utils/generate_release_notes.py | 4 +--- 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index f5810fbe7c2..cd2624051a5 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.7.9" # renovate: datasource=pypi depName=ruff - RUFF_VERSION: "0.6.4" + RUFF_VERSION: "0.6.5" runs-on: ${{ matrix.os }} permissions: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a5221f29efe..3fdb0741681 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: ) - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.6.4 + rev: v0.6.5 hooks: # Run the linter. - id: ruff diff --git a/man/parser_standard_options.py b/man/parser_standard_options.py index 15d1e0fc9ae..ad027a1b6b4 100644 --- a/man/parser_standard_options.py +++ b/man/parser_standard_options.py @@ -47,8 +47,7 @@ def split_opt_line(line): index = line.index("=") key = line[:index].strip() default = line[index + 1 :].strip() - if default.startswith("_("): - default = default[2:] + default = default.removeprefix("_(") return key, default def parse_glines(glines): diff --git a/python/grass/gunittest/reporters.py b/python/grass/gunittest/reporters.py index 0911ca0fdd7..ec175613bc3 100644 --- a/python/grass/gunittest/reporters.py +++ b/python/grass/gunittest/reporters.py @@ -172,8 +172,7 @@ def get_svn_revision(): rc = p.poll() if not rc: stdout = stdout.strip() - if stdout.endswith("M"): - stdout = stdout[:-1] + stdout = stdout.removesuffix("M") if ":" in stdout: # the first one is the one of source code stdout = stdout.split(":")[0] @@ -211,8 +210,7 @@ def get_svn_info(): if relurl is not None: relurl = relurl.text # relative path has ^ at the beginning in SVN version 1.8.8 - if relurl.startswith("^"): - relurl = relurl[1:] + relurl = relurl.removeprefix("^") else: # SVN version 1.8.8 supports relative-url but older do not # so, get relative part from absolute URL diff --git a/utils/generate_release_notes.py b/utils/generate_release_notes.py index 3cfffe77bd2..66aa4ced08c 100755 --- a/utils/generate_release_notes.py +++ b/utils/generate_release_notes.py @@ -97,9 +97,7 @@ def print_category(category, changes, file=None): # Relies on author being specified as username. if " " in author: author = author.split(" ", maxsplit=1)[0] - if author.startswith("@"): - # We expect that to be always the case, but we test anyway. - author = author[1:] + author = author.removeprefix("@") if author in known_bot_names or author.endswith("[bot]"): hidden.append(item) elif len(visible) > max_section_length: From d7c126f2d844c014b79cb94bda55e97984e6445f Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Mon, 16 Sep 2024 16:05:15 +0200 Subject: [PATCH 039/209] docs: add README.md to doc/development/rfc/ (#4316) --- doc/development/rfc/README.md | 26 ++++++++++++++++++++++++ doc/development/rfc/version_numbering.md | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 doc/development/rfc/README.md diff --git a/doc/development/rfc/README.md b/doc/development/rfc/README.md new file mode 100644 index 00000000000..590be34e169 --- /dev/null +++ b/doc/development/rfc/README.md @@ -0,0 +1,26 @@ +# Request For Comment (RFC) List + +GRASS Project Steering Committee: + +- [GRASS-PSC](https://grasswiki.osgeo.org/wiki/PSC) + +A list of all GRASS GIS RFC documents, with status: + +- [RFC 1: Project Steering Committee Guidelines](PSC_guidelines.md) (Adopted) +- [RFC 2: Legal aspects of code contributions](legal_aspects_of_code_contributions.md) + (Adopted) +- [RFC 3: PSC Voting Procedures](PSC_voting_procedures.md) (Adopted) +- [RFC 4: Release Procedure](https://github.com/OSGeo/grass/pull/2815) (Draft) +- [RFC 5: GRASS GIS Errata](https://github.com/OSGeo/grass/pull/2813) (Draft) +- [RFC 6: Migration from SVN to GitHub](migration_github.md) (Adopted) +- [RFC 7: Language Standards Support](language_standards_support.md) (Adopted) +- [RFC 8: Python Language Support](python_language_support.md) (Adopted) +- [RFC 9: Version Numbering](version_numbering.md) (Adopted) +- [RFC X: Release Policy](https://github.com/OSGeo/grass/pull/3673) (Draft) + +Status values: + +- Adopted: RFC is approved (and presumably implemented). +- Proposed: RFC is complete, and open for voting. +- Draft: RFC is being written/revised/discussed. +- Withdrawn: RFC is unapproved, and not being pursued further. diff --git a/doc/development/rfc/version_numbering.md b/doc/development/rfc/version_numbering.md index 7829b0eb513..3428a8b92aa 100644 --- a/doc/development/rfc/version_numbering.md +++ b/doc/development/rfc/version_numbering.md @@ -1,4 +1,4 @@ -# RFC: Version Numbering +# RFC 9: Version Numbering Author: Vaclav Petras From 7c2708027889e5c0f7f19c841839b3f9f568f7ea Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 16 Sep 2024 12:04:33 -0400 Subject: [PATCH 040/209] r.clump: Fix unchecked return value from lseek (#4151) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change addresses an issue identified by Coverity Scan (CID : 1415709) [unchecked return value from library]. The checks are added for lseek usages using an error message already used in the library. --------- Co-authored-by: Edouard Choinière <27212526+echoix@users.noreply.github.com> --- raster/r.clump/clump.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/raster/r.clump/clump.c b/raster/r.clump/clump.c index 052ad6ef034..cf94a5bf142 100644 --- a/raster/r.clump/clump.c +++ b/raster/r.clump/clump.c @@ -25,6 +25,8 @@ #include #include #include "local_proto.h" +#include +#include #define INCR 1024 @@ -92,7 +94,9 @@ static CELL do_renumber(int *in_fd, DCELL *rng, int nin, int diag, int minsize, G_percent(row, nrows, 2); coffset = (off_t)row * csize; - lseek(cfd, coffset, SEEK_SET); + if (lseek(cfd, coffset, SEEK_SET) == -1) { + G_fatal_error(_("Unable to seek: %s"), strerror(errno)); + } if (read(cfd, cur_clump, csize) != csize) G_fatal_error(_("Unable to read from temp file")); @@ -108,7 +112,9 @@ static CELL do_renumber(int *in_fd, DCELL *rng, int nin, int diag, int minsize, temp_clump++; } if (do_write) { - lseek(cfd, coffset, SEEK_SET); + if (lseek(cfd, coffset, SEEK_SET) == -1) { + G_fatal_error(_("Unable to seek: %s"), strerror(errno)); + } if (write(cfd, cur_clump, csize) != csize) G_fatal_error(_("Unable to write to temp file")); } From fdcd8d8223fed5c1e5b05c0579f111a0325bd5ca Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 16 Sep 2024 13:01:57 -0400 Subject: [PATCH 041/209] v.to.3d: Fix Resource Leak Issue in trans2.c (#4320) * Handling Resource Leak * Resource Leak --- vector/v.to.3d/trans2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vector/v.to.3d/trans2.c b/vector/v.to.3d/trans2.c index 1680d950117..c4bde9b3888 100644 --- a/vector/v.to.3d/trans2.c +++ b/vector/v.to.3d/trans2.c @@ -73,6 +73,7 @@ void trans2d(struct Map_info *In, struct Map_info *Out, int type, double height, G_debug(3, "%d records selected", cvarr.n_values); db_close_database_shutdown_driver(driver); + Vect_destroy_field_info(Fi); } G_message(_("Transforming features...")); From c840f3c43874fa8ebb52ea45ddb1c1a3fec5bf55 Mon Sep 17 00:00:00 2001 From: Mohan Yelugoti Date: Mon, 16 Sep 2024 13:02:43 -0400 Subject: [PATCH 042/209] r.viewshed: initialize struct member before using struct (#4232) * r.viewshed: initialize struct member before using struct This was reported by cppcheck tool. Technically, we are not using the member in the struct variable in any of the subsequent functions, but it's a good practice to initialize all the struct members whenever possible. Signed-off-by: Mohan Yelugoti * Use right literal while initializing angle Signed-off-by: Mohan Yelugoti --------- Signed-off-by: Mohan Yelugoti --- raster/r.viewshed/viewshed.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/raster/r.viewshed/viewshed.cpp b/raster/r.viewshed/viewshed.cpp index 17ef21b7811..3ce07fa4652 100644 --- a/raster/r.viewshed/viewshed.cpp +++ b/raster/r.viewshed/viewshed.cpp @@ -261,6 +261,7 @@ MemoryVisibilityGrid *viewshed_in_memory(char *inputfname, GridHeader *hd, e.elev[0] = data[0][i]; e.elev[1] = data[1][i]; e.elev[2] = data[2][i]; + e.angle = -1.0; if (!is_nodata(visgrid->grid->hd, data[1][i]) && !is_point_outside_max_dist(*vp, *hd, sn.row, sn.col, @@ -499,6 +500,7 @@ IOVisibilityGrid *viewshed_external(char *inputfname, GridHeader *hd, e.elev[0] = data[0][i]; e.elev[1] = data[1][i]; e.elev[2] = data[2][i]; + e.angle = -1.0; if (!is_nodata(visgrid->hd, data[1][i]) && !is_point_outside_max_dist(*vp, *hd, sn.row, sn.col, viewOptions.maxDist)) { From 95c123d4b8ce740cefa2fcbc23f649ba25454807 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 16 Sep 2024 13:04:15 -0400 Subject: [PATCH 043/209] i.rectify: Fix copy into fixed size buffer issue in main.c of i.rectify module (#4299) * Copy into fix size buffer issue * removed variable Len * Update imagery/i.rectify/main.c Co-authored-by: Nicklas Larsson --------- Co-authored-by: Shubham Vasudeo Desai Co-authored-by: Shubham Vasudeo Desai Co-authored-by: Nicklas Larsson --- imagery/i.rectify/main.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/imagery/i.rectify/main.c b/imagery/i.rectify/main.c index 3bbe830e3cd..a740a07a0ae 100644 --- a/imagery/i.rectify/main.c +++ b/imagery/i.rectify/main.c @@ -26,6 +26,8 @@ #include #include "global.h" +#include + int seg_mb_img; func interpolate; @@ -151,8 +153,14 @@ int main(int argc, char *argv[]) interpolate = menu[method].method; G_strip(grp->answer); - strcpy(group.name, grp->answer); - strcpy(extension, ext->answer); + if (G_strlcpy(group.name, grp->answer, sizeof(group.name)) >= + sizeof(group.name)) { + G_fatal_error(_("Group name <%s> is too long"), grp->answer); + } + if (G_strlcpy(extension, ext->answer, sizeof(extension)) >= + sizeof(extension)) { + G_fatal_error(_("Extension <%s> is too long"), ext->answer); + } order = atoi(val->answer); seg_mb = NULL; From 826ab62d781b07ac456cf0056631f39882419859 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 16 Sep 2024 20:18:31 -0400 Subject: [PATCH 044/209] i.segment: Move unused variable value into a code comment (#4153) * remove unused variable * Specify old ideas in the comment explicitly --------- Co-authored-by: Vaclav Petras --- imagery/i.segment/mean_shift.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imagery/i.segment/mean_shift.c b/imagery/i.segment/mean_shift.c index 833ff5ca8a8..1d838335352 100644 --- a/imagery/i.segment/mean_shift.c +++ b/imagery/i.segment/mean_shift.c @@ -179,8 +179,9 @@ int mean_shift(struct globals *globals) hspec = globals->hr; if (hspec < 0 || hspec >= 1) { - hspec = sqrt(avgdiffavg / 10.0); - hspec = avgdiffavg; + // Other ideas how to compute this are: + // sqrt(avgdiffavg / 10.0) + // avgdiffavg (as is) hspec = mindiffzeroavg; if (do_progressive) From a0486dd3a7f3d00abf4541e96f814fda8de66f2d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2024 07:35:21 -0400 Subject: [PATCH 045/209] CI(deps): Update ubuntu:22.04 Docker digest to 58b8789 (#4331) --- Dockerfile | 2 +- docker/ubuntu/Dockerfile | 2 +- docker/ubuntu_wxgui/Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index aba1df48a1d..c6366eeb873 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ ARG GUI=without -FROM ubuntu:22.04@sha256:adbb90115a21969d2fe6fa7f9af4253e16d45f8d4c1e930182610c4731962658 as common_start +FROM ubuntu:22.04@sha256:58b87898e82351c6cf9cf5b9f3c20257bb9e2dcf33af051e12ce532d7f94e3fe as common_start LABEL authors="Carmen Tawalika,Markus Neteler,Anika Weinmann,Stefan Blumentrath" LABEL maintainer="tawalika@mundialis.de,neteler@mundialis.de,weinmann@mundialis.de" diff --git a/docker/ubuntu/Dockerfile b/docker/ubuntu/Dockerfile index aba1df48a1d..c6366eeb873 100644 --- a/docker/ubuntu/Dockerfile +++ b/docker/ubuntu/Dockerfile @@ -5,7 +5,7 @@ ARG GUI=without -FROM ubuntu:22.04@sha256:adbb90115a21969d2fe6fa7f9af4253e16d45f8d4c1e930182610c4731962658 as common_start +FROM ubuntu:22.04@sha256:58b87898e82351c6cf9cf5b9f3c20257bb9e2dcf33af051e12ce532d7f94e3fe as common_start LABEL authors="Carmen Tawalika,Markus Neteler,Anika Weinmann,Stefan Blumentrath" LABEL maintainer="tawalika@mundialis.de,neteler@mundialis.de,weinmann@mundialis.de" diff --git a/docker/ubuntu_wxgui/Dockerfile b/docker/ubuntu_wxgui/Dockerfile index 21426eca886..36d33ffeb20 100644 --- a/docker/ubuntu_wxgui/Dockerfile +++ b/docker/ubuntu_wxgui/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04@sha256:adbb90115a21969d2fe6fa7f9af4253e16d45f8d4c1e930182610c4731962658 +FROM ubuntu:22.04@sha256:58b87898e82351c6cf9cf5b9f3c20257bb9e2dcf33af051e12ce532d7f94e3fe LABEL authors="Carmen Tawalika,Markus Neteler,Anika Weinmann,Tomas Zigo" LABEL maintainer="tawalika@mundialis.de,neteler@mundialis.de,weinmann@mundialis.de" From 083fc212767839553dba185cde94c947a5827b9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Tue, 17 Sep 2024 10:22:44 -0400 Subject: [PATCH 046/209] style: Enable checking for SIM115 adding exclusions for existing issues (#4330) --- pyproject.toml | 77 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f6d37ac3bea..f3ca9ab8dd6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -255,7 +255,6 @@ ignore = [ "SIM110", # reimplemented-builtin "SIM113", # enumerate-for-loop "SIM114", # if-with-same-arms - "SIM115", # open-file-with-context-handler "SIM116", # if-else-block-instead-of-dict-lookup "SIM118", # in-dict-keys "SIM201", # negate-equal-op @@ -284,41 +283,109 @@ ignore = [ # Ignore `E402` (import violations) in all `__init__.py` files "*/testsuite/**.py" = ["PT009", "PT027"] "__init__.py" = ["E402"] +"display/d.mon/render_cmd.py" = ["SIM115"] "gui/**" = ["PLW0108"] # See https://github.com/OSGeo/grass/issues/4124 +"gui/wxpython/animation/temporal_manager.py" = ["SIM115"] +"gui/wxpython/core/*.py" = ["SIM115"] +"gui/wxpython/dbmgr/base.py" = ["SIM115"] +"gui/wxpython/gcp/manager.py" = ["SIM115"] +"gui/wxpython/gmodeler/*.py" = ["SIM115"] +"gui/wxpython/gui_core/*.py" = ["SIM115"] +"gui/wxpython/iclass/frame*.py" = ["SIM115"] "gui/wxpython/iclass/frame.py" = ["FLY002"] "gui/wxpython/iclass/statistics.py" = ["A005"] +"gui/wxpython/image2target/*.py" = ["SIM115"] "gui/wxpython/iscatt/plots.py" = ["PLW0108"] +"gui/wxpython/lmgr/workspace.py" = ["SIM115"] +"gui/wxpython/location_wizard/wizard.py" = ["SIM115"] +"gui/wxpython/mapdisp/main.py" = ["SIM115"] +"gui/wxpython/modules/colorrules.py" = ["SIM115"] +"gui/wxpython/modules/mcalc_builder.py" = ["SIM115"] +"gui/wxpython/photo2image/*.py" = ["SIM115"] +"gui/wxpython/psmap/*.py" = ["SIM115"] "gui/wxpython/psmap/utils.py" = ["PGH004"] +"gui/wxpython/rdigit/controller.py" = ["SIM115"] +"gui/wxpython/rlisetup/*.py" = ["SIM115"] "gui/wxpython/timeline/frame.py" = ["FLY002"] +"gui/wxpython/tools/update_menudata.py" = ["SIM115"] "gui/wxpython/tplot/frame.py" = ["FLY002"] +"gui/wxpython/vdigit/mapwindow.py" = ["SIM115"] +"gui/wxpython/vnet/*.py" = ["SIM115"] +"gui/wxpython/web_services/dialogs.py" = ["SIM115"] +"gui/wxpython/wxplot/profile*.py" = ["SIM115"] "gui/wxpython/wxplot/profile.py" = ["A005"] +"imagery/i.atcorr/create_iwave.py" = ["SIM115"] +"lib/imagery/testsuite/test_imagery_signature_management.py" = ["SIM115"] "lib/imagery/testsuite/test_imagery_sigsetfile.py" = ["FURB152"] +"lib/init/grass.py" = ["SIM115"] +"locale/grass_po_stats.py" = ["SIM115"] +"man/build_*.py" = ["SIM115"] +"man/parser_standard_options.py" = ["SIM115"] "python/grass/__init__.py" = ["PYI056"] "python/grass/exp*/tests/grass_script_mapset_session_test.py" = ["SIM117"] "python/grass/exp*/tests/grass_script_tmp_mapset_session_test.py" = ["SIM117"] +"python/grass/gunittest/*.py" = ["SIM115"] "python/grass/gunittest/loader.py" = ["PYI024"] "python/grass/gunittest/multireport.py" = ["PYI024"] "python/grass/gunittest/testsu*/d*/s*/s*/subsub*/t*/test_segfaut.py" = ["B018"] "python/grass/gunittest/testsuite/test_assertions_rast3d.py" = ["FLY002"] +"python/grass/imaging/images2*.py" = ["SIM115"] "python/grass/jupyter/tests/reprojection_renderer_test.py" = ["PT013"] "python/grass/jupyter/testsuite/interactivemap_test.py" = ["PGH004"] "python/grass/jupyter/testsuite/map_test.py" = ["PGH004"] "python/grass/pydispatch/signal.py" = ["A005"] +"python/grass/pygrass/modules/grid/grid.py" = ["SIM115"] +"python/grass/pygrass/modules/interface/env.py" = ["SIM115"] +"python/grass/pygrass/raster/segment.py" = ["SIM115"] +"python/grass/pygrass/tests/*.py" = ["SIM115"] "python/grass/pygrass/vector/geometry.py" = ["PYI024"] "python/grass/pygrass/vector/sql.py" = ["FLY002"] "python/grass/pygrass/vector/testsuite/test_table.py" = ["PLW0108"] "python/grass/script/array.py" = ["A005"] +"python/grass/script/core.py" = ["SIM115"] +"python/grass/script/db.py" = ["SIM115"] +"python/grass/script/raster.py" = ["SIM115"] +"python/grass/script/utils.py" = ["SIM115"] +"python/grass/temporal/*.py" = ["SIM115"] +"python/grass/utils/download.py" = ["SIM115"] +"raster/r.*/testsuite/*.py" = ["SIM115"] +"raster/r.topidx/*.py" = ["SIM115"] "raster3d/r3.flow/testsuite/r3flow_test.py" = ["FLY002"] "raster3d/r3.gradient/testsuite/r3gradient_test.py" = ["FLY002"] -"scripts/d.polar/d.polar.py" = ["FURB154"] -"scripts/i.pansharpen/i.pansharpen.py" = ["FLY002"] -"scripts/i.spectral/i.spectral.py" = ["FLY002"] -"scripts/r.in.srtm/r.in.srtm.py" = ["FLY002"] +"scripts/d.correlate/d.correlate.py" = ["SIM115"] +"scripts/d.frame/d.frame.py" = ["SIM115"] +"scripts/d.polar/d.polar.py" = ["FURB154", "SIM115"] +"scripts/db.in.ogr/db.in.ogr.py" = ["SIM115"] +"scripts/db.test/db.test.py" = ["SIM115"] +"scripts/db.univar/db.univar.py" = ["SIM115"] +"scripts/g.extension.all/g.extension.all.py" = ["SIM115"] +"scripts/g.extension/g.extension.py" = ["SIM115"] +"scripts/g.search.modules/g.search.modules.py" = ["SIM115"] +"scripts/i.in.spotvgt/i.in.spotvgt.py" = ["SIM115"] +"scripts/i.oif/i.oif*.py" = ["SIM115"] +"scripts/i.pansharpen/i.pansharpen.py" = ["FLY002", "SIM115"] +"scripts/i.spectral/i.spectral.py" = ["FLY002", "SIM115"] +"scripts/m.proj/m.proj.py" = ["SIM115"] +"scripts/r.fillnulls/r.fillnulls.py" = ["SIM115"] +"scripts/r.in.srtm/r.in.srtm.py" = ["FLY002", "SIM115"] +"scripts/r.in.wms/wms_*.py" = ["SIM115"] +"scripts/r.tileset/r.tileset.py" = ["SIM115"] +"scripts/v.*/v.*.py" = ["SIM115"] +"scripts/wxpyimgview/wxpyimgview_gui.py" = ["SIM115"] +"temporal/t.list/t.list.py" = ["SIM115"] "temporal/t.rast.algebra/testsu*/*_algebra_arithmetic.py" = ["FLY002"] +"temporal/t.rast.colors/t.rast.colors.py" = ["SIM115"] +"temporal/t.rast.series/t.rast.series.py" = ["SIM115"] +"temporal/t.rast.univar/testsuite/test_t_rast_univar.py" = ["SIM115"] +"temporal/t.rast.what/t.rast.what.py" = ["SIM115"] +"temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py" = ["SIM115"] "temporal/t.register/testsu*/*_raster_different_local.py" = ["FLY002"] "temporal/t.register/testsu*/*_raster_mapmetadata.py" = ["FLY002"] "temporal/t.register/testsuite/test_t_register_raster.py" = ["FLY002"] "temporal/t.register/testsuite/test_t_register_raster_file.py" = ["FLY002"] +"temporal/t.remove/t.remove.py" = ["SIM115"] +"temporal/t.unregister/t.unregister.py" = ["SIM115"] +"utils/**.py" = ["SIM115"] "utils/generate_release_notes.py" = ["PGH004"] "vector/v.fill.holes/examples.ipynb" = ["PTH201"] From df714ec1f02fef2301a7bea3c7647f39b1530b55 Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Tue, 17 Sep 2024 17:27:11 +0200 Subject: [PATCH 047/209] docs: update and cleanup of infrastructure.md (#4294) - various minor updates - removal of GRASS Travis CI section --- doc/infrastructure.md | 78 ++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/doc/infrastructure.md b/doc/infrastructure.md index 4494a6cbd69..e5b59eee73b 100644 --- a/doc/infrastructure.md +++ b/doc/infrastructure.md @@ -1,11 +1,11 @@ # How the GRASS GIS Webserver and related infrastructure works Author: Markus Neteler -Last update: Dec 2023 +Last update: Sep 2024 ## GRASS GIS Source code repository -Maintainer: Markus Neteler, Martin Landa, OSGeo-SAC, +Maintainer: Markus Neteler, Martin Landa, OSGeo-SAC, Important update April 2019: The source code is now managed on GitHub (rather than in SVN). @@ -17,12 +17,12 @@ The GitHub repositories are: - GRASS GIS Add-ons: - GRASS GIS promotional material: - GRASS GIS Website (Hugo site): -- Github mirror at OSGeo: +- Github mirror at OSGeo (updated daily): Git usage: - [CONTRIBUTING.md file](../CONTRIBUTING.md) -- +- [Guide to contributing on GitHub](development/github_guide.md) Issues: @@ -39,8 +39,8 @@ Maintainer: M. Neteler - - - osgeo7-grass: LXD container on osgeo7 () - - OS: Debian Buster + - osgeo8-grass: LXD container on osgeo8 () + - OS: Debian GNU/Linux 11 bullseye - Apache Server with Hugo () - for migration details (7/2020), see - ssh login: via jumphost hop.osgeo8.osgeo.org @@ -48,17 +48,14 @@ Maintainer: M. Neteler - (CMSMS, replaced in 2020 by above Hugo based solution) - - Shared virtual OSGeo machine (osgeo6) hosted at Oregon State University - Open Source Lab server: osgeo6.osgeo.osuosl.org) - - Login: via OSGeo LDAP, there is a "grass" LDAP group - - Software: - - OS: Debian Wheezy - - Apache Server with PHP - - Login: via OSGeo LDAP, there is a "grass" LDAP group + - a static copy of the old site is found at + `neteler@grasslxd:old-grass-website/old.grass.osgeo.org/` (13 GB) + - otherwise: - Backups: - - osgeo7-grass: container on osgeo8 is backup'ed, see + - osgeo8-grass + wiki: container on osgeo8 is backup'ed, + see - Mirrors: @@ -70,18 +67,18 @@ Maintainer: M. Neteler - Weekly software snapshots (generated Saturday morning Portland (OR), US time): - Source code tarball of git (GitHub) - - Linux binary snapshot is compiled on osgeo7-grass + - Linux binary snapshot is compiled on osgeo8-grass - GRASS is compiled with GDAL, PROJ, SQLite, MySQL, PostgreSQL, FFTW, C++ support, see - binary tar.gz and manuals are moved into Web space - GRASS user manual HTML: - - generated during compilation of weekly Linux binary snapshot on osgeo7-grass + - generated during compilation of weekly Linux binary snapshot on osgeo8-grass - GRASS addons manual HTML: - - generated during compilation of weekly Linux binary snapshot on osgeo7-grass + - generated during compilation of weekly Linux binary snapshot on osgeo8-grass - GRASS programmer's manual () @@ -89,13 +86,15 @@ Maintainer: M. Neteler - HTML: cronjob run Saturday morning Portland (OR), US time - disabled: PDF: cronjob run Saturday morning Portland (OR), US time -- Mailman mailing lists + automated greylisting (at lists.osgeo.org since 11/2007) +- Mailman mailing lists + automated greylisting + (at , since 11/2007) - Mailman is doing the job, only registered users can post - messages from unsubscribed people is auto-discarded without notification - the open "weblist" operates instead like this: - - User -> grass-web at lists osgeo.org -> greylisting -> Mailman - - for greylisting, see + - mails goes to grass-web at lists osgeo.org -> greylisting -> Mailman + - for greylisting, see + - Moderation of queue: - Backup of mailing lists (mbox files) @@ -104,7 +103,7 @@ Maintainer: M. Neteler - Web statistics - Matomo: (not publicly accessible; access: Markus Neteler) - - Selected stats: + - Selected stats: and Summary: The system should run almost autonomously. @@ -148,11 +147,9 @@ Maintainer: Martin Landa, Markus Neteler - - Mediawiki software -- requires registration to keep spammers out - -Summary: The system should run almost autonomous. An eye must be be kept -on people trying to spam the site. Several layers of registration protection -are in place due to excessive spam. +- requires registration at + [OSGeo-LDAP](https://www.osgeo.org/community/getting-started-osgeo/osgeo_userid/) + (to keep spammers out) Macros for manual pages (src, cmd, API, ...): @@ -163,9 +160,15 @@ Macros for manual pages (src, cmd, API, ...): Channel: irc://irc.libera.chat/grass Web based client: See +Libera IRC: + +- Founder: jmckenna, markusN + +Former freenode IRC: + - channel owner: Alessandro Frigeri ("geoalf") - quasi guru level: Markus Neteler ("markusN") -- original (freenode) operators: +- original operators: - Jachym ("jachym") - Luca ("doktoreas") - Soeren ("huhabla") @@ -181,16 +184,16 @@ Old bugtrackers: see ## GRASS GIS Addons -Maintainer: Martin Landa and Markus Neteler +Maintainer: Martin Landa, Tomas Zigo, and Markus Neteler Details: -- Windows-addons: grass-addons/utils/addons/README.txt +- Windows-addons: `grass-addons/utils/addons/README.txt` - Addon manual pages cronjob: - Rendered manuals: -The redirect to the latest grassX directory is defined on grass.osgeo.org: -/etc/apache2/includes/grass.osgeo.org.inc +The redirect to the latest `grassX` directory is defined on grass.osgeo.org: +`/etc/apache2/includes/grass.osgeo.org.inc` Procedure building of binaries (Windows): @@ -199,8 +202,8 @@ Procedure building of binaries (Windows): - A new compilation is triggered every time a commit is done in the Addons repo. - Logs: - Linux log files: (compiled on - `grasslxd` on `osgeo7`) - - Windows log files: + `grasslxd` on `osgeo8`) + - Windows log files: Procedure of granting write access to Addons repo: @@ -213,14 +216,7 @@ Procedure of granting write access to Addons repo: XML file for g.extension: -- generated in grass-addons/utils/addons/grass-addons-publish.sh - -## GRASS Travis CI - -Maintainer: Martin Landa - -- -- +- generated in `grass-addons/utils/addons/grass-addons-publish.sh` ## GRASS CI: GitHub Actions From a816dc1548fec62273cb3829d614f2ffb8290d67 Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Tue, 17 Sep 2024 18:50:39 +0200 Subject: [PATCH 048/209] docs: update Programmer's Manual's GIS lib (string) section (#4333) --- lib/gis/gislib.dox | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/lib/gis/gislib.dox b/lib/gis/gislib.dox index fbe1df178e6..852159228cb 100644 --- a/lib/gis/gislib.dox +++ b/lib/gis/gislib.dox @@ -1179,6 +1179,14 @@ The next routines replaces character(s) from string. Replace all occurrences of character in string with new. + - G_str_to_sql() + +Make string SQL compliant. + + - G_str_replace() + +Replace all occurrences of old_str in buffer with new_str. + This next routine copies a string to allocated memory. - G_store() @@ -1186,6 +1194,14 @@ This next routine copies a string to allocated memory. This routine allocates enough memory to hold the string, and returns a pointer to the allocated memory. + - G_store_lower() + +Copy string to allocated memory and convert copied string to lower case. + + - G_store_upper() + +Copy string to allocated memory and convert copied string to upper case. + The next 2 routines convert between upper and lower case. - G_tolcase() @@ -1203,12 +1219,6 @@ equivalent. This routine remove trailing zeros from decimal number for example: 23.45000 would come back as 23.45. - - G_index() - - - G_rindex() - -Get position of delimiter. - - G_strcasecmp() - G_strncasecmp() @@ -1220,11 +1230,24 @@ String compare ignoring case (upper or lower). Return a pointer to the first occurrence of subString in mainString, or NULL if no occurrences are found. - - G_strdup() + - G_str_concat() + +Concatenation of a list of strings, separated by a given character. + + - G_tokenize() + - G_tokenize2() + +Tokenize string. Create array of strings from an input string split up with +given delimiter characters. + + - G_strlcat() + +Size-bounded string concatenation (wrapper function to strlcat()). + + - G_strlcpy() + +Size-bounded string copying (wrapper function to strlcpy()). -Returns a pointer to a string that is a duplicate of the string given -to G_strdup. The duplicate is created using malloc. If unable to -allocate the required space, NULL is returned. \section Enhanced_UNIX_Routines Enhanced UNIX Routines From 5d6a2e84e19a37adbecc684ca8c5b2e1d5c154c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Tue, 17 Sep 2024 14:27:20 -0400 Subject: [PATCH 049/209] t.rast.univar: Use pathlib Path.read_text to open test outputs in t.rast.univar and t.rast3d.univar (#4334) --- pyproject.toml | 2 -- temporal/t.rast.univar/testsuite/test_t_rast_univar.py | 7 ++++--- temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py | 5 +++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f3ca9ab8dd6..52c24a386fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -376,9 +376,7 @@ ignore = [ "temporal/t.rast.algebra/testsu*/*_algebra_arithmetic.py" = ["FLY002"] "temporal/t.rast.colors/t.rast.colors.py" = ["SIM115"] "temporal/t.rast.series/t.rast.series.py" = ["SIM115"] -"temporal/t.rast.univar/testsuite/test_t_rast_univar.py" = ["SIM115"] "temporal/t.rast.what/t.rast.what.py" = ["SIM115"] -"temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py" = ["SIM115"] "temporal/t.register/testsu*/*_raster_different_local.py" = ["FLY002"] "temporal/t.register/testsu*/*_raster_mapmetadata.py" = ["FLY002"] "temporal/t.register/testsuite/test_t_register_raster.py" = ["FLY002"] diff --git a/temporal/t.rast.univar/testsuite/test_t_rast_univar.py b/temporal/t.rast.univar/testsuite/test_t_rast_univar.py index cfdfa78ab27..11a91614b6c 100644 --- a/temporal/t.rast.univar/testsuite/test_t_rast_univar.py +++ b/temporal/t.rast.univar/testsuite/test_t_rast_univar.py @@ -8,6 +8,7 @@ @author Soeren Gebbert """ +from pathlib import Path from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule @@ -243,7 +244,7 @@ def test_subset_with_output(self): a_3@testing||2001-07-01 00:00:00|2001-10-01 00:00:00|300|300|300|300|0|0|0|2880000|0|9600|9600 a_4@testing||2001-10-01 00:00:00|2002-01-01 00:00:00|400|400|400|400|0|0|0|3840000|0|9600|9600 """ - univar_output = open("univar_output.txt", "r").read() + univar_output = Path("univar_output.txt").read_text() for ref, res in zip(univar_text.split("\n"), univar_output.split("\n")): if ref and res: @@ -269,7 +270,7 @@ def test_subset_with_extended_statistics_and_output(self): a_3@m2||2001-07-01 00:00:00|2001-10-01 00:00:00|300|300|300|300|0|0|0|2880000|0|9600|9600|300|300|300|300|300 a_4@m2||2001-10-01 00:00:00|2002-01-01 00:00:00|400|400|400|400|0|0|0|3840000|0|9600|9600|400|400|400|400|400 """ - univar_output = open("univar_output.txt", "r").read() + univar_output = Path("univar_output.txt").read_text() for ref, res in zip(univar_text.split("\n"), univar_output.split("\n")): if ref and res: @@ -292,7 +293,7 @@ def test_subset_with_extended_statistics_and_output(self): a_3@testing||2001-07-01 00:00:00|2001-10-01 00:00:00|300|300|300|300|0|0|0|2880000|0|9600|9600 a_4@testing||2001-10-01 00:00:00|2002-01-01 00:00:00|400|400|400|400|0|0|0|3840000|0|9600|9600 """ - univar_output = open("univar_output.txt", "r").read() + univar_output = Path("univar_output.txt").read_text() for ref, res in zip(univar_text.split("\n"), univar_output.split("\n")): if ref and res: diff --git a/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py b/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py index d34c1f253aa..7c8ab1e4100 100644 --- a/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py +++ b/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py @@ -8,6 +8,7 @@ @author Soeren Gebbert """ +from pathlib import Path from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule @@ -119,7 +120,7 @@ def test_subset_with_output(self): a_3@testing|2001-07-01 00:00:00|2001-10-01 00:00:00|300|300|300|300|0|0|0|144000000|0|480000|480000 a_4@testing|2001-10-01 00:00:00|2002-01-01 00:00:00|400|400|400|400|0|0|0|192000000|0|480000|480000 """ - univar_output = open("univar_output.txt", "r").read() + univar_output = Path("univar_output.txt").read_text() for ref, res in zip(univar_text.split("\n"), univar_output.split("\n")): if ref and res: @@ -142,7 +143,7 @@ def test_subset_with_output_no_header(self): a_3@testing|2001-07-01 00:00:00|2001-10-01 00:00:00|300|300|300|300|0|0|0|144000000|0|480000|480000 a_4@testing|2001-10-01 00:00:00|2002-01-01 00:00:00|400|400|400|400|0|0|0|192000000|0|480000|480000 """ - univar_output = open("univar_output.txt", "r").read() + univar_output = Path("univar_output.txt").read_text() for ref, res in zip(univar_text.split("\n"), univar_output.split("\n")): if ref and res: From 5e47e41efad02e47aec2e017a07e12215ec61197 Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Wed, 18 Sep 2024 00:50:13 +0200 Subject: [PATCH 050/209] docs: update outdated trac URLs to GitHub (#4317) Several documents and files contain references to documents on https://trac.osgeo.org/grass/wiki/ while newer versions exist in GitHub. This PR updates a series of URLs and drops the outdated files `CHANGES` and `NEWS`. Additionally, some minor markdown fixes. --- .github/labeler.yml | 2 -- CHANGES | 10 ------- INSTALL.md | 50 +++++++++++++++++---------------- Makefile | 2 +- NEWS | 18 ------------ README.md | 10 +++---- SECURITY.md | 2 +- general/g.parser/g.parser.html | 2 +- gui/wxpython/gui_core/pyedit.py | 8 ++++-- rpm/grass.spec | 2 +- 10 files changed, 41 insertions(+), 65 deletions(-) delete mode 100644 CHANGES delete mode 100644 NEWS diff --git a/.github/labeler.yml b/.github/labeler.yml index d6caa447e2e..464ccdce2b8 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -123,9 +123,7 @@ docs: - '**/*.png' - '**.cff' - CITING - - CHANGES - AUTHORS - - NEWS - TODO - all-globs-to-all-files: - '!doc/development/rfc/**' diff --git a/CHANGES b/CHANGES deleted file mode 100644 index d4c8280bc7b..00000000000 --- a/CHANGES +++ /dev/null @@ -1,10 +0,0 @@ -CHANGES in GRASS GIS 8.x - -https://trac.osgeo.org/grass/wiki/Grass8/NewFeatures80 -https://trac.osgeo.org/grass/wiki/Grass8/NewFeatures82 - -List of releases: - -- GitHub list: https://github.com/OSGeo/grass/releases -- Overview list: https://trac.osgeo.org/grass/wiki/Release -- History: https://grass.osgeo.org/home/history/releases/ (starting 1984!) diff --git a/INSTALL.md b/INSTALL.md index e6bd041fcf9..41249a04143 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -29,8 +29,8 @@ directory. Installation order: 1. PROJ -2. GDAL-OGR (compiled without GRASS support) -3. optionally: databases such as PostgreSQL, MySQL, sqlite +2. GDAL/OGR (compiled without GRASS support) +3. optionally: databases such as PostgreSQL, MySQL, SQLite 4. GRASS GIS 5. optionally: GDAL-OGR-GRASS plugin @@ -41,7 +41,7 @@ GRASS source code is currently distributed in 2 forms: ### Officially released source code The full source code version contains all the GRASS source code -required for compilation. It is distributed as one file (*.tar.gz +required for compilation. It is distributed as one file (`*.tar.gz` package) and the version is composed of 3 numbers, e.g. 3.7.0, 3.7.1 etc. See . @@ -52,7 +52,7 @@ This version of the source code can be acquired either from the GitHub repository () or as a auto-generated snapshot (`*.tar.gz` package) of the GitHub repository. The snapshot name contains the date when the snapshot was created (checked out from -the GitHub repository), e.g. grass-3.7.git_src_snapshot_2022_04_27.tar.gz +the GitHub repository), e.g. `grass-3.7.git_src_snapshot_2022_04_27.tar.gz` from ## (B) COMPILATION @@ -72,7 +72,7 @@ Detailed Wiki notes for various operating systems (MS-Windows, GNU/Linux distributions, FreeBSD, AIX, etc) are available at: -First step of the compilation (-g for debugging, or -O2 for optimization): +First step of the compilation (`-g` for debugging, or `-O2` for optimization): ```bash CFLAGS="-g -Wall" ./configure @@ -108,7 +108,7 @@ make Note for Solaris users (see also Wiki page above): To configure GRASS correctly on a system which doesn't have a suitable -install program (AC_PROG_INSTALL ignores versions which are known to +install program (`AC_PROG_INSTALL` ignores versions which are known to have problems), you need to ensure that $srcdir is an absolute path, by using e.g.: @@ -136,7 +136,7 @@ CC=cc CPP=cpp ./configure ... ## (C) COMPILATION NOTES for 64bit platforms To successfully compile GRASS on 64bit platforms, the required -FFTW2 library has to be compiled with -fPIC flag: +FFTW library has to be compiled with `-fPIC` flag: ```bash #this applies to FFTW3, not to GRASS GIS: @@ -151,13 +151,13 @@ make install After compilation, the resulting code is stored in the directory ```bash -./dist.$ARCH +./dist.$ARCH/ ``` -and the scripts (grass, ...) in +and the script (`grass`) in ```bash -./bin.$ARCH +./bin.$ARCH/ ``` To run GRASS, simply start @@ -175,7 +175,7 @@ grass ## (E) INSTALLATION ON MACOSX -See the ReadMe.rtf in the ./macosx/ folder and the Wiki page above. +See the `ReadMe.rtf` in the `./macosx/` folder and the Wiki page above. ## (F) RUNNING GRASS GIS @@ -206,7 +206,7 @@ make make install ``` -For details, see +For details, see [Guide to contributing on GitHub](./doc/development/github_guide.md). ## (H) COMPILING INDIVIDUAL MODULES - OWN MODULES @@ -240,7 +240,7 @@ gmake Note: If you keep your module source code outside the standard GRASS source code directory structure, you will have to change the relative -path(s) in the Makefile to absolute path(s). +path(s) in the `Makefile` to absolute path(s). ## (I) CODE OPTIMIZATION @@ -258,8 +258,8 @@ setenv CFLAGS -O ./configure ``` -whichever works on your shell. Use -O2 instead of -O if your compiler -supports this (note: O is the letter, not zero). Using the "gcc" compiler, +whichever works on your shell. Use `-O2` instead of `-O` if your compiler +supports this (note: `O` is the letter, not zero). Using the "gcc" compiler, you can also specify processor specific flags (examples, please suggest better settings to us): @@ -272,11 +272,11 @@ CFLAGS="-O2 -msse -msse2 -mfpmath=sse \ CFLAGS="-mtune=nocona -m64 -minline-all-stringops" # Intel Pentium 64bit processor ``` -Note: As of version 4.3.0, GCC offers the -march=native switch that +Note: As of version 4.3.0, GCC offers the `-march=native` switch that enables CPU auto-detection and automatically selects optimizations supported -by the local machine at GCC runtime including -mtune. +by the local machine at GCC runtime including `-mtune`. -To find out optional CFLAGS for your platform, enter: +To find out optional `CFLAGS` for your platform, enter: ```bash gcc -dumpspecs @@ -285,7 +285,7 @@ gcc -dumpspecs See also: A real fast GRASS version (and small binaries) will be created with -LDFLAGS set to "stripping" (but this disables debugging): +`LDFLAGS` set to "stripping" (but this disables debugging): ```bash CFLAGS="-O2 -mcpu= -Wall" LDFLAGS="-s" ./configure @@ -296,7 +296,7 @@ CFLAGS="-O2 -mcpu= -Wall" LDFLAGS="-s" ./configure The `LDFLAGS=""` part must be undefined as `-s` will strip the debugging information. -Don't use `-O` for CFLAGS if you want to be able to step through function +Don't use `-O` for `CFLAGS` if you want to be able to step through function bodies. When optimisation is enabled, the compiler will re-order statements and re-arrange expressions, resulting in object code which barely resembles the source code. @@ -307,7 +307,7 @@ The `-g` and `-Wall` compiler flags are often useful for assisting debugging: CFLAGS="-g -Wall" ./configure ``` -See also the file ./doc/debugging.txt and the Wiki page +See also the file `./doc/debugging.txt` and the Wiki page ## (K) SUPPORT @@ -322,13 +322,15 @@ developers mailing list. See ## (L) GRASS PROGRAMMER'S MANUAL The Programmer's manual is generated with doxygen from the source code. -Please see the README file and the files at: +Please see the [README](doc/development/README.md) file and the files at: ## (M) CONTRIBUTING CODE AND PATCHES -Please see ./SUBMITTING in this directory, or better, - +Please see + +- [GRASS Programming Style Guide](./doc/development/style_guide.md) +- [Guide to contributing on GitHub](./doc/development/github_guide.md) ## Authors diff --git a/Makefile b/Makefile index be8834ecf42..8b32a149a5a 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ DIRS = \ SUBDIRS = $(DIRS) -FILES = AUTHORS CHANGES CITING COPYING GPL.TXT INSTALL.md REQUIREMENTS.md contributors.csv contributors_extra.csv translators.csv +FILES = AUTHORS CITING COPYING GPL.TXT INSTALL.md REQUIREMENTS.md contributors.csv contributors_extra.csv translators.csv FILES_DST = $(patsubst %,$(ARCH_DISTDIR)/%,$(FILES)) default: diff --git a/NEWS b/NEWS deleted file mode 100644 index 32b4cd52110..00000000000 --- a/NEWS +++ /dev/null @@ -1,18 +0,0 @@ -NEWS - -GRASS GIS 8 - o https://trac.osgeo.org/grass/wiki/Grass8/NewFeatures80 - o https://trac.osgeo.org/grass/wiki/Grass8/NewFeatures82 - -GRASS GIS 7 - o https://trac.osgeo.org/grass/wiki/Grass7/NewFeatures78 - o https://trac.osgeo.org/grass/wiki/Grass7/NewFeatures76 - o https://trac.osgeo.org/grass/wiki/Grass7/NewFeatures74 - o https://trac.osgeo.org/grass/wiki/Grass7/NewFeatures72 - o https://trac.osgeo.org/grass/wiki/Grass7/NewFeatures - - List of releases - o https://trac.osgeo.org/grass/wiki/Release - -GRASS GIS 1-6 - o List of older releases, starting in 1984 (!), see https://grass.osgeo.org/about/history/releases/ diff --git a/README.md b/README.md index b10bd51ec03..7dfdb49df82 100644 --- a/README.md +++ b/README.md @@ -31,11 +31,6 @@ In general: you don't really need write access as you can simply open a [pull request](https://github.com/OSGeo/grass/pulls) to contribute to GRASS GIS. See [CONTRIBUTING file](CONTRIBUTING.md) for more details. -How to get write access here - -Want to become a core developer? See -[Procedure for gaining Git write access](https://trac.osgeo.org/grass/wiki/HowToContribute#WriteaccesstotheGRASScorerepository) - ## How to compile GRASS > See the INSTALL.md file. @@ -111,6 +106,11 @@ this issue, clean all the compiled files from the source code: make distclean ``` +## Further documents + +- [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md) +- [Roadmap](https://grass.osgeo.org/about/roadmap/) + ## Thanks to all contributors ❤ [![GRASS contributors](https://contrib.rocks/image?repo=OSGeo/grass "GRASS contributors")](https://github.com/OSGeo/grass/graphs/contributors) diff --git a/SECURITY.md b/SECURITY.md index feef9649806..0b566dc899d 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -25,7 +25,7 @@ vulnerability, please follow these steps: ## Supported Versions -Please refer to our [Release Schedule](https://trac.osgeo.org/grass/wiki/Release/Schedule) +Please refer to our [download section](https://grass.osgeo.org/download/) for details on which versions are currently supported. ## Security Measures diff --git a/general/g.parser/g.parser.html b/general/g.parser/g.parser.html index 1c0154cca09..b1de89a3a08 100644 --- a/general/g.parser/g.parser.html +++ b/general/g.parser/g.parser.html @@ -673,7 +673,7 @@

SEE ALSO

Overview table: Parser standard options

-Submitting rules for Python +Style Guide: Developing Python scripts

Related Wiki pages: diff --git a/gui/wxpython/gui_core/pyedit.py b/gui/wxpython/gui_core/pyedit.py index 4974e0ce8f5..2de2d45b066 100644 --- a/gui/wxpython/gui_core/pyedit.py +++ b/gui/wxpython/gui_core/pyedit.py @@ -631,10 +631,14 @@ def OnModulesHelp(self, event): self.giface.Help("full_index") def OnSubmittingHelp(self, event): - open_url("https://trac.osgeo.org/grass/wiki/Submitting/Python") + open_url( + "https://github.com/OSGeo/grass/blob/main/doc/development/style_guide.md#python" # noqa: E501 + ) def OnAddonsHelp(self, event): - open_url("https://grass.osgeo.org/development/code-submission/") + open_url( + "https://github.com/OSGeo/grass/blob/main/doc/development/style_guide.md#developing-grass-addons" # noqa: E501 + ) def OnSupport(self, event): open_url("https://grass.osgeo.org/support/") diff --git a/rpm/grass.spec b/rpm/grass.spec index a68453145bc..90c79bc939f 100644 --- a/rpm/grass.spec +++ b/rpm/grass.spec @@ -320,7 +320,7 @@ fi %{_docdir}/%{name}%{shortver} %files libs -%license AUTHORS COPYING GPL.TXT CHANGES +%license AUTHORS COPYING GPL.TXT %{_sysconfdir}/ld.so.conf.d/%{name}-%{_arch}.conf %{_libdir}/%{name}%{shortver}/lib/*.so %dir %{_libdir}/%{name}%{shortver}/driver From 3bc6e957803ce5cafe25313e0b515bf8c8d1bd95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Tue, 17 Sep 2024 18:52:28 -0400 Subject: [PATCH 051/209] grass.temporal.abstract_space_time_dataset: Use Path.read_text() to load SQL template files (#4335) grass.temporal.abstract_space_time_dataset: Use Path.read_text() to load SQL template files Fixes ResourceWarnings about unclosed files, fixing ruff SIM115 at the same time. These 4 places were opening a file and reading it completely in the same line, but never closed explicitly the file, nor used a context manager that would kick in as much as possible on errors inside the calls. --- pyproject.toml | 6 +++- .../temporal/abstract_space_time_dataset.py | 34 +++++++------------ 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 52c24a386fb..b5c7a478864 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -346,7 +346,11 @@ ignore = [ "python/grass/script/db.py" = ["SIM115"] "python/grass/script/raster.py" = ["SIM115"] "python/grass/script/utils.py" = ["SIM115"] -"python/grass/temporal/*.py" = ["SIM115"] +"python/grass/temporal/aggregation.py" = ["SIM115"] +"python/grass/temporal/register.py" = ["SIM115"] +"python/grass/temporal/stds_export.py" = ["SIM115"] +"python/grass/temporal/stds_import.py" = ["SIM115"] +"python/grass/temporal/univar_statistics.py" = ["SIM115"] "python/grass/utils/download.py" = ["SIM115"] "raster/r.*/testsuite/*.py" = ["SIM115"] "raster/r.topidx/*.py" = ["SIM115"] diff --git a/python/grass/temporal/abstract_space_time_dataset.py b/python/grass/temporal/abstract_space_time_dataset.py index cc68f92af2b..fc154270f59 100644 --- a/python/grass/temporal/abstract_space_time_dataset.py +++ b/python/grass/temporal/abstract_space_time_dataset.py @@ -16,6 +16,7 @@ class that is the base class for all space time datasets. import uuid from abc import ABCMeta, abstractmethod from datetime import datetime +from pathlib import Path from .abstract_dataset import AbstractDataset, AbstractDatasetComparisonKeyStartTime from .core import ( @@ -395,9 +396,7 @@ def insert(self, dbif=None, execute=True): # %s;"%(stds_register_table + "_index", stds_register_table)) # Read the SQL template - sql = open( - os.path.join(sql_path, "stds_map_register_table_template.sql"), "r" - ).read() + sql = Path(sql_path, "stds_map_register_table_template.sql").read_text() # Create a raster, raster3d or vector tables sql = sql.replace("SPACETIME_REGISTER_TABLE", stds_register_table) @@ -2818,13 +2817,10 @@ def update_from_registered_maps(self, dbif=None): ) if old_sqlite_version: template_suffix = "_old" - sql = open( - os.path.join( - sql_path, - f"update_stds_spatial_temporal_extent_template{template_suffix}.sql", - ), - "r", - ).read() + sql = Path( + sql_path, + f"update_stds_spatial_temporal_extent_template{template_suffix}.sql", + ).read_text() sql = sql.replace("GRASS_MAP", self.get_new_map_instance(None).get_type()) sql = sql.replace("SPACETIME_REGISTER_TABLE", stds_register_table) sql = sql.replace("SPACETIME_ID", self.base.get_id()) @@ -2834,13 +2830,10 @@ def update_from_registered_maps(self, dbif=None): sql_script += "\n" # Update type specific metadata - sql = open( - os.path.join( - sql_path, - f"update_{self.get_type()}_metadata_template{template_suffix}.sql", - ), - "r", - ).read() + sql = Path( + sql_path, + f"update_{self.get_type()}_metadata_template{template_suffix}.sql", + ).read_text() # Comment out update of semantic labels for DB version < 3 if get_tgis_db_version_from_metadata() < 3: @@ -2853,10 +2846,9 @@ def update_from_registered_maps(self, dbif=None): "-- count(distinct semantic_label)", ) elif old_sqlite_version and self.get_type() == "strds": - semantic_label_sql = open( - os.path.join(sql_path, "update_strds_metadata_template_v3.sql"), - "r", - ).read() + semantic_label_sql = Path( + sql_path, "update_strds_metadata_template_v3.sql" + ).read_text() sql = sql + "\n" + semantic_label_sql sql = sql.replace("SPACETIME_REGISTER_TABLE", stds_register_table) From da15442d8428bb534272fc8fd65f1f13f8dbf55b Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Wed, 18 Sep 2024 09:42:17 +0200 Subject: [PATCH 052/209] lib/gis: match prototype with declaration for G_strlcat and G_strlcpy (#4332) Make local implementations of strlcpy() and strlcat() optimizable by using restrict type qualifier, while keeping public API for G_strlcat and G_strlcpy available to C++ code and having identical prototype and declaration. --- lib/gis/strlcat.c | 14 +++++++++++--- lib/gis/strlcpy.c | 14 +++++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/lib/gis/strlcat.c b/lib/gis/strlcat.c index ed6c3887e72..635ffbdedb8 100644 --- a/lib/gis/strlcat.c +++ b/lib/gis/strlcat.c @@ -28,6 +28,9 @@ #include #include +static size_t G__strlcat(char *restrict dst, const char *restrict src, + size_t dsize); + /** * \brief Size-bounded string concatenation * @@ -51,12 +54,18 @@ * including the terminating NUL character). If the return value * is >= dsize, truncation occurred. */ - -size_t G_strlcat(char *restrict dst, const char *restrict src, size_t dsize) +size_t G_strlcat(char *dst, const char *src, size_t dsize) { #ifdef HAVE_STRLCAT return strlcat(dst, src, dsize); #else + return G__strlcat(dst, src, dsize); +#endif +} + +static size_t G__strlcat(char *restrict dst, const char *restrict src, + size_t dsize) +{ const char *odst = dst; const char *osrc = src; size_t n = dsize; @@ -80,5 +89,4 @@ size_t G_strlcat(char *restrict dst, const char *restrict src, size_t dsize) *dst = '\0'; return (dlen + (src - osrc)); /* count does not include NUL */ -#endif } diff --git a/lib/gis/strlcpy.c b/lib/gis/strlcpy.c index 5c0601391f5..a2d6e8918e7 100644 --- a/lib/gis/strlcpy.c +++ b/lib/gis/strlcpy.c @@ -22,6 +22,9 @@ #include +static size_t G__strlcpy(char *restrict dst, const char *restrict src, + size_t dsize); + /** * \brief Safe string copy function. * @@ -46,12 +49,18 @@ * \warning The src string must be a valid NUL-terminated C string. Passing an * unterminated string may result in buffer overrun. */ - -size_t G_strlcpy(char *restrict dst, const char *restrict src, size_t dsize) +size_t G_strlcpy(char *dst, const char *src, size_t dsize) { #ifdef HAVE_STRLCPY return strlcpy(dst, src, dsize); #else + return G__strlcpy(dst, src, dsize); +#endif +} + +static size_t G__strlcpy(char *restrict dst, const char *restrict src, + size_t dsize) +{ const char *osrc = src; size_t nleft = dsize; @@ -72,5 +81,4 @@ size_t G_strlcpy(char *restrict dst, const char *restrict src, size_t dsize) } return (src - osrc - 1); /* count does not include NUL */ -#endif } From 9420d00ea851c6c089b39d450e31bd4c8cab841e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Wed, 18 Sep 2024 13:02:52 -0400 Subject: [PATCH 053/209] grass.gunittest: Fix parsing exclusion from config file on Windows (#4324) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * grass.gunittest: Ensure file list exists before processing exclusions * grass.gunittest: Use pathlib.Path to handle test files across platforms * grass.gunittest: Use pathlib.PurePath instead of concrete pathlib.Path * grass.gunittest: Also use pathlib.PurePath for patterns * grass.gunittest: Simplify pathlib filtering using a set comprehension * grass.gunittest: Add typing to fnmatch_exclude_with_base signature * style: Sort imports with isort * Add Edouard Choinière (echoix) to the authors * Fix typo in comment * grass.gunittest: Filter file list respecting all three filter arguments if specified * grass.gunittest: Change set comprehension variable name --- python/grass/gunittest/loader.py | 47 ++++++++++++++++---------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/python/grass/gunittest/loader.py b/python/grass/gunittest/loader.py index 33234e2b083..f01467ef1ba 100644 --- a/python/grass/gunittest/loader.py +++ b/python/grass/gunittest/loader.py @@ -6,17 +6,28 @@ License (>=v2). Read the file COPYING that comes with GRASS GIS for details. -:authors: Vaclav Petras +:authors: Vaclav Petras, Edouard Choinière """ -import os -import fnmatch -import unittest +from __future__ import annotations + import collections +import fnmatch +import os import re +import unittest +from pathlib import PurePath +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterable -def fnmatch_exclude_with_base(files, base, exclude): +def fnmatch_exclude_with_base( + files: Iterable[str], + base: str | os.PathLike, + exclude: Iterable[str | os.PathLike | PurePath], +) -> list[str]: """Return list of files not matching any exclusion pattern :param files: list of file names @@ -24,23 +35,13 @@ def fnmatch_exclude_with_base(files, base, exclude): :param exclude: list of fnmatch glob patterns for exclusion """ not_excluded = [] - patterns = [] - # Make all dir separators slashes and drop leading current dir - # for both patterns and (later) for files. - for pattern in exclude: - pattern = pattern.replace(os.sep, "/") - if pattern.startswith("./"): - patterns.append(pattern[2:]) - else: - patterns.append(pattern) + patterns = {str(PurePath(item)) for item in exclude} + base_path = PurePath(base) for filename in files: - full_file_path = os.path.join(base, filename) - test_filename = full_file_path.replace(os.sep, "/") - if full_file_path.startswith("./"): - test_filename = full_file_path[2:] + test_filename: PurePath = base_path / filename matches = False for pattern in patterns: - if fnmatch.fnmatch(test_filename, pattern): + if fnmatch.fnmatch(str(test_filename), pattern): matches = True break if not matches: @@ -116,16 +117,16 @@ def discover_modules( dirs.remove(testsuite_dir) # do not recurse to testsuite full = os.path.join(root, testsuite_dir) - all_files = os.listdir(full) + files = os.listdir(full) if file_pattern: - files = fnmatch.filter(all_files, file_pattern) + files = fnmatch.filter(files, file_pattern) if file_regexp: - files = [f for f in all_files if re.match(file_regexp, f)] + files = [f for f in files if re.match(file_regexp, f)] if exclude: files = fnmatch_exclude_with_base(files, full, exclude) files = sorted(files) # get test/module name without .py - # extpecting all files to end with .py + # expecting all files to end with .py # this will not work for invoking bat files but it works fine # as long as we handle only Python files (and using Python # interpreter for invoking) From 05363519914f963f1a2c2d13df0e59e0ad9593e3 Mon Sep 17 00:00:00 2001 From: Makiko Shukunobe Date: Wed, 18 Sep 2024 15:00:49 -0400 Subject: [PATCH 054/209] checks: Flake8 F841 fixes in the wxpython directory part 1 (#4244) --- .flake8 | 8 ++------ gui/wxpython/animation/mapwindow.py | 2 +- gui/wxpython/animation/provider.py | 2 +- gui/wxpython/core/gthread.py | 2 -- gui/wxpython/core/render.py | 2 -- gui/wxpython/core/utils.py | 16 ++++++++++++---- gui/wxpython/core/ws.py | 2 -- 7 files changed, 16 insertions(+), 18 deletions(-) diff --git a/.flake8 b/.flake8 index 3182812dd1d..2cc14b2c6fd 100644 --- a/.flake8 +++ b/.flake8 @@ -29,13 +29,11 @@ per-file-ignores = locale/grass_po_stats.py: E122, E128, E231, E401, E722 gui/scripts/d.wms.py: E501 gui/wxpython/core/gcmd.py: E402 - gui/wxpython/core/gthread.py: F841 gui/wxpython/core/gconsole.py: E722 gui/wxpython/core/toolboxes.py: E722 - gui/wxpython/core/utils.py: E722, F841 + gui/wxpython/core/utils.py: E722 gui/wxpython/core/workspace.py: E722 - gui/wxpython/core/render.py: E722, F841 - gui/wxpython/core/ws.py: F841 + gui/wxpython/core/render.py: E722 gui/wxpython/core/settings.py: E722 gui/wxpython/core/watchdog.py: E402 gui/wxpython/datacatalog/tree.py: E731, E402 @@ -71,8 +69,6 @@ per-file-ignores = gui/wxpython/vnet/*: F841 gui/wxpython/wxgui.py: F841 gui/wxpython/animation/g.gui.animation.py: E501 - gui/wxpython/animation/mapwindow.py: F841 - gui/wxpython/animation/provider.py: F841 gui/wxpython/tplot/frame.py: F841, E722 gui/wxpython/tplot/g.gui.tplot.py: E501 gui/wxpython/rdigit/g.gui.rdigit.py: F841 diff --git a/gui/wxpython/animation/mapwindow.py b/gui/wxpython/animation/mapwindow.py index 749a2da147d..4a6822e0841 100644 --- a/gui/wxpython/animation/mapwindow.py +++ b/gui/wxpython/animation/mapwindow.py @@ -61,7 +61,7 @@ def Draw(self, dc): def OnPaint(self, event): Debug.msg(5, "BufferedWindow.OnPaint()") # All that is needed here is to draw the buffer to screen - dc = wx.BufferedPaintDC(self, self._Buffer) + wx.BufferedPaintDC(self, self._Buffer) def OnSize(self, event): Debug.msg(5, "BufferedWindow.OnSize()") diff --git a/gui/wxpython/animation/provider.py b/gui/wxpython/animation/provider.py index 46eddea7294..fd966219407 100644 --- a/gui/wxpython/animation/provider.py +++ b/gui/wxpython/animation/provider.py @@ -924,7 +924,7 @@ def test(): prov.mapsLoaded.connect(lambda: sys.stdout.write("Maps loading finished\n")) cmdMatrix = layerListToCmdsMatrix(layerList) prov.SetCmds(cmdMatrix, [layer.opacity for layer in layerList]) - app = wx.App() + wx.App() prov.Load(bgcolor=(13, 156, 230), nprocs=4) diff --git a/gui/wxpython/core/gthread.py b/gui/wxpython/core/gthread.py index 7bd8929c553..44a938f335a 100644 --- a/gui/wxpython/core/gthread.py +++ b/gui/wxpython/core/gthread.py @@ -95,8 +95,6 @@ def run(self): else: vars()[key] = None - requestTime = time.time() - ret = None exception = None time.sleep(0.01) diff --git a/gui/wxpython/core/render.py b/gui/wxpython/core/render.py index 3095cb47fc8..b98e4323578 100644 --- a/gui/wxpython/core/render.py +++ b/gui/wxpython/core/render.py @@ -666,8 +666,6 @@ def OnRenderDone(self, env): Make image composiotion, emits updateMap event. """ - stopTime = time.time() - maps = [] masks = [] opacities = [] diff --git a/gui/wxpython/core/utils.py b/gui/wxpython/core/utils.py index fe4f40c359a..10d6dca2759 100644 --- a/gui/wxpython/core/utils.py +++ b/gui/wxpython/core/utils.py @@ -827,8 +827,12 @@ def StoreEnvVariable(key, value=None, envFile=None): if os.path.exists(envFile): try: fd = open(envFile) - except OSError as e: - sys.stderr.write(_("Unable to open file '%s'\n") % envFile) + except OSError as error: + sys.stderr.write( + _("Unable to open file '{name}': {error}\n").format( + name=envFile, error=error + ) + ) return for line in fd: line = line.rstrip(os.linesep) @@ -857,8 +861,12 @@ def StoreEnvVariable(key, value=None, envFile=None): # write update env file try: fd = open(envFile, "w") - except OSError as e: - sys.stderr.write(_("Unable to create file '%s'\n") % envFile) + except OSError as error: + sys.stderr.write( + _("Unable to create file '{name}': {error}\n").format( + name=envFile, error=error + ) + ) return if windows: expCmd = "set" diff --git a/gui/wxpython/core/ws.py b/gui/wxpython/core/ws.py index 156cd0166f9..010deac824f 100644 --- a/gui/wxpython/core/ws.py +++ b/gui/wxpython/core/ws.py @@ -99,7 +99,6 @@ def Render(self, cmd, env): self.updateMap = True fetchData = True # changed to True when calling Render() - zoomChanged = False if self.renderedRegion is None or cmd != self.fetched_data_cmd: fetchData = True @@ -111,7 +110,6 @@ def Render(self, cmd, env): for c in ["e-w resol", "n-s resol"]: if self.renderedRegion and region[c] != self.renderedRegion[c]: - zoomChanged = True break if fetchData: From 4f8f676b8bd25da1d27ddf8fcb3007d3774ae714 Mon Sep 17 00:00:00 2001 From: Makiko Shukunobe Date: Wed, 18 Sep 2024 16:12:44 -0400 Subject: [PATCH 055/209] checks: Flake8 F841 fixes in the wxpython directory part 3 (#4261) --- .flake8 | 17 +++---- gui/wxpython/gcp/g.gui.gcp.py | 2 +- gui/wxpython/gcp/manager.py | 66 ++++++++++++---------------- gui/wxpython/gcp/mapdisplay.py | 2 - gui/wxpython/gui_core/dialogs.py | 1 - gui/wxpython/gui_core/forms.py | 3 -- gui/wxpython/gui_core/goutput.py | 6 +-- gui/wxpython/gui_core/gselect.py | 6 --- gui/wxpython/gui_core/menu.py | 15 ------- gui/wxpython/gui_core/preferences.py | 2 - gui/wxpython/gui_core/prompt.py | 2 - gui/wxpython/gui_core/pystc.py | 1 - gui/wxpython/gui_core/treeview.py | 16 ++++--- gui/wxpython/gui_core/widgets.py | 2 +- 14 files changed, 48 insertions(+), 93 deletions(-) diff --git a/.flake8 b/.flake8 index 2cc14b2c6fd..e72eaa73333 100644 --- a/.flake8 +++ b/.flake8 @@ -42,17 +42,14 @@ per-file-ignores = gui/wxpython/dbmgr/sqlbuilder.py: E722 gui/wxpython/dbmgr/manager.py: E722 gui/wxpython/docs/wxgui_sphinx/conf.py: E402, W291 - gui/wxpython/gcp/g.gui.gcp.py: F841 - gui/wxpython/gcp/manager.py: F841, E722 - gui/wxpython/gcp/mapdisplay.py: F841 - gui/wxpython/gui_core/*: F841, E266, E722 - gui/wxpython/gui_core/dialogs.py: E722, F841 - gui/wxpython/gui_core/forms.py: E722, F841 + gui/wxpython/gcp/manager.py: E722 + gui/wxpython/gui_core/*: E266, E722 + gui/wxpython/gui_core/dialogs.py: E722 + gui/wxpython/gui_core/forms.py: E722 gui/wxpython/gui_core/ghelp.py: E722 - gui/wxpython/gui_core/gselect.py: F841, E266, E722 - gui/wxpython/gui_core/preferences.py: E266, F841 - gui/wxpython/gui_core/treeview.py: F841 - gui/wxpython/gui_core/widgets.py: F841, E722, E266 + gui/wxpython/gui_core/gselect.py: E266, E722 + gui/wxpython/gui_core/preferences.py: E266 + gui/wxpython/gui_core/widgets.py: E722, E266 gui/wxpython/image2target/*: F841, E722, E265 gui/wxpython/image2target/g.gui.image2target.py: E501, E265, F841 gui/wxpython/iscatt/*: F841, E722, F405, F403 diff --git a/gui/wxpython/gcp/g.gui.gcp.py b/gui/wxpython/gcp/g.gui.gcp.py index 32ef2c4fc0d..12f0a152090 100755 --- a/gui/wxpython/gcp/g.gui.gcp.py +++ b/gui/wxpython/gcp/g.gui.gcp.py @@ -65,7 +65,7 @@ def main(): app = wx.App() - wizard = GCPWizard(parent=None, giface=StandaloneGrassInterface()) + GCPWizard(parent=None, giface=StandaloneGrassInterface()) app.MainLoop() diff --git a/gui/wxpython/gcp/manager.py b/gui/wxpython/gcp/manager.py index 696bc53609f..e5e0dd37471 100644 --- a/gui/wxpython/gcp/manager.py +++ b/gui/wxpython/gcp/manager.py @@ -1825,23 +1825,21 @@ def OnGeorect(self, event): else: flags = "a" - busy = wx.BusyInfo(_("Rectifying images, please wait..."), parent=self) - wx.GetApp().Yield() - - ret, msg = RunCommand( - "i.rectify", - parent=self, - getErrorMsg=True, - quiet=True, - group=self.xygroup, - extension=self.extension, - order=self.gr_order, - method=self.gr_method, - flags=flags, - overwrite=overwrite, - ) + with wx.BusyInfo(_("Rectifying images, please wait..."), parent=self): + wx.GetApp().Yield() - del busy + ret, msg = RunCommand( + "i.rectify", + parent=self, + getErrorMsg=True, + quiet=True, + group=self.xygroup, + extension=self.extension, + order=self.gr_order, + method=self.gr_method, + flags=flags, + overwrite=overwrite, + ) # provide feedback on failure if ret != 0: @@ -1885,24 +1883,22 @@ def OnGeorect(self, event): ) ret = msg = "" - busy = wx.BusyInfo( + with wx.BusyInfo( _("Rectifying vector map <%s>, please wait...") % vect, parent=self - ) - wx.GetApp().Yield() - - ret, msg = RunCommand( - "v.rectify", - parent=self, - getErrorMsg=True, - quiet=True, - input=vect, - output=self.outname, - group=self.xygroup, - order=self.gr_order, - overwrite=overwrite, - ) - - del busy + ): + wx.GetApp().Yield() + + ret, msg = RunCommand( + "v.rectify", + parent=self, + getErrorMsg=True, + quiet=True, + input=vect, + output=self.outname, + group=self.xygroup, + order=self.gr_order, + overwrite=overwrite, + ) # provide feedback on failure if ret != 0: @@ -2027,7 +2023,6 @@ def OnGROrder(self, event): elif self.gr_order == 2: minNumOfItems = 6 - diff = 6 - numOfItems # self.SetStatusText( # _('Insufficient points, 6+ points needed for 2nd order')) @@ -2330,7 +2325,6 @@ def OnZoomToTarget(self, event): def OnZoomMenuGCP(self, event): """Popup Zoom menu""" - point = wx.GetMousePosition() zoommenu = Menu() # Add items to the menu @@ -3432,7 +3426,6 @@ def UpdateSettings(self): srcrenderVector = False tgtrender = False tgtrenderVector = False - reload_target = False if self.new_src_map != src_map: # remove old layer layers = self.parent.grwiz.SrcMap.GetListOfLayers() @@ -3470,7 +3463,6 @@ def UpdateSettings(self): del layers[0] layers = self.parent.grwiz.TgtMap.GetListOfLayers() # self.parent.grwiz.TgtMap.DeleteAllLayers() - reload_target = True tgt_map["raster"] = self.new_tgt_map["raster"] tgt_map["vector"] = self.new_tgt_map["vector"] diff --git a/gui/wxpython/gcp/mapdisplay.py b/gui/wxpython/gcp/mapdisplay.py index 13872b807cf..66daa70d2ca 100644 --- a/gui/wxpython/gcp/mapdisplay.py +++ b/gui/wxpython/gcp/mapdisplay.py @@ -484,7 +484,6 @@ def PrintMenu(self, event): """ Print options and output menu for map display """ - point = wx.GetMousePosition() printmenu = Menu() # Add items to the menu setup = wx.MenuItem(printmenu, wx.ID_ANY, _("Page setup")) @@ -528,7 +527,6 @@ def SaveDisplayRegion(self, event): def OnZoomMenu(self, event): """Popup Zoom menu""" - point = wx.GetMousePosition() zoommenu = Menu() # Add items to the menu diff --git a/gui/wxpython/gui_core/dialogs.py b/gui/wxpython/gui_core/dialogs.py index c31939312a7..f7c7711cadf 100644 --- a/gui/wxpython/gui_core/dialogs.py +++ b/gui/wxpython/gui_core/dialogs.py @@ -180,7 +180,6 @@ def OnLocation(self, event): dbase = grass.gisenv()["GISDBASE"] self.element2.UpdateItems(dbase=dbase, location=location) self.element2.SetSelection(0) - mapset = self.element2.GetStringSelection() def GetValues(self): """Get location, mapset""" diff --git a/gui/wxpython/gui_core/forms.py b/gui/wxpython/gui_core/forms.py index f9829cd9d9b..84fd849908c 100644 --- a/gui/wxpython/gui_core/forms.py +++ b/gui/wxpython/gui_core/forms.py @@ -307,8 +307,6 @@ def run(self): pTable = self.task.get_param( "dbtable", element="element", raiseError=False ) - if pTable: - table = pTable.get("value", "") if name == "LayerSelect": # determine format @@ -1546,7 +1544,6 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar if value: selection.SetValue(value) - formatSelector = True # A gselect.Select is a combobox with two children: a textctl # and a popupwindow; we target the textctl here textWin = selection.GetTextCtrl() diff --git a/gui/wxpython/gui_core/goutput.py b/gui/wxpython/gui_core/goutput.py index 6aca497f365..3c8927f2233 100644 --- a/gui/wxpython/gui_core/goutput.py +++ b/gui/wxpython/gui_core/goutput.py @@ -619,11 +619,7 @@ def AddStyledMessage(self, message, style=None): if c == "\b": self.linePos -= 1 else: - if c == "\r": - pos = self.GetCurLine()[1] - # self.SetCurrentPos(pos) - else: - self.SetCurrentPos(self.linePos) + self.SetCurrentPos(self.linePos) self.ReplaceSelection(c) self.linePos = self.GetCurrentPos() if c != " ": diff --git a/gui/wxpython/gui_core/gselect.py b/gui/wxpython/gui_core/gselect.py index eae12085f92..cec6963a527 100644 --- a/gui/wxpython/gui_core/gselect.py +++ b/gui/wxpython/gui_core/gselect.py @@ -1373,12 +1373,6 @@ def Insert(self, group): """Insert subgroups for defined group""" if not group: return - gisenv = gs.gisenv() - try: - name, mapset = group.split("@", 1) - except ValueError: - name = group - mapset = gisenv["MAPSET"] mlist = RunCommand("i.group", group=group, read=True, flags="sg").splitlines() try: diff --git a/gui/wxpython/gui_core/menu.py b/gui/wxpython/gui_core/menu.py index 71d6d153f8b..de6b49b7e93 100644 --- a/gui/wxpython/gui_core/menu.py +++ b/gui/wxpython/gui_core/menu.py @@ -68,8 +68,6 @@ def _createMenu(self, node): self._createMenuItem(menu, label=child.label, **data) - self.parent.Bind(wx.EVT_MENU_HIGHLIGHT_ALL, self.OnMenuHighlight) - return menu def _createMenuItem( @@ -136,19 +134,6 @@ def GetCmd(self): """ return self.menucmd - def OnMenuHighlight(self, event): - """ - Default menu help handler - """ - # Show how to get menu item info from this event handler - id = event.GetMenuId() - item = self.FindItemById(id) - if item: - help = item.GetHelp() - - # but in this case just call Skip so the default is done - event.Skip() - class Menu(MenuBase, wx.MenuBar): def __init__(self, parent, model, class_handler=None): diff --git a/gui/wxpython/gui_core/preferences.py b/gui/wxpython/gui_core/preferences.py index 3c3df8e8e42..c2020b2ffba 100644 --- a/gui/wxpython/gui_core/preferences.py +++ b/gui/wxpython/gui_core/preferences.py @@ -2021,8 +2021,6 @@ def OnCheckColorTable(self, event): def OnLoadEpsgCodes(self, event): """Load EPSG codes from the file""" - win = self.FindWindowById(self.winId["projection:statusbar:projFile"]) - path = win.GetValue() epsgCombo = self.FindWindowById(self.winId["projection:statusbar:epsg"]) wx.BeginBusyCursor() try: diff --git a/gui/wxpython/gui_core/prompt.py b/gui/wxpython/gui_core/prompt.py index 6ac9219f827..6734de169a9 100644 --- a/gui/wxpython/gui_core/prompt.py +++ b/gui/wxpython/gui_core/prompt.py @@ -511,7 +511,6 @@ def OnChar(self, event): # complete command after pressing '.' if event.GetKeyCode() == 46: self.autoCompList = [] - entry = self.GetTextLeft() self.InsertText(pos, ".") self.CharRight() self.toComplete = self.EntityToComplete() @@ -538,7 +537,6 @@ def OnChar(self, event): or event.GetKeyCode() == wx.WXK_SUBTRACT ): self.autoCompList = [] - entry = self.GetTextLeft() self.InsertText(pos, "-") self.CharRight() self.toComplete = self.EntityToComplete() diff --git a/gui/wxpython/gui_core/pystc.py b/gui/wxpython/gui_core/pystc.py index 33d5f03b5f9..d545ccb21e4 100644 --- a/gui/wxpython/gui_core/pystc.py +++ b/gui/wxpython/gui_core/pystc.py @@ -98,7 +98,6 @@ def __init__(self, parent, id=wx.ID_ANY, statusbar=None): 9, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL ) face = font.GetFaceName() - size = font.GetPointSize() # setting the monospace here to not mess with the rest of the code # TODO: review the whole styling diff --git a/gui/wxpython/gui_core/treeview.py b/gui/wxpython/gui_core/treeview.py index 4c20885599c..b5ee50a7822 100644 --- a/gui/wxpython/gui_core/treeview.py +++ b/gui/wxpython/gui_core/treeview.py @@ -303,17 +303,19 @@ def main(): root = tree.root n1 = tree.AppendNode(parent=root, data={"label": "node1"}) n2 = tree.AppendNode(parent=root, data={"label": "node2"}) - n3 = tree.AppendNode(parent=root, data={"label": "node3"}) # pylint: disable=W0612 + n3 = tree.AppendNode( # noqa: F841 # pylint: disable=W0612 + parent=root, data={"label": "node3"} + ) n11 = tree.AppendNode(parent=n1, data={"label": "node11", "xxx": "A"}) - n12 = tree.AppendNode( + n12 = tree.AppendNode( # noqa: F841 # pylint: disable=W0612 parent=n1, data={"label": "node12", "xxx": "B"} - ) # pylint: disable=W0612 - n21 = tree.AppendNode( + ) + n21 = tree.AppendNode( # noqa: F841 # pylint: disable=W0612 parent=n2, data={"label": "node21", "xxx": "A"} - ) # pylint: disable=W0612 - n111 = tree.AppendNode( + ) + n111 = tree.AppendNode( # noqa: F841 # pylint: disable=W0612 parent=n11, data={"label": "node111", "xxx": "A"} - ) # pylint: disable=W0612 + ) app = wx.App() frame = TreeFrame(model=tree) diff --git a/gui/wxpython/gui_core/widgets.py b/gui/wxpython/gui_core/widgets.py index 035c70e6fbd..0ec50553114 100644 --- a/gui/wxpython/gui_core/widgets.py +++ b/gui/wxpython/gui_core/widgets.py @@ -170,7 +170,7 @@ def InsertPage(self, *args, **kwargs): self.classObject.InsertPage(self.widget, *args, **kwargs) except ( TypeError - ) as e: # documentation says 'index', but certain versions of wx require 'n' + ): # documentation says 'index', but certain versions of wx require 'n' kwargs["n"] = kwargs["index"] del kwargs["index"] self.classObject.InsertPage(self.widget, *args, **kwargs) From dc27b28b4142504ac69a4a17cd4a1673ebbdbf4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Wed, 18 Sep 2024 19:06:08 -0400 Subject: [PATCH 056/209] grass.gunittest: Fix SIM115 using context managers to open files (#4338) * grass.gunittest: Use a context manager for opening htmldiff_file * grass.gunittest: Specify encoding for writing htmldiff_file * grass.gunittest: Write all lines of htmldiff_file at once * grass.gunittest: Use Path.write_text() to write htmldiff_file * grass.gunittest: Use a context manager for opening actual and reference files (SIM115) * grass.gunittest: Use a context manager for output StringIO in case.py * grass.gunittest: Use a context manager for opening files (SIM115) In function replace_in_file of reporters.py * grass.gunittest: Use a context manager for opening files (SIM115) In function wrap_stdstream_to_html of reporters.py * grass.gunittest: Use a context manager for opening files (SIM115) In function report_for_dirs of reporters.py. Reordered so string creation ends up together outside the context manger where the file is written. * grass.gunittest: Use a context manager for opening files (SIM115) In function end_file_test of class GrassTestFilesHtmlReporter of reporters.py. Reordered so string creation ends up together outside the context manger where the strings are written to the file. * grass.gunittest: Use a context manager for opening files (SIM115) In function report_for_dir of class TestsuiteDirReporter of reporters.py * grass.gunittest: Ignore remaining two SIM115 in reporters.py * grass.gunittest: Use a context manager for opening files in multireport (SIM115) * style: Enable checking of SIM115 --- pyproject.toml | 1 - python/grass/gunittest/case.py | 28 +-- python/grass/gunittest/multireport.py | 280 +++++++++++++------------- python/grass/gunittest/reporters.py | 277 ++++++++++++------------- 4 files changed, 300 insertions(+), 286 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b5c7a478864..992e48391ad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -324,7 +324,6 @@ ignore = [ "python/grass/__init__.py" = ["PYI056"] "python/grass/exp*/tests/grass_script_mapset_session_test.py" = ["SIM117"] "python/grass/exp*/tests/grass_script_tmp_mapset_session_test.py" = ["SIM117"] -"python/grass/gunittest/*.py" = ["SIM115"] "python/grass/gunittest/loader.py" = ["PYI024"] "python/grass/gunittest/multireport.py" = ["PYI024"] "python/grass/gunittest/testsu*/d*/s*/s*/subsub*/t*/test_segfaut.py" = ["B018"] diff --git a/python/grass/gunittest/case.py b/python/grass/gunittest/case.py index 4d1b37bdfed..da2c7486d16 100644 --- a/python/grass/gunittest/case.py +++ b/python/grass/gunittest/case.py @@ -10,6 +10,7 @@ """ import os +from pathlib import Path import shutil import subprocess import hashlib @@ -1227,8 +1228,9 @@ def assertVectorAsciiEqualsVectorAscii( """ import difflib - fromlines = open(actual).readlines() - tolines = open(reference).readlines() + with open(actual) as f1, open(reference) as f2: + fromlines = f1.readlines() + tolines = f2.readlines() context_lines = 3 # number of context lines # TODO: filenames are set to "actual" and "reference", isn't it too general? # it is even more useful if map names or file names are some generated @@ -1252,18 +1254,18 @@ def assertVectorAsciiEqualsVectorAscii( os.remove(reference) stdmsg = "There is a difference between vectors when compared as ASCII files.\n" - output = StringIO() # TODO: there is a diff size constant which we can use # we are setting it unlimited but we can just set it large maxlines = 100 i = 0 - for line in diff: - if i >= maxlines: - break - output.write(line) - i += 1 - stdmsg += output.getvalue() - output.close() + with StringIO() as output: + for line in diff: + if i >= maxlines: + break + output.write(line) + i += 1 + stdmsg += output.getvalue() + # it seems that there is not better way of asking whether there was # a difference (always a iterator object is returned) if i > 0: @@ -1288,11 +1290,9 @@ def assertVectorAsciiEqualsVectorAscii( "actual", context=True, numlines=context_lines, + charset="utf-8", ) - htmldiff_file = open(htmldiff_file_name, "w") - for line in htmldiff: - htmldiff_file.write(line) - htmldiff_file.close() + Path(htmldiff_file_name).write_text(htmldiff, encoding="utf-8") self.fail(self._formatMessage(msg, stdmsg)) diff --git a/python/grass/gunittest/multireport.py b/python/grass/gunittest/multireport.py index edeb98636ee..f183d4e0219 100644 --- a/python/grass/gunittest/multireport.py +++ b/python/grass/gunittest/multireport.py @@ -16,6 +16,7 @@ import datetime import operator from collections import defaultdict, namedtuple +from pathlib import Path from grass.gunittest.checkers import text_to_keyvalue from grass.gunittest.utils import ensure_dir @@ -472,7 +473,7 @@ def main(): # skipping incomplete reports # use only results list for further processing continue - summary = text_to_keyvalue(open(summary_file).read(), sep="=") + summary = text_to_keyvalue(Path(summary_file).read_text(), sep="=") if use_timestamps: test_timestamp = datetime.datetime.fromtimestamp( os.path.getmtime(summary_file) @@ -516,147 +517,156 @@ def main(): except KeyError as e: print("File %s does not have right values (%s)" % (report, e.message)) - locations_main_page = open(os.path.join(output, "index.html"), "w") - locations_main_page.write( - "" - "

Test reports grouped by location type

" - "" - "" - "" - "" - "" - "" - ) + with open(os.path.join(output, "index.html"), "w") as locations_main_page: + locations_main_page.write( + "" + "

Test reports grouped by location type

" + "
LocationSuccessful filesSuccessful tests
" + "" + "" + "" + "" + "" + ) - PlotStyle = namedtuple( - "PlotStyle", - ["linestyle", "linewidth", "success_color", "fail_color", "total_color"], - ) - plot_style = PlotStyle( - linestyle="-", linewidth=4.0, success_color="g", fail_color="r", total_color="b" - ) + PlotStyle = namedtuple( + "PlotStyle", + ["linestyle", "linewidth", "success_color", "fail_color", "total_color"], + ) + plot_style = PlotStyle( + linestyle="-", + linewidth=4.0, + success_color="g", + fail_color="r", + total_color="b", + ) - for location_type, results in results_in_locations.items(): - results = sorted(results, key=operator.attrgetter("timestamp")) - # TODO: document: location type must be a valid dir name - directory = os.path.join(output, location_type) - ensure_dir(directory) + for location_type, results in results_in_locations.items(): + results = sorted(results, key=operator.attrgetter("timestamp")) + # TODO: document: location type must be a valid dir name + directory = os.path.join(output, location_type) + ensure_dir(directory) - if location_type == "unknown": - title = "Test reports" - else: - title = "Test reports for <{type}> location type".format( - type=location_type + if location_type == "unknown": + title = "Test reports" + else: + title = "Test reports for <{type}> location type".format( + type=location_type + ) + + x = [date2num(result.timestamp) for result in results] + # the following would be an alternative but it does not work with + # labels and automatic axis limits even after removing another date fun + # x = [result.svn_revision for result in results] + xlabels = [ + result.timestamp.strftime("%Y-%m-%d") + + " (r" + + result.svn_revision + + ")" + for result in results + ] + step = len(x) / 10 + xticks = x[step::step] + xlabels = xlabels[step::step] + tests_successful_plot( + x=x, + xticks=xticks, + xlabels=xlabels, + results=results, + filename=os.path.join(directory, "tests_successful_plot.png"), + style=plot_style, + ) + files_successful_plot( + x=x, + xticks=xticks, + xlabels=xlabels, + results=results, + filename=os.path.join(directory, "files_successful_plot.png"), + style=plot_style, + ) + tests_plot( + x=x, + xticks=xticks, + xlabels=xlabels, + results=results, + filename=os.path.join(directory, "tests_plot.png"), + style=plot_style, + ) + tests_percent_plot( + x=x, + xticks=xticks, + xlabels=xlabels, + results=results, + filename=os.path.join(directory, "tests_percent_plot.png"), + style=plot_style, + ) + files_plot( + x=x, + xticks=xticks, + xlabels=xlabels, + results=results, + filename=os.path.join(directory, "files_plot.png"), + style=plot_style, + ) + files_percent_plot( + x=x, + xticks=xticks, + xlabels=xlabels, + results=results, + filename=os.path.join(directory, "files_percent_plot.png"), + style=plot_style, + ) + info_plot( + x=x, + xticks=xticks, + xlabels=xlabels, + results=results, + filename=os.path.join(directory, "info_plot.png"), + style=plot_style, ) - x = [date2num(result.timestamp) for result in results] - # the following would be an alternative but it does not work with - # labels and automatic axis limits even after removing another date fun - # x = [result.svn_revision for result in results] - xlabels = [ - result.timestamp.strftime("%Y-%m-%d") + " (r" + result.svn_revision + ")" - for result in results - ] - step = len(x) / 10 - xticks = x[step::step] - xlabels = xlabels[step::step] - tests_successful_plot( - x=x, - xticks=xticks, - xlabels=xlabels, - results=results, - filename=os.path.join(directory, "tests_successful_plot.png"), - style=plot_style, - ) - files_successful_plot( - x=x, - xticks=xticks, - xlabels=xlabels, - results=results, - filename=os.path.join(directory, "files_successful_plot.png"), - style=plot_style, - ) - tests_plot( - x=x, - xticks=xticks, - xlabels=xlabels, - results=results, - filename=os.path.join(directory, "tests_plot.png"), - style=plot_style, - ) - tests_percent_plot( - x=x, - xticks=xticks, - xlabels=xlabels, - results=results, - filename=os.path.join(directory, "tests_percent_plot.png"), - style=plot_style, - ) - files_plot( - x=x, - xticks=xticks, - xlabels=xlabels, - results=results, - filename=os.path.join(directory, "files_plot.png"), - style=plot_style, - ) - files_percent_plot( - x=x, - xticks=xticks, - xlabels=xlabels, - results=results, - filename=os.path.join(directory, "files_percent_plot.png"), - style=plot_style, - ) - info_plot( - x=x, - xticks=xticks, - xlabels=xlabels, - results=results, - filename=os.path.join(directory, "info_plot.png"), - style=plot_style, - ) + main_page( + results=results, + filename="index.html", + images=[ + "tests_successful_plot.png", + "files_successful_plot.png", + "tests_plot.png", + "files_plot.png", + "tests_percent_plot.png", + "files_percent_plot.png", + "info_plot.png", + ], + captions=[ + "Success of individual tests in percents", + "Success of test files in percents", + "Successes, failures and number of individual tests", + "Successes, failures and number of test files", + "Successes and failures of individual tests in percent", + "Successes and failures of test files in percents", + "Additional information", + ], + directory=directory, + title=title, + ) - main_page( - results=results, - filename="index.html", - images=[ - "tests_successful_plot.png", - "files_successful_plot.png", - "tests_plot.png", - "files_plot.png", - "tests_percent_plot.png", - "files_percent_plot.png", - "info_plot.png", - ], - captions=[ - "Success of individual tests in percents", - "Success of test files in percents", - "Successes, failures and number of individual tests", - "Successes, failures and number of test files", - "Successes and failures of individual tests in percent", - "Successes and failures of test files in percents", - "Additional information", - ], - directory=directory, - title=title, - ) + files_successes = sum(result.files_successes for result in results) + files_total = sum(result.files_total for result in results) + successes = sum(result.successes for result in results) + total = sum(result.total for result in results) + per_test = success_to_html_percent(total=total, successes=successes) + per_file = success_to_html_percent( + total=files_total, successes=files_successes + ) + locations_main_page.write( + "" + "" + "" + "".format(location=location_type, pfiles=per_file, ptests=per_test) + ) + locations_main_page.write("
LocationSuccessful filesSuccessful tests
{location}{pfiles}{ptests}
") + locations_main_page.write("") - files_successes = sum(result.files_successes for result in results) - files_total = sum(result.files_total for result in results) - successes = sum(result.successes for result in results) - total = sum(result.total for result in results) - per_test = success_to_html_percent(total=total, successes=successes) - per_file = success_to_html_percent(total=files_total, successes=files_successes) - locations_main_page.write( - "" - "{location}" - "{pfiles}{ptests}" - "".format(location=location_type, pfiles=per_file, ptests=per_test) - ) - locations_main_page.write("") - locations_main_page.write("") - locations_main_page.close() return 0 diff --git a/python/grass/gunittest/reporters.py b/python/grass/gunittest/reporters.py index ec175613bc3..650480a234c 100644 --- a/python/grass/gunittest/reporters.py +++ b/python/grass/gunittest/reporters.py @@ -51,12 +51,9 @@ def replace_in_file(file_path, pattern, repl): """ # using tmp file to store the replaced content tmp_file_path = file_path + ".tmp" - old_file = open(file_path, "r") - new_file = open(tmp_file_path, "w") - for line in old_file: - new_file.write(re.sub(pattern=pattern, string=line, repl=repl)) - new_file.close() - old_file.close() + with open(file_path, "r") as old_file, open(tmp_file_path, "w") as new_file: + for line in old_file: + new_file.write(re.sub(pattern=pattern, string=line, repl=repl)) # remove old file since it must not exist for rename/move os.remove(file_path) # replace old file by new file @@ -455,13 +452,11 @@ def percent_to_html(percent): def wrap_stdstream_to_html(infile, outfile, module, stream): before = "

%s

" % (module.name + " " + stream)
     after = "
" - html = open(outfile, "w") - html.write(before) - with open(infile) as text: + with open(outfile, "w") as html, open(infile) as text: + html.write(before) for line in text: html.write(color_error_line(html_escape(line))) - html.write(after) - html.close() + html.write(after) def html_file_preview(filename): @@ -482,7 +477,7 @@ def html_file_preview(filename): elif size < 10 * max_size: def tail(filename, n): - return collections.deque(open(filename), n) + return collections.deque(open(filename), n) # noqa: SIM115 html.write("... (lines omitted)\n") for line in tail(filename, 50): @@ -564,7 +559,8 @@ def start(self, results_dir): super().start(results_dir) # having all variables public although not really part of API main_page_name = os.path.join(results_dir, self._main_page_name) - self.main_index = open(main_page_name, "w") + # TODO: Ensure file is closed in all situations + self.main_index = open(main_page_name, "w") # noqa: SIM115 # TODO: this can be moved to the counter class self.failures = 0 @@ -733,8 +729,7 @@ def end_file_test( ) file_index_path = os.path.join(cwd, "index.html") - file_index = open(file_index_path, "w") - file_index.write( + header = ( '' "

{m.name}

" "

{m.tested_dir} – {m.name}

" @@ -773,7 +768,6 @@ def end_file_test( dur=self.file_time, ) ) - file_index.write(summary_section) modules = test_summary.get("tested_modules", None) if modules: @@ -782,12 +776,6 @@ def end_file_test( # alternatively a link to module test summary if type(modules) is not list: modules = [modules] - file_index.write( - "Tested modules{0}".format( - ", ".join(sorted(set(modules))) - ) - ) - file_index.write("") # here we would have also links to coverage, profiling, ... # '
  • code coverage
  • ' @@ -797,7 +785,6 @@ def end_file_test( '
  • standard output (stdout)
  • ' '
  • standard error output (stderr)
  • ' ) - file_index.write(files_section) supplementary_files = test_summary.get("supplementary_files", None) if supplementary_files: @@ -809,17 +796,31 @@ def end_file_test( # moreover something can be shared with other explicitly # using constructors as seems advantageous for counting self._file_anonymizer.anonymize(supplementary_files) - for f in supplementary_files: - file_index.write('
  • {f}
  • '.format(f=f)) - file_index.write("") + with open(file_index_path, "w") as file_index: + file_index.write(header) + file_index.write(summary_section) + if modules: + file_index.write( + "Tested modules{0}".format( + ", ".join(sorted(set(modules))) + ) + ) + file_index.write("") + + file_index.write(files_section) - if returncode: - file_index.write("

    Standard error output (stderr)

    ") - file_index.write(html_file_preview(stderr)) + if supplementary_files: + for f in supplementary_files: + file_index.write('
  • {f}
  • '.format(f=f)) + + file_index.write("") - file_index.write("") - file_index.close() + if returncode: + file_index.write("

    Standard error output (stderr)

    ") + file_index.write(html_file_preview(stderr)) + + file_index.write("") if returncode: pass @@ -1093,7 +1094,7 @@ def report_for_dir(self, root, directory, test_files): os.path.join(root, directory) ) == os.path.abspath(root): page_name = os.path.join(root, self.top_level_testsuite_page_name) - page = open(page_name, "w") + # TODO: should we use forward slashes also for the HTML because # it is simpler are more consistent with the rest on MS Windows? head = "

    {name} testsuite results

    ".format(name=directory) @@ -1106,106 +1107,108 @@ def report_for_dir(self, root, directory, test_files): "FailedPercent successful" "" ) - page.write(head) - page.write(tests_table_head) - for test_file_name in test_files: - # TODO: put keyvalue fine name to constant - summary_filename = os.path.join( - root, directory, test_file_name, "test_keyvalue_result.txt" - ) - # if os.path.exists(summary_filename): - summary = text_to_keyvalue(Path(summary_filename).read_text(), sep="=") - # else: - # TODO: write else here - # summary = None - - if "total" not in summary: - bad_ones = successes = UNKNOWN_NUMBER_HTML - total = None - else: - bad_ones = summary["failures"] + summary["errors"] - successes = summary["successes"] - total = summary["total"] - - self.failures += summary["failures"] - self.errors += summary["errors"] - self.skipped += summary["skipped"] - self.successes += summary["successes"] - self.expected_failures += summary["expected_failures"] - self.unexpected_successes += summary["unexpected_successes"] - self.total += summary["total"] - - dir_failures += summary["failures"] - dir_errors += summary["failures"] - dir_skipped += summary["skipped"] - dir_successes += summary["successes"] - dir_expected_failures += summary["expected_failures"] - dir_unexpected_success += summary["unexpected_successes"] - dir_total += summary["total"] - - # TODO: keyvalue method should have types for keys function - # perhaps just the current post processing function is enough - test_file_authors = summary.get("test_file_authors") - if not test_file_authors: - test_file_authors = [] - if type(test_file_authors) is not list: - test_file_authors = [test_file_authors] - test_files_authors.extend(test_file_authors) - - file_total += 1 - # Use non-zero return code in case it is missing. - # (This can happen when the test has timed out.) - return_code = summary.get("returncode", 1) - file_successes += 0 if return_code else 1 + with open(page_name, "w") as page: + page.write(head) + page.write(tests_table_head) + for test_file_name in test_files: + # TODO: put keyvalue fine name to constant + summary_filename = os.path.join( + root, directory, test_file_name, "test_keyvalue_result.txt" + ) + # if os.path.exists(summary_filename): + summary = text_to_keyvalue(Path(summary_filename).read_text(), sep="=") + # else: + # TODO: write else here + # summary = None + + if "total" not in summary: + bad_ones = successes = UNKNOWN_NUMBER_HTML + total = None + else: + bad_ones = summary["failures"] + summary["errors"] + successes = summary["successes"] + total = summary["total"] + + self.failures += summary["failures"] + self.errors += summary["errors"] + self.skipped += summary["skipped"] + self.successes += summary["successes"] + self.expected_failures += summary["expected_failures"] + self.unexpected_successes += summary["unexpected_successes"] + self.total += summary["total"] + + dir_failures += summary["failures"] + dir_errors += summary["failures"] + dir_skipped += summary["skipped"] + dir_successes += summary["successes"] + dir_expected_failures += summary["expected_failures"] + dir_unexpected_success += summary["unexpected_successes"] + dir_total += summary["total"] + + # TODO: keyvalue method should have types for keys function + # perhaps just the current post processing function is enough + test_file_authors = summary.get("test_file_authors") + if not test_file_authors: + test_file_authors = [] + if type(test_file_authors) is not list: + test_file_authors = [test_file_authors] + test_files_authors.extend(test_file_authors) + + file_total += 1 + # Use non-zero return code in case it is missing. + # (This can happen when the test has timed out.) + return_code = summary.get("returncode", 1) + file_successes += 0 if return_code else 1 + + pass_per = success_to_html_percent(total=total, successes=successes) + row = ( + "" + '{f}' + "{status}" + "{ntests}{stests}" + "{ftests}{ptests}" + "".format( + f=test_file_name, + status=returncode_to_html_text(return_code), + stests=successes, + ftests=bad_ones, + ntests=total, + ptests=pass_per, + ) + ) + page.write(row) - pass_per = success_to_html_percent(total=total, successes=successes) - row = ( - "" - '{f}' + self.testsuites += 1 + self.testsuites_successes += 1 if file_successes == file_total else 0 + self.files += file_total + self.files_successes += file_successes + + dir_pass_per = success_to_html_percent( + total=dir_total, successes=dir_successes + ) + file_pass_per = success_to_html_percent( + total=file_total, successes=file_successes + ) + tests_table_foot = ( + "" + "Summary" "{status}" "{ntests}{stests}" "{ftests}{ptests}" - "".format( - f=test_file_name, - status=returncode_to_html_text(return_code), - stests=successes, - ftests=bad_ones, - ntests=total, - ptests=pass_per, + "".format( + status=file_pass_per, + stests=dir_successes, + ftests=dir_failures + dir_errors, + ntests=dir_total, + ptests=dir_pass_per, ) ) - page.write(row) - - self.testsuites += 1 - self.testsuites_successes += 1 if file_successes == file_total else 0 - self.files += file_total - self.files_successes += file_successes - - dir_pass_per = success_to_html_percent(total=dir_total, successes=dir_successes) - file_pass_per = success_to_html_percent( - total=file_total, successes=file_successes - ) - tests_table_foot = ( - "" - "Summary" - "{status}" - "{ntests}{stests}" - "{ftests}{ptests}" - "".format( - status=file_pass_per, - stests=dir_successes, - ftests=dir_failures + dir_errors, - ntests=dir_total, - ptests=dir_pass_per, + page.write(tests_table_foot) + test_authors = get_html_test_authors_table( + directory=directory, tests_authors=test_files_authors ) - ) - page.write(tests_table_foot) - test_authors = get_html_test_authors_table( - directory=directory, tests_authors=test_files_authors - ) - page.write(test_authors) - page.write("") - page.close() + page.write(test_authors) + page.write("") status = success_to_html_text(total=file_total, successes=file_successes) return ( @@ -1233,7 +1236,6 @@ def report_for_dirs(self, root, directories): # absolute/relative paths page_name = os.path.join(root, self.main_page_name) - page = open(page_name, "w") head = "

    Testsuites results

    " tests_table_head = ( "" @@ -1246,14 +1248,6 @@ def report_for_dirs(self, root, directories): "" "" ) - page.write(head) - page.write(tests_table_head) - - for directory, test_files in directories.items(): - row = self.report_for_dir( - root=root, directory=directory, test_files=test_files - ) - page.write(row) pass_per = success_to_html_percent(total=self.total, successes=self.successes) file_pass_per = success_to_html_percent( @@ -1281,5 +1275,16 @@ def report_for_dirs(self, root, directories): ptests=pass_per, ) ) - page.write(tests_table_foot) - page.write("") + + with open(page_name, "w") as page: + page.write(head) + page.write(tests_table_head) + + for directory, test_files in directories.items(): + row = self.report_for_dir( + root=root, directory=directory, test_files=test_files + ) + page.write(row) + + page.write(tests_table_foot) + page.write("") From b69cacf7ab1737a823148e537099a120b0b33b01 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 00:00:14 +0000 Subject: [PATCH 057/209] CI(deps): Update peter-evans/create-pull-request action to v7.0.5 (#4339) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/periodic_update.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/periodic_update.yml b/.github/workflows/periodic_update.yml index 7b8c08b5b70..bea3b53af4a 100644 --- a/.github/workflows/periodic_update.yml +++ b/.github/workflows/periodic_update.yml @@ -33,7 +33,7 @@ jobs: run: git status --ignored - name: Create Pull Request id: cpr - uses: peter-evans/create-pull-request@6cd32fd93684475c31847837f87bb135d40a2b79 # v7.0.3 + uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5 with: commit-message: "config.guess + config.sub: updated from http://git.savannah.gnu.org/cgit/config.git/plain/" branch: periodic/update-configure From 05584c1fbe3012debcefa66b6f27b83a2254b2ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Wed, 18 Sep 2024 21:02:01 -0400 Subject: [PATCH 058/209] CI(OSGeo4W): Update min-success to 86% for gunittest on Windows (#4341) --- .github/workflows/test_thorough.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_thorough.bat b/.github/workflows/test_thorough.bat index 963f24b9b43..40df9534a20 100644 --- a/.github/workflows/test_thorough.bat +++ b/.github/workflows/test_thorough.bat @@ -2,4 +2,4 @@ set grass=%1 set python=%2 call %grass% --tmp-project XY --exec g.download.project url=https://grass.osgeo.org/sampledata/north_carolina/nc_spm_full_v2alpha2.tar.gz path=%USERPROFILE% -call %grass% --tmp-project XY --exec %python% -m grass.gunittest.main --grassdata %USERPROFILE% --location nc_spm_full_v2alpha2 --location-type nc --min-success 80 +call %grass% --tmp-project XY --exec %python% -m grass.gunittest.main --grassdata %USERPROFILE% --location nc_spm_full_v2alpha2 --location-type nc --min-success 86 From 7dc46cdadd53399c566cf0a496632c80ea03db81 Mon Sep 17 00:00:00 2001 From: Mohan Yelugoti Date: Wed, 18 Sep 2024 21:06:20 -0400 Subject: [PATCH 059/209] v.in.dwg: Retire v.in.dwg infavor of v.in.redwg (#4329) v.in.dwg is linked to proprietary library 'OpenDWG toolkit'. One needs to become a member of OpenDWG Alliance to get the needed libraries and headers in order to compile this tool. However, OpenDWG webpage went offline around 2011 and we have 'v.in.redwg' as replacement for it (available in grass-addons). Hence retire 'v.in.dwg' tool. Besides the tool, this completely removes OpenDWG from configure.ac and platform. Signed-off-by: Mohan Yelugoti --- configure | 151 ---------- configure.ac | 43 --- include/Make/Platform.make.in | 6 - vector/Makefile | 1 - vector/v.in.dwg/Makefile | 31 -- vector/v.in.dwg/README | 23 -- vector/v.in.dwg/WARNING | 7 - vector/v.in.dwg/entity.c | 540 ---------------------------------- vector/v.in.dwg/global.h | 59 ---- vector/v.in.dwg/main.c | 295 ------------------- vector/v.in.dwg/v.in.dwg.html | 32 -- 11 files changed, 1188 deletions(-) delete mode 100644 vector/v.in.dwg/Makefile delete mode 100644 vector/v.in.dwg/README delete mode 100644 vector/v.in.dwg/WARNING delete mode 100644 vector/v.in.dwg/entity.c delete mode 100644 vector/v.in.dwg/global.h delete mode 100644 vector/v.in.dwg/main.c delete mode 100644 vector/v.in.dwg/v.in.dwg.html diff --git a/configure b/configure index bc60ae7c41c..4b9a63f7947 100755 --- a/configure +++ b/configure @@ -666,10 +666,6 @@ USE_PTHREAD PTHREADLIB PTHREADLIBPATH PTHREADINCPATH -USE_OPENDWG -OPENDWGLIB -OPENDWGLIBPATH -OPENDWGINCPATH HAVE_NLS INTLLIB FTLIB @@ -912,7 +908,6 @@ with_cairo with_freetype with_nls with_readline -with_opendwg with_regex with_pthread with_openmp @@ -964,8 +959,6 @@ with_freetype_libs with_proj_includes with_proj_libs with_proj_share -with_opendwg_includes -with_opendwg_libs with_regex_includes with_regex_libs with_pthread_includes @@ -1647,7 +1640,6 @@ Optional Packages: --with-freetype support FreeType functionality (default: yes) --with-nls support NLS functionality (default: no) --with-readline support Readline functionality (default: no) - --with-opendwg support openDWG functionality (default: no) --with-regex support regex functionality (default: yes) --with-pthread support POSIX threads functionality (default: no) --with-openmp support OpenMP functionality (default: no) @@ -1734,10 +1726,6 @@ Optional Packages: External PROJ.4 include files are in DIRS --with-proj-libs=DIRS External PROJ.4 library files are in DIRS --with-proj-share=DIR External PROJ.4 data files are in DIR - --with-opendwg-includes=DIRS - openDWG include files are in DIRS - --with-opendwg-libs=DIRS - openDWG library files are in DIRS --with-regex-includes=DIRS regex include files are in DIRS --with-regex-libs=DIRS regex library files are in DIRS @@ -5566,17 +5554,6 @@ fi -# Check whether --with-opendwg was given. -if test ${with_opendwg+y} -then : - withval=$with_opendwg; -else $as_nop - with_opendwg=no -fi - - - - # Check whether --with-regex was given. if test ${with_regex+y} then : @@ -6069,25 +6046,6 @@ fi -# Check whether --with-opendwg-includes was given. -if test ${with_opendwg_includes+y} -then : - withval=$with_opendwg_includes; -fi - - - - -# Check whether --with-opendwg-libs was given. -if test ${with_opendwg_libs+y} -then : - withval=$with_opendwg_libs; -fi - - - - - # Check whether --with-regex-includes was given. if test ${with_regex_includes+y} then : @@ -15207,113 +15165,6 @@ fi -# Enable openDWG option - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use openDWG" >&5 -printf %s "checking whether to use openDWG... " >&6; } -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$with_opendwg\"" >&5 -printf "%s\n" "\"$with_opendwg\"" >&6; } -case "$with_opendwg" in - "no") USE_OPENDWG= ;; - "yes") USE_OPENDWG="1" ;; - *) as_fn_error $? "*** You must answer yes or no." "$LINENO" 5 ;; -esac - - - -OPENDWGINCPATH= -OPENDWGLIBPATH= -OPENDWGLIB= - -if test -n "${USE_OPENDWG}"; then - -# With OPENDWG includes directory - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for location of openDGW includes" >&5 -printf %s "checking for location of openDGW includes... " >&6; } -case "$with_opendwg_includes" in -y | ye | yes | n | no) - as_fn_error $? "*** You must supply a directory to --with-opendwg-includes." "$LINENO" 5 - ;; -esac -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_opendwg_includes" >&5 -printf "%s\n" "$with_opendwg_includes" >&6; } - -if test -n "$with_opendwg_includes" ; then - for dir in $with_opendwg_includes; do - if test -d "$dir"; then - OPENDWGINCPATH="$OPENDWGINCPATH -I$dir" - else - as_fn_error $? "*** openDGW includes directory $dir does not exist." "$LINENO" 5 - fi - done -fi - - - -ac_save_cppflags="$CPPFLAGS" -CPPFLAGS="$OPENDWGINCPATH $CPPFLAGS" - for ac_header in ad2.h -do : - ac_fn_c_check_header_compile "$LINENO" "ad2.h" "ac_cv_header_ad2_h" "$ac_includes_default" -if test "x$ac_cv_header_ad2_h" = xyes -then : - printf "%s\n" "#define HAVE_AD2_H 1" >>confdefs.h - -else $as_nop - - as_fn_error $? "*** Unable to locate openDWG includes." "$LINENO" 5 - -fi - -done -CPPFLAGS=$ac_save_cppflags - - -# With OPENDWG library directory - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for location of openDWG library" >&5 -printf %s "checking for location of openDWG library... " >&6; } -case "$with_opendwg_libs" in -y | ye | yes | n | no) - as_fn_error $? "*** You must supply a directory to --with-opendwg-libs." "$LINENO" 5 - ;; -esac -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_opendwg_libs" >&5 -printf "%s\n" "$with_opendwg_libs" >&6; } - -if test -n "$with_opendwg_libs"; then - for dir in $with_opendwg_libs; do - if test -d "$dir"; then - OPENDWGLIBPATH="$OPENDWGLIBPATH -L$dir" - else - as_fn_error $? "*** openDWG library directory $dir does not exist." "$LINENO" 5 - fi - done -fi - - -#search for ad2.a, ad3.a ... in openDWG toolkit directory: -#FIX ME how to program this test?? -#LOC_CHECK_LIBS(ad?.a,adSeekLayer,openDWG,$OPENDWGLIBPATH,OPENDWGLIB,,) -# -#for now hack (but working): -TRUEOPENDWGLIBPATH=`echo "$OPENDWGLIBPATH" | cut -b3-` -adlib=`ls -1 "$TRUEOPENDWGLIBPATH"/ad?.a | tail -1` -OPENDWGLIB="$adlib" - -fi # $USE_OPENDWG - - - - - - -# Done checking OPENDWG - # Enable pthread option @@ -17688,8 +17539,6 @@ echo " C++ support: `if test -n "${USE_CXX}" ; then echo yes ; e echo " Cairo support: `if test -n "${USE_CAIRO}" ; then echo yes ; else echo no ; fi`" -echo " DWG support: `if test -n "${USE_OPENDWG}" ; then echo yes ; else echo no ; fi`" - echo " FFTW support: `if test -n "${USE_FFTW}" ; then echo yes ; else echo no ; fi`" echo " FreeType support: `if test -n "${USE_FREETYPE}" ; then echo yes ; else echo no ; fi`" diff --git a/configure.ac b/configure.ac index b38a2a5936c..00403f1e665 100644 --- a/configure.ac +++ b/configure.ac @@ -312,7 +312,6 @@ LOC_ARG_WITH(cairo, Cairo) LOC_ARG_WITH(freetype, FreeType) LOC_ARG_WITH(nls, NLS, no) LOC_ARG_WITH(readline, Readline, no) -LOC_ARG_WITH(opendwg, openDWG, no) LOC_ARG_WITH(regex, regex) LOC_ARG_WITH(pthread, POSIX threads, no) LOC_ARG_WITH(openmp, OpenMP, no) @@ -411,9 +410,6 @@ LOC_ARG_WITH_INC(proj, External PROJ.4) LOC_ARG_WITH_LIB(proj, External PROJ.4) LOC_ARG_WITH_SHARE(proj, External PROJ.4) -LOC_ARG_WITH_INC(opendwg, openDWG) -LOC_ARG_WITH_LIB(opendwg, openDWG) - LOC_ARG_WITH_INC(regex, regex) LOC_ARG_WITH_LIB(regex, regex) @@ -1860,44 +1856,6 @@ fi AC_SUBST(INTLLIB) AC_SUBST(HAVE_NLS) -# Enable openDWG option - -LOC_CHECK_USE(opendwg,openDWG,USE_OPENDWG) - -OPENDWGINCPATH= -OPENDWGLIBPATH= -OPENDWGLIB= - -if test -n "${USE_OPENDWG}"; then - -# With OPENDWG includes directory - -LOC_CHECK_INC_PATH(opendwg,openDGW,OPENDWGINCPATH) - -LOC_CHECK_INCLUDES(ad2.h,openDWG,$OPENDWGINCPATH) - -# With OPENDWG library directory - -LOC_CHECK_LIB_PATH(opendwg,openDWG,OPENDWGLIBPATH) - -#search for ad2.a, ad3.a ... in openDWG toolkit directory: -#FIX ME how to program this test?? -#LOC_CHECK_LIBS(ad?.a,adSeekLayer,openDWG,$OPENDWGLIBPATH,OPENDWGLIB,,) -# -#for now hack (but working): -TRUEOPENDWGLIBPATH=`echo "$OPENDWGLIBPATH" | cut -b3-` -adlib=`ls -1 "$TRUEOPENDWGLIBPATH"/ad?.a | tail -1` -OPENDWGLIB="$adlib" - -fi # $USE_OPENDWG - -AC_SUBST(OPENDWGINCPATH) -AC_SUBST(OPENDWGLIBPATH) -AC_SUBST(OPENDWGLIB) -AC_SUBST(USE_OPENDWG) - -# Done checking OPENDWG - # Enable pthread option LOC_CHECK_USE(pthread,POSIX threads,USE_PTHREAD) @@ -2072,7 +2030,6 @@ LOC_MSG_USE(BLAS support,USE_BLAS) LOC_MSG_USE(BZIP2 support,USE_BZIP2) LOC_MSG_USE(C++ support,USE_CXX) LOC_MSG_USE(Cairo support,USE_CAIRO) -LOC_MSG_USE(DWG support,USE_OPENDWG) LOC_MSG_USE(FFTW support,USE_FFTW) LOC_MSG_USE(FreeType support,USE_FREETYPE) LOC_MSG_USE(GDAL support,USE_GDAL) diff --git a/include/Make/Platform.make.in b/include/Make/Platform.make.in index c65ed28c686..a66ddf801d3 100644 --- a/include/Make/Platform.make.in +++ b/include/Make/Platform.make.in @@ -203,12 +203,6 @@ PROJINC = @PROJINC@ PROJLIB = @PROJLIB@ PROJSHARE = @PROJSHARE@ -#OPENDWG: -OPENDWGINCPATH = @OPENDWGINCPATH@ -OPENDWGLIBPATH = @OPENDWGLIBPATH@ -OPENDWGLIB = @OPENDWGLIB@ -USE_OPENDWG = @USE_OPENDWG@ - #cairo CAIROINC = @CAIROINC@ CAIROLIB = @CAIROLIB@ diff --git a/vector/Makefile b/vector/Makefile index f195ce3aafb..7244ac59af5 100644 --- a/vector/Makefile +++ b/vector/Makefile @@ -102,7 +102,6 @@ SUBDIRS = \ v.out.ogr \ v.in.ogr \ v.external \ - v.in.dwg \ v.in.lidar \ v.external.out diff --git a/vector/v.in.dwg/Makefile b/vector/v.in.dwg/Makefile deleted file mode 100644 index c5c30c1dde7..00000000000 --- a/vector/v.in.dwg/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -MODULE_TOPDIR = ../.. - -PGM=v.in.dwg -ADINIT = $(ETC)/adinit.dat -ADINITSRC := $(shell echo $(OPENDWGINCPATH) | cut -b3- )/adinit/adinit.dat - -DEPENDENCIES = $(VECTORDEP) $(DBMIDEP) $(GISDEP) -LIBES = $(VECTORLIB) $(DBMILIB) $(GISLIB) $(OPENDWGLIBPATH) $(OPENDWGLIB) -EXTRA_INC = $(VECT_INC) $(OPENDWGINCPATH) -EXTRA_CFLAGS = $(VECT_CFLAGS) - -include $(MODULE_TOPDIR)/include/Make/Module.make - -ifneq ($(USE_OPENDWG),) -default: check - $(MAKE) cmd $(ADINIT) -endif - -check: -ifneq ($(strip $(MINGW)),) - cat WARNING -else - cat WARNING >/dev/tty -endif - @read IN ." diff --git a/vector/v.in.dwg/entity.c b/vector/v.in.dwg/entity.c deleted file mode 100644 index c70bc308fe0..00000000000 --- a/vector/v.in.dwg/entity.c +++ /dev/null @@ -1,540 +0,0 @@ -/* ************************************************************** - * - * MODULE: v.in.dwg - * - * AUTHOR(S): Radim Blazek - * - * PURPOSE: Import of DWG/DXF files - * - * COPYRIGHT: (C) 2001 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. - * - * In addition, as a special exception, Radim Blazek gives permission - * to link the code of this program with the OpenDWG libraries (or with - * modified versions of the OpenDWG libraries that use the same license - * as OpenDWG libraries), and distribute linked combinations including the two. - * You must obey the GNU General Public License in all respects for all - * of the code used other than. If you modify this file, you may extend - * this exception to your version of the file, but you are not obligated - * to do so. If you do not wish to do so, delete this exception statement - * from your version. - * - * **************************************************************/ - -/* Documentation: - * http://www.opendwg.org - * -> OpenDWG Toolkit Reference - * - * Unsupported entities must be added in wrentity() - * - * TODO: 3rd dimension is not functional for CIRCLE and ARC - * -> required updated of transformation in INSERT - * (how to do that??) - */ - -#define AD_PROTOTYPES -#define AD_VM_PC - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ad2.h" -#include "global.h" - -#define exampleprintf printf -#define LOCPI M_PI - -char buf[1000]; -char buf2[1000]; - -void getEntTypeName(PAD_ENT_HDR adenhd, char *name) -{ - switch (adenhd->enttype) { - case AD_ENT_LINE: - strcpy(name, "LINE"); - break; - case AD_ENT_POINT: - strcpy(name, "POINT"); - break; - case AD_ENT_CIRCLE: - strcpy(name, "CIRCLE"); - break; - case AD_ENT_SHAPE: - strcpy(name, "SHAPE"); - break; - case AD_ENT_ELLIPSE: - strcpy(name, "ELLIPSE"); - break; - case AD_ENT_SPLINE: - strcpy(name, "SPLINE"); - break; - case AD_ENT_TEXT: - strcpy(name, "TEXT"); - break; - case AD_ENT_ARC: - strcpy(name, "ARC"); - break; - case AD_ENT_TRACE: - strcpy(name, "TRACE"); - break; - case AD_ENT_SOLID: - strcpy(name, "SOLID"); - break; - case AD_ENT_BLOCK: - strcpy(name, "BLOCK"); - break; - case AD_ENT_ENDBLK: - strcpy(name, "ENDBLK"); - break; - case AD_ENT_INSERT: - strcpy(name, "INSERT"); - break; - case AD_ENT_ATTDEF: - strcpy(name, "ATTDEF"); - break; - case AD_ENT_ATTRIB: - strcpy(name, "ATTRIB"); - break; - case AD_ENT_SEQEND: - strcpy(name, "SEQEND"); - break; - case AD_ENT_POLYLINE: - strcpy(name, "POLYLINE"); - break; - case AD_ENT_VERTEX: - strcpy(name, "VERTEX"); - break; - case AD_ENT_LINE3D: - strcpy(name, "3DLINE"); - break; - case AD_ENT_FACE3D: - strcpy(name, "3DFACE"); - break; - case AD_ENT_DIMENSION: - strcpy(name, "DIMENSION"); - break; - case AD_ENT_VIEWPORT: - strcpy(name, "VIEWPORT"); - break; - case AD_ENT_SOLID3D: - strcpy(name, "SOLID3D"); - break; - case AD_ENT_RAY: - strcpy(name, "RAY"); - break; - case AD_ENT_XLINE: - strcpy(name, "XLINE"); - break; - case AD_ENT_MTEXT: - strcpy(name, "MTEXT"); - break; - case AD_ENT_LEADER: - strcpy(name, "LEADER"); - break; - case AD_ENT_TOLERANCE: - strcpy(name, "TOLERANCE"); - break; - case AD_ENT_MLINE: - strcpy(name, "MLINE"); - break; - case AD_ENT_BODY: - strcpy(name, "BODY"); - break; - case AD_ENT_REGION: - strcpy(name, "REGION"); - break; - default: - if (adenhd->enttype == adOle2frameEnttype(dwghandle)) - strcpy(name, "OLE2FRAME"); - else if (adenhd->enttype == adLwplineEnttype(dwghandle)) - strcpy(name, "LWPOLYLINE"); - else if (adenhd->enttype == adHatchEnttype(dwghandle)) - strcpy(name, "HATCH"); - else if (adenhd->enttype == adImageEnttype(dwghandle)) - strcpy(name, "IMAGE"); - else if (adenhd->enttype == adArcAlignedTextEnttype(dwghandle)) - strcpy(name, "ArcAlignedText"); - else if (adenhd->enttype == adWipeoutEnttype(dwghandle)) - strcpy(name, "Wipeout"); - else if (adenhd->enttype == adRtextEnttype(dwghandle)) - strcpy(name, "Rtext"); - else { /* regular proxy */ - - G_debug(3, "adenhd->enttype: %d", adenhd->enttype); - strcpy(name, "Proxy"); - } - break; - } -} - -int write_line(PAD_ENT_HDR adenhd, int type, int level) -{ - int i, l; - double x, y, z, r, ang; - - adSeekLayer(dwghandle, adenhd->entlayerobjhandle, Layer); - - /* Transformation, go up through all levels of transformation */ - /* not sure what is the right order of transformation */ - for (l = level; l >= 0; l--) { - for (i = 0; i < Points->n_points; i++) { - /* scale */ - x = Points->x[i] * Trans[l].xscale; - y = Points->y[i] * Trans[l].yscale; - z = Points->z[i] * Trans[l].zscale; - /* rotate */ - r = sqrt(x * x + y * y); - ang = atan2(y, x) + Trans[l].rotang; - x = r * cos(ang); - y = r * sin(ang); - /* move */ - x += Trans[l].dx; - y += Trans[l].dy; - z += Trans[l].dz; - Points->x[i] = x; - Points->y[i] = y; - Points->z[i] = z; - } - } - - Vect_reset_cats(Cats); - Vect_cat_set(Cats, 1, cat); - Vect_write_line(&Map, type, Points, Cats); - - /* Cat */ - sprintf(buf, "insert into %s values ( %d", Fi->table, cat); - db_set_string(&sql, buf); - - /* Entity name */ - getEntTypeName(adenhd, buf2); - sprintf(buf, ", '%s'", buf2); - db_append_string(&sql, buf); - - /* Color */ - sprintf(buf, ", %d", adenhd->entcolor); - db_append_string(&sql, buf); - - /* Weight */ - sprintf(buf, ", %d", adenhd->lineweight); - db_append_string(&sql, buf); - - /* Layer name */ - if (!Layer->purgedflag && Layer->name != NULL) { - db_set_string(&str, Layer->name); - db_double_quote_string(&str); - sprintf(buf, ", '%s'", db_get_string(&str)); - } - else { - sprintf(buf, ", ''"); - } - db_append_string(&sql, buf); - - /* Block name */ - if (Block != NULL) { - db_set_string(&str, Block); - db_double_quote_string(&str); - } - else { - db_set_string(&str, ""); - } - sprintf(buf, ", '%s'", db_get_string(&str)); - db_append_string(&sql, buf); - - /* Text */ - if (Txt != NULL) { - db_set_string(&str, Txt); - db_double_quote_string(&str); - } - else { - db_set_string(&str, ""); - } - sprintf(buf, ", '%s'", db_get_string(&str)); - db_append_string(&sql, buf); - - db_append_string(&sql, ")"); - G_debug(3, db_get_string(&sql)); - - if (db_execute_immediate(driver, &sql) != DB_OK) { - db_close_database(driver); - db_shutdown_driver(driver); - G_fatal_error("Cannot insert new row: %s", db_get_string(&sql)); - } - - cat++; - return 0; -} - -/* Returns 1 if element has geometry and may be written to vector */ -int is_low_level(PAD_ENT_HDR adenhd) -{ - if (adenhd->enttype == AD_ENT_BLOCK || adenhd->enttype == AD_ENT_ENDBLK || - adenhd->enttype == AD_ENT_SEQEND || adenhd->enttype == AD_ENT_INSERT) { - return 0; - } - return 1; -} - -void wrentity(PAD_ENT_HDR adenhd, PAD_ENT aden, int level, AD_VMADDR entlist, - int circle_as_point) -{ - short ret; - PAD_BLOB_CTRL bcptr; - PAD_ENT_HDR adenhd2; - PAD_ENT aden2; - OdaLong il; - double tempdouble[3], tempbulge, tempwidth[3]; - double x, y, z, ang; - PAD_BLKH adblkh; - int layer_found = 1; - - if (is_low_level(adenhd)) - n_elements++; - - /* Check layer name */ - if (layers_opt->answers) { - int i = 0; - - adSeekLayer(dwghandle, adenhd->entlayerobjhandle, Layer); - - layer_found = 0; - if (!Layer->purgedflag) { - while (layers_opt->answers[i]) { - if (strcmp(Layer->name, layers_opt->answers[i]) == 0) { - layer_found = 1; - break; - } - i++; - } - } - - if ((!invert_flag->answer && !layer_found) || - (invert_flag->answer && layer_found)) { - if (is_low_level(adenhd)) - n_skipped++; - if (adenhd->enttype != AD_ENT_INSERT && - adenhd->enttype != AD_ENT_POLYLINE) - return; - } - } - - getEntTypeName(adenhd, buf); - G_debug(1, "Entity: %s", buf); - - Txt = NULL; - adenhd2 = (PAD_ENT_HDR)G_malloc(sizeof(AD_ENT_HDR)); - aden2 = (PAD_ENT)G_malloc(sizeof(AD_ENT)); - adblkh = (PAD_BLKH)G_malloc(sizeof(AD_BLKH)); - Vect_reset_line(Points); - - /* Check space for lower level */ - if (level + 1 == atrans) { - atrans += 10; - Trans = (TRANS *)G_realloc(Trans, atrans * sizeof(TRANS)); - } - - switch (adenhd->enttype) { - case AD_ENT_LINE: - Vect_append_point(Points, aden->line.pt0[0], aden->line.pt0[1], - aden->line.pt0[2]); - Vect_append_point(Points, aden->line.pt1[0], aden->line.pt1[1], - aden->line.pt1[2]); - write_line(adenhd, GV_LINE, level); - break; - - case AD_ENT_FACE3D: - Vect_append_point(Points, aden->face3d.pt0[0], aden->face3d.pt0[1], - aden->face3d.pt0[2]); - Vect_append_point(Points, aden->face3d.pt1[0], aden->face3d.pt1[1], - aden->face3d.pt1[2]); - Vect_append_point(Points, aden->face3d.pt2[0], aden->face3d.pt2[1], - aden->face3d.pt2[2]); - Vect_append_point(Points, aden->face3d.pt3[0], aden->face3d.pt3[1], - aden->face3d.pt3[2]); - write_line(adenhd, GV_FACE, level); - break; - - case AD_ENT_SOLID: - Vect_append_point(Points, aden->solid.pt0[0], aden->solid.pt0[1], - aden->solid.pt0[2]); - Vect_append_point(Points, aden->solid.pt1[0], aden->solid.pt1[1], - aden->solid.pt1[2]); - Vect_append_point(Points, aden->solid.pt2[0], aden->solid.pt2[1], - aden->solid.pt2[2]); - Vect_append_point(Points, aden->solid.pt3[0], aden->solid.pt3[1], - aden->solid.pt3[2]); - write_line(adenhd, GV_FACE, level); - break; - - case AD_ENT_TEXT: - Txt = aden->text.textstr; - Vect_append_point(Points, aden->text.pt0[0], aden->text.pt0[1], - aden->line.pt0[2]); - write_line(adenhd, GV_POINT, level); - break; - - case AD_ENT_POINT: - Vect_append_point(Points, aden->point.pt0[0], aden->point.pt0[1], - aden->line.pt0[2]); - write_line(adenhd, GV_POINT, level); - break; - - case AD_ENT_ARC: - for (ang = aden->arc.stang; ang < aden->arc.endang; - ang += 2 * LOCPI / 360) { - x = aden->arc.pt0[0] + aden->arc.radius * cos(ang); - y = aden->arc.pt0[1] + aden->arc.radius * sin(ang); - z = aden->arc.pt0[2]; - Vect_append_point(Points, x, y, z); - } - x = aden->arc.pt0[0] + aden->arc.radius * cos(aden->arc.endang); - y = aden->arc.pt0[1] + aden->arc.radius * sin(aden->arc.endang); - z = aden->arc.pt0[2]; - Vect_append_point(Points, x, y, z); - write_line(adenhd, GV_LINE, level); - break; - - case AD_ENT_CIRCLE: - if (circle_as_point) { - Vect_append_point(Points, aden->circle.pt0[0], aden->circle.pt0[1], - aden->circle.pt0[3]); - write_line(adenhd, GV_POINT, level); - } - else { - for (ang = 0; ang < 2 * LOCPI; ang += 2 * LOCPI / 360) { - x = aden->circle.pt0[0] + aden->circle.radius * cos(ang); - y = aden->circle.pt0[1] + aden->circle.radius * sin(ang); - z = aden->circle.pt0[3]; - Vect_append_point(Points, x, y, z); - } - Vect_append_point(Points, Points->x[0], Points->y[0], Points->z[0]); - write_line(adenhd, GV_LINE, level); - } - break; - - /* BLOCK starts block of entities but makes no transformation - is it - * right ? - * -> do nothing just warn for xref */ - case AD_ENT_BLOCK: - if (aden->block.xrefpath[0]) { - G_warning("External reference for block not supported.\n xref: %s", - aden->block.xrefpath); - } - Block = G_store(aden->block.name2); - break; - - case AD_ENT_ENDBLK: /* endblk - no data */ - G_free(Block); - Block = NULL; - break; - - case AD_ENT_INSERT: /* insert */ - /* get transformation */ - /* TODO: fix rotation for CIRCLE and ARC */ - G_debug(3, " x,y,z: %f, %f, %f", aden->insert.pt0[0], - aden->insert.pt0[1], aden->insert.pt0[2]); - G_debug(3, " xscale, yscale, zscale: %f, %f, %f", aden->insert.xscale, - aden->insert.yscale, aden->insert.zscale); - G_debug(3, " rotang: %f", aden->insert.rotang); - G_debug(3, " ncols, nrows: %d, %d", aden->insert.numcols, - aden->insert.numrows); - G_debug(3, " coldist, rowdist: %f, %f", aden->insert.coldist, - aden->insert.rowdist); - - /* write block entities */ - adSeekBlockheader(dwghandle, aden->insert.blockheaderobjhandle, adblkh); - if (!adblkh->purgedflag) { - adStartEntityGet(adblkh->entitylist); - while (1) { - ret = adGetEntity(adblkh->entitylist, adenhd2, aden2); - if (adenhd2->enttype == AD_ENT_ENDBLK) - break; - if (ret) { - /* Set transformation for lower level */ - Trans[level + 1].dx = aden->insert.pt0[0]; - Trans[level + 1].dy = aden->insert.pt0[1]; - Trans[level + 1].dz = aden->insert.pt0[2]; - Trans[level + 1].xscale = aden->insert.xscale; - Trans[level + 1].yscale = aden->insert.yscale; - Trans[level + 1].zscale = aden->insert.zscale; - Trans[level + 1].rotang = aden->insert.rotang; - wrentity(adenhd2, aden2, level + 1, adblkh->entitylist, - circle_as_point); - } - } - } - break; - - case AD_ENT_SEQEND: /* seqend */ - break; - - case AD_ENT_POLYLINE: - while (1) { - ret = adGetEntity(entlist, adenhd2, aden2); - if (ret != 1) { - G_warning("Cannot get entity: %d: %s.", adError(), - adErrorStr(adError())); - break; - } - - if (adenhd2->enttype == AD_ENT_SEQEND) - break; - if (adenhd2->enttype != AD_ENT_VERTEX) { - getEntTypeName(adenhd2, buf); - G_warning("Expected VERTEX got %s in POLYLINE -> skip", buf); - } - else { - Vect_append_point(Points, aden2->vertex.pt0[0], - aden2->vertex.pt0[1], aden2->vertex.pt0[2]); - } - }; - if ((!invert_flag->answer && layer_found) || - (invert_flag->answer && !layer_found)) - write_line(adenhd, GV_LINE, level); - break; - - default: - if (adenhd->enttype == adLwplineEnttype(dwghandle)) { - G_debug(3, "Npoints: %ld\n", aden->lwpline.numpoints); - bcptr = adStartBlobRead(aden->lwpline.ldblob); - for (il = 0; il < aden->lwpline.numpoints; il++) { - adReadBlob2Double(bcptr, tempdouble); - Vect_append_point(Points, tempdouble[0], tempdouble[1], - tempdouble[2]); - tempbulge = tempwidth[0] = tempwidth[1] = tempwidth[2] = 0.0; - if (aden->lwpline.flag & AD_LWPLINE_HAS_BULGES) { - adReadBlobDouble(bcptr, &tempbulge); - } - if (aden->lwpline.flag & AD_LWPLINE_HAS_WIDTHS) { - adReadBlob2Double(bcptr, tempwidth); - } - } - G_debug(3, "flag = %d", aden->lwpline.flag); - if (aden->lwpline.flag & AD_LWPLINE_IS_CLOSED) { - G_debug(3, " -> is closed"); - Vect_append_point(Points, Points->x[0], Points->y[0], - Points->z[0]); - } - write_line(adenhd, GV_LINE, level); - adEndBlobRead(bcptr); - } - else { - getEntTypeName(adenhd, buf); - G_warning("%s entity not supported", buf); - } - break; - - } /* end of switch */ - - G_free(aden2); - G_free(adenhd2); -} diff --git a/vector/v.in.dwg/global.h b/vector/v.in.dwg/global.h deleted file mode 100644 index 39e46f17856..00000000000 --- a/vector/v.in.dwg/global.h +++ /dev/null @@ -1,59 +0,0 @@ -/* ************************************************************** - * - * MODULE: v.in.dwg - * - * AUTHOR(S): Radim Blazek - * - * PURPOSE: Import of DWG/DXF files - * - * COPYRIGHT: (C) 2001 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. - * - * In addition, as a special exception, Radim Blazek gives permission - * to link the code of this program with the OpenDWG libraries (or with - * modified versions of the OpenDWG libraries that use the same license - * as OpenDWG libraries), and distribute linked combinations including the two. - * You must obey the GNU General Public License in all respects for all - * of the code used other than. If you modify this file, you may extend - * this exception to your version of the file, but you are not obligated - * to do so. If you do not wish to do so, delete this exception statement - * from your version. - * - * **************************************************************/ - -/* transformation, first level is 0 ( called from main ) and transformation - * for this level is 0,0,0, 1,1,1, 0 so that no transformation is done on first - * level (not effective but better readable?) */ -typedef struct { - double dx, dy, dz; - double xscale, yscale, zscale; - double rotang; -} TRANS; - -extern int cat; -extern int - n_elements; /* number of processed elements (only low level elements) */ -extern int - n_skipped; /* number of skipped low level elements (different layer name) */ -extern struct Map_info Map; -extern dbDriver *driver; -extern dbString sql; -extern dbString str; -extern struct line_pnts *Points; -extern struct line_cats *Cats; -extern PAD_LAY Layer; -extern char *Txt; -extern char *Block; -extern struct field_info *Fi; -extern AD_DB_HANDLE dwghandle; -extern TRANS *Trans; /* transformation */ -extern int atrans; /* number of allocated levels */ -extern struct Option *layers_opt; -extern struct Flag *invert_flag; - -void wrentity(PAD_ENT_HDR adenhd, PAD_ENT aden, int level, AD_VMADDR entlist, - int circle_as_point); diff --git a/vector/v.in.dwg/main.c b/vector/v.in.dwg/main.c deleted file mode 100644 index cc7b9a217b1..00000000000 --- a/vector/v.in.dwg/main.c +++ /dev/null @@ -1,295 +0,0 @@ -/* ************************************************************** - * - * MODULE: v.in.dwg - * - * AUTHOR(S): Radim Blazek - * - * PURPOSE: Import of DWG/DXF files - * - * COPYRIGHT: (C) 2001-2008 by the GRASS Development Team - * - * This program is free software under the - * GNU General Public License (>=v2). - * Read the file COPYING that comes with GRASS - * for details. - * - * In addition, as a special exception, Radim Blazek gives permission - * to link the code of this program with the OpenDWG libraries (or with - * modified versions of the OpenDWG libraries that use the same license - * as OpenDWG libraries), and distribute linked combinations including the two. - * You must obey the GNU General Public License in all respects for all - * of the code used other than. If you modify this file, you may extend - * this exception to your version of the file, but you are not obligated - * to do so. If you do not wish to do so, delete this exception statement - * from your version. - * - * **************************************************************/ -#define AD_PROTOTYPES -#define AD_VM_PC -#define OD_GENERIC_READ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ad2.h" -#include "io/odio.h" -#include "global.h" - -int cat; -int n_elements; /* number of processed elements (only low level elements) */ -int n_skipped; /* number of skipped low level elements (different layer name) */ -struct Map_info Map; -dbDriver *driver; -dbString sql; -dbString str; -struct line_pnts *Points; -struct line_cats *Cats; -PAD_LAY Layer; -char *Txt; -char *Block; -struct field_info *Fi; -AD_DB_HANDLE dwghandle; -TRANS *Trans; /* transformation */ -int atrans; /* number of allocated levels */ -struct Option *layers_opt; -struct Flag *invert_flag; - -int main(int argc, char *argv[]) -{ - struct GModule *module; - struct Option *out_opt, *in_opt; - struct Flag *z_flag, *circle_flag, *l_flag, *int_flag; - const size_t BUFSIZE = 2000; - char buf[BUFSIZE]; - - /* DWG */ - char path[2000]; - short initerror, entset, retval; - AD_OBJHANDLE pspace, mspace; - PAD_ENT_HDR adenhd; - PAD_ENT aden; - AD_VMADDR entlist; - - G_gisinit(argv[0]); - - module = G_define_module(); - G_add_keyword(_("vector")); - G_add_keyword(_("import")); - module->description = _("Converts DWG/DXF to GRASS vector map"); - - in_opt = G_define_standard_option(G_OPT_F_INPUT); - in_opt->description = _("Name of DWG or DXF file"); - - out_opt = G_define_standard_option(G_OPT_V_OUTPUT); - out_opt->required = YES; - - layers_opt = G_define_option(); - layers_opt->key = "layers"; - layers_opt->type = TYPE_STRING; - layers_opt->required = NO; - layers_opt->multiple = YES; - layers_opt->description = _("List of layers to import"); - - invert_flag = G_define_flag(); - invert_flag->key = 'i'; - invert_flag->description = - _("Invert selection by layers (don't import layers in list)"); - - z_flag = G_define_flag(); - z_flag->key = 'z'; - z_flag->description = _("Create 3D vector map"); - - circle_flag = G_define_flag(); - circle_flag->key = 'c'; - circle_flag->description = _("Write circles as points (centre)"); - - l_flag = G_define_flag(); - l_flag->key = 'l'; - l_flag->description = _("List available layers and exit"); - - int_flag = G_define_flag(); - int_flag->key = 'n'; - int_flag->description = _("Use numeric type for attribute \"layer\""); - - if (G_parser(argc, argv)) - exit(EXIT_FAILURE); - - db_init_string(&sql); - db_init_string(&str); - adenhd = (PAD_ENT_HDR)G_malloc(sizeof(AD_ENT_HDR)); - aden = (PAD_ENT)G_malloc(sizeof(AD_ENT)); - Layer = (PAD_LAY)G_malloc(sizeof(AD_LAY)); - Points = Vect_new_line_struct(); - Cats = Vect_new_cats_struct(); - Block = NULL; - - atrans = 20; /* nested, recursive levels */ - Trans = (TRANS *)G_malloc(atrans * sizeof(TRANS)); - - /* Init OpenDWG */ - sprintf(path, "%s/etc/adinit.dat", G_gisbase()); - if (!adInitAd2(path, &initerror)) { - snprintf(buf, BUFSIZE, - _("Unable to initialize OpenDWG Toolkit, error: %d: %s."), - initerror, adErrorStr(initerror)); - size_t buflen = strlen(buf); - if (initerror == AD_UNABLE_TO_OPEN_INIT_FILE) - snprintf(buf + buflen, BUFSIZE - buflen, _(" Cannot open %s"), - path); - G_fatal_error(buf); - } - adSetupDwgRead(); - adSetupDxfRead(); - - /* Open input file */ - if ((dwghandle = adLoadFile(in_opt->answer, AD_PRELOAD_ALL, 1)) == NULL) { - G_fatal_error(_("Unable to open input file <%s>. Error %d: %s"), - in_opt->answer, adError(), adErrorStr(adError())); - } - - if (l_flag->answer) { /* List layers */ - PAD_TB adtb; - AD_DWGHDR adhd; - int i; - char on, frozen, vpfrozen, locked; - - adtb = (PAD_TB)G_malloc(sizeof(AD_TB)); - - G_debug(2, "%d layers", (int)adNumLayers(dwghandle)); - adReadHeaderBlock(dwghandle, &adhd); - adStartLayerGet(dwghandle); - - fprintf(stdout, "%d layers:\n", (int)adNumLayers(dwghandle)); - for (i = 0; i < (int)adNumLayers(dwghandle); i++) { - adGetLayer(dwghandle, &(adtb->lay)); - if (!adtb->lay.purgedflag) { - fprintf(stdout, "%s COLOR %d, ", adtb->lay.name, - adtb->lay.color); - } - adGetLayerState(dwghandle, adtb->lay.objhandle, &on, &frozen, - &vpfrozen, &locked); - if (on) - fprintf(stdout, "ON, "); - else - fprintf(stdout, "OFF, "); - if (frozen) - fprintf(stdout, "FROZEN, "); - else - fprintf(stdout, "THAWED, "); - if (vpfrozen) - fprintf(stdout, "VPFROZEN, "); - else - fprintf(stdout, "VPTHAWED, "); - if (locked) - fprintf(stdout, "LOCKED\n"); - else - fprintf(stdout, "UNLOCKED\n"); - } - adCloseFile(dwghandle); - adCloseAd2(); - exit(EXIT_SUCCESS); - } - - /* open output vector */ - if (Vect_open_new(&Map, out_opt->answer, z_flag->answer) < 0) - G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer); - - Vect_hist_command(&Map); - - /* Add DB link */ - Fi = Vect_default_field_info(&Map, 1, NULL, GV_1TABLE); - Vect_map_add_dblink(&Map, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database, - Fi->driver); - - driver = db_start_driver_open_database(Fi->driver, - Vect_subst_var(Fi->database, &Map)); - if (driver == NULL) { - G_fatal_error(_("Unable to open database <%s> by driver <%s>"), - Vect_subst_var(Fi->database, &Map), Fi->driver); - } - db_set_error_handler_driver(driver); - - db_begin_transaction(driver); - - /* Create table */ - if (int_flag->answer) { /* List layers */ - sprintf(buf, - "create table %s ( cat integer, entity_name varchar(20), color " - "int, weight int, " - "layer real, block varchar(100), txt varchar(100) )", - Fi->table); - } - else { - sprintf(buf, - "create table %s ( cat integer, entity_name varchar(20), color " - "int, weight int, " - "layer varchar(100), block varchar(100), txt varchar(100) )", - Fi->table); - } - db_set_string(&sql, buf); - G_debug(3, db_get_string(&sql)); - - if (db_execute_immediate(driver, &sql) != DB_OK) { - db_close_database(driver); - db_shutdown_driver(driver); - G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&sql)); - } - - if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK) - G_warning(_("Unable to create index for table <%s>, key <%s>"), - Fi->table, GV_KEY_COLUMN); - - if (db_grant_on_table(driver, Fi->table, DB_PRIV_SELECT, - DB_GROUP | DB_PUBLIC) != DB_OK) - G_fatal_error(_("Unable to grant privileges on table <%s>"), Fi->table); - - cat = 1; - n_elements = n_skipped = 0; - /* Write each entity. Some entities may be composed by other entities (like - * INSERT or BLOCK) */ - /* Set transformation for first (index 0) level */ - Trans[0].dx = Trans[0].dy = Trans[0].dz = 0; - Trans[0].xscale = Trans[0].yscale = Trans[0].zscale = 1; - Trans[0].rotang = 0; - if (adGetBlockHandle(dwghandle, pspace, AD_PAPERSPACE_HANDLE)) { - entlist = adEntityList(dwghandle, pspace); - adStartEntityGet(entlist); - for (entset = 0; entset < 2; entset++) { - do { - if (!(retval = adGetEntity(entlist, adenhd, aden))) - continue; - wrentity(adenhd, aden, 0, entlist, circle_flag->answer); - } while (retval == 1); - if (entset == 0) { - if (adGetBlockHandle(dwghandle, mspace, AD_MODELSPACE_HANDLE)) { - entlist = adEntityList(dwghandle, mspace); - adStartEntityGet(entlist); - } - } - } - } - - db_commit_transaction(driver); - db_close_database_shutdown_driver(driver); - - adCloseFile(dwghandle); - adCloseAd2(); - - Vect_build(&Map, stderr); - Vect_close(&Map); - - if (n_skipped > 0) - G_message(_("%d elements skipped (layer name was not in list)"), - n_skipped); - - G_done_msg(_("%d elements processed"), n_elements); - - exit(EXIT_SUCCESS); -} diff --git a/vector/v.in.dwg/v.in.dwg.html b/vector/v.in.dwg/v.in.dwg.html deleted file mode 100644 index 60f00966f9d..00000000000 --- a/vector/v.in.dwg/v.in.dwg.html +++ /dev/null @@ -1,32 +0,0 @@ -

    DESCRIPTION

    - -v.in.dwg imports DWG/DXF file into GRASS. - -

    EXAMPLE

    - -
    -v.in.dwg input=map.dwg output=map
    -
    - -

    NOTES

    - -v.in.dwg requires OpenDWG toolkit. To get this toolkit you must become at -least "Associate Member" of OpenDWG Alliance (http://www.opendesign.com/). -

    The toolkit, for example ad27linx.tar, unpack in a directory -(e.g. /home/usr1/opendwg27) and use the related configure options -to tell GRASS about it: - -

    -   ./configure \
    -   ... \
    -   --with-opendwg \
    -   --with-opendwg-includes=/home/usr1/opendwg27 \
    -   --with-opendwg-libs=/home/usr1/opendwg27
    -
    - -Then you can compile this module. -

    Not all entity types are supported (warning printed). - -

    AUTHOR

    - -Radim Blazek, ITC-Irst, Trento, Italy From a536bd49c55cc11d0a765c6e58c1829f2e679379 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Thu, 19 Sep 2024 02:21:55 -0400 Subject: [PATCH 060/209] d.mon: Fix unbounded source buffer (#4260) --- display/d.mon/list.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/display/d.mon/list.c b/display/d.mon/list.c index ab346302a61..c61c1081991 100644 --- a/display/d.mon/list.c +++ b/display/d.mon/list.c @@ -14,11 +14,13 @@ char *get_path(const char *name, int fpath) char tmpdir[GPATH_MAX]; G_temp_element(tmpdir); - strcat(tmpdir, "/"); - strcat(tmpdir, "MONITORS"); + (void)G_strlcat(tmpdir, "/", sizeof(tmpdir)); + (void)G_strlcat(tmpdir, "MONITORS", sizeof(tmpdir)); if (name) { - strcat(tmpdir, "/"); - strcat(tmpdir, name); + (void)G_strlcat(tmpdir, "/", sizeof(tmpdir)); + if (G_strlcat(tmpdir, name, sizeof(tmpdir)) >= sizeof(tmpdir)) { + G_fatal_error(_("Failed to append <%s> to path"), name); + } } if (fpath) { @@ -132,10 +134,13 @@ void list_files(const char *name, FILE *fd_out) DIR *dirp; G_temp_element(tmpdir); - strcat(tmpdir, "/"); - strcat(tmpdir, "MONITORS"); - strcat(tmpdir, "/"); - strcat(tmpdir, name); + (void)G_strlcat(tmpdir, "/", sizeof(tmpdir)); + (void)G_strlcat(tmpdir, "MONITORS", sizeof(tmpdir)); + (void)G_strlcat(tmpdir, "/", sizeof(tmpdir)); + + if (G_strlcat(tmpdir, name, sizeof(tmpdir)) >= sizeof(tmpdir)) { + G_fatal_error(_("Failed to append <%s> to path"), name); + } G_file_name(mon_path, tmpdir, NULL, G_mapset()); fprintf(fd_out, "path=%s\n", mon_path); From d5bb442d7b121861928a37842e05e5265a980427 Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Thu, 19 Sep 2024 09:03:26 +0200 Subject: [PATCH 061/209] lib/gmath: use C interface to BLAS and LAPACK libraries (#4247) Replace outdated direct use of Fortran libraries via g2c.h, f2c.h or private prototypes, with the C interface API and libraries CBLAS and LAPACKE. This simplifies our own code and makes it easier to maintain and expand. Configure is simplified to use pkg-config to retrieve INC and LIB info. `--with-blas` defaults to `--with-blas=cblas` where "cblas" is the pkg-config package name; `---with-lapack` defaults to `--with-lapack=lapacke`. If the default fails the test a list of package names are tested: - BLAS package names tested: cblas blas-netlib openblas blas-atlas - LAPACKE package name tested: lapacke openblas - CI(Linux): replace libopenblas-dev with liblapacke-dev dependency - CI(macOS): replace blas and lapack with openblas dependency - CI(Windows): replace lapack with openblas dependency --- .github/workflows/apt.txt | 2 +- .github/workflows/macos_dependencies.txt | 3 +- .github/workflows/macos_install.sh | 8 +- .github/workflows/osgeo4w.yml | 2 +- configure | 992 +---- configure.ac | 245 +- include/grass/blas.h | 412 -- include/grass/config.h.in | 16 +- include/grass/la.h | 116 +- include/grass/lapack.h | 4748 ---------------------- lib/gmath/ATLAS_wrapper_blas_level_1.c | 90 +- lib/gmath/Makefile | 2 +- lib/gmath/la.c | 139 +- mswindows/osgeo4w/build_osgeo4w.sh | 2 +- 14 files changed, 416 insertions(+), 6361 deletions(-) delete mode 100644 include/grass/blas.h delete mode 100644 include/grass/lapack.h diff --git a/.github/workflows/apt.txt b/.github/workflows/apt.txt index a5a221c939c..4c14cb7b067 100644 --- a/.github/workflows/apt.txt +++ b/.github/workflows/apt.txt @@ -7,8 +7,8 @@ libfftw3-dev libgdal-dev libgl1-mesa-dev libglu1-mesa-dev +liblapacke-dev libnetcdf-dev -libopenblas-dev libpdal-dev libpng-dev libproj-dev diff --git a/.github/workflows/macos_dependencies.txt b/.github/workflows/macos_dependencies.txt index bc60609f7b5..8ef1d3460f6 100644 --- a/.github/workflows/macos_dependencies.txt +++ b/.github/workflows/macos_dependencies.txt @@ -1,4 +1,3 @@ -blas cairo clangxx_osx-arm64 clang_osx-arm64 @@ -13,7 +12,6 @@ giflib git ipython krb5 -lapack lastools libgdal-arrow-parquet libgdal-core @@ -32,6 +30,7 @@ libtiff llvm-openmp matplotlib numpy<2 +openblas pandoc pdal pillow diff --git a/.github/workflows/macos_install.sh b/.github/workflows/macos_install.sh index 79446f51867..8a94bc15c6a 100755 --- a/.github/workflows/macos_install.sh +++ b/.github/workflows/macos_install.sh @@ -47,12 +47,8 @@ CONFIGURE_FLAGS="\ --with-bzlib-libs=${CONDA_PREFIX}/lib \ --with-bzlib-includes=${CONDA_PREFIX}/include \ --with-netcdf=${CONDA_PREFIX}/bin/nc-config \ - --with-blas \ - --with-blas-libs=${CONDA_PREFIX}/lib \ - --with-blas-includes=${CONDA_PREFIX}/include \ - --with-lapack - --with-lapack-includes=${CONDA_PREFIX}/include \ - --with-lapack-libs=${CONDA_PREFIX}/lib \ + --with-blas=openblas \ + --with-lapack=openblas \ --with-netcdf=${CONDA_PREFIX}/bin/nc-config \ --with-nls \ --with-libs=${CONDA_PREFIX}/lib \ diff --git a/.github/workflows/osgeo4w.yml b/.github/workflows/osgeo4w.yml index 2b92c254238..10acd64dc37 100644 --- a/.github/workflows/osgeo4w.yml +++ b/.github/workflows/osgeo4w.yml @@ -39,7 +39,7 @@ jobs: update: true msystem: MINGW64 install: tar libintl make bison flex diffutils git dos2unix zip mingw-w64-x86_64-toolchain - mingw-w64-x86_64-fftw mingw-w64-x86_64-lapack mingw-w64-x86_64-pkgconf + mingw-w64-x86_64-fftw mingw-w64-x86_64-openblas mingw-w64-x86_64-pkgconf mingw-w64-x86_64-gcc mingw-w64-x86_64-ccache mingw-w64-x86_64-zlib mingw-w64-x86_64-libiconv mingw-w64-x86_64-bzip2 mingw-w64-x86_64-gettext mingw-w64-x86_64-libsystre mingw-w64-x86_64-libtre-git mingw-w64-x86_64-libwinpthread-git mingw-w64-x86_64-libpng diff --git a/configure b/configure index 4b9a63f7947..17182bc4b7a 100755 --- a/configure +++ b/configure @@ -901,8 +901,6 @@ with_sqlite with_opengl with_odbc with_fftw -with_blas -with_lapack with_libsvm with_cairo with_freetype @@ -915,6 +913,8 @@ with_opencl with_bzlib with_zstd with_pdal +with_blas +with_lapack with_libpng with_gdal with_liblas @@ -945,10 +945,6 @@ with_odbc_includes with_odbc_libs with_fftw_includes with_fftw_libs -with_blas_includes -with_blas_libs -with_lapack_includes -with_lapack_libs with_libsvm_includes with_libsvm_libs with_cairo_includes @@ -1633,8 +1629,6 @@ Optional Packages: --with-opengl support OpenGL functionality (default: yes) --with-odbc support ODBC functionality (default: no) --with-fftw support FFTW functionality (default: yes) - --with-blas support BLAS functionality (default: no) - --with-lapack support LAPACK functionality (default: no) --with-libsvm support LIBSVM functionality (default: no) --with-cairo support Cairo functionality (default: yes) --with-freetype support FreeType functionality (default: yes) @@ -1647,6 +1641,14 @@ Optional Packages: --with-bzlib support BZIP2 functionality (default: no) --with-zstd support Zstandard functionality (default: yes) --with-pdal support PDAL functionality (default: yes) + --with-blas=pkg-config-package + enable BLAS support with by adding name of + pkg-config package name for CBLAS library, e.g. + '--with-lapack-package=openblas', default: cblas + --with-lapack=pkg-config-package + enable LAPACK support with by adding name of + pkg-config package name for LAPACKE library, e.g. + '--with-lapack-package=openblas', default: lapacke --with-libpng=path/libpng-config enable PNG support (libpng-config with path, e.g. '--with-libpng=/usr/local/bin/libpng-config') @@ -1704,12 +1706,6 @@ Optional Packages: --with-fftw-includes=DIRS FFTW include files are in DIRS --with-fftw-libs=DIRS FFTW library files are in DIRS - --with-blas-includes=DIRS - BLAS include files are in DIRS - --with-blas-libs=DIRS BLAS library files are in DIRS - --with-lapack-includes=DIRS - LAPACK include files are in DIRS - --with-lapack-libs=DIRS LAPACK library files are in DIRS --with-libsvm-includes=DIRS LIBSVM include files are in DIRS --with-libsvm-libs=DIRS LIBSVM library files are in DIRS @@ -5477,28 +5473,6 @@ fi -# Check whether --with-blas was given. -if test ${with_blas+y} -then : - withval=$with_blas; -else $as_nop - with_blas=no -fi - - - - -# Check whether --with-lapack was given. -if test ${with_lapack+y} -then : - withval=$with_lapack; -else $as_nop - with_lapack=no -fi - - - - # Check whether --with-libsvm was given. if test ${with_libsvm+y} then : @@ -5631,6 +5605,27 @@ fi + +# Check whether --with-blas was given. +if test ${with_blas+y} +then : + withval=$with_blas; +else $as_nop + with-blas="no" +fi + + + +# Check whether --with-lapack was given. +if test ${with_lapack+y} +then : + withval=$with_lapack; +else $as_nop + with-lapack="no" +fi + + + # Check whether --with-libpng was given. if test ${with_libpng+y} then : @@ -5914,44 +5909,6 @@ fi -# Check whether --with-blas-includes was given. -if test ${with_blas_includes+y} -then : - withval=$with_blas_includes; -fi - - - - -# Check whether --with-blas-libs was given. -if test ${with_blas_libs+y} -then : - withval=$with_blas_libs; -fi - - - - - -# Check whether --with-lapack-includes was given. -if test ${with_lapack_includes+y} -then : - withval=$with_lapack_includes; -fi - - - - -# Check whether --with-lapack-libs was given. -if test ${with_lapack_libs+y} -then : - withval=$with_lapack_libs; -fi - - - - - # Check whether --with-libsvm-includes was given. if test ${with_libsvm_includes+y} then : @@ -6899,18 +6856,6 @@ if test "x$ac_cv_header_values_h" = xyes then : printf "%s\n" "#define HAVE_VALUES_H 1" >>confdefs.h -fi -ac_fn_c_check_header_compile "$LINENO" "f2c.h" "ac_cv_header_f2c_h" "$ac_includes_default" -if test "x$ac_cv_header_f2c_h" = xyes -then : - printf "%s\n" "#define HAVE_F2C_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "g2c.h" "ac_cv_header_g2c_h" "$ac_includes_default" -if test "x$ac_cv_header_g2c_h" = xyes -then : - printf "%s\n" "#define HAVE_G2C_H 1" >>confdefs.h - fi ac_fn_c_check_header_compile "$LINENO" "sys/ioctl.h" "ac_cv_header_sys_ioctl_h" "$ac_includes_default" @@ -13759,827 +13704,214 @@ fi # $USE_FFTW # Enable BLAS option - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use BLAS" >&5 -printf %s "checking whether to use BLAS... " >&6; } -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$with_blas\"" >&5 -printf "%s\n" "\"$with_blas\"" >&6; } -case "$with_blas" in - "no") USE_BLAS= ;; - "yes") USE_BLAS="1" ;; - *) as_fn_error $? "*** You must answer yes or no." "$LINENO" 5 ;; -esac - - +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use (C)BLAS" >&5 +printf %s "checking whether to use (C)BLAS... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_blas" >&5 +printf "%s\n" "$with_blas" >&6; } BLASLIB= BLASINC= +USE_BLAS= +BLAS_PKGS="cblas blas-netlib openblas blas-atlas" +BLAS_PKG= -if test -n "$USE_BLAS"; then - -# With BLAS includes directory -# BLAS doesn't have includes (FORTRAN library) -# With BLAS library directory - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for location of BLAS includes" >&5 -printf %s "checking for location of BLAS includes... " >&6; } -case "$with_blas_includes" in -y | ye | yes | n | no) - as_fn_error $? "*** You must supply a directory to --with-blas-includes." "$LINENO" 5 - ;; +case "$with_blas" in + no) + ;; + yes) + USE_BLAS="$with_blas" + ;; + *) + USE_BLAS=yes + BLAS_PKGS="$with_blas" + ;; esac -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_blas_includes" >&5 -printf "%s\n" "$with_blas_includes" >&6; } -if test -n "$with_blas_includes" ; then - for dir in $with_blas_includes; do - if test -d "$dir"; then - BLASINC="$BLASINC -I$dir" - else - as_fn_error $? "*** BLAS includes directory $dir does not exist." "$LINENO" 5 - fi - done -fi +if test -n "$USE_BLAS"; then + blas_ok=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for location of BLAS library" >&5 -printf %s "checking for location of BLAS library... " >&6; } -case "$with_blas_libs" in -y | ye | yes | n | no) - as_fn_error $? "*** You must supply a directory to --with-blas-libs." "$LINENO" 5 - ;; -esac -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_blas_libs" >&5 -printf "%s\n" "$with_blas_libs" >&6; } + for blas_chk in ${BLAS_PKGS} + do + if ! ${PKG_CONFIG} --exists ${blas_chk} ; then + continue + else + BLAS_PKG=${blas_chk} + break + fi + done -if test -n "$with_blas_libs"; then - for dir in $with_blas_libs; do - if test -d "$dir"; then - BLASLIB="$BLASLIB -L$dir" - else - as_fn_error $? "*** BLAS library directory $dir does not exist." "$LINENO" 5 - fi - done -fi + if test -z "$BLAS_PKG" ; then + as_fn_error $? "*** Unable to locate (C)BLAS pkg-conf package(s) + \"${BLAS_PKGS}\". Perhaps you need to set PKG_CONFIG_PATH." "$LINENO" 5 + fi + BLASLIB=$(${PKG_CONFIG} --libs ${BLAS_PKG}) + BLASINC=$(${PKG_CONFIG} --cflags ${BLAS_PKG}) -# See if cblas.h exists (CBLAS,ATLAS,others) -save_CPPFLAGS="$CPPFLAGS" -CPPFLAGS="$BLASINC $CPPFLAGS" -ac_fn_c_check_header_compile "$LINENO" "cblas.h" "ac_cv_header_cblas_h" "$ac_includes_default" + save_CFLAGS="$CFLAGS"; CFLAGS="$BLASINC $CFLAGS" + save_LIBS="$LIBS"; LIBS="$BLASLIB" + + for ac_header in cblas.h +do : + ac_fn_c_check_header_compile "$LINENO" "cblas.h" "ac_cv_header_cblas_h" "$ac_includes_default" if test "x$ac_cv_header_cblas_h" = xyes then : printf "%s\n" "#define HAVE_CBLAS_H 1" >>confdefs.h -fi - -CPPFLAGS="$save_CPPFLAGS" - - -ac_save_ldflags="$LDFLAGS" -LDFLAGS="$BLASLIB $LDFLAGS" - - - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dnrm2_ in -lblas" >&5 -printf %s "checking for dnrm2_ in -lblas... " >&6; } - -ac_check_lib_save_LIBS=$LIBS -LIBS="-lblas $MATHLIB $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char dnrm2_ (); -int -main (void) -{ -return dnrm2_ (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_blas_dnrm2_=yes else $as_nop - ac_cv_lib_blas_dnrm2_=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_blas_dnrm2_" >&5 -printf "%s\n" "$ac_cv_lib_blas_dnrm2_" >&6; } -if test "x$ac_cv_lib_blas_dnrm2_" = xyes + for ac_header in cblas-atlas.h +do : + ac_fn_c_check_header_compile "$LINENO" "cblas-atlas.h" "ac_cv_header_cblas_atlas_h" "$ac_includes_default" +if test "x$ac_cv_header_cblas_atlas_h" = xyes then : - BLASLIB="$BLASLIB -lblas " + printf "%s\n" "#define HAVE_CBLAS_ATLAS_H 1" >>confdefs.h + else $as_nop + as_fn_error $? "*** Failed to find either \"cblas.h\" or \"cblas-atlas.h\" with \"$CFLAGS\"" "$LINENO" 5 +fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dnrm2_ in -lblas" >&5 -printf %s "checking for dnrm2_ in -lblas... " >&6; } +done +fi -ac_check_lib_save_LIBS=$LIBS -LIBS="-lblas $MATHLIB -lg2c $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ +done -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char dnrm2_ (); + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linking to (C)BLAS" >&5 +printf %s "checking for linking to (C)BLAS... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +char cblas_dgemm(); int main (void) { -return dnrm2_ (); +return cblas_dgemm(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : - ac_cv_lib_blas_dnrm2_=yes + blas_ok=yes else $as_nop - ac_cv_lib_blas_dnrm2_=no + + as_fn_error $? "*** Unable to link to (C)BLAS library with \"$LIBS\"." "$LINENO" 5 fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_blas_dnrm2_" >&5 -printf "%s\n" "$ac_cv_lib_blas_dnrm2_" >&6; } -if test "x$ac_cv_lib_blas_dnrm2_" = xyes -then : - BLASLIB="$BLASLIB -lblas -lg2c" -else $as_nop - -LDFLAGS=${ac_save_ldflags} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BLAS_PKG" >&5 +printf "%s\n" "$BLAS_PKG" >&6; } - as_fn_error $? "*** Unable to locate BLAS library." "$LINENO" 5 + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" -fi +printf "%s\n" "#define HAVE_LIBBLAS 1" >>confdefs.h +fi # $USE_BLAS -fi +# Done checking BLAS +# Enable LAPACK option +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use LAPACK(E)" >&5 +printf %s "checking whether to use LAPACK(E)... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_lapack" >&5 +printf "%s\n" "$with_lapack" >&6; } +LAPACKLIB= +LAPACKINC= +USE_LAPACK= +LAPACK_PKGS="lapacke openblas" +LAPACK_PKG= -LDFLAGS=${ac_save_ldflags} +case "$with_lapack" in + no) + ;; + yes) + USE_LAPACK="$with_lapack" + ;; + *) + USE_LAPACK=yes + LAPACK_PKG="$with_lapack" + ;; +esac +# LAPACK is useless without BLAS +if test -n "$USE_BLAS" && test -n "$USE_LAPACK"; then -blas_ok=no + lapack_ok=no -# Check for ATLAS -save_LDFLAGS="$LDFLAGS" -LDFLAGS="$BLASLIB $LDFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ATL_xerbla in -latlas" >&5 -printf %s "checking for ATL_xerbla in -latlas... " >&6; } + for lapack_chk in ${LAPACK_PKGS} + do + if ! ${PKG_CONFIG} --exists ${lapack_chk} ; then + continue + else + LAPACK_PKG=${lapack_chk} + break + fi + done -ac_check_lib_save_LIBS=$LIBS -LIBS="-latlas $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ + if test -z "$LAPACK_PKG" ; then + as_fn_error $? "*** Unable to locate LAPACK(E) pkg-conf package(s) + \"$LAPACK_PKGS\". Perhaps you need to set PKG_CONFIG_PATH." "$LINENO" 5 + fi -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char ATL_xerbla (); -int -main (void) -{ -return ATL_xerbla (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_atlas_ATL_xerbla=yes -else $as_nop - ac_cv_lib_atlas_ATL_xerbla=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_atlas_ATL_xerbla" >&5 -printf "%s\n" "$ac_cv_lib_atlas_ATL_xerbla" >&6; } -if test "x$ac_cv_lib_atlas_ATL_xerbla" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sgemm_ in -lf77blas" >&5 -printf %s "checking for sgemm_ in -lf77blas... " >&6; } + LAPACKLIB=`${PKG_CONFIG} --libs ${LAPACK_PKG}` + LAPACKINC=`${PKG_CONFIG} --cflags ${LAPACK_PKG}` -ac_check_lib_save_LIBS=$LIBS -LIBS="-lf77blas -latlas $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ + save_CFLAGS="$CFLAGS"; CFLAGS="$LAPACKINC $CFLAGS" + save_LIBS="$LIBS"; LIBS="$LAPACKLIB" -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char sgemm_ (); -int -main (void) -{ -return sgemm_ (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" + for ac_header in lapacke.h +do : + ac_fn_c_check_header_compile "$LINENO" "lapacke.h" "ac_cv_header_lapacke_h" "$ac_includes_default" +if test "x$ac_cv_header_lapacke_h" = xyes then : - ac_cv_lib_f77blas_sgemm_=yes + printf "%s\n" "#define HAVE_LAPACKE_H 1" >>confdefs.h + else $as_nop - ac_cv_lib_f77blas_sgemm_=no + as_fn_error $? "*** Unable to find \"lapacke.h\" with \"$CFLAGS\"." "$LINENO" 5 fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_f77blas_sgemm_" >&5 -printf "%s\n" "$ac_cv_lib_f77blas_sgemm_" >&6; } -if test "x$ac_cv_lib_f77blas_sgemm_" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cblas_dgemm in -lcblas" >&5 -printf %s "checking for cblas_dgemm in -lcblas... " >&6; } -ac_check_lib_save_LIBS=$LIBS -LIBS="-lcblas -lf77blas -latlas $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ +done -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char cblas_dgemm (); + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linking to LAPACK(E)" >&5 +printf %s "checking for linking to LAPACK(E)... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +char LAPACKE_dgesv(); int main (void) { -return cblas_dgemm (); +return LAPACKE_dgesv(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : - ac_cv_lib_cblas_cblas_dgemm=yes + lapack_ok=yes else $as_nop - ac_cv_lib_cblas_cblas_dgemm=no + + as_fn_error $? "*** Unable to link to LAPACK(E) library with \"$LIBS\"." "$LINENO" 5 fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cblas_cblas_dgemm" >&5 -printf "%s\n" "$ac_cv_lib_cblas_cblas_dgemm" >&6; } -if test "x$ac_cv_lib_cblas_cblas_dgemm" = xyes -then : - blas_ok=yes; BLASLIB="-lcblas -lf77blas -latlas" -fi - -fi - + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LAPACK_PKG" >&5 +printf "%s\n" "$LAPACK_PKG" >&6; } -fi - -LDFLAGS="$save_LDFLAGS" + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" -# Do we have ATLAS? -if test $blas_ok = yes; then -printf "%s\n" "#define HAVE_LIBATLAS 1" >>confdefs.h - -fi +printf "%s\n" "#define HAVE_LIBLAPACK 1" >>confdefs.h -# BLAS in Apple vecLib framework? (Mac OS-X) -# not dependent on APP build -#if test -n "$MACOSX_APP"; then -if test $blas_ok = no; then - vlib_flags="-framework vecLib" - save_LIBS="$LIBS" - LIBS="$vlib_flags $LIBS" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sgemm in $vlib_flags" >&5 -printf %s "checking for sgemm in $vlib_flags... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int -main (void) -{ -sgemm - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - blas_ok=yes; BLASLIB="$vlib_flags" -else $as_nop - BLASLIB="" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $blas_ok" >&5 -printf "%s\n" "$blas_ok" >&6; } - LIBS="$save_LIBS" -fi -#fi # $MACOSX_APP - -# BLAS in PhiPACK libraries? (requires generic BLAS, too) -if test $blas_ok = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sgemm_ in -lblas" >&5 -printf %s "checking for sgemm_ in -lblas... " >&6; } - -ac_check_lib_save_LIBS=$LIBS -LIBS="-lblas $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char sgemm_ (); -int -main (void) -{ -return sgemm_ (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_blas_sgemm_=yes -else $as_nop - ac_cv_lib_blas_sgemm_=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_blas_sgemm_" >&5 -printf "%s\n" "$ac_cv_lib_blas_sgemm_" >&6; } -if test "x$ac_cv_lib_blas_sgemm_" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dgemm_ in -ldgemm" >&5 -printf %s "checking for dgemm_ in -ldgemm... " >&6; } - -ac_check_lib_save_LIBS=$LIBS -LIBS="-ldgemm -lblas $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char dgemm_ (); -int -main (void) -{ -return dgemm_ (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dgemm_dgemm_=yes -else $as_nop - ac_cv_lib_dgemm_dgemm_=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dgemm_dgemm_" >&5 -printf "%s\n" "$ac_cv_lib_dgemm_dgemm_" >&6; } -if test "x$ac_cv_lib_dgemm_dgemm_" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sgemm_ in -lsgemm" >&5 -printf %s "checking for sgemm_ in -lsgemm... " >&6; } - -ac_check_lib_save_LIBS=$LIBS -LIBS="-lsgemm -lblas $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char sgemm_ (); -int -main (void) -{ -return sgemm_ (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_sgemm_sgemm_=yes -else $as_nop - ac_cv_lib_sgemm_sgemm_=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sgemm_sgemm_" >&5 -printf "%s\n" "$ac_cv_lib_sgemm_sgemm_" >&6; } -if test "x$ac_cv_lib_sgemm_sgemm_" = xyes -then : - blas_ok=yes; BLASLIB="-lsgemm -ldgemm -lblas" -fi - -fi - - -fi - -fi - -# BLAS in Sun Performance library? -if test $blas_ok = no; then - if test "x$GCC" != xyes; then # only works with Sun CC - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for acosp in -lsunmath" >&5 -printf %s "checking for acosp in -lsunmath... " >&6; } - -ac_check_lib_save_LIBS=$LIBS -LIBS="-lsunmath $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char acosp (); -int -main (void) -{ -return acosp (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_sunmath_acosp=yes -else $as_nop - ac_cv_lib_sunmath_acosp=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sunmath_acosp" >&5 -printf "%s\n" "$ac_cv_lib_sunmath_acosp" >&6; } -if test "x$ac_cv_lib_sunmath_acosp" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sgemm_ in -lsunperf" >&5 -printf %s "checking for sgemm_ in -lsunperf... " >&6; } - -ac_check_lib_save_LIBS=$LIBS -LIBS="-lsunperf -lsunmath $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char sgemm_ (); -int -main (void) -{ -return sgemm_ (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_sunperf_sgemm_=yes -else $as_nop - ac_cv_lib_sunperf_sgemm_=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sunperf_sgemm_" >&5 -printf "%s\n" "$ac_cv_lib_sunperf_sgemm_" >&6; } -if test "x$ac_cv_lib_sunperf_sgemm_" = xyes -then : - blas_ok=yes; BLASLIB="-xlic_lib=sunperf -lsunmath" -fi - - -fi - - fi -fi - -# Generic BLAS library -if test $blas_ok = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sgemm_ in -lblas" >&5 -printf %s "checking for sgemm_ in -lblas... " >&6; } - -ac_check_lib_save_LIBS=$LIBS -LIBS="-lblas $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char sgemm_ (); -int -main (void) -{ -return sgemm_ (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_blas_sgemm_=yes -else $as_nop - ac_cv_lib_blas_sgemm_=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_blas_sgemm_" >&5 -printf "%s\n" "$ac_cv_lib_blas_sgemm_" >&6; } -if test "x$ac_cv_lib_blas_sgemm_" = xyes -then : - blas_ok=yes; BLASLIB="-lblas" -fi - -fi - -if test $blas_ok = yes; then - -printf "%s\n" "#define HAVE_LIBBLAS 1" >>confdefs.h - -fi - -fi # $USE_BLAS - - - - -# Done checking BLAS - -# Enable LAPACK option - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use LAPACK" >&5 -printf %s "checking whether to use LAPACK... " >&6; } -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$with_lapack\"" >&5 -printf "%s\n" "\"$with_lapack\"" >&6; } -case "$with_lapack" in - "no") USE_LAPACK= ;; - "yes") USE_LAPACK="1" ;; - *) as_fn_error $? "*** You must answer yes or no." "$LINENO" 5 ;; -esac - - - -LAPACKLIB= -LAPACKINC= - -# LAPACK is useless without BLAS -if test -n "$USE_BLAS"; then -if test -n "$USE_LAPACK"; then - -# With LAPACK includes directory -# LAPACK doesn't have includes (FORTRAN library) -# With LAPACK library directory - -lapack_ok=no - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for location of LAPACK includes" >&5 -printf %s "checking for location of LAPACK includes... " >&6; } -case "$with_lapack_includes" in -y | ye | yes | n | no) - as_fn_error $? "*** You must supply a directory to --with-lapack-includes." "$LINENO" 5 - ;; -esac -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_lapack_includes" >&5 -printf "%s\n" "$with_lapack_includes" >&6; } - -if test -n "$with_lapack_includes" ; then - for dir in $with_lapack_includes; do - if test -d "$dir"; then - LAPACKINC="$LAPACKINC -I$dir" - else - as_fn_error $? "*** LAPACK includes directory $dir does not exist." "$LINENO" 5 - fi - done -fi - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for location of LAPACK library" >&5 -printf %s "checking for location of LAPACK library... " >&6; } -case "$with_lapack_libs" in -y | ye | yes | n | no) - as_fn_error $? "*** You must supply a directory to --with-lapack-libs." "$LINENO" 5 - ;; -esac -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_lapack_libs" >&5 -printf "%s\n" "$with_lapack_libs" >&6; } - -if test -n "$with_lapack_libs"; then - for dir in $with_lapack_libs; do - if test -d "$dir"; then - LAPACKLIB="$LAPACKLIB -L$dir" - else - as_fn_error $? "*** LAPACK library directory $dir does not exist." "$LINENO" 5 - fi - done -fi - - -# See if clapack.h exists (ATLAS) -save_CPPFLAGS="$CPPFLAGS" -CPPFLAGS="$LAPACKINC $CPPFLAGS" -ac_fn_c_check_header_compile "$LINENO" "clapack.h" "ac_cv_header_clapack_h" "$ac_includes_default" -if test "x$ac_cv_header_clapack_h" = xyes -then : - printf "%s\n" "#define HAVE_CLAPACK_H 1" >>confdefs.h - -fi - -CPPFLAGS="$save_CPPFLAGS" - -# LAPACK linked to by default? -if test lapack_ok=no; then - save_LIBS="$LIBS"; LIBS="$LIBS $BLASLIB $MATHLIB $FLIBS" - save_LDFLAGS="$LDFLAGS"; LDFLAGS="$LAPACKLIB $LDFLAGS" - ac_fn_c_check_func "$LINENO" "dsegv_" "ac_cv_func_dsegv_" -if test "x$ac_cv_func_dsegv_" = xyes -then : - lapack_ok=yes -fi - - LIBS="$save_LIBS" - LDFLAGS="$save_LDFLAGS" -fi - -# Generic LAPACK library? -if test $lapack_ok = no; then - save_libs="$LIBS"; LIBS="$BLASLIB $MATHLIB $LIBS" - save_LDFLAGS="$LDFLAGS"; LDFLAGS="$LAPACKLIB $LDFLAGS" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for desgv_ in -llapack" >&5 -printf %s "checking for desgv_ in -llapack... " >&6; } - -ac_check_lib_save_LIBS=$LIBS -LIBS="-llapack $FLIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char desgv_ (); -int -main (void) -{ -return desgv_ (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_lapack_desgv_=yes -else $as_nop - ac_cv_lib_lapack_desgv_=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lapack_desgv_" >&5 -printf "%s\n" "$ac_cv_lib_lapack_desgv_" >&6; } -if test "x$ac_cv_lib_lapack_desgv_" = xyes -then : - lapack_ok=yes; LAPACKLIB="-llapack" -fi - - LIBS="$save_LIBS" - LDFLAGS="$save_LDFLAGS" -fi - -if test $lapack_ok = no; then - -ac_save_ldflags="$LDFLAGS" -LDFLAGS="$LAPACKLIB $LDFLAGS" - - - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dgesv_ in -llapack" >&5 -printf %s "checking for dgesv_ in -llapack... " >&6; } - -ac_check_lib_save_LIBS=$LIBS -LIBS="-llapack $BLASLIB $MATHLIB $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char dgesv_ (); -int -main (void) -{ -return dgesv_ (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_lapack_dgesv_=yes -else $as_nop - ac_cv_lib_lapack_dgesv_=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lapack_dgesv_" >&5 -printf "%s\n" "$ac_cv_lib_lapack_dgesv_" >&6; } -if test "x$ac_cv_lib_lapack_dgesv_" = xyes -then : - LAPACKLIB="$LAPACKLIB -llapack " -else $as_nop - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dgesv_ in -llapack" >&5 -printf %s "checking for dgesv_ in -llapack... " >&6; } - -ac_check_lib_save_LIBS=$LIBS -LIBS="-llapack $BLASLIB $MATHLIB -lg2c $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char dgesv_ (); -int -main (void) -{ -return dgesv_ (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_lapack_dgesv_=yes -else $as_nop - ac_cv_lib_lapack_dgesv_=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lapack_dgesv_" >&5 -printf "%s\n" "$ac_cv_lib_lapack_dgesv_" >&6; } -if test "x$ac_cv_lib_lapack_dgesv_" = xyes -then : - LAPACKLIB="$LAPACKLIB -llapack -lg2c" -else $as_nop - -LDFLAGS=${ac_save_ldflags} - - as_fn_error $? "*** Unable to locate LAPACK library." "$LINENO" 5 - - -fi - - - - -fi - - - - - - -LDFLAGS=${ac_save_ldflags} - -fi - - -printf "%s\n" "#define HAVE_LIBLAPACK 1" >>confdefs.h - - -fi # $USE_LAPACK -fi # $USE_BLAS +fi # $USE_BLAS $USE_LAPACK diff --git a/configure.ac b/configure.ac index 00403f1e665..8b7413c7cea 100644 --- a/configure.ac +++ b/configure.ac @@ -305,8 +305,6 @@ LOC_ARG_WITH(sqlite, SQLite) LOC_ARG_WITH(opengl, OpenGL) LOC_ARG_WITH(odbc, ODBC, no) LOC_ARG_WITH(fftw, FFTW) -LOC_ARG_WITH(blas, BLAS, no) -LOC_ARG_WITH(lapack, LAPACK, no) LOC_ARG_WITH(libsvm, LIBSVM, no) LOC_ARG_WITH(cairo, Cairo) LOC_ARG_WITH(freetype, FreeType) @@ -320,6 +318,19 @@ LOC_ARG_WITH(bzlib, BZIP2, no) LOC_ARG_WITH(zstd, Zstandard) LOC_ARG_WITH(pdal, PDAL) + +AC_ARG_WITH([blas], + [AS_HELP_STRING([--with-blas=pkg-config-package], + [enable BLAS support with by adding name of pkg-config package name + for CBLAS library, e.g. '--with-lapack-package=openblas', + default: cblas])],, [with-blas="no"]) + +AC_ARG_WITH([lapack], + [AS_HELP_STRING([--with-lapack=pkg-config-package], + [enable LAPACK support with by adding name of pkg-config package name + for LAPACKE library, e.g. '--with-lapack-package=openblas', + default: lapacke])],, [with-lapack="no"]) + AC_ARG_WITH(libpng, [ --with-libpng[=path/libpng-config] enable PNG support (libpng-config with path, @@ -390,12 +401,6 @@ LOC_ARG_WITH_LIB(odbc, ODBC) LOC_ARG_WITH_INC(fftw, FFTW) LOC_ARG_WITH_LIB(fftw, FFTW) -LOC_ARG_WITH_INC(blas, BLAS) -LOC_ARG_WITH_LIB(blas, BLAS) - -LOC_ARG_WITH_INC(lapack, LAPACK) -LOC_ARG_WITH_LIB(lapack, LAPACK) - LOC_ARG_WITH_INC(libsvm, LIBSVM) LOC_ARG_WITH_LIB(libsvm, LIBSVM) @@ -501,7 +506,7 @@ AC_CHECK_PROGS(ENV, env) AC_PATH_PROG(PERL, perl, no) #AC_CHECK_HEADERS(curses.h limits.h termio.h termios.h unistd.h values.h) -AC_CHECK_HEADERS(limits.h termio.h termios.h unistd.h values.h f2c.h g2c.h) +AC_CHECK_HEADERS(limits.h termio.h termios.h unistd.h values.h) AC_CHECK_HEADERS(sys/ioctl.h sys/mtio.h sys/resource.h sys/time.h) AC_CHECK_HEADERS(sys/timeb.h sys/types.h sys/utsname.h) AC_CHECK_HEADERS(libintl.h iconv.h) @@ -1576,91 +1581,67 @@ AC_SUBST(FFTWLIB) # Enable BLAS option -LOC_CHECK_USE(blas,BLAS,USE_BLAS) +AC_MSG_CHECKING([whether to use (C)BLAS]) +AC_MSG_RESULT([$with_blas]) BLASLIB= BLASINC= +USE_BLAS= +BLAS_PKGS="cblas blas-netlib openblas blas-atlas" +BLAS_PKG= + +case "$with_blas" in + no) + ;; + yes) + USE_BLAS="$with_blas" + ;; + *) + USE_BLAS=yes + BLAS_PKGS="$with_blas" + ;; +esac if test -n "$USE_BLAS"; then -# With BLAS includes directory -# BLAS doesn't have includes (FORTRAN library) -# With BLAS library directory - -LOC_CHECK_INC_PATH(blas, BLAS, BLASINC) -LOC_CHECK_LIB_PATH(blas, BLAS, BLASLIB) - -# See if cblas.h exists (CBLAS,ATLAS,others) -save_CPPFLAGS="$CPPFLAGS" -CPPFLAGS="$BLASINC $CPPFLAGS" -AC_CHECK_HEADERS(cblas.h) -CPPFLAGS="$save_CPPFLAGS" - -LOC_CHECK_LIBS(blas,dnrm2_,BLAS,$BLASLIB,BLASLIB,$MATHLIB,,,-lg2c) - -blas_ok=no - -# Check for ATLAS -save_LDFLAGS="$LDFLAGS" -LDFLAGS="$BLASLIB $LDFLAGS" -AC_CHECK_LIB(atlas, ATL_xerbla, - [AC_CHECK_LIB(f77blas, sgemm_, - [AC_CHECK_LIB(cblas, cblas_dgemm, - [blas_ok=yes; BLASLIB="-lcblas -lf77blas -latlas"], - [],[-lf77blas -latlas])], - [],[-latlas])] -) -LDFLAGS="$save_LDFLAGS" - -# Do we have ATLAS? -if test $blas_ok = yes; then - AC_DEFINE(HAVE_LIBATLAS, 1, [Define to 1 if ATLAS exists.]) -fi + blas_ok=no -# BLAS in Apple vecLib framework? (Mac OS-X) -# not dependent on APP build -#if test -n "$MACOSX_APP"; then -if test $blas_ok = no; then - vlib_flags="-framework vecLib" - save_LIBS="$LIBS" - LIBS="$vlib_flags $LIBS" - AC_MSG_CHECKING([for sgemm in $vlib_flags]) - AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[sgemm]])],[blas_ok=yes; BLASLIB="$vlib_flags"],[BLASLIB=""]) - AC_MSG_RESULT($blas_ok) - LIBS="$save_LIBS" -fi -#fi # $MACOSX_APP - -# BLAS in PhiPACK libraries? (requires generic BLAS, too) -if test $blas_ok = no; then - AC_CHECK_LIB(blas, sgemm_, - [AC_CHECK_LIB(dgemm, dgemm_, - [AC_CHECK_LIB(sgemm, sgemm_, - [blas_ok=yes; BLASLIB="-lsgemm -ldgemm -lblas"], - [], [-lblas])], - [], [-lblas])] - ) -fi + for blas_chk in ${BLAS_PKGS} + do + if ! ${PKG_CONFIG} --exists ${blas_chk} ; then + continue + else + BLAS_PKG=${blas_chk} + break + fi + done -# BLAS in Sun Performance library? -if test $blas_ok = no; then - if test "x$GCC" != xyes; then # only works with Sun CC - AC_CHECK_LIB(sunmath, acosp, - [AC_CHECK_LIB(sunperf, sgemm_, - [blas_ok=yes; BLASLIB="-xlic_lib=sunperf -lsunmath"], - [], [-lsunmath])] - ) - fi -fi + if test -z "$BLAS_PKG" ; then + AC_MSG_ERROR([*** Unable to locate (C)BLAS pkg-conf package(s) + "${BLAS_PKGS}". Perhaps you need to set PKG_CONFIG_PATH.]) + fi -# Generic BLAS library -if test $blas_ok = no; then - AC_CHECK_LIB(blas, sgemm_, [blas_ok=yes; BLASLIB="-lblas"]) -fi + BLASLIB=$(${PKG_CONFIG} --libs ${BLAS_PKG}) + BLASINC=$(${PKG_CONFIG} --cflags ${BLAS_PKG}) -if test $blas_ok = yes; then -AC_DEFINE(HAVE_LIBBLAS, 1, [Define to 1 if BLAS exists.]) -fi + save_CFLAGS="$CFLAGS"; CFLAGS="$BLASINC $CFLAGS" + save_LIBS="$LIBS"; LIBS="$BLASLIB" + + AC_CHECK_HEADERS([cblas.h],, + AC_CHECK_HEADERS([cblas-atlas.h],, + AC_MSG_ERROR([*** Failed to find either "cblas.h" or "cblas-atlas.h" with "$CFLAGS"]))) + + AC_MSG_CHECKING([for linking to (C)BLAS]) + AC_LINK_IFELSE([AC_LANG_PROGRAM( + [[char cblas_dgemm();]], [[return cblas_dgemm();]])], + [blas_ok=yes] , [ + AC_MSG_ERROR([*** Unable to link to (C)BLAS library with "$LIBS".])]) + AC_MSG_RESULT([$BLAS_PKG]) + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + + AC_DEFINE(HAVE_LIBBLAS, 1, [Define to 1 if BLAS exists.]) fi # $USE_BLAS @@ -1671,57 +1652,69 @@ AC_SUBST(BLASINC) # Enable LAPACK option -LOC_CHECK_USE(lapack,LAPACK,USE_LAPACK) +AC_MSG_CHECKING([whether to use LAPACK(E)]) +AC_MSG_RESULT([$with_lapack]) LAPACKLIB= LAPACKINC= +USE_LAPACK= +LAPACK_PKGS="lapacke openblas" +LAPACK_PKG= + +case "$with_lapack" in + no) + ;; + yes) + USE_LAPACK="$with_lapack" + ;; + *) + USE_LAPACK=yes + LAPACK_PKG="$with_lapack" + ;; +esac # LAPACK is useless without BLAS -if test -n "$USE_BLAS"; then -if test -n "$USE_LAPACK"; then - -# With LAPACK includes directory -# LAPACK doesn't have includes (FORTRAN library) -# With LAPACK library directory - -lapack_ok=no - -LOC_CHECK_INC_PATH(lapack, LAPACK, LAPACKINC) -LOC_CHECK_LIB_PATH(lapack, LAPACK, LAPACKLIB) - -# See if clapack.h exists (ATLAS) -save_CPPFLAGS="$CPPFLAGS" -CPPFLAGS="$LAPACKINC $CPPFLAGS" -AC_CHECK_HEADERS(clapack.h) -CPPFLAGS="$save_CPPFLAGS" - -# LAPACK linked to by default? -if test lapack_ok=no; then - save_LIBS="$LIBS"; LIBS="$LIBS $BLASLIB $MATHLIB $FLIBS" - save_LDFLAGS="$LDFLAGS"; LDFLAGS="$LAPACKLIB $LDFLAGS" - AC_CHECK_FUNC(dsegv_, [lapack_ok=yes]) - LIBS="$save_LIBS" - LDFLAGS="$save_LDFLAGS" -fi +if test -n "$USE_BLAS" && test -n "$USE_LAPACK"; then -# Generic LAPACK library? -if test $lapack_ok = no; then - save_libs="$LIBS"; LIBS="$BLASLIB $MATHLIB $LIBS" - save_LDFLAGS="$LDFLAGS"; LDFLAGS="$LAPACKLIB $LDFLAGS" - AC_CHECK_LIB(lapack, desgv_, - [lapack_ok=yes; LAPACKLIB="-llapack"], [], [$FLIBS]) - LIBS="$save_LIBS" - LDFLAGS="$save_LDFLAGS" -fi + lapack_ok=no -if test $lapack_ok = no; then - LOC_CHECK_LIBS(lapack,dgesv_,LAPACK,$LAPACKLIB,LAPACKLIB,$BLASLIB $MATHLIB,,,-lg2c) -fi + for lapack_chk in ${LAPACK_PKGS} + do + if ! ${PKG_CONFIG} --exists ${lapack_chk} ; then + continue + else + LAPACK_PKG=${lapack_chk} + break + fi + done -AC_DEFINE(HAVE_LIBLAPACK, 1, [Define to 1 if LAPACK exists.]) + if test -z "$LAPACK_PKG" ; then + AC_MSG_ERROR([*** Unable to locate LAPACK(E) pkg-conf package(s) + "$LAPACK_PKGS". Perhaps you need to set PKG_CONFIG_PATH.]) + fi -fi # $USE_LAPACK -fi # $USE_BLAS + LAPACKLIB=`${PKG_CONFIG} --libs ${LAPACK_PKG}` + LAPACKINC=`${PKG_CONFIG} --cflags ${LAPACK_PKG}` + + save_CFLAGS="$CFLAGS"; CFLAGS="$LAPACKINC $CFLAGS" + save_LIBS="$LIBS"; LIBS="$LAPACKLIB" + + AC_CHECK_HEADERS([lapacke.h], [], + AC_MSG_ERROR([*** Unable to find "lapacke.h" with "$CFLAGS".])) + + AC_MSG_CHECKING([for linking to LAPACK(E)]) + AC_LINK_IFELSE([AC_LANG_PROGRAM( + [[char LAPACKE_dgesv();]], [[return LAPACKE_dgesv(); ]])], + [lapack_ok=yes] , [ + AC_MSG_ERROR([*** Unable to link to LAPACK(E) library with "$LIBS".])]) + AC_MSG_RESULT([$LAPACK_PKG]) + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + + AC_DEFINE(HAVE_LIBLAPACK, 1, [Define to 1 if LAPACK exists.]) + +fi # $USE_BLAS $USE_LAPACK AC_SUBST(LAPACKLIB) AC_SUBST(LAPACKINC) diff --git a/include/grass/blas.h b/include/grass/blas.h deleted file mode 100644 index 2e7fe0a31f2..00000000000 --- a/include/grass/blas.h +++ /dev/null @@ -1,412 +0,0 @@ -#ifndef BLAS_WRAP_H -#define BLAS_WRAP_H - -extern int caxpy_(integer *n, complex *ca, complex *cx, integer *incx, - complex *cy, integer *incy); -extern int ccopy_(integer *n, complex *cx, integer *incx, complex *cy, - integer *incy); -extern C_f cdotc_(complex *ret_val, integer *n, complex *cx, integer *incx, - complex *cy, integer *incy); -extern C_f cdotu_(complex *ret_val, integer *n, complex *cx, integer *incx, - complex *cy, integer *incy); -extern int cgbmv_(char *trans, integer *m, integer *n, integer *kl, integer *ku, - complex *alpha, complex *a, integer *lda, complex *x, - integer *incx, complex *beta, complex *y, integer *incy, - ftnlen trans_len); -extern int cgemm_(char *transa, char *transb, integer *m, integer *n, - integer *k, complex *alpha, complex *a, integer *lda, - complex *b, integer *ldb, complex *beta, complex *c__, - integer *ldc, ftnlen transa_len, ftnlen transb_len); -extern int cgemv_(char *trans, integer *m, integer *n, complex *alpha, - complex *a, integer *lda, complex *x, integer *incx, - complex *beta, complex *y, integer *incy, ftnlen trans_len); -extern int cgerc_(integer *m, integer *n, complex *alpha, complex *x, - integer *incx, complex *y, integer *incy, complex *a, - integer *lda); -extern int cgeru_(integer *m, integer *n, complex *alpha, complex *x, - integer *incx, complex *y, integer *incy, complex *a, - integer *lda); -extern int chbmv_(char *uplo, integer *n, integer *k, complex *alpha, - complex *a, integer *lda, complex *x, integer *incx, - complex *beta, complex *y, integer *incy, ftnlen uplo_len); -extern int chemm_(char *side, char *uplo, integer *m, integer *n, - complex *alpha, complex *a, integer *lda, complex *b, - integer *ldb, complex *beta, complex *c__, integer *ldc, - ftnlen side_len, ftnlen uplo_len); -extern int chemv_(char *uplo, integer *n, complex *alpha, complex *a, - integer *lda, complex *x, integer *incx, complex *beta, - complex *y, integer *incy, ftnlen uplo_len); -extern int cher_(char *uplo, integer *n, real *alpha, complex *x, integer *incx, - complex *a, integer *lda, ftnlen uplo_len); -extern int cher2_(char *uplo, integer *n, complex *alpha, complex *x, - integer *incx, complex *y, integer *incy, complex *a, - integer *lda, ftnlen uplo_len); -extern int cher2k_(char *uplo, char *trans, integer *n, integer *k, - complex *alpha, complex *a, integer *lda, complex *b, - integer *ldb, real *beta, complex *c__, integer *ldc, - ftnlen uplo_len, ftnlen trans_len); -extern int cherk_(char *uplo, char *trans, integer *n, integer *k, real *alpha, - complex *a, integer *lda, real *beta, complex *c__, - integer *ldc, ftnlen uplo_len, ftnlen trans_len); -extern int chpmv_(char *uplo, integer *n, complex *alpha, complex *ap, - complex *x, integer *incx, complex *beta, complex *y, - integer *incy, ftnlen uplo_len); -extern int chpr_(char *uplo, integer *n, real *alpha, complex *x, integer *incx, - complex *ap, ftnlen uplo_len); -extern int chpr2_(char *uplo, integer *n, complex *alpha, complex *x, - integer *incx, complex *y, integer *incy, complex *ap, - ftnlen uplo_len); -extern int crotg_(complex *ca, complex *cb, real *c__, complex *s); -extern int cscal_(integer *n, complex *ca, complex *cx, integer *incx); -extern int csrot_(integer *n, complex *cx, integer *incx, complex *cy, - integer *incy, real *c__, real *s); -extern int csscal_(integer *n, real *sa, complex *cx, integer *incx); -extern int cswap_(integer *n, complex *cx, integer *incx, complex *cy, - integer *incy); -extern int csymm_(char *side, char *uplo, integer *m, integer *n, - complex *alpha, complex *a, integer *lda, complex *b, - integer *ldb, complex *beta, complex *c__, integer *ldc, - ftnlen side_len, ftnlen uplo_len); -extern int csyr2k_(char *uplo, char *trans, integer *n, integer *k, - complex *alpha, complex *a, integer *lda, complex *b, - integer *ldb, complex *beta, complex *c__, integer *ldc, - ftnlen uplo_len, ftnlen trans_len); -extern int csyrk_(char *uplo, char *trans, integer *n, integer *k, - complex *alpha, complex *a, integer *lda, complex *beta, - complex *c__, integer *ldc, ftnlen uplo_len, - ftnlen trans_len); -extern int ctbmv_(char *uplo, char *trans, char *diag, integer *n, integer *k, - complex *a, integer *lda, complex *x, integer *incx, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len); -extern int ctbsv_(char *uplo, char *trans, char *diag, integer *n, integer *k, - complex *a, integer *lda, complex *x, integer *incx, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len); -extern int ctpmv_(char *uplo, char *trans, char *diag, integer *n, complex *ap, - complex *x, integer *incx, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len); -extern int ctpsv_(char *uplo, char *trans, char *diag, integer *n, complex *ap, - complex *x, integer *incx, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len); -extern int ctrmm_(char *side, char *uplo, char *transa, char *diag, integer *m, - integer *n, complex *alpha, complex *a, integer *lda, - complex *b, integer *ldb, ftnlen side_len, ftnlen uplo_len, - ftnlen transa_len, ftnlen diag_len); -extern int ctrmv_(char *uplo, char *trans, char *diag, integer *n, complex *a, - integer *lda, complex *x, integer *incx, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern int ctrsm_(char *side, char *uplo, char *transa, char *diag, integer *m, - integer *n, complex *alpha, complex *a, integer *lda, - complex *b, integer *ldb, ftnlen side_len, ftnlen uplo_len, - ftnlen transa_len, ftnlen diag_len); -extern int ctrsv_(char *uplo, char *trans, char *diag, integer *n, complex *a, - integer *lda, complex *x, integer *incx, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern doublereal dasum_(integer *n, doublereal *dx, integer *incx); -extern int daxpy_(integer *n, doublereal *da, doublereal *dx, integer *incx, - doublereal *dy, integer *incy); -extern doublereal dcabs1_(doublecomplex *z__); -extern int dcopy_(integer *n, doublereal *dx, integer *incx, doublereal *dy, - integer *incy); -extern doublereal ddot_(integer *n, doublereal *dx, integer *incx, - doublereal *dy, integer *incy); -extern int dgbmv_(char *trans, integer *m, integer *n, integer *kl, integer *ku, - doublereal *alpha, doublereal *a, integer *lda, doublereal *x, - integer *incx, doublereal *beta, doublereal *y, integer *incy, - ftnlen trans_len); -extern int dgemm_(char *transa, char *transb, integer *m, integer *n, - integer *k, doublereal *alpha, doublereal *a, integer *lda, - doublereal *b, integer *ldb, doublereal *beta, - doublereal *c__, integer *ldc); -extern int dgemv_(char *trans, integer *m, integer *n, doublereal *alpha, - doublereal *a, integer *lda, doublereal *x, integer *incx, - doublereal *beta, doublereal *y, integer *incy, - ftnlen trans_len); -extern int dger_(integer *m, integer *n, doublereal *alpha, doublereal *x, - integer *incx, doublereal *y, integer *incy, doublereal *a, - integer *lda); -extern doublereal dnrm2_(integer *n, doublereal *x, integer *incx); -extern int drot_(integer *n, doublereal *dx, integer *incx, doublereal *dy, - integer *incy, doublereal *c__, doublereal *s); -extern int drotg_(doublereal *da, doublereal *db, doublereal *c__, - doublereal *s); -extern int drotm_(integer *n, doublereal *dx, integer *incx, doublereal *dy, - integer *incy, doublereal *dparam); -extern int drotmg_(doublereal *dd1, doublereal *dd2, doublereal *dx1, - doublereal *dy1, doublereal *dparam); -extern int dsbmv_(char *uplo, integer *n, integer *k, doublereal *alpha, - doublereal *a, integer *lda, doublereal *x, integer *incx, - doublereal *beta, doublereal *y, integer *incy, - ftnlen uplo_len); -extern int dscal_(integer *n, doublereal *da, doublereal *dx, integer *incx); -extern doublereal dsdot_(integer *n, real *sx, integer *incx, real *sy, - integer *incy); -extern int dspmv_(char *uplo, integer *n, doublereal *alpha, doublereal *ap, - doublereal *x, integer *incx, doublereal *beta, doublereal *y, - integer *incy, ftnlen uplo_len); -extern int dspr_(char *uplo, integer *n, doublereal *alpha, doublereal *x, - integer *incx, doublereal *ap, ftnlen uplo_len); -extern int dspr2_(char *uplo, integer *n, doublereal *alpha, doublereal *x, - integer *incx, doublereal *y, integer *incy, doublereal *ap, - ftnlen uplo_len); -extern int dswap_(integer *n, doublereal *dx, integer *incx, doublereal *dy, - integer *incy); -extern int dsymm_(char *side, char *uplo, integer *m, integer *n, - doublereal *alpha, doublereal *a, integer *lda, doublereal *b, - integer *ldb, doublereal *beta, doublereal *c__, integer *ldc, - ftnlen side_len, ftnlen uplo_len); -extern int dsymv_(char *uplo, integer *n, doublereal *alpha, doublereal *a, - integer *lda, doublereal *x, integer *incx, doublereal *beta, - doublereal *y, integer *incy, ftnlen uplo_len); -extern int dsyr_(char *uplo, integer *n, doublereal *alpha, doublereal *x, - integer *incx, doublereal *a, integer *lda, ftnlen uplo_len); -extern int dsyr2_(char *uplo, integer *n, doublereal *alpha, doublereal *x, - integer *incx, doublereal *y, integer *incy, doublereal *a, - integer *lda, ftnlen uplo_len); -extern int dsyr2k_(char *uplo, char *trans, integer *n, integer *k, - doublereal *alpha, doublereal *a, integer *lda, - doublereal *b, integer *ldb, doublereal *beta, - doublereal *c__, integer *ldc, ftnlen uplo_len, - ftnlen trans_len); -extern int dsyrk_(char *uplo, char *trans, integer *n, integer *k, - doublereal *alpha, doublereal *a, integer *lda, - doublereal *beta, doublereal *c__, integer *ldc, - ftnlen uplo_len, ftnlen trans_len); -extern int dtbmv_(char *uplo, char *trans, char *diag, integer *n, integer *k, - doublereal *a, integer *lda, doublereal *x, integer *incx, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len); -extern int dtbsv_(char *uplo, char *trans, char *diag, integer *n, integer *k, - doublereal *a, integer *lda, doublereal *x, integer *incx, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len); -extern int dtpmv_(char *uplo, char *trans, char *diag, integer *n, - doublereal *ap, doublereal *x, integer *incx, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern int dtpsv_(char *uplo, char *trans, char *diag, integer *n, - doublereal *ap, doublereal *x, integer *incx, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern int dtrmm_(char *side, char *uplo, char *transa, char *diag, integer *m, - integer *n, doublereal *alpha, doublereal *a, integer *lda, - doublereal *b, integer *ldb, ftnlen side_len, ftnlen uplo_len, - ftnlen transa_len, ftnlen diag_len); -extern int dtrmv_(char *uplo, char *trans, char *diag, integer *n, - doublereal *a, integer *lda, doublereal *x, integer *incx, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len); -extern int dtrsm_(char *side, char *uplo, char *transa, char *diag, integer *m, - integer *n, doublereal *alpha, doublereal *a, integer *lda, - doublereal *b, integer *ldb, ftnlen side_len, ftnlen uplo_len, - ftnlen transa_len, ftnlen diag_len); -extern int dtrsv_(char *uplo, char *trans, char *diag, integer *n, - doublereal *a, integer *lda, doublereal *x, integer *incx, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len); -extern doublereal dzasum_(integer *n, doublecomplex *zx, integer *incx); -extern doublereal dznrm2_(integer *n, doublecomplex *x, integer *incx); -extern integer icamax_(integer *n, complex *cx, integer *incx); -extern integer idamax_(integer *n, doublereal *dx, integer *incx); -extern integer isamax_(integer *n, real *sx, integer *incx); -extern integer izamax_(integer *n, doublecomplex *zx, integer *incx); -extern logical lsame_(char *ca, char *cb, ftnlen ca_len, ftnlen cb_len); -extern E_f sasum_(integer *n, real *sx, integer *incx); -extern int saxpy_(integer *n, real *sa, real *sx, integer *incx, real *sy, - integer *incy); -extern E_f scasum_(integer *n, complex *cx, integer *incx); -extern E_f scnrm2_(integer *n, complex *x, integer *incx); -extern int scopy_(integer *n, real *sx, integer *incx, real *sy, integer *incy); -extern E_f sdot_(integer *n, real *sx, integer *incx, real *sy, integer *incy); -extern E_f sdsdot_(integer *n, real *sb, real *sx, integer *incx, real *sy, - integer *incy); -extern int sgbmv_(char *trans, integer *m, integer *n, integer *kl, integer *ku, - real *alpha, real *a, integer *lda, real *x, integer *incx, - real *beta, real *y, integer *incy, ftnlen trans_len); -extern int sgemm_(char *transa, char *transb, integer *m, integer *n, - integer *k, real *alpha, real *a, integer *lda, real *b, - integer *ldb, real *beta, real *c__, integer *ldc, - ftnlen transa_len, ftnlen transb_len); -extern int sgemv_(char *trans, integer *m, integer *n, real *alpha, real *a, - integer *lda, real *x, integer *incx, real *beta, real *y, - integer *incy, ftnlen trans_len); -extern int sger_(integer *m, integer *n, real *alpha, real *x, integer *incx, - real *y, integer *incy, real *a, integer *lda); -extern E_f snrm2_(integer *n, real *x, integer *incx); -extern int srot_(integer *n, real *sx, integer *incx, real *sy, integer *incy, - real *c__, real *s); -extern int srotg_(real *sa, real *sb, real *c__, real *s); -extern int srotm_(integer *n, real *sx, integer *incx, real *sy, integer *incy, - real *sparam); -extern int srotmg_(real *sd1, real *sd2, real *sx1, real *sy1, real *sparam); -extern int ssbmv_(char *uplo, integer *n, integer *k, real *alpha, real *a, - integer *lda, real *x, integer *incx, real *beta, real *y, - integer *incy, ftnlen uplo_len); -extern int sscal_(integer *n, real *sa, real *sx, integer *incx); -extern int sspmv_(char *uplo, integer *n, real *alpha, real *ap, real *x, - integer *incx, real *beta, real *y, integer *incy, - ftnlen uplo_len); -extern int sspr_(char *uplo, integer *n, real *alpha, real *x, integer *incx, - real *ap, ftnlen uplo_len); -extern int sspr2_(char *uplo, integer *n, real *alpha, real *x, integer *incx, - real *y, integer *incy, real *ap, ftnlen uplo_len); -extern int sswap_(integer *n, real *sx, integer *incx, real *sy, integer *incy); -extern int ssymm_(char *side, char *uplo, integer *m, integer *n, real *alpha, - real *a, integer *lda, real *b, integer *ldb, real *beta, - real *c__, integer *ldc, ftnlen side_len, ftnlen uplo_len); -extern int ssymv_(char *uplo, integer *n, real *alpha, real *a, integer *lda, - real *x, integer *incx, real *beta, real *y, integer *incy, - ftnlen uplo_len); -extern int ssyr_(char *uplo, integer *n, real *alpha, real *x, integer *incx, - real *a, integer *lda, ftnlen uplo_len); -extern int ssyr2_(char *uplo, integer *n, real *alpha, real *x, integer *incx, - real *y, integer *incy, real *a, integer *lda, - ftnlen uplo_len); -extern int ssyr2k_(char *uplo, char *trans, integer *n, integer *k, real *alpha, - real *a, integer *lda, real *b, integer *ldb, real *beta, - real *c__, integer *ldc, ftnlen uplo_len, ftnlen trans_len); -extern int ssyrk_(char *uplo, char *trans, integer *n, integer *k, real *alpha, - real *a, integer *lda, real *beta, real *c__, integer *ldc, - ftnlen uplo_len, ftnlen trans_len); -extern int stbmv_(char *uplo, char *trans, char *diag, integer *n, integer *k, - real *a, integer *lda, real *x, integer *incx, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len); -extern int stbsv_(char *uplo, char *trans, char *diag, integer *n, integer *k, - real *a, integer *lda, real *x, integer *incx, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len); -extern int stpmv_(char *uplo, char *trans, char *diag, integer *n, real *ap, - real *x, integer *incx, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len); -extern int stpsv_(char *uplo, char *trans, char *diag, integer *n, real *ap, - real *x, integer *incx, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len); -extern int strmm_(char *side, char *uplo, char *transa, char *diag, integer *m, - integer *n, real *alpha, real *a, integer *lda, real *b, - integer *ldb, ftnlen side_len, ftnlen uplo_len, - ftnlen transa_len, ftnlen diag_len); -extern int strmv_(char *uplo, char *trans, char *diag, integer *n, real *a, - integer *lda, real *x, integer *incx, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern int strsm_(char *side, char *uplo, char *transa, char *diag, integer *m, - integer *n, real *alpha, real *a, integer *lda, real *b, - integer *ldb, ftnlen side_len, ftnlen uplo_len, - ftnlen transa_len, ftnlen diag_len); -extern int strsv_(char *uplo, char *trans, char *diag, integer *n, real *a, - integer *lda, real *x, integer *incx, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern int xerbla_(char *srname, integer *info, ftnlen srname_len); -extern int zaxpy_(integer *n, doublecomplex *za, doublecomplex *zx, - integer *incx, doublecomplex *zy, integer *incy); -extern int zcopy_(integer *n, doublecomplex *zx, integer *incx, - doublecomplex *zy, integer *incy); -extern Z_f zdotc_(doublecomplex *ret_val, integer *n, doublecomplex *zx, - integer *incx, doublecomplex *zy, integer *incy); -extern Z_f zdotu_(doublecomplex *ret_val, integer *n, doublecomplex *zx, - integer *incx, doublecomplex *zy, integer *incy); -extern int zdrot_(integer *n, doublecomplex *zx, integer *incx, - doublecomplex *zy, integer *incy, doublereal *c__, - doublereal *s); -extern int zdscal_(integer *n, doublereal *da, doublecomplex *zx, - integer *incx); -extern int zgbmv_(char *trans, integer *m, integer *n, integer *kl, integer *ku, - doublecomplex *alpha, doublecomplex *a, integer *lda, - doublecomplex *x, integer *incx, doublecomplex *beta, - doublecomplex *y, integer *incy, ftnlen trans_len); -extern int zgemm_(char *transa, char *transb, integer *m, integer *n, - integer *k, doublecomplex *alpha, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, - doublecomplex *beta, doublecomplex *c__, integer *ldc, - ftnlen transa_len, ftnlen transb_len); -extern int zgemv_(char *trans, integer *m, integer *n, doublecomplex *alpha, - doublecomplex *a, integer *lda, doublecomplex *x, - integer *incx, doublecomplex *beta, doublecomplex *y, - integer *incy, ftnlen trans_len); -extern int zgerc_(integer *m, integer *n, doublecomplex *alpha, - doublecomplex *x, integer *incx, doublecomplex *y, - integer *incy, doublecomplex *a, integer *lda); -extern int zgeru_(integer *m, integer *n, doublecomplex *alpha, - doublecomplex *x, integer *incx, doublecomplex *y, - integer *incy, doublecomplex *a, integer *lda); -extern int zhbmv_(char *uplo, integer *n, integer *k, doublecomplex *alpha, - doublecomplex *a, integer *lda, doublecomplex *x, - integer *incx, doublecomplex *beta, doublecomplex *y, - integer *incy, ftnlen uplo_len); -extern int zhemm_(char *side, char *uplo, integer *m, integer *n, - doublecomplex *alpha, doublecomplex *a, integer *lda, - doublecomplex *b, integer *ldb, doublecomplex *beta, - doublecomplex *c__, integer *ldc, ftnlen side_len, - ftnlen uplo_len); -extern int zhemv_(char *uplo, integer *n, doublecomplex *alpha, - doublecomplex *a, integer *lda, doublecomplex *x, - integer *incx, doublecomplex *beta, doublecomplex *y, - integer *incy, ftnlen uplo_len); -extern int zher_(char *uplo, integer *n, doublereal *alpha, doublecomplex *x, - integer *incx, doublecomplex *a, integer *lda, - ftnlen uplo_len); -extern int zher2_(char *uplo, integer *n, doublecomplex *alpha, - doublecomplex *x, integer *incx, doublecomplex *y, - integer *incy, doublecomplex *a, integer *lda, - ftnlen uplo_len); -extern int zher2k_(char *uplo, char *trans, integer *n, integer *k, - doublecomplex *alpha, doublecomplex *a, integer *lda, - doublecomplex *b, integer *ldb, doublereal *beta, - doublecomplex *c__, integer *ldc, ftnlen uplo_len, - ftnlen trans_len); -extern int zherk_(char *uplo, char *trans, integer *n, integer *k, - doublereal *alpha, doublecomplex *a, integer *lda, - doublereal *beta, doublecomplex *c__, integer *ldc, - ftnlen uplo_len, ftnlen trans_len); -extern int zhpmv_(char *uplo, integer *n, doublecomplex *alpha, - doublecomplex *ap, doublecomplex *x, integer *incx, - doublecomplex *beta, doublecomplex *y, integer *incy, - ftnlen uplo_len); -extern int zhpr_(char *uplo, integer *n, doublereal *alpha, doublecomplex *x, - integer *incx, doublecomplex *ap, ftnlen uplo_len); -extern int zhpr2_(char *uplo, integer *n, doublecomplex *alpha, - doublecomplex *x, integer *incx, doublecomplex *y, - integer *incy, doublecomplex *ap, ftnlen uplo_len); -extern int zrotg_(doublecomplex *ca, doublecomplex *cb, doublereal *c__, - doublecomplex *s); -extern int zscal_(integer *n, doublecomplex *za, doublecomplex *zx, - integer *incx); -extern int zswap_(integer *n, doublecomplex *zx, integer *incx, - doublecomplex *zy, integer *incy); -extern int zsymm_(char *side, char *uplo, integer *m, integer *n, - doublecomplex *alpha, doublecomplex *a, integer *lda, - doublecomplex *b, integer *ldb, doublecomplex *beta, - doublecomplex *c__, integer *ldc, ftnlen side_len, - ftnlen uplo_len); -extern int zsyr2k_(char *uplo, char *trans, integer *n, integer *k, - doublecomplex *alpha, doublecomplex *a, integer *lda, - doublecomplex *b, integer *ldb, doublecomplex *beta, - doublecomplex *c__, integer *ldc, ftnlen uplo_len, - ftnlen trans_len); -extern int zsyrk_(char *uplo, char *trans, integer *n, integer *k, - doublecomplex *alpha, doublecomplex *a, integer *lda, - doublecomplex *beta, doublecomplex *c__, integer *ldc, - ftnlen uplo_len, ftnlen trans_len); -extern int ztbmv_(char *uplo, char *trans, char *diag, integer *n, integer *k, - doublecomplex *a, integer *lda, doublecomplex *x, - integer *incx, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len); -extern int ztbsv_(char *uplo, char *trans, char *diag, integer *n, integer *k, - doublecomplex *a, integer *lda, doublecomplex *x, - integer *incx, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len); -extern int ztpmv_(char *uplo, char *trans, char *diag, integer *n, - doublecomplex *ap, doublecomplex *x, integer *incx, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len); -extern int ztpsv_(char *uplo, char *trans, char *diag, integer *n, - doublecomplex *ap, doublecomplex *x, integer *incx, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len); -extern int ztrmm_(char *side, char *uplo, char *transa, char *diag, integer *m, - integer *n, doublecomplex *alpha, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, ftnlen side_len, - ftnlen uplo_len, ftnlen transa_len, ftnlen diag_len); -extern int ztrmv_(char *uplo, char *trans, char *diag, integer *n, - doublecomplex *a, integer *lda, doublecomplex *x, - integer *incx, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len); -extern int ztrsm_(char *side, char *uplo, char *transa, char *diag, integer *m, - integer *n, doublecomplex *alpha, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, ftnlen side_len, - ftnlen uplo_len, ftnlen transa_len, ftnlen diag_len); -extern int ztrsv_(char *uplo, char *trans, char *diag, integer *n, - doublecomplex *a, integer *lda, doublecomplex *x, - integer *incx, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len); - -#endif diff --git a/include/grass/config.h.in b/include/grass/config.h.in index 95dc2bc034b..2451d8cc2b8 100644 --- a/include/grass/config.h.in +++ b/include/grass/config.h.in @@ -20,12 +20,12 @@ /* Define to 1 if you have the header file. */ #undef HAVE_CAIRO_H +/* Define to 1 if you have the header file. */ +#undef HAVE_CBLAS_ATLAS_H + /* Define to 1 if you have the header file. */ #undef HAVE_CBLAS_H -/* Define to 1 if you have the header file. */ -#undef HAVE_CLAPACK_H - /* Define to 1 if you have the header file. */ #undef HAVE_CL_CL_H @@ -35,9 +35,6 @@ /* Define to 1 if you have the `drand48' function. */ #undef HAVE_DRAND48 -/* Define to 1 if you have the header file. */ -#undef HAVE_F2C_H - /* Define to 1 if you have the header file. */ #undef HAVE_FFTW3_H @@ -53,9 +50,6 @@ /* Define to 1 if you have the `ftime' function. */ #undef HAVE_FTIME -/* Define to 1 if you have the header file. */ -#undef HAVE_G2C_H - /* Define to 1 if GDAL is to be used. */ #undef HAVE_GDAL @@ -89,8 +83,8 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LANGINFO_H -/* Define to 1 if ATLAS exists. */ -#undef HAVE_LIBATLAS +/* Define to 1 if you have the header file. */ +#undef HAVE_LAPACKE_H /* Define to 1 if BLAS exists. */ #undef HAVE_LIBBLAS diff --git a/include/grass/la.h b/include/grass/la.h index 2981dc3401e..edec847c8e1 100644 --- a/include/grass/la.h +++ b/include/grass/la.h @@ -23,93 +23,9 @@ #ifndef GRASS_LA_H #define GRASS_LA_H -/* QUESTION: On some systems there appears to be no default link - to this. Do we create a symlink to - /usr/lib/gcc-lib///include/g2c.h - - or link to any old f2c.h that happens to hanging around? - - A job for autoconf - - [Also a consideration for -lg2c] - */ - #include #include -#ifdef HAVE_G2C_H -typedef int __g77_integer; -typedef unsigned int __g77_uinteger; -typedef long int __g77_longint; -typedef unsigned long int __g77_ulongint; - -#include -#else /* for gcc4+ */ -typedef int integer; -typedef unsigned int uinteger; -typedef char *address; -typedef short shortint; -typedef float real; -typedef double doublereal; -typedef struct { - real r, i; -} complex; -typedef struct { - doublereal r, i; -} doublecomplex; -typedef int logical; -typedef short shortlogical; -typedef char logical1; -typedef char integer1; -typedef long longint; -typedef unsigned long ulongint; - -/* IO stuff */ -typedef int ftnlen; - -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wstrict-prototypes" -#elif defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstrict-prototypes" -#endif - -/* procedure parameter types for -A */ -typedef int (*U_fp)(); -typedef shortint (*J_fp)(); -typedef integer (*I_fp)(); -typedef real (*R_fp)(); -typedef doublereal (*D_fp)(), (*E_fp)(); -typedef void (*C_fp)(); -typedef void (*Z_fp)(); -typedef logical (*L_fp)(); -typedef shortlogical (*K_fp)(); -typedef void (*H_fp)(); -typedef int (*S_fp)(); - -#if defined(__clang__) -#pragma clang diagnostic pop -#elif defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - -/* E_fp is for real functions when -R is not specified */ -typedef void C_f; /* complex function */ -typedef void H_f; /* character function */ -typedef void Z_f; /* double complex function */ -typedef doublereal E_f; /* real function with -R not specified */ -#endif /* HAVE_G2C_H */ - -/* The following may have to be selectively installed according - to platform, at least partly - */ - -#if defined(HAVE_LIBBLAS) && defined(HAVE_LIBLAPACK) -#include -#include -#endif - /* Useful defines */ #define MAX_POS 1 /* Indicates maximum value */ @@ -117,17 +33,7 @@ typedef doublereal E_f; /* real function with -R not specified */ #define MAX_ABS 0 /* Indicates absolute value */ #define DO_COMPACT 0 /* Eliminate unnecessary rows (cols) in matrix */ -#define NO_COMPACT 1 /* ... or not */ - -/* define macros for fortran symbols (called directly). Needed because - of platform invariance on fortran->C symbol translations - */ - -#if defined(HAVE_LIBBLAS) && defined(HAVE_LIBLAPACK) -#define f77_dgesv dgesv_ -#define f77_dgemm dgemm_ -#define f77_dnrm2 dnrm2_ -#endif +#define NO_COMPACT 1 /* ... or not */ /* Operations should know type of coefficient matrix, so that they can call the right driver @@ -146,16 +52,16 @@ typedef enum { RVEC, CVEC } vtype; typedef struct matrix_ { - mat_spec type; /* matrix, row vector or column vector? */ - int v_indx; /* If a vector, which row(column) is active? - * If a matrix this is ignored. If value is < 0, - * the first row(column) is assumed, ie. index 0. */ - int rows, cols; /* Rows and columns of matrix */ - int ldim; /* Lead dimension of matrix. How many `rows' are - * alloc'ed? May exceed real number of rows `rows' */ - doublereal *vals; /* The values (should be dimensioned to lda * cols */ - int is_init; /* Is matrix initialised: values array - * is allocated and parameters set ? */ + mat_spec type; /* matrix, row vector or column vector? */ + int v_indx; /* If a vector, which row(column) is active? + * If a matrix this is ignored. If value is < 0, + * the first row(column) is assumed, ie. index 0. */ + int rows, cols; /* Rows and columns of matrix */ + int ldim; /* Lead dimension of matrix. How many `rows' are + * alloc'ed? May exceed real number of rows `rows' */ + double *vals; /* The values (should be dimensioned to lda * cols */ + int is_init; /* Is matrix initialised: values array + * is allocated and parameters set ? */ } mat_struct; typedef mat_struct vec_struct; diff --git a/include/grass/lapack.h b/include/grass/lapack.h deleted file mode 100644 index 2763404ae8c..00000000000 --- a/include/grass/lapack.h +++ /dev/null @@ -1,4748 +0,0 @@ -#ifndef LAPACK_WRAP_ -#define LAPACK_WRAP_ - -extern int cbdsqr_(char *uplo, integer *n, integer *ncvt, integer *nru, - integer *ncc, real *d__, real *e, complex *vt, integer *ldvt, - complex *u, integer *ldu, complex *c__, integer *ldc, - real *rwork, integer *info, ftnlen uplo_len); -extern int cgbbrd_(char *vect, integer *m, integer *n, integer *ncc, - integer *kl, integer *ku, complex *ab, integer *ldab, - real *d__, real *e, complex *q, integer *ldq, complex *pt, - integer *ldpt, complex *c__, integer *ldc, complex *work, - real *rwork, integer *info, ftnlen vect_len); -extern int cgbcon_(char *norm, integer *n, integer *kl, integer *ku, - complex *ab, integer *ldab, integer *ipiv, real *anorm, - real *rcond, complex *work, real *rwork, integer *info, - ftnlen norm_len); -extern int cgbequ_(integer *m, integer *n, integer *kl, integer *ku, - complex *ab, integer *ldab, real *r__, real *c__, - real *rowcnd, real *colcnd, real *amax, integer *info); -extern int cgbrfs_(char *trans, integer *n, integer *kl, integer *ku, - integer *nrhs, complex *ab, integer *ldab, complex *afb, - integer *ldafb, integer *ipiv, complex *b, integer *ldb, - complex *x, integer *ldx, real *ferr, real *berr, - complex *work, real *rwork, integer *info, ftnlen trans_len); -extern int cgbsv_(integer *n, integer *kl, integer *ku, integer *nrhs, - complex *ab, integer *ldab, integer *ipiv, complex *b, - integer *ldb, integer *info); -extern int cgbsvx_(char *fact, char *trans, integer *n, integer *kl, - integer *ku, integer *nrhs, complex *ab, integer *ldab, - complex *afb, integer *ldafb, integer *ipiv, char *equed, - real *r__, real *c__, complex *b, integer *ldb, complex *x, - integer *ldx, real *rcond, real *ferr, real *berr, - complex *work, real *rwork, integer *info, ftnlen fact_len, - ftnlen trans_len, ftnlen equed_len); -extern int cgbtf2_(integer *m, integer *n, integer *kl, integer *ku, - complex *ab, integer *ldab, integer *ipiv, integer *info); -extern int cgbtrf_(integer *m, integer *n, integer *kl, integer *ku, - complex *ab, integer *ldab, integer *ipiv, integer *info); -extern int cgbtrs_(char *trans, integer *n, integer *kl, integer *ku, - integer *nrhs, complex *ab, integer *ldab, integer *ipiv, - complex *b, integer *ldb, integer *info, ftnlen trans_len); -extern int cgebak_(char *job, char *side, integer *n, integer *ilo, - integer *ihi, real *scale, integer *m, complex *v, - integer *ldv, integer *info, ftnlen job_len, - ftnlen side_len); -extern int cgebal_(char *job, integer *n, complex *a, integer *lda, - integer *ilo, integer *ihi, real *scale, integer *info, - ftnlen job_len); -extern int cgebd2_(integer *m, integer *n, complex *a, integer *lda, real *d__, - real *e, complex *tauq, complex *taup, complex *work, - integer *info); -extern int cgebrd_(integer *m, integer *n, complex *a, integer *lda, real *d__, - real *e, complex *tauq, complex *taup, complex *work, - integer *lwork, integer *info); -extern int cgecon_(char *norm, integer *n, complex *a, integer *lda, - real *anorm, real *rcond, complex *work, real *rwork, - integer *info, ftnlen norm_len); -extern int cgeequ_(integer *m, integer *n, complex *a, integer *lda, real *r__, - real *c__, real *rowcnd, real *colcnd, real *amax, - integer *info); -extern int cgees_(char *jobvs, char *sort, L_fp select, integer *n, complex *a, - integer *lda, integer *sdim, complex *w, complex *vs, - integer *ldvs, complex *work, integer *lwork, real *rwork, - logical *bwork, integer *info, ftnlen jobvs_len, - ftnlen sort_len); -extern int cgeesx_(char *jobvs, char *sort, L_fp select, char *sense, - integer *n, complex *a, integer *lda, integer *sdim, - complex *w, complex *vs, integer *ldvs, real *rconde, - real *rcondv, complex *work, integer *lwork, real *rwork, - logical *bwork, integer *info, ftnlen jobvs_len, - ftnlen sort_len, ftnlen sense_len); -extern int cgeev_(char *jobvl, char *jobvr, integer *n, complex *a, - integer *lda, complex *w, complex *vl, integer *ldvl, - complex *vr, integer *ldvr, complex *work, integer *lwork, - real *rwork, integer *info, ftnlen jobvl_len, - ftnlen jobvr_len); -extern int cgeevx_(char *balanc, char *jobvl, char *jobvr, char *sense, - integer *n, complex *a, integer *lda, complex *w, - complex *vl, integer *ldvl, complex *vr, integer *ldvr, - integer *ilo, integer *ihi, real *scale, real *abnrm, - real *rconde, real *rcondv, complex *work, integer *lwork, - real *rwork, integer *info, ftnlen balanc_len, - ftnlen jobvl_len, ftnlen jobvr_len, ftnlen sense_len); -extern int cgegs_(char *jobvsl, char *jobvsr, integer *n, complex *a, - integer *lda, complex *b, integer *ldb, complex *alpha, - complex *beta, complex *vsl, integer *ldvsl, complex *vsr, - integer *ldvsr, complex *work, integer *lwork, real *rwork, - integer *info, ftnlen jobvsl_len, ftnlen jobvsr_len); -extern int cgegv_(char *jobvl, char *jobvr, integer *n, complex *a, - integer *lda, complex *b, integer *ldb, complex *alpha, - complex *beta, complex *vl, integer *ldvl, complex *vr, - integer *ldvr, complex *work, integer *lwork, real *rwork, - integer *info, ftnlen jobvl_len, ftnlen jobvr_len); -extern int cgehd2_(integer *n, integer *ilo, integer *ihi, complex *a, - integer *lda, complex *tau, complex *work, integer *info); -extern int cgehrd_(integer *n, integer *ilo, integer *ihi, complex *a, - integer *lda, complex *tau, complex *work, integer *lwork, - integer *info); -extern int cgelq2_(integer *m, integer *n, complex *a, integer *lda, - complex *tau, complex *work, integer *info); -extern int cgelqf_(integer *m, integer *n, complex *a, integer *lda, - complex *tau, complex *work, integer *lwork, integer *info); -extern int cgels_(char *trans, integer *m, integer *n, integer *nrhs, - complex *a, integer *lda, complex *b, integer *ldb, - complex *work, integer *lwork, integer *info, - ftnlen trans_len); -extern int cgelsd_(integer *m, integer *n, integer *nrhs, complex *a, - integer *lda, complex *b, integer *ldb, real *s, real *rcond, - integer *rank, complex *work, integer *lwork, real *rwork, - integer *iwork, integer *info); -extern int cgelss_(integer *m, integer *n, integer *nrhs, complex *a, - integer *lda, complex *b, integer *ldb, real *s, real *rcond, - integer *rank, complex *work, integer *lwork, real *rwork, - integer *info); -extern int cgelsx_(integer *m, integer *n, integer *nrhs, complex *a, - integer *lda, complex *b, integer *ldb, integer *jpvt, - real *rcond, integer *rank, complex *work, real *rwork, - integer *info); -extern int cgelsy_(integer *m, integer *n, integer *nrhs, complex *a, - integer *lda, complex *b, integer *ldb, integer *jpvt, - real *rcond, integer *rank, complex *work, integer *lwork, - real *rwork, integer *info); -extern int cgeql2_(integer *m, integer *n, complex *a, integer *lda, - complex *tau, complex *work, integer *info); -extern int cgeqlf_(integer *m, integer *n, complex *a, integer *lda, - complex *tau, complex *work, integer *lwork, integer *info); -extern int cgeqp3_(integer *m, integer *n, complex *a, integer *lda, - integer *jpvt, complex *tau, complex *work, integer *lwork, - real *rwork, integer *info); -extern int cgeqpf_(integer *m, integer *n, complex *a, integer *lda, - integer *jpvt, complex *tau, complex *work, real *rwork, - integer *info); -extern int cgeqr2_(integer *m, integer *n, complex *a, integer *lda, - complex *tau, complex *work, integer *info); -extern int cgeqrf_(integer *m, integer *n, complex *a, integer *lda, - complex *tau, complex *work, integer *lwork, integer *info); -extern int cgerfs_(char *trans, integer *n, integer *nrhs, complex *a, - integer *lda, complex *af, integer *ldaf, integer *ipiv, - complex *b, integer *ldb, complex *x, integer *ldx, - real *ferr, real *berr, complex *work, real *rwork, - integer *info, ftnlen trans_len); -extern int cgerq2_(integer *m, integer *n, complex *a, integer *lda, - complex *tau, complex *work, integer *info); -extern int cgerqf_(integer *m, integer *n, complex *a, integer *lda, - complex *tau, complex *work, integer *lwork, integer *info); -extern int cgesc2_(integer *n, complex *a, integer *lda, complex *rhs, - integer *ipiv, integer *jpiv, real *scale); -extern int cgesdd_(char *jobz, integer *m, integer *n, complex *a, integer *lda, - real *s, complex *u, integer *ldu, complex *vt, - integer *ldvt, complex *work, integer *lwork, real *rwork, - integer *iwork, integer *info, ftnlen jobz_len); -extern int cgesv_(integer *n, integer *nrhs, complex *a, integer *lda, - integer *ipiv, complex *b, integer *ldb, integer *info); -extern int cgesvd_(char *jobu, char *jobvt, integer *m, integer *n, complex *a, - integer *lda, real *s, complex *u, integer *ldu, complex *vt, - integer *ldvt, complex *work, integer *lwork, real *rwork, - integer *info, ftnlen jobu_len, ftnlen jobvt_len); -extern int cgesvx_(char *fact, char *trans, integer *n, integer *nrhs, - complex *a, integer *lda, complex *af, integer *ldaf, - integer *ipiv, char *equed, real *r__, real *c__, complex *b, - integer *ldb, complex *x, integer *ldx, real *rcond, - real *ferr, real *berr, complex *work, real *rwork, - integer *info, ftnlen fact_len, ftnlen trans_len, - ftnlen equed_len); -extern int cgetc2_(integer *n, complex *a, integer *lda, integer *ipiv, - integer *jpiv, integer *info); -extern int cgetf2_(integer *m, integer *n, complex *a, integer *lda, - integer *ipiv, integer *info); -extern int cgetrf_(integer *m, integer *n, complex *a, integer *lda, - integer *ipiv, integer *info); -extern int cgetri_(integer *n, complex *a, integer *lda, integer *ipiv, - complex *work, integer *lwork, integer *info); -extern int cgetrs_(char *trans, integer *n, integer *nrhs, complex *a, - integer *lda, integer *ipiv, complex *b, integer *ldb, - integer *info, ftnlen trans_len); -extern int cggbak_(char *job, char *side, integer *n, integer *ilo, - integer *ihi, real *lscale, real *rscale, integer *m, - complex *v, integer *ldv, integer *info, ftnlen job_len, - ftnlen side_len); -extern int cggbal_(char *job, integer *n, complex *a, integer *lda, complex *b, - integer *ldb, integer *ilo, integer *ihi, real *lscale, - real *rscale, real *work, integer *info, ftnlen job_len); -extern int cgges_(char *jobvsl, char *jobvsr, char *sort, L_fp selctg, - integer *n, complex *a, integer *lda, complex *b, - integer *ldb, integer *sdim, complex *alpha, complex *beta, - complex *vsl, integer *ldvsl, complex *vsr, integer *ldvsr, - complex *work, integer *lwork, real *rwork, logical *bwork, - integer *info, ftnlen jobvsl_len, ftnlen jobvsr_len, - ftnlen sort_len); -extern int cggesx_(char *jobvsl, char *jobvsr, char *sort, L_fp selctg, - char *sense, integer *n, complex *a, integer *lda, - complex *b, integer *ldb, integer *sdim, complex *alpha, - complex *beta, complex *vsl, integer *ldvsl, complex *vsr, - integer *ldvsr, real *rconde, real *rcondv, complex *work, - integer *lwork, real *rwork, integer *iwork, integer *liwork, - logical *bwork, integer *info, ftnlen jobvsl_len, - ftnlen jobvsr_len, ftnlen sort_len, ftnlen sense_len); -extern int cggev_(char *jobvl, char *jobvr, integer *n, complex *a, - integer *lda, complex *b, integer *ldb, complex *alpha, - complex *beta, complex *vl, integer *ldvl, complex *vr, - integer *ldvr, complex *work, integer *lwork, real *rwork, - integer *info, ftnlen jobvl_len, ftnlen jobvr_len); -extern int cggevx_(char *balanc, char *jobvl, char *jobvr, char *sense, - integer *n, complex *a, integer *lda, complex *b, - integer *ldb, complex *alpha, complex *beta, complex *vl, - integer *ldvl, complex *vr, integer *ldvr, integer *ilo, - integer *ihi, real *lscale, real *rscale, real *abnrm, - real *bbnrm, real *rconde, real *rcondv, complex *work, - integer *lwork, real *rwork, integer *iwork, logical *bwork, - integer *info, ftnlen balanc_len, ftnlen jobvl_len, - ftnlen jobvr_len, ftnlen sense_len); -extern int cggglm_(integer *n, integer *m, integer *p, complex *a, integer *lda, - complex *b, integer *ldb, complex *d__, complex *x, - complex *y, complex *work, integer *lwork, integer *info); -extern int cgghrd_(char *compq, char *compz, integer *n, integer *ilo, - integer *ihi, complex *a, integer *lda, complex *b, - integer *ldb, complex *q, integer *ldq, complex *z__, - integer *ldz, integer *info, ftnlen compq_len, - ftnlen compz_len); -extern int cgglse_(integer *m, integer *n, integer *p, complex *a, integer *lda, - complex *b, integer *ldb, complex *c__, complex *d__, - complex *x, complex *work, integer *lwork, integer *info); -extern int cggqrf_(integer *n, integer *m, integer *p, complex *a, integer *lda, - complex *taua, complex *b, integer *ldb, complex *taub, - complex *work, integer *lwork, integer *info); -extern int cggrqf_(integer *m, integer *p, integer *n, complex *a, integer *lda, - complex *taua, complex *b, integer *ldb, complex *taub, - complex *work, integer *lwork, integer *info); -extern int cggsvd_(char *jobu, char *jobv, char *jobq, integer *m, integer *n, - integer *p, integer *k, integer *l, complex *a, integer *lda, - complex *b, integer *ldb, real *alpha, real *beta, - complex *u, integer *ldu, complex *v, integer *ldv, - complex *q, integer *ldq, complex *work, real *rwork, - integer *iwork, integer *info, ftnlen jobu_len, - ftnlen jobv_len, ftnlen jobq_len); -extern int cggsvp_(char *jobu, char *jobv, char *jobq, integer *m, integer *p, - integer *n, complex *a, integer *lda, complex *b, - integer *ldb, real *tola, real *tolb, integer *k, integer *l, - complex *u, integer *ldu, complex *v, integer *ldv, - complex *q, integer *ldq, integer *iwork, real *rwork, - complex *tau, complex *work, integer *info, ftnlen jobu_len, - ftnlen jobv_len, ftnlen jobq_len); -extern int cgtcon_(char *norm, integer *n, complex *dl, complex *d__, - complex *du, complex *du2, integer *ipiv, real *anorm, - real *rcond, complex *work, integer *info, ftnlen norm_len); -extern int cgtrfs_(char *trans, integer *n, integer *nrhs, complex *dl, - complex *d__, complex *du, complex *dlf, complex *df, - complex *duf, complex *du2, integer *ipiv, complex *b, - integer *ldb, complex *x, integer *ldx, real *ferr, - real *berr, complex *work, real *rwork, integer *info, - ftnlen trans_len); -extern int cgtsv_(integer *n, integer *nrhs, complex *dl, complex *d__, - complex *du, complex *b, integer *ldb, integer *info); -extern int cgtsvx_(char *fact, char *trans, integer *n, integer *nrhs, - complex *dl, complex *d__, complex *du, complex *dlf, - complex *df, complex *duf, complex *du2, integer *ipiv, - complex *b, integer *ldb, complex *x, integer *ldx, - real *rcond, real *ferr, real *berr, complex *work, - real *rwork, integer *info, ftnlen fact_len, - ftnlen trans_len); -extern int cgttrf_(integer *n, complex *dl, complex *d__, complex *du, - complex *du2, integer *ipiv, integer *info); -extern int cgttrs_(char *trans, integer *n, integer *nrhs, complex *dl, - complex *d__, complex *du, complex *du2, integer *ipiv, - complex *b, integer *ldb, integer *info, ftnlen trans_len); -extern int cgtts2_(integer *itrans, integer *n, integer *nrhs, complex *dl, - complex *d__, complex *du, complex *du2, integer *ipiv, - complex *b, integer *ldb); -extern int chbev_(char *jobz, char *uplo, integer *n, integer *kd, complex *ab, - integer *ldab, real *w, complex *z__, integer *ldz, - complex *work, real *rwork, integer *info, ftnlen jobz_len, - ftnlen uplo_len); -extern int chbevd_(char *jobz, char *uplo, integer *n, integer *kd, complex *ab, - integer *ldab, real *w, complex *z__, integer *ldz, - complex *work, integer *lwork, real *rwork, integer *lrwork, - integer *iwork, integer *liwork, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int chbevx_(char *jobz, char *range, char *uplo, integer *n, integer *kd, - complex *ab, integer *ldab, complex *q, integer *ldq, - real *vl, real *vu, integer *il, integer *iu, real *abstol, - integer *m, real *w, complex *z__, integer *ldz, - complex *work, real *rwork, integer *iwork, integer *ifail, - integer *info, ftnlen jobz_len, ftnlen range_len, - ftnlen uplo_len); -extern int chbgst_(char *vect, char *uplo, integer *n, integer *ka, integer *kb, - complex *ab, integer *ldab, complex *bb, integer *ldbb, - complex *x, integer *ldx, complex *work, real *rwork, - integer *info, ftnlen vect_len, ftnlen uplo_len); -extern int chbgv_(char *jobz, char *uplo, integer *n, integer *ka, integer *kb, - complex *ab, integer *ldab, complex *bb, integer *ldbb, - real *w, complex *z__, integer *ldz, complex *work, - real *rwork, integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int chbgvd_(char *jobz, char *uplo, integer *n, integer *ka, integer *kb, - complex *ab, integer *ldab, complex *bb, integer *ldbb, - real *w, complex *z__, integer *ldz, complex *work, - integer *lwork, real *rwork, integer *lrwork, integer *iwork, - integer *liwork, integer *info, ftnlen jobz_len, - ftnlen uplo_len); -extern int chbgvx_(char *jobz, char *range, char *uplo, integer *n, integer *ka, - integer *kb, complex *ab, integer *ldab, complex *bb, - integer *ldbb, complex *q, integer *ldq, real *vl, real *vu, - integer *il, integer *iu, real *abstol, integer *m, real *w, - complex *z__, integer *ldz, complex *work, real *rwork, - integer *iwork, integer *ifail, integer *info, - ftnlen jobz_len, ftnlen range_len, ftnlen uplo_len); -extern int chbtrd_(char *vect, char *uplo, integer *n, integer *kd, complex *ab, - integer *ldab, real *d__, real *e, complex *q, integer *ldq, - complex *work, integer *info, ftnlen vect_len, - ftnlen uplo_len); -extern int checon_(char *uplo, integer *n, complex *a, integer *lda, - integer *ipiv, real *anorm, real *rcond, complex *work, - integer *info, ftnlen uplo_len); -extern int cheev_(char *jobz, char *uplo, integer *n, complex *a, integer *lda, - real *w, complex *work, integer *lwork, real *rwork, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int cheevd_(char *jobz, char *uplo, integer *n, complex *a, integer *lda, - real *w, complex *work, integer *lwork, real *rwork, - integer *lrwork, integer *iwork, integer *liwork, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int cheevr_(char *jobz, char *range, char *uplo, integer *n, complex *a, - integer *lda, real *vl, real *vu, integer *il, integer *iu, - real *abstol, integer *m, real *w, complex *z__, - integer *ldz, integer *isuppz, complex *work, integer *lwork, - real *rwork, integer *lrwork, integer *iwork, - integer *liwork, integer *info, ftnlen jobz_len, - ftnlen range_len, ftnlen uplo_len); -extern int cheevx_(char *jobz, char *range, char *uplo, integer *n, complex *a, - integer *lda, real *vl, real *vu, integer *il, integer *iu, - real *abstol, integer *m, real *w, complex *z__, - integer *ldz, complex *work, integer *lwork, real *rwork, - integer *iwork, integer *ifail, integer *info, - ftnlen jobz_len, ftnlen range_len, ftnlen uplo_len); -extern int chegs2_(integer *itype, char *uplo, integer *n, complex *a, - integer *lda, complex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int chegst_(integer *itype, char *uplo, integer *n, complex *a, - integer *lda, complex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int chegv_(integer *itype, char *jobz, char *uplo, integer *n, - complex *a, integer *lda, complex *b, integer *ldb, real *w, - complex *work, integer *lwork, real *rwork, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int chegvd_(integer *itype, char *jobz, char *uplo, integer *n, - complex *a, integer *lda, complex *b, integer *ldb, real *w, - complex *work, integer *lwork, real *rwork, integer *lrwork, - integer *iwork, integer *liwork, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int chegvx_(integer *itype, char *jobz, char *range, char *uplo, - integer *n, complex *a, integer *lda, complex *b, - integer *ldb, real *vl, real *vu, integer *il, integer *iu, - real *abstol, integer *m, real *w, complex *z__, - integer *ldz, complex *work, integer *lwork, real *rwork, - integer *iwork, integer *ifail, integer *info, - ftnlen jobz_len, ftnlen range_len, ftnlen uplo_len); -extern int cherfs_(char *uplo, integer *n, integer *nrhs, complex *a, - integer *lda, complex *af, integer *ldaf, integer *ipiv, - complex *b, integer *ldb, complex *x, integer *ldx, - real *ferr, real *berr, complex *work, real *rwork, - integer *info, ftnlen uplo_len); -extern int chesv_(char *uplo, integer *n, integer *nrhs, complex *a, - integer *lda, integer *ipiv, complex *b, integer *ldb, - complex *work, integer *lwork, integer *info, - ftnlen uplo_len); -extern int chesvx_(char *fact, char *uplo, integer *n, integer *nrhs, - complex *a, integer *lda, complex *af, integer *ldaf, - integer *ipiv, complex *b, integer *ldb, complex *x, - integer *ldx, real *rcond, real *ferr, real *berr, - complex *work, integer *lwork, real *rwork, integer *info, - ftnlen fact_len, ftnlen uplo_len); -extern int chetd2_(char *uplo, integer *n, complex *a, integer *lda, real *d__, - real *e, complex *tau, integer *info, ftnlen uplo_len); -extern int chetf2_(char *uplo, integer *n, complex *a, integer *lda, - integer *ipiv, integer *info, ftnlen uplo_len); -extern int chetrd_(char *uplo, integer *n, complex *a, integer *lda, real *d__, - real *e, complex *tau, complex *work, integer *lwork, - integer *info, ftnlen uplo_len); -extern int chetrf_(char *uplo, integer *n, complex *a, integer *lda, - integer *ipiv, complex *work, integer *lwork, integer *info, - ftnlen uplo_len); -extern int chetri_(char *uplo, integer *n, complex *a, integer *lda, - integer *ipiv, complex *work, integer *info, - ftnlen uplo_len); -extern int chetrs_(char *uplo, integer *n, integer *nrhs, complex *a, - integer *lda, integer *ipiv, complex *b, integer *ldb, - integer *info, ftnlen uplo_len); -extern int chgeqz_(char *job, char *compq, char *compz, integer *n, - integer *ilo, integer *ihi, complex *a, integer *lda, - complex *b, integer *ldb, complex *alpha, complex *beta, - complex *q, integer *ldq, complex *z__, integer *ldz, - complex *work, integer *lwork, real *rwork, integer *info, - ftnlen job_len, ftnlen compq_len, ftnlen compz_len); -extern int chpcon_(char *uplo, integer *n, complex *ap, integer *ipiv, - real *anorm, real *rcond, complex *work, integer *info, - ftnlen uplo_len); -extern int chpev_(char *jobz, char *uplo, integer *n, complex *ap, real *w, - complex *z__, integer *ldz, complex *work, real *rwork, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int chpevd_(char *jobz, char *uplo, integer *n, complex *ap, real *w, - complex *z__, integer *ldz, complex *work, integer *lwork, - real *rwork, integer *lrwork, integer *iwork, - integer *liwork, integer *info, ftnlen jobz_len, - ftnlen uplo_len); -extern int chpevx_(char *jobz, char *range, char *uplo, integer *n, complex *ap, - real *vl, real *vu, integer *il, integer *iu, real *abstol, - integer *m, real *w, complex *z__, integer *ldz, - complex *work, real *rwork, integer *iwork, integer *ifail, - integer *info, ftnlen jobz_len, ftnlen range_len, - ftnlen uplo_len); -extern int chpgst_(integer *itype, char *uplo, integer *n, complex *ap, - complex *bp, integer *info, ftnlen uplo_len); -extern int chpgv_(integer *itype, char *jobz, char *uplo, integer *n, - complex *ap, complex *bp, real *w, complex *z__, integer *ldz, - complex *work, real *rwork, integer *info, ftnlen jobz_len, - ftnlen uplo_len); -extern int chpgvd_(integer *itype, char *jobz, char *uplo, integer *n, - complex *ap, complex *bp, real *w, complex *z__, - integer *ldz, complex *work, integer *lwork, real *rwork, - integer *lrwork, integer *iwork, integer *liwork, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int chpgvx_(integer *itype, char *jobz, char *range, char *uplo, - integer *n, complex *ap, complex *bp, real *vl, real *vu, - integer *il, integer *iu, real *abstol, integer *m, real *w, - complex *z__, integer *ldz, complex *work, real *rwork, - integer *iwork, integer *ifail, integer *info, - ftnlen jobz_len, ftnlen range_len, ftnlen uplo_len); -extern int chprfs_(char *uplo, integer *n, integer *nrhs, complex *ap, - complex *afp, integer *ipiv, complex *b, integer *ldb, - complex *x, integer *ldx, real *ferr, real *berr, - complex *work, real *rwork, integer *info, ftnlen uplo_len); -extern int chpsv_(char *uplo, integer *n, integer *nrhs, complex *ap, - integer *ipiv, complex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int chpsvx_(char *fact, char *uplo, integer *n, integer *nrhs, - complex *ap, complex *afp, integer *ipiv, complex *b, - integer *ldb, complex *x, integer *ldx, real *rcond, - real *ferr, real *berr, complex *work, real *rwork, - integer *info, ftnlen fact_len, ftnlen uplo_len); -extern int chptrd_(char *uplo, integer *n, complex *ap, real *d__, real *e, - complex *tau, integer *info, ftnlen uplo_len); -extern int chptrf_(char *uplo, integer *n, complex *ap, integer *ipiv, - integer *info, ftnlen uplo_len); -extern int chptri_(char *uplo, integer *n, complex *ap, integer *ipiv, - complex *work, integer *info, ftnlen uplo_len); -extern int chptrs_(char *uplo, integer *n, integer *nrhs, complex *ap, - integer *ipiv, complex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int chsein_(char *side, char *eigsrc, char *initv, logical *select, - integer *n, complex *h__, integer *ldh, complex *w, - complex *vl, integer *ldvl, complex *vr, integer *ldvr, - integer *mm, integer *m, complex *work, real *rwork, - integer *ifaill, integer *ifailr, integer *info, - ftnlen side_len, ftnlen eigsrc_len, ftnlen initv_len); -extern int chseqr_(char *job, char *compz, integer *n, integer *ilo, - integer *ihi, complex *h__, integer *ldh, complex *w, - complex *z__, integer *ldz, complex *work, integer *lwork, - integer *info, ftnlen job_len, ftnlen compz_len); -extern int clabrd_(integer *m, integer *n, integer *nb, complex *a, - integer *lda, real *d__, real *e, complex *tauq, - complex *taup, complex *x, integer *ldx, complex *y, - integer *ldy); -extern int clacgv_(integer *n, complex *x, integer *incx); -extern int clacon_(integer *n, complex *v, complex *x, real *est, - integer *kase); -extern int clacp2_(char *uplo, integer *m, integer *n, real *a, integer *lda, - complex *b, integer *ldb, ftnlen uplo_len); -extern int clacpy_(char *uplo, integer *m, integer *n, complex *a, integer *lda, - complex *b, integer *ldb, ftnlen uplo_len); -extern int clacrm_(integer *m, integer *n, complex *a, integer *lda, real *b, - integer *ldb, complex *c__, integer *ldc, real *rwork); -extern int clacrt_(integer *n, complex *cx, integer *incx, complex *cy, - integer *incy, complex *c__, complex *s); -extern C_f cladiv_(complex *ret_val, complex *x, complex *y); -extern int claed0_(integer *qsiz, integer *n, real *d__, real *e, complex *q, - integer *ldq, complex *qstore, integer *ldqs, real *rwork, - integer *iwork, integer *info); -extern int claed7_(integer *n, integer *cutpnt, integer *qsiz, integer *tlvls, - integer *curlvl, integer *curpbm, real *d__, complex *q, - integer *ldq, real *rho, integer *indxq, real *qstore, - integer *qptr, integer *prmptr, integer *perm, - integer *givptr, integer *givcol, real *givnum, - complex *work, real *rwork, integer *iwork, integer *info); -extern int claed8_(integer *k, integer *n, integer *qsiz, complex *q, - integer *ldq, real *d__, real *rho, integer *cutpnt, - real *z__, real *dlamda, complex *q2, integer *ldq2, real *w, - integer *indxp, integer *indx, integer *indxq, integer *perm, - integer *givptr, integer *givcol, real *givnum, - integer *info); -extern int claein_(logical *rightv, logical *noinit, integer *n, complex *h__, - integer *ldh, complex *w, complex *v, complex *b, - integer *ldb, real *rwork, real *eps3, real *smlnum, - integer *info); -extern int claesy_(complex *a, complex *b, complex *c__, complex *rt1, - complex *rt2, complex *evscal, complex *cs1, complex *sn1); -extern int claev2_(complex *a, complex *b, complex *c__, real *rt1, real *rt2, - real *cs1, complex *sn1); -extern int clags2_(logical *upper, real *a1, complex *a2, real *a3, real *b1, - complex *b2, real *b3, real *csu, complex *snu, real *csv, - complex *snv, real *csq, complex *snq); -extern int clagtm_(char *trans, integer *n, integer *nrhs, real *alpha, - complex *dl, complex *d__, complex *du, complex *x, - integer *ldx, real *beta, complex *b, integer *ldb, - ftnlen trans_len); -extern int clahef_(char *uplo, integer *n, integer *nb, integer *kb, complex *a, - integer *lda, integer *ipiv, complex *w, integer *ldw, - integer *info, ftnlen uplo_len); -extern int clahqr_(logical *wantt, logical *wantz, integer *n, integer *ilo, - integer *ihi, complex *h__, integer *ldh, complex *w, - integer *iloz, integer *ihiz, complex *z__, integer *ldz, - integer *info); -extern int clahrd_(integer *n, integer *k, integer *nb, complex *a, - integer *lda, complex *tau, complex *t, integer *ldt, - complex *y, integer *ldy); -extern int claic1_(integer *job, integer *j, complex *x, real *sest, complex *w, - complex *gamma, real *sestpr, complex *s, complex *c__); -extern int clals0_(integer *icompq, integer *nl, integer *nr, integer *sqre, - integer *nrhs, complex *b, integer *ldb, complex *bx, - integer *ldbx, integer *perm, integer *givptr, - integer *givcol, integer *ldgcol, real *givnum, - integer *ldgnum, real *poles, real *difl, real *difr, - real *z__, integer *k, real *c__, real *s, real *rwork, - integer *info); -extern int clalsa_(integer *icompq, integer *smlsiz, integer *n, integer *nrhs, - complex *b, integer *ldb, complex *bx, integer *ldbx, - real *u, integer *ldu, real *vt, integer *k, real *difl, - real *difr, real *z__, real *poles, integer *givptr, - integer *givcol, integer *ldgcol, integer *perm, - real *givnum, real *c__, real *s, real *rwork, - integer *iwork, integer *info); -extern int clalsd_(char *uplo, integer *smlsiz, integer *n, integer *nrhs, - real *d__, real *e, complex *b, integer *ldb, real *rcond, - integer *rank, complex *work, real *rwork, integer *iwork, - integer *info, ftnlen uplo_len); -extern E_f clangb_(char *norm, integer *n, integer *kl, integer *ku, - complex *ab, integer *ldab, real *work, ftnlen norm_len); -extern E_f clange_(char *norm, integer *m, integer *n, complex *a, integer *lda, - real *work, ftnlen norm_len); -extern E_f clangt_(char *norm, integer *n, complex *dl, complex *d__, - complex *du, ftnlen norm_len); -extern E_f clanhb_(char *norm, char *uplo, integer *n, integer *k, complex *ab, - integer *ldab, real *work, ftnlen norm_len, ftnlen uplo_len); -extern E_f clanhe_(char *norm, char *uplo, integer *n, complex *a, integer *lda, - real *work, ftnlen norm_len, ftnlen uplo_len); -extern E_f clanhp_(char *norm, char *uplo, integer *n, complex *ap, real *work, - ftnlen norm_len, ftnlen uplo_len); -extern E_f clanhs_(char *norm, integer *n, complex *a, integer *lda, real *work, - ftnlen norm_len); -extern E_f clanht_(char *norm, integer *n, real *d__, complex *e, - ftnlen norm_len); -extern E_f clansb_(char *norm, char *uplo, integer *n, integer *k, complex *ab, - integer *ldab, real *work, ftnlen norm_len, ftnlen uplo_len); -extern E_f clansp_(char *norm, char *uplo, integer *n, complex *ap, real *work, - ftnlen norm_len, ftnlen uplo_len); -extern E_f clansy_(char *norm, char *uplo, integer *n, complex *a, integer *lda, - real *work, ftnlen norm_len, ftnlen uplo_len); -extern E_f clantb_(char *norm, char *uplo, char *diag, integer *n, integer *k, - complex *ab, integer *ldab, real *work, ftnlen norm_len, - ftnlen uplo_len, ftnlen diag_len); -extern E_f clantp_(char *norm, char *uplo, char *diag, integer *n, complex *ap, - real *work, ftnlen norm_len, ftnlen uplo_len, - ftnlen diag_len); -extern E_f clantr_(char *norm, char *uplo, char *diag, integer *m, integer *n, - complex *a, integer *lda, real *work, ftnlen norm_len, - ftnlen uplo_len, ftnlen diag_len); -extern int clapll_(integer *n, complex *x, integer *incx, complex *y, - integer *incy, real *ssmin); -extern int clapmt_(logical *forwrd, integer *m, integer *n, complex *x, - integer *ldx, integer *k); -extern int claqgb_(integer *m, integer *n, integer *kl, integer *ku, - complex *ab, integer *ldab, real *r__, real *c__, - real *rowcnd, real *colcnd, real *amax, char *equed, - ftnlen equed_len); -extern int claqge_(integer *m, integer *n, complex *a, integer *lda, real *r__, - real *c__, real *rowcnd, real *colcnd, real *amax, - char *equed, ftnlen equed_len); -extern int claqhb_(char *uplo, integer *n, integer *kd, complex *ab, - integer *ldab, real *s, real *scond, real *amax, char *equed, - ftnlen uplo_len, ftnlen equed_len); -extern int claqhe_(char *uplo, integer *n, complex *a, integer *lda, real *s, - real *scond, real *amax, char *equed, ftnlen uplo_len, - ftnlen equed_len); -extern int claqhp_(char *uplo, integer *n, complex *ap, real *s, real *scond, - real *amax, char *equed, ftnlen uplo_len, ftnlen equed_len); -extern int claqp2_(integer *m, integer *n, integer *offset, complex *a, - integer *lda, integer *jpvt, complex *tau, real *vn1, - real *vn2, complex *work); -extern int claqps_(integer *m, integer *n, integer *offset, integer *nb, - integer *kb, complex *a, integer *lda, integer *jpvt, - complex *tau, real *vn1, real *vn2, complex *auxv, - complex *f, integer *ldf); -extern int claqsb_(char *uplo, integer *n, integer *kd, complex *ab, - integer *ldab, real *s, real *scond, real *amax, char *equed, - ftnlen uplo_len, ftnlen equed_len); -extern int claqsp_(char *uplo, integer *n, complex *ap, real *s, real *scond, - real *amax, char *equed, ftnlen uplo_len, ftnlen equed_len); -extern int claqsy_(char *uplo, integer *n, complex *a, integer *lda, real *s, - real *scond, real *amax, char *equed, ftnlen uplo_len, - ftnlen equed_len); -extern int clar1v_(integer *n, integer *b1, integer *bn, real *sigma, real *d__, - real *l, real *ld, real *lld, real *gersch, complex *z__, - real *ztz, real *mingma, integer *r__, integer *isuppz, - real *work); -extern int clar2v_(integer *n, complex *x, complex *y, complex *z__, - integer *incx, real *c__, complex *s, integer *incc); -extern int clarcm_(integer *m, integer *n, real *a, integer *lda, complex *b, - integer *ldb, complex *c__, integer *ldc, real *rwork); -extern int clarf_(char *side, integer *m, integer *n, complex *v, integer *incv, - complex *tau, complex *c__, integer *ldc, complex *work, - ftnlen side_len); -extern int clarfb_(char *side, char *trans, char *direct, char *storev, - integer *m, integer *n, integer *k, complex *v, integer *ldv, - complex *t, integer *ldt, complex *c__, integer *ldc, - complex *work, integer *ldwork, ftnlen side_len, - ftnlen trans_len, ftnlen direct_len, ftnlen storev_len); -extern int clarfg_(integer *n, complex *alpha, complex *x, integer *incx, - complex *tau); -extern int clarft_(char *direct, char *storev, integer *n, integer *k, - complex *v, integer *ldv, complex *tau, complex *t, - integer *ldt, ftnlen direct_len, ftnlen storev_len); -extern int clarfx_(char *side, integer *m, integer *n, complex *v, complex *tau, - complex *c__, integer *ldc, complex *work, ftnlen side_len); -extern int clargv_(integer *n, complex *x, integer *incx, complex *y, - integer *incy, real *c__, integer *incc); -extern int clarnv_(integer *idist, integer *iseed, integer *n, complex *x); -extern int clarrv_(integer *n, real *d__, real *l, integer *isplit, integer *m, - real *w, integer *iblock, real *gersch, real *tol, - complex *z__, integer *ldz, integer *isuppz, real *work, - integer *iwork, integer *info); -extern int clartg_(complex *f, complex *g, real *cs, complex *sn, complex *r__); -extern int clartv_(integer *n, complex *x, integer *incx, complex *y, - integer *incy, real *c__, complex *s, integer *incc); -extern int clarz_(char *side, integer *m, integer *n, integer *l, complex *v, - integer *incv, complex *tau, complex *c__, integer *ldc, - complex *work, ftnlen side_len); -extern int clarzb_(char *side, char *trans, char *direct, char *storev, - integer *m, integer *n, integer *k, integer *l, complex *v, - integer *ldv, complex *t, integer *ldt, complex *c__, - integer *ldc, complex *work, integer *ldwork, - ftnlen side_len, ftnlen trans_len, ftnlen direct_len, - ftnlen storev_len); -extern int clarzt_(char *direct, char *storev, integer *n, integer *k, - complex *v, integer *ldv, complex *tau, complex *t, - integer *ldt, ftnlen direct_len, ftnlen storev_len); -extern int clascl_(char *type__, integer *kl, integer *ku, real *cfrom, - real *cto, integer *m, integer *n, complex *a, integer *lda, - integer *info, ftnlen type_len); -extern int claset_(char *uplo, integer *m, integer *n, complex *alpha, - complex *beta, complex *a, integer *lda, ftnlen uplo_len); -extern int clasr_(char *side, char *pivot, char *direct, integer *m, integer *n, - real *c__, real *s, complex *a, integer *lda, ftnlen side_len, - ftnlen pivot_len, ftnlen direct_len); -extern int classq_(integer *n, complex *x, integer *incx, real *scale, - real *sumsq); -extern int claswp_(integer *n, complex *a, integer *lda, integer *k1, - integer *k2, integer *ipiv, integer *incx); -extern int clasyf_(char *uplo, integer *n, integer *nb, integer *kb, complex *a, - integer *lda, integer *ipiv, complex *w, integer *ldw, - integer *info, ftnlen uplo_len); -extern int clatbs_(char *uplo, char *trans, char *diag, char *normin, - integer *n, integer *kd, complex *ab, integer *ldab, - complex *x, real *scale, real *cnorm, integer *info, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len, - ftnlen normin_len); -extern int clatdf_(integer *ijob, integer *n, complex *z__, integer *ldz, - complex *rhs, real *rdsum, real *rdscal, integer *ipiv, - integer *jpiv); -extern int clatps_(char *uplo, char *trans, char *diag, char *normin, - integer *n, complex *ap, complex *x, real *scale, - real *cnorm, integer *info, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len, ftnlen normin_len); -extern int clatrd_(char *uplo, integer *n, integer *nb, complex *a, - integer *lda, real *e, complex *tau, complex *w, - integer *ldw, ftnlen uplo_len); -extern int clatrs_(char *uplo, char *trans, char *diag, char *normin, - integer *n, complex *a, integer *lda, complex *x, - real *scale, real *cnorm, integer *info, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len, ftnlen normin_len); -extern int clatrz_(integer *m, integer *n, integer *l, complex *a, integer *lda, - complex *tau, complex *work); -extern int clatzm_(char *side, integer *m, integer *n, complex *v, - integer *incv, complex *tau, complex *c1, complex *c2, - integer *ldc, complex *work, ftnlen side_len); -extern int clauu2_(char *uplo, integer *n, complex *a, integer *lda, - integer *info, ftnlen uplo_len); -extern int clauum_(char *uplo, integer *n, complex *a, integer *lda, - integer *info, ftnlen uplo_len); -extern int cpbcon_(char *uplo, integer *n, integer *kd, complex *ab, - integer *ldab, real *anorm, real *rcond, complex *work, - real *rwork, integer *info, ftnlen uplo_len); -extern int cpbequ_(char *uplo, integer *n, integer *kd, complex *ab, - integer *ldab, real *s, real *scond, real *amax, - integer *info, ftnlen uplo_len); -extern int cpbrfs_(char *uplo, integer *n, integer *kd, integer *nrhs, - complex *ab, integer *ldab, complex *afb, integer *ldafb, - complex *b, integer *ldb, complex *x, integer *ldx, - real *ferr, real *berr, complex *work, real *rwork, - integer *info, ftnlen uplo_len); -extern int cpbstf_(char *uplo, integer *n, integer *kd, complex *ab, - integer *ldab, integer *info, ftnlen uplo_len); -extern int cpbsv_(char *uplo, integer *n, integer *kd, integer *nrhs, - complex *ab, integer *ldab, complex *b, integer *ldb, - integer *info, ftnlen uplo_len); -extern int cpbsvx_(char *fact, char *uplo, integer *n, integer *kd, - integer *nrhs, complex *ab, integer *ldab, complex *afb, - integer *ldafb, char *equed, real *s, complex *b, - integer *ldb, complex *x, integer *ldx, real *rcond, - real *ferr, real *berr, complex *work, real *rwork, - integer *info, ftnlen fact_len, ftnlen uplo_len, - ftnlen equed_len); -extern int cpbtf2_(char *uplo, integer *n, integer *kd, complex *ab, - integer *ldab, integer *info, ftnlen uplo_len); -extern int cpbtrf_(char *uplo, integer *n, integer *kd, complex *ab, - integer *ldab, integer *info, ftnlen uplo_len); -extern int cpbtrs_(char *uplo, integer *n, integer *kd, integer *nrhs, - complex *ab, integer *ldab, complex *b, integer *ldb, - integer *info, ftnlen uplo_len); -extern int cpocon_(char *uplo, integer *n, complex *a, integer *lda, - real *anorm, real *rcond, complex *work, real *rwork, - integer *info, ftnlen uplo_len); -extern int cpoequ_(integer *n, complex *a, integer *lda, real *s, real *scond, - real *amax, integer *info); -extern int cporfs_(char *uplo, integer *n, integer *nrhs, complex *a, - integer *lda, complex *af, integer *ldaf, complex *b, - integer *ldb, complex *x, integer *ldx, real *ferr, - real *berr, complex *work, real *rwork, integer *info, - ftnlen uplo_len); -extern int cposv_(char *uplo, integer *n, integer *nrhs, complex *a, - integer *lda, complex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int cposvx_(char *fact, char *uplo, integer *n, integer *nrhs, - complex *a, integer *lda, complex *af, integer *ldaf, - char *equed, real *s, complex *b, integer *ldb, complex *x, - integer *ldx, real *rcond, real *ferr, real *berr, - complex *work, real *rwork, integer *info, ftnlen fact_len, - ftnlen uplo_len, ftnlen equed_len); -extern int cpotf2_(char *uplo, integer *n, complex *a, integer *lda, - integer *info, ftnlen uplo_len); -extern int cpotrf_(char *uplo, integer *n, complex *a, integer *lda, - integer *info, ftnlen uplo_len); -extern int cpotri_(char *uplo, integer *n, complex *a, integer *lda, - integer *info, ftnlen uplo_len); -extern int cpotrs_(char *uplo, integer *n, integer *nrhs, complex *a, - integer *lda, complex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int cppcon_(char *uplo, integer *n, complex *ap, real *anorm, - real *rcond, complex *work, real *rwork, integer *info, - ftnlen uplo_len); -extern int cppequ_(char *uplo, integer *n, complex *ap, real *s, real *scond, - real *amax, integer *info, ftnlen uplo_len); -extern int cpprfs_(char *uplo, integer *n, integer *nrhs, complex *ap, - complex *afp, complex *b, integer *ldb, complex *x, - integer *ldx, real *ferr, real *berr, complex *work, - real *rwork, integer *info, ftnlen uplo_len); -extern int cppsv_(char *uplo, integer *n, integer *nrhs, complex *ap, - complex *b, integer *ldb, integer *info, ftnlen uplo_len); -extern int cppsvx_(char *fact, char *uplo, integer *n, integer *nrhs, - complex *ap, complex *afp, char *equed, real *s, complex *b, - integer *ldb, complex *x, integer *ldx, real *rcond, - real *ferr, real *berr, complex *work, real *rwork, - integer *info, ftnlen fact_len, ftnlen uplo_len, - ftnlen equed_len); -extern int cpptrf_(char *uplo, integer *n, complex *ap, integer *info, - ftnlen uplo_len); -extern int cpptri_(char *uplo, integer *n, complex *ap, integer *info, - ftnlen uplo_len); -extern int cpptrs_(char *uplo, integer *n, integer *nrhs, complex *ap, - complex *b, integer *ldb, integer *info, ftnlen uplo_len); -extern int cptcon_(integer *n, real *d__, complex *e, real *anorm, real *rcond, - real *rwork, integer *info); -extern int cpteqr_(char *compz, integer *n, real *d__, real *e, complex *z__, - integer *ldz, real *work, integer *info, ftnlen compz_len); -extern int cptrfs_(char *uplo, integer *n, integer *nrhs, real *d__, complex *e, - real *df, complex *ef, complex *b, integer *ldb, complex *x, - integer *ldx, real *ferr, real *berr, complex *work, - real *rwork, integer *info, ftnlen uplo_len); -extern int cptsv_(integer *n, integer *nrhs, real *d__, complex *e, complex *b, - integer *ldb, integer *info); -extern int cptsvx_(char *fact, integer *n, integer *nrhs, real *d__, complex *e, - real *df, complex *ef, complex *b, integer *ldb, complex *x, - integer *ldx, real *rcond, real *ferr, real *berr, - complex *work, real *rwork, integer *info, ftnlen fact_len); -extern int cpttrf_(integer *n, real *d__, complex *e, integer *info); -extern int cpttrs_(char *uplo, integer *n, integer *nrhs, real *d__, complex *e, - complex *b, integer *ldb, integer *info, ftnlen uplo_len); -extern int cptts2_(integer *iuplo, integer *n, integer *nrhs, real *d__, - complex *e, complex *b, integer *ldb); -extern int crot_(integer *n, complex *cx, integer *incx, complex *cy, - integer *incy, real *c__, complex *s); -extern int cspcon_(char *uplo, integer *n, complex *ap, integer *ipiv, - real *anorm, real *rcond, complex *work, integer *info, - ftnlen uplo_len); -extern int cspmv_(char *uplo, integer *n, complex *alpha, complex *ap, - complex *x, integer *incx, complex *beta, complex *y, - integer *incy, ftnlen uplo_len); -extern int cspr_(char *uplo, integer *n, complex *alpha, complex *x, - integer *incx, complex *ap, ftnlen uplo_len); -extern int csprfs_(char *uplo, integer *n, integer *nrhs, complex *ap, - complex *afp, integer *ipiv, complex *b, integer *ldb, - complex *x, integer *ldx, real *ferr, real *berr, - complex *work, real *rwork, integer *info, ftnlen uplo_len); -extern int cspsv_(char *uplo, integer *n, integer *nrhs, complex *ap, - integer *ipiv, complex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int cspsvx_(char *fact, char *uplo, integer *n, integer *nrhs, - complex *ap, complex *afp, integer *ipiv, complex *b, - integer *ldb, complex *x, integer *ldx, real *rcond, - real *ferr, real *berr, complex *work, real *rwork, - integer *info, ftnlen fact_len, ftnlen uplo_len); -extern int csptrf_(char *uplo, integer *n, complex *ap, integer *ipiv, - integer *info, ftnlen uplo_len); -extern int csptri_(char *uplo, integer *n, complex *ap, integer *ipiv, - complex *work, integer *info, ftnlen uplo_len); -extern int csptrs_(char *uplo, integer *n, integer *nrhs, complex *ap, - integer *ipiv, complex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int csrot_(integer *n, complex *cx, integer *incx, complex *cy, - integer *incy, real *c__, real *s); -extern int csrscl_(integer *n, real *sa, complex *sx, integer *incx); -extern int cstedc_(char *compz, integer *n, real *d__, real *e, complex *z__, - integer *ldz, complex *work, integer *lwork, real *rwork, - integer *lrwork, integer *iwork, integer *liwork, - integer *info, ftnlen compz_len); -extern int cstegr_(char *jobz, char *range, integer *n, real *d__, real *e, - real *vl, real *vu, integer *il, integer *iu, real *abstol, - integer *m, real *w, complex *z__, integer *ldz, - integer *isuppz, real *work, integer *lwork, integer *iwork, - integer *liwork, integer *info, ftnlen jobz_len, - ftnlen range_len); -extern int cstein_(integer *n, real *d__, real *e, integer *m, real *w, - integer *iblock, integer *isplit, complex *z__, integer *ldz, - real *work, integer *iwork, integer *ifail, integer *info); -extern int csteqr_(char *compz, integer *n, real *d__, real *e, complex *z__, - integer *ldz, real *work, integer *info, ftnlen compz_len); -extern int csycon_(char *uplo, integer *n, complex *a, integer *lda, - integer *ipiv, real *anorm, real *rcond, complex *work, - integer *info, ftnlen uplo_len); -extern int csymv_(char *uplo, integer *n, complex *alpha, complex *a, - integer *lda, complex *x, integer *incx, complex *beta, - complex *y, integer *incy, ftnlen uplo_len); -extern int csyr_(char *uplo, integer *n, complex *alpha, complex *x, - integer *incx, complex *a, integer *lda, ftnlen uplo_len); -extern int csyrfs_(char *uplo, integer *n, integer *nrhs, complex *a, - integer *lda, complex *af, integer *ldaf, integer *ipiv, - complex *b, integer *ldb, complex *x, integer *ldx, - real *ferr, real *berr, complex *work, real *rwork, - integer *info, ftnlen uplo_len); -extern int csysv_(char *uplo, integer *n, integer *nrhs, complex *a, - integer *lda, integer *ipiv, complex *b, integer *ldb, - complex *work, integer *lwork, integer *info, - ftnlen uplo_len); -extern int csysvx_(char *fact, char *uplo, integer *n, integer *nrhs, - complex *a, integer *lda, complex *af, integer *ldaf, - integer *ipiv, complex *b, integer *ldb, complex *x, - integer *ldx, real *rcond, real *ferr, real *berr, - complex *work, integer *lwork, real *rwork, integer *info, - ftnlen fact_len, ftnlen uplo_len); -extern int csytf2_(char *uplo, integer *n, complex *a, integer *lda, - integer *ipiv, integer *info, ftnlen uplo_len); -extern int csytrf_(char *uplo, integer *n, complex *a, integer *lda, - integer *ipiv, complex *work, integer *lwork, integer *info, - ftnlen uplo_len); -extern int csytri_(char *uplo, integer *n, complex *a, integer *lda, - integer *ipiv, complex *work, integer *info, - ftnlen uplo_len); -extern int csytrs_(char *uplo, integer *n, integer *nrhs, complex *a, - integer *lda, integer *ipiv, complex *b, integer *ldb, - integer *info, ftnlen uplo_len); -extern int ctbcon_(char *norm, char *uplo, char *diag, integer *n, integer *kd, - complex *ab, integer *ldab, real *rcond, complex *work, - real *rwork, integer *info, ftnlen norm_len, ftnlen uplo_len, - ftnlen diag_len); -extern int ctbrfs_(char *uplo, char *trans, char *diag, integer *n, integer *kd, - integer *nrhs, complex *ab, integer *ldab, complex *b, - integer *ldb, complex *x, integer *ldx, real *ferr, - real *berr, complex *work, real *rwork, integer *info, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len); -extern int ctbtrs_(char *uplo, char *trans, char *diag, integer *n, integer *kd, - integer *nrhs, complex *ab, integer *ldab, complex *b, - integer *ldb, integer *info, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern int ctgevc_(char *side, char *howmny, logical *select, integer *n, - complex *a, integer *lda, complex *b, integer *ldb, - complex *vl, integer *ldvl, complex *vr, integer *ldvr, - integer *mm, integer *m, complex *work, real *rwork, - integer *info, ftnlen side_len, ftnlen howmny_len); -extern int ctgex2_(logical *wantq, logical *wantz, integer *n, complex *a, - integer *lda, complex *b, integer *ldb, complex *q, - integer *ldq, complex *z__, integer *ldz, integer *j1, - integer *info); -extern int ctgexc_(logical *wantq, logical *wantz, integer *n, complex *a, - integer *lda, complex *b, integer *ldb, complex *q, - integer *ldq, complex *z__, integer *ldz, integer *ifst, - integer *ilst, integer *info); -extern int ctgsen_(integer *ijob, logical *wantq, logical *wantz, - logical *select, integer *n, complex *a, integer *lda, - complex *b, integer *ldb, complex *alpha, complex *beta, - complex *q, integer *ldq, complex *z__, integer *ldz, - integer *m, real *pl, real *pr, real *dif, complex *work, - integer *lwork, integer *iwork, integer *liwork, - integer *info); -extern int ctgsja_(char *jobu, char *jobv, char *jobq, integer *m, integer *p, - integer *n, integer *k, integer *l, complex *a, integer *lda, - complex *b, integer *ldb, real *tola, real *tolb, - real *alpha, real *beta, complex *u, integer *ldu, - complex *v, integer *ldv, complex *q, integer *ldq, - complex *work, integer *ncycle, integer *info, - ftnlen jobu_len, ftnlen jobv_len, ftnlen jobq_len); -extern int ctgsna_(char *job, char *howmny, logical *select, integer *n, - complex *a, integer *lda, complex *b, integer *ldb, - complex *vl, integer *ldvl, complex *vr, integer *ldvr, - real *s, real *dif, integer *mm, integer *m, complex *work, - integer *lwork, integer *iwork, integer *info, - ftnlen job_len, ftnlen howmny_len); -extern int ctgsy2_(char *trans, integer *ijob, integer *m, integer *n, - complex *a, integer *lda, complex *b, integer *ldb, - complex *c__, integer *ldc, complex *d__, integer *ldd, - complex *e, integer *lde, complex *f, integer *ldf, - real *scale, real *rdsum, real *rdscal, integer *info, - ftnlen trans_len); -extern int ctgsyl_(char *trans, integer *ijob, integer *m, integer *n, - complex *a, integer *lda, complex *b, integer *ldb, - complex *c__, integer *ldc, complex *d__, integer *ldd, - complex *e, integer *lde, complex *f, integer *ldf, - real *scale, real *dif, complex *work, integer *lwork, - integer *iwork, integer *info, ftnlen trans_len); -extern int ctpcon_(char *norm, char *uplo, char *diag, integer *n, complex *ap, - real *rcond, complex *work, real *rwork, integer *info, - ftnlen norm_len, ftnlen uplo_len, ftnlen diag_len); -extern int ctprfs_(char *uplo, char *trans, char *diag, integer *n, - integer *nrhs, complex *ap, complex *b, integer *ldb, - complex *x, integer *ldx, real *ferr, real *berr, - complex *work, real *rwork, integer *info, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern int ctptri_(char *uplo, char *diag, integer *n, complex *ap, - integer *info, ftnlen uplo_len, ftnlen diag_len); -extern int ctptrs_(char *uplo, char *trans, char *diag, integer *n, - integer *nrhs, complex *ap, complex *b, integer *ldb, - integer *info, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len); -extern int ctrcon_(char *norm, char *uplo, char *diag, integer *n, complex *a, - integer *lda, real *rcond, complex *work, real *rwork, - integer *info, ftnlen norm_len, ftnlen uplo_len, - ftnlen diag_len); -extern int ctrevc_(char *side, char *howmny, logical *select, integer *n, - complex *t, integer *ldt, complex *vl, integer *ldvl, - complex *vr, integer *ldvr, integer *mm, integer *m, - complex *work, real *rwork, integer *info, ftnlen side_len, - ftnlen howmny_len); -extern int ctrexc_(char *compq, integer *n, complex *t, integer *ldt, - complex *q, integer *ldq, integer *ifst, integer *ilst, - integer *info, ftnlen compq_len); -extern int ctrrfs_(char *uplo, char *trans, char *diag, integer *n, - integer *nrhs, complex *a, integer *lda, complex *b, - integer *ldb, complex *x, integer *ldx, real *ferr, - real *berr, complex *work, real *rwork, integer *info, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len); -extern int ctrsen_(char *job, char *compq, logical *select, integer *n, - complex *t, integer *ldt, complex *q, integer *ldq, - complex *w, integer *m, real *s, real *sep, complex *work, - integer *lwork, integer *info, ftnlen job_len, - ftnlen compq_len); -extern int ctrsna_(char *job, char *howmny, logical *select, integer *n, - complex *t, integer *ldt, complex *vl, integer *ldvl, - complex *vr, integer *ldvr, real *s, real *sep, integer *mm, - integer *m, complex *work, integer *ldwork, real *rwork, - integer *info, ftnlen job_len, ftnlen howmny_len); -extern int ctrsyl_(char *trana, char *tranb, integer *isgn, integer *m, - integer *n, complex *a, integer *lda, complex *b, - integer *ldb, complex *c__, integer *ldc, real *scale, - integer *info, ftnlen trana_len, ftnlen tranb_len); -extern int ctrti2_(char *uplo, char *diag, integer *n, complex *a, integer *lda, - integer *info, ftnlen uplo_len, ftnlen diag_len); -extern int ctrtri_(char *uplo, char *diag, integer *n, complex *a, integer *lda, - integer *info, ftnlen uplo_len, ftnlen diag_len); -extern int ctrtrs_(char *uplo, char *trans, char *diag, integer *n, - integer *nrhs, complex *a, integer *lda, complex *b, - integer *ldb, integer *info, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern int ctzrqf_(integer *m, integer *n, complex *a, integer *lda, - complex *tau, integer *info); -extern int ctzrzf_(integer *m, integer *n, complex *a, integer *lda, - complex *tau, complex *work, integer *lwork, integer *info); -extern int cung2l_(integer *m, integer *n, integer *k, complex *a, integer *lda, - complex *tau, complex *work, integer *info); -extern int cung2r_(integer *m, integer *n, integer *k, complex *a, integer *lda, - complex *tau, complex *work, integer *info); -extern int cungbr_(char *vect, integer *m, integer *n, integer *k, complex *a, - integer *lda, complex *tau, complex *work, integer *lwork, - integer *info, ftnlen vect_len); -extern int cunghr_(integer *n, integer *ilo, integer *ihi, complex *a, - integer *lda, complex *tau, complex *work, integer *lwork, - integer *info); -extern int cungl2_(integer *m, integer *n, integer *k, complex *a, integer *lda, - complex *tau, complex *work, integer *info); -extern int cunglq_(integer *m, integer *n, integer *k, complex *a, integer *lda, - complex *tau, complex *work, integer *lwork, integer *info); -extern int cungql_(integer *m, integer *n, integer *k, complex *a, integer *lda, - complex *tau, complex *work, integer *lwork, integer *info); -extern int cungqr_(integer *m, integer *n, integer *k, complex *a, integer *lda, - complex *tau, complex *work, integer *lwork, integer *info); -extern int cungr2_(integer *m, integer *n, integer *k, complex *a, integer *lda, - complex *tau, complex *work, integer *info); -extern int cungrq_(integer *m, integer *n, integer *k, complex *a, integer *lda, - complex *tau, complex *work, integer *lwork, integer *info); -extern int cungtr_(char *uplo, integer *n, complex *a, integer *lda, - complex *tau, complex *work, integer *lwork, integer *info, - ftnlen uplo_len); -extern int cunm2l_(char *side, char *trans, integer *m, integer *n, integer *k, - complex *a, integer *lda, complex *tau, complex *c__, - integer *ldc, complex *work, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int cunm2r_(char *side, char *trans, integer *m, integer *n, integer *k, - complex *a, integer *lda, complex *tau, complex *c__, - integer *ldc, complex *work, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int cunmbr_(char *vect, char *side, char *trans, integer *m, integer *n, - integer *k, complex *a, integer *lda, complex *tau, - complex *c__, integer *ldc, complex *work, integer *lwork, - integer *info, ftnlen vect_len, ftnlen side_len, - ftnlen trans_len); -extern int cunmhr_(char *side, char *trans, integer *m, integer *n, - integer *ilo, integer *ihi, complex *a, integer *lda, - complex *tau, complex *c__, integer *ldc, complex *work, - integer *lwork, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int cunml2_(char *side, char *trans, integer *m, integer *n, integer *k, - complex *a, integer *lda, complex *tau, complex *c__, - integer *ldc, complex *work, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int cunmlq_(char *side, char *trans, integer *m, integer *n, integer *k, - complex *a, integer *lda, complex *tau, complex *c__, - integer *ldc, complex *work, integer *lwork, integer *info, - ftnlen side_len, ftnlen trans_len); -extern int cunmql_(char *side, char *trans, integer *m, integer *n, integer *k, - complex *a, integer *lda, complex *tau, complex *c__, - integer *ldc, complex *work, integer *lwork, integer *info, - ftnlen side_len, ftnlen trans_len); -extern int cunmqr_(char *side, char *trans, integer *m, integer *n, integer *k, - complex *a, integer *lda, complex *tau, complex *c__, - integer *ldc, complex *work, integer *lwork, integer *info, - ftnlen side_len, ftnlen trans_len); -extern int cunmr2_(char *side, char *trans, integer *m, integer *n, integer *k, - complex *a, integer *lda, complex *tau, complex *c__, - integer *ldc, complex *work, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int cunmr3_(char *side, char *trans, integer *m, integer *n, integer *k, - integer *l, complex *a, integer *lda, complex *tau, - complex *c__, integer *ldc, complex *work, integer *info, - ftnlen side_len, ftnlen trans_len); -extern int cunmrq_(char *side, char *trans, integer *m, integer *n, integer *k, - complex *a, integer *lda, complex *tau, complex *c__, - integer *ldc, complex *work, integer *lwork, integer *info, - ftnlen side_len, ftnlen trans_len); -extern int cunmrz_(char *side, char *trans, integer *m, integer *n, integer *k, - integer *l, complex *a, integer *lda, complex *tau, - complex *c__, integer *ldc, complex *work, integer *lwork, - integer *info, ftnlen side_len, ftnlen trans_len); -extern int cunmtr_(char *side, char *uplo, char *trans, integer *m, integer *n, - complex *a, integer *lda, complex *tau, complex *c__, - integer *ldc, complex *work, integer *lwork, integer *info, - ftnlen side_len, ftnlen uplo_len, ftnlen trans_len); -extern int cupgtr_(char *uplo, integer *n, complex *ap, complex *tau, - complex *q, integer *ldq, complex *work, integer *info, - ftnlen uplo_len); -extern int cupmtr_(char *side, char *uplo, char *trans, integer *m, integer *n, - complex *ap, complex *tau, complex *c__, integer *ldc, - complex *work, integer *info, ftnlen side_len, - ftnlen uplo_len, ftnlen trans_len); -extern int dbdsdc_(char *uplo, char *compq, integer *n, doublereal *d__, - doublereal *e, doublereal *u, integer *ldu, doublereal *vt, - integer *ldvt, doublereal *q, integer *iq, doublereal *work, - integer *iwork, integer *info, ftnlen uplo_len, - ftnlen compq_len); -extern int dbdsqr_(char *uplo, integer *n, integer *ncvt, integer *nru, - integer *ncc, doublereal *d__, doublereal *e, doublereal *vt, - integer *ldvt, doublereal *u, integer *ldu, doublereal *c__, - integer *ldc, doublereal *work, integer *info, - ftnlen uplo_len); -extern int ddisna_(char *job, integer *m, integer *n, doublereal *d__, - doublereal *sep, integer *info, ftnlen job_len); -extern int dgbbrd_(char *vect, integer *m, integer *n, integer *ncc, - integer *kl, integer *ku, doublereal *ab, integer *ldab, - doublereal *d__, doublereal *e, doublereal *q, integer *ldq, - doublereal *pt, integer *ldpt, doublereal *c__, integer *ldc, - doublereal *work, integer *info, ftnlen vect_len); -extern int dgbcon_(char *norm, integer *n, integer *kl, integer *ku, - doublereal *ab, integer *ldab, integer *ipiv, - doublereal *anorm, doublereal *rcond, doublereal *work, - integer *iwork, integer *info, ftnlen norm_len); -extern int dgbequ_(integer *m, integer *n, integer *kl, integer *ku, - doublereal *ab, integer *ldab, doublereal *r__, - doublereal *c__, doublereal *rowcnd, doublereal *colcnd, - doublereal *amax, integer *info); -extern int dgbrfs_(char *trans, integer *n, integer *kl, integer *ku, - integer *nrhs, doublereal *ab, integer *ldab, - doublereal *afb, integer *ldafb, integer *ipiv, - doublereal *b, integer *ldb, doublereal *x, integer *ldx, - doublereal *ferr, doublereal *berr, doublereal *work, - integer *iwork, integer *info, ftnlen trans_len); -extern int dgbsv_(integer *n, integer *kl, integer *ku, integer *nrhs, - doublereal *ab, integer *ldab, integer *ipiv, doublereal *b, - integer *ldb, integer *info); -extern int dgbsvx_(char *fact, char *trans, integer *n, integer *kl, - integer *ku, integer *nrhs, doublereal *ab, integer *ldab, - doublereal *afb, integer *ldafb, integer *ipiv, char *equed, - doublereal *r__, doublereal *c__, doublereal *b, - integer *ldb, doublereal *x, integer *ldx, doublereal *rcond, - doublereal *ferr, doublereal *berr, doublereal *work, - integer *iwork, integer *info, ftnlen fact_len, - ftnlen trans_len, ftnlen equed_len); -extern int dgbtf2_(integer *m, integer *n, integer *kl, integer *ku, - doublereal *ab, integer *ldab, integer *ipiv, integer *info); -extern int dgbtrf_(integer *m, integer *n, integer *kl, integer *ku, - doublereal *ab, integer *ldab, integer *ipiv, integer *info); -extern int dgbtrs_(char *trans, integer *n, integer *kl, integer *ku, - integer *nrhs, doublereal *ab, integer *ldab, integer *ipiv, - doublereal *b, integer *ldb, integer *info, - ftnlen trans_len); -extern int dgebak_(char *job, char *side, integer *n, integer *ilo, - integer *ihi, doublereal *scale, integer *m, doublereal *v, - integer *ldv, integer *info, ftnlen job_len, - ftnlen side_len); -extern int dgebal_(char *job, integer *n, doublereal *a, integer *lda, - integer *ilo, integer *ihi, doublereal *scale, integer *info, - ftnlen job_len); -extern int dgebd2_(integer *m, integer *n, doublereal *a, integer *lda, - doublereal *d__, doublereal *e, doublereal *tauq, - doublereal *taup, doublereal *work, integer *info); -extern int dgebrd_(integer *m, integer *n, doublereal *a, integer *lda, - doublereal *d__, doublereal *e, doublereal *tauq, - doublereal *taup, doublereal *work, integer *lwork, - integer *info); -extern int dgecon_(char *norm, integer *n, doublereal *a, integer *lda, - doublereal *anorm, doublereal *rcond, doublereal *work, - integer *iwork, integer *info, ftnlen norm_len); -extern int dgeequ_(integer *m, integer *n, doublereal *a, integer *lda, - doublereal *r__, doublereal *c__, doublereal *rowcnd, - doublereal *colcnd, doublereal *amax, integer *info); -extern int dgees_(char *jobvs, char *sort, L_fp select, integer *n, - doublereal *a, integer *lda, integer *sdim, doublereal *wr, - doublereal *wi, doublereal *vs, integer *ldvs, - doublereal *work, integer *lwork, logical *bwork, - integer *info, ftnlen jobvs_len, ftnlen sort_len); -extern int dgeesx_(char *jobvs, char *sort, L_fp select, char *sense, - integer *n, doublereal *a, integer *lda, integer *sdim, - doublereal *wr, doublereal *wi, doublereal *vs, - integer *ldvs, doublereal *rconde, doublereal *rcondv, - doublereal *work, integer *lwork, integer *iwork, - integer *liwork, logical *bwork, integer *info, - ftnlen jobvs_len, ftnlen sort_len, ftnlen sense_len); -extern int dgeev_(char *jobvl, char *jobvr, integer *n, doublereal *a, - integer *lda, doublereal *wr, doublereal *wi, doublereal *vl, - integer *ldvl, doublereal *vr, integer *ldvr, - doublereal *work, integer *lwork, integer *info, - ftnlen jobvl_len, ftnlen jobvr_len); -extern int dgeevx_(char *balanc, char *jobvl, char *jobvr, char *sense, - integer *n, doublereal *a, integer *lda, doublereal *wr, - doublereal *wi, doublereal *vl, integer *ldvl, - doublereal *vr, integer *ldvr, integer *ilo, integer *ihi, - doublereal *scale, doublereal *abnrm, doublereal *rconde, - doublereal *rcondv, doublereal *work, integer *lwork, - integer *iwork, integer *info, ftnlen balanc_len, - ftnlen jobvl_len, ftnlen jobvr_len, ftnlen sense_len); -extern int dgegs_(char *jobvsl, char *jobvsr, integer *n, doublereal *a, - integer *lda, doublereal *b, integer *ldb, doublereal *alphar, - doublereal *alphai, doublereal *beta, doublereal *vsl, - integer *ldvsl, doublereal *vsr, integer *ldvsr, - doublereal *work, integer *lwork, integer *info, - ftnlen jobvsl_len, ftnlen jobvsr_len); -extern int dgegv_(char *jobvl, char *jobvr, integer *n, doublereal *a, - integer *lda, doublereal *b, integer *ldb, doublereal *alphar, - doublereal *alphai, doublereal *beta, doublereal *vl, - integer *ldvl, doublereal *vr, integer *ldvr, - doublereal *work, integer *lwork, integer *info, - ftnlen jobvl_len, ftnlen jobvr_len); -extern int dgehd2_(integer *n, integer *ilo, integer *ihi, doublereal *a, - integer *lda, doublereal *tau, doublereal *work, - integer *info); -extern int dgehrd_(integer *n, integer *ilo, integer *ihi, doublereal *a, - integer *lda, doublereal *tau, doublereal *work, - integer *lwork, integer *info); -extern int dgelq2_(integer *m, integer *n, doublereal *a, integer *lda, - doublereal *tau, doublereal *work, integer *info); -extern int dgelqf_(integer *m, integer *n, doublereal *a, integer *lda, - doublereal *tau, doublereal *work, integer *lwork, - integer *info); -extern int dgels_(char *trans, integer *m, integer *n, integer *nrhs, - doublereal *a, integer *lda, doublereal *b, integer *ldb, - doublereal *work, integer *lwork, integer *info, - ftnlen trans_len); -extern int dgelsd_(integer *m, integer *n, integer *nrhs, doublereal *a, - integer *lda, doublereal *b, integer *ldb, doublereal *s, - doublereal *rcond, integer *rank, doublereal *work, - integer *lwork, integer *iwork, integer *info); -extern int dgelss_(integer *m, integer *n, integer *nrhs, doublereal *a, - integer *lda, doublereal *b, integer *ldb, doublereal *s, - doublereal *rcond, integer *rank, doublereal *work, - integer *lwork, integer *info); -extern int dgelsx_(integer *m, integer *n, integer *nrhs, doublereal *a, - integer *lda, doublereal *b, integer *ldb, integer *jpvt, - doublereal *rcond, integer *rank, doublereal *work, - integer *info); -extern int dgelsy_(integer *m, integer *n, integer *nrhs, doublereal *a, - integer *lda, doublereal *b, integer *ldb, integer *jpvt, - doublereal *rcond, integer *rank, doublereal *work, - integer *lwork, integer *info); -extern int dgeql2_(integer *m, integer *n, doublereal *a, integer *lda, - doublereal *tau, doublereal *work, integer *info); -extern int dgeqlf_(integer *m, integer *n, doublereal *a, integer *lda, - doublereal *tau, doublereal *work, integer *lwork, - integer *info); -extern int dgeqp3_(integer *m, integer *n, doublereal *a, integer *lda, - integer *jpvt, doublereal *tau, doublereal *work, - integer *lwork, integer *info); -extern int dgeqpf_(integer *m, integer *n, doublereal *a, integer *lda, - integer *jpvt, doublereal *tau, doublereal *work, - integer *info); -extern int dgeqr2_(integer *m, integer *n, doublereal *a, integer *lda, - doublereal *tau, doublereal *work, integer *info); -extern int dgeqrf_(integer *m, integer *n, doublereal *a, integer *lda, - doublereal *tau, doublereal *work, integer *lwork, - integer *info); -extern int dgerfs_(char *trans, integer *n, integer *nrhs, doublereal *a, - integer *lda, doublereal *af, integer *ldaf, integer *ipiv, - doublereal *b, integer *ldb, doublereal *x, integer *ldx, - doublereal *ferr, doublereal *berr, doublereal *work, - integer *iwork, integer *info, ftnlen trans_len); -extern int dgerq2_(integer *m, integer *n, doublereal *a, integer *lda, - doublereal *tau, doublereal *work, integer *info); -extern int dgerqf_(integer *m, integer *n, doublereal *a, integer *lda, - doublereal *tau, doublereal *work, integer *lwork, - integer *info); -extern int dgesc2_(integer *n, doublereal *a, integer *lda, doublereal *rhs, - integer *ipiv, integer *jpiv, doublereal *scale); -extern int dgesdd_(char *jobz, integer *m, integer *n, doublereal *a, - integer *lda, doublereal *s, doublereal *u, integer *ldu, - doublereal *vt, integer *ldvt, doublereal *work, - integer *lwork, integer *iwork, integer *info, - ftnlen jobz_len); -extern int dgesv_(integer *n, integer *nrhs, doublereal *a, integer *lda, - integer *ipiv, doublereal *b, integer *ldb, integer *info); -extern int dgesvd_(char *jobu, char *jobvt, integer *m, integer *n, - doublereal *a, integer *lda, doublereal *s, doublereal *u, - integer *ldu, doublereal *vt, integer *ldvt, - doublereal *work, integer *lwork, integer *info, - ftnlen jobu_len, ftnlen jobvt_len); -extern int dgesvx_(char *fact, char *trans, integer *n, integer *nrhs, - doublereal *a, integer *lda, doublereal *af, integer *ldaf, - integer *ipiv, char *equed, doublereal *r__, doublereal *c__, - doublereal *b, integer *ldb, doublereal *x, integer *ldx, - doublereal *rcond, doublereal *ferr, doublereal *berr, - doublereal *work, integer *iwork, integer *info, - ftnlen fact_len, ftnlen trans_len, ftnlen equed_len); -extern int dgetc2_(integer *n, doublereal *a, integer *lda, integer *ipiv, - integer *jpiv, integer *info); -extern int dgetf2_(integer *m, integer *n, doublereal *a, integer *lda, - integer *ipiv, integer *info); -extern int dgetrf_(integer *m, integer *n, doublereal *a, integer *lda, - integer *ipiv, integer *info); -extern int dgetri_(integer *n, doublereal *a, integer *lda, integer *ipiv, - doublereal *work, integer *lwork, integer *info); -extern int dgetrs_(char *trans, integer *n, integer *nrhs, doublereal *a, - integer *lda, integer *ipiv, doublereal *b, integer *ldb, - integer *info, ftnlen trans_len); -extern int dggbak_(char *job, char *side, integer *n, integer *ilo, - integer *ihi, doublereal *lscale, doublereal *rscale, - integer *m, doublereal *v, integer *ldv, integer *info, - ftnlen job_len, ftnlen side_len); -extern int dggbal_(char *job, integer *n, doublereal *a, integer *lda, - doublereal *b, integer *ldb, integer *ilo, integer *ihi, - doublereal *lscale, doublereal *rscale, doublereal *work, - integer *info, ftnlen job_len); -extern int dgges_(char *jobvsl, char *jobvsr, char *sort, L_fp delctg, - integer *n, doublereal *a, integer *lda, doublereal *b, - integer *ldb, integer *sdim, doublereal *alphar, - doublereal *alphai, doublereal *beta, doublereal *vsl, - integer *ldvsl, doublereal *vsr, integer *ldvsr, - doublereal *work, integer *lwork, logical *bwork, - integer *info, ftnlen jobvsl_len, ftnlen jobvsr_len, - ftnlen sort_len); -extern int dggesx_(char *jobvsl, char *jobvsr, char *sort, L_fp delctg, - char *sense, integer *n, doublereal *a, integer *lda, - doublereal *b, integer *ldb, integer *sdim, - doublereal *alphar, doublereal *alphai, doublereal *beta, - doublereal *vsl, integer *ldvsl, doublereal *vsr, - integer *ldvsr, doublereal *rconde, doublereal *rcondv, - doublereal *work, integer *lwork, integer *iwork, - integer *liwork, logical *bwork, integer *info, - ftnlen jobvsl_len, ftnlen jobvsr_len, ftnlen sort_len, - ftnlen sense_len); -extern int dggev_(char *jobvl, char *jobvr, integer *n, doublereal *a, - integer *lda, doublereal *b, integer *ldb, doublereal *alphar, - doublereal *alphai, doublereal *beta, doublereal *vl, - integer *ldvl, doublereal *vr, integer *ldvr, - doublereal *work, integer *lwork, integer *info, - ftnlen jobvl_len, ftnlen jobvr_len); -extern int dggevx_(char *balanc, char *jobvl, char *jobvr, char *sense, - integer *n, doublereal *a, integer *lda, doublereal *b, - integer *ldb, doublereal *alphar, doublereal *alphai, - doublereal *beta, doublereal *vl, integer *ldvl, - doublereal *vr, integer *ldvr, integer *ilo, integer *ihi, - doublereal *lscale, doublereal *rscale, doublereal *abnrm, - doublereal *bbnrm, doublereal *rconde, doublereal *rcondv, - doublereal *work, integer *lwork, integer *iwork, - logical *bwork, integer *info, ftnlen balanc_len, - ftnlen jobvl_len, ftnlen jobvr_len, ftnlen sense_len); -extern int dggglm_(integer *n, integer *m, integer *p, doublereal *a, - integer *lda, doublereal *b, integer *ldb, doublereal *d__, - doublereal *x, doublereal *y, doublereal *work, - integer *lwork, integer *info); -extern int dgghrd_(char *compq, char *compz, integer *n, integer *ilo, - integer *ihi, doublereal *a, integer *lda, doublereal *b, - integer *ldb, doublereal *q, integer *ldq, doublereal *z__, - integer *ldz, integer *info, ftnlen compq_len, - ftnlen compz_len); -extern int dgglse_(integer *m, integer *n, integer *p, doublereal *a, - integer *lda, doublereal *b, integer *ldb, doublereal *c__, - doublereal *d__, doublereal *x, doublereal *work, - integer *lwork, integer *info); -extern int dggqrf_(integer *n, integer *m, integer *p, doublereal *a, - integer *lda, doublereal *taua, doublereal *b, integer *ldb, - doublereal *taub, doublereal *work, integer *lwork, - integer *info); -extern int dggrqf_(integer *m, integer *p, integer *n, doublereal *a, - integer *lda, doublereal *taua, doublereal *b, integer *ldb, - doublereal *taub, doublereal *work, integer *lwork, - integer *info); -extern int dggsvd_(char *jobu, char *jobv, char *jobq, integer *m, integer *n, - integer *p, integer *k, integer *l, doublereal *a, - integer *lda, doublereal *b, integer *ldb, doublereal *alpha, - doublereal *beta, doublereal *u, integer *ldu, doublereal *v, - integer *ldv, doublereal *q, integer *ldq, doublereal *work, - integer *iwork, integer *info, ftnlen jobu_len, - ftnlen jobv_len, ftnlen jobq_len); -extern int dggsvp_(char *jobu, char *jobv, char *jobq, integer *m, integer *p, - integer *n, doublereal *a, integer *lda, doublereal *b, - integer *ldb, doublereal *tola, doublereal *tolb, integer *k, - integer *l, doublereal *u, integer *ldu, doublereal *v, - integer *ldv, doublereal *q, integer *ldq, integer *iwork, - doublereal *tau, doublereal *work, integer *info, - ftnlen jobu_len, ftnlen jobv_len, ftnlen jobq_len); -extern int dgtcon_(char *norm, integer *n, doublereal *dl, doublereal *d__, - doublereal *du, doublereal *du2, integer *ipiv, - doublereal *anorm, doublereal *rcond, doublereal *work, - integer *iwork, integer *info, ftnlen norm_len); -extern int dgtrfs_(char *trans, integer *n, integer *nrhs, doublereal *dl, - doublereal *d__, doublereal *du, doublereal *dlf, - doublereal *df, doublereal *duf, doublereal *du2, - integer *ipiv, doublereal *b, integer *ldb, doublereal *x, - integer *ldx, doublereal *ferr, doublereal *berr, - doublereal *work, integer *iwork, integer *info, - ftnlen trans_len); -extern int dgtsv_(integer *n, integer *nrhs, doublereal *dl, doublereal *d__, - doublereal *du, doublereal *b, integer *ldb, integer *info); -extern int dgtsvx_(char *fact, char *trans, integer *n, integer *nrhs, - doublereal *dl, doublereal *d__, doublereal *du, - doublereal *dlf, doublereal *df, doublereal *duf, - doublereal *du2, integer *ipiv, doublereal *b, integer *ldb, - doublereal *x, integer *ldx, doublereal *rcond, - doublereal *ferr, doublereal *berr, doublereal *work, - integer *iwork, integer *info, ftnlen fact_len, - ftnlen trans_len); -extern int dgttrf_(integer *n, doublereal *dl, doublereal *d__, doublereal *du, - doublereal *du2, integer *ipiv, integer *info); -extern int dgttrs_(char *trans, integer *n, integer *nrhs, doublereal *dl, - doublereal *d__, doublereal *du, doublereal *du2, - integer *ipiv, doublereal *b, integer *ldb, integer *info, - ftnlen trans_len); -extern int dgtts2_(integer *itrans, integer *n, integer *nrhs, doublereal *dl, - doublereal *d__, doublereal *du, doublereal *du2, - integer *ipiv, doublereal *b, integer *ldb); -extern int dhgeqz_(char *job, char *compq, char *compz, integer *n, - integer *ilo, integer *ihi, doublereal *a, integer *lda, - doublereal *b, integer *ldb, doublereal *alphar, - doublereal *alphai, doublereal *beta, doublereal *q, - integer *ldq, doublereal *z__, integer *ldz, - doublereal *work, integer *lwork, integer *info, - ftnlen job_len, ftnlen compq_len, ftnlen compz_len); -extern int dhsein_(char *side, char *eigsrc, char *initv, logical *select, - integer *n, doublereal *h__, integer *ldh, doublereal *wr, - doublereal *wi, doublereal *vl, integer *ldvl, - doublereal *vr, integer *ldvr, integer *mm, integer *m, - doublereal *work, integer *ifaill, integer *ifailr, - integer *info, ftnlen side_len, ftnlen eigsrc_len, - ftnlen initv_len); -extern int dhseqr_(char *job, char *compz, integer *n, integer *ilo, - integer *ihi, doublereal *h__, integer *ldh, doublereal *wr, - doublereal *wi, doublereal *z__, integer *ldz, - doublereal *work, integer *lwork, integer *info, - ftnlen job_len, ftnlen compz_len); -extern int dlabad_(doublereal *small, doublereal *large); -extern int dlabrd_(integer *m, integer *n, integer *nb, doublereal *a, - integer *lda, doublereal *d__, doublereal *e, - doublereal *tauq, doublereal *taup, doublereal *x, - integer *ldx, doublereal *y, integer *ldy); -extern int dlacon_(integer *n, doublereal *v, doublereal *x, integer *isgn, - doublereal *est, integer *kase); -extern int dlacpy_(char *uplo, integer *m, integer *n, doublereal *a, - integer *lda, doublereal *b, integer *ldb, ftnlen uplo_len); -extern int dladiv_(doublereal *a, doublereal *b, doublereal *c__, - doublereal *d__, doublereal *p, doublereal *q); -extern int dlae2_(doublereal *a, doublereal *b, doublereal *c__, - doublereal *rt1, doublereal *rt2); -extern int dlaebz_(integer *ijob, integer *nitmax, integer *n, integer *mmax, - integer *minp, integer *nbmin, doublereal *abstol, - doublereal *reltol, doublereal *pivmin, doublereal *d__, - doublereal *e, doublereal *e2, integer *nval, doublereal *ab, - doublereal *c__, integer *mout, integer *nab, - doublereal *work, integer *iwork, integer *info); -extern int dlaed0_(integer *icompq, integer *qsiz, integer *n, doublereal *d__, - doublereal *e, doublereal *q, integer *ldq, - doublereal *qstore, integer *ldqs, doublereal *work, - integer *iwork, integer *info); -extern int dlaed1_(integer *n, doublereal *d__, doublereal *q, integer *ldq, - integer *indxq, doublereal *rho, integer *cutpnt, - doublereal *work, integer *iwork, integer *info); -extern int dlaed2_(integer *k, integer *n, integer *n1, doublereal *d__, - doublereal *q, integer *ldq, integer *indxq, doublereal *rho, - doublereal *z__, doublereal *dlamda, doublereal *w, - doublereal *q2, integer *indx, integer *indxc, - integer *indxp, integer *coltyp, integer *info); -extern int dlaed3_(integer *k, integer *n, integer *n1, doublereal *d__, - doublereal *q, integer *ldq, doublereal *rho, - doublereal *dlamda, doublereal *q2, integer *indx, - integer *ctot, doublereal *w, doublereal *s, integer *info); -extern int dlaed4_(integer *n, integer *i__, doublereal *d__, doublereal *z__, - doublereal *delta, doublereal *rho, doublereal *dlam, - integer *info); -extern int dlaed5_(integer *i__, doublereal *d__, doublereal *z__, - doublereal *delta, doublereal *rho, doublereal *dlam); -extern int dlaed6_(integer *kniter, logical *orgati, doublereal *rho, - doublereal *d__, doublereal *z__, doublereal *finit, - doublereal *tau, integer *info); -extern int dlaed7_(integer *icompq, integer *n, integer *qsiz, integer *tlvls, - integer *curlvl, integer *curpbm, doublereal *d__, - doublereal *q, integer *ldq, integer *indxq, doublereal *rho, - integer *cutpnt, doublereal *qstore, integer *qptr, - integer *prmptr, integer *perm, integer *givptr, - integer *givcol, doublereal *givnum, doublereal *work, - integer *iwork, integer *info); -extern int dlaed8_(integer *icompq, integer *k, integer *n, integer *qsiz, - doublereal *d__, doublereal *q, integer *ldq, integer *indxq, - doublereal *rho, integer *cutpnt, doublereal *z__, - doublereal *dlamda, doublereal *q2, integer *ldq2, - doublereal *w, integer *perm, integer *givptr, - integer *givcol, doublereal *givnum, integer *indxp, - integer *indx, integer *info); -extern int dlaed9_(integer *k, integer *kstart, integer *kstop, integer *n, - doublereal *d__, doublereal *q, integer *ldq, - doublereal *rho, doublereal *dlamda, doublereal *w, - doublereal *s, integer *lds, integer *info); -extern int dlaeda_(integer *n, integer *tlvls, integer *curlvl, integer *curpbm, - integer *prmptr, integer *perm, integer *givptr, - integer *givcol, doublereal *givnum, doublereal *q, - integer *qptr, doublereal *z__, doublereal *ztemp, - integer *info); -extern int dlaein_(logical *rightv, logical *noinit, integer *n, - doublereal *h__, integer *ldh, doublereal *wr, - doublereal *wi, doublereal *vr, doublereal *vi, - doublereal *b, integer *ldb, doublereal *work, - doublereal *eps3, doublereal *smlnum, doublereal *bignum, - integer *info); -extern int dlaev2_(doublereal *a, doublereal *b, doublereal *c__, - doublereal *rt1, doublereal *rt2, doublereal *cs1, - doublereal *sn1); -extern int dlaexc_(logical *wantq, integer *n, doublereal *t, integer *ldt, - doublereal *q, integer *ldq, integer *j1, integer *n1, - integer *n2, doublereal *work, integer *info); -extern int dlag2_(doublereal *a, integer *lda, doublereal *b, integer *ldb, - doublereal *safmin, doublereal *scale1, doublereal *scale2, - doublereal *wr1, doublereal *wr2, doublereal *wi); -extern int dlags2_(logical *upper, doublereal *a1, doublereal *a2, - doublereal *a3, doublereal *b1, doublereal *b2, - doublereal *b3, doublereal *csu, doublereal *snu, - doublereal *csv, doublereal *snv, doublereal *csq, - doublereal *snq); -extern int dlagtf_(integer *n, doublereal *a, doublereal *lambda, doublereal *b, - doublereal *c__, doublereal *tol, doublereal *d__, - integer *in, integer *info); -extern int dlagtm_(char *trans, integer *n, integer *nrhs, doublereal *alpha, - doublereal *dl, doublereal *d__, doublereal *du, - doublereal *x, integer *ldx, doublereal *beta, doublereal *b, - integer *ldb, ftnlen trans_len); -extern int dlagts_(integer *job, integer *n, doublereal *a, doublereal *b, - doublereal *c__, doublereal *d__, integer *in, doublereal *y, - doublereal *tol, integer *info); -extern int dlagv2_(doublereal *a, integer *lda, doublereal *b, integer *ldb, - doublereal *alphar, doublereal *alphai, doublereal *beta, - doublereal *csl, doublereal *snl, doublereal *csr, - doublereal *snr); -extern int dlahqr_(logical *wantt, logical *wantz, integer *n, integer *ilo, - integer *ihi, doublereal *h__, integer *ldh, doublereal *wr, - doublereal *wi, integer *iloz, integer *ihiz, - doublereal *z__, integer *ldz, integer *info); -extern int dlahrd_(integer *n, integer *k, integer *nb, doublereal *a, - integer *lda, doublereal *tau, doublereal *t, integer *ldt, - doublereal *y, integer *ldy); -extern int dlaic1_(integer *job, integer *j, doublereal *x, doublereal *sest, - doublereal *w, doublereal *gamma, doublereal *sestpr, - doublereal *s, doublereal *c__); -extern int dlaln2_(logical *ltrans, integer *na, integer *nw, doublereal *smin, - doublereal *ca, doublereal *a, integer *lda, doublereal *d1, - doublereal *d2, doublereal *b, integer *ldb, doublereal *wr, - doublereal *wi, doublereal *x, integer *ldx, - doublereal *scale, doublereal *xnorm, integer *info); -extern int dlals0_(integer *icompq, integer *nl, integer *nr, integer *sqre, - integer *nrhs, doublereal *b, integer *ldb, doublereal *bx, - integer *ldbx, integer *perm, integer *givptr, - integer *givcol, integer *ldgcol, doublereal *givnum, - integer *ldgnum, doublereal *poles, doublereal *difl, - doublereal *difr, doublereal *z__, integer *k, - doublereal *c__, doublereal *s, doublereal *work, - integer *info); -extern int dlalsa_(integer *icompq, integer *smlsiz, integer *n, integer *nrhs, - doublereal *b, integer *ldb, doublereal *bx, integer *ldbx, - doublereal *u, integer *ldu, doublereal *vt, integer *k, - doublereal *difl, doublereal *difr, doublereal *z__, - doublereal *poles, integer *givptr, integer *givcol, - integer *ldgcol, integer *perm, doublereal *givnum, - doublereal *c__, doublereal *s, doublereal *work, - integer *iwork, integer *info); -extern int dlalsd_(char *uplo, integer *smlsiz, integer *n, integer *nrhs, - doublereal *d__, doublereal *e, doublereal *b, integer *ldb, - doublereal *rcond, integer *rank, doublereal *work, - integer *iwork, integer *info, ftnlen uplo_len); -extern doublereal dlamch_(char *cmach, ftnlen cmach_len); -extern int dlamc1_(integer *beta, integer *t, logical *rnd, logical *ieee1); -extern int dlamc2_(integer *beta, integer *t, logical *rnd, doublereal *eps, - integer *emin, doublereal *rmin, integer *emax, - doublereal *rmax); -extern doublereal dlamc3_(doublereal *a, doublereal *b); -extern int dlamc4_(integer *emin, doublereal *start, integer *base); -extern int dlamc5_(integer *beta, integer *p, integer *emin, logical *ieee, - integer *emax, doublereal *rmax); -extern int dlamrg_(integer *n1, integer *n2, doublereal *a, integer *dtrd1, - integer *dtrd2, integer *index); -extern doublereal dlangb_(char *norm, integer *n, integer *kl, integer *ku, - doublereal *ab, integer *ldab, doublereal *work, - ftnlen norm_len); -extern doublereal dlange_(char *norm, integer *m, integer *n, doublereal *a, - integer *lda, doublereal *work, ftnlen norm_len); -extern doublereal dlangt_(char *norm, integer *n, doublereal *dl, - doublereal *d__, doublereal *du, ftnlen norm_len); -extern doublereal dlanhs_(char *norm, integer *n, doublereal *a, integer *lda, - doublereal *work, ftnlen norm_len); -extern doublereal dlansb_(char *norm, char *uplo, integer *n, integer *k, - doublereal *ab, integer *ldab, doublereal *work, - ftnlen norm_len, ftnlen uplo_len); -extern doublereal dlansp_(char *norm, char *uplo, integer *n, doublereal *ap, - doublereal *work, ftnlen norm_len, ftnlen uplo_len); -extern doublereal dlanst_(char *norm, integer *n, doublereal *d__, - doublereal *e, ftnlen norm_len); -extern doublereal dlansy_(char *norm, char *uplo, integer *n, doublereal *a, - integer *lda, doublereal *work, ftnlen norm_len, - ftnlen uplo_len); -extern doublereal dlantb_(char *norm, char *uplo, char *diag, integer *n, - integer *k, doublereal *ab, integer *ldab, - doublereal *work, ftnlen norm_len, ftnlen uplo_len, - ftnlen diag_len); -extern doublereal dlantp_(char *norm, char *uplo, char *diag, integer *n, - doublereal *ap, doublereal *work, ftnlen norm_len, - ftnlen uplo_len, ftnlen diag_len); -extern doublereal dlantr_(char *norm, char *uplo, char *diag, integer *m, - integer *n, doublereal *a, integer *lda, - doublereal *work, ftnlen norm_len, ftnlen uplo_len, - ftnlen diag_len); -extern int dlanv2_(doublereal *a, doublereal *b, doublereal *c__, - doublereal *d__, doublereal *rt1r, doublereal *rt1i, - doublereal *rt2r, doublereal *rt2i, doublereal *cs, - doublereal *sn); -extern int dlapll_(integer *n, doublereal *x, integer *incx, doublereal *y, - integer *incy, doublereal *ssmin); -extern int dlapmt_(logical *forwrd, integer *m, integer *n, doublereal *x, - integer *ldx, integer *k); -extern doublereal dlapy2_(doublereal *x, doublereal *y); -extern doublereal dlapy3_(doublereal *x, doublereal *y, doublereal *z__); -extern int dlaqgb_(integer *m, integer *n, integer *kl, integer *ku, - doublereal *ab, integer *ldab, doublereal *r__, - doublereal *c__, doublereal *rowcnd, doublereal *colcnd, - doublereal *amax, char *equed, ftnlen equed_len); -extern int dlaqge_(integer *m, integer *n, doublereal *a, integer *lda, - doublereal *r__, doublereal *c__, doublereal *rowcnd, - doublereal *colcnd, doublereal *amax, char *equed, - ftnlen equed_len); -extern int dlaqp2_(integer *m, integer *n, integer *offset, doublereal *a, - integer *lda, integer *jpvt, doublereal *tau, - doublereal *vn1, doublereal *vn2, doublereal *work); -extern int dlaqps_(integer *m, integer *n, integer *offset, integer *nb, - integer *kb, doublereal *a, integer *lda, integer *jpvt, - doublereal *tau, doublereal *vn1, doublereal *vn2, - doublereal *auxv, doublereal *f, integer *ldf); -extern int dlaqsb_(char *uplo, integer *n, integer *kd, doublereal *ab, - integer *ldab, doublereal *s, doublereal *scond, - doublereal *amax, char *equed, ftnlen uplo_len, - ftnlen equed_len); -extern int dlaqsp_(char *uplo, integer *n, doublereal *ap, doublereal *s, - doublereal *scond, doublereal *amax, char *equed, - ftnlen uplo_len, ftnlen equed_len); -extern int dlaqsy_(char *uplo, integer *n, doublereal *a, integer *lda, - doublereal *s, doublereal *scond, doublereal *amax, - char *equed, ftnlen uplo_len, ftnlen equed_len); -extern int dlaqtr_(logical *ltran, logical *lreal, integer *n, doublereal *t, - integer *ldt, doublereal *b, doublereal *w, - doublereal *scale, doublereal *x, doublereal *work, - integer *info); -extern int dlar1v_(integer *n, integer *b1, integer *bn, doublereal *sigma, - doublereal *d__, doublereal *l, doublereal *ld, - doublereal *lld, doublereal *gersch, doublereal *z__, - doublereal *ztz, doublereal *mingma, integer *r__, - integer *isuppz, doublereal *work); -extern int dlar2v_(integer *n, doublereal *x, doublereal *y, doublereal *z__, - integer *incx, doublereal *c__, doublereal *s, - integer *incc); -extern int dlarf_(char *side, integer *m, integer *n, doublereal *v, - integer *incv, doublereal *tau, doublereal *c__, integer *ldc, - doublereal *work, ftnlen side_len); -extern int dlarfb_(char *side, char *trans, char *direct, char *storev, - integer *m, integer *n, integer *k, doublereal *v, - integer *ldv, doublereal *t, integer *ldt, doublereal *c__, - integer *ldc, doublereal *work, integer *ldwork, - ftnlen side_len, ftnlen trans_len, ftnlen direct_len, - ftnlen storev_len); -extern int dlarfg_(integer *n, doublereal *alpha, doublereal *x, integer *incx, - doublereal *tau); -extern int dlarft_(char *direct, char *storev, integer *n, integer *k, - doublereal *v, integer *ldv, doublereal *tau, doublereal *t, - integer *ldt, ftnlen direct_len, ftnlen storev_len); -extern int dlarfx_(char *side, integer *m, integer *n, doublereal *v, - doublereal *tau, doublereal *c__, integer *ldc, - doublereal *work, ftnlen side_len); -extern int dlargv_(integer *n, doublereal *x, integer *incx, doublereal *y, - integer *incy, doublereal *c__, integer *incc); -extern int dlarnv_(integer *idist, integer *iseed, integer *n, doublereal *x); -extern int dlarrb_(integer *n, doublereal *d__, doublereal *l, doublereal *ld, - doublereal *lld, integer *ifirst, integer *ilast, - doublereal *sigma, doublereal *reltol, doublereal *w, - doublereal *wgap, doublereal *werr, doublereal *work, - integer *iwork, integer *info); -extern int dlarre_(integer *n, doublereal *d__, doublereal *e, doublereal *tol, - integer *nsplit, integer *isplit, integer *m, doublereal *w, - doublereal *woff, doublereal *gersch, doublereal *work, - integer *info); -extern int dlarrf_(integer *n, doublereal *d__, doublereal *l, doublereal *ld, - doublereal *lld, integer *ifirst, integer *ilast, - doublereal *w, doublereal *dplus, doublereal *lplus, - doublereal *work, integer *iwork, integer *info); -extern int dlarrv_(integer *n, doublereal *d__, doublereal *l, integer *isplit, - integer *m, doublereal *w, integer *iblock, - doublereal *gersch, doublereal *tol, doublereal *z__, - integer *ldz, integer *isuppz, doublereal *work, - integer *iwork, integer *info); -extern int dlartg_(doublereal *f, doublereal *g, doublereal *cs, doublereal *sn, - doublereal *r__); -extern int dlartv_(integer *n, doublereal *x, integer *incx, doublereal *y, - integer *incy, doublereal *c__, doublereal *s, - integer *incc); -extern int dlaruv_(integer *iseed, integer *n, doublereal *x); -extern int dlarz_(char *side, integer *m, integer *n, integer *l, doublereal *v, - integer *incv, doublereal *tau, doublereal *c__, integer *ldc, - doublereal *work, ftnlen side_len); -extern int dlarzb_(char *side, char *trans, char *direct, char *storev, - integer *m, integer *n, integer *k, integer *l, - doublereal *v, integer *ldv, doublereal *t, integer *ldt, - doublereal *c__, integer *ldc, doublereal *work, - integer *ldwork, ftnlen side_len, ftnlen trans_len, - ftnlen direct_len, ftnlen storev_len); -extern int dlarzt_(char *direct, char *storev, integer *n, integer *k, - doublereal *v, integer *ldv, doublereal *tau, doublereal *t, - integer *ldt, ftnlen direct_len, ftnlen storev_len); -extern int dlas2_(doublereal *f, doublereal *g, doublereal *h__, - doublereal *ssmin, doublereal *ssmax); -extern int dlascl_(char *type__, integer *kl, integer *ku, doublereal *cfrom, - doublereal *cto, integer *m, integer *n, doublereal *a, - integer *lda, integer *info, ftnlen type_len); -extern int dlasd0_(integer *n, integer *sqre, doublereal *d__, doublereal *e, - doublereal *u, integer *ldu, doublereal *vt, integer *ldvt, - integer *smlsiz, integer *iwork, doublereal *work, - integer *info); -extern int dlasd1_(integer *nl, integer *nr, integer *sqre, doublereal *d__, - doublereal *alpha, doublereal *beta, doublereal *u, - integer *ldu, doublereal *vt, integer *ldvt, integer *idxq, - integer *iwork, doublereal *work, integer *info); -extern int dlasd2_(integer *nl, integer *nr, integer *sqre, integer *k, - doublereal *d__, doublereal *z__, doublereal *alpha, - doublereal *beta, doublereal *u, integer *ldu, - doublereal *vt, integer *ldvt, doublereal *dsigma, - doublereal *u2, integer *ldu2, doublereal *vt2, - integer *ldvt2, integer *idxp, integer *idx, integer *idxc, - integer *idxq, integer *coltyp, integer *info); -extern int dlasd3_(integer *nl, integer *nr, integer *sqre, integer *k, - doublereal *d__, doublereal *q, integer *ldq, - doublereal *dsigma, doublereal *u, integer *ldu, - doublereal *u2, integer *ldu2, doublereal *vt, integer *ldvt, - doublereal *vt2, integer *ldvt2, integer *idxc, - integer *ctot, doublereal *z__, integer *info); -extern int dlasd4_(integer *n, integer *i__, doublereal *d__, doublereal *z__, - doublereal *delta, doublereal *rho, doublereal *sigma, - doublereal *work, integer *info); -extern int dlasd5_(integer *i__, doublereal *d__, doublereal *z__, - doublereal *delta, doublereal *rho, doublereal *dsigma, - doublereal *work); -extern int dlasd6_(integer *icompq, integer *nl, integer *nr, integer *sqre, - doublereal *d__, doublereal *vf, doublereal *vl, - doublereal *alpha, doublereal *beta, integer *idxq, - integer *perm, integer *givptr, integer *givcol, - integer *ldgcol, doublereal *givnum, integer *ldgnum, - doublereal *poles, doublereal *difl, doublereal *difr, - doublereal *z__, integer *k, doublereal *c__, doublereal *s, - doublereal *work, integer *iwork, integer *info); -extern int dlasd7_(integer *icompq, integer *nl, integer *nr, integer *sqre, - integer *k, doublereal *d__, doublereal *z__, doublereal *zw, - doublereal *vf, doublereal *vfw, doublereal *vl, - doublereal *vlw, doublereal *alpha, doublereal *beta, - doublereal *dsigma, integer *idx, integer *idxp, - integer *idxq, integer *perm, integer *givptr, - integer *givcol, integer *ldgcol, doublereal *givnum, - integer *ldgnum, doublereal *c__, doublereal *s, - integer *info); -extern int dlasd8_(integer *icompq, integer *k, doublereal *d__, - doublereal *z__, doublereal *vf, doublereal *vl, - doublereal *difl, doublereal *difr, integer *lddifr, - doublereal *dsigma, doublereal *work, integer *info); -extern int dlasd9_(integer *icompq, integer *ldu, integer *k, doublereal *d__, - doublereal *z__, doublereal *vf, doublereal *vl, - doublereal *difl, doublereal *difr, doublereal *dsigma, - doublereal *work, integer *info); -extern int dlasda_(integer *icompq, integer *smlsiz, integer *n, integer *sqre, - doublereal *d__, doublereal *e, doublereal *u, integer *ldu, - doublereal *vt, integer *k, doublereal *difl, - doublereal *difr, doublereal *z__, doublereal *poles, - integer *givptr, integer *givcol, integer *ldgcol, - integer *perm, doublereal *givnum, doublereal *c__, - doublereal *s, doublereal *work, integer *iwork, - integer *info); -extern int dlasdq_(char *uplo, integer *sqre, integer *n, integer *ncvt, - integer *nru, integer *ncc, doublereal *d__, doublereal *e, - doublereal *vt, integer *ldvt, doublereal *u, integer *ldu, - doublereal *c__, integer *ldc, doublereal *work, - integer *info, ftnlen uplo_len); -extern int dlasdt_(integer *n, integer *lvl, integer *nd, integer *inode, - integer *ndiml, integer *ndimr, integer *msub); -extern int dlaset_(char *uplo, integer *m, integer *n, doublereal *alpha, - doublereal *beta, doublereal *a, integer *lda, - ftnlen uplo_len); -extern int dlasq1_(integer *n, doublereal *d__, doublereal *e, doublereal *work, - integer *info); -extern int dlasq2_(integer *n, doublereal *z__, integer *info); -extern int dlasq3_(integer *i0, integer *n0, doublereal *z__, integer *pp, - doublereal *dmin__, doublereal *sigma, doublereal *desig, - doublereal *qmax, integer *nfail, integer *iter, - integer *ndiv); -extern int dlasq4_(integer *i0, integer *n0, doublereal *z__, integer *pp, - integer *n0in, doublereal *dmin__, doublereal *dmin1, - doublereal *dmin2, doublereal *dn, doublereal *dn1, - doublereal *dn2, doublereal *tau, integer *ttype); -extern int dlasq5_(integer *i0, integer *n0, doublereal *z__, integer *pp, - doublereal *tau, doublereal *dmin__, doublereal *dmin1, - doublereal *dmin2, doublereal *dn, doublereal *dnm1, - doublereal *dnm2); -extern int dlasq6_(integer *i0, integer *n0, doublereal *z__, integer *pp, - doublereal *dmin__, doublereal *dmin1, doublereal *dmin2, - doublereal *dn, doublereal *dnm1, doublereal *dnm2); -extern int dlasr_(char *side, char *pivot, char *direct, integer *m, integer *n, - doublereal *c__, doublereal *s, doublereal *a, integer *lda, - ftnlen side_len, ftnlen pivot_len, ftnlen direct_len); -extern int dlasrt_(char *id, integer *n, doublereal *d__, integer *info, - ftnlen id_len); -extern int dlassq_(integer *n, doublereal *x, integer *incx, doublereal *scale, - doublereal *sumsq); -extern int dlasv2_(doublereal *f, doublereal *g, doublereal *h__, - doublereal *ssmin, doublereal *ssmax, doublereal *snr, - doublereal *csr, doublereal *snl, doublereal *csl); -extern int dlaswp_(integer *n, doublereal *a, integer *lda, integer *k1, - integer *k2, integer *ipiv, integer *incx); -extern int dlasy2_(logical *ltranl, logical *ltranr, integer *isgn, integer *n1, - integer *n2, doublereal *tl, integer *ldtl, doublereal *tr, - integer *ldtr, doublereal *b, integer *ldb, - doublereal *scale, doublereal *x, integer *ldx, - doublereal *xnorm, integer *info); -extern int dlasyf_(char *uplo, integer *n, integer *nb, integer *kb, - doublereal *a, integer *lda, integer *ipiv, doublereal *w, - integer *ldw, integer *info, ftnlen uplo_len); -extern int dlatbs_(char *uplo, char *trans, char *diag, char *normin, - integer *n, integer *kd, doublereal *ab, integer *ldab, - doublereal *x, doublereal *scale, doublereal *cnorm, - integer *info, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len, ftnlen normin_len); -extern int dlatdf_(integer *ijob, integer *n, doublereal *z__, integer *ldz, - doublereal *rhs, doublereal *rdsum, doublereal *rdscal, - integer *ipiv, integer *jpiv); -extern int dlatps_(char *uplo, char *trans, char *diag, char *normin, - integer *n, doublereal *ap, doublereal *x, doublereal *scale, - doublereal *cnorm, integer *info, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len, ftnlen normin_len); -extern int dlatrd_(char *uplo, integer *n, integer *nb, doublereal *a, - integer *lda, doublereal *e, doublereal *tau, doublereal *w, - integer *ldw, ftnlen uplo_len); -extern int dlatrs_(char *uplo, char *trans, char *diag, char *normin, - integer *n, doublereal *a, integer *lda, doublereal *x, - doublereal *scale, doublereal *cnorm, integer *info, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len, - ftnlen normin_len); -extern int dlatrz_(integer *m, integer *n, integer *l, doublereal *a, - integer *lda, doublereal *tau, doublereal *work); -extern int dlatzm_(char *side, integer *m, integer *n, doublereal *v, - integer *incv, doublereal *tau, doublereal *c1, - doublereal *c2, integer *ldc, doublereal *work, - ftnlen side_len); -extern int dlauu2_(char *uplo, integer *n, doublereal *a, integer *lda, - integer *info, ftnlen uplo_len); -extern int dlauum_(char *uplo, integer *n, doublereal *a, integer *lda, - integer *info, ftnlen uplo_len); -extern int dopgtr_(char *uplo, integer *n, doublereal *ap, doublereal *tau, - doublereal *q, integer *ldq, doublereal *work, integer *info, - ftnlen uplo_len); -extern int dopmtr_(char *side, char *uplo, char *trans, integer *m, integer *n, - doublereal *ap, doublereal *tau, doublereal *c__, - integer *ldc, doublereal *work, integer *info, - ftnlen side_len, ftnlen uplo_len, ftnlen trans_len); -extern int dorg2l_(integer *m, integer *n, integer *k, doublereal *a, - integer *lda, doublereal *tau, doublereal *work, - integer *info); -extern int dorg2r_(integer *m, integer *n, integer *k, doublereal *a, - integer *lda, doublereal *tau, doublereal *work, - integer *info); -extern int dorgbr_(char *vect, integer *m, integer *n, integer *k, - doublereal *a, integer *lda, doublereal *tau, - doublereal *work, integer *lwork, integer *info, - ftnlen vect_len); -extern int dorghr_(integer *n, integer *ilo, integer *ihi, doublereal *a, - integer *lda, doublereal *tau, doublereal *work, - integer *lwork, integer *info); -extern int dorgl2_(integer *m, integer *n, integer *k, doublereal *a, - integer *lda, doublereal *tau, doublereal *work, - integer *info); -extern int dorglq_(integer *m, integer *n, integer *k, doublereal *a, - integer *lda, doublereal *tau, doublereal *work, - integer *lwork, integer *info); -extern int dorgql_(integer *m, integer *n, integer *k, doublereal *a, - integer *lda, doublereal *tau, doublereal *work, - integer *lwork, integer *info); -extern int dorgqr_(integer *m, integer *n, integer *k, doublereal *a, - integer *lda, doublereal *tau, doublereal *work, - integer *lwork, integer *info); -extern int dorgr2_(integer *m, integer *n, integer *k, doublereal *a, - integer *lda, doublereal *tau, doublereal *work, - integer *info); -extern int dorgrq_(integer *m, integer *n, integer *k, doublereal *a, - integer *lda, doublereal *tau, doublereal *work, - integer *lwork, integer *info); -extern int dorgtr_(char *uplo, integer *n, doublereal *a, integer *lda, - doublereal *tau, doublereal *work, integer *lwork, - integer *info, ftnlen uplo_len); -extern int dorm2l_(char *side, char *trans, integer *m, integer *n, integer *k, - doublereal *a, integer *lda, doublereal *tau, - doublereal *c__, integer *ldc, doublereal *work, - integer *info, ftnlen side_len, ftnlen trans_len); -extern int dorm2r_(char *side, char *trans, integer *m, integer *n, integer *k, - doublereal *a, integer *lda, doublereal *tau, - doublereal *c__, integer *ldc, doublereal *work, - integer *info, ftnlen side_len, ftnlen trans_len); -extern int dormbr_(char *vect, char *side, char *trans, integer *m, integer *n, - integer *k, doublereal *a, integer *lda, doublereal *tau, - doublereal *c__, integer *ldc, doublereal *work, - integer *lwork, integer *info, ftnlen vect_len, - ftnlen side_len, ftnlen trans_len); -extern int dormhr_(char *side, char *trans, integer *m, integer *n, - integer *ilo, integer *ihi, doublereal *a, integer *lda, - doublereal *tau, doublereal *c__, integer *ldc, - doublereal *work, integer *lwork, integer *info, - ftnlen side_len, ftnlen trans_len); -extern int dorml2_(char *side, char *trans, integer *m, integer *n, integer *k, - doublereal *a, integer *lda, doublereal *tau, - doublereal *c__, integer *ldc, doublereal *work, - integer *info, ftnlen side_len, ftnlen trans_len); -extern int dormlq_(char *side, char *trans, integer *m, integer *n, integer *k, - doublereal *a, integer *lda, doublereal *tau, - doublereal *c__, integer *ldc, doublereal *work, - integer *lwork, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int dormql_(char *side, char *trans, integer *m, integer *n, integer *k, - doublereal *a, integer *lda, doublereal *tau, - doublereal *c__, integer *ldc, doublereal *work, - integer *lwork, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int dormqr_(char *side, char *trans, integer *m, integer *n, integer *k, - doublereal *a, integer *lda, doublereal *tau, - doublereal *c__, integer *ldc, doublereal *work, - integer *lwork, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int dormr2_(char *side, char *trans, integer *m, integer *n, integer *k, - doublereal *a, integer *lda, doublereal *tau, - doublereal *c__, integer *ldc, doublereal *work, - integer *info, ftnlen side_len, ftnlen trans_len); -extern int dormr3_(char *side, char *trans, integer *m, integer *n, integer *k, - integer *l, doublereal *a, integer *lda, doublereal *tau, - doublereal *c__, integer *ldc, doublereal *work, - integer *info, ftnlen side_len, ftnlen trans_len); -extern int dormrq_(char *side, char *trans, integer *m, integer *n, integer *k, - doublereal *a, integer *lda, doublereal *tau, - doublereal *c__, integer *ldc, doublereal *work, - integer *lwork, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int dormrz_(char *side, char *trans, integer *m, integer *n, integer *k, - integer *l, doublereal *a, integer *lda, doublereal *tau, - doublereal *c__, integer *ldc, doublereal *work, - integer *lwork, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int dormtr_(char *side, char *uplo, char *trans, integer *m, integer *n, - doublereal *a, integer *lda, doublereal *tau, - doublereal *c__, integer *ldc, doublereal *work, - integer *lwork, integer *info, ftnlen side_len, - ftnlen uplo_len, ftnlen trans_len); -extern int dpbcon_(char *uplo, integer *n, integer *kd, doublereal *ab, - integer *ldab, doublereal *anorm, doublereal *rcond, - doublereal *work, integer *iwork, integer *info, - ftnlen uplo_len); -extern int dpbequ_(char *uplo, integer *n, integer *kd, doublereal *ab, - integer *ldab, doublereal *s, doublereal *scond, - doublereal *amax, integer *info, ftnlen uplo_len); -extern int dpbrfs_(char *uplo, integer *n, integer *kd, integer *nrhs, - doublereal *ab, integer *ldab, doublereal *afb, - integer *ldafb, doublereal *b, integer *ldb, doublereal *x, - integer *ldx, doublereal *ferr, doublereal *berr, - doublereal *work, integer *iwork, integer *info, - ftnlen uplo_len); -extern int dpbstf_(char *uplo, integer *n, integer *kd, doublereal *ab, - integer *ldab, integer *info, ftnlen uplo_len); -extern int dpbsv_(char *uplo, integer *n, integer *kd, integer *nrhs, - doublereal *ab, integer *ldab, doublereal *b, integer *ldb, - integer *info, ftnlen uplo_len); -extern int dpbsvx_(char *fact, char *uplo, integer *n, integer *kd, - integer *nrhs, doublereal *ab, integer *ldab, - doublereal *afb, integer *ldafb, char *equed, doublereal *s, - doublereal *b, integer *ldb, doublereal *x, integer *ldx, - doublereal *rcond, doublereal *ferr, doublereal *berr, - doublereal *work, integer *iwork, integer *info, - ftnlen fact_len, ftnlen uplo_len, ftnlen equed_len); -extern int dpbtf2_(char *uplo, integer *n, integer *kd, doublereal *ab, - integer *ldab, integer *info, ftnlen uplo_len); -extern int dpbtrf_(char *uplo, integer *n, integer *kd, doublereal *ab, - integer *ldab, integer *info, ftnlen uplo_len); -extern int dpbtrs_(char *uplo, integer *n, integer *kd, integer *nrhs, - doublereal *ab, integer *ldab, doublereal *b, integer *ldb, - integer *info, ftnlen uplo_len); -extern int dpocon_(char *uplo, integer *n, doublereal *a, integer *lda, - doublereal *anorm, doublereal *rcond, doublereal *work, - integer *iwork, integer *info, ftnlen uplo_len); -extern int dpoequ_(integer *n, doublereal *a, integer *lda, doublereal *s, - doublereal *scond, doublereal *amax, integer *info); -extern int dporfs_(char *uplo, integer *n, integer *nrhs, doublereal *a, - integer *lda, doublereal *af, integer *ldaf, doublereal *b, - integer *ldb, doublereal *x, integer *ldx, doublereal *ferr, - doublereal *berr, doublereal *work, integer *iwork, - integer *info, ftnlen uplo_len); -extern int dposv_(char *uplo, integer *n, integer *nrhs, doublereal *a, - integer *lda, doublereal *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int dposvx_(char *fact, char *uplo, integer *n, integer *nrhs, - doublereal *a, integer *lda, doublereal *af, integer *ldaf, - char *equed, doublereal *s, doublereal *b, integer *ldb, - doublereal *x, integer *ldx, doublereal *rcond, - doublereal *ferr, doublereal *berr, doublereal *work, - integer *iwork, integer *info, ftnlen fact_len, - ftnlen uplo_len, ftnlen equed_len); -extern int dpotf2_(char *uplo, integer *n, doublereal *a, integer *lda, - integer *info, ftnlen uplo_len); -extern int dpotrf_(char *uplo, integer *n, doublereal *a, integer *lda, - integer *info, ftnlen uplo_len); -extern int dpotri_(char *uplo, integer *n, doublereal *a, integer *lda, - integer *info, ftnlen uplo_len); -extern int dpotrs_(char *uplo, integer *n, integer *nrhs, doublereal *a, - integer *lda, doublereal *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int dppcon_(char *uplo, integer *n, doublereal *ap, doublereal *anorm, - doublereal *rcond, doublereal *work, integer *iwork, - integer *info, ftnlen uplo_len); -extern int dppequ_(char *uplo, integer *n, doublereal *ap, doublereal *s, - doublereal *scond, doublereal *amax, integer *info, - ftnlen uplo_len); -extern int dpprfs_(char *uplo, integer *n, integer *nrhs, doublereal *ap, - doublereal *afp, doublereal *b, integer *ldb, doublereal *x, - integer *ldx, doublereal *ferr, doublereal *berr, - doublereal *work, integer *iwork, integer *info, - ftnlen uplo_len); -extern int dppsv_(char *uplo, integer *n, integer *nrhs, doublereal *ap, - doublereal *b, integer *ldb, integer *info, ftnlen uplo_len); -extern int dppsvx_(char *fact, char *uplo, integer *n, integer *nrhs, - doublereal *ap, doublereal *afp, char *equed, doublereal *s, - doublereal *b, integer *ldb, doublereal *x, integer *ldx, - doublereal *rcond, doublereal *ferr, doublereal *berr, - doublereal *work, integer *iwork, integer *info, - ftnlen fact_len, ftnlen uplo_len, ftnlen equed_len); -extern int dpptrf_(char *uplo, integer *n, doublereal *ap, integer *info, - ftnlen uplo_len); -extern int dpptri_(char *uplo, integer *n, doublereal *ap, integer *info, - ftnlen uplo_len); -extern int dpptrs_(char *uplo, integer *n, integer *nrhs, doublereal *ap, - doublereal *b, integer *ldb, integer *info, ftnlen uplo_len); -extern int dptcon_(integer *n, doublereal *d__, doublereal *e, - doublereal *anorm, doublereal *rcond, doublereal *work, - integer *info); -extern int dpteqr_(char *compz, integer *n, doublereal *d__, doublereal *e, - doublereal *z__, integer *ldz, doublereal *work, - integer *info, ftnlen compz_len); -extern int dptrfs_(integer *n, integer *nrhs, doublereal *d__, doublereal *e, - doublereal *df, doublereal *ef, doublereal *b, integer *ldb, - doublereal *x, integer *ldx, doublereal *ferr, - doublereal *berr, doublereal *work, integer *info); -extern int dptsv_(integer *n, integer *nrhs, doublereal *d__, doublereal *e, - doublereal *b, integer *ldb, integer *info); -extern int dptsvx_(char *fact, integer *n, integer *nrhs, doublereal *d__, - doublereal *e, doublereal *df, doublereal *ef, doublereal *b, - integer *ldb, doublereal *x, integer *ldx, doublereal *rcond, - doublereal *ferr, doublereal *berr, doublereal *work, - integer *info, ftnlen fact_len); -extern int dpttrf_(integer *n, doublereal *d__, doublereal *e, integer *info); -extern int dpttrs_(integer *n, integer *nrhs, doublereal *d__, doublereal *e, - doublereal *b, integer *ldb, integer *info); -extern int dptts2_(integer *n, integer *nrhs, doublereal *d__, doublereal *e, - doublereal *b, integer *ldb); -extern int drscl_(integer *n, doublereal *sa, doublereal *sx, integer *incx); -extern int dsbev_(char *jobz, char *uplo, integer *n, integer *kd, - doublereal *ab, integer *ldab, doublereal *w, doublereal *z__, - integer *ldz, doublereal *work, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int dsbevd_(char *jobz, char *uplo, integer *n, integer *kd, - doublereal *ab, integer *ldab, doublereal *w, - doublereal *z__, integer *ldz, doublereal *work, - integer *lwork, integer *iwork, integer *liwork, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int dsbevx_(char *jobz, char *range, char *uplo, integer *n, integer *kd, - doublereal *ab, integer *ldab, doublereal *q, integer *ldq, - doublereal *vl, doublereal *vu, integer *il, integer *iu, - doublereal *abstol, integer *m, doublereal *w, - doublereal *z__, integer *ldz, doublereal *work, - integer *iwork, integer *ifail, integer *info, - ftnlen jobz_len, ftnlen range_len, ftnlen uplo_len); -extern int dsbgst_(char *vect, char *uplo, integer *n, integer *ka, integer *kb, - doublereal *ab, integer *ldab, doublereal *bb, integer *ldbb, - doublereal *x, integer *ldx, doublereal *work, integer *info, - ftnlen vect_len, ftnlen uplo_len); -extern int dsbgv_(char *jobz, char *uplo, integer *n, integer *ka, integer *kb, - doublereal *ab, integer *ldab, doublereal *bb, integer *ldbb, - doublereal *w, doublereal *z__, integer *ldz, - doublereal *work, integer *info, ftnlen jobz_len, - ftnlen uplo_len); -extern int dsbgvd_(char *jobz, char *uplo, integer *n, integer *ka, integer *kb, - doublereal *ab, integer *ldab, doublereal *bb, integer *ldbb, - doublereal *w, doublereal *z__, integer *ldz, - doublereal *work, integer *lwork, integer *iwork, - integer *liwork, integer *info, ftnlen jobz_len, - ftnlen uplo_len); -extern int dsbgvx_(char *jobz, char *range, char *uplo, integer *n, integer *ka, - integer *kb, doublereal *ab, integer *ldab, doublereal *bb, - integer *ldbb, doublereal *q, integer *ldq, doublereal *vl, - doublereal *vu, integer *il, integer *iu, doublereal *abstol, - integer *m, doublereal *w, doublereal *z__, integer *ldz, - doublereal *work, integer *iwork, integer *ifail, - integer *info, ftnlen jobz_len, ftnlen range_len, - ftnlen uplo_len); -extern int dsbtrd_(char *vect, char *uplo, integer *n, integer *kd, - doublereal *ab, integer *ldab, doublereal *d__, - doublereal *e, doublereal *q, integer *ldq, doublereal *work, - integer *info, ftnlen vect_len, ftnlen uplo_len); -extern doublereal dsecnd_(void); -extern int dspcon_(char *uplo, integer *n, doublereal *ap, integer *ipiv, - doublereal *anorm, doublereal *rcond, doublereal *work, - integer *iwork, integer *info, ftnlen uplo_len); -extern int dspev_(char *jobz, char *uplo, integer *n, doublereal *ap, - doublereal *w, doublereal *z__, integer *ldz, - doublereal *work, integer *info, ftnlen jobz_len, - ftnlen uplo_len); -extern int dspevd_(char *jobz, char *uplo, integer *n, doublereal *ap, - doublereal *w, doublereal *z__, integer *ldz, - doublereal *work, integer *lwork, integer *iwork, - integer *liwork, integer *info, ftnlen jobz_len, - ftnlen uplo_len); -extern int dspevx_(char *jobz, char *range, char *uplo, integer *n, - doublereal *ap, doublereal *vl, doublereal *vu, integer *il, - integer *iu, doublereal *abstol, integer *m, doublereal *w, - doublereal *z__, integer *ldz, doublereal *work, - integer *iwork, integer *ifail, integer *info, - ftnlen jobz_len, ftnlen range_len, ftnlen uplo_len); -extern int dspgst_(integer *itype, char *uplo, integer *n, doublereal *ap, - doublereal *bp, integer *info, ftnlen uplo_len); -extern int dspgv_(integer *itype, char *jobz, char *uplo, integer *n, - doublereal *ap, doublereal *bp, doublereal *w, - doublereal *z__, integer *ldz, doublereal *work, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int dspgvd_(integer *itype, char *jobz, char *uplo, integer *n, - doublereal *ap, doublereal *bp, doublereal *w, - doublereal *z__, integer *ldz, doublereal *work, - integer *lwork, integer *iwork, integer *liwork, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int dspgvx_(integer *itype, char *jobz, char *range, char *uplo, - integer *n, doublereal *ap, doublereal *bp, doublereal *vl, - doublereal *vu, integer *il, integer *iu, doublereal *abstol, - integer *m, doublereal *w, doublereal *z__, integer *ldz, - doublereal *work, integer *iwork, integer *ifail, - integer *info, ftnlen jobz_len, ftnlen range_len, - ftnlen uplo_len); -extern int dsprfs_(char *uplo, integer *n, integer *nrhs, doublereal *ap, - doublereal *afp, integer *ipiv, doublereal *b, integer *ldb, - doublereal *x, integer *ldx, doublereal *ferr, - doublereal *berr, doublereal *work, integer *iwork, - integer *info, ftnlen uplo_len); -extern int dspsv_(char *uplo, integer *n, integer *nrhs, doublereal *ap, - integer *ipiv, doublereal *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int dspsvx_(char *fact, char *uplo, integer *n, integer *nrhs, - doublereal *ap, doublereal *afp, integer *ipiv, - doublereal *b, integer *ldb, doublereal *x, integer *ldx, - doublereal *rcond, doublereal *ferr, doublereal *berr, - doublereal *work, integer *iwork, integer *info, - ftnlen fact_len, ftnlen uplo_len); -extern int dsptrd_(char *uplo, integer *n, doublereal *ap, doublereal *d__, - doublereal *e, doublereal *tau, integer *info, - ftnlen uplo_len); -extern int dsptrf_(char *uplo, integer *n, doublereal *ap, integer *ipiv, - integer *info, ftnlen uplo_len); -extern int dsptri_(char *uplo, integer *n, doublereal *ap, integer *ipiv, - doublereal *work, integer *info, ftnlen uplo_len); -extern int dsptrs_(char *uplo, integer *n, integer *nrhs, doublereal *ap, - integer *ipiv, doublereal *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int dstebz_(char *range, char *order, integer *n, doublereal *vl, - doublereal *vu, integer *il, integer *iu, doublereal *abstol, - doublereal *d__, doublereal *e, integer *m, integer *nsplit, - doublereal *w, integer *iblock, integer *isplit, - doublereal *work, integer *iwork, integer *info, - ftnlen range_len, ftnlen order_len); -extern int dstedc_(char *compz, integer *n, doublereal *d__, doublereal *e, - doublereal *z__, integer *ldz, doublereal *work, - integer *lwork, integer *iwork, integer *liwork, - integer *info, ftnlen compz_len); -extern int dstegr_(char *jobz, char *range, integer *n, doublereal *d__, - doublereal *e, doublereal *vl, doublereal *vu, integer *il, - integer *iu, doublereal *abstol, integer *m, doublereal *w, - doublereal *z__, integer *ldz, integer *isuppz, - doublereal *work, integer *lwork, integer *iwork, - integer *liwork, integer *info, ftnlen jobz_len, - ftnlen range_len); -extern int dstein_(integer *n, doublereal *d__, doublereal *e, integer *m, - doublereal *w, integer *iblock, integer *isplit, - doublereal *z__, integer *ldz, doublereal *work, - integer *iwork, integer *ifail, integer *info); -extern int dsteqr_(char *compz, integer *n, doublereal *d__, doublereal *e, - doublereal *z__, integer *ldz, doublereal *work, - integer *info, ftnlen compz_len); -extern int dsterf_(integer *n, doublereal *d__, doublereal *e, integer *info); -extern int dstev_(char *jobz, integer *n, doublereal *d__, doublereal *e, - doublereal *z__, integer *ldz, doublereal *work, - integer *info, ftnlen jobz_len); -extern int dstevd_(char *jobz, integer *n, doublereal *d__, doublereal *e, - doublereal *z__, integer *ldz, doublereal *work, - integer *lwork, integer *iwork, integer *liwork, - integer *info, ftnlen jobz_len); -extern int dstevr_(char *jobz, char *range, integer *n, doublereal *d__, - doublereal *e, doublereal *vl, doublereal *vu, integer *il, - integer *iu, doublereal *abstol, integer *m, doublereal *w, - doublereal *z__, integer *ldz, integer *isuppz, - doublereal *work, integer *lwork, integer *iwork, - integer *liwork, integer *info, ftnlen jobz_len, - ftnlen range_len); -extern int dstevx_(char *jobz, char *range, integer *n, doublereal *d__, - doublereal *e, doublereal *vl, doublereal *vu, integer *il, - integer *iu, doublereal *abstol, integer *m, doublereal *w, - doublereal *z__, integer *ldz, doublereal *work, - integer *iwork, integer *ifail, integer *info, - ftnlen jobz_len, ftnlen range_len); -extern int dsycon_(char *uplo, integer *n, doublereal *a, integer *lda, - integer *ipiv, doublereal *anorm, doublereal *rcond, - doublereal *work, integer *iwork, integer *info, - ftnlen uplo_len); -extern int dsyev_(char *jobz, char *uplo, integer *n, doublereal *a, - integer *lda, doublereal *w, doublereal *work, integer *lwork, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int dsyevd_(char *jobz, char *uplo, integer *n, doublereal *a, - integer *lda, doublereal *w, doublereal *work, - integer *lwork, integer *iwork, integer *liwork, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int dsyevr_(char *jobz, char *range, char *uplo, integer *n, - doublereal *a, integer *lda, doublereal *vl, doublereal *vu, - integer *il, integer *iu, doublereal *abstol, integer *m, - doublereal *w, doublereal *z__, integer *ldz, - integer *isuppz, doublereal *work, integer *lwork, - integer *iwork, integer *liwork, integer *info, - ftnlen jobz_len, ftnlen range_len, ftnlen uplo_len); -extern int dsyevx_(char *jobz, char *range, char *uplo, integer *n, - doublereal *a, integer *lda, doublereal *vl, doublereal *vu, - integer *il, integer *iu, doublereal *abstol, integer *m, - doublereal *w, doublereal *z__, integer *ldz, - doublereal *work, integer *lwork, integer *iwork, - integer *ifail, integer *info, ftnlen jobz_len, - ftnlen range_len, ftnlen uplo_len); -extern int dsygs2_(integer *itype, char *uplo, integer *n, doublereal *a, - integer *lda, doublereal *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int dsygst_(integer *itype, char *uplo, integer *n, doublereal *a, - integer *lda, doublereal *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int dsygv_(integer *itype, char *jobz, char *uplo, integer *n, - doublereal *a, integer *lda, doublereal *b, integer *ldb, - doublereal *w, doublereal *work, integer *lwork, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int dsygvd_(integer *itype, char *jobz, char *uplo, integer *n, - doublereal *a, integer *lda, doublereal *b, integer *ldb, - doublereal *w, doublereal *work, integer *lwork, - integer *iwork, integer *liwork, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int dsygvx_(integer *itype, char *jobz, char *range, char *uplo, - integer *n, doublereal *a, integer *lda, doublereal *b, - integer *ldb, doublereal *vl, doublereal *vu, integer *il, - integer *iu, doublereal *abstol, integer *m, doublereal *w, - doublereal *z__, integer *ldz, doublereal *work, - integer *lwork, integer *iwork, integer *ifail, - integer *info, ftnlen jobz_len, ftnlen range_len, - ftnlen uplo_len); -extern int dsyrfs_(char *uplo, integer *n, integer *nrhs, doublereal *a, - integer *lda, doublereal *af, integer *ldaf, integer *ipiv, - doublereal *b, integer *ldb, doublereal *x, integer *ldx, - doublereal *ferr, doublereal *berr, doublereal *work, - integer *iwork, integer *info, ftnlen uplo_len); -extern int dsysv_(char *uplo, integer *n, integer *nrhs, doublereal *a, - integer *lda, integer *ipiv, doublereal *b, integer *ldb, - doublereal *work, integer *lwork, integer *info, - ftnlen uplo_len); -extern int dsysvx_(char *fact, char *uplo, integer *n, integer *nrhs, - doublereal *a, integer *lda, doublereal *af, integer *ldaf, - integer *ipiv, doublereal *b, integer *ldb, doublereal *x, - integer *ldx, doublereal *rcond, doublereal *ferr, - doublereal *berr, doublereal *work, integer *lwork, - integer *iwork, integer *info, ftnlen fact_len, - ftnlen uplo_len); -extern int dsytd2_(char *uplo, integer *n, doublereal *a, integer *lda, - doublereal *d__, doublereal *e, doublereal *tau, - integer *info, ftnlen uplo_len); -extern int dsytf2_(char *uplo, integer *n, doublereal *a, integer *lda, - integer *ipiv, integer *info, ftnlen uplo_len); -extern int dsytrd_(char *uplo, integer *n, doublereal *a, integer *lda, - doublereal *d__, doublereal *e, doublereal *tau, - doublereal *work, integer *lwork, integer *info, - ftnlen uplo_len); -extern int dsytrf_(char *uplo, integer *n, doublereal *a, integer *lda, - integer *ipiv, doublereal *work, integer *lwork, - integer *info, ftnlen uplo_len); -extern int dsytri_(char *uplo, integer *n, doublereal *a, integer *lda, - integer *ipiv, doublereal *work, integer *info, - ftnlen uplo_len); -extern int dsytrs_(char *uplo, integer *n, integer *nrhs, doublereal *a, - integer *lda, integer *ipiv, doublereal *b, integer *ldb, - integer *info, ftnlen uplo_len); -extern int dtbcon_(char *norm, char *uplo, char *diag, integer *n, integer *kd, - doublereal *ab, integer *ldab, doublereal *rcond, - doublereal *work, integer *iwork, integer *info, - ftnlen norm_len, ftnlen uplo_len, ftnlen diag_len); -extern int dtbrfs_(char *uplo, char *trans, char *diag, integer *n, integer *kd, - integer *nrhs, doublereal *ab, integer *ldab, doublereal *b, - integer *ldb, doublereal *x, integer *ldx, doublereal *ferr, - doublereal *berr, doublereal *work, integer *iwork, - integer *info, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len); -extern int dtbtrs_(char *uplo, char *trans, char *diag, integer *n, integer *kd, - integer *nrhs, doublereal *ab, integer *ldab, doublereal *b, - integer *ldb, integer *info, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern int dtgevc_(char *side, char *howmny, logical *select, integer *n, - doublereal *a, integer *lda, doublereal *b, integer *ldb, - doublereal *vl, integer *ldvl, doublereal *vr, integer *ldvr, - integer *mm, integer *m, doublereal *work, integer *info, - ftnlen side_len, ftnlen howmny_len); -extern int dtgex2_(logical *wantq, logical *wantz, integer *n, doublereal *a, - integer *lda, doublereal *b, integer *ldb, doublereal *q, - integer *ldq, doublereal *z__, integer *ldz, integer *j1, - integer *n1, integer *n2, doublereal *work, integer *lwork, - integer *info); -extern int dtgexc_(logical *wantq, logical *wantz, integer *n, doublereal *a, - integer *lda, doublereal *b, integer *ldb, doublereal *q, - integer *ldq, doublereal *z__, integer *ldz, integer *ifst, - integer *ilst, doublereal *work, integer *lwork, - integer *info); -extern int dtgsen_(integer *ijob, logical *wantq, logical *wantz, - logical *select, integer *n, doublereal *a, integer *lda, - doublereal *b, integer *ldb, doublereal *alphar, - doublereal *alphai, doublereal *beta, doublereal *q, - integer *ldq, doublereal *z__, integer *ldz, integer *m, - doublereal *pl, doublereal *pr, doublereal *dif, - doublereal *work, integer *lwork, integer *iwork, - integer *liwork, integer *info); -extern int dtgsja_(char *jobu, char *jobv, char *jobq, integer *m, integer *p, - integer *n, integer *k, integer *l, doublereal *a, - integer *lda, doublereal *b, integer *ldb, doublereal *tola, - doublereal *tolb, doublereal *alpha, doublereal *beta, - doublereal *u, integer *ldu, doublereal *v, integer *ldv, - doublereal *q, integer *ldq, doublereal *work, - integer *ncycle, integer *info, ftnlen jobu_len, - ftnlen jobv_len, ftnlen jobq_len); -extern int dtgsna_(char *job, char *howmny, logical *select, integer *n, - doublereal *a, integer *lda, doublereal *b, integer *ldb, - doublereal *vl, integer *ldvl, doublereal *vr, integer *ldvr, - doublereal *s, doublereal *dif, integer *mm, integer *m, - doublereal *work, integer *lwork, integer *iwork, - integer *info, ftnlen job_len, ftnlen howmny_len); -extern int dtgsy2_(char *trans, integer *ijob, integer *m, integer *n, - doublereal *a, integer *lda, doublereal *b, integer *ldb, - doublereal *c__, integer *ldc, doublereal *d__, integer *ldd, - doublereal *e, integer *lde, doublereal *f, integer *ldf, - doublereal *scale, doublereal *rdsum, doublereal *rdscal, - integer *iwork, integer *pq, integer *info, - ftnlen trans_len); -extern int dtgsyl_(char *trans, integer *ijob, integer *m, integer *n, - doublereal *a, integer *lda, doublereal *b, integer *ldb, - doublereal *c__, integer *ldc, doublereal *d__, integer *ldd, - doublereal *e, integer *lde, doublereal *f, integer *ldf, - doublereal *scale, doublereal *dif, doublereal *work, - integer *lwork, integer *iwork, integer *info, - ftnlen trans_len); -extern int dtpcon_(char *norm, char *uplo, char *diag, integer *n, - doublereal *ap, doublereal *rcond, doublereal *work, - integer *iwork, integer *info, ftnlen norm_len, - ftnlen uplo_len, ftnlen diag_len); -extern int dtprfs_(char *uplo, char *trans, char *diag, integer *n, - integer *nrhs, doublereal *ap, doublereal *b, integer *ldb, - doublereal *x, integer *ldx, doublereal *ferr, - doublereal *berr, doublereal *work, integer *iwork, - integer *info, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len); -extern int dtptri_(char *uplo, char *diag, integer *n, doublereal *ap, - integer *info, ftnlen uplo_len, ftnlen diag_len); -extern int dtptrs_(char *uplo, char *trans, char *diag, integer *n, - integer *nrhs, doublereal *ap, doublereal *b, integer *ldb, - integer *info, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len); -extern int dtrcon_(char *norm, char *uplo, char *diag, integer *n, - doublereal *a, integer *lda, doublereal *rcond, - doublereal *work, integer *iwork, integer *info, - ftnlen norm_len, ftnlen uplo_len, ftnlen diag_len); -extern int dtrevc_(char *side, char *howmny, logical *select, integer *n, - doublereal *t, integer *ldt, doublereal *vl, integer *ldvl, - doublereal *vr, integer *ldvr, integer *mm, integer *m, - doublereal *work, integer *info, ftnlen side_len, - ftnlen howmny_len); -extern int dtrexc_(char *compq, integer *n, doublereal *t, integer *ldt, - doublereal *q, integer *ldq, integer *ifst, integer *ilst, - doublereal *work, integer *info, ftnlen compq_len); -extern int dtrrfs_(char *uplo, char *trans, char *diag, integer *n, - integer *nrhs, doublereal *a, integer *lda, doublereal *b, - integer *ldb, doublereal *x, integer *ldx, doublereal *ferr, - doublereal *berr, doublereal *work, integer *iwork, - integer *info, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len); -extern int dtrsen_(char *job, char *compq, logical *select, integer *n, - doublereal *t, integer *ldt, doublereal *q, integer *ldq, - doublereal *wr, doublereal *wi, integer *m, doublereal *s, - doublereal *sep, doublereal *work, integer *lwork, - integer *iwork, integer *liwork, integer *info, - ftnlen job_len, ftnlen compq_len); -extern int dtrsna_(char *job, char *howmny, logical *select, integer *n, - doublereal *t, integer *ldt, doublereal *vl, integer *ldvl, - doublereal *vr, integer *ldvr, doublereal *s, - doublereal *sep, integer *mm, integer *m, doublereal *work, - integer *ldwork, integer *iwork, integer *info, - ftnlen job_len, ftnlen howmny_len); -extern int dtrsyl_(char *trana, char *tranb, integer *isgn, integer *m, - integer *n, doublereal *a, integer *lda, doublereal *b, - integer *ldb, doublereal *c__, integer *ldc, - doublereal *scale, integer *info, ftnlen trana_len, - ftnlen tranb_len); -extern int dtrti2_(char *uplo, char *diag, integer *n, doublereal *a, - integer *lda, integer *info, ftnlen uplo_len, - ftnlen diag_len); -extern int dtrtri_(char *uplo, char *diag, integer *n, doublereal *a, - integer *lda, integer *info, ftnlen uplo_len, - ftnlen diag_len); -extern int dtrtrs_(char *uplo, char *trans, char *diag, integer *n, - integer *nrhs, doublereal *a, integer *lda, doublereal *b, - integer *ldb, integer *info, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern int dtzrqf_(integer *m, integer *n, doublereal *a, integer *lda, - doublereal *tau, integer *info); -extern int dtzrzf_(integer *m, integer *n, doublereal *a, integer *lda, - doublereal *tau, doublereal *work, integer *lwork, - integer *info); -extern doublereal dzsum1_(integer *n, doublecomplex *cx, integer *incx); -extern integer icmax1_(integer *n, complex *cx, integer *incx); -extern integer ieeeck_(integer *ispec, real *zero, real *one); -extern integer ilaenv_(integer *ispec, char *name__, char *opts, integer *n1, - integer *n2, integer *n3, integer *n4, ftnlen name_len, - ftnlen opts_len); -extern integer izmax1_(integer *n, doublecomplex *cx, integer *incx); -extern logical lsame_(char *ca, char *cb, ftnlen ca_len, ftnlen cb_len); -extern logical lsamen_(integer *n, char *ca, char *cb, ftnlen ca_len, - ftnlen cb_len); -extern int sbdsdc_(char *uplo, char *compq, integer *n, real *d__, real *e, - real *u, integer *ldu, real *vt, integer *ldvt, real *q, - integer *iq, real *work, integer *iwork, integer *info, - ftnlen uplo_len, ftnlen compq_len); -extern int sbdsqr_(char *uplo, integer *n, integer *ncvt, integer *nru, - integer *ncc, real *d__, real *e, real *vt, integer *ldvt, - real *u, integer *ldu, real *c__, integer *ldc, real *work, - integer *info, ftnlen uplo_len); -extern E_f scsum1_(integer *n, complex *cx, integer *incx); -extern int sdisna_(char *job, integer *m, integer *n, real *d__, real *sep, - integer *info, ftnlen job_len); -extern E_f second_(void); -extern int sgbbrd_(char *vect, integer *m, integer *n, integer *ncc, - integer *kl, integer *ku, real *ab, integer *ldab, real *d__, - real *e, real *q, integer *ldq, real *pt, integer *ldpt, - real *c__, integer *ldc, real *work, integer *info, - ftnlen vect_len); -extern int sgbcon_(char *norm, integer *n, integer *kl, integer *ku, real *ab, - integer *ldab, integer *ipiv, real *anorm, real *rcond, - real *work, integer *iwork, integer *info, ftnlen norm_len); -extern int sgbequ_(integer *m, integer *n, integer *kl, integer *ku, real *ab, - integer *ldab, real *r__, real *c__, real *rowcnd, - real *colcnd, real *amax, integer *info); -extern int sgbrfs_(char *trans, integer *n, integer *kl, integer *ku, - integer *nrhs, real *ab, integer *ldab, real *afb, - integer *ldafb, integer *ipiv, real *b, integer *ldb, - real *x, integer *ldx, real *ferr, real *berr, real *work, - integer *iwork, integer *info, ftnlen trans_len); -extern int sgbsv_(integer *n, integer *kl, integer *ku, integer *nrhs, real *ab, - integer *ldab, integer *ipiv, real *b, integer *ldb, - integer *info); -extern int sgbsvx_(char *fact, char *trans, integer *n, integer *kl, - integer *ku, integer *nrhs, real *ab, integer *ldab, - real *afb, integer *ldafb, integer *ipiv, char *equed, - real *r__, real *c__, real *b, integer *ldb, real *x, - integer *ldx, real *rcond, real *ferr, real *berr, - real *work, integer *iwork, integer *info, ftnlen fact_len, - ftnlen trans_len, ftnlen equed_len); -extern int sgbtf2_(integer *m, integer *n, integer *kl, integer *ku, real *ab, - integer *ldab, integer *ipiv, integer *info); -extern int sgbtrf_(integer *m, integer *n, integer *kl, integer *ku, real *ab, - integer *ldab, integer *ipiv, integer *info); -extern int sgbtrs_(char *trans, integer *n, integer *kl, integer *ku, - integer *nrhs, real *ab, integer *ldab, integer *ipiv, - real *b, integer *ldb, integer *info, ftnlen trans_len); -extern int sgebak_(char *job, char *side, integer *n, integer *ilo, - integer *ihi, real *scale, integer *m, real *v, integer *ldv, - integer *info, ftnlen job_len, ftnlen side_len); -extern int sgebal_(char *job, integer *n, real *a, integer *lda, integer *ilo, - integer *ihi, real *scale, integer *info, ftnlen job_len); -extern int sgebd2_(integer *m, integer *n, real *a, integer *lda, real *d__, - real *e, real *tauq, real *taup, real *work, integer *info); -extern int sgebrd_(integer *m, integer *n, real *a, integer *lda, real *d__, - real *e, real *tauq, real *taup, real *work, integer *lwork, - integer *info); -extern int sgecon_(char *norm, integer *n, real *a, integer *lda, real *anorm, - real *rcond, real *work, integer *iwork, integer *info, - ftnlen norm_len); -extern int sgeequ_(integer *m, integer *n, real *a, integer *lda, real *r__, - real *c__, real *rowcnd, real *colcnd, real *amax, - integer *info); -extern int sgees_(char *jobvs, char *sort, L_fp select, integer *n, real *a, - integer *lda, integer *sdim, real *wr, real *wi, real *vs, - integer *ldvs, real *work, integer *lwork, logical *bwork, - integer *info, ftnlen jobvs_len, ftnlen sort_len); -extern int sgeesx_(char *jobvs, char *sort, L_fp select, char *sense, - integer *n, real *a, integer *lda, integer *sdim, real *wr, - real *wi, real *vs, integer *ldvs, real *rconde, - real *rcondv, real *work, integer *lwork, integer *iwork, - integer *liwork, logical *bwork, integer *info, - ftnlen jobvs_len, ftnlen sort_len, ftnlen sense_len); -extern int sgeev_(char *jobvl, char *jobvr, integer *n, real *a, integer *lda, - real *wr, real *wi, real *vl, integer *ldvl, real *vr, - integer *ldvr, real *work, integer *lwork, integer *info, - ftnlen jobvl_len, ftnlen jobvr_len); -extern int sgeevx_(char *balanc, char *jobvl, char *jobvr, char *sense, - integer *n, real *a, integer *lda, real *wr, real *wi, - real *vl, integer *ldvl, real *vr, integer *ldvr, - integer *ilo, integer *ihi, real *scale, real *abnrm, - real *rconde, real *rcondv, real *work, integer *lwork, - integer *iwork, integer *info, ftnlen balanc_len, - ftnlen jobvl_len, ftnlen jobvr_len, ftnlen sense_len); -extern int sgegs_(char *jobvsl, char *jobvsr, integer *n, real *a, integer *lda, - real *b, integer *ldb, real *alphar, real *alphai, real *beta, - real *vsl, integer *ldvsl, real *vsr, integer *ldvsr, - real *work, integer *lwork, integer *info, ftnlen jobvsl_len, - ftnlen jobvsr_len); -extern int sgegv_(char *jobvl, char *jobvr, integer *n, real *a, integer *lda, - real *b, integer *ldb, real *alphar, real *alphai, real *beta, - real *vl, integer *ldvl, real *vr, integer *ldvr, real *work, - integer *lwork, integer *info, ftnlen jobvl_len, - ftnlen jobvr_len); -extern int sgehd2_(integer *n, integer *ilo, integer *ihi, real *a, - integer *lda, real *tau, real *work, integer *info); -extern int sgehrd_(integer *n, integer *ilo, integer *ihi, real *a, - integer *lda, real *tau, real *work, integer *lwork, - integer *info); -extern int sgelq2_(integer *m, integer *n, real *a, integer *lda, real *tau, - real *work, integer *info); -extern int sgelqf_(integer *m, integer *n, real *a, integer *lda, real *tau, - real *work, integer *lwork, integer *info); -extern int sgels_(char *trans, integer *m, integer *n, integer *nrhs, real *a, - integer *lda, real *b, integer *ldb, real *work, - integer *lwork, integer *info, ftnlen trans_len); -extern int sgelsd_(integer *m, integer *n, integer *nrhs, real *a, integer *lda, - real *b, integer *ldb, real *s, real *rcond, integer *rank, - real *work, integer *lwork, integer *iwork, integer *info); -extern int sgelss_(integer *m, integer *n, integer *nrhs, real *a, integer *lda, - real *b, integer *ldb, real *s, real *rcond, integer *rank, - real *work, integer *lwork, integer *info); -extern int sgelsx_(integer *m, integer *n, integer *nrhs, real *a, integer *lda, - real *b, integer *ldb, integer *jpvt, real *rcond, - integer *rank, real *work, integer *info); -extern int sgelsy_(integer *m, integer *n, integer *nrhs, real *a, integer *lda, - real *b, integer *ldb, integer *jpvt, real *rcond, - integer *rank, real *work, integer *lwork, integer *info); -extern int sgeql2_(integer *m, integer *n, real *a, integer *lda, real *tau, - real *work, integer *info); -extern int sgeqlf_(integer *m, integer *n, real *a, integer *lda, real *tau, - real *work, integer *lwork, integer *info); -extern int sgeqp3_(integer *m, integer *n, real *a, integer *lda, integer *jpvt, - real *tau, real *work, integer *lwork, integer *info); -extern int sgeqpf_(integer *m, integer *n, real *a, integer *lda, integer *jpvt, - real *tau, real *work, integer *info); -extern int sgeqr2_(integer *m, integer *n, real *a, integer *lda, real *tau, - real *work, integer *info); -extern int sgeqrf_(integer *m, integer *n, real *a, integer *lda, real *tau, - real *work, integer *lwork, integer *info); -extern int sgerfs_(char *trans, integer *n, integer *nrhs, real *a, - integer *lda, real *af, integer *ldaf, integer *ipiv, - real *b, integer *ldb, real *x, integer *ldx, real *ferr, - real *berr, real *work, integer *iwork, integer *info, - ftnlen trans_len); -extern int sgerq2_(integer *m, integer *n, real *a, integer *lda, real *tau, - real *work, integer *info); -extern int sgerqf_(integer *m, integer *n, real *a, integer *lda, real *tau, - real *work, integer *lwork, integer *info); -extern int sgesc2_(integer *n, real *a, integer *lda, real *rhs, integer *ipiv, - integer *jpiv, real *scale); -extern int sgesdd_(char *jobz, integer *m, integer *n, real *a, integer *lda, - real *s, real *u, integer *ldu, real *vt, integer *ldvt, - real *work, integer *lwork, integer *iwork, integer *info, - ftnlen jobz_len); -extern int sgesv_(integer *n, integer *nrhs, real *a, integer *lda, - integer *ipiv, real *b, integer *ldb, integer *info); -extern int sgesvd_(char *jobu, char *jobvt, integer *m, integer *n, real *a, - integer *lda, real *s, real *u, integer *ldu, real *vt, - integer *ldvt, real *work, integer *lwork, integer *info, - ftnlen jobu_len, ftnlen jobvt_len); -extern int sgesvx_(char *fact, char *trans, integer *n, integer *nrhs, real *a, - integer *lda, real *af, integer *ldaf, integer *ipiv, - char *equed, real *r__, real *c__, real *b, integer *ldb, - real *x, integer *ldx, real *rcond, real *ferr, real *berr, - real *work, integer *iwork, integer *info, ftnlen fact_len, - ftnlen trans_len, ftnlen equed_len); -extern int sgetc2_(integer *n, real *a, integer *lda, integer *ipiv, - integer *jpiv, integer *info); -extern int sgetf2_(integer *m, integer *n, real *a, integer *lda, integer *ipiv, - integer *info); -extern int sgetrf_(integer *m, integer *n, real *a, integer *lda, integer *ipiv, - integer *info); -extern int sgetri_(integer *n, real *a, integer *lda, integer *ipiv, real *work, - integer *lwork, integer *info); -extern int sgetrs_(char *trans, integer *n, integer *nrhs, real *a, - integer *lda, integer *ipiv, real *b, integer *ldb, - integer *info, ftnlen trans_len); -extern int sggbak_(char *job, char *side, integer *n, integer *ilo, - integer *ihi, real *lscale, real *rscale, integer *m, - real *v, integer *ldv, integer *info, ftnlen job_len, - ftnlen side_len); -extern int sggbal_(char *job, integer *n, real *a, integer *lda, real *b, - integer *ldb, integer *ilo, integer *ihi, real *lscale, - real *rscale, real *work, integer *info, ftnlen job_len); -extern int sgges_(char *jobvsl, char *jobvsr, char *sort, L_fp selctg, - integer *n, real *a, integer *lda, real *b, integer *ldb, - integer *sdim, real *alphar, real *alphai, real *beta, - real *vsl, integer *ldvsl, real *vsr, integer *ldvsr, - real *work, integer *lwork, logical *bwork, integer *info, - ftnlen jobvsl_len, ftnlen jobvsr_len, ftnlen sort_len); -extern int sggesx_(char *jobvsl, char *jobvsr, char *sort, L_fp selctg, - char *sense, integer *n, real *a, integer *lda, real *b, - integer *ldb, integer *sdim, real *alphar, real *alphai, - real *beta, real *vsl, integer *ldvsl, real *vsr, - integer *ldvsr, real *rconde, real *rcondv, real *work, - integer *lwork, integer *iwork, integer *liwork, - logical *bwork, integer *info, ftnlen jobvsl_len, - ftnlen jobvsr_len, ftnlen sort_len, ftnlen sense_len); -extern int sggev_(char *jobvl, char *jobvr, integer *n, real *a, integer *lda, - real *b, integer *ldb, real *alphar, real *alphai, real *beta, - real *vl, integer *ldvl, real *vr, integer *ldvr, real *work, - integer *lwork, integer *info, ftnlen jobvl_len, - ftnlen jobvr_len); -extern int sggevx_(char *balanc, char *jobvl, char *jobvr, char *sense, - integer *n, real *a, integer *lda, real *b, integer *ldb, - real *alphar, real *alphai, real *beta, real *vl, - integer *ldvl, real *vr, integer *ldvr, integer *ilo, - integer *ihi, real *lscale, real *rscale, real *abnrm, - real *bbnrm, real *rconde, real *rcondv, real *work, - integer *lwork, integer *iwork, logical *bwork, - integer *info, ftnlen balanc_len, ftnlen jobvl_len, - ftnlen jobvr_len, ftnlen sense_len); -extern int sggglm_(integer *n, integer *m, integer *p, real *a, integer *lda, - real *b, integer *ldb, real *d__, real *x, real *y, - real *work, integer *lwork, integer *info); -extern int sgghrd_(char *compq, char *compz, integer *n, integer *ilo, - integer *ihi, real *a, integer *lda, real *b, integer *ldb, - real *q, integer *ldq, real *z__, integer *ldz, - integer *info, ftnlen compq_len, ftnlen compz_len); -extern int sgglse_(integer *m, integer *n, integer *p, real *a, integer *lda, - real *b, integer *ldb, real *c__, real *d__, real *x, - real *work, integer *lwork, integer *info); -extern int sggqrf_(integer *n, integer *m, integer *p, real *a, integer *lda, - real *taua, real *b, integer *ldb, real *taub, real *work, - integer *lwork, integer *info); -extern int sggrqf_(integer *m, integer *p, integer *n, real *a, integer *lda, - real *taua, real *b, integer *ldb, real *taub, real *work, - integer *lwork, integer *info); -extern int sggsvd_(char *jobu, char *jobv, char *jobq, integer *m, integer *n, - integer *p, integer *k, integer *l, real *a, integer *lda, - real *b, integer *ldb, real *alpha, real *beta, real *u, - integer *ldu, real *v, integer *ldv, real *q, integer *ldq, - real *work, integer *iwork, integer *info, ftnlen jobu_len, - ftnlen jobv_len, ftnlen jobq_len); -extern int sggsvp_(char *jobu, char *jobv, char *jobq, integer *m, integer *p, - integer *n, real *a, integer *lda, real *b, integer *ldb, - real *tola, real *tolb, integer *k, integer *l, real *u, - integer *ldu, real *v, integer *ldv, real *q, integer *ldq, - integer *iwork, real *tau, real *work, integer *info, - ftnlen jobu_len, ftnlen jobv_len, ftnlen jobq_len); -extern int sgtcon_(char *norm, integer *n, real *dl, real *d__, real *du, - real *du2, integer *ipiv, real *anorm, real *rcond, - real *work, integer *iwork, integer *info, ftnlen norm_len); -extern int sgtrfs_(char *trans, integer *n, integer *nrhs, real *dl, real *d__, - real *du, real *dlf, real *df, real *duf, real *du2, - integer *ipiv, real *b, integer *ldb, real *x, integer *ldx, - real *ferr, real *berr, real *work, integer *iwork, - integer *info, ftnlen trans_len); -extern int sgtsv_(integer *n, integer *nrhs, real *dl, real *d__, real *du, - real *b, integer *ldb, integer *info); -extern int sgtsvx_(char *fact, char *trans, integer *n, integer *nrhs, real *dl, - real *d__, real *du, real *dlf, real *df, real *duf, - real *du2, integer *ipiv, real *b, integer *ldb, real *x, - integer *ldx, real *rcond, real *ferr, real *berr, - real *work, integer *iwork, integer *info, ftnlen fact_len, - ftnlen trans_len); -extern int sgttrf_(integer *n, real *dl, real *d__, real *du, real *du2, - integer *ipiv, integer *info); -extern int sgttrs_(char *trans, integer *n, integer *nrhs, real *dl, real *d__, - real *du, real *du2, integer *ipiv, real *b, integer *ldb, - integer *info, ftnlen trans_len); -extern int sgtts2_(integer *itrans, integer *n, integer *nrhs, real *dl, - real *d__, real *du, real *du2, integer *ipiv, real *b, - integer *ldb); -extern int shgeqz_(char *job, char *compq, char *compz, integer *n, - integer *ilo, integer *ihi, real *a, integer *lda, real *b, - integer *ldb, real *alphar, real *alphai, real *beta, - real *q, integer *ldq, real *z__, integer *ldz, real *work, - integer *lwork, integer *info, ftnlen job_len, - ftnlen compq_len, ftnlen compz_len); -extern int shsein_(char *side, char *eigsrc, char *initv, logical *select, - integer *n, real *h__, integer *ldh, real *wr, real *wi, - real *vl, integer *ldvl, real *vr, integer *ldvr, - integer *mm, integer *m, real *work, integer *ifaill, - integer *ifailr, integer *info, ftnlen side_len, - ftnlen eigsrc_len, ftnlen initv_len); -extern int shseqr_(char *job, char *compz, integer *n, integer *ilo, - integer *ihi, real *h__, integer *ldh, real *wr, real *wi, - real *z__, integer *ldz, real *work, integer *lwork, - integer *info, ftnlen job_len, ftnlen compz_len); -extern int slabad_(real *small, real *large); -extern int slabrd_(integer *m, integer *n, integer *nb, real *a, integer *lda, - real *d__, real *e, real *tauq, real *taup, real *x, - integer *ldx, real *y, integer *ldy); -extern int slacon_(integer *n, real *v, real *x, integer *isgn, real *est, - integer *kase); -extern int slacpy_(char *uplo, integer *m, integer *n, real *a, integer *lda, - real *b, integer *ldb, ftnlen uplo_len); -extern int sladiv_(real *a, real *b, real *c__, real *d__, real *p, real *q); -extern int slae2_(real *a, real *b, real *c__, real *rt1, real *rt2); -extern int slaebz_(integer *ijob, integer *nitmax, integer *n, integer *mmax, - integer *minp, integer *nbmin, real *abstol, real *reltol, - real *pivmin, real *d__, real *e, real *e2, integer *nval, - real *ab, real *c__, integer *mout, integer *nab, real *work, - integer *iwork, integer *info); -extern int slaed0_(integer *icompq, integer *qsiz, integer *n, real *d__, - real *e, real *q, integer *ldq, real *qstore, integer *ldqs, - real *work, integer *iwork, integer *info); -extern int slaed1_(integer *n, real *d__, real *q, integer *ldq, integer *indxq, - real *rho, integer *cutpnt, real *work, integer *iwork, - integer *info); -extern int slaed2_(integer *k, integer *n, integer *n1, real *d__, real *q, - integer *ldq, integer *indxq, real *rho, real *z__, - real *dlamda, real *w, real *q2, integer *indx, - integer *indxc, integer *indxp, integer *coltyp, - integer *info); -extern int slaed3_(integer *k, integer *n, integer *n1, real *d__, real *q, - integer *ldq, real *rho, real *dlamda, real *q2, - integer *indx, integer *ctot, real *w, real *s, - integer *info); -extern int slaed4_(integer *n, integer *i__, real *d__, real *z__, real *delta, - real *rho, real *dlam, integer *info); -extern int slaed5_(integer *i__, real *d__, real *z__, real *delta, real *rho, - real *dlam); -extern int slaed6_(integer *kniter, logical *orgati, real *rho, real *d__, - real *z__, real *finit, real *tau, integer *info); -extern int slaed7_(integer *icompq, integer *n, integer *qsiz, integer *tlvls, - integer *curlvl, integer *curpbm, real *d__, real *q, - integer *ldq, integer *indxq, real *rho, integer *cutpnt, - real *qstore, integer *qptr, integer *prmptr, integer *perm, - integer *givptr, integer *givcol, real *givnum, real *work, - integer *iwork, integer *info); -extern int slaed8_(integer *icompq, integer *k, integer *n, integer *qsiz, - real *d__, real *q, integer *ldq, integer *indxq, real *rho, - integer *cutpnt, real *z__, real *dlamda, real *q2, - integer *ldq2, real *w, integer *perm, integer *givptr, - integer *givcol, real *givnum, integer *indxp, integer *indx, - integer *info); -extern int slaed9_(integer *k, integer *kstart, integer *kstop, integer *n, - real *d__, real *q, integer *ldq, real *rho, real *dlamda, - real *w, real *s, integer *lds, integer *info); -extern int slaeda_(integer *n, integer *tlvls, integer *curlvl, integer *curpbm, - integer *prmptr, integer *perm, integer *givptr, - integer *givcol, real *givnum, real *q, integer *qptr, - real *z__, real *ztemp, integer *info); -extern int slaein_(logical *rightv, logical *noinit, integer *n, real *h__, - integer *ldh, real *wr, real *wi, real *vr, real *vi, - real *b, integer *ldb, real *work, real *eps3, real *smlnum, - real *bignum, integer *info); -extern int slaev2_(real *a, real *b, real *c__, real *rt1, real *rt2, real *cs1, - real *sn1); -extern int slaexc_(logical *wantq, integer *n, real *t, integer *ldt, real *q, - integer *ldq, integer *j1, integer *n1, integer *n2, - real *work, integer *info); -extern int slag2_(real *a, integer *lda, real *b, integer *ldb, real *safmin, - real *scale1, real *scale2, real *wr1, real *wr2, real *wi); -extern int slags2_(logical *upper, real *a1, real *a2, real *a3, real *b1, - real *b2, real *b3, real *csu, real *snu, real *csv, - real *snv, real *csq, real *snq); -extern int slagtf_(integer *n, real *a, real *lambda, real *b, real *c__, - real *tol, real *d__, integer *in, integer *info); -extern int slagtm_(char *trans, integer *n, integer *nrhs, real *alpha, - real *dl, real *d__, real *du, real *x, integer *ldx, - real *beta, real *b, integer *ldb, ftnlen trans_len); -extern int slagts_(integer *job, integer *n, real *a, real *b, real *c__, - real *d__, integer *in, real *y, real *tol, integer *info); -extern int slagv2_(real *a, integer *lda, real *b, integer *ldb, real *alphar, - real *alphai, real *beta, real *csl, real *snl, real *csr, - real *snr); -extern int slahqr_(logical *wantt, logical *wantz, integer *n, integer *ilo, - integer *ihi, real *h__, integer *ldh, real *wr, real *wi, - integer *iloz, integer *ihiz, real *z__, integer *ldz, - integer *info); -extern int slahrd_(integer *n, integer *k, integer *nb, real *a, integer *lda, - real *tau, real *t, integer *ldt, real *y, integer *ldy); -extern int slaic1_(integer *job, integer *j, real *x, real *sest, real *w, - real *gamma, real *sestpr, real *s, real *c__); -extern int slaln2_(logical *ltrans, integer *na, integer *nw, real *smin, - real *ca, real *a, integer *lda, real *d1, real *d2, real *b, - integer *ldb, real *wr, real *wi, real *x, integer *ldx, - real *scale, real *xnorm, integer *info); -extern int slals0_(integer *icompq, integer *nl, integer *nr, integer *sqre, - integer *nrhs, real *b, integer *ldb, real *bx, - integer *ldbx, integer *perm, integer *givptr, - integer *givcol, integer *ldgcol, real *givnum, - integer *ldgnum, real *poles, real *difl, real *difr, - real *z__, integer *k, real *c__, real *s, real *work, - integer *info); -extern int slalsa_(integer *icompq, integer *smlsiz, integer *n, integer *nrhs, - real *b, integer *ldb, real *bx, integer *ldbx, real *u, - integer *ldu, real *vt, integer *k, real *difl, real *difr, - real *z__, real *poles, integer *givptr, integer *givcol, - integer *ldgcol, integer *perm, real *givnum, real *c__, - real *s, real *work, integer *iwork, integer *info); -extern int slalsd_(char *uplo, integer *smlsiz, integer *n, integer *nrhs, - real *d__, real *e, real *b, integer *ldb, real *rcond, - integer *rank, real *work, integer *iwork, integer *info, - ftnlen uplo_len); -extern E_f slamch_(char *cmach, ftnlen cmach_len); -extern int slamc1_(integer *beta, integer *t, logical *rnd, logical *ieee1); -extern int slamc2_(integer *beta, integer *t, logical *rnd, real *eps, - integer *emin, real *rmin, integer *emax, real *rmax); -extern E_f slamc3_(real *a, real *b); -extern int slamc4_(integer *emin, real *start, integer *base); -extern int slamc5_(integer *beta, integer *p, integer *emin, logical *ieee, - integer *emax, real *rmax); -extern int slamrg_(integer *n1, integer *n2, real *a, integer *strd1, - integer *strd2, integer *index); -extern E_f slangb_(char *norm, integer *n, integer *kl, integer *ku, real *ab, - integer *ldab, real *work, ftnlen norm_len); -extern E_f slange_(char *norm, integer *m, integer *n, real *a, integer *lda, - real *work, ftnlen norm_len); -extern E_f slangt_(char *norm, integer *n, real *dl, real *d__, real *du, - ftnlen norm_len); -extern E_f slanhs_(char *norm, integer *n, real *a, integer *lda, real *work, - ftnlen norm_len); -extern E_f slansb_(char *norm, char *uplo, integer *n, integer *k, real *ab, - integer *ldab, real *work, ftnlen norm_len, ftnlen uplo_len); -extern E_f slansp_(char *norm, char *uplo, integer *n, real *ap, real *work, - ftnlen norm_len, ftnlen uplo_len); -extern E_f slanst_(char *norm, integer *n, real *d__, real *e, ftnlen norm_len); -extern E_f slansy_(char *norm, char *uplo, integer *n, real *a, integer *lda, - real *work, ftnlen norm_len, ftnlen uplo_len); -extern E_f slantb_(char *norm, char *uplo, char *diag, integer *n, integer *k, - real *ab, integer *ldab, real *work, ftnlen norm_len, - ftnlen uplo_len, ftnlen diag_len); -extern E_f slantp_(char *norm, char *uplo, char *diag, integer *n, real *ap, - real *work, ftnlen norm_len, ftnlen uplo_len, - ftnlen diag_len); -extern E_f slantr_(char *norm, char *uplo, char *diag, integer *m, integer *n, - real *a, integer *lda, real *work, ftnlen norm_len, - ftnlen uplo_len, ftnlen diag_len); -extern int slanv2_(real *a, real *b, real *c__, real *d__, real *rt1r, - real *rt1i, real *rt2r, real *rt2i, real *cs, real *sn); -extern int slapll_(integer *n, real *x, integer *incx, real *y, integer *incy, - real *ssmin); -extern int slapmt_(logical *forwrd, integer *m, integer *n, real *x, - integer *ldx, integer *k); -extern E_f slapy2_(real *x, real *y); -extern E_f slapy3_(real *x, real *y, real *z__); -extern int slaqgb_(integer *m, integer *n, integer *kl, integer *ku, real *ab, - integer *ldab, real *r__, real *c__, real *rowcnd, - real *colcnd, real *amax, char *equed, ftnlen equed_len); -extern int slaqge_(integer *m, integer *n, real *a, integer *lda, real *r__, - real *c__, real *rowcnd, real *colcnd, real *amax, - char *equed, ftnlen equed_len); -extern int slaqp2_(integer *m, integer *n, integer *offset, real *a, - integer *lda, integer *jpvt, real *tau, real *vn1, real *vn2, - real *work); -extern int slaqps_(integer *m, integer *n, integer *offset, integer *nb, - integer *kb, real *a, integer *lda, integer *jpvt, real *tau, - real *vn1, real *vn2, real *auxv, real *f, integer *ldf); -extern int slaqsb_(char *uplo, integer *n, integer *kd, real *ab, integer *ldab, - real *s, real *scond, real *amax, char *equed, - ftnlen uplo_len, ftnlen equed_len); -extern int slaqsp_(char *uplo, integer *n, real *ap, real *s, real *scond, - real *amax, char *equed, ftnlen uplo_len, ftnlen equed_len); -extern int slaqsy_(char *uplo, integer *n, real *a, integer *lda, real *s, - real *scond, real *amax, char *equed, ftnlen uplo_len, - ftnlen equed_len); -extern int slaqtr_(logical *ltran, logical *lreal, integer *n, real *t, - integer *ldt, real *b, real *w, real *scale, real *x, - real *work, integer *info); -extern int slar1v_(integer *n, integer *b1, integer *bn, real *sigma, real *d__, - real *l, real *ld, real *lld, real *gersch, real *z__, - real *ztz, real *mingma, integer *r__, integer *isuppz, - real *work); -extern int slar2v_(integer *n, real *x, real *y, real *z__, integer *incx, - real *c__, real *s, integer *incc); -extern int slarf_(char *side, integer *m, integer *n, real *v, integer *incv, - real *tau, real *c__, integer *ldc, real *work, - ftnlen side_len); -extern int slarfb_(char *side, char *trans, char *direct, char *storev, - integer *m, integer *n, integer *k, real *v, integer *ldv, - real *t, integer *ldt, real *c__, integer *ldc, real *work, - integer *ldwork, ftnlen side_len, ftnlen trans_len, - ftnlen direct_len, ftnlen storev_len); -extern int slarfg_(integer *n, real *alpha, real *x, integer *incx, real *tau); -extern int slarft_(char *direct, char *storev, integer *n, integer *k, real *v, - integer *ldv, real *tau, real *t, integer *ldt, - ftnlen direct_len, ftnlen storev_len); -extern int slarfx_(char *side, integer *m, integer *n, real *v, real *tau, - real *c__, integer *ldc, real *work, ftnlen side_len); -extern int slargv_(integer *n, real *x, integer *incx, real *y, integer *incy, - real *c__, integer *incc); -extern int slarnv_(integer *idist, integer *iseed, integer *n, real *x); -extern int slarrb_(integer *n, real *d__, real *l, real *ld, real *lld, - integer *ifirst, integer *ilast, real *sigma, real *reltol, - real *w, real *wgap, real *werr, real *work, integer *iwork, - integer *info); -extern int slarre_(integer *n, real *d__, real *e, real *tol, integer *nsplit, - integer *isplit, integer *m, real *w, real *woff, - real *gersch, real *work, integer *info); -extern int slarrf_(integer *n, real *d__, real *l, real *ld, real *lld, - integer *ifirst, integer *ilast, real *w, real *dplus, - real *lplus, real *work, integer *iwork, integer *info); -extern int slarrv_(integer *n, real *d__, real *l, integer *isplit, integer *m, - real *w, integer *iblock, real *gersch, real *tol, real *z__, - integer *ldz, integer *isuppz, real *work, integer *iwork, - integer *info); -extern int slartg_(real *f, real *g, real *cs, real *sn, real *r__); -extern int slartv_(integer *n, real *x, integer *incx, real *y, integer *incy, - real *c__, real *s, integer *incc); -extern int slaruv_(integer *iseed, integer *n, real *x); -extern int slarz_(char *side, integer *m, integer *n, integer *l, real *v, - integer *incv, real *tau, real *c__, integer *ldc, real *work, - ftnlen side_len); -extern int slarzb_(char *side, char *trans, char *direct, char *storev, - integer *m, integer *n, integer *k, integer *l, real *v, - integer *ldv, real *t, integer *ldt, real *c__, integer *ldc, - real *work, integer *ldwork, ftnlen side_len, - ftnlen trans_len, ftnlen direct_len, ftnlen storev_len); -extern int slarzt_(char *direct, char *storev, integer *n, integer *k, real *v, - integer *ldv, real *tau, real *t, integer *ldt, - ftnlen direct_len, ftnlen storev_len); -extern int slas2_(real *f, real *g, real *h__, real *ssmin, real *ssmax); -extern int slascl_(char *type__, integer *kl, integer *ku, real *cfrom, - real *cto, integer *m, integer *n, real *a, integer *lda, - integer *info, ftnlen type_len); -extern int slasd0_(integer *n, integer *sqre, real *d__, real *e, real *u, - integer *ldu, real *vt, integer *ldvt, integer *smlsiz, - integer *iwork, real *work, integer *info); -extern int slasd1_(integer *nl, integer *nr, integer *sqre, real *d__, - real *alpha, real *beta, real *u, integer *ldu, real *vt, - integer *ldvt, integer *idxq, integer *iwork, real *work, - integer *info); -extern int slasd2_(integer *nl, integer *nr, integer *sqre, integer *k, - real *d__, real *z__, real *alpha, real *beta, real *u, - integer *ldu, real *vt, integer *ldvt, real *dsigma, - real *u2, integer *ldu2, real *vt2, integer *ldvt2, - integer *idxp, integer *idx, integer *idxc, integer *idxq, - integer *coltyp, integer *info); -extern int slasd3_(integer *nl, integer *nr, integer *sqre, integer *k, - real *d__, real *q, integer *ldq, real *dsigma, real *u, - integer *ldu, real *u2, integer *ldu2, real *vt, - integer *ldvt, real *vt2, integer *ldvt2, integer *idxc, - integer *ctot, real *z__, integer *info); -extern int slasd4_(integer *n, integer *i__, real *d__, real *z__, real *delta, - real *rho, real *sigma, real *work, integer *info); -extern int slasd5_(integer *i__, real *d__, real *z__, real *delta, real *rho, - real *dsigma, real *work); -extern int slasd6_(integer *icompq, integer *nl, integer *nr, integer *sqre, - real *d__, real *vf, real *vl, real *alpha, real *beta, - integer *idxq, integer *perm, integer *givptr, - integer *givcol, integer *ldgcol, real *givnum, - integer *ldgnum, real *poles, real *difl, real *difr, - real *z__, integer *k, real *c__, real *s, real *work, - integer *iwork, integer *info); -extern int slasd7_(integer *icompq, integer *nl, integer *nr, integer *sqre, - integer *k, real *d__, real *z__, real *zw, real *vf, - real *vfw, real *vl, real *vlw, real *alpha, real *beta, - real *dsigma, integer *idx, integer *idxp, integer *idxq, - integer *perm, integer *givptr, integer *givcol, - integer *ldgcol, real *givnum, integer *ldgnum, real *c__, - real *s, integer *info); -extern int slasd8_(integer *icompq, integer *k, real *d__, real *z__, real *vf, - real *vl, real *difl, real *difr, integer *lddifr, - real *dsigma, real *work, integer *info); -extern int slasd9_(integer *icompq, integer *ldu, integer *k, real *d__, - real *z__, real *vf, real *vl, real *difl, real *difr, - real *dsigma, real *work, integer *info); -extern int slasda_(integer *icompq, integer *smlsiz, integer *n, integer *sqre, - real *d__, real *e, real *u, integer *ldu, real *vt, - integer *k, real *difl, real *difr, real *z__, real *poles, - integer *givptr, integer *givcol, integer *ldgcol, - integer *perm, real *givnum, real *c__, real *s, real *work, - integer *iwork, integer *info); -extern int slasdq_(char *uplo, integer *sqre, integer *n, integer *ncvt, - integer *nru, integer *ncc, real *d__, real *e, real *vt, - integer *ldvt, real *u, integer *ldu, real *c__, - integer *ldc, real *work, integer *info, ftnlen uplo_len); -extern int slasdt_(integer *n, integer *lvl, integer *nd, integer *inode, - integer *ndiml, integer *ndimr, integer *msub); -extern int slaset_(char *uplo, integer *m, integer *n, real *alpha, real *beta, - real *a, integer *lda, ftnlen uplo_len); -extern int slasq1_(integer *n, real *d__, real *e, real *work, integer *info); -extern int slasq2_(integer *n, real *z__, integer *info); -extern int slasq3_(integer *i0, integer *n0, real *z__, integer *pp, - real *dmin__, real *sigma, real *desig, real *qmax, - integer *nfail, integer *iter, integer *ndiv); -extern int slasq4_(integer *i0, integer *n0, real *z__, integer *pp, - integer *n0in, real *dmin__, real *dmin1, real *dmin2, - real *dn, real *dn1, real *dn2, real *tau, integer *ttype); -extern int slasq5_(integer *i0, integer *n0, real *z__, integer *pp, real *tau, - real *dmin__, real *dmin1, real *dmin2, real *dn, real *dnm1, - real *dnm2); -extern int slasq6_(integer *i0, integer *n0, real *z__, integer *pp, - real *dmin__, real *dmin1, real *dmin2, real *dn, real *dnm1, - real *dnm2); -extern int slasr_(char *side, char *pivot, char *direct, integer *m, integer *n, - real *c__, real *s, real *a, integer *lda, ftnlen side_len, - ftnlen pivot_len, ftnlen direct_len); -extern int slasrt_(char *id, integer *n, real *d__, integer *info, - ftnlen id_len); -extern int slassq_(integer *n, real *x, integer *incx, real *scale, - real *sumsq); -extern int slasv2_(real *f, real *g, real *h__, real *ssmin, real *ssmax, - real *snr, real *csr, real *snl, real *csl); -extern int slaswp_(integer *n, real *a, integer *lda, integer *k1, integer *k2, - integer *ipiv, integer *incx); -extern int slasy2_(logical *ltranl, logical *ltranr, integer *isgn, integer *n1, - integer *n2, real *tl, integer *ldtl, real *tr, - integer *ldtr, real *b, integer *ldb, real *scale, real *x, - integer *ldx, real *xnorm, integer *info); -extern int slasyf_(char *uplo, integer *n, integer *nb, integer *kb, real *a, - integer *lda, integer *ipiv, real *w, integer *ldw, - integer *info, ftnlen uplo_len); -extern int slatbs_(char *uplo, char *trans, char *diag, char *normin, - integer *n, integer *kd, real *ab, integer *ldab, real *x, - real *scale, real *cnorm, integer *info, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len, ftnlen normin_len); -extern int slatdf_(integer *ijob, integer *n, real *z__, integer *ldz, - real *rhs, real *rdsum, real *rdscal, integer *ipiv, - integer *jpiv); -extern int slatps_(char *uplo, char *trans, char *diag, char *normin, - integer *n, real *ap, real *x, real *scale, real *cnorm, - integer *info, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len, ftnlen normin_len); -extern int slatrd_(char *uplo, integer *n, integer *nb, real *a, integer *lda, - real *e, real *tau, real *w, integer *ldw, ftnlen uplo_len); -extern int slatrs_(char *uplo, char *trans, char *diag, char *normin, - integer *n, real *a, integer *lda, real *x, real *scale, - real *cnorm, integer *info, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len, ftnlen normin_len); -extern int slatrz_(integer *m, integer *n, integer *l, real *a, integer *lda, - real *tau, real *work); -extern int slatzm_(char *side, integer *m, integer *n, real *v, integer *incv, - real *tau, real *c1, real *c2, integer *ldc, real *work, - ftnlen side_len); -extern int slauu2_(char *uplo, integer *n, real *a, integer *lda, integer *info, - ftnlen uplo_len); -extern int slauum_(char *uplo, integer *n, real *a, integer *lda, integer *info, - ftnlen uplo_len); -extern int sopgtr_(char *uplo, integer *n, real *ap, real *tau, real *q, - integer *ldq, real *work, integer *info, ftnlen uplo_len); -extern int sopmtr_(char *side, char *uplo, char *trans, integer *m, integer *n, - real *ap, real *tau, real *c__, integer *ldc, real *work, - integer *info, ftnlen side_len, ftnlen uplo_len, - ftnlen trans_len); -extern int sorg2l_(integer *m, integer *n, integer *k, real *a, integer *lda, - real *tau, real *work, integer *info); -extern int sorg2r_(integer *m, integer *n, integer *k, real *a, integer *lda, - real *tau, real *work, integer *info); -extern int sorgbr_(char *vect, integer *m, integer *n, integer *k, real *a, - integer *lda, real *tau, real *work, integer *lwork, - integer *info, ftnlen vect_len); -extern int sorghr_(integer *n, integer *ilo, integer *ihi, real *a, - integer *lda, real *tau, real *work, integer *lwork, - integer *info); -extern int sorgl2_(integer *m, integer *n, integer *k, real *a, integer *lda, - real *tau, real *work, integer *info); -extern int sorglq_(integer *m, integer *n, integer *k, real *a, integer *lda, - real *tau, real *work, integer *lwork, integer *info); -extern int sorgql_(integer *m, integer *n, integer *k, real *a, integer *lda, - real *tau, real *work, integer *lwork, integer *info); -extern int sorgqr_(integer *m, integer *n, integer *k, real *a, integer *lda, - real *tau, real *work, integer *lwork, integer *info); -extern int sorgr2_(integer *m, integer *n, integer *k, real *a, integer *lda, - real *tau, real *work, integer *info); -extern int sorgrq_(integer *m, integer *n, integer *k, real *a, integer *lda, - real *tau, real *work, integer *lwork, integer *info); -extern int sorgtr_(char *uplo, integer *n, real *a, integer *lda, real *tau, - real *work, integer *lwork, integer *info, ftnlen uplo_len); -extern int sorm2l_(char *side, char *trans, integer *m, integer *n, integer *k, - real *a, integer *lda, real *tau, real *c__, integer *ldc, - real *work, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int sorm2r_(char *side, char *trans, integer *m, integer *n, integer *k, - real *a, integer *lda, real *tau, real *c__, integer *ldc, - real *work, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int sormbr_(char *vect, char *side, char *trans, integer *m, integer *n, - integer *k, real *a, integer *lda, real *tau, real *c__, - integer *ldc, real *work, integer *lwork, integer *info, - ftnlen vect_len, ftnlen side_len, ftnlen trans_len); -extern int sormhr_(char *side, char *trans, integer *m, integer *n, - integer *ilo, integer *ihi, real *a, integer *lda, real *tau, - real *c__, integer *ldc, real *work, integer *lwork, - integer *info, ftnlen side_len, ftnlen trans_len); -extern int sorml2_(char *side, char *trans, integer *m, integer *n, integer *k, - real *a, integer *lda, real *tau, real *c__, integer *ldc, - real *work, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int sormlq_(char *side, char *trans, integer *m, integer *n, integer *k, - real *a, integer *lda, real *tau, real *c__, integer *ldc, - real *work, integer *lwork, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int sormql_(char *side, char *trans, integer *m, integer *n, integer *k, - real *a, integer *lda, real *tau, real *c__, integer *ldc, - real *work, integer *lwork, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int sormqr_(char *side, char *trans, integer *m, integer *n, integer *k, - real *a, integer *lda, real *tau, real *c__, integer *ldc, - real *work, integer *lwork, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int sormr2_(char *side, char *trans, integer *m, integer *n, integer *k, - real *a, integer *lda, real *tau, real *c__, integer *ldc, - real *work, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int sormr3_(char *side, char *trans, integer *m, integer *n, integer *k, - integer *l, real *a, integer *lda, real *tau, real *c__, - integer *ldc, real *work, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int sormrq_(char *side, char *trans, integer *m, integer *n, integer *k, - real *a, integer *lda, real *tau, real *c__, integer *ldc, - real *work, integer *lwork, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int sormrz_(char *side, char *trans, integer *m, integer *n, integer *k, - integer *l, real *a, integer *lda, real *tau, real *c__, - integer *ldc, real *work, integer *lwork, integer *info, - ftnlen side_len, ftnlen trans_len); -extern int sormtr_(char *side, char *uplo, char *trans, integer *m, integer *n, - real *a, integer *lda, real *tau, real *c__, integer *ldc, - real *work, integer *lwork, integer *info, ftnlen side_len, - ftnlen uplo_len, ftnlen trans_len); -extern int spbcon_(char *uplo, integer *n, integer *kd, real *ab, integer *ldab, - real *anorm, real *rcond, real *work, integer *iwork, - integer *info, ftnlen uplo_len); -extern int spbequ_(char *uplo, integer *n, integer *kd, real *ab, integer *ldab, - real *s, real *scond, real *amax, integer *info, - ftnlen uplo_len); -extern int spbrfs_(char *uplo, integer *n, integer *kd, integer *nrhs, real *ab, - integer *ldab, real *afb, integer *ldafb, real *b, - integer *ldb, real *x, integer *ldx, real *ferr, real *berr, - real *work, integer *iwork, integer *info, ftnlen uplo_len); -extern int spbstf_(char *uplo, integer *n, integer *kd, real *ab, integer *ldab, - integer *info, ftnlen uplo_len); -extern int spbsv_(char *uplo, integer *n, integer *kd, integer *nrhs, real *ab, - integer *ldab, real *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int spbsvx_(char *fact, char *uplo, integer *n, integer *kd, - integer *nrhs, real *ab, integer *ldab, real *afb, - integer *ldafb, char *equed, real *s, real *b, integer *ldb, - real *x, integer *ldx, real *rcond, real *ferr, real *berr, - real *work, integer *iwork, integer *info, ftnlen fact_len, - ftnlen uplo_len, ftnlen equed_len); -extern int spbtf2_(char *uplo, integer *n, integer *kd, real *ab, integer *ldab, - integer *info, ftnlen uplo_len); -extern int spbtrf_(char *uplo, integer *n, integer *kd, real *ab, integer *ldab, - integer *info, ftnlen uplo_len); -extern int spbtrs_(char *uplo, integer *n, integer *kd, integer *nrhs, real *ab, - integer *ldab, real *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int spocon_(char *uplo, integer *n, real *a, integer *lda, real *anorm, - real *rcond, real *work, integer *iwork, integer *info, - ftnlen uplo_len); -extern int spoequ_(integer *n, real *a, integer *lda, real *s, real *scond, - real *amax, integer *info); -extern int sporfs_(char *uplo, integer *n, integer *nrhs, real *a, integer *lda, - real *af, integer *ldaf, real *b, integer *ldb, real *x, - integer *ldx, real *ferr, real *berr, real *work, - integer *iwork, integer *info, ftnlen uplo_len); -extern int sposv_(char *uplo, integer *n, integer *nrhs, real *a, integer *lda, - real *b, integer *ldb, integer *info, ftnlen uplo_len); -extern int sposvx_(char *fact, char *uplo, integer *n, integer *nrhs, real *a, - integer *lda, real *af, integer *ldaf, char *equed, real *s, - real *b, integer *ldb, real *x, integer *ldx, real *rcond, - real *ferr, real *berr, real *work, integer *iwork, - integer *info, ftnlen fact_len, ftnlen uplo_len, - ftnlen equed_len); -extern int spotf2_(char *uplo, integer *n, real *a, integer *lda, integer *info, - ftnlen uplo_len); -extern int spotrf_(char *uplo, integer *n, real *a, integer *lda, integer *info, - ftnlen uplo_len); -extern int spotri_(char *uplo, integer *n, real *a, integer *lda, integer *info, - ftnlen uplo_len); -extern int spotrs_(char *uplo, integer *n, integer *nrhs, real *a, integer *lda, - real *b, integer *ldb, integer *info, ftnlen uplo_len); -extern int sppcon_(char *uplo, integer *n, real *ap, real *anorm, real *rcond, - real *work, integer *iwork, integer *info, ftnlen uplo_len); -extern int sppequ_(char *uplo, integer *n, real *ap, real *s, real *scond, - real *amax, integer *info, ftnlen uplo_len); -extern int spprfs_(char *uplo, integer *n, integer *nrhs, real *ap, real *afp, - real *b, integer *ldb, real *x, integer *ldx, real *ferr, - real *berr, real *work, integer *iwork, integer *info, - ftnlen uplo_len); -extern int sppsv_(char *uplo, integer *n, integer *nrhs, real *ap, real *b, - integer *ldb, integer *info, ftnlen uplo_len); -extern int sppsvx_(char *fact, char *uplo, integer *n, integer *nrhs, real *ap, - real *afp, char *equed, real *s, real *b, integer *ldb, - real *x, integer *ldx, real *rcond, real *ferr, real *berr, - real *work, integer *iwork, integer *info, ftnlen fact_len, - ftnlen uplo_len, ftnlen equed_len); -extern int spptrf_(char *uplo, integer *n, real *ap, integer *info, - ftnlen uplo_len); -extern int spptri_(char *uplo, integer *n, real *ap, integer *info, - ftnlen uplo_len); -extern int spptrs_(char *uplo, integer *n, integer *nrhs, real *ap, real *b, - integer *ldb, integer *info, ftnlen uplo_len); -extern int sptcon_(integer *n, real *d__, real *e, real *anorm, real *rcond, - real *work, integer *info); -extern int spteqr_(char *compz, integer *n, real *d__, real *e, real *z__, - integer *ldz, real *work, integer *info, ftnlen compz_len); -extern int sptrfs_(integer *n, integer *nrhs, real *d__, real *e, real *df, - real *ef, real *b, integer *ldb, real *x, integer *ldx, - real *ferr, real *berr, real *work, integer *info); -extern int sptsv_(integer *n, integer *nrhs, real *d__, real *e, real *b, - integer *ldb, integer *info); -extern int sptsvx_(char *fact, integer *n, integer *nrhs, real *d__, real *e, - real *df, real *ef, real *b, integer *ldb, real *x, - integer *ldx, real *rcond, real *ferr, real *berr, - real *work, integer *info, ftnlen fact_len); -extern int spttrf_(integer *n, real *d__, real *e, integer *info); -extern int spttrs_(integer *n, integer *nrhs, real *d__, real *e, real *b, - integer *ldb, integer *info); -extern int sptts2_(integer *n, integer *nrhs, real *d__, real *e, real *b, - integer *ldb); -extern int srscl_(integer *n, real *sa, real *sx, integer *incx); -extern int ssbev_(char *jobz, char *uplo, integer *n, integer *kd, real *ab, - integer *ldab, real *w, real *z__, integer *ldz, real *work, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int ssbevd_(char *jobz, char *uplo, integer *n, integer *kd, real *ab, - integer *ldab, real *w, real *z__, integer *ldz, real *work, - integer *lwork, integer *iwork, integer *liwork, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int ssbevx_(char *jobz, char *range, char *uplo, integer *n, integer *kd, - real *ab, integer *ldab, real *q, integer *ldq, real *vl, - real *vu, integer *il, integer *iu, real *abstol, integer *m, - real *w, real *z__, integer *ldz, real *work, integer *iwork, - integer *ifail, integer *info, ftnlen jobz_len, - ftnlen range_len, ftnlen uplo_len); -extern int ssbgst_(char *vect, char *uplo, integer *n, integer *ka, integer *kb, - real *ab, integer *ldab, real *bb, integer *ldbb, real *x, - integer *ldx, real *work, integer *info, ftnlen vect_len, - ftnlen uplo_len); -extern int ssbgv_(char *jobz, char *uplo, integer *n, integer *ka, integer *kb, - real *ab, integer *ldab, real *bb, integer *ldbb, real *w, - real *z__, integer *ldz, real *work, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int ssbgvd_(char *jobz, char *uplo, integer *n, integer *ka, integer *kb, - real *ab, integer *ldab, real *bb, integer *ldbb, real *w, - real *z__, integer *ldz, real *work, integer *lwork, - integer *iwork, integer *liwork, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int ssbgvx_(char *jobz, char *range, char *uplo, integer *n, integer *ka, - integer *kb, real *ab, integer *ldab, real *bb, - integer *ldbb, real *q, integer *ldq, real *vl, real *vu, - integer *il, integer *iu, real *abstol, integer *m, real *w, - real *z__, integer *ldz, real *work, integer *iwork, - integer *ifail, integer *info, ftnlen jobz_len, - ftnlen range_len, ftnlen uplo_len); -extern int ssbtrd_(char *vect, char *uplo, integer *n, integer *kd, real *ab, - integer *ldab, real *d__, real *e, real *q, integer *ldq, - real *work, integer *info, ftnlen vect_len, ftnlen uplo_len); -extern int sspcon_(char *uplo, integer *n, real *ap, integer *ipiv, real *anorm, - real *rcond, real *work, integer *iwork, integer *info, - ftnlen uplo_len); -extern int sspev_(char *jobz, char *uplo, integer *n, real *ap, real *w, - real *z__, integer *ldz, real *work, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int sspevd_(char *jobz, char *uplo, integer *n, real *ap, real *w, - real *z__, integer *ldz, real *work, integer *lwork, - integer *iwork, integer *liwork, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int sspevx_(char *jobz, char *range, char *uplo, integer *n, real *ap, - real *vl, real *vu, integer *il, integer *iu, real *abstol, - integer *m, real *w, real *z__, integer *ldz, real *work, - integer *iwork, integer *ifail, integer *info, - ftnlen jobz_len, ftnlen range_len, ftnlen uplo_len); -extern int sspgst_(integer *itype, char *uplo, integer *n, real *ap, real *bp, - integer *info, ftnlen uplo_len); -extern int sspgv_(integer *itype, char *jobz, char *uplo, integer *n, real *ap, - real *bp, real *w, real *z__, integer *ldz, real *work, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int sspgvd_(integer *itype, char *jobz, char *uplo, integer *n, real *ap, - real *bp, real *w, real *z__, integer *ldz, real *work, - integer *lwork, integer *iwork, integer *liwork, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int sspgvx_(integer *itype, char *jobz, char *range, char *uplo, - integer *n, real *ap, real *bp, real *vl, real *vu, - integer *il, integer *iu, real *abstol, integer *m, real *w, - real *z__, integer *ldz, real *work, integer *iwork, - integer *ifail, integer *info, ftnlen jobz_len, - ftnlen range_len, ftnlen uplo_len); -extern int ssprfs_(char *uplo, integer *n, integer *nrhs, real *ap, real *afp, - integer *ipiv, real *b, integer *ldb, real *x, integer *ldx, - real *ferr, real *berr, real *work, integer *iwork, - integer *info, ftnlen uplo_len); -extern int sspsv_(char *uplo, integer *n, integer *nrhs, real *ap, - integer *ipiv, real *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int sspsvx_(char *fact, char *uplo, integer *n, integer *nrhs, real *ap, - real *afp, integer *ipiv, real *b, integer *ldb, real *x, - integer *ldx, real *rcond, real *ferr, real *berr, - real *work, integer *iwork, integer *info, ftnlen fact_len, - ftnlen uplo_len); -extern int ssptrd_(char *uplo, integer *n, real *ap, real *d__, real *e, - real *tau, integer *info, ftnlen uplo_len); -extern int ssptrf_(char *uplo, integer *n, real *ap, integer *ipiv, - integer *info, ftnlen uplo_len); -extern int ssptri_(char *uplo, integer *n, real *ap, integer *ipiv, real *work, - integer *info, ftnlen uplo_len); -extern int ssptrs_(char *uplo, integer *n, integer *nrhs, real *ap, - integer *ipiv, real *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int sstebz_(char *range, char *order, integer *n, real *vl, real *vu, - integer *il, integer *iu, real *abstol, real *d__, real *e, - integer *m, integer *nsplit, real *w, integer *iblock, - integer *isplit, real *work, integer *iwork, integer *info, - ftnlen range_len, ftnlen order_len); -extern int sstedc_(char *compz, integer *n, real *d__, real *e, real *z__, - integer *ldz, real *work, integer *lwork, integer *iwork, - integer *liwork, integer *info, ftnlen compz_len); -extern int sstegr_(char *jobz, char *range, integer *n, real *d__, real *e, - real *vl, real *vu, integer *il, integer *iu, real *abstol, - integer *m, real *w, real *z__, integer *ldz, - integer *isuppz, real *work, integer *lwork, integer *iwork, - integer *liwork, integer *info, ftnlen jobz_len, - ftnlen range_len); -extern int sstein_(integer *n, real *d__, real *e, integer *m, real *w, - integer *iblock, integer *isplit, real *z__, integer *ldz, - real *work, integer *iwork, integer *ifail, integer *info); -extern int ssteqr_(char *compz, integer *n, real *d__, real *e, real *z__, - integer *ldz, real *work, integer *info, ftnlen compz_len); -extern int ssterf_(integer *n, real *d__, real *e, integer *info); -extern int sstev_(char *jobz, integer *n, real *d__, real *e, real *z__, - integer *ldz, real *work, integer *info, ftnlen jobz_len); -extern int sstevd_(char *jobz, integer *n, real *d__, real *e, real *z__, - integer *ldz, real *work, integer *lwork, integer *iwork, - integer *liwork, integer *info, ftnlen jobz_len); -extern int sstevr_(char *jobz, char *range, integer *n, real *d__, real *e, - real *vl, real *vu, integer *il, integer *iu, real *abstol, - integer *m, real *w, real *z__, integer *ldz, - integer *isuppz, real *work, integer *lwork, integer *iwork, - integer *liwork, integer *info, ftnlen jobz_len, - ftnlen range_len); -extern int sstevx_(char *jobz, char *range, integer *n, real *d__, real *e, - real *vl, real *vu, integer *il, integer *iu, real *abstol, - integer *m, real *w, real *z__, integer *ldz, real *work, - integer *iwork, integer *ifail, integer *info, - ftnlen jobz_len, ftnlen range_len); -extern int ssycon_(char *uplo, integer *n, real *a, integer *lda, integer *ipiv, - real *anorm, real *rcond, real *work, integer *iwork, - integer *info, ftnlen uplo_len); -extern int ssyev_(char *jobz, char *uplo, integer *n, real *a, integer *lda, - real *w, real *work, integer *lwork, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int ssyevd_(char *jobz, char *uplo, integer *n, real *a, integer *lda, - real *w, real *work, integer *lwork, integer *iwork, - integer *liwork, integer *info, ftnlen jobz_len, - ftnlen uplo_len); -extern int ssyevr_(char *jobz, char *range, char *uplo, integer *n, real *a, - integer *lda, real *vl, real *vu, integer *il, integer *iu, - real *abstol, integer *m, real *w, real *z__, integer *ldz, - integer *isuppz, real *work, integer *lwork, integer *iwork, - integer *liwork, integer *info, ftnlen jobz_len, - ftnlen range_len, ftnlen uplo_len); -extern int ssyevx_(char *jobz, char *range, char *uplo, integer *n, real *a, - integer *lda, real *vl, real *vu, integer *il, integer *iu, - real *abstol, integer *m, real *w, real *z__, integer *ldz, - real *work, integer *lwork, integer *iwork, integer *ifail, - integer *info, ftnlen jobz_len, ftnlen range_len, - ftnlen uplo_len); -extern int ssygs2_(integer *itype, char *uplo, integer *n, real *a, - integer *lda, real *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int ssygst_(integer *itype, char *uplo, integer *n, real *a, - integer *lda, real *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int ssygv_(integer *itype, char *jobz, char *uplo, integer *n, real *a, - integer *lda, real *b, integer *ldb, real *w, real *work, - integer *lwork, integer *info, ftnlen jobz_len, - ftnlen uplo_len); -extern int ssygvd_(integer *itype, char *jobz, char *uplo, integer *n, real *a, - integer *lda, real *b, integer *ldb, real *w, real *work, - integer *lwork, integer *iwork, integer *liwork, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int ssygvx_(integer *itype, char *jobz, char *range, char *uplo, - integer *n, real *a, integer *lda, real *b, integer *ldb, - real *vl, real *vu, integer *il, integer *iu, real *abstol, - integer *m, real *w, real *z__, integer *ldz, real *work, - integer *lwork, integer *iwork, integer *ifail, - integer *info, ftnlen jobz_len, ftnlen range_len, - ftnlen uplo_len); -extern int ssyrfs_(char *uplo, integer *n, integer *nrhs, real *a, integer *lda, - real *af, integer *ldaf, integer *ipiv, real *b, - integer *ldb, real *x, integer *ldx, real *ferr, real *berr, - real *work, integer *iwork, integer *info, ftnlen uplo_len); -extern int ssysv_(char *uplo, integer *n, integer *nrhs, real *a, integer *lda, - integer *ipiv, real *b, integer *ldb, real *work, - integer *lwork, integer *info, ftnlen uplo_len); -extern int ssysvx_(char *fact, char *uplo, integer *n, integer *nrhs, real *a, - integer *lda, real *af, integer *ldaf, integer *ipiv, - real *b, integer *ldb, real *x, integer *ldx, real *rcond, - real *ferr, real *berr, real *work, integer *lwork, - integer *iwork, integer *info, ftnlen fact_len, - ftnlen uplo_len); -extern int ssytd2_(char *uplo, integer *n, real *a, integer *lda, real *d__, - real *e, real *tau, integer *info, ftnlen uplo_len); -extern int ssytf2_(char *uplo, integer *n, real *a, integer *lda, integer *ipiv, - integer *info, ftnlen uplo_len); -extern int ssytrd_(char *uplo, integer *n, real *a, integer *lda, real *d__, - real *e, real *tau, real *work, integer *lwork, - integer *info, ftnlen uplo_len); -extern int ssytrf_(char *uplo, integer *n, real *a, integer *lda, integer *ipiv, - real *work, integer *lwork, integer *info, ftnlen uplo_len); -extern int ssytri_(char *uplo, integer *n, real *a, integer *lda, integer *ipiv, - real *work, integer *info, ftnlen uplo_len); -extern int ssytrs_(char *uplo, integer *n, integer *nrhs, real *a, integer *lda, - integer *ipiv, real *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int stbcon_(char *norm, char *uplo, char *diag, integer *n, integer *kd, - real *ab, integer *ldab, real *rcond, real *work, - integer *iwork, integer *info, ftnlen norm_len, - ftnlen uplo_len, ftnlen diag_len); -extern int stbrfs_(char *uplo, char *trans, char *diag, integer *n, integer *kd, - integer *nrhs, real *ab, integer *ldab, real *b, - integer *ldb, real *x, integer *ldx, real *ferr, real *berr, - real *work, integer *iwork, integer *info, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern int stbtrs_(char *uplo, char *trans, char *diag, integer *n, integer *kd, - integer *nrhs, real *ab, integer *ldab, real *b, - integer *ldb, integer *info, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern int stgevc_(char *side, char *howmny, logical *select, integer *n, - real *a, integer *lda, real *b, integer *ldb, real *vl, - integer *ldvl, real *vr, integer *ldvr, integer *mm, - integer *m, real *work, integer *info, ftnlen side_len, - ftnlen howmny_len); -extern int stgex2_(logical *wantq, logical *wantz, integer *n, real *a, - integer *lda, real *b, integer *ldb, real *q, integer *ldq, - real *z__, integer *ldz, integer *j1, integer *n1, - integer *n2, real *work, integer *lwork, integer *info); -extern int stgexc_(logical *wantq, logical *wantz, integer *n, real *a, - integer *lda, real *b, integer *ldb, real *q, integer *ldq, - real *z__, integer *ldz, integer *ifst, integer *ilst, - real *work, integer *lwork, integer *info); -extern int stgsen_(integer *ijob, logical *wantq, logical *wantz, - logical *select, integer *n, real *a, integer *lda, real *b, - integer *ldb, real *alphar, real *alphai, real *beta, - real *q, integer *ldq, real *z__, integer *ldz, integer *m, - real *pl, real *pr, real *dif, real *work, integer *lwork, - integer *iwork, integer *liwork, integer *info); -extern int stgsja_(char *jobu, char *jobv, char *jobq, integer *m, integer *p, - integer *n, integer *k, integer *l, real *a, integer *lda, - real *b, integer *ldb, real *tola, real *tolb, real *alpha, - real *beta, real *u, integer *ldu, real *v, integer *ldv, - real *q, integer *ldq, real *work, integer *ncycle, - integer *info, ftnlen jobu_len, ftnlen jobv_len, - ftnlen jobq_len); -extern int stgsna_(char *job, char *howmny, logical *select, integer *n, - real *a, integer *lda, real *b, integer *ldb, real *vl, - integer *ldvl, real *vr, integer *ldvr, real *s, real *dif, - integer *mm, integer *m, real *work, integer *lwork, - integer *iwork, integer *info, ftnlen job_len, - ftnlen howmny_len); -extern int stgsy2_(char *trans, integer *ijob, integer *m, integer *n, real *a, - integer *lda, real *b, integer *ldb, real *c__, integer *ldc, - real *d__, integer *ldd, real *e, integer *lde, real *f, - integer *ldf, real *scale, real *rdsum, real *rdscal, - integer *iwork, integer *pq, integer *info, - ftnlen trans_len); -extern int stgsyl_(char *trans, integer *ijob, integer *m, integer *n, real *a, - integer *lda, real *b, integer *ldb, real *c__, integer *ldc, - real *d__, integer *ldd, real *e, integer *lde, real *f, - integer *ldf, real *scale, real *dif, real *work, - integer *lwork, integer *iwork, integer *info, - ftnlen trans_len); -extern int stpcon_(char *norm, char *uplo, char *diag, integer *n, real *ap, - real *rcond, real *work, integer *iwork, integer *info, - ftnlen norm_len, ftnlen uplo_len, ftnlen diag_len); -extern int stprfs_(char *uplo, char *trans, char *diag, integer *n, - integer *nrhs, real *ap, real *b, integer *ldb, real *x, - integer *ldx, real *ferr, real *berr, real *work, - integer *iwork, integer *info, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern int stptri_(char *uplo, char *diag, integer *n, real *ap, integer *info, - ftnlen uplo_len, ftnlen diag_len); -extern int stptrs_(char *uplo, char *trans, char *diag, integer *n, - integer *nrhs, real *ap, real *b, integer *ldb, - integer *info, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len); -extern int strcon_(char *norm, char *uplo, char *diag, integer *n, real *a, - integer *lda, real *rcond, real *work, integer *iwork, - integer *info, ftnlen norm_len, ftnlen uplo_len, - ftnlen diag_len); -extern int strevc_(char *side, char *howmny, logical *select, integer *n, - real *t, integer *ldt, real *vl, integer *ldvl, real *vr, - integer *ldvr, integer *mm, integer *m, real *work, - integer *info, ftnlen side_len, ftnlen howmny_len); -extern int strexc_(char *compq, integer *n, real *t, integer *ldt, real *q, - integer *ldq, integer *ifst, integer *ilst, real *work, - integer *info, ftnlen compq_len); -extern int strrfs_(char *uplo, char *trans, char *diag, integer *n, - integer *nrhs, real *a, integer *lda, real *b, integer *ldb, - real *x, integer *ldx, real *ferr, real *berr, real *work, - integer *iwork, integer *info, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern int strsen_(char *job, char *compq, logical *select, integer *n, real *t, - integer *ldt, real *q, integer *ldq, real *wr, real *wi, - integer *m, real *s, real *sep, real *work, integer *lwork, - integer *iwork, integer *liwork, integer *info, - ftnlen job_len, ftnlen compq_len); -extern int strsna_(char *job, char *howmny, logical *select, integer *n, - real *t, integer *ldt, real *vl, integer *ldvl, real *vr, - integer *ldvr, real *s, real *sep, integer *mm, integer *m, - real *work, integer *ldwork, integer *iwork, integer *info, - ftnlen job_len, ftnlen howmny_len); -extern int strsyl_(char *trana, char *tranb, integer *isgn, integer *m, - integer *n, real *a, integer *lda, real *b, integer *ldb, - real *c__, integer *ldc, real *scale, integer *info, - ftnlen trana_len, ftnlen tranb_len); -extern int strti2_(char *uplo, char *diag, integer *n, real *a, integer *lda, - integer *info, ftnlen uplo_len, ftnlen diag_len); -extern int strtri_(char *uplo, char *diag, integer *n, real *a, integer *lda, - integer *info, ftnlen uplo_len, ftnlen diag_len); -extern int strtrs_(char *uplo, char *trans, char *diag, integer *n, - integer *nrhs, real *a, integer *lda, real *b, integer *ldb, - integer *info, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len); -extern int stzrqf_(integer *m, integer *n, real *a, integer *lda, real *tau, - integer *info); -extern int stzrzf_(integer *m, integer *n, real *a, integer *lda, real *tau, - real *work, integer *lwork, integer *info); -extern int xerbla_(char *srname, integer *info, ftnlen srname_len); -extern int zbdsqr_(char *uplo, integer *n, integer *ncvt, integer *nru, - integer *ncc, doublereal *d__, doublereal *e, - doublecomplex *vt, integer *ldvt, doublecomplex *u, - integer *ldu, doublecomplex *c__, integer *ldc, - doublereal *rwork, integer *info, ftnlen uplo_len); -extern int zdrot_(integer *n, doublecomplex *cx, integer *incx, - doublecomplex *cy, integer *incy, doublereal *c__, - doublereal *s); -extern int zdrscl_(integer *n, doublereal *sa, doublecomplex *sx, - integer *incx); -extern int zgbbrd_(char *vect, integer *m, integer *n, integer *ncc, - integer *kl, integer *ku, doublecomplex *ab, integer *ldab, - doublereal *d__, doublereal *e, doublecomplex *q, - integer *ldq, doublecomplex *pt, integer *ldpt, - doublecomplex *c__, integer *ldc, doublecomplex *work, - doublereal *rwork, integer *info, ftnlen vect_len); -extern int zgbcon_(char *norm, integer *n, integer *kl, integer *ku, - doublecomplex *ab, integer *ldab, integer *ipiv, - doublereal *anorm, doublereal *rcond, doublecomplex *work, - doublereal *rwork, integer *info, ftnlen norm_len); -extern int zgbequ_(integer *m, integer *n, integer *kl, integer *ku, - doublecomplex *ab, integer *ldab, doublereal *r__, - doublereal *c__, doublereal *rowcnd, doublereal *colcnd, - doublereal *amax, integer *info); -extern int zgbrfs_(char *trans, integer *n, integer *kl, integer *ku, - integer *nrhs, doublecomplex *ab, integer *ldab, - doublecomplex *afb, integer *ldafb, integer *ipiv, - doublecomplex *b, integer *ldb, doublecomplex *x, - integer *ldx, doublereal *ferr, doublereal *berr, - doublecomplex *work, doublereal *rwork, integer *info, - ftnlen trans_len); -extern int zgbsv_(integer *n, integer *kl, integer *ku, integer *nrhs, - doublecomplex *ab, integer *ldab, integer *ipiv, - doublecomplex *b, integer *ldb, integer *info); -extern int zgbsvx_(char *fact, char *trans, integer *n, integer *kl, - integer *ku, integer *nrhs, doublecomplex *ab, integer *ldab, - doublecomplex *afb, integer *ldafb, integer *ipiv, - char *equed, doublereal *r__, doublereal *c__, - doublecomplex *b, integer *ldb, doublecomplex *x, - integer *ldx, doublereal *rcond, doublereal *ferr, - doublereal *berr, doublecomplex *work, doublereal *rwork, - integer *info, ftnlen fact_len, ftnlen trans_len, - ftnlen equed_len); -extern int zgbtf2_(integer *m, integer *n, integer *kl, integer *ku, - doublecomplex *ab, integer *ldab, integer *ipiv, - integer *info); -extern int zgbtrf_(integer *m, integer *n, integer *kl, integer *ku, - doublecomplex *ab, integer *ldab, integer *ipiv, - integer *info); -extern int zgbtrs_(char *trans, integer *n, integer *kl, integer *ku, - integer *nrhs, doublecomplex *ab, integer *ldab, - integer *ipiv, doublecomplex *b, integer *ldb, integer *info, - ftnlen trans_len); -extern int zgebak_(char *job, char *side, integer *n, integer *ilo, - integer *ihi, doublereal *scale, integer *m, - doublecomplex *v, integer *ldv, integer *info, - ftnlen job_len, ftnlen side_len); -extern int zgebal_(char *job, integer *n, doublecomplex *a, integer *lda, - integer *ilo, integer *ihi, doublereal *scale, integer *info, - ftnlen job_len); -extern int zgebd2_(integer *m, integer *n, doublecomplex *a, integer *lda, - doublereal *d__, doublereal *e, doublecomplex *tauq, - doublecomplex *taup, doublecomplex *work, integer *info); -extern int zgebrd_(integer *m, integer *n, doublecomplex *a, integer *lda, - doublereal *d__, doublereal *e, doublecomplex *tauq, - doublecomplex *taup, doublecomplex *work, integer *lwork, - integer *info); -extern int zgecon_(char *norm, integer *n, doublecomplex *a, integer *lda, - doublereal *anorm, doublereal *rcond, doublecomplex *work, - doublereal *rwork, integer *info, ftnlen norm_len); -extern int zgeequ_(integer *m, integer *n, doublecomplex *a, integer *lda, - doublereal *r__, doublereal *c__, doublereal *rowcnd, - doublereal *colcnd, doublereal *amax, integer *info); -extern int zgees_(char *jobvs, char *sort, L_fp select, integer *n, - doublecomplex *a, integer *lda, integer *sdim, - doublecomplex *w, doublecomplex *vs, integer *ldvs, - doublecomplex *work, integer *lwork, doublereal *rwork, - logical *bwork, integer *info, ftnlen jobvs_len, - ftnlen sort_len); -extern int zgeesx_(char *jobvs, char *sort, L_fp select, char *sense, - integer *n, doublecomplex *a, integer *lda, integer *sdim, - doublecomplex *w, doublecomplex *vs, integer *ldvs, - doublereal *rconde, doublereal *rcondv, doublecomplex *work, - integer *lwork, doublereal *rwork, logical *bwork, - integer *info, ftnlen jobvs_len, ftnlen sort_len, - ftnlen sense_len); -extern int zgeev_(char *jobvl, char *jobvr, integer *n, doublecomplex *a, - integer *lda, doublecomplex *w, doublecomplex *vl, - integer *ldvl, doublecomplex *vr, integer *ldvr, - doublecomplex *work, integer *lwork, doublereal *rwork, - integer *info, ftnlen jobvl_len, ftnlen jobvr_len); -extern int zgeevx_(char *balanc, char *jobvl, char *jobvr, char *sense, - integer *n, doublecomplex *a, integer *lda, doublecomplex *w, - doublecomplex *vl, integer *ldvl, doublecomplex *vr, - integer *ldvr, integer *ilo, integer *ihi, doublereal *scale, - doublereal *abnrm, doublereal *rconde, doublereal *rcondv, - doublecomplex *work, integer *lwork, doublereal *rwork, - integer *info, ftnlen balanc_len, ftnlen jobvl_len, - ftnlen jobvr_len, ftnlen sense_len); -extern int zgegs_(char *jobvsl, char *jobvsr, integer *n, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, - doublecomplex *alpha, doublecomplex *beta, doublecomplex *vsl, - integer *ldvsl, doublecomplex *vsr, integer *ldvsr, - doublecomplex *work, integer *lwork, doublereal *rwork, - integer *info, ftnlen jobvsl_len, ftnlen jobvsr_len); -extern int zgegv_(char *jobvl, char *jobvr, integer *n, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, - doublecomplex *alpha, doublecomplex *beta, doublecomplex *vl, - integer *ldvl, doublecomplex *vr, integer *ldvr, - doublecomplex *work, integer *lwork, doublereal *rwork, - integer *info, ftnlen jobvl_len, ftnlen jobvr_len); -extern int zgehd2_(integer *n, integer *ilo, integer *ihi, doublecomplex *a, - integer *lda, doublecomplex *tau, doublecomplex *work, - integer *info); -extern int zgehrd_(integer *n, integer *ilo, integer *ihi, doublecomplex *a, - integer *lda, doublecomplex *tau, doublecomplex *work, - integer *lwork, integer *info); -extern int zgelq2_(integer *m, integer *n, doublecomplex *a, integer *lda, - doublecomplex *tau, doublecomplex *work, integer *info); -extern int zgelqf_(integer *m, integer *n, doublecomplex *a, integer *lda, - doublecomplex *tau, doublecomplex *work, integer *lwork, - integer *info); -extern int zgels_(char *trans, integer *m, integer *n, integer *nrhs, - doublecomplex *a, integer *lda, doublecomplex *b, - integer *ldb, doublecomplex *work, integer *lwork, - integer *info, ftnlen trans_len); -extern int zgelsd_(integer *m, integer *n, integer *nrhs, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, doublereal *s, - doublereal *rcond, integer *rank, doublecomplex *work, - integer *lwork, doublereal *rwork, integer *iwork, - integer *info); -extern int zgelss_(integer *m, integer *n, integer *nrhs, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, doublereal *s, - doublereal *rcond, integer *rank, doublecomplex *work, - integer *lwork, doublereal *rwork, integer *info); -extern int zgelsx_(integer *m, integer *n, integer *nrhs, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, integer *jpvt, - doublereal *rcond, integer *rank, doublecomplex *work, - doublereal *rwork, integer *info); -extern int zgelsy_(integer *m, integer *n, integer *nrhs, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, integer *jpvt, - doublereal *rcond, integer *rank, doublecomplex *work, - integer *lwork, doublereal *rwork, integer *info); -extern int zgeql2_(integer *m, integer *n, doublecomplex *a, integer *lda, - doublecomplex *tau, doublecomplex *work, integer *info); -extern int zgeqlf_(integer *m, integer *n, doublecomplex *a, integer *lda, - doublecomplex *tau, doublecomplex *work, integer *lwork, - integer *info); -extern int zgeqp3_(integer *m, integer *n, doublecomplex *a, integer *lda, - integer *jpvt, doublecomplex *tau, doublecomplex *work, - integer *lwork, doublereal *rwork, integer *info); -extern int zgeqpf_(integer *m, integer *n, doublecomplex *a, integer *lda, - integer *jpvt, doublecomplex *tau, doublecomplex *work, - doublereal *rwork, integer *info); -extern int zgeqr2_(integer *m, integer *n, doublecomplex *a, integer *lda, - doublecomplex *tau, doublecomplex *work, integer *info); -extern int zgeqrf_(integer *m, integer *n, doublecomplex *a, integer *lda, - doublecomplex *tau, doublecomplex *work, integer *lwork, - integer *info); -extern int zgerfs_(char *trans, integer *n, integer *nrhs, doublecomplex *a, - integer *lda, doublecomplex *af, integer *ldaf, - integer *ipiv, doublecomplex *b, integer *ldb, - doublecomplex *x, integer *ldx, doublereal *ferr, - doublereal *berr, doublecomplex *work, doublereal *rwork, - integer *info, ftnlen trans_len); -extern int zgerq2_(integer *m, integer *n, doublecomplex *a, integer *lda, - doublecomplex *tau, doublecomplex *work, integer *info); -extern int zgerqf_(integer *m, integer *n, doublecomplex *a, integer *lda, - doublecomplex *tau, doublecomplex *work, integer *lwork, - integer *info); -extern int zgesc2_(integer *n, doublecomplex *a, integer *lda, - doublecomplex *rhs, integer *ipiv, integer *jpiv, - doublereal *scale); -extern int zgesdd_(char *jobz, integer *m, integer *n, doublecomplex *a, - integer *lda, doublereal *s, doublecomplex *u, integer *ldu, - doublecomplex *vt, integer *ldvt, doublecomplex *work, - integer *lwork, doublereal *rwork, integer *iwork, - integer *info, ftnlen jobz_len); -extern int zgesv_(integer *n, integer *nrhs, doublecomplex *a, integer *lda, - integer *ipiv, doublecomplex *b, integer *ldb, integer *info); -extern int zgesvd_(char *jobu, char *jobvt, integer *m, integer *n, - doublecomplex *a, integer *lda, doublereal *s, - doublecomplex *u, integer *ldu, doublecomplex *vt, - integer *ldvt, doublecomplex *work, integer *lwork, - doublereal *rwork, integer *info, ftnlen jobu_len, - ftnlen jobvt_len); -extern int zgesvx_(char *fact, char *trans, integer *n, integer *nrhs, - doublecomplex *a, integer *lda, doublecomplex *af, - integer *ldaf, integer *ipiv, char *equed, doublereal *r__, - doublereal *c__, doublecomplex *b, integer *ldb, - doublecomplex *x, integer *ldx, doublereal *rcond, - doublereal *ferr, doublereal *berr, doublecomplex *work, - doublereal *rwork, integer *info, ftnlen fact_len, - ftnlen trans_len, ftnlen equed_len); -extern int zgetc2_(integer *n, doublecomplex *a, integer *lda, integer *ipiv, - integer *jpiv, integer *info); -extern int zgetf2_(integer *m, integer *n, doublecomplex *a, integer *lda, - integer *ipiv, integer *info); -extern int zgetrf_(integer *m, integer *n, doublecomplex *a, integer *lda, - integer *ipiv, integer *info); -extern int zgetri_(integer *n, doublecomplex *a, integer *lda, integer *ipiv, - doublecomplex *work, integer *lwork, integer *info); -extern int zgetrs_(char *trans, integer *n, integer *nrhs, doublecomplex *a, - integer *lda, integer *ipiv, doublecomplex *b, integer *ldb, - integer *info, ftnlen trans_len); -extern int zggbak_(char *job, char *side, integer *n, integer *ilo, - integer *ihi, doublereal *lscale, doublereal *rscale, - integer *m, doublecomplex *v, integer *ldv, integer *info, - ftnlen job_len, ftnlen side_len); -extern int zggbal_(char *job, integer *n, doublecomplex *a, integer *lda, - doublecomplex *b, integer *ldb, integer *ilo, integer *ihi, - doublereal *lscale, doublereal *rscale, doublereal *work, - integer *info, ftnlen job_len); -extern int zgges_(char *jobvsl, char *jobvsr, char *sort, L_fp delctg, - integer *n, doublecomplex *a, integer *lda, doublecomplex *b, - integer *ldb, integer *sdim, doublecomplex *alpha, - doublecomplex *beta, doublecomplex *vsl, integer *ldvsl, - doublecomplex *vsr, integer *ldvsr, doublecomplex *work, - integer *lwork, doublereal *rwork, logical *bwork, - integer *info, ftnlen jobvsl_len, ftnlen jobvsr_len, - ftnlen sort_len); -extern int zggesx_(char *jobvsl, char *jobvsr, char *sort, L_fp delctg, - char *sense, integer *n, doublecomplex *a, integer *lda, - doublecomplex *b, integer *ldb, integer *sdim, - doublecomplex *alpha, doublecomplex *beta, - doublecomplex *vsl, integer *ldvsl, doublecomplex *vsr, - integer *ldvsr, doublereal *rconde, doublereal *rcondv, - doublecomplex *work, integer *lwork, doublereal *rwork, - integer *iwork, integer *liwork, logical *bwork, - integer *info, ftnlen jobvsl_len, ftnlen jobvsr_len, - ftnlen sort_len, ftnlen sense_len); -extern int zggev_(char *jobvl, char *jobvr, integer *n, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, - doublecomplex *alpha, doublecomplex *beta, doublecomplex *vl, - integer *ldvl, doublecomplex *vr, integer *ldvr, - doublecomplex *work, integer *lwork, doublereal *rwork, - integer *info, ftnlen jobvl_len, ftnlen jobvr_len); -extern int zggevx_(char *balanc, char *jobvl, char *jobvr, char *sense, - integer *n, doublecomplex *a, integer *lda, doublecomplex *b, - integer *ldb, doublecomplex *alpha, doublecomplex *beta, - doublecomplex *vl, integer *ldvl, doublecomplex *vr, - integer *ldvr, integer *ilo, integer *ihi, - doublereal *lscale, doublereal *rscale, doublereal *abnrm, - doublereal *bbnrm, doublereal *rconde, doublereal *rcondv, - doublecomplex *work, integer *lwork, doublereal *rwork, - integer *iwork, logical *bwork, integer *info, - ftnlen balanc_len, ftnlen jobvl_len, ftnlen jobvr_len, - ftnlen sense_len); -extern int zggglm_(integer *n, integer *m, integer *p, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, - doublecomplex *d__, doublecomplex *x, doublecomplex *y, - doublecomplex *work, integer *lwork, integer *info); -extern int zgghrd_(char *compq, char *compz, integer *n, integer *ilo, - integer *ihi, doublecomplex *a, integer *lda, - doublecomplex *b, integer *ldb, doublecomplex *q, - integer *ldq, doublecomplex *z__, integer *ldz, - integer *info, ftnlen compq_len, ftnlen compz_len); -extern int zgglse_(integer *m, integer *n, integer *p, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, - doublecomplex *c__, doublecomplex *d__, doublecomplex *x, - doublecomplex *work, integer *lwork, integer *info); -extern int zggqrf_(integer *n, integer *m, integer *p, doublecomplex *a, - integer *lda, doublecomplex *taua, doublecomplex *b, - integer *ldb, doublecomplex *taub, doublecomplex *work, - integer *lwork, integer *info); -extern int zggrqf_(integer *m, integer *p, integer *n, doublecomplex *a, - integer *lda, doublecomplex *taua, doublecomplex *b, - integer *ldb, doublecomplex *taub, doublecomplex *work, - integer *lwork, integer *info); -extern int zggsvd_(char *jobu, char *jobv, char *jobq, integer *m, integer *n, - integer *p, integer *k, integer *l, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, - doublereal *alpha, doublereal *beta, doublecomplex *u, - integer *ldu, doublecomplex *v, integer *ldv, - doublecomplex *q, integer *ldq, doublecomplex *work, - doublereal *rwork, integer *iwork, integer *info, - ftnlen jobu_len, ftnlen jobv_len, ftnlen jobq_len); -extern int zggsvp_(char *jobu, char *jobv, char *jobq, integer *m, integer *p, - integer *n, doublecomplex *a, integer *lda, doublecomplex *b, - integer *ldb, doublereal *tola, doublereal *tolb, integer *k, - integer *l, doublecomplex *u, integer *ldu, doublecomplex *v, - integer *ldv, doublecomplex *q, integer *ldq, integer *iwork, - doublereal *rwork, doublecomplex *tau, doublecomplex *work, - integer *info, ftnlen jobu_len, ftnlen jobv_len, - ftnlen jobq_len); -extern int zgtcon_(char *norm, integer *n, doublecomplex *dl, - doublecomplex *d__, doublecomplex *du, doublecomplex *du2, - integer *ipiv, doublereal *anorm, doublereal *rcond, - doublecomplex *work, integer *info, ftnlen norm_len); -extern int zgtrfs_(char *trans, integer *n, integer *nrhs, doublecomplex *dl, - doublecomplex *d__, doublecomplex *du, doublecomplex *dlf, - doublecomplex *df, doublecomplex *duf, doublecomplex *du2, - integer *ipiv, doublecomplex *b, integer *ldb, - doublecomplex *x, integer *ldx, doublereal *ferr, - doublereal *berr, doublecomplex *work, doublereal *rwork, - integer *info, ftnlen trans_len); -extern int zgtsv_(integer *n, integer *nrhs, doublecomplex *dl, - doublecomplex *d__, doublecomplex *du, doublecomplex *b, - integer *ldb, integer *info); -extern int zgtsvx_(char *fact, char *trans, integer *n, integer *nrhs, - doublecomplex *dl, doublecomplex *d__, doublecomplex *du, - doublecomplex *dlf, doublecomplex *df, doublecomplex *duf, - doublecomplex *du2, integer *ipiv, doublecomplex *b, - integer *ldb, doublecomplex *x, integer *ldx, - doublereal *rcond, doublereal *ferr, doublereal *berr, - doublecomplex *work, doublereal *rwork, integer *info, - ftnlen fact_len, ftnlen trans_len); -extern int zgttrf_(integer *n, doublecomplex *dl, doublecomplex *d__, - doublecomplex *du, doublecomplex *du2, integer *ipiv, - integer *info); -extern int zgttrs_(char *trans, integer *n, integer *nrhs, doublecomplex *dl, - doublecomplex *d__, doublecomplex *du, doublecomplex *du2, - integer *ipiv, doublecomplex *b, integer *ldb, integer *info, - ftnlen trans_len); -extern int zgtts2_(integer *itrans, integer *n, integer *nrhs, - doublecomplex *dl, doublecomplex *d__, doublecomplex *du, - doublecomplex *du2, integer *ipiv, doublecomplex *b, - integer *ldb); -extern int zhbev_(char *jobz, char *uplo, integer *n, integer *kd, - doublecomplex *ab, integer *ldab, doublereal *w, - doublecomplex *z__, integer *ldz, doublecomplex *work, - doublereal *rwork, integer *info, ftnlen jobz_len, - ftnlen uplo_len); -extern int zhbevd_(char *jobz, char *uplo, integer *n, integer *kd, - doublecomplex *ab, integer *ldab, doublereal *w, - doublecomplex *z__, integer *ldz, doublecomplex *work, - integer *lwork, doublereal *rwork, integer *lrwork, - integer *iwork, integer *liwork, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int zhbevx_(char *jobz, char *range, char *uplo, integer *n, integer *kd, - doublecomplex *ab, integer *ldab, doublecomplex *q, - integer *ldq, doublereal *vl, doublereal *vu, integer *il, - integer *iu, doublereal *abstol, integer *m, doublereal *w, - doublecomplex *z__, integer *ldz, doublecomplex *work, - doublereal *rwork, integer *iwork, integer *ifail, - integer *info, ftnlen jobz_len, ftnlen range_len, - ftnlen uplo_len); -extern int zhbgst_(char *vect, char *uplo, integer *n, integer *ka, integer *kb, - doublecomplex *ab, integer *ldab, doublecomplex *bb, - integer *ldbb, doublecomplex *x, integer *ldx, - doublecomplex *work, doublereal *rwork, integer *info, - ftnlen vect_len, ftnlen uplo_len); -extern int zhbgv_(char *jobz, char *uplo, integer *n, integer *ka, integer *kb, - doublecomplex *ab, integer *ldab, doublecomplex *bb, - integer *ldbb, doublereal *w, doublecomplex *z__, - integer *ldz, doublecomplex *work, doublereal *rwork, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int zhbgvd_(char *jobz, char *uplo, integer *n, integer *ka, integer *kb, - doublecomplex *ab, integer *ldab, doublecomplex *bb, - integer *ldbb, doublereal *w, doublecomplex *z__, - integer *ldz, doublecomplex *work, integer *lwork, - doublereal *rwork, integer *lrwork, integer *iwork, - integer *liwork, integer *info, ftnlen jobz_len, - ftnlen uplo_len); -extern int zhbgvx_(char *jobz, char *range, char *uplo, integer *n, integer *ka, - integer *kb, doublecomplex *ab, integer *ldab, - doublecomplex *bb, integer *ldbb, doublecomplex *q, - integer *ldq, doublereal *vl, doublereal *vu, integer *il, - integer *iu, doublereal *abstol, integer *m, doublereal *w, - doublecomplex *z__, integer *ldz, doublecomplex *work, - doublereal *rwork, integer *iwork, integer *ifail, - integer *info, ftnlen jobz_len, ftnlen range_len, - ftnlen uplo_len); -extern int zhbtrd_(char *vect, char *uplo, integer *n, integer *kd, - doublecomplex *ab, integer *ldab, doublereal *d__, - doublereal *e, doublecomplex *q, integer *ldq, - doublecomplex *work, integer *info, ftnlen vect_len, - ftnlen uplo_len); -extern int zhecon_(char *uplo, integer *n, doublecomplex *a, integer *lda, - integer *ipiv, doublereal *anorm, doublereal *rcond, - doublecomplex *work, integer *info, ftnlen uplo_len); -extern int zheev_(char *jobz, char *uplo, integer *n, doublecomplex *a, - integer *lda, doublereal *w, doublecomplex *work, - integer *lwork, doublereal *rwork, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int zheevd_(char *jobz, char *uplo, integer *n, doublecomplex *a, - integer *lda, doublereal *w, doublecomplex *work, - integer *lwork, doublereal *rwork, integer *lrwork, - integer *iwork, integer *liwork, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int zheevr_(char *jobz, char *range, char *uplo, integer *n, - doublecomplex *a, integer *lda, doublereal *vl, - doublereal *vu, integer *il, integer *iu, doublereal *abstol, - integer *m, doublereal *w, doublecomplex *z__, integer *ldz, - integer *isuppz, doublecomplex *work, integer *lwork, - doublereal *rwork, integer *lrwork, integer *iwork, - integer *liwork, integer *info, ftnlen jobz_len, - ftnlen range_len, ftnlen uplo_len); -extern int zheevx_(char *jobz, char *range, char *uplo, integer *n, - doublecomplex *a, integer *lda, doublereal *vl, - doublereal *vu, integer *il, integer *iu, doublereal *abstol, - integer *m, doublereal *w, doublecomplex *z__, integer *ldz, - doublecomplex *work, integer *lwork, doublereal *rwork, - integer *iwork, integer *ifail, integer *info, - ftnlen jobz_len, ftnlen range_len, ftnlen uplo_len); -extern int zhegs2_(integer *itype, char *uplo, integer *n, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int zhegst_(integer *itype, char *uplo, integer *n, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int zhegv_(integer *itype, char *jobz, char *uplo, integer *n, - doublecomplex *a, integer *lda, doublecomplex *b, - integer *ldb, doublereal *w, doublecomplex *work, - integer *lwork, doublereal *rwork, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int zhegvd_(integer *itype, char *jobz, char *uplo, integer *n, - doublecomplex *a, integer *lda, doublecomplex *b, - integer *ldb, doublereal *w, doublecomplex *work, - integer *lwork, doublereal *rwork, integer *lrwork, - integer *iwork, integer *liwork, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int zhegvx_(integer *itype, char *jobz, char *range, char *uplo, - integer *n, doublecomplex *a, integer *lda, doublecomplex *b, - integer *ldb, doublereal *vl, doublereal *vu, integer *il, - integer *iu, doublereal *abstol, integer *m, doublereal *w, - doublecomplex *z__, integer *ldz, doublecomplex *work, - integer *lwork, doublereal *rwork, integer *iwork, - integer *ifail, integer *info, ftnlen jobz_len, - ftnlen range_len, ftnlen uplo_len); -extern int zherfs_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, - integer *lda, doublecomplex *af, integer *ldaf, - integer *ipiv, doublecomplex *b, integer *ldb, - doublecomplex *x, integer *ldx, doublereal *ferr, - doublereal *berr, doublecomplex *work, doublereal *rwork, - integer *info, ftnlen uplo_len); -extern int zhesv_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, - integer *lda, integer *ipiv, doublecomplex *b, integer *ldb, - doublecomplex *work, integer *lwork, integer *info, - ftnlen uplo_len); -extern int zhesvx_(char *fact, char *uplo, integer *n, integer *nrhs, - doublecomplex *a, integer *lda, doublecomplex *af, - integer *ldaf, integer *ipiv, doublecomplex *b, integer *ldb, - doublecomplex *x, integer *ldx, doublereal *rcond, - doublereal *ferr, doublereal *berr, doublecomplex *work, - integer *lwork, doublereal *rwork, integer *info, - ftnlen fact_len, ftnlen uplo_len); -extern int zhetd2_(char *uplo, integer *n, doublecomplex *a, integer *lda, - doublereal *d__, doublereal *e, doublecomplex *tau, - integer *info, ftnlen uplo_len); -extern int zhetf2_(char *uplo, integer *n, doublecomplex *a, integer *lda, - integer *ipiv, integer *info, ftnlen uplo_len); -extern int zhetrd_(char *uplo, integer *n, doublecomplex *a, integer *lda, - doublereal *d__, doublereal *e, doublecomplex *tau, - doublecomplex *work, integer *lwork, integer *info, - ftnlen uplo_len); -extern int zhetrf_(char *uplo, integer *n, doublecomplex *a, integer *lda, - integer *ipiv, doublecomplex *work, integer *lwork, - integer *info, ftnlen uplo_len); -extern int zhetri_(char *uplo, integer *n, doublecomplex *a, integer *lda, - integer *ipiv, doublecomplex *work, integer *info, - ftnlen uplo_len); -extern int zhetrs_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, - integer *lda, integer *ipiv, doublecomplex *b, integer *ldb, - integer *info, ftnlen uplo_len); -extern int zhgeqz_(char *job, char *compq, char *compz, integer *n, - integer *ilo, integer *ihi, doublecomplex *a, integer *lda, - doublecomplex *b, integer *ldb, doublecomplex *alpha, - doublecomplex *beta, doublecomplex *q, integer *ldq, - doublecomplex *z__, integer *ldz, doublecomplex *work, - integer *lwork, doublereal *rwork, integer *info, - ftnlen job_len, ftnlen compq_len, ftnlen compz_len); -extern int zhpcon_(char *uplo, integer *n, doublecomplex *ap, integer *ipiv, - doublereal *anorm, doublereal *rcond, doublecomplex *work, - integer *info, ftnlen uplo_len); -extern int zhpev_(char *jobz, char *uplo, integer *n, doublecomplex *ap, - doublereal *w, doublecomplex *z__, integer *ldz, - doublecomplex *work, doublereal *rwork, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int zhpevd_(char *jobz, char *uplo, integer *n, doublecomplex *ap, - doublereal *w, doublecomplex *z__, integer *ldz, - doublecomplex *work, integer *lwork, doublereal *rwork, - integer *lrwork, integer *iwork, integer *liwork, - integer *info, ftnlen jobz_len, ftnlen uplo_len); -extern int zhpevx_(char *jobz, char *range, char *uplo, integer *n, - doublecomplex *ap, doublereal *vl, doublereal *vu, - integer *il, integer *iu, doublereal *abstol, integer *m, - doublereal *w, doublecomplex *z__, integer *ldz, - doublecomplex *work, doublereal *rwork, integer *iwork, - integer *ifail, integer *info, ftnlen jobz_len, - ftnlen range_len, ftnlen uplo_len); -extern int zhpgst_(integer *itype, char *uplo, integer *n, doublecomplex *ap, - doublecomplex *bp, integer *info, ftnlen uplo_len); -extern int zhpgv_(integer *itype, char *jobz, char *uplo, integer *n, - doublecomplex *ap, doublecomplex *bp, doublereal *w, - doublecomplex *z__, integer *ldz, doublecomplex *work, - doublereal *rwork, integer *info, ftnlen jobz_len, - ftnlen uplo_len); -extern int zhpgvd_(integer *itype, char *jobz, char *uplo, integer *n, - doublecomplex *ap, doublecomplex *bp, doublereal *w, - doublecomplex *z__, integer *ldz, doublecomplex *work, - integer *lwork, doublereal *rwork, integer *lrwork, - integer *iwork, integer *liwork, integer *info, - ftnlen jobz_len, ftnlen uplo_len); -extern int zhpgvx_(integer *itype, char *jobz, char *range, char *uplo, - integer *n, doublecomplex *ap, doublecomplex *bp, - doublereal *vl, doublereal *vu, integer *il, integer *iu, - doublereal *abstol, integer *m, doublereal *w, - doublecomplex *z__, integer *ldz, doublecomplex *work, - doublereal *rwork, integer *iwork, integer *ifail, - integer *info, ftnlen jobz_len, ftnlen range_len, - ftnlen uplo_len); -extern int zhprfs_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, - doublecomplex *afp, integer *ipiv, doublecomplex *b, - integer *ldb, doublecomplex *x, integer *ldx, - doublereal *ferr, doublereal *berr, doublecomplex *work, - doublereal *rwork, integer *info, ftnlen uplo_len); -extern int zhpsv_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, - integer *ipiv, doublecomplex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int zhpsvx_(char *fact, char *uplo, integer *n, integer *nrhs, - doublecomplex *ap, doublecomplex *afp, integer *ipiv, - doublecomplex *b, integer *ldb, doublecomplex *x, - integer *ldx, doublereal *rcond, doublereal *ferr, - doublereal *berr, doublecomplex *work, doublereal *rwork, - integer *info, ftnlen fact_len, ftnlen uplo_len); -extern int zhptrd_(char *uplo, integer *n, doublecomplex *ap, doublereal *d__, - doublereal *e, doublecomplex *tau, integer *info, - ftnlen uplo_len); -extern int zhptrf_(char *uplo, integer *n, doublecomplex *ap, integer *ipiv, - integer *info, ftnlen uplo_len); -extern int zhptri_(char *uplo, integer *n, doublecomplex *ap, integer *ipiv, - doublecomplex *work, integer *info, ftnlen uplo_len); -extern int zhptrs_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, - integer *ipiv, doublecomplex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int zhsein_(char *side, char *eigsrc, char *initv, logical *select, - integer *n, doublecomplex *h__, integer *ldh, - doublecomplex *w, doublecomplex *vl, integer *ldvl, - doublecomplex *vr, integer *ldvr, integer *mm, integer *m, - doublecomplex *work, doublereal *rwork, integer *ifaill, - integer *ifailr, integer *info, ftnlen side_len, - ftnlen eigsrc_len, ftnlen initv_len); -extern int zhseqr_(char *job, char *compz, integer *n, integer *ilo, - integer *ihi, doublecomplex *h__, integer *ldh, - doublecomplex *w, doublecomplex *z__, integer *ldz, - doublecomplex *work, integer *lwork, integer *info, - ftnlen job_len, ftnlen compz_len); -extern int zlabrd_(integer *m, integer *n, integer *nb, doublecomplex *a, - integer *lda, doublereal *d__, doublereal *e, - doublecomplex *tauq, doublecomplex *taup, doublecomplex *x, - integer *ldx, doublecomplex *y, integer *ldy); -extern int zlacgv_(integer *n, doublecomplex *x, integer *incx); -extern int zlacon_(integer *n, doublecomplex *v, doublecomplex *x, - doublereal *est, integer *kase); -extern int zlacp2_(char *uplo, integer *m, integer *n, doublereal *a, - integer *lda, doublecomplex *b, integer *ldb, - ftnlen uplo_len); -extern int zlacpy_(char *uplo, integer *m, integer *n, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, - ftnlen uplo_len); -extern int zlacrm_(integer *m, integer *n, doublecomplex *a, integer *lda, - doublereal *b, integer *ldb, doublecomplex *c__, - integer *ldc, doublereal *rwork); -extern int zlacrt_(integer *n, doublecomplex *cx, integer *incx, - doublecomplex *cy, integer *incy, doublecomplex *c__, - doublecomplex *s); -extern Z_f zladiv_(doublecomplex *ret_val, doublecomplex *x, doublecomplex *y); -extern int zlaed0_(integer *qsiz, integer *n, doublereal *d__, doublereal *e, - doublecomplex *q, integer *ldq, doublecomplex *qstore, - integer *ldqs, doublereal *rwork, integer *iwork, - integer *info); -extern int zlaed7_(integer *n, integer *cutpnt, integer *qsiz, integer *tlvls, - integer *curlvl, integer *curpbm, doublereal *d__, - doublecomplex *q, integer *ldq, doublereal *rho, - integer *indxq, doublereal *qstore, integer *qptr, - integer *prmptr, integer *perm, integer *givptr, - integer *givcol, doublereal *givnum, doublecomplex *work, - doublereal *rwork, integer *iwork, integer *info); -extern int zlaed8_(integer *k, integer *n, integer *qsiz, doublecomplex *q, - integer *ldq, doublereal *d__, doublereal *rho, - integer *cutpnt, doublereal *z__, doublereal *dlamda, - doublecomplex *q2, integer *ldq2, doublereal *w, - integer *indxp, integer *indx, integer *indxq, integer *perm, - integer *givptr, integer *givcol, doublereal *givnum, - integer *info); -extern int zlaein_(logical *rightv, logical *noinit, integer *n, - doublecomplex *h__, integer *ldh, doublecomplex *w, - doublecomplex *v, doublecomplex *b, integer *ldb, - doublereal *rwork, doublereal *eps3, doublereal *smlnum, - integer *info); -extern int zlaesy_(doublecomplex *a, doublecomplex *b, doublecomplex *c__, - doublecomplex *rt1, doublecomplex *rt2, - doublecomplex *evscal, doublecomplex *cs1, - doublecomplex *sn1); -extern int zlaev2_(doublecomplex *a, doublecomplex *b, doublecomplex *c__, - doublereal *rt1, doublereal *rt2, doublereal *cs1, - doublecomplex *sn1); -extern int zlags2_(logical *upper, doublereal *a1, doublecomplex *a2, - doublereal *a3, doublereal *b1, doublecomplex *b2, - doublereal *b3, doublereal *csu, doublecomplex *snu, - doublereal *csv, doublecomplex *snv, doublereal *csq, - doublecomplex *snq); -extern int zlagtm_(char *trans, integer *n, integer *nrhs, doublereal *alpha, - doublecomplex *dl, doublecomplex *d__, doublecomplex *du, - doublecomplex *x, integer *ldx, doublereal *beta, - doublecomplex *b, integer *ldb, ftnlen trans_len); -extern int zlahef_(char *uplo, integer *n, integer *nb, integer *kb, - doublecomplex *a, integer *lda, integer *ipiv, - doublecomplex *w, integer *ldw, integer *info, - ftnlen uplo_len); -extern int zlahqr_(logical *wantt, logical *wantz, integer *n, integer *ilo, - integer *ihi, doublecomplex *h__, integer *ldh, - doublecomplex *w, integer *iloz, integer *ihiz, - doublecomplex *z__, integer *ldz, integer *info); -extern int zlahrd_(integer *n, integer *k, integer *nb, doublecomplex *a, - integer *lda, doublecomplex *tau, doublecomplex *t, - integer *ldt, doublecomplex *y, integer *ldy); -extern int zlaic1_(integer *job, integer *j, doublecomplex *x, doublereal *sest, - doublecomplex *w, doublecomplex *gamma, doublereal *sestpr, - doublecomplex *s, doublecomplex *c__); -extern int zlals0_(integer *icompq, integer *nl, integer *nr, integer *sqre, - integer *nrhs, doublecomplex *b, integer *ldb, - doublecomplex *bx, integer *ldbx, integer *perm, - integer *givptr, integer *givcol, integer *ldgcol, - doublereal *givnum, integer *ldgnum, doublereal *poles, - doublereal *difl, doublereal *difr, doublereal *z__, - integer *k, doublereal *c__, doublereal *s, - doublereal *rwork, integer *info); -extern int zlalsa_(integer *icompq, integer *smlsiz, integer *n, integer *nrhs, - doublecomplex *b, integer *ldb, doublecomplex *bx, - integer *ldbx, doublereal *u, integer *ldu, doublereal *vt, - integer *k, doublereal *difl, doublereal *difr, - doublereal *z__, doublereal *poles, integer *givptr, - integer *givcol, integer *ldgcol, integer *perm, - doublereal *givnum, doublereal *c__, doublereal *s, - doublereal *rwork, integer *iwork, integer *info); -extern int zlalsd_(char *uplo, integer *smlsiz, integer *n, integer *nrhs, - doublereal *d__, doublereal *e, doublecomplex *b, - integer *ldb, doublereal *rcond, integer *rank, - doublecomplex *work, doublereal *rwork, integer *iwork, - integer *info, ftnlen uplo_len); -extern doublereal zlangb_(char *norm, integer *n, integer *kl, integer *ku, - doublecomplex *ab, integer *ldab, doublereal *work, - ftnlen norm_len); -extern doublereal zlange_(char *norm, integer *m, integer *n, doublecomplex *a, - integer *lda, doublereal *work, ftnlen norm_len); -extern doublereal zlangt_(char *norm, integer *n, doublecomplex *dl, - doublecomplex *d__, doublecomplex *du, - ftnlen norm_len); -extern doublereal zlanhb_(char *norm, char *uplo, integer *n, integer *k, - doublecomplex *ab, integer *ldab, doublereal *work, - ftnlen norm_len, ftnlen uplo_len); -extern doublereal zlanhe_(char *norm, char *uplo, integer *n, doublecomplex *a, - integer *lda, doublereal *work, ftnlen norm_len, - ftnlen uplo_len); -extern doublereal zlanhp_(char *norm, char *uplo, integer *n, doublecomplex *ap, - doublereal *work, ftnlen norm_len, ftnlen uplo_len); -extern doublereal zlanhs_(char *norm, integer *n, doublecomplex *a, - integer *lda, doublereal *work, ftnlen norm_len); -extern doublereal zlanht_(char *norm, integer *n, doublereal *d__, - doublecomplex *e, ftnlen norm_len); -extern doublereal zlansb_(char *norm, char *uplo, integer *n, integer *k, - doublecomplex *ab, integer *ldab, doublereal *work, - ftnlen norm_len, ftnlen uplo_len); -extern doublereal zlansp_(char *norm, char *uplo, integer *n, doublecomplex *ap, - doublereal *work, ftnlen norm_len, ftnlen uplo_len); -extern doublereal zlansy_(char *norm, char *uplo, integer *n, doublecomplex *a, - integer *lda, doublereal *work, ftnlen norm_len, - ftnlen uplo_len); -extern doublereal zlantb_(char *norm, char *uplo, char *diag, integer *n, - integer *k, doublecomplex *ab, integer *ldab, - doublereal *work, ftnlen norm_len, ftnlen uplo_len, - ftnlen diag_len); -extern doublereal zlantp_(char *norm, char *uplo, char *diag, integer *n, - doublecomplex *ap, doublereal *work, ftnlen norm_len, - ftnlen uplo_len, ftnlen diag_len); -extern doublereal zlantr_(char *norm, char *uplo, char *diag, integer *m, - integer *n, doublecomplex *a, integer *lda, - doublereal *work, ftnlen norm_len, ftnlen uplo_len, - ftnlen diag_len); -extern int zlapll_(integer *n, doublecomplex *x, integer *incx, - doublecomplex *y, integer *incy, doublereal *ssmin); -extern int zlapmt_(logical *forwrd, integer *m, integer *n, doublecomplex *x, - integer *ldx, integer *k); -extern int zlaqgb_(integer *m, integer *n, integer *kl, integer *ku, - doublecomplex *ab, integer *ldab, doublereal *r__, - doublereal *c__, doublereal *rowcnd, doublereal *colcnd, - doublereal *amax, char *equed, ftnlen equed_len); -extern int zlaqge_(integer *m, integer *n, doublecomplex *a, integer *lda, - doublereal *r__, doublereal *c__, doublereal *rowcnd, - doublereal *colcnd, doublereal *amax, char *equed, - ftnlen equed_len); -extern int zlaqhb_(char *uplo, integer *n, integer *kd, doublecomplex *ab, - integer *ldab, doublereal *s, doublereal *scond, - doublereal *amax, char *equed, ftnlen uplo_len, - ftnlen equed_len); -extern int zlaqhe_(char *uplo, integer *n, doublecomplex *a, integer *lda, - doublereal *s, doublereal *scond, doublereal *amax, - char *equed, ftnlen uplo_len, ftnlen equed_len); -extern int zlaqhp_(char *uplo, integer *n, doublecomplex *ap, doublereal *s, - doublereal *scond, doublereal *amax, char *equed, - ftnlen uplo_len, ftnlen equed_len); -extern int zlaqp2_(integer *m, integer *n, integer *offset, doublecomplex *a, - integer *lda, integer *jpvt, doublecomplex *tau, - doublereal *vn1, doublereal *vn2, doublecomplex *work); -extern int zlaqps_(integer *m, integer *n, integer *offset, integer *nb, - integer *kb, doublecomplex *a, integer *lda, integer *jpvt, - doublecomplex *tau, doublereal *vn1, doublereal *vn2, - doublecomplex *auxv, doublecomplex *f, integer *ldf); -extern int zlaqsb_(char *uplo, integer *n, integer *kd, doublecomplex *ab, - integer *ldab, doublereal *s, doublereal *scond, - doublereal *amax, char *equed, ftnlen uplo_len, - ftnlen equed_len); -extern int zlaqsp_(char *uplo, integer *n, doublecomplex *ap, doublereal *s, - doublereal *scond, doublereal *amax, char *equed, - ftnlen uplo_len, ftnlen equed_len); -extern int zlaqsy_(char *uplo, integer *n, doublecomplex *a, integer *lda, - doublereal *s, doublereal *scond, doublereal *amax, - char *equed, ftnlen uplo_len, ftnlen equed_len); -extern int zlar1v_(integer *n, integer *b1, integer *bn, doublereal *sigma, - doublereal *d__, doublereal *l, doublereal *ld, - doublereal *lld, doublereal *gersch, doublecomplex *z__, - doublereal *ztz, doublereal *mingma, integer *r__, - integer *isuppz, doublereal *work); -extern int zlar2v_(integer *n, doublecomplex *x, doublecomplex *y, - doublecomplex *z__, integer *incx, doublereal *c__, - doublecomplex *s, integer *incc); -extern int zlarcm_(integer *m, integer *n, doublereal *a, integer *lda, - doublecomplex *b, integer *ldb, doublecomplex *c__, - integer *ldc, doublereal *rwork); -extern int zlarf_(char *side, integer *m, integer *n, doublecomplex *v, - integer *incv, doublecomplex *tau, doublecomplex *c__, - integer *ldc, doublecomplex *work, ftnlen side_len); -extern int zlarfb_(char *side, char *trans, char *direct, char *storev, - integer *m, integer *n, integer *k, doublecomplex *v, - integer *ldv, doublecomplex *t, integer *ldt, - doublecomplex *c__, integer *ldc, doublecomplex *work, - integer *ldwork, ftnlen side_len, ftnlen trans_len, - ftnlen direct_len, ftnlen storev_len); -extern int zlarfg_(integer *n, doublecomplex *alpha, doublecomplex *x, - integer *incx, doublecomplex *tau); -extern int zlarft_(char *direct, char *storev, integer *n, integer *k, - doublecomplex *v, integer *ldv, doublecomplex *tau, - doublecomplex *t, integer *ldt, ftnlen direct_len, - ftnlen storev_len); -extern int zlarfx_(char *side, integer *m, integer *n, doublecomplex *v, - doublecomplex *tau, doublecomplex *c__, integer *ldc, - doublecomplex *work, ftnlen side_len); -extern int zlargv_(integer *n, doublecomplex *x, integer *incx, - doublecomplex *y, integer *incy, doublereal *c__, - integer *incc); -extern int zlarnv_(integer *idist, integer *iseed, integer *n, - doublecomplex *x); -extern int zlarrv_(integer *n, doublereal *d__, doublereal *l, integer *isplit, - integer *m, doublereal *w, integer *iblock, - doublereal *gersch, doublereal *tol, doublecomplex *z__, - integer *ldz, integer *isuppz, doublereal *work, - integer *iwork, integer *info); -extern int zlartg_(doublecomplex *f, doublecomplex *g, doublereal *cs, - doublecomplex *sn, doublecomplex *r__); -extern int zlartv_(integer *n, doublecomplex *x, integer *incx, - doublecomplex *y, integer *incy, doublereal *c__, - doublecomplex *s, integer *incc); -extern int zlarz_(char *side, integer *m, integer *n, integer *l, - doublecomplex *v, integer *incv, doublecomplex *tau, - doublecomplex *c__, integer *ldc, doublecomplex *work, - ftnlen side_len); -extern int zlarzb_(char *side, char *trans, char *direct, char *storev, - integer *m, integer *n, integer *k, integer *l, - doublecomplex *v, integer *ldv, doublecomplex *t, - integer *ldt, doublecomplex *c__, integer *ldc, - doublecomplex *work, integer *ldwork, ftnlen side_len, - ftnlen trans_len, ftnlen direct_len, ftnlen storev_len); -extern int zlarzt_(char *direct, char *storev, integer *n, integer *k, - doublecomplex *v, integer *ldv, doublecomplex *tau, - doublecomplex *t, integer *ldt, ftnlen direct_len, - ftnlen storev_len); -extern int zlascl_(char *type__, integer *kl, integer *ku, doublereal *cfrom, - doublereal *cto, integer *m, integer *n, doublecomplex *a, - integer *lda, integer *info, ftnlen type_len); -extern int zlaset_(char *uplo, integer *m, integer *n, doublecomplex *alpha, - doublecomplex *beta, doublecomplex *a, integer *lda, - ftnlen uplo_len); -extern int zlasr_(char *side, char *pivot, char *direct, integer *m, integer *n, - doublereal *c__, doublereal *s, doublecomplex *a, - integer *lda, ftnlen side_len, ftnlen pivot_len, - ftnlen direct_len); -extern int zlassq_(integer *n, doublecomplex *x, integer *incx, - doublereal *scale, doublereal *sumsq); -extern int zlaswp_(integer *n, doublecomplex *a, integer *lda, integer *k1, - integer *k2, integer *ipiv, integer *incx); -extern int zlasyf_(char *uplo, integer *n, integer *nb, integer *kb, - doublecomplex *a, integer *lda, integer *ipiv, - doublecomplex *w, integer *ldw, integer *info, - ftnlen uplo_len); -extern int zlatbs_(char *uplo, char *trans, char *diag, char *normin, - integer *n, integer *kd, doublecomplex *ab, integer *ldab, - doublecomplex *x, doublereal *scale, doublereal *cnorm, - integer *info, ftnlen uplo_len, ftnlen trans_len, - ftnlen diag_len, ftnlen normin_len); -extern int zlatdf_(integer *ijob, integer *n, doublecomplex *z__, integer *ldz, - doublecomplex *rhs, doublereal *rdsum, doublereal *rdscal, - integer *ipiv, integer *jpiv); -extern int zlatps_(char *uplo, char *trans, char *diag, char *normin, - integer *n, doublecomplex *ap, doublecomplex *x, - doublereal *scale, doublereal *cnorm, integer *info, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len, - ftnlen normin_len); -extern int zlatrd_(char *uplo, integer *n, integer *nb, doublecomplex *a, - integer *lda, doublereal *e, doublecomplex *tau, - doublecomplex *w, integer *ldw, ftnlen uplo_len); -extern int zlatrs_(char *uplo, char *trans, char *diag, char *normin, - integer *n, doublecomplex *a, integer *lda, doublecomplex *x, - doublereal *scale, doublereal *cnorm, integer *info, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len, - ftnlen normin_len); -extern int zlatrz_(integer *m, integer *n, integer *l, doublecomplex *a, - integer *lda, doublecomplex *tau, doublecomplex *work); -extern int zlatzm_(char *side, integer *m, integer *n, doublecomplex *v, - integer *incv, doublecomplex *tau, doublecomplex *c1, - doublecomplex *c2, integer *ldc, doublecomplex *work, - ftnlen side_len); -extern int zlauu2_(char *uplo, integer *n, doublecomplex *a, integer *lda, - integer *info, ftnlen uplo_len); -extern int zlauum_(char *uplo, integer *n, doublecomplex *a, integer *lda, - integer *info, ftnlen uplo_len); -extern int zpbcon_(char *uplo, integer *n, integer *kd, doublecomplex *ab, - integer *ldab, doublereal *anorm, doublereal *rcond, - doublecomplex *work, doublereal *rwork, integer *info, - ftnlen uplo_len); -extern int zpbequ_(char *uplo, integer *n, integer *kd, doublecomplex *ab, - integer *ldab, doublereal *s, doublereal *scond, - doublereal *amax, integer *info, ftnlen uplo_len); -extern int zpbrfs_(char *uplo, integer *n, integer *kd, integer *nrhs, - doublecomplex *ab, integer *ldab, doublecomplex *afb, - integer *ldafb, doublecomplex *b, integer *ldb, - doublecomplex *x, integer *ldx, doublereal *ferr, - doublereal *berr, doublecomplex *work, doublereal *rwork, - integer *info, ftnlen uplo_len); -extern int zpbstf_(char *uplo, integer *n, integer *kd, doublecomplex *ab, - integer *ldab, integer *info, ftnlen uplo_len); -extern int zpbsv_(char *uplo, integer *n, integer *kd, integer *nrhs, - doublecomplex *ab, integer *ldab, doublecomplex *b, - integer *ldb, integer *info, ftnlen uplo_len); -extern int zpbsvx_(char *fact, char *uplo, integer *n, integer *kd, - integer *nrhs, doublecomplex *ab, integer *ldab, - doublecomplex *afb, integer *ldafb, char *equed, - doublereal *s, doublecomplex *b, integer *ldb, - doublecomplex *x, integer *ldx, doublereal *rcond, - doublereal *ferr, doublereal *berr, doublecomplex *work, - doublereal *rwork, integer *info, ftnlen fact_len, - ftnlen uplo_len, ftnlen equed_len); -extern int zpbtf2_(char *uplo, integer *n, integer *kd, doublecomplex *ab, - integer *ldab, integer *info, ftnlen uplo_len); -extern int zpbtrf_(char *uplo, integer *n, integer *kd, doublecomplex *ab, - integer *ldab, integer *info, ftnlen uplo_len); -extern int zpbtrs_(char *uplo, integer *n, integer *kd, integer *nrhs, - doublecomplex *ab, integer *ldab, doublecomplex *b, - integer *ldb, integer *info, ftnlen uplo_len); -extern int zpocon_(char *uplo, integer *n, doublecomplex *a, integer *lda, - doublereal *anorm, doublereal *rcond, doublecomplex *work, - doublereal *rwork, integer *info, ftnlen uplo_len); -extern int zpoequ_(integer *n, doublecomplex *a, integer *lda, doublereal *s, - doublereal *scond, doublereal *amax, integer *info); -extern int zporfs_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, - integer *lda, doublecomplex *af, integer *ldaf, - doublecomplex *b, integer *ldb, doublecomplex *x, - integer *ldx, doublereal *ferr, doublereal *berr, - doublecomplex *work, doublereal *rwork, integer *info, - ftnlen uplo_len); -extern int zposv_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int zposvx_(char *fact, char *uplo, integer *n, integer *nrhs, - doublecomplex *a, integer *lda, doublecomplex *af, - integer *ldaf, char *equed, doublereal *s, doublecomplex *b, - integer *ldb, doublecomplex *x, integer *ldx, - doublereal *rcond, doublereal *ferr, doublereal *berr, - doublecomplex *work, doublereal *rwork, integer *info, - ftnlen fact_len, ftnlen uplo_len, ftnlen equed_len); -extern int zpotf2_(char *uplo, integer *n, doublecomplex *a, integer *lda, - integer *info, ftnlen uplo_len); -extern int zpotrf_(char *uplo, integer *n, doublecomplex *a, integer *lda, - integer *info, ftnlen uplo_len); -extern int zpotri_(char *uplo, integer *n, doublecomplex *a, integer *lda, - integer *info, ftnlen uplo_len); -extern int zpotrs_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int zppcon_(char *uplo, integer *n, doublecomplex *ap, doublereal *anorm, - doublereal *rcond, doublecomplex *work, doublereal *rwork, - integer *info, ftnlen uplo_len); -extern int zppequ_(char *uplo, integer *n, doublecomplex *ap, doublereal *s, - doublereal *scond, doublereal *amax, integer *info, - ftnlen uplo_len); -extern int zpprfs_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, - doublecomplex *afp, doublecomplex *b, integer *ldb, - doublecomplex *x, integer *ldx, doublereal *ferr, - doublereal *berr, doublecomplex *work, doublereal *rwork, - integer *info, ftnlen uplo_len); -extern int zppsv_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, - doublecomplex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int zppsvx_(char *fact, char *uplo, integer *n, integer *nrhs, - doublecomplex *ap, doublecomplex *afp, char *equed, - doublereal *s, doublecomplex *b, integer *ldb, - doublecomplex *x, integer *ldx, doublereal *rcond, - doublereal *ferr, doublereal *berr, doublecomplex *work, - doublereal *rwork, integer *info, ftnlen fact_len, - ftnlen uplo_len, ftnlen equed_len); -extern int zpptrf_(char *uplo, integer *n, doublecomplex *ap, integer *info, - ftnlen uplo_len); -extern int zpptri_(char *uplo, integer *n, doublecomplex *ap, integer *info, - ftnlen uplo_len); -extern int zpptrs_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, - doublecomplex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int zptcon_(integer *n, doublereal *d__, doublecomplex *e, - doublereal *anorm, doublereal *rcond, doublereal *rwork, - integer *info); -extern int zpteqr_(char *compz, integer *n, doublereal *d__, doublereal *e, - doublecomplex *z__, integer *ldz, doublereal *work, - integer *info, ftnlen compz_len); -extern int zptrfs_(char *uplo, integer *n, integer *nrhs, doublereal *d__, - doublecomplex *e, doublereal *df, doublecomplex *ef, - doublecomplex *b, integer *ldb, doublecomplex *x, - integer *ldx, doublereal *ferr, doublereal *berr, - doublecomplex *work, doublereal *rwork, integer *info, - ftnlen uplo_len); -extern int zptsv_(integer *n, integer *nrhs, doublereal *d__, doublecomplex *e, - doublecomplex *b, integer *ldb, integer *info); -extern int zptsvx_(char *fact, integer *n, integer *nrhs, doublereal *d__, - doublecomplex *e, doublereal *df, doublecomplex *ef, - doublecomplex *b, integer *ldb, doublecomplex *x, - integer *ldx, doublereal *rcond, doublereal *ferr, - doublereal *berr, doublecomplex *work, doublereal *rwork, - integer *info, ftnlen fact_len); -extern int zpttrf_(integer *n, doublereal *d__, doublecomplex *e, - integer *info); -extern int zpttrs_(char *uplo, integer *n, integer *nrhs, doublereal *d__, - doublecomplex *e, doublecomplex *b, integer *ldb, - integer *info, ftnlen uplo_len); -extern int zptts2_(integer *iuplo, integer *n, integer *nrhs, doublereal *d__, - doublecomplex *e, doublecomplex *b, integer *ldb); -extern int zrot_(integer *n, doublecomplex *cx, integer *incx, - doublecomplex *cy, integer *incy, doublereal *c__, - doublecomplex *s); -extern int zspcon_(char *uplo, integer *n, doublecomplex *ap, integer *ipiv, - doublereal *anorm, doublereal *rcond, doublecomplex *work, - integer *info, ftnlen uplo_len); -extern int zspmv_(char *uplo, integer *n, doublecomplex *alpha, - doublecomplex *ap, doublecomplex *x, integer *incx, - doublecomplex *beta, doublecomplex *y, integer *incy, - ftnlen uplo_len); -extern int zspr_(char *uplo, integer *n, doublecomplex *alpha, doublecomplex *x, - integer *incx, doublecomplex *ap, ftnlen uplo_len); -extern int zsprfs_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, - doublecomplex *afp, integer *ipiv, doublecomplex *b, - integer *ldb, doublecomplex *x, integer *ldx, - doublereal *ferr, doublereal *berr, doublecomplex *work, - doublereal *rwork, integer *info, ftnlen uplo_len); -extern int zspsv_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, - integer *ipiv, doublecomplex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int zspsvx_(char *fact, char *uplo, integer *n, integer *nrhs, - doublecomplex *ap, doublecomplex *afp, integer *ipiv, - doublecomplex *b, integer *ldb, doublecomplex *x, - integer *ldx, doublereal *rcond, doublereal *ferr, - doublereal *berr, doublecomplex *work, doublereal *rwork, - integer *info, ftnlen fact_len, ftnlen uplo_len); -extern int zsptrf_(char *uplo, integer *n, doublecomplex *ap, integer *ipiv, - integer *info, ftnlen uplo_len); -extern int zsptri_(char *uplo, integer *n, doublecomplex *ap, integer *ipiv, - doublecomplex *work, integer *info, ftnlen uplo_len); -extern int zsptrs_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, - integer *ipiv, doublecomplex *b, integer *ldb, integer *info, - ftnlen uplo_len); -extern int zstedc_(char *compz, integer *n, doublereal *d__, doublereal *e, - doublecomplex *z__, integer *ldz, doublecomplex *work, - integer *lwork, doublereal *rwork, integer *lrwork, - integer *iwork, integer *liwork, integer *info, - ftnlen compz_len); -extern int zstegr_(char *jobz, char *range, integer *n, doublereal *d__, - doublereal *e, doublereal *vl, doublereal *vu, integer *il, - integer *iu, doublereal *abstol, integer *m, doublereal *w, - doublecomplex *z__, integer *ldz, integer *isuppz, - doublereal *work, integer *lwork, integer *iwork, - integer *liwork, integer *info, ftnlen jobz_len, - ftnlen range_len); -extern int zstein_(integer *n, doublereal *d__, doublereal *e, integer *m, - doublereal *w, integer *iblock, integer *isplit, - doublecomplex *z__, integer *ldz, doublereal *work, - integer *iwork, integer *ifail, integer *info); -extern int zsteqr_(char *compz, integer *n, doublereal *d__, doublereal *e, - doublecomplex *z__, integer *ldz, doublereal *work, - integer *info, ftnlen compz_len); -extern int zsycon_(char *uplo, integer *n, doublecomplex *a, integer *lda, - integer *ipiv, doublereal *anorm, doublereal *rcond, - doublecomplex *work, integer *info, ftnlen uplo_len); -extern int zsymv_(char *uplo, integer *n, doublecomplex *alpha, - doublecomplex *a, integer *lda, doublecomplex *x, - integer *incx, doublecomplex *beta, doublecomplex *y, - integer *incy, ftnlen uplo_len); -extern int zsyr_(char *uplo, integer *n, doublecomplex *alpha, doublecomplex *x, - integer *incx, doublecomplex *a, integer *lda, - ftnlen uplo_len); -extern int zsyrfs_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, - integer *lda, doublecomplex *af, integer *ldaf, - integer *ipiv, doublecomplex *b, integer *ldb, - doublecomplex *x, integer *ldx, doublereal *ferr, - doublereal *berr, doublecomplex *work, doublereal *rwork, - integer *info, ftnlen uplo_len); -extern int zsysv_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, - integer *lda, integer *ipiv, doublecomplex *b, integer *ldb, - doublecomplex *work, integer *lwork, integer *info, - ftnlen uplo_len); -extern int zsysvx_(char *fact, char *uplo, integer *n, integer *nrhs, - doublecomplex *a, integer *lda, doublecomplex *af, - integer *ldaf, integer *ipiv, doublecomplex *b, integer *ldb, - doublecomplex *x, integer *ldx, doublereal *rcond, - doublereal *ferr, doublereal *berr, doublecomplex *work, - integer *lwork, doublereal *rwork, integer *info, - ftnlen fact_len, ftnlen uplo_len); -extern int zsytf2_(char *uplo, integer *n, doublecomplex *a, integer *lda, - integer *ipiv, integer *info, ftnlen uplo_len); -extern int zsytrf_(char *uplo, integer *n, doublecomplex *a, integer *lda, - integer *ipiv, doublecomplex *work, integer *lwork, - integer *info, ftnlen uplo_len); -extern int zsytri_(char *uplo, integer *n, doublecomplex *a, integer *lda, - integer *ipiv, doublecomplex *work, integer *info, - ftnlen uplo_len); -extern int zsytrs_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, - integer *lda, integer *ipiv, doublecomplex *b, integer *ldb, - integer *info, ftnlen uplo_len); -extern int ztbcon_(char *norm, char *uplo, char *diag, integer *n, integer *kd, - doublecomplex *ab, integer *ldab, doublereal *rcond, - doublecomplex *work, doublereal *rwork, integer *info, - ftnlen norm_len, ftnlen uplo_len, ftnlen diag_len); -extern int ztbrfs_(char *uplo, char *trans, char *diag, integer *n, integer *kd, - integer *nrhs, doublecomplex *ab, integer *ldab, - doublecomplex *b, integer *ldb, doublecomplex *x, - integer *ldx, doublereal *ferr, doublereal *berr, - doublecomplex *work, doublereal *rwork, integer *info, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len); -extern int ztbtrs_(char *uplo, char *trans, char *diag, integer *n, integer *kd, - integer *nrhs, doublecomplex *ab, integer *ldab, - doublecomplex *b, integer *ldb, integer *info, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len); -extern int ztgevc_(char *side, char *howmny, logical *select, integer *n, - doublecomplex *a, integer *lda, doublecomplex *b, - integer *ldb, doublecomplex *vl, integer *ldvl, - doublecomplex *vr, integer *ldvr, integer *mm, integer *m, - doublecomplex *work, doublereal *rwork, integer *info, - ftnlen side_len, ftnlen howmny_len); -extern int ztgex2_(logical *wantq, logical *wantz, integer *n, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, - doublecomplex *q, integer *ldq, doublecomplex *z__, - integer *ldz, integer *j1, integer *info); -extern int ztgexc_(logical *wantq, logical *wantz, integer *n, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, - doublecomplex *q, integer *ldq, doublecomplex *z__, - integer *ldz, integer *ifst, integer *ilst, integer *info); -extern int ztgsen_(integer *ijob, logical *wantq, logical *wantz, - logical *select, integer *n, doublecomplex *a, integer *lda, - doublecomplex *b, integer *ldb, doublecomplex *alpha, - doublecomplex *beta, doublecomplex *q, integer *ldq, - doublecomplex *z__, integer *ldz, integer *m, doublereal *pl, - doublereal *pr, doublereal *dif, doublecomplex *work, - integer *lwork, integer *iwork, integer *liwork, - integer *info); -extern int ztgsja_(char *jobu, char *jobv, char *jobq, integer *m, integer *p, - integer *n, integer *k, integer *l, doublecomplex *a, - integer *lda, doublecomplex *b, integer *ldb, - doublereal *tola, doublereal *tolb, doublereal *alpha, - doublereal *beta, doublecomplex *u, integer *ldu, - doublecomplex *v, integer *ldv, doublecomplex *q, - integer *ldq, doublecomplex *work, integer *ncycle, - integer *info, ftnlen jobu_len, ftnlen jobv_len, - ftnlen jobq_len); -extern int ztgsna_(char *job, char *howmny, logical *select, integer *n, - doublecomplex *a, integer *lda, doublecomplex *b, - integer *ldb, doublecomplex *vl, integer *ldvl, - doublecomplex *vr, integer *ldvr, doublereal *s, - doublereal *dif, integer *mm, integer *m, - doublecomplex *work, integer *lwork, integer *iwork, - integer *info, ftnlen job_len, ftnlen howmny_len); -extern int ztgsy2_(char *trans, integer *ijob, integer *m, integer *n, - doublecomplex *a, integer *lda, doublecomplex *b, - integer *ldb, doublecomplex *c__, integer *ldc, - doublecomplex *d__, integer *ldd, doublecomplex *e, - integer *lde, doublecomplex *f, integer *ldf, - doublereal *scale, doublereal *rdsum, doublereal *rdscal, - integer *info, ftnlen trans_len); -extern int ztgsyl_(char *trans, integer *ijob, integer *m, integer *n, - doublecomplex *a, integer *lda, doublecomplex *b, - integer *ldb, doublecomplex *c__, integer *ldc, - doublecomplex *d__, integer *ldd, doublecomplex *e, - integer *lde, doublecomplex *f, integer *ldf, - doublereal *scale, doublereal *dif, doublecomplex *work, - integer *lwork, integer *iwork, integer *info, - ftnlen trans_len); -extern int ztpcon_(char *norm, char *uplo, char *diag, integer *n, - doublecomplex *ap, doublereal *rcond, doublecomplex *work, - doublereal *rwork, integer *info, ftnlen norm_len, - ftnlen uplo_len, ftnlen diag_len); -extern int ztprfs_(char *uplo, char *trans, char *diag, integer *n, - integer *nrhs, doublecomplex *ap, doublecomplex *b, - integer *ldb, doublecomplex *x, integer *ldx, - doublereal *ferr, doublereal *berr, doublecomplex *work, - doublereal *rwork, integer *info, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern int ztptri_(char *uplo, char *diag, integer *n, doublecomplex *ap, - integer *info, ftnlen uplo_len, ftnlen diag_len); -extern int ztptrs_(char *uplo, char *trans, char *diag, integer *n, - integer *nrhs, doublecomplex *ap, doublecomplex *b, - integer *ldb, integer *info, ftnlen uplo_len, - ftnlen trans_len, ftnlen diag_len); -extern int ztrcon_(char *norm, char *uplo, char *diag, integer *n, - doublecomplex *a, integer *lda, doublereal *rcond, - doublecomplex *work, doublereal *rwork, integer *info, - ftnlen norm_len, ftnlen uplo_len, ftnlen diag_len); -extern int ztrevc_(char *side, char *howmny, logical *select, integer *n, - doublecomplex *t, integer *ldt, doublecomplex *vl, - integer *ldvl, doublecomplex *vr, integer *ldvr, integer *mm, - integer *m, doublecomplex *work, doublereal *rwork, - integer *info, ftnlen side_len, ftnlen howmny_len); -extern int ztrexc_(char *compq, integer *n, doublecomplex *t, integer *ldt, - doublecomplex *q, integer *ldq, integer *ifst, integer *ilst, - integer *info, ftnlen compq_len); -extern int ztrrfs_(char *uplo, char *trans, char *diag, integer *n, - integer *nrhs, doublecomplex *a, integer *lda, - doublecomplex *b, integer *ldb, doublecomplex *x, - integer *ldx, doublereal *ferr, doublereal *berr, - doublecomplex *work, doublereal *rwork, integer *info, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len); -extern int ztrsen_(char *job, char *compq, logical *select, integer *n, - doublecomplex *t, integer *ldt, doublecomplex *q, - integer *ldq, doublecomplex *w, integer *m, doublereal *s, - doublereal *sep, doublecomplex *work, integer *lwork, - integer *info, ftnlen job_len, ftnlen compq_len); -extern int ztrsna_(char *job, char *howmny, logical *select, integer *n, - doublecomplex *t, integer *ldt, doublecomplex *vl, - integer *ldvl, doublecomplex *vr, integer *ldvr, - doublereal *s, doublereal *sep, integer *mm, integer *m, - doublecomplex *work, integer *ldwork, doublereal *rwork, - integer *info, ftnlen job_len, ftnlen howmny_len); -extern int ztrsyl_(char *trana, char *tranb, integer *isgn, integer *m, - integer *n, doublecomplex *a, integer *lda, doublecomplex *b, - integer *ldb, doublecomplex *c__, integer *ldc, - doublereal *scale, integer *info, ftnlen trana_len, - ftnlen tranb_len); -extern int ztrti2_(char *uplo, char *diag, integer *n, doublecomplex *a, - integer *lda, integer *info, ftnlen uplo_len, - ftnlen diag_len); -extern int ztrtri_(char *uplo, char *diag, integer *n, doublecomplex *a, - integer *lda, integer *info, ftnlen uplo_len, - ftnlen diag_len); -extern int ztrtrs_(char *uplo, char *trans, char *diag, integer *n, - integer *nrhs, doublecomplex *a, integer *lda, - doublecomplex *b, integer *ldb, integer *info, - ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len); -extern int ztzrqf_(integer *m, integer *n, doublecomplex *a, integer *lda, - doublecomplex *tau, integer *info); -extern int ztzrzf_(integer *m, integer *n, doublecomplex *a, integer *lda, - doublecomplex *tau, doublecomplex *work, integer *lwork, - integer *info); -extern int zung2l_(integer *m, integer *n, integer *k, doublecomplex *a, - integer *lda, doublecomplex *tau, doublecomplex *work, - integer *info); -extern int zung2r_(integer *m, integer *n, integer *k, doublecomplex *a, - integer *lda, doublecomplex *tau, doublecomplex *work, - integer *info); -extern int zungbr_(char *vect, integer *m, integer *n, integer *k, - doublecomplex *a, integer *lda, doublecomplex *tau, - doublecomplex *work, integer *lwork, integer *info, - ftnlen vect_len); -extern int zunghr_(integer *n, integer *ilo, integer *ihi, doublecomplex *a, - integer *lda, doublecomplex *tau, doublecomplex *work, - integer *lwork, integer *info); -extern int zungl2_(integer *m, integer *n, integer *k, doublecomplex *a, - integer *lda, doublecomplex *tau, doublecomplex *work, - integer *info); -extern int zunglq_(integer *m, integer *n, integer *k, doublecomplex *a, - integer *lda, doublecomplex *tau, doublecomplex *work, - integer *lwork, integer *info); -extern int zungql_(integer *m, integer *n, integer *k, doublecomplex *a, - integer *lda, doublecomplex *tau, doublecomplex *work, - integer *lwork, integer *info); -extern int zungqr_(integer *m, integer *n, integer *k, doublecomplex *a, - integer *lda, doublecomplex *tau, doublecomplex *work, - integer *lwork, integer *info); -extern int zungr2_(integer *m, integer *n, integer *k, doublecomplex *a, - integer *lda, doublecomplex *tau, doublecomplex *work, - integer *info); -extern int zungrq_(integer *m, integer *n, integer *k, doublecomplex *a, - integer *lda, doublecomplex *tau, doublecomplex *work, - integer *lwork, integer *info); -extern int zungtr_(char *uplo, integer *n, doublecomplex *a, integer *lda, - doublecomplex *tau, doublecomplex *work, integer *lwork, - integer *info, ftnlen uplo_len); -extern int zunm2l_(char *side, char *trans, integer *m, integer *n, integer *k, - doublecomplex *a, integer *lda, doublecomplex *tau, - doublecomplex *c__, integer *ldc, doublecomplex *work, - integer *info, ftnlen side_len, ftnlen trans_len); -extern int zunm2r_(char *side, char *trans, integer *m, integer *n, integer *k, - doublecomplex *a, integer *lda, doublecomplex *tau, - doublecomplex *c__, integer *ldc, doublecomplex *work, - integer *info, ftnlen side_len, ftnlen trans_len); -extern int zunmbr_(char *vect, char *side, char *trans, integer *m, integer *n, - integer *k, doublecomplex *a, integer *lda, - doublecomplex *tau, doublecomplex *c__, integer *ldc, - doublecomplex *work, integer *lwork, integer *info, - ftnlen vect_len, ftnlen side_len, ftnlen trans_len); -extern int zunmhr_(char *side, char *trans, integer *m, integer *n, - integer *ilo, integer *ihi, doublecomplex *a, integer *lda, - doublecomplex *tau, doublecomplex *c__, integer *ldc, - doublecomplex *work, integer *lwork, integer *info, - ftnlen side_len, ftnlen trans_len); -extern int zunml2_(char *side, char *trans, integer *m, integer *n, integer *k, - doublecomplex *a, integer *lda, doublecomplex *tau, - doublecomplex *c__, integer *ldc, doublecomplex *work, - integer *info, ftnlen side_len, ftnlen trans_len); -extern int zunmlq_(char *side, char *trans, integer *m, integer *n, integer *k, - doublecomplex *a, integer *lda, doublecomplex *tau, - doublecomplex *c__, integer *ldc, doublecomplex *work, - integer *lwork, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int zunmql_(char *side, char *trans, integer *m, integer *n, integer *k, - doublecomplex *a, integer *lda, doublecomplex *tau, - doublecomplex *c__, integer *ldc, doublecomplex *work, - integer *lwork, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int zunmqr_(char *side, char *trans, integer *m, integer *n, integer *k, - doublecomplex *a, integer *lda, doublecomplex *tau, - doublecomplex *c__, integer *ldc, doublecomplex *work, - integer *lwork, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int zunmr2_(char *side, char *trans, integer *m, integer *n, integer *k, - doublecomplex *a, integer *lda, doublecomplex *tau, - doublecomplex *c__, integer *ldc, doublecomplex *work, - integer *info, ftnlen side_len, ftnlen trans_len); -extern int zunmr3_(char *side, char *trans, integer *m, integer *n, integer *k, - integer *l, doublecomplex *a, integer *lda, - doublecomplex *tau, doublecomplex *c__, integer *ldc, - doublecomplex *work, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int zunmrq_(char *side, char *trans, integer *m, integer *n, integer *k, - doublecomplex *a, integer *lda, doublecomplex *tau, - doublecomplex *c__, integer *ldc, doublecomplex *work, - integer *lwork, integer *info, ftnlen side_len, - ftnlen trans_len); -extern int zunmrz_(char *side, char *trans, integer *m, integer *n, integer *k, - integer *l, doublecomplex *a, integer *lda, - doublecomplex *tau, doublecomplex *c__, integer *ldc, - doublecomplex *work, integer *lwork, integer *info, - ftnlen side_len, ftnlen trans_len); -extern int zunmtr_(char *side, char *uplo, char *trans, integer *m, integer *n, - doublecomplex *a, integer *lda, doublecomplex *tau, - doublecomplex *c__, integer *ldc, doublecomplex *work, - integer *lwork, integer *info, ftnlen side_len, - ftnlen uplo_len, ftnlen trans_len); -extern int zupgtr_(char *uplo, integer *n, doublecomplex *ap, - doublecomplex *tau, doublecomplex *q, integer *ldq, - doublecomplex *work, integer *info, ftnlen uplo_len); -extern int zupmtr_(char *side, char *uplo, char *trans, integer *m, integer *n, - doublecomplex *ap, doublecomplex *tau, doublecomplex *c__, - integer *ldc, doublecomplex *work, integer *info, - ftnlen side_len, ftnlen uplo_len, ftnlen trans_len); - -#endif diff --git a/lib/gmath/ATLAS_wrapper_blas_level_1.c b/lib/gmath/ATLAS_wrapper_blas_level_1.c index 24390a61dfb..556f1654b46 100644 --- a/lib/gmath/ATLAS_wrapper_blas_level_1.c +++ b/lib/gmath/ATLAS_wrapper_blas_level_1.c @@ -21,15 +21,19 @@ #include #include -#if defined(HAVE_ATLAS) +#if defined(HAVE_LIBBLAS) +#if defined(HAVE_CBLAS_ATLAS_H) +#include +#else #include #endif +#endif /* HAVE_LIBBLAS */ /*! * \brief Compute the dot product of vector x and y - * using the ATLAS routine cblas_ddot + * using the CBLAS routine cblas_ddot * - * If grass was not compiled with ATLAS support + * If grass was not compiled with CBLAS support * it will call #G_math_f_x_dot_y, the OpenMP multi threaded * grass implementatiom * @@ -41,7 +45,7 @@ * */ double G_math_ddot(double *x, double *y, int rows) { -#if defined(HAVE_ATLAS) +#if defined(HAVE_LIBBLAS) return cblas_ddot(rows, x, 1, y, 1); #else double val; @@ -53,9 +57,9 @@ double G_math_ddot(double *x, double *y, int rows) /*! * \brief Compute the dot product of vector x and y - * using the ATLAS routine cblas_sdsdot + * using the CBLAS routine cblas_sdsdot * - * If grass was not compiled with ATLAS support + * If grass was not compiled with CBLAS support * it will call #G_math_f_x_dot_y, the OpenMP multi threaded * grass implementatiom * @@ -68,7 +72,7 @@ double G_math_ddot(double *x, double *y, int rows) * */ float G_math_sdsdot(float *x, float *y, float a, int rows) { -#if defined(HAVE_ATLAS) +#if defined(HAVE_LIBBLAS) return cblas_sdsdot(rows, a, x, 1, y, 1); #else float val; @@ -80,9 +84,9 @@ float G_math_sdsdot(float *x, float *y, float a, int rows) /*! * \brief Compute the euclidean norm of vector x - * using the ATLAS routine cblas_dnrm2 + * using the CBLAS routine cblas_dnrm2 * - * If grass was not compiled with ATLAS support + * If grass was not compiled with CBLAS support * it will call #G_math_d_euclid_norm, the OpenMP multi threaded * grass implementatiom * @@ -93,7 +97,7 @@ float G_math_sdsdot(float *x, float *y, float a, int rows) * */ double G_math_dnrm2(double *x, int rows) { -#if defined(HAVE_ATLAS) +#if defined(HAVE_LIBBLAS) return cblas_dnrm2(rows, x, 1); #else double val; @@ -105,9 +109,9 @@ double G_math_dnrm2(double *x, int rows) /*! * \brief Compute the absolute sum norm of vector x - * using the ATLAS routine cblas_dasum + * using the CBLAS routine cblas_dasum * - * If grass was not compiled with ATLAS support + * If grass was not compiled with CBLAS support * it will call #G_math_d_asum_norm, the OpenMP multi threaded * grass implementatiom * @@ -118,7 +122,7 @@ double G_math_dnrm2(double *x, int rows) * */ double G_math_dasum(double *x, int rows) { -#if defined(HAVE_ATLAS) +#if defined(HAVE_LIBBLAS) return cblas_dasum(rows, x, 1); #else double val; @@ -130,9 +134,9 @@ double G_math_dasum(double *x, int rows) /*! * \brief Compute the maximum norm of vector x - * using the ATLAS routine cblas_idamax + * using the CBLAS routine cblas_idamax * - * If grass was not compiled with ATLAS support + * If grass was not compiled with CBLAS support * it will call #G_math_d_max_norm, the OpenMP multi threaded * grass implementatiom * @@ -143,7 +147,7 @@ double G_math_dasum(double *x, int rows) * */ double G_math_idamax(double *x, int rows) { -#if defined(HAVE_ATLAS) +#if defined(HAVE_LIBBLAS) return cblas_idamax(rows, x, 1); #else double val; @@ -155,9 +159,9 @@ double G_math_idamax(double *x, int rows) /*! * \brief Scale vector x with scalar a - * using the ATLAS routine cblas_dscal + * using the CBLAS routine cblas_dscal * - * If grass was not compiled with ATLAS support + * If grass was not compiled with CBLAS support * it will call #G_math_d_ax_by, the OpenMP multi threaded * grass implementatiom * @@ -169,7 +173,7 @@ double G_math_idamax(double *x, int rows) * */ void G_math_dscal(double *x, double a, int rows) { -#if defined(HAVE_ATLAS) +#if defined(HAVE_LIBBLAS) cblas_dscal(rows, a, x, 1); #else G_math_d_ax_by(x, x, x, a, 0.0, rows); @@ -181,7 +185,7 @@ void G_math_dscal(double *x, double a, int rows) /*! * \brief Copy vector x to vector y * - * If grass was not compiled with ATLAS support + * If grass was not compiled with CBLAS support * it will call #G_math_d_copy * * \param x (double *) @@ -192,7 +196,7 @@ void G_math_dscal(double *x, double a, int rows) * */ void G_math_dcopy(double *x, double *y, int rows) { -#if defined(HAVE_ATLAS) +#if defined(HAVE_LIBBLAS) cblas_dcopy(rows, x, 1, y, 1); #else G_math_d_copy(x, y, rows); @@ -206,7 +210,7 @@ void G_math_dcopy(double *x, double *y, int rows) * * \f[ {\bf z} = a{\bf x} + {\bf y} \f] * - * If grass was not compiled with ATLAS support + * If grass was not compiled with CBLAS support * it will call #G_math_d_ax_by, the * grass implementatiom @@ -220,7 +224,7 @@ void G_math_dcopy(double *x, double *y, int rows) * */ void G_math_daxpy(double *x, double *y, double a, int rows) { -#if defined(HAVE_ATLAS) +#if defined(HAVE_LIBBLAS) cblas_daxpy(rows, a, x, 1, y, 1); #else G_math_d_ax_by(x, y, y, a, 1.0, rows); @@ -231,15 +235,15 @@ void G_math_daxpy(double *x, double *y, double a, int rows) /****************************************************************** */ -/********* F L O A T / S I N G L E P E P R E C I S I O N ******** */ +/********* F L O A T / S I N G L E P R E C I S I O N ********* */ /****************************************************************** */ /*! * \brief Compute the dot product of vector x and y - * using the ATLAS routine cblas_sdot + * using the CBLAS routine cblas_sdot * - * If grass was not compiled with ATLAS support + * If grass was not compiled with CBLAS support * it will call #G_math_f_x_dot_y, the OpenMP multi threaded * grass implementatiom * @@ -251,7 +255,7 @@ void G_math_daxpy(double *x, double *y, double a, int rows) * */ float G_math_sdot(float *x, float *y, int rows) { -#if defined(HAVE_ATLAS) +#if defined(HAVE_LIBBLAS) return cblas_sdot(rows, x, 1, y, 1); #else float val; @@ -263,9 +267,9 @@ float G_math_sdot(float *x, float *y, int rows) /*! * \brief Compute the euclidean norm of vector x - * using the ATLAS routine cblas_dnrm2 + * using the CBLAS routine cblas_dnrm2 * - * If grass was not compiled with ATLAS support + * If grass was not compiled with CBLAS support * it will call #G_math_f_euclid_norm, the OpenMP multi threaded * grass implementatiom * @@ -276,7 +280,7 @@ float G_math_sdot(float *x, float *y, int rows) * */ float G_math_snrm2(float *x, int rows) { -#if defined(HAVE_ATLAS) +#if defined(HAVE_LIBBLAS) return cblas_snrm2(rows, x, 1); #else float val; @@ -288,9 +292,9 @@ float G_math_snrm2(float *x, int rows) /*! * \brief Compute the absolute sum norm of vector x - * using the ATLAS routine cblas_dasum + * using the CBLAS routine cblas_dasum * - * If grass was not compiled with ATLAS support + * If grass was not compiled with CBLAS support * it will call #G_math_f_asum_norm, the OpenMP multi threaded * grass implementatiom * @@ -301,7 +305,7 @@ float G_math_snrm2(float *x, int rows) * */ float G_math_sasum(float *x, int rows) { -#if defined(HAVE_ATLAS) +#if defined(HAVE_LIBBLAS) return cblas_sasum(rows, x, 1); #else float val; @@ -313,9 +317,9 @@ float G_math_sasum(float *x, int rows) /*! * \brief Compute the maximum norm of vector x - * using the ATLAS routine cblas_idamax + * using the CBLAS routine cblas_idamax * - * If grass was not compiled with ATLAS support + * If grass was not compiled with CBLAS support * it will call #G_math_f_max_norm, the OpenMP multi threaded * grass implementatiom * @@ -326,7 +330,7 @@ float G_math_sasum(float *x, int rows) * */ float G_math_isamax(float *x, int rows) { -#if defined(HAVE_ATLAS) +#if defined(HAVE_LIBBLAS) return cblas_isamax(rows, x, 1); #else float val; @@ -338,9 +342,9 @@ float G_math_isamax(float *x, int rows) /*! * \brief Scale vector x with scalar a - * using the ATLAS routine cblas_dscal + * using the CBLAS routine cblas_dscal * - * If grass was not compiled with ATLAS support + * If grass was not compiled with CBLAS support * it will call #G_math_f_ax_by, the OpenMP multi threaded * grass implementatiom * @@ -352,7 +356,7 @@ float G_math_isamax(float *x, int rows) * */ void G_math_sscal(float *x, float a, int rows) { -#if defined(HAVE_ATLAS) +#if defined(HAVE_LIBBLAS) cblas_sscal(rows, a, x, 1); #else G_math_f_ax_by(x, x, x, a, 0.0, rows); @@ -364,7 +368,7 @@ void G_math_sscal(float *x, float a, int rows) /*! * \brief Copy vector x to vector y * - * If grass was not compiled with ATLAS support + * If grass was not compiled with CBLAS support * it will call #G_math_f_copy, the * grass implementatiom * @@ -376,7 +380,7 @@ void G_math_sscal(float *x, float a, int rows) * */ void G_math_scopy(float *x, float *y, int rows) { -#if defined(HAVE_ATLAS) +#if defined(HAVE_LIBBLAS) cblas_scopy(rows, x, 1, y, 1); #else G_math_f_copy(x, y, rows); @@ -390,7 +394,7 @@ void G_math_scopy(float *x, float *y, int rows) * * \f[ {\bf z} = a{\bf x} + {\bf y} \f] * - * If grass was not compiled with ATLAS support + * If grass was not compiled with CBLAS support * it will call #G_math_f_ax_by, the * grass implementatiom @@ -404,7 +408,7 @@ void G_math_scopy(float *x, float *y, int rows) * */ void G_math_saxpy(float *x, float *y, float a, int rows) { -#if defined(HAVE_ATLAS) +#if defined(HAVE_LIBBLAS) cblas_saxpy(rows, a, x, 1, y, 1); #else G_math_f_ax_by(x, y, y, a, 1.0, rows); diff --git a/lib/gmath/Makefile b/lib/gmath/Makefile index 0fd6e14f55d..2927d32dec6 100644 --- a/lib/gmath/Makefile +++ b/lib/gmath/Makefile @@ -1,7 +1,7 @@ MODULE_TOPDIR = ../.. EXTRA_LIBS = $(OPENMP_LIBPATH) $(OPENMP_LIB) -EXTRA_INC = $(OPENMP_INCPATH) +EXTRA_INC = $(OPENMP_INCPATH) $(BLASINC) $(LAPACKINC) EXTRA_CFLAGS = $(FFTWINC) $(OPENMP_CFLAGS) LIB = GMATH diff --git a/lib/gmath/la.c b/lib/gmath/la.c index 5c0e59cb862..48a4cbc7817 100644 --- a/lib/gmath/la.c +++ b/lib/gmath/la.c @@ -22,19 +22,25 @@ ******************************************************************************/ -#include /* needed here for ifdef/else */ -#include -#include -#include - #include - -#if defined(HAVE_LIBLAPACK) && defined(HAVE_LIBBLAS) - #include #include #include +#if defined(HAVE_LIBLAPACK) && defined(HAVE_LIBBLAS) +#include +#if defined(HAVE_CBLAS_ATLAS_H) +#include +#else +#include +#endif +#endif + +#include +#include +#include +#include + static int egcmp(const void *pa, const void *pb); /*! @@ -66,7 +72,7 @@ mat_struct *G_matrix_init(int rows, int cols, int ldim) tmp_arry->type = MATRIX_; tmp_arry->v_indx = -1; - tmp_arry->vals = (doublereal *)G_calloc(ldim * cols, sizeof(doublereal)); + tmp_arry->vals = (double *)G_calloc(ldim * cols, sizeof(double)); tmp_arry->is_init = 1; return tmp_arry; @@ -86,7 +92,7 @@ int G_matrix_zero(mat_struct *A) if (!A->vals) return 0; - memset(A->vals, 0, (A->ldim * A->cols) * sizeof(doublereal)); + memset(A->vals, 0, (A->ldim * A->cols) * sizeof(double)); return 1; } @@ -119,7 +125,7 @@ int G_matrix_set(mat_struct *A, int rows, int cols, int ldim) A->type = MATRIX_; A->v_indx = -1; - A->vals = (doublereal *)G_calloc(ldim * cols, sizeof(doublereal)); + A->vals = (double *)G_calloc(ldim * cols, sizeof(double)); A->is_init = 1; return 0; @@ -150,7 +156,8 @@ mat_struct *G_matrix_copy(const mat_struct *A) return NULL; } - memcpy(&B->vals[0], &A->vals[0], A->cols * A->ldim * sizeof(doublereal)); + memcpy(&B->vals[0], &A->vals[0], + (size_t)A->cols * A->ldim * sizeof(double)); return B; } @@ -225,7 +232,7 @@ mat_struct *G_matrix_scalar_mul(double scalar, mat_struct *matrix, for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { - doublereal value = scalar * G_matrix_get_element(matrix, i, j); + double value = scalar * G_matrix_get_element(matrix, i, j); G_matrix_set_element(out, i, j, value); } @@ -346,9 +353,8 @@ mat_struct *G__matrix_add(mat_struct *mt1, mat_struct *mt2, const double c1, mat_struct *G_matrix_product(mat_struct *mt1, mat_struct *mt2) { mat_struct *mt3; - doublereal unity = 1, zero = 0; - integer rows, cols, interdim, lda, ldb; - integer1 no_trans = 'n'; + double unity = 1., zero = 0.; + int rows, cols, interdim, lda, ldb; if (!((mt1->is_init) || (mt2->is_init))) { G_warning(_("One or both input matrices uninitialised")); @@ -367,21 +373,19 @@ mat_struct *G_matrix_product(mat_struct *mt1, mat_struct *mt2) /* Call the driver */ - rows = (integer)mt1->rows; - interdim = (integer)mt1->cols; - cols = (integer)mt2->cols; + rows = (int)mt1->rows; + interdim = (int)mt1->cols; + cols = (int)mt2->cols; - lda = (integer)mt1->ldim; - ldb = (integer)mt2->ldim; + lda = (int)mt1->ldim; + ldb = (int)mt2->ldim; - f77_dgemm(&no_trans, &no_trans, &rows, &cols, &interdim, &unity, mt1->vals, - &lda, mt2->vals, &ldb, &zero, mt3->vals, &lda); + cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, rows, cols, interdim, + unity, mt1->vals, lda, mt2->vals, ldb, zero, mt3->vals, lda); return mt3; } -#else /* defined(HAVE_LIBBLAS) */ -#warning G_matrix_product() not compiled; requires BLAS library #endif /* defined(HAVE_LIBBLAS) */ /*! @@ -401,7 +405,7 @@ mat_struct *G_matrix_transpose(mat_struct *mt) { mat_struct *mt1; int ldim, ldo; - doublereal *dbo, *dbt, *dbx, *dby; + double *dbo, *dbt, *dbx, *dby; int cnt, cnt2; /* Word align the workspace blocks */ @@ -509,20 +513,20 @@ int G_matrix_LU_solve(const mat_struct *mt1, mat_struct **xmat0, switch (mtype) { case NONSYM: { - integer *perm, res_info; - integer num_eqns, nrhs, lda, ldb; + int *perm, res_info; + int num_eqns, nrhs, lda, ldb; - perm = (integer *)G_malloc(wmat->rows * sizeof(integer)); + perm = (int *)G_malloc(wmat->rows * sizeof(int)); /* Set fields to pass to fortran routine */ - num_eqns = (integer)mt1->rows; - nrhs = (integer)wmat->cols; - lda = (integer)mt1->ldim; - ldb = (integer)wmat->ldim; + num_eqns = (int)mt1->rows; + nrhs = (int)wmat->cols; + lda = (int)mt1->ldim; + ldb = (int)wmat->ldim; /* Call LA driver */ - f77_dgesv(&num_eqns, &nrhs, mtx->vals, &lda, perm, wmat->vals, &ldb, - &res_info); + res_info = LAPACKE_dgesv(LAPACK_COL_MAJOR, num_eqns, nrhs, mtx->vals, + lda, perm, wmat->vals, ldb); /* Copy the results from the modified data matrix, taking account of pivot permutations ??? @@ -545,7 +549,7 @@ int G_matrix_LU_solve(const mat_struct *mt1, mat_struct **xmat0, */ memcpy(xmat->vals, wmat->vals, - wmat->cols * wmat->ldim * sizeof(doublereal)); + (size_t)wmat->cols * wmat->ldim * sizeof(double)); /* Free temp arrays */ G_free(perm); @@ -574,8 +578,6 @@ int G_matrix_LU_solve(const mat_struct *mt1, mat_struct **xmat0, return 0; } -#else /* defined(HAVE_LIBBLAS) && defined(HAVE_LIBLAPACK) */ -#warning G_matrix_LU_solve() not compiled; requires BLAS and LAPACK libraries #endif /* defined(HAVE_LIBBLAS) && defined(HAVE_LIBLAPACK) */ #if defined(HAVE_LIBBLAS) && defined(HAVE_LIBLAPACK) @@ -635,8 +637,6 @@ mat_struct *G_matrix_inverse(mat_struct *mt) } } -#else /* defined(HAVE_LIBBLAS) && defined(HAVE_LIBLAPACK) */ -#warning G_matrix_inverse() not compiled; requires BLAS and LAPACK libraries #endif /* defined(HAVE_LIBBLAS) && defined(HAVE_LIBLAPACK) */ /*! @@ -672,14 +672,14 @@ void G_matrix_free(mat_struct *mt) void G_matrix_print(mat_struct *mt) { int i, j; - char buf[64], numbuf[64]; + char buf[2048], numbuf[64]; for (i = 0; i < mt->rows; i++) { - strcpy(buf, ""); + G_strlcpy(buf, "", sizeof(buf)); for (j = 0; j < mt->cols; j++) { - - sprintf(numbuf, "%14.6f", G_matrix_get_element(mt, i, j)); + snprintf(numbuf, sizeof(numbuf), "%14.6f", + G_matrix_get_element(mt, i, j)); strcat(buf, numbuf); if (j < mt->cols - 1) strcat(buf, ", "); @@ -720,7 +720,7 @@ int G_matrix_set_element(mat_struct *mt, int rowval, int colval, double val) return -1; } - mt->vals[rowval + colval * mt->ldim] = (doublereal)val; + mt->vals[rowval + colval * mt->ldim] = (double)val; return 0; } @@ -918,7 +918,7 @@ int G_matvect_retrieve_matrix(vec_struct *vc) vec_struct *G_matvect_product(mat_struct *A, vec_struct *b, vec_struct *out) { unsigned int i, m, n, j; - register doublereal sum; + register double sum; /* G_message("A=%d,%d,%d", A->cols, A->rows, A->ldim); */ /* G_message("B=%d,%d,%d", b->cols, b->rows, b->ldim); */ @@ -997,8 +997,7 @@ vec_struct *G_vector_init(int cells, int ldim, vtype vt) tmp_arry->v_indx = 0; - tmp_arry->vals = - (doublereal *)G_calloc(ldim * tmp_arry->cols, sizeof(doublereal)); + tmp_arry->vals = (double *)G_calloc(ldim * tmp_arry->cols, sizeof(double)); tmp_arry->is_init = 1; return tmp_arry; @@ -1144,7 +1143,7 @@ int G_vector_set(vec_struct *A, int cells, int ldim, vtype vt, int vindx) else A->v_indx = vindx; - A->vals = (doublereal *)G_calloc(ldim * A->cols, sizeof(doublereal)); + A->vals = (double *)G_calloc(ldim * A->cols, sizeof(double)); A->is_init = 1; return 0; @@ -1166,22 +1165,22 @@ int G_vector_set(vec_struct *A, int cells, int ldim, vtype vt, int vindx) double G_vector_norm_euclid(vec_struct *vc) { - integer incr, Nval; - doublereal *startpt; + int incr, Nval; + double *startpt; if (!vc->is_init) G_fatal_error(_("Matrix is not initialised")); if (vc->type == ROWVEC_) { - Nval = (integer)vc->cols; - incr = (integer)vc->ldim; + Nval = (int)vc->cols; + incr = (int)vc->ldim; if (vc->v_indx < 0) startpt = vc->vals; else startpt = vc->vals + vc->v_indx; } else { - Nval = (integer)vc->rows; + Nval = (int)vc->rows; incr = 1; if (vc->v_indx < 0) startpt = vc->vals; @@ -1190,11 +1189,9 @@ double G_vector_norm_euclid(vec_struct *vc) } /* Call the BLAS routine dnrm2_() */ - return (double)f77_dnrm2(&Nval, startpt, &incr); + return cblas_dnrm2(Nval, startpt, incr); } -#else /* defined(HAVE_LIBBLAS) */ -#warning G_vector_norm_euclid() not compiled; requires BLAS library #endif /* defined(HAVE_LIBBLAS) */ /*! @@ -1216,7 +1213,7 @@ double G_vector_norm_euclid(vec_struct *vc) double G_vector_norm_maxval(vec_struct *vc, int vflag) { - doublereal xval, *startpt, *curpt; + double xval, *startpt, *curpt; double cellval; int ncells, incr; @@ -1224,15 +1221,15 @@ double G_vector_norm_maxval(vec_struct *vc, int vflag) G_fatal_error(_("Matrix is not initialised")); if (vc->type == ROWVEC_) { - ncells = (integer)vc->cols; - incr = (integer)vc->ldim; + ncells = (int)vc->cols; + incr = (int)vc->ldim; if (vc->v_indx < 0) startpt = vc->vals; else startpt = vc->vals + vc->v_indx; } else { - ncells = (integer)vc->rows; + ncells = (int)vc->rows; incr = 1; if (vc->v_indx < 0) startpt = vc->vals; @@ -1360,9 +1357,6 @@ vec_struct *G_vector_product(vec_struct *v1, vec_struct *v2, vec_struct *out) return NULL; } -#if defined(HAVE_LAPACK) && defined(HAVE_LIBBLAS) - f77_dhad(v1->cols, 1.0, v1->vals, 1, v2->vals, 1, 0.0, out->vals, 1.0); -#else idx1 = (v1->v_indx > 0) ? v1->v_indx : 0; idx2 = (v2->v_indx > 0) ? v2->v_indx : 0; idx0 = (out->v_indx > 0) ? out->v_indx : 0; @@ -1379,7 +1373,6 @@ vec_struct *G_vector_product(vec_struct *v1, vec_struct *v2, vec_struct *out) G_matrix_get_element(v1, i, idx1) * G_matrix_get_element(v2, i, idx2)); } -#endif return out; } @@ -1399,7 +1392,7 @@ vec_struct *G_vector_copy(const vec_struct *vc1, int comp_flag) { vec_struct *tmp_arry; int incr1, incr2; - doublereal *startpt1, *startpt2, *curpt1, *curpt2; + double *startpt1, *startpt2, *curpt1, *curpt2; int cnt; if (!vc1->is_init) { @@ -1441,8 +1434,8 @@ vec_struct *G_vector_copy(const vec_struct *vc1, int comp_flag) return NULL; } - tmp_arry->vals = (doublereal *)G_calloc(tmp_arry->ldim * tmp_arry->cols, - sizeof(doublereal)); + tmp_arry->vals = + (double *)G_calloc(tmp_arry->ldim * tmp_arry->cols, sizeof(double)); if (comp_flag == DO_COMPACT) { if (tmp_arry->type == ROWVEC_) { startpt1 = tmp_arry->vals; @@ -1482,7 +1475,7 @@ vec_struct *G_vector_copy(const vec_struct *vc1, int comp_flag) } while (cnt > 0) { - memcpy(curpt1, curpt2, sizeof(doublereal)); + memcpy(curpt1, curpt2, sizeof(double)); curpt1 += incr1; curpt2 += incr2; cnt--; @@ -1633,7 +1626,7 @@ int G_matrix_eigen_sort(vec_struct *d, mat_struct *m) } /* sort the combined matrix */ - qsort(tmp.vals, tmp.cols, tmp.ldim * sizeof(doublereal), egcmp); + qsort(tmp.vals, tmp.cols, tmp.ldim * sizeof(double), egcmp); /* split tmp into m and d */ for (i = 0; i < m->cols; i++) { @@ -1652,8 +1645,8 @@ int G_matrix_eigen_sort(vec_struct *d, mat_struct *m) static int egcmp(const void *pa, const void *pb) { - double a = *(doublereal *const)pa; - double b = *(doublereal *const)pb; + double a = *(double *const)pa; + double b = *(double *const)pb; if (a > b) return 1; @@ -1662,5 +1655,3 @@ static int egcmp(const void *pa, const void *pb) return 0; } - -#endif /* HAVE_BLAS && HAVE_LAPACK && HAVE_G2C */ diff --git a/mswindows/osgeo4w/build_osgeo4w.sh b/mswindows/osgeo4w/build_osgeo4w.sh index 6885bfe02f8..d38354d4b78 100755 --- a/mswindows/osgeo4w/build_osgeo4w.sh +++ b/mswindows/osgeo4w/build_osgeo4w.sh @@ -38,7 +38,7 @@ export ARCH=x86_64-w64-mingw32 --with-nls \ --with-readline \ --with-blas \ - --with-lapack-includes=/mingw64/include/lapack \ + --with-lapack \ --with-freetype \ --with-freetype-includes=${OSGEO4W_ROOT_MSYS}/include/freetype2 \ --with-proj-share=${OSGEO4W_ROOT_MSYS}/share/proj \ From 89cfc5230d7ac460da62692132f8da3d2d59538f Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Thu, 19 Sep 2024 09:37:25 +0200 Subject: [PATCH 062/209] docs: move Programmer's manual creation to INSTALL.md (#4336) - move Programmer's manual creation from `doc/development/README.md` to `INSTALL.md`. update `doc/development/README.md` - add Python API; add subsections - update URLs and wording - list guides - remove stray control chars (visible in vim) in `doc/development/style_guide.md` --- INSTALL.md | 32 ++++++++++++++++++++--- doc/development/README.md | 46 ++++++++-------------------------- doc/development/style_guide.md | 8 +++--- 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 41249a04143..7687266d7c8 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -321,9 +321,35 @@ developers mailing list. See ## (L) GRASS PROGRAMMER'S MANUAL -The Programmer's manual is generated with doxygen from the source code. -Please see the [README](doc/development/README.md) file and the files at: - +The Programmer's manual is +generated from the source code. This requires the installation of +`doxygen` () and optionally Graphviz `dot` +(). + +The main file is: `./grasslib.dox` where all sub-documents have +to be linked to. + +To locally generate the 'Programmer's Manual', run + +```sh +make htmldocs +``` + +To generate documentation as a single html file +(recommended for simple reading) + +```sh +make htmldocs-single +``` + +This process takes some time. The result will be found in +the file `lib/html/index.html`. + +To generate the 'Programmer's Manual' in PDF format, run + +```sh +make pdfdocs +``` ## (M) CONTRIBUTING CODE AND PATCHES diff --git a/doc/development/README.md b/doc/development/README.md index 9845f20649e..db5244a5a72 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -1,43 +1,19 @@ # Development and Maintenance Documentation -Here is development and maitanance documentation. The API documentation -is at appropriate places, but here is the information relevant to -contributing to GRASS GIS and its maintanance. +Find below the development and maintenance documentation. +The API documentation is available in the appropriate places, +but here is the information relevant to contributing to and +maintaining GRASS GIS. -## How to generate the 'Programmer's Manual' +## Style and GitHub guide -You can locally generate the [GRASS GIS Programmer's Manual](https://grass.osgeo.org/programming8/). +- [GRASS Programming Style Guide](style_guide.md) +- [Guide to contributing on GitHub](github_guide.md) -This needs doxygen () and optionally -Graphviz dot (). +## Python API -To build the GRASS programmer's documentation, run +- ["grass" Python package documentation](https://grass.osgeo.org/grass-devel/manuals/libpython/) -```sh -make htmldocs -``` +## C API -Or to generate documentation as a single html file -(recommended for simple reading) - -```sh -make htmldocs-single -``` - -This takes quite some time. The result is in `lib/html/index.html` -which refers to further document repositories in - -```text -lib/vector/html/index.html -lib/db/html/index.html -lib/gis/html/index.html -``` - -The master file is: `./grasslib.dox` where all sub-documents have to -be linked to. - -To generate the documents in PDF format, run - -```sh -make pdfdocs -``` +- [GRASS Programmer's manual](https://grass.osgeo.org/programming8/) diff --git a/doc/development/style_guide.md b/doc/development/style_guide.md index 8f1d5ab5245..3b065d9f838 100644 --- a/doc/development/style_guide.md +++ b/doc/development/style_guide.md @@ -122,7 +122,7 @@ sorted and separated by a newline. Use function names which fulfill the official [GNU naming convention](https://www.gnu.org/prep/standards/html_node/Names.html). Instead of -naming a function like: MyNewFunction() use snake case: my_new_function()`. +naming a function like: `MyNewFunction()` use snake case: `my_new_function()`. ### Using pre-commit @@ -192,7 +192,7 @@ There are three types of documentation: C API, Python API and tool documentation #### C API documentation We -[​use doxygen and document the functions](https://grass.osgeo.org/programming8/) +[use doxygen and document the functions](https://grass.osgeo.org/programming8/) directly in the source code. See `lib/gis/open.c` and `lib/gis/gislib.dox` for examples. @@ -947,7 +947,7 @@ gs.message(_("Running through {}").format(shellname)) ### Developing C tools Refer to the [online GRASS Programmer's -Manual](​https://grass.osgeo.org/programming8/) or generate it with `make +Manual](https://grass.osgeo.org/programming8/) or generate it with `make htmldocs` or `make pdfdocs`. #### Use GRASS library functions @@ -962,7 +962,7 @@ improves portability. - File seek: `G_fseek()`, `G_ftell()` - Printing: `G_asprintf()`, `G_vsaprintf()`, `G_vfaprintf()`, ... -Please refer to [the programmers manual](https://grass.osgeo.org/programming8/) +Please refer to the [programmers manual](https://grass.osgeo.org/programming8/) for the proper use (e.g., determining if any casts are needed for arguments or return values) of these library functions. They may perform a task slightly different from their corresponding C library function, and thus, their use may From a94c3b0bb42968c98d513558f458990c91e799a7 Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Thu, 19 Sep 2024 13:08:06 +0200 Subject: [PATCH 063/209] configure: fix default variable name for blas and lapack (#4343) In addition: improve handling of configuration with LAPACK without BLAS --- configure | 18 ++++++++++++------ configure.ac | 17 +++++++++++------ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/configure b/configure index 17182bc4b7a..56b203e0c13 100755 --- a/configure +++ b/configure @@ -5611,7 +5611,7 @@ if test ${with_blas+y} then : withval=$with_blas; else $as_nop - with-blas="no" + with_blas=no fi @@ -5621,7 +5621,7 @@ if test ${with_lapack+y} then : withval=$with_lapack; else $as_nop - with-lapack="no" + with_lapack=no fi @@ -13719,10 +13719,10 @@ case "$with_blas" in no) ;; yes) - USE_BLAS="$with_blas" + USE_BLAS=1 ;; *) - USE_BLAS=yes + USE_BLAS=1 BLAS_PKGS="$with_blas" ;; esac @@ -13832,15 +13832,21 @@ case "$with_lapack" in no) ;; yes) - USE_LAPACK="$with_lapack" + USE_LAPACK=1 ;; *) - USE_LAPACK=yes + USE_LAPACK=1 LAPACK_PKG="$with_lapack" ;; esac # LAPACK is useless without BLAS +if test -z "$USE_BLAS" && test -n "$USE_LAPACK"; then + USE_LAPACK= + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: LAPACK is disabled, BLAS configuration is missing" >&5 +printf "%s\n" "$as_me: WARNING: LAPACK is disabled, BLAS configuration is missing" >&2;} +fi + if test -n "$USE_BLAS" && test -n "$USE_LAPACK"; then lapack_ok=no diff --git a/configure.ac b/configure.ac index 8b7413c7cea..52a985960c3 100644 --- a/configure.ac +++ b/configure.ac @@ -323,13 +323,13 @@ AC_ARG_WITH([blas], [AS_HELP_STRING([--with-blas=pkg-config-package], [enable BLAS support with by adding name of pkg-config package name for CBLAS library, e.g. '--with-lapack-package=openblas', - default: cblas])],, [with-blas="no"]) + default: cblas])],, [with_blas=no]) AC_ARG_WITH([lapack], [AS_HELP_STRING([--with-lapack=pkg-config-package], [enable LAPACK support with by adding name of pkg-config package name for LAPACKE library, e.g. '--with-lapack-package=openblas', - default: lapacke])],, [with-lapack="no"]) + default: lapacke])],, [with_lapack=no]) AC_ARG_WITH(libpng, [ --with-libpng[=path/libpng-config] @@ -1594,10 +1594,10 @@ case "$with_blas" in no) ;; yes) - USE_BLAS="$with_blas" + USE_BLAS=1 ;; *) - USE_BLAS=yes + USE_BLAS=1 BLAS_PKGS="$with_blas" ;; esac @@ -1665,15 +1665,20 @@ case "$with_lapack" in no) ;; yes) - USE_LAPACK="$with_lapack" + USE_LAPACK=1 ;; *) - USE_LAPACK=yes + USE_LAPACK=1 LAPACK_PKG="$with_lapack" ;; esac # LAPACK is useless without BLAS +if test -z "$USE_BLAS" && test -n "$USE_LAPACK"; then + USE_LAPACK= + AC_MSG_WARN([LAPACK is disabled, BLAS configuration is missing]) +fi + if test -n "$USE_BLAS" && test -n "$USE_LAPACK"; then lapack_ok=no From 5fd45e48affcc387fb4f225e24c02017125f1cb1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 12:18:21 +0000 Subject: [PATCH 064/209] CI(deps): Update github/codeql-action action to v3.26.8 (#4344) --- .github/workflows/codeql-analysis.yml | 4 ++-- .github/workflows/python-code-quality.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b4562dd75c8..b4fb254d11d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -56,7 +56,7 @@ jobs: if: ${{ matrix.language == 'c-cpp' }} - name: Initialize CodeQL - uses: github/codeql-action/init@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7 + uses: github/codeql-action/init@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -81,6 +81,6 @@ jobs: run: .github/workflows/build_ubuntu-22.04.sh "${HOME}/install" - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7 + uses: github/codeql-action/analyze@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index cd2624051a5..2ca2822d897 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -135,7 +135,7 @@ jobs: path: bandit.sarif - name: Upload SARIF File into Security Tab - uses: github/codeql-action/upload-sarif@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7 + uses: github/codeql-action/upload-sarif@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 with: sarif_file: bandit.sarif From 333d8e6989982854ee4490e2d6ffbd336390e88d Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Thu, 19 Sep 2024 09:57:06 -0400 Subject: [PATCH 065/209] v.cluster: Fix unused value assignment (#4094) Removes the lines with unused assignments with 90%. The variable eps 90% value got overwritten. The used 99% confidence interval is mentioned in the documentation. Fixes the issue identified by Coverity Scan (CID: 1270389). --- vector/v.cluster/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/vector/v.cluster/main.c b/vector/v.cluster/main.c index c3f95e78778..49c7535beca 100644 --- a/vector/v.cluster/main.c +++ b/vector/v.cluster/main.c @@ -286,7 +286,6 @@ int main(int argc, char *argv[]) mean = sum / n; sd = sqrt(sumsq / n - mean * mean); - eps = mean + 1.644854 * sd; /* 90% CI */ eps = mean + 2.575829 * sd; /* 99% CI */ if (eps > max) @@ -493,7 +492,6 @@ int main(int argc, char *argv[]) mean = sum / n; sd = sqrt(sumsq / n - mean * mean); - eps = mean + 1.644854 * sd; /* 90% CI */ eps = mean + 2.575829 * sd; /* 99% CI */ if (eps > max) From 6607e1cebe8b82728d0cb8ff3f69325a98fc0cbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Thu, 19 Sep 2024 17:05:04 -0400 Subject: [PATCH 066/209] CI(macOS): Cache micromamba environment on same week (#4342) * CI(macOS): Cache micromamba environment on same day * Use year and week of year for cache key date segment * Update macos.yml Co-authored-by: Vaclav Petras --------- Co-authored-by: Vaclav Petras --- .github/workflows/macos.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index b74b2b042c9..4fad9d315a7 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -45,12 +45,19 @@ jobs: # Rehash to forget about the deleted files hash -r - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - name: Get current date cache key segment + id: date + # Year and week of year so cache key changes weekly + run: echo "date=$(date +%Y-%U)" >> "${GITHUB_OUTPUT}" - name: Setup Mamba uses: mamba-org/setup-micromamba@f8b8a1e23a26f60a44c853292711bacfd3eac822 # v1.9.0 with: init-shell: bash environment-file: .github/workflows/macos_dependencies.txt environment-name: grass-env + # Persist on the same period (date). + cache-environment-key: environment-${{ steps.date.outputs.date }} + - name: Environment info shell: bash -el {0} run: | From 51f865b774a6f00e7776fae97886c59c394b796a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Thu, 19 Sep 2024 17:05:23 -0400 Subject: [PATCH 067/209] style: Bump Black's target Python versions for Python 3.9 minimum (#4347) * style: Bump Black's target Python versions * style: Format with new Black settings --- pyproject.toml | 2 +- scripts/g.extension/g.extension.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 992e48391ad..6689d6375eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ requires-python = ">=3.9" [tool.black] required-version = '24' line-length = 88 -target-version = ['py38', 'py39', 'py310', 'py311', 'py312'] +target-version = ['py39', 'py310', 'py311', 'py312', 'py313'] # 'extend-exclude' excludes files or directories in addition to the defaults extend-exclude = ''' ( diff --git a/scripts/g.extension/g.extension.py b/scripts/g.extension/g.extension.py index bf8cd183135..ed0544ee2c4 100644 --- a/scripts/g.extension/g.extension.py +++ b/scripts/g.extension/g.extension.py @@ -470,9 +470,10 @@ def replace_shebang_win(python_file): cur_dir = os.path.dirname(python_file) tmp_name = os.path.join(cur_dir, gs.tempname(12)) - with codecs.open(python_file, "r", encoding="utf8") as in_file, codecs.open( - tmp_name, "w", encoding="utf8" - ) as out_file: + with ( + codecs.open(python_file, "r", encoding="utf8") as in_file, + codecs.open(tmp_name, "w", encoding="utf8") as out_file, + ): for line in in_file: new_line = line.replace( "#!/usr/bin/env python\n", "#!/usr/bin/env python3\n" From 75458f8e642a42b3ffbfbe9e69c6d50b3be76629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Thu, 19 Sep 2024 17:05:49 -0400 Subject: [PATCH 068/209] style: Call `startswith` or `endswith` once with a `tuple` (PIE810) (#4348) style: Call `startswith` once with a `tuple` (PIE810) Ruff rule: https://docs.astral.sh/ruff/rules/multiple-starts-ends-with/ --- gui/wxpython/core/toolboxes.py | 2 +- gui/wxpython/psmap/instructions.py | 6 +----- lib/init/grass.py | 4 +--- man/build_class_graphical.py | 4 +--- pyproject.toml | 1 - utils/generate_release_notes.py | 2 +- utils/gitlog2changelog.py | 2 +- 7 files changed, 6 insertions(+), 15 deletions(-) diff --git a/gui/wxpython/core/toolboxes.py b/gui/wxpython/core/toolboxes.py index 441898fa8f6..ae6b1b6a0a6 100644 --- a/gui/wxpython/core/toolboxes.py +++ b/gui/wxpython/core/toolboxes.py @@ -855,7 +855,7 @@ def module_test(): someDiff = False for line in result: - if line.startswith("+") or line.startswith("-"): + if line.startswith(("+", "-")): sys.stdout.write(line) someDiff = True if someDiff: diff --git a/gui/wxpython/psmap/instructions.py b/gui/wxpython/psmap/instructions.py index 2ae68a91069..8a535b96704 100644 --- a/gui/wxpython/psmap/instructions.py +++ b/gui/wxpython/psmap/instructions.py @@ -1936,11 +1936,7 @@ def Read(self, instruction, text, **kwargs): instr = {} for line in text: - if ( - line.startswith("vpoints") - or line.startswith("vlines") - or line.startswith("vareas") - ): + if line.startswith(("vpoints", "vlines", "vareas")): # subtype if line.startswith("vpoints"): subType = "points" diff --git a/lib/init/grass.py b/lib/init/grass.py index 28537f957b1..30c0a1a68ba 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -1057,9 +1057,7 @@ def load_env(grass_env_file): v = v.strip('"') # we'll keep expand=True to expand $var's inside "value" because # they are within double quotes - elif ( - v.startswith("'") or v.endswith("'") or v.startswith('"') or v.endswith('"') - ): + elif v.startswith(("'", '"')) or v.endswith(("'", '"')): # here, let's try to ignore unmatching single/double quotes, which # might be a multi-line variable or just a user error debug("Ignoring multi-line environmental variable {0}".format(k)) diff --git a/man/build_class_graphical.py b/man/build_class_graphical.py index 955f5c2a63e..35b2a731cfe 100644 --- a/man/build_class_graphical.py +++ b/man/build_class_graphical.py @@ -102,9 +102,7 @@ def starts_with_module(string, module) -> bool: # module = module.replace('wxGUI.', 'g.gui.') # TODO: matches g.mapsets images for g.mapset and d.rast.num for d.rast return bool( - string.startswith(module.replace(".", "_")) - or string.startswith(module.replace(".", "")) - or string.startswith(module) + string.startswith((module.replace(".", "_"), module.replace(".", ""), module)) ) diff --git a/pyproject.toml b/pyproject.toml index 6689d6375eb..649e309a73f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -154,7 +154,6 @@ ignore = [ "PERF403", # manual-dict-comprehension "PIE794", # duplicate-class-field-definition "PIE808", # unnecessary-range-start - "PIE810", # multiple-starts-ends-with "PLC0415", # import-outside-top-level "PLC1901", # compare-to-empty-string "PLC2701", # import-private-name diff --git a/utils/generate_release_notes.py b/utils/generate_release_notes.py index 66aa4ced08c..c8a22b01d86 100755 --- a/utils/generate_release_notes.py +++ b/utils/generate_release_notes.py @@ -227,7 +227,7 @@ def notes_from_gh_api(start_tag, end_tag, branch, categories, exclude): raw_changes = lines[start_whats_changed + 1 : end_whats_changed] changes = [] for change in raw_changes: - if change.startswith("* ") or change.startswith("- "): + if change.startswith(("* ", "- ")): changes.append(change[2:]) else: changes.append(change) diff --git a/utils/gitlog2changelog.py b/utils/gitlog2changelog.py index 758b142196b..43aedcfb491 100755 --- a/utils/gitlog2changelog.py +++ b/utils/gitlog2changelog.py @@ -79,7 +79,7 @@ except Exception as e: print(f"Could not parse dateList = '{line}'. Error: {e!s}") # The Fossil-IDs are ignored: - elif line.startswith(" Fossil-ID:") or line.startswith(" [[SVN:"): + elif line.startswith((" Fossil-ID:", " [[SVN:")): continue # The svn-id lines are ignored elif " git-svn-id:" in line: From 4bb31562d99c312f402c9d7b67cfb36f8b59fa7c Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Fri, 20 Sep 2024 10:30:51 +0200 Subject: [PATCH 069/209] wxGUI/history: fix the run of a special cmds only once (#4322) After left double mouse click on the wxGUI history tab tree cmd node. Special cmds are: ``` r"^d\..*|^r[3]?\.mapcalc$|^i.group$|^r.import$|^r.external$|^r.external.out$|" r"^v.import$|^v.external$|^v.external.out$" ``` --- gui/wxpython/history/tree.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/gui/wxpython/history/tree.py b/gui/wxpython/history/tree.py index 929f2d9f53b..74c321aeb67 100644 --- a/gui/wxpython/history/tree.py +++ b/gui/wxpython/history/tree.py @@ -557,14 +557,12 @@ def Run(self, node=None): selected_command = self.selected_command[0] command = selected_command.data["name"] - lst = re.split(r"\s+", command) if ( globalvar.ignoredCmdPattern and re.compile(globalvar.ignoredCmdPattern).search(command) and "--help" not in command and "--ui" not in command ): - self.runIgnoredCmdPattern.emit(cmd=lst) self.runIgnoredCmdPattern.emit(cmd=split(command)) return if re.compile(r"^r[3]?\.mapcalc").search(command): From 64deef26fe5fff239c178fb586b93b62cae1d75b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 07:24:07 -0400 Subject: [PATCH 070/209] CI(deps): Update ruff to v0.6.6 (#4350) --- .github/workflows/python-code-quality.yml | 2 +- .pre-commit-config.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 2ca2822d897..55e6cb02e53 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.7.9" # renovate: datasource=pypi depName=ruff - RUFF_VERSION: "0.6.5" + RUFF_VERSION: "0.6.6" runs-on: ${{ matrix.os }} permissions: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3fdb0741681..425205e24cf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: ) - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.6.5 + rev: v0.6.6 hooks: # Run the linter. - id: ruff From 6bc69e3d75b0b095c902e9fec9891afbeffbc59f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Fri, 20 Sep 2024 07:46:21 -0400 Subject: [PATCH 071/209] CI(OSGeo4W): Use setup-OSGeo4W action to parametrize install options (#4290) * CI(OSGeo4W): Use setup-OSGeo4W action to parametrize instal options * Remon extra double quote * Remove unnecessary space in OSGeo4W workflow file * CI: Multiline sorted OSGeo4W package list --- .github/workflows/osgeo4w.yml | 41 ++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/.github/workflows/osgeo4w.yml b/.github/workflows/osgeo4w.yml index 10acd64dc37..79a44937755 100644 --- a/.github/workflows/osgeo4w.yml +++ b/.github/workflows/osgeo4w.yml @@ -45,19 +45,34 @@ jobs: mingw-w64-x86_64-libtre-git mingw-w64-x86_64-libwinpthread-git mingw-w64-x86_64-libpng mingw-w64-x86_64-pcre - - name: Install OSGeo4W - run: | - $exe = 'osgeo4w-setup.exe' - $url = 'http://download.osgeo.org/osgeo4w/v2/' + $exe - (New-Object System.Net.WebClient).DownloadFile($url, $exe) - Start-Process ('.\'+$exe) -ArgumentList '-A -g -k -q \ - -s http://download.osgeo.org/osgeo4w/v2/ -P ${{ env.Deps }}' -Wait - env: - Deps: "proj-devel,gdal-devel,geos-devel,libtiff-devel,libpng-devel,\ - pdal-devel,netcdf-devel,cairo-devel,fftw,freetype-devel,gdal-ecw,\ - gdal-mrsid,liblas-devel,libxdr,libpq-devel,pdcurses,\ - python3-matplotlib,python3-numpy,python3-ply,python3-pywin32,\ - python3-wxpython,regex-devel,zstd-devel" + - name: Setup OSGeo4W environment + uses: echoix/setup-OSGeo4W@17deecd39e077a80bf1081443998ea8edd6f15bf # v0.1.0 + with: + package-dir: "D:/OSGeo4W_pkg" + packages: | + cairo-devel + fftw + freetype-devel + gdal-devel + gdal-ecw + gdal-mrsid + geos-devel + liblas-devel + libpng-devel + libpq-devel + libtiff-devel + libxdr + netcdf-devel + pdal-devel + pdcurses + proj-devel + python3-matplotlib + python3-numpy + python3-ply + python3-pywin32 + python3-wxpython + regex-devel + zstd-devel - name: Set number of cores for compilation run: | From bf41fc770d27e4784b971d2dd6ccf6cd31c25b0b Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Fri, 20 Sep 2024 16:50:02 +0200 Subject: [PATCH 072/209] lib/gmath: rename ATLAS_wrapper to CBLAS_wrapper (#4351) Rename file to reflect changes made with https://github.com/OSGeo/grass/commit/d5bb442d7b121861928a37842e05e5265a980427 --- ...{ATLAS_wrapper_blas_level_1.c => CBLAS_wrapper_blas_level_1.c} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/gmath/{ATLAS_wrapper_blas_level_1.c => CBLAS_wrapper_blas_level_1.c} (100%) diff --git a/lib/gmath/ATLAS_wrapper_blas_level_1.c b/lib/gmath/CBLAS_wrapper_blas_level_1.c similarity index 100% rename from lib/gmath/ATLAS_wrapper_blas_level_1.c rename to lib/gmath/CBLAS_wrapper_blas_level_1.c From c4424ab14a4b3679b2001e376892ec711d06f856 Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Fri, 20 Sep 2024 16:53:16 +0200 Subject: [PATCH 073/209] lib/gmath: properly guard BLAS and LAPACK dependent code (#4346) --- lib/gmath/la.c | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/lib/gmath/la.c b/lib/gmath/la.c index 48a4cbc7817..5696a174bda 100644 --- a/lib/gmath/la.c +++ b/lib/gmath/la.c @@ -23,23 +23,24 @@ ******************************************************************************/ #include -#include -#include -#include -#if defined(HAVE_LIBLAPACK) && defined(HAVE_LIBBLAS) +#if defined(HAVE_LIBBLAS) && defined(HAVE_LIBLAPACK) + +#include +#include +#include +#include + #include #if defined(HAVE_CBLAS_ATLAS_H) #include #else #include -#endif -#endif +#endif // HAVE_CBLAS_ATLAS_H -#include -#include -#include -#include +#include +#include +#include static int egcmp(const void *pa, const void *pb); @@ -335,8 +336,6 @@ mat_struct *G__matrix_add(mat_struct *mt1, mat_struct *mt2, const double c1, return mt3; } -#if defined(HAVE_LIBBLAS) - /*! * \fn mat_struct *G_matrix_product (mat_struct *mt1, mat_struct *mt2) * @@ -386,8 +385,6 @@ mat_struct *G_matrix_product(mat_struct *mt1, mat_struct *mt2) return mt3; } -#endif /* defined(HAVE_LIBBLAS) */ - /*! * \fn mat_struct *G_matrix_transpose (mat_struct *mt) * @@ -442,8 +439,6 @@ mat_struct *G_matrix_transpose(mat_struct *mt) return mt1; } -#if defined(HAVE_LIBBLAS) && defined(HAVE_LIBLAPACK) - /*! * \fn int G_matrix_LU_solve (const mat_struct *mt1, mat_struct **xmat0, * const mat_struct *bmat, mat_type mtype) @@ -578,10 +573,6 @@ int G_matrix_LU_solve(const mat_struct *mt1, mat_struct **xmat0, return 0; } -#endif /* defined(HAVE_LIBBLAS) && defined(HAVE_LIBLAPACK) */ - -#if defined(HAVE_LIBBLAS) && defined(HAVE_LIBLAPACK) - /*! * \fn mat_struct *G_matrix_inverse (mat_struct *mt) * @@ -637,8 +628,6 @@ mat_struct *G_matrix_inverse(mat_struct *mt) } } -#endif /* defined(HAVE_LIBBLAS) && defined(HAVE_LIBLAPACK) */ - /*! * \fn void G_matrix_free (mat_struct *mt) * @@ -1149,8 +1138,6 @@ int G_vector_set(vec_struct *A, int cells, int ldim, vtype vt, int vindx) return 0; } -#if defined(HAVE_LIBBLAS) - /*! * \fn double G_vector_norm_euclid (vec_struct *vc) * @@ -1192,8 +1179,6 @@ double G_vector_norm_euclid(vec_struct *vc) return cblas_dnrm2(Nval, startpt, incr); } -#endif /* defined(HAVE_LIBBLAS) */ - /*! * \fn double G_vector_norm_maxval (vec_struct *vc, int vflag) * @@ -1655,3 +1640,7 @@ static int egcmp(const void *pa, const void *pb) return 0; } + +#endif // HAVE_LIBLAPACK HAVE_LIBBLAS + +typedef int suppress_empty_translation_unit_compiler_warning; From 2356520814d2ab272c308af9e89c3af466c13a13 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Fri, 20 Sep 2024 23:05:38 -0400 Subject: [PATCH 074/209] doc: Fix most Flake8 issues in example files (#4353) This addresses F403 and F405. These are mostly related to wild card imports. This does not touch max line length issue with long tool description documentation line (current format limitation). --- .flake8 | 4 +--- doc/python/m.distance.py | 15 +++++++++++++-- doc/python/raster_example_ctypes.py | 20 +++++++++++++++++--- doc/python/vector_example_ctypes.py | 23 +++++++++++++++++++++-- 4 files changed, 52 insertions(+), 10 deletions(-) diff --git a/.flake8 b/.flake8 index e72eaa73333..bd33e493bfc 100644 --- a/.flake8 +++ b/.flake8 @@ -22,9 +22,7 @@ per-file-ignores = __init__.py: F401, F403 man/build_html.py: E501 imagery/i.atcorr/create_iwave.py: F632, F821, W293 - doc/python/raster_example_ctypes.py: F403, F405 - doc/python/vector_example_ctypes.py: F403, F405 - doc/python/m.distance.py: F403, F405, E501 + doc/python/m.distance.py: E501 doc/gui/wxpython/example/dialogs.py: F401 locale/grass_po_stats.py: E122, E128, E231, E401, E722 gui/scripts/d.wms.py: E501 diff --git a/doc/python/m.distance.py b/doc/python/m.distance.py index 5eddb1dcc56..576760c3b40 100755 --- a/doc/python/m.distance.py +++ b/doc/python/m.distance.py @@ -45,10 +45,21 @@ # %end import sys +from ctypes import byref, c_double import grass.script as gs - -from grass.lib.gis import * +from grass.lib.gis import ( + G_gisinit, + G_begin_distance_calculations, + G_scan_easting, + G_scan_northing, + G_distance, + G_begin_polygon_area_calculations, + G_area_of_polygon, + G_database_units_to_meters_factor, + G_database_unit_name, + PROJECTION_LL, +) def main(): diff --git a/doc/python/raster_example_ctypes.py b/doc/python/raster_example_ctypes.py index f62ce4a9492..67f7a2cf4cb 100644 --- a/doc/python/raster_example_ctypes.py +++ b/doc/python/raster_example_ctypes.py @@ -17,9 +17,23 @@ import os import sys - -from grass.lib.gis import * -from grass.lib.raster import * +import math + +from ctypes import POINTER, c_int, c_float, c_double, c_void_p, cast + +from grass.lib.gis import G_gisinit, G_find_raster2, G_free +from grass.lib.raster import ( + Rast_map_type, + CELL_TYPE, + FCELL_TYPE, + DCELL_TYPE, + Rast_open_old, + Rast_allocate_buf, + Rast_window_rows, + Rast_window_cols, + Rast_get_row, + Rast_close, +) # check if GRASS is running or not if "GISBASE" not in os.environ: diff --git a/doc/python/vector_example_ctypes.py b/doc/python/vector_example_ctypes.py index 9f8a90d6459..ae3877224d0 100644 --- a/doc/python/vector_example_ctypes.py +++ b/doc/python/vector_example_ctypes.py @@ -7,9 +7,28 @@ import os import sys +from ctypes import pointer, byref -from grass.lib.gis import * -from grass.lib.vector import * +# Import specific functions and classes instead of using wildcard imports +from grass.lib.gis import G_gisinit, G_find_vector2 +from grass.lib.vector import ( + Map_info, + Vect_set_open_level, + Vect_open_old, + Vect_get_full_name, + Vect_is_3d, + Vect_get_num_dblinks, + Vect_get_scale, + Vect_get_map_box, + Vect_point_in_box, + Vect_get_num_lines, + Vect_get_num_primitives, + Vect_get_num_areas, + Vect_close, + bound_box, + GV_POINT, + GV_LINE, +) if "GISBASE" not in os.environ: sys.exit("You must be in GRASS GIS to run this program.") From d89ad9e3a186a6791190f25d6cbc1e093390bb37 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Sat, 21 Sep 2024 14:36:34 -0400 Subject: [PATCH 075/209] g.proj: Fix copy into fixed size buffer issue in input.c file (#4359) Co-authored-by: Shubham Vasudeo Desai --- general/g.proj/input.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/general/g.proj/input.c b/general/g.proj/input.c index 7f07b9bdcbf..c4232bdb9dd 100644 --- a/general/g.proj/input.c +++ b/general/g.proj/input.c @@ -230,8 +230,12 @@ int input_proj4(char *proj4params) if (fgets(buff, sizeof(buff), infd) == NULL) G_warning(_("Failed to read PROJ.4 parameter from stdin")); } - else - strcpy(buff, proj4params); + else { + if (G_strlcpy(buff, proj4params, sizeof(buff)) >= sizeof(buff)) { + G_fatal_error(_("PROJ.4 parameter string is too long: %s"), + proj4params); + } + } #if PROJ_VERSION_MAJOR >= 6 if (!strstr(buff, "+type=crs")) From 93781e51e659174b4203ce5690a6404d6af5cfbc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 21 Sep 2024 19:21:32 +0000 Subject: [PATCH 076/209] CI(deps): Update ruff to v0.6.7 (#4360) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/python-code-quality.yml | 2 +- .pre-commit-config.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 55e6cb02e53..92ef7d788b2 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.7.9" # renovate: datasource=pypi depName=ruff - RUFF_VERSION: "0.6.6" + RUFF_VERSION: "0.6.7" runs-on: ${{ matrix.os }} permissions: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 425205e24cf..e1f98c7a2a5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: ) - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.6.6 + rev: v0.6.7 hooks: # Run the linter. - id: ruff From 5aed1a6aa939bbe6ad8a82a6313eeb6cdc8b2dc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 21 Sep 2024 18:30:35 -0400 Subject: [PATCH 077/209] tests: Re-enable passing tests from .gunittest.cfg exclusion list (#4358) * tests: Re-enable passing tests from .gunittest.cfg exclusion list * tests: Re-enable all macOS excluded tests that are passing * tests: Exclude back tests that are failing on macOS --- .github/workflows/macos_gunittest.cfg | 9 +-------- .gunittest.cfg | 7 ------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/.github/workflows/macos_gunittest.cfg b/.github/workflows/macos_gunittest.cfg index b6806ff5823..923ae2cbe5d 100644 --- a/.github/workflows/macos_gunittest.cfg +++ b/.github/workflows/macos_gunittest.cfg @@ -6,25 +6,18 @@ exclude = gui/wxpython/core/testsuite/test_gcmd.py gui/wxpython/core/testsuite/toolboxes.sh - lib/init/testsuite/test_grass_tmp_mapset.py - python/grass/gunittest/testsuite/test_assertions_rast3d.py python/grass/gunittest/testsuite/test_assertions_vect.py - python/grass/gunittest/testsuite/test_gmodules.py - python/grass/gunittest/testsuite/test_gunitest_doctests.py python/grass/pygrass/raster/testsuite/test_pygrass_raster_doctests.py python/grass/pygrass/rpc/testsuite/test_pygrass_rpc_doctests.py - python/grass/script/testsuite/test_script_doctests.py python/grass/temporal/testsuite/unittests_temporal_raster_algebra_equal_ts.py python/grass/temporal/testsuite/unittests_temporal_raster_conditionals_complement_else.py raster/r.in.lidar/testsuite/test_base_resolution.sh raster/r.in.pdal/testsuite/test_r_in_pdal_binning.py raster/r.in.pdal/testsuite/test_r_in_pdal_selection.py - raster/r.terraflow/testsuite/test_r_terraflow.py raster/r.sun/testsuite/test_rsun.py raster3d/r3.flow/testsuite/r3flow_test.py - scripts/g.search.modules/testsuite/test_g_search_modules.py - temporal/t.connect/testsuite/test_distr_tgis_db_raster3d.py temporal/t.connect/testsuite/test_distr_tgis_db_raster.py + temporal/t.connect/testsuite/test_distr_tgis_db_raster3d.py temporal/t.connect/testsuite/test_distr_tgis_db_vector.py temporal/t.info/testsuite/test.t.info.sh temporal/t.rast.aggregate/testsuite/test_aggregation_relative.py diff --git a/.gunittest.cfg b/.gunittest.cfg index 01b06c78913..2117fde9d7a 100644 --- a/.gunittest.cfg +++ b/.gunittest.cfg @@ -4,21 +4,14 @@ # space. This would be ideally empty or it would include just special cases, # but it includes mainly tests which can (and should) be fixed. exclude = - gui/wxpython/core/testsuite/test_gcmd.py gui/wxpython/core/testsuite/toolboxes.sh - lib/init/testsuite/test_grass_tmp_mapset.py - python/grass/gunittest/testsuite/test_assertions_rast3d.py python/grass/gunittest/testsuite/test_assertions_vect.py - python/grass/gunittest/testsuite/test_gmodules.py python/grass/gunittest/testsuite/test_gunitest_doctests.py python/grass/pygrass/raster/testsuite/test_pygrass_raster_doctests.py python/grass/pygrass/rpc/testsuite/test_pygrass_rpc_doctests.py - python/grass/script/testsuite/test_script_doctests.py python/grass/temporal/testsuite/unittests_temporal_raster_algebra_equal_ts.py python/grass/temporal/testsuite/unittests_temporal_raster_conditionals_complement_else.py raster/r.in.lidar/testsuite/test_base_resolution.sh - raster/r.in.lidar/testsuite/test_base_resolution.sh - scripts/g.search.modules/testsuite/test_g_search_modules.py temporal/t.connect/testsuite/test_distr_tgis_db_raster3d.py temporal/t.connect/testsuite/test_distr_tgis_db_raster.py temporal/t.connect/testsuite/test_distr_tgis_db_vector.py From 0c1e79bdf80b5c3f3e584c7cc5432d65e962399d Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Sat, 21 Sep 2024 19:28:51 -0400 Subject: [PATCH 078/209] checks: Move imports to the top in wxGUI/core (#4357) Moves imports to the top to fix Flake8 E402 warning for wxGUI/core. Also orders ignores alphabetically. --- .flake8 | 6 ++---- gui/wxpython/core/gcmd.py | 12 ++++++------ gui/wxpython/core/watchdog.py | 9 ++++----- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/.flake8 b/.flake8 index bd33e493bfc..ecea7b82a0b 100644 --- a/.flake8 +++ b/.flake8 @@ -26,14 +26,12 @@ per-file-ignores = doc/gui/wxpython/example/dialogs.py: F401 locale/grass_po_stats.py: E122, E128, E231, E401, E722 gui/scripts/d.wms.py: E501 - gui/wxpython/core/gcmd.py: E402 gui/wxpython/core/gconsole.py: E722 + gui/wxpython/core/render.py: E722 + gui/wxpython/core/settings.py: E722 gui/wxpython/core/toolboxes.py: E722 gui/wxpython/core/utils.py: E722 gui/wxpython/core/workspace.py: E722 - gui/wxpython/core/render.py: E722 - gui/wxpython/core/settings.py: E722 - gui/wxpython/core/watchdog.py: E402 gui/wxpython/datacatalog/tree.py: E731, E402 gui/wxpython/dbmgr/base.py: E722 gui/wxpython/dbmgr/dialogs.py: E722 diff --git a/gui/wxpython/core/gcmd.py b/gui/wxpython/core/gcmd.py index 7d4ed678d79..b93789f22f7 100644 --- a/gui/wxpython/core/gcmd.py +++ b/gui/wxpython/core/gcmd.py @@ -36,6 +36,12 @@ from threading import Thread import wx +from core.debug import Debug +from core.globalvar import SCT_EXT + +from grass.script import core as grass +from grass.script.utils import decode, encode + is_mswindows = sys.platform == "win32" if is_mswindows: from win32file import ReadFile, WriteFile @@ -45,12 +51,6 @@ import select import fcntl -from core.debug import Debug -from core.globalvar import SCT_EXT - -from grass.script import core as grass -from grass.script.utils import decode, encode - def DecodeString(string): """Decode string using system encoding diff --git a/gui/wxpython/core/watchdog.py b/gui/wxpython/core/watchdog.py index 9315a1010d6..652bc1d755d 100644 --- a/gui/wxpython/core/watchdog.py +++ b/gui/wxpython/core/watchdog.py @@ -19,6 +19,10 @@ import os import time +import wx +from wx.lib.newevent import NewEvent + +from grass.script import core as grass watchdog_used = True try: @@ -32,11 +36,6 @@ PatternMatchingEventHandler = object FileSystemEventHandler = object -import wx -from wx.lib.newevent import NewEvent - -from grass.script import core as grass - updateMapset, EVT_UPDATE_MAPSET = NewEvent() currentMapsetChanged, EVT_CURRENT_MAPSET_CHANGED = NewEvent() From 7b4a2404a4fe9fe7cda1807f8ab144b02928d661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sun, 22 Sep 2024 08:28:07 -0400 Subject: [PATCH 079/209] tests: Add `xfail_windows` decorator for failing tests on Windows (#4362) * grass.gunittest: Add xfail_windows decorator for Windows expected failures * lib/imagery: Add xfail_windows decorator to test functions * Fix spacing issue in xfail_windows warning message * Add stacklevel=2 to xfail_windows decorator warning message * Update utils.py Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Format end of file * Comment out warning in decorator * i.maxlik: Add xfail_windows decorator to SuccessTest class * lib/gis: Add xfail_windows decorator to TestNewlinesWithGetlFunctions class * Update warning stacklevel to 3 * Update utils.py Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update utils.py Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update utils.py * tests: Add expected failures to failing tests on windows * tests: Apply xfail_windows decorator to setUpClass in lib/gis getl tests * tests: Apply xfail_windows decorator to parser json tests in lib/gis * tests: Apply xfail_windows decorator to failing test in lib/imagery * Remove wrong import of xfail_windows * tests: Temporarily remove all gunittest exclusions * tests: Apply xfail_windows decorator to failing test in test_gcmd.py * tests: Apply xfail_windows decorator to failing test in lib/init in test_grass_tmp_mapset.py * CI(OSGeo4W): Use an OSGeo4W-specific gunittest.cfg config file * Revert "tests: Temporarily remove all gunittest exclusions" This reverts commit 20eb947d4cc0f1b2f79ffb9e16541fcb94d59a9a. * v.out.lidar: Apply xfail_windows decorator to one failing test * t.rast.series: Apply xfail_windows decorator to failing tests * t.connect: Apply xfail_windows decorator to three failing tests * g.search.modules: Apply xfail_windows decorator to a failing test * grass.temporal: Apply xfail_windows decorator to failing tests in unittests_temporal_raster_algebra_equal_ts * grass.gunittest: Apply xfail_windows decorator to failing test test_assertVectorEqualsAscii_by_import * tests: Re-enable excluded tests that are not failing on Windows * tests: Re-enable passing tests from .gunittest.cfg exclusion list * Update test_gis_lib_getl.py * Update test_raster_img.py * tests: Try re-enabling python/grass/script/testsuite/test_script_doctests.py * i.maxlik: Add xfail_windows decorator to all tests in class * tests: Exclude more tests that are failing on Windows * v.univar: Apply xfail_windows decorator to failing tests * t.rast.univar: Apply xfail_windows decorator to a failing test * r.in.gdal: Try avoiding error in calling gdal-config in skipif decorator on Windows * CI(OSGeo4W): Increase min-success to 96% for gunittest * Add line in test_grass_tmp_mapset.py * Update test_r_tileset.py --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .github/workflows/osgeo4w_gunittest.cfg | 32 +++++++++++++++++++ .github/workflows/test_thorough.bat | 2 +- gui/wxpython/core/testsuite/test_gcmd.py | 3 ++ imagery/i.maxlik/testsuite/test_i_maxlik.py | 3 ++ lib/gis/testsuite/test_parser_json.py | 5 +++ .../test_imagery_signature_management.py | 4 +++ lib/init/testsuite/test_grass_tmp_mapset.py | 5 +++ python/grass/grassdb/testsuite/test_manage.py | 5 +++ .../gunittest/testsuite/test_assertions.py | 3 ++ .../testsuite/test_assertions_vect.py | 2 ++ .../gunittest/testsuite/test_checkers.py | 2 ++ python/grass/gunittest/utils.py | 16 ++++++++++ python/grass/jupyter/testsuite/map3d_test.py | 5 +++ .../pygrass/raster/testsuite/test_category.py | 2 ++ .../pygrass/raster/testsuite/test_numpy.py | 2 ++ .../raster/testsuite/test_raster_img.py | 4 +++ .../testsuite/test_start_command_functions.py | 3 ++ python/grass/script/testsuite/test_utils.py | 2 ++ ...ttests_temporal_raster_algebra_equal_ts.py | 3 ++ raster/r.in.gdal/testsuite/test_r_in_gdal.py | 4 ++- raster/r.kappa/testsuite/test_r_kappa.py | 2 ++ raster/r.mfilter/testsuite/test_r_mfilter.py | 7 ++++ raster/r.report/testsuite/test_r_report.py | 2 ++ .../testsuite/test_addons_modules.py | 7 +++- .../testsuite/test_addons_toolboxes.py | 3 ++ .../testsuite/test_g_search_modules.py | 2 ++ scripts/r.tileset/testsuite/test_r_tileset.py | 2 ++ .../testsuite/test_v_rast_stats.py | 6 ++++ .../testsuite/test_distr_tgis_db_raster.py | 3 +- .../testsuite/test_distr_tgis_db_raster3d.py | 3 +- .../testsuite/test_distr_tgis_db_vector.py | 3 +- .../t.rast.gapfill/testsuite/test_gapfill.py | 6 ++++ .../t.rast.series/testsuite/test_series.py | 3 ++ .../testsuite/test_t_rast_univar.py | 10 ++++++ temporal/t.rast.what/testsuite/test_what.py | 5 +++ .../testsuite/test_t_rast3d_univar.py | 5 +++ .../v.out.lidar/testsuite/test_v_out_lidar.py | 2 ++ vector/v.univar/testsuite/test_v_univar.py | 5 +++ 38 files changed, 177 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/osgeo4w_gunittest.cfg diff --git a/.github/workflows/osgeo4w_gunittest.cfg b/.github/workflows/osgeo4w_gunittest.cfg new file mode 100644 index 00000000000..b9252cf49ef --- /dev/null +++ b/.github/workflows/osgeo4w_gunittest.cfg @@ -0,0 +1,32 @@ +[gunittest] + +# Files (or wildcard patterns) to exclude from testing separated by newline or +# space. This would be ideally empty or it would include just special cases, +# but it includes mainly tests which can (and should) be fixed. +exclude = + gui/wxpython/core/testsuite/toolboxes.sh + lib/init/testsuite/test_grass_tmp_mapset.py + python/grass/gunittest/testsuite/test_gunitest_doctests.py + python/grass/pygrass/raster/testsuite/test_pygrass_raster_doctests.py + python/grass/pygrass/rpc/testsuite/test_pygrass_rpc_doctests.py + python/grass/script/testsuite/test_script_doctests.py + python/grass/temporal/testsuite/unittests_temporal_raster_conditionals_complement_else.py + temporal/t.info/testsuite/test.t.info.sh + temporal/t.rast.accdetect/testsuite/test.t.rast.accdetect.reverse.sh + temporal/t.rast.accdetect/testsuite/test.t.rast.accdetect.sh + temporal/t.rast.aggregate/testsuite/test_aggregation_relative.py + vector/v.edit/testsuite/select_all_flag.sh + vector/v.in.lidar/testsuite/decimation_test.py + vector/v.in.lidar/testsuite/mask_test.py + vector/v.in.lidar/testsuite/test_v_in_lidar_basic.py + vector/v.in.lidar/testsuite/test_v_in_lidar_filter.py + vector/v.what.rast3/testsuite/test.v.what.rast3.sh + vector/v.what/testsuite/test_vwhat_layers.py + vector/v.what/testsuite/test_vwhat_ncspm.py + +# Maximum time for execution of one test file (not a test function) +# after which test is terminated (which may not terminate child processes +# from that test). +# Using 5 minutes as maximum (average test time should be much shorter, +# couple seconds per file, median should be around one second). +timeout = 300 diff --git a/.github/workflows/test_thorough.bat b/.github/workflows/test_thorough.bat index 40df9534a20..843adb4c4f0 100644 --- a/.github/workflows/test_thorough.bat +++ b/.github/workflows/test_thorough.bat @@ -2,4 +2,4 @@ set grass=%1 set python=%2 call %grass% --tmp-project XY --exec g.download.project url=https://grass.osgeo.org/sampledata/north_carolina/nc_spm_full_v2alpha2.tar.gz path=%USERPROFILE% -call %grass% --tmp-project XY --exec %python% -m grass.gunittest.main --grassdata %USERPROFILE% --location nc_spm_full_v2alpha2 --location-type nc --min-success 86 +call %grass% --tmp-project XY --exec %python% -m grass.gunittest.main --grassdata %USERPROFILE% --location nc_spm_full_v2alpha2 --location-type nc --min-success 96 --config .github\workflows\osgeo4w_gunittest.cfg diff --git a/gui/wxpython/core/testsuite/test_gcmd.py b/gui/wxpython/core/testsuite/test_gcmd.py index 121ede99b77..75d3bf5932b 100644 --- a/gui/wxpython/core/testsuite/test_gcmd.py +++ b/gui/wxpython/core/testsuite/test_gcmd.py @@ -1,5 +1,6 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test +from grass.gunittest.utils import xfail_windows class Rcv: @@ -16,6 +17,8 @@ def recv(self): class Recv_SomeTest(TestCase): + + @xfail_windows def test_decode(self): """ Multibyte chars should not be split diff --git a/imagery/i.maxlik/testsuite/test_i_maxlik.py b/imagery/i.maxlik/testsuite/test_i_maxlik.py index 1f6829e92b4..e7fbf6c1a79 100644 --- a/imagery/i.maxlik/testsuite/test_i_maxlik.py +++ b/imagery/i.maxlik/testsuite/test_i_maxlik.py @@ -19,6 +19,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test +from grass.gunittest.utils import xfail_windows from grass.lib.gis import G_mapset_path from grass.lib.raster import Rast_write_semantic_label @@ -172,6 +173,7 @@ def tearDownClass(cls): ) cls.runModule("g.remove", flags="f", type="group", name=cls.group, quiet=True) + @xfail_windows def test_v1(self): """Test v1 signature""" self.assertModule( @@ -193,6 +195,7 @@ def test_v1(self): self.assertEqual(res.get_cat(0)[1], 1) res.close() + @xfail_windows def test_v2(self): """Test v2 signature""" self.assertModule( diff --git a/lib/gis/testsuite/test_parser_json.py b/lib/gis/testsuite/test_parser_json.py index 918fb453d04..74ff9673c7f 100644 --- a/lib/gis/testsuite/test_parser_json.py +++ b/lib/gis/testsuite/test_parser_json.py @@ -10,11 +10,14 @@ import subprocess from grass.gunittest.case import TestCase +from grass.gunittest.utils import xfail_windows from grass.script import decode import json class TestParserJson(TestCase): + + @xfail_windows def test_r_slope_aspect_json(self): args = [ "r.slope.aspect", @@ -58,6 +61,7 @@ def test_r_slope_aspect_json(self): self.assertEqual(json_code["inputs"], inputs) self.assertEqual(json_code["outputs"], outputs) + @xfail_windows def test_v_out_ascii(self): args = [ "v.out.ascii", @@ -91,6 +95,7 @@ def test_v_out_ascii(self): self.assertEqual(json_code["inputs"], inputs) self.assertEqual(json_code["outputs"], outputs) + @xfail_windows def test_v_info(self): args = ["v.info", "map=hospitals@PERMANENT", "-c", "--json"] diff --git a/lib/imagery/testsuite/test_imagery_signature_management.py b/lib/imagery/testsuite/test_imagery_signature_management.py index 7b1dc8bdc57..42c55c45123 100644 --- a/lib/imagery/testsuite/test_imagery_signature_management.py +++ b/lib/imagery/testsuite/test_imagery_signature_management.py @@ -15,6 +15,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test +from grass.gunittest.utils import xfail_windows from grass.script.core import tempname import grass.script as gs @@ -44,16 +45,19 @@ class GetSignaturesDirTestCase(TestCase): + @xfail_windows def test_get_sig(self): cdir = ctypes.create_string_buffer(GNAME_MAX) I_get_signatures_dir(cdir, I_SIGFILE_TYPE_SIG) self.assertEqual(utils.decode(cdir.value), f"signatures{HOST_DIRSEP}sig") + @xfail_windows def test_get_sigset(self): cdir = ctypes.create_string_buffer(GNAME_MAX) I_get_signatures_dir(cdir, I_SIGFILE_TYPE_SIGSET) self.assertEqual(utils.decode(cdir.value), f"signatures{HOST_DIRSEP}sigset") + @xfail_windows def test_get_libsvm(self): elem = ctypes.create_string_buffer(GNAME_MAX) I_get_signatures_dir(elem, I_SIGFILE_TYPE_LIBSVM) diff --git a/lib/init/testsuite/test_grass_tmp_mapset.py b/lib/init/testsuite/test_grass_tmp_mapset.py index 7a488dadb5f..9379957cd3f 100644 --- a/lib/init/testsuite/test_grass_tmp_mapset.py +++ b/lib/init/testsuite/test_grass_tmp_mapset.py @@ -18,6 +18,7 @@ import os import shutil import subprocess +from grass.gunittest.utils import xfail_windows # Note that unlike rest of GRASS GIS, here we are using unittest package @@ -43,6 +44,7 @@ def tearDown(self): """Deletes the location""" shutil.rmtree(self.location, ignore_errors=True) + @xfail_windows def test_command_runs(self): """Check that correct parameters are accepted""" return_code = subprocess.call( @@ -57,6 +59,7 @@ def test_command_runs(self): ), ) + @xfail_windows def test_command_fails_without_location(self): """Check that the command fails with a nonexistent location""" return_code = subprocess.call( @@ -78,6 +81,7 @@ def test_command_fails_without_location(self): ), ) + @xfail_windows def test_mapset_metadata_correct(self): """Check that metadata is readable and have expected value (XY CRS)""" output = subprocess.check_output( @@ -91,6 +95,7 @@ def test_mapset_metadata_correct(self): ), ) + @xfail_windows def test_mapset_deleted(self): """Check that mapset is deleted at the end of execution""" subprocess.check_call( diff --git a/python/grass/grassdb/testsuite/test_manage.py b/python/grass/grassdb/testsuite/test_manage.py index a2788d4f1a8..43b8945bd31 100644 --- a/python/grass/grassdb/testsuite/test_manage.py +++ b/python/grass/grassdb/testsuite/test_manage.py @@ -18,6 +18,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.gmodules import call_module from grass.gunittest.main import test +from grass.gunittest.utils import xfail_windows class TestMapsetPath(TestCase): @@ -38,6 +39,7 @@ def test_mapset_from_path_object(self): self.assertEqual(mapset_path.mapset, mapset_name) self.assertEqual(mapset_path.path, Path(path) / location_name / mapset_name) + @xfail_windows def test_mapset_from_str(self): """Check with path from str and database directory as Path""" path = "does/not/exist" @@ -60,6 +62,7 @@ def test_mapset_from_str(self): class TestSplitMapsetPath(TestCase): """Check that split works with different parameters""" + @xfail_windows def test_split_path(self): """Check that pathlib.Path is correctly split""" ref_db = "does/not/exist" @@ -71,6 +74,7 @@ def test_split_path(self): self.assertEqual(new_location, ref_location) self.assertEqual(new_mapset, ref_mapset) + @xfail_windows def test_split_str(self): """Check that path as str is correctly split""" ref_db = "does/not/exist" @@ -82,6 +86,7 @@ def test_split_str(self): self.assertEqual(new_location, ref_location) self.assertEqual(new_mapset, ref_mapset) + @xfail_windows def test_split_str_trailing_slash(self): """Check that path as str with a trailing slash is correctly split""" ref_db = "does/not/exist" diff --git a/python/grass/gunittest/testsuite/test_assertions.py b/python/grass/gunittest/testsuite/test_assertions.py index 3af538132f3..ed27c0e54fb 100644 --- a/python/grass/gunittest/testsuite/test_assertions.py +++ b/python/grass/gunittest/testsuite/test_assertions.py @@ -11,6 +11,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.gmodules import SimpleModule +from grass.gunittest.utils import xfail_windows class TestTextAssertions(TestCase): @@ -34,6 +35,7 @@ def test_assertLooksLike(self): def test_assertLooksLike_multiline(self): self.assertLooksLike("a=123\nb=456\nc=789", "a=...\nb=...\nc=...") + @xfail_windows def test_assertLooksLike_multiline_platform_dependent(self): self.assertLooksLike( "a=123\nb=456\nc=789", "a=...{nl}b=...{nl}c=...".format(nl=os.linesep) @@ -384,6 +386,7 @@ def test_assertFileExists_empty_file(self): self.failureException, self.assertFileExists, filename=self.emtpy_file ) + @xfail_windows def test_assertFileMd5(self): self.assertFileMd5(filename=self.file_with_md5, md5=self.file_md5) self.assertRaises( diff --git a/python/grass/gunittest/testsuite/test_assertions_vect.py b/python/grass/gunittest/testsuite/test_assertions_vect.py index 8b3288ad2ca..0a73580ba58 100644 --- a/python/grass/gunittest/testsuite/test_assertions_vect.py +++ b/python/grass/gunittest/testsuite/test_assertions_vect.py @@ -5,6 +5,7 @@ from grass.exceptions import CalledModuleError from grass.gunittest.case import TestCase from grass.gunittest.main import test +from grass.gunittest.utils import xfail_windows V_UNIVAR_SCHOOLS_WIDTH_SUBSET = """n=144 @@ -281,6 +282,7 @@ def test_assertVectorAsciiEqualsVectorAscii_diff_content(self): self.assertFileExists(self.simple_base_file) self.assertFileExists(self.simple_modified_file) + @xfail_windows def test_assertVectorEqualsAscii_by_import(self): amap = "simple_vector_map_imported_base" self.runModule( diff --git a/python/grass/gunittest/testsuite/test_checkers.py b/python/grass/gunittest/testsuite/test_checkers.py index d35ffcb19d8..b11b25778a3 100644 --- a/python/grass/gunittest/testsuite/test_checkers.py +++ b/python/grass/gunittest/testsuite/test_checkers.py @@ -24,6 +24,7 @@ file_md5, text_file_md5, ) +from grass.gunittest.utils import xfail_windows class TestValuesEqual(TestCase): @@ -386,6 +387,7 @@ def tearDownClass(cls): try_remove(cls.correct_file_name_unix_nl) try_remove(cls.wrong_file_name) + @xfail_windows def test_text_file_binary(self): r"""File with ``\n`` (LF) newlines as binary (MD5 has ``\n``).""" self.assertEqual( diff --git a/python/grass/gunittest/utils.py b/python/grass/gunittest/utils.py index c1afea3d5ad..5313dbb9bc8 100644 --- a/python/grass/gunittest/utils.py +++ b/python/grass/gunittest/utils.py @@ -14,6 +14,8 @@ from pathlib import Path import shutil import sys +from unittest import expectedFailure +import warnings def ensure_dir(directory): @@ -80,3 +82,17 @@ def safe_repr(obj, short=False): if not short or len(result) < _MAX_LENGTH: return result return result[:_MAX_LENGTH] + " [truncated]..." + + +def xfail_windows(test_item): + """Marks a test as an expected failure or error only on Windows + Equivalent to applying @unittest.expectedFailure only when running + on Windows. + """ + if not sys.platform.startswith("win"): + return lambda func: func + warnings.warn( + "Once the test is fixed and passing, remove the @xfail_windows decorator", + stacklevel=2, + ) + return expectedFailure(test_item) diff --git a/python/grass/jupyter/testsuite/map3d_test.py b/python/grass/jupyter/testsuite/map3d_test.py index b28b6a03a5b..5f88fad24e7 100644 --- a/python/grass/jupyter/testsuite/map3d_test.py +++ b/python/grass/jupyter/testsuite/map3d_test.py @@ -26,6 +26,7 @@ import grass.jupyter as gj from grass.gunittest.case import TestCase from grass.gunittest.main import test +from grass.gunittest.utils import xfail_windows def can_import_ipython(): @@ -81,12 +82,14 @@ def tearDown(self): else: file.unlink(missing_ok=True) + @xfail_windows def test_defaults(self): """Check that default settings work""" renderer = gj.Map3D() renderer.render(elevation_map="elevation", color_map="elevation") self.assertFileExists(renderer.filename) + @xfail_windows def test_filename(self): """Check that custom filename works""" custom_filename = "test_filename.png" @@ -96,12 +99,14 @@ def test_filename(self): renderer.render(elevation_map="elevation", color_map="elevation") self.assertFileExists(custom_filename) + @xfail_windows def test_hw(self): """Check that custom width and height works""" renderer = gj.Map3D(width=200, height=400) renderer.render(elevation_map="elevation", color_map="elevation") self.assertFileExists(renderer.filename) + @xfail_windows def test_overlay(self): """Check that overlay works""" renderer = gj.Map3D() diff --git a/python/grass/pygrass/raster/testsuite/test_category.py b/python/grass/pygrass/raster/testsuite/test_category.py index 527c43b894f..113264c82f6 100644 --- a/python/grass/pygrass/raster/testsuite/test_category.py +++ b/python/grass/pygrass/raster/testsuite/test_category.py @@ -6,6 +6,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test +from grass.gunittest.utils import xfail_windows from grass.pygrass.raster import RasterRow from grass.pygrass.raster.category import Category @@ -76,6 +77,7 @@ def testFirstCat(self): self.assertEqual(cats[7], cat7) self.assertEqual(cats[15], cat15) + @xfail_windows def testWrite(self): tmpfile = tempfile(False) cats = Category(self.name) diff --git a/python/grass/pygrass/raster/testsuite/test_numpy.py b/python/grass/pygrass/raster/testsuite/test_numpy.py index 5f0b2309544..b23926d8ba7 100644 --- a/python/grass/pygrass/raster/testsuite/test_numpy.py +++ b/python/grass/pygrass/raster/testsuite/test_numpy.py @@ -6,6 +6,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test +from grass.gunittest.utils import xfail_windows from numpy.random import default_rng from grass.pygrass.raster import raster2numpy, numpy2raster, RasterRow @@ -48,6 +49,7 @@ def test_len(self): self.assertTrue(len(self.numpy_obj), 40) self.assertTrue(len(self.numpy_obj[0]), 60) + @xfail_windows def test_write(self): rng = default_rng() numpy2raster(rng.random([40, 60]), "FCELL", self.name, True) diff --git a/python/grass/pygrass/raster/testsuite/test_raster_img.py b/python/grass/pygrass/raster/testsuite/test_raster_img.py index bbc1cb2dabd..b873b16a86b 100644 --- a/python/grass/pygrass/raster/testsuite/test_raster_img.py +++ b/python/grass/pygrass/raster/testsuite/test_raster_img.py @@ -3,6 +3,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test +from grass.gunittest.utils import xfail_windows from grass.pygrass.raster import raster2numpy_img from grass.pygrass.gis.region import Region @@ -149,6 +150,7 @@ def test_resampling_to_numpy_img_1(self): self.assertEqual(len(a), region.rows * region.cols * 4) + @xfail_windows def test_resampling_to_numpy_img_2(self): region = Region() region.ewres = 1 @@ -159,6 +161,7 @@ def test_resampling_to_numpy_img_2(self): self.assertEqual(len(a), region.rows * region.cols * 4) + @xfail_windows def test_resampling_to_numpy_img_3(self): region = Region() region.ewres = 0.4 @@ -169,6 +172,7 @@ def test_resampling_to_numpy_img_3(self): self.assertEqual(len(a), region.rows * region.cols * 1) + @xfail_windows def test_resampling_to_numpy_img_4(self): region = Region() region.ewres = 0.1 diff --git a/python/grass/script/testsuite/test_start_command_functions.py b/python/grass/script/testsuite/test_start_command_functions.py index 414a68cd270..368669263a8 100644 --- a/python/grass/script/testsuite/test_start_command_functions.py +++ b/python/grass/script/testsuite/test_start_command_functions.py @@ -4,6 +4,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test +from grass.gunittest.utils import xfail_windows from grass.script.core import start_command, PIPE, run_command, write_command from grass.script.core import read_command, find_program @@ -85,6 +86,7 @@ def setUpClass(cls): def tearDownClass(cls): cls.runModule("g.remove", type="raster", name=cls.raster, flags="f") + @xfail_windows def test_write_labels_unicode(self): """This tests if Python module works""" find_program("ls", "--version") @@ -99,6 +101,7 @@ def test_write_labels_unicode(self): self.assertEqual(res, "1:kůň\n2:kráva\n3:ovečka\n4:býk") self.assertIsInstance(res, str) + @xfail_windows def test_write_labels_bytes(self): """This tests if Python module works""" write_command( diff --git a/python/grass/script/testsuite/test_utils.py b/python/grass/script/testsuite/test_utils.py index db12041d66d..67d2c59dd69 100644 --- a/python/grass/script/testsuite/test_utils.py +++ b/python/grass/script/testsuite/test_utils.py @@ -2,6 +2,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test +from grass.gunittest.utils import xfail_windows from grass.script import utils @@ -39,6 +40,7 @@ def test_bytes(self): def test_unicode(self): self.assertEqual(b"text", utils.encode("text")) + @xfail_windows def test_bytes_garbage_in_out(self): """If the input is bytes we should not touch it for encoding""" self.assertEqual( diff --git a/python/grass/temporal/testsuite/unittests_temporal_raster_algebra_equal_ts.py b/python/grass/temporal/testsuite/unittests_temporal_raster_algebra_equal_ts.py index 92397cd825c..f96ed12899f 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_raster_algebra_equal_ts.py +++ b/python/grass/temporal/testsuite/unittests_temporal_raster_algebra_equal_ts.py @@ -12,6 +12,7 @@ import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.main import test +from grass.gunittest.utils import xfail_windows class TestTemporalRasterAlgebraImplicitAggregation(TestCase): @@ -64,6 +65,7 @@ def tearDownClass(cls): cls.runModule("t.unregister", maps="singletmap", quiet=True) cls.del_temp_region() + @xfail_windows def test_simple_operator(self): """Test implicit aggregation @@ -149,6 +151,7 @@ def test_single_map_complex_operator(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), None) + @xfail_windows def test_single_map_simple_operator(self): """Test implicit aggregation diff --git a/raster/r.in.gdal/testsuite/test_r_in_gdal.py b/raster/r.in.gdal/testsuite/test_r_in_gdal.py index 355e9b74eda..2390e9838cd 100644 --- a/raster/r.in.gdal/testsuite/test_r_in_gdal.py +++ b/raster/r.in.gdal/testsuite/test_r_in_gdal.py @@ -4,6 +4,7 @@ """ import unittest +import sys from subprocess import check_output @@ -311,7 +312,8 @@ def test_netCDF_3d_5(self): self.assertLooksLike(map_list, text_from_file) @unittest.skipIf( - tuple( + not sys.platform.startswith("win") + and tuple( map( int, check_output(["gdal-config", "--version"]) diff --git a/raster/r.kappa/testsuite/test_r_kappa.py b/raster/r.kappa/testsuite/test_r_kappa.py index 56e356ca20b..620a4f4979b 100644 --- a/raster/r.kappa/testsuite/test_r_kappa.py +++ b/raster/r.kappa/testsuite/test_r_kappa.py @@ -21,6 +21,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.checkers import keyvalue_equals +from grass.gunittest.utils import xfail_windows class MatrixCorrectnessTest(TestCase): @@ -474,6 +475,7 @@ def test_stdout(self): keyvalue_equals(self.expected_outputs[i], json_out, precision=4) ) + @xfail_windows def test_file(self): for i in range(len(self.references)): f = NamedTemporaryFile() diff --git a/raster/r.mfilter/testsuite/test_r_mfilter.py b/raster/r.mfilter/testsuite/test_r_mfilter.py index 3d1764b4894..c18aa7c9273 100644 --- a/raster/r.mfilter/testsuite/test_r_mfilter.py +++ b/raster/r.mfilter/testsuite/test_r_mfilter.py @@ -1,6 +1,7 @@ from tempfile import NamedTemporaryFile from grass.gunittest.case import TestCase from grass.gunittest.main import test +from grass.gunittest.utils import xfail_windows class TestNeighbors(TestCase): @@ -202,6 +203,7 @@ def tearDownClass(cls): "g.remove", flags="f", type="raster", name=",".join(cls.to_remove) ) + @xfail_windows def test_sequential(self): """Test output with sequential filter type.""" test_case = "test_sequential" @@ -235,6 +237,7 @@ def test_sequential(self): precision=1e-5, ) + @xfail_windows def test_parallel(self): """Test output with parallel filter type.""" test_case = "test_parallel" @@ -268,6 +271,7 @@ def test_parallel(self): precision=1e-5, ) + @xfail_windows def test_sequential_null(self): """Test output with sequential filter type with null mode enabled.""" test_case = "test_sequential_null" @@ -301,6 +305,7 @@ def test_sequential_null(self): precision=1e-5, ) + @xfail_windows def test_parallel_null(self): """Test output with parallel filter type with null mode enabled.""" test_case = "test_parallel_null" @@ -361,6 +366,7 @@ def test_parallel_null(self): precision=1e-5, ) + @xfail_windows def test_multiple_filters(self): """Test output with multiple filters.""" test_case = "test_multiple_filters" @@ -394,6 +400,7 @@ def test_multiple_filters(self): precision=1e-5, ) + @xfail_windows def test_repeated_filters(self): """Test output with repeated filters.""" test_case = "test_repeated_filters" diff --git a/raster/r.report/testsuite/test_r_report.py b/raster/r.report/testsuite/test_r_report.py index 53e49fdc174..86a16c27adb 100644 --- a/raster/r.report/testsuite/test_r_report.py +++ b/raster/r.report/testsuite/test_r_report.py @@ -17,6 +17,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule +from grass.gunittest.utils import xfail_windows class TestRasterreport(TestCase): @@ -294,6 +295,7 @@ def test_json(self): data = json.loads(module.outputs.stdout) self._assert_report_equal(reference, data) + @xfail_windows def test_json2(self): """Test JSON format with more options""" reference = { diff --git a/scripts/g.extension/testsuite/test_addons_modules.py b/scripts/g.extension/testsuite/test_addons_modules.py index c1cab5c954a..9b99e7ac2ae 100644 --- a/scripts/g.extension/testsuite/test_addons_modules.py +++ b/scripts/g.extension/testsuite/test_addons_modules.py @@ -15,7 +15,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.gmodules import SimpleModule -from grass.gunittest.utils import silent_rmtree +from grass.gunittest.utils import silent_rmtree, xfail_windows from grass.script.utils import decode import os @@ -52,6 +52,7 @@ class TestModulesMetadata(TestCase): url = "file://" + os.path.abspath("data") + @xfail_windows def test_listing(self): """List individual extensions/modules/addons""" module = SimpleModule("g.extension", flags="l", url=self.url) @@ -90,6 +91,7 @@ def tearDown(self): """Remove created files""" silent_rmtree(self.install_prefix) + @xfail_windows def test_directory_install(self): """Test installing extension from directory""" self.assertModule( @@ -102,6 +104,7 @@ def test_directory_install(self): for file in self.files: self.assertFileExists(file) + @xfail_windows def test_targz_install(self): """Test installing extension from local .tar.gz""" self.assertModule( @@ -113,6 +116,7 @@ def test_targz_install(self): for file in self.files: self.assertFileExists(file) + @xfail_windows def test_remote_targz_without_dir_install(self): """Test installing extension from (remote) .tar.gz without main dir""" self.assertModule( @@ -125,6 +129,7 @@ def test_remote_targz_without_dir_install(self): for file in self.files: self.assertFileExists(file) + @xfail_windows def test_remote_zip_install(self): """Test installing extension from .zip specified by URL (local)""" self.assertModule( diff --git a/scripts/g.extension/testsuite/test_addons_toolboxes.py b/scripts/g.extension/testsuite/test_addons_toolboxes.py index 5cbc0454a41..17d7e4b5b74 100644 --- a/scripts/g.extension/testsuite/test_addons_toolboxes.py +++ b/scripts/g.extension/testsuite/test_addons_toolboxes.py @@ -15,9 +15,11 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.gmodules import SimpleModule +from grass.gunittest.utils import xfail_windows import os + FULL_TOOLBOXES_OUTPUT = """\ Hydrology (HY) * r.stream.basins @@ -39,6 +41,7 @@ class TestToolboxesMetadata(TestCase): url = "file://" + os.path.abspath("data") + @xfail_windows def test_listing(self): """List toolboxes and their content""" module = SimpleModule("g.extension", flags="lt", url=self.url) diff --git a/scripts/g.search.modules/testsuite/test_g_search_modules.py b/scripts/g.search.modules/testsuite/test_g_search_modules.py index d280ffc1441..75537eb8d78 100644 --- a/scripts/g.search.modules/testsuite/test_g_search_modules.py +++ b/scripts/g.search.modules/testsuite/test_g_search_modules.py @@ -15,6 +15,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.gmodules import SimpleModule +from grass.gunittest.utils import xfail_windows from grass.script.utils import decode import unittest @@ -65,6 +66,7 @@ def test_colored_terminal(self): stdout = decode(module.outputs.stdout).split() self.assertEqual(stdout[0], termcolor.colored("r.basins.fill", attrs=["bold"])) + @xfail_windows def test_manual_pages(self): module = SimpleModule("g.search.modules", keyword="kapri", flags="gm") self.assertModule(module) diff --git a/scripts/r.tileset/testsuite/test_r_tileset.py b/scripts/r.tileset/testsuite/test_r_tileset.py index 7f1c62ed1f5..cba9908d900 100644 --- a/scripts/r.tileset/testsuite/test_r_tileset.py +++ b/scripts/r.tileset/testsuite/test_r_tileset.py @@ -7,6 +7,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.gmodules import SimpleModule +from grass.gunittest.utils import xfail_windows from grass.script.utils import decode @@ -36,6 +37,7 @@ def tearDownClass(cls): """!Remove the temporary region""" cls.del_temp_region() + @xfail_windows def test_tiling(self): """Produce tiling test""" module = SimpleModule( diff --git a/scripts/v.rast.stats/testsuite/test_v_rast_stats.py b/scripts/v.rast.stats/testsuite/test_v_rast_stats.py index ca3111d14d8..56acbce5964 100644 --- a/scripts/v.rast.stats/testsuite/test_v_rast_stats.py +++ b/scripts/v.rast.stats/testsuite/test_v_rast_stats.py @@ -5,6 +5,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule +from grass.gunittest.utils import xfail_windows from grass.pygrass.vector import VectorTopo from grass.pygrass.vector.geometry import Line from grass.pygrass.vector.geometry import Boundary @@ -71,6 +72,7 @@ def setUp(self): vt.table.conn.commit() vt.close() + @xfail_windows def test_1(self): # Output of v.rast.stats univar_string = """cat|value|label|a_minimum|a_maximum|a_sum @@ -91,6 +93,7 @@ def test_1(self): self.runModule(v_db_select) self.assertLooksLike(univar_string, str(v_db_select.outputs.stdout)) + @xfail_windows def test_line_d(self): output_str = """cat|name|a_median|a_number|a_range 1|first|192|3|1 @@ -109,6 +112,7 @@ def test_line_d(self): self.runModule(v_db_select) self.assertLooksLike(output_str, str(v_db_select.outputs.stdout)) + @xfail_windows def test_line(self): output_str = """cat|name|a_median|a_number|a_range 1|first|192|5|2 @@ -128,6 +132,7 @@ def test_line(self): self.runModule(v_db_select) self.assertLooksLike(output_str, str(v_db_select.outputs.stdout)) + @xfail_windows def test_zone_all(self): # Output of v.rast.stats univar_string = """cat|value|label|a_number|a_null_cells|a_minimum|a_maximum|a_range|a_average|a_stddev|a_variance|a_coeff_var|a_sum|a_first_quartile|a_median|a_third_quartile|a_percentile_90 @@ -143,6 +148,7 @@ def test_zone_all(self): self.runModule(v_db_select) self.assertLooksLike(univar_string, str(v_db_select.outputs.stdout)) + @xfail_windows def test_small_area_with_centroid(self): # Output of v.rast.stats univar_string = """cat|name|a_number|a_null_cells|a_minimum|a_maximum|a_range|a_average|a_stddev|a_variance|a_coeff_var|a_sum|a_first_quartile|a_median|a_third_quartile|a_percentile_90 diff --git a/temporal/t.connect/testsuite/test_distr_tgis_db_raster.py b/temporal/t.connect/testsuite/test_distr_tgis_db_raster.py index 412a926f01d..6e4d76b26c5 100644 --- a/temporal/t.connect/testsuite/test_distr_tgis_db_raster.py +++ b/temporal/t.connect/testsuite/test_distr_tgis_db_raster.py @@ -13,7 +13,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule -from grass.gunittest.utils import silent_rmtree +from grass.gunittest.utils import silent_rmtree, xfail_windows class TestRasterExtraction(TestCase): @@ -254,6 +254,7 @@ def test_strds_info(self): module=info, reference=tinfo_string, precision=2, sep="=" ) + @xfail_windows def test_raster_info(self): self.runModule("g.mapset", mapset="test3") tinfo_string = """id=a1@test1 diff --git a/temporal/t.connect/testsuite/test_distr_tgis_db_raster3d.py b/temporal/t.connect/testsuite/test_distr_tgis_db_raster3d.py index 23bc11c271e..f9b4df76d88 100644 --- a/temporal/t.connect/testsuite/test_distr_tgis_db_raster3d.py +++ b/temporal/t.connect/testsuite/test_distr_tgis_db_raster3d.py @@ -13,7 +13,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule -from grass.gunittest.utils import silent_rmtree +from grass.gunittest.utils import silent_rmtree, xfail_windows class testRaster3dExtraction(TestCase): @@ -242,6 +242,7 @@ def test_strds_info(self): module=info, reference=tinfo_string, precision=2, sep="=" ) + @xfail_windows def test_raster_info(self): self.runModule("g.mapset", mapset="test3d3") tinfo_string = """id=a1@test3d1 diff --git a/temporal/t.connect/testsuite/test_distr_tgis_db_vector.py b/temporal/t.connect/testsuite/test_distr_tgis_db_vector.py index fd26cc93e26..7184fd32cb5 100644 --- a/temporal/t.connect/testsuite/test_distr_tgis_db_vector.py +++ b/temporal/t.connect/testsuite/test_distr_tgis_db_vector.py @@ -13,7 +13,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule -from grass.gunittest.utils import silent_rmtree +from grass.gunittest.utils import silent_rmtree, xfail_windows class TestRasterExtraction(TestCase): @@ -259,6 +259,7 @@ def test_stvds_info(self): module=info, reference=tinfo_string, precision=2, sep="=" ) + @xfail_windows def testv_vector_info(self): self.runModule("g.mapset", mapset="testvect3") tinfo_string = """id=a1@testvect1 diff --git a/temporal/t.rast.gapfill/testsuite/test_gapfill.py b/temporal/t.rast.gapfill/testsuite/test_gapfill.py index 63cd2b83c26..7b083617d08 100644 --- a/temporal/t.rast.gapfill/testsuite/test_gapfill.py +++ b/temporal/t.rast.gapfill/testsuite/test_gapfill.py @@ -12,6 +12,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule +from grass.gunittest.utils import xfail_windows class TestRasterToVector(TestCase): @@ -75,6 +76,7 @@ def tearDown(self): """Remove generated data""" self.runModule("t.remove", flags="df", type="strds", inputs="A") + @xfail_windows def test_simple_2procs(self): self.assertModule( "t.rast.gapfill", @@ -125,6 +127,7 @@ def test_simple_2procs(self): self.assertModule(rast_list) self.assertLooksLike(text, rast_list.outputs.stdout) + @xfail_windows def test_simple_where(self): self.assertModule( "t.rast.gapfill", @@ -173,6 +176,7 @@ def test_simple_where(self): self.assertModule(rast_list) self.assertLooksLike(text, rast_list.outputs.stdout) + @xfail_windows def test_simple_where_2(self): self.assertModule( "t.rast.gapfill", @@ -216,6 +220,7 @@ def test_simple_where_2(self): self.assertModule(rast_list) self.assertLooksLike(text, rast_list.outputs.stdout) + @xfail_windows def test_simple_empty(self): self.assertModule( "t.rast.gapfill", @@ -302,6 +307,7 @@ def test_simple_gran(self): self.assertModule(rast_list) self.assertLooksLike(text, rast_list.outputs.stdout) + @xfail_windows def test_simple_gran(self): self.assertModule( "t.rast.gapfill", diff --git a/temporal/t.rast.series/testsuite/test_series.py b/temporal/t.rast.series/testsuite/test_series.py index cfb17a338cd..8070b4de44b 100644 --- a/temporal/t.rast.series/testsuite/test_series.py +++ b/temporal/t.rast.series/testsuite/test_series.py @@ -14,6 +14,7 @@ import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule +from grass.gunittest.utils import xfail_windows class TestSnapAbsoluteSTRDS(TestCase): @@ -66,6 +67,7 @@ def tearDownClass(cls): cls.runModule("g.remove", flags="f", type="raster", name="series_minimum_2") cls.runModule("g.remove", flags="f", type="raster", name="series_quantile") + @xfail_windows def test_time_stamp(self): self.assertModule( "t.rast.series", @@ -146,6 +148,7 @@ def test_minimum_where(self): map="series_minimum_2", refmin=300, refmax=300, msg="Minimum must be 300" ) + @xfail_windows def test_quantile(self): self.assertModule( "t.rast.series", diff --git a/temporal/t.rast.univar/testsuite/test_t_rast_univar.py b/temporal/t.rast.univar/testsuite/test_t_rast_univar.py index 11a91614b6c..dca870d6a98 100644 --- a/temporal/t.rast.univar/testsuite/test_t_rast_univar.py +++ b/temporal/t.rast.univar/testsuite/test_t_rast_univar.py @@ -11,6 +11,7 @@ from pathlib import Path from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule +from grass.gunittest.utils import xfail_windows class TestRasterUnivar(TestCase): @@ -152,6 +153,7 @@ def tearDownClass(cls): cls.del_temp_region() + @xfail_windows def test_with_all_maps(self): t_rast_univar = SimpleModule( "t.rast.univar", @@ -177,6 +179,7 @@ def test_with_all_maps(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) + @xfail_windows def test_with_subset_of_maps(self): t_rast_univar = SimpleModule( "t.rast.univar", @@ -201,6 +204,7 @@ def test_with_subset_of_maps(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) + @xfail_windows def test_coarser_resolution(self): t_rast_univar = SimpleModule( "t.rast.univar", @@ -316,6 +320,7 @@ def test_error_handling_no_input(self): # No input self.assertModuleFail("t.rast.univar", output="out.txt") + @xfail_windows def test_with_zones(self): """Test use of zones""" @@ -353,6 +358,7 @@ def test_with_zones(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) + @xfail_windows def test_with_semantic_label(self): """Test semantic labels""" t_rast_univar = SimpleModule( @@ -379,6 +385,7 @@ def test_with_semantic_label(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) + @xfail_windows def test_with_semantic_label_parallel(self): """Test semantic labels""" t_rast_univar = SimpleModule( @@ -406,6 +413,7 @@ def test_with_semantic_label_parallel(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) + @xfail_windows def test_with_spatial_filter_intersects(self): """Test spatial filter overlaps""" t_rast_univar = SimpleModule( @@ -434,6 +442,7 @@ def test_with_spatial_filter_intersects(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) + @xfail_windows def test_with_spatial_filter_contains(self): """Test spatial filter contains""" t_rast_univar = SimpleModule( @@ -460,6 +469,7 @@ def test_with_spatial_filter_contains(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) + @xfail_windows def test_with_spatial_filter_is_contained(self): """Test spatial filter is_contained""" t_rast_univar = SimpleModule( diff --git a/temporal/t.rast.what/testsuite/test_what.py b/temporal/t.rast.what/testsuite/test_what.py index 96432eff4e1..18c7af63807 100644 --- a/temporal/t.rast.what/testsuite/test_what.py +++ b/temporal/t.rast.what/testsuite/test_what.py @@ -10,6 +10,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule +from grass.gunittest.utils import xfail_windows class TestRasterWhat(TestCase): @@ -218,6 +219,7 @@ def test_timerow_output_coords(self): "out_timerow_coords.txt", "ca4ee0e7e4aaca170d6034e0d57d292d", text=True ) + @xfail_windows def test_row_stdout_where_parallel(self): t_rast_what = SimpleModule( "t.rast.what", @@ -245,6 +247,7 @@ def test_row_stdout_where_parallel(self): """ self.assertLooksLike(text, str(t_rast_what.outputs.stdout)) + @xfail_windows def test_row_stdout_where_parallel_cat(self): t_rast_what = SimpleModule( "t.rast.what", @@ -272,6 +275,7 @@ def test_row_stdout_where_parallel_cat(self): """ self.assertLooksLike(text, str(t_rast_what.outputs.stdout)) + @xfail_windows def test_row_stdout_where_parallel2(self): """Here without output definition, the default is used then""" @@ -385,6 +389,7 @@ def tearDownClass(cls): cls.runModule("t.remove", flags="df", type="strds", inputs="A") cls.del_temp_region() + @xfail_windows def test_null_value(self): """Test setting the null value""" diff --git a/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py b/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py index 7c8ab1e4100..4ca64e88442 100644 --- a/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py +++ b/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py @@ -11,6 +11,7 @@ from pathlib import Path from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule +from grass.gunittest.utils import xfail_windows class TestRasterUnivar(TestCase): @@ -58,6 +59,7 @@ def tearDownClass(cls): cls.runModule("g.remove", flags="f", type="raster_3d", name="zones") cls.del_temp_region() + @xfail_windows def test_with_all_maps(self): t_rast3d_univar = SimpleModule( "t.rast3d.univar", @@ -82,6 +84,7 @@ def test_with_all_maps(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) + @xfail_windows def test_with_subset_of_maps(self): t_rast3d_univar = SimpleModule( "t.rast3d.univar", @@ -166,6 +169,7 @@ def test_error_handling_no_input(self): # No input self.assertModuleFail("t.rast3d.univar", output="out.txt") + @xfail_windows def test_with_zones(self): """Test use of zones""" @@ -203,6 +207,7 @@ def test_with_zones(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) + @xfail_windows def test_with_zones_parallel(self): """Test use of zones""" diff --git a/vector/v.out.lidar/testsuite/test_v_out_lidar.py b/vector/v.out.lidar/testsuite/test_v_out_lidar.py index 9be4f57d3b6..613cb14b61a 100644 --- a/vector/v.out.lidar/testsuite/test_v_out_lidar.py +++ b/vector/v.out.lidar/testsuite/test_v_out_lidar.py @@ -12,6 +12,7 @@ import os from grass.gunittest.case import TestCase from grass.gunittest.main import test +from grass.gunittest.utils import xfail_windows class BasicTest(TestCase): @@ -60,6 +61,7 @@ def test_module_runs_output_created(self): self.assertModule("v.out.lidar", input=self.vector_points, output=self.las_file) self.assertFileExists(self.las_file) + @xfail_windows def test_output_identical(self): """Test to see if the standard outputs are created diff --git a/vector/v.univar/testsuite/test_v_univar.py b/vector/v.univar/testsuite/test_v_univar.py index 766871d951c..e5fc2685cac 100644 --- a/vector/v.univar/testsuite/test_v_univar.py +++ b/vector/v.univar/testsuite/test_v_univar.py @@ -15,9 +15,11 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.gmodules import SimpleModule +from grass.gunittest.utils import xfail_windows class TestProfiling(TestCase): + @xfail_windows def test_flagg(self): """Testing flag g with map lakes""" output_str = """n=15279 @@ -40,6 +42,7 @@ def test_flagg(self): v_univar.run() self.assertLooksLike(actual=v_univar.outputs.stdout, reference=output_str) + @xfail_windows def test_flage(self): """Testing flag e with map geology""" output_str = """number of features with non NULL attribute: 1832 @@ -68,6 +71,7 @@ def test_flage(self): v_univar.run() self.assertLooksLike(actual=v_univar.outputs.stdout, reference=output_str) + @xfail_windows def test_flagw(self): """Testing flag w with map lakes""" output_str = """number of features with non NULL attribute: 15279 @@ -83,6 +87,7 @@ def test_flagw(self): v_univar.run() self.assertLooksLike(actual=v_univar.outputs.stdout, reference=output_str) + @xfail_windows def test_flagd(self): """Testing flag d with map hospitals""" univar_string = """number of primitives: 160 From 6d046ece6537d02796251a9d2cc51bbd8adaf9a5 Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Sun, 22 Sep 2024 10:42:02 -0400 Subject: [PATCH 080/209] grass.temporal: fix regression in printing metadata (#4328) * grass.temporal: fix regression in printing metadata * Update python/grass/temporal/metadata.py Co-authored-by: Stefan Blumentrath --------- Co-authored-by: Stefan Blumentrath --- python/grass/temporal/metadata.py | 186 +++++++++++++++++++----------- 1 file changed, 116 insertions(+), 70 deletions(-) diff --git a/python/grass/temporal/metadata.py b/python/grass/temporal/metadata.py index 6094bbbe146..369fadc03cf 100644 --- a/python/grass/temporal/metadata.py +++ b/python/grass/temporal/metadata.py @@ -251,6 +251,26 @@ def get_max(self): min = property(fget=get_min, fset=set_min) max = property(fget=get_max, fset=set_max) + def print_info(self): + """Print information about this class in human readable style""" + self._print_info_body(shell=False) + + def print_shell_info(self): + """Print information about this class in shell style""" + self._print_info_body(shell=True) + + def _print_info_head(self, shell=False): + """Print information about this class (head part). + + No header printed in shell style mode. + + :param bool shell: True for human readable style otherwise shell style + """ + if not shell: + print( + " +-------------------- Metadata information ----------------------------------+" # noqa: E501 + ) + def _print_info_body(self, shell=False): """Print information about this class (body part). @@ -331,6 +351,7 @@ class RasterMetadata(RasterMetadataBase): | East-west resolution:....... 0.1 | Minimum value:.............. 0.0 | Maximum value:.............. 100.0 + | Semantic label:............. None >>> meta.print_shell_info() datatype=CELL cols=100 @@ -340,6 +361,7 @@ class RasterMetadata(RasterMetadataBase): ewres=0.1 min=0.0 max=100.0 + semantic_label=None """ @@ -384,17 +406,19 @@ def get_semantic_label(self): semantic_label = property(fget=get_semantic_label, fset=set_semantic_label) - def _print_info_body(self, shell=False): - """Print information about this class (body part). + def print_info(self): + """Print information about this class.""" + self._print_info_head(shell=False) + self._print_info_body(shell=False) + # semantic label section (raster specific only) + print(" | Semantic label:............. " + str(self.get_semantic_label())) - :param bool shell: True for human readable style otherwise shell style - """ - super()._print_info_body(shell) + def print_shell_info(self): + """Print information about this class in shell style""" + self._print_info_head(shell=True) + self._print_info_body(shell=True) # semantic label section (raster specific only) - if shell: - print("semantic_label=" + str(self.get_semantic_label())) - else: - print(" | Semantic label:............. " + str(self.get_semantic_label())) + print("semantic_label=" + str(self.get_semantic_label())) ############################################################################### @@ -539,18 +563,19 @@ def get_tbres(self): depths = property(fget=get_depths, fset=set_depths) tbres = property(fget=get_tbres, fset=set_tbres) - def _print_info_body(self, shell=False): - """Print information about this class (body part). + def print_info(self): + """Print information about this class.""" + self._print_info_head(shell=False) + self._print_info_body(shell=False) + print(" | Number of depths:........... " + str(self.get_depths())) + print(" | Top-Bottom resolution:...... " + str(self.get_tbres())) - :param bool shell: True for human readable style otherwise shell style - """ - super()._print_info_body(shell) - if shell: - print("depths=" + str(self.get_depths())) - print("tbres=" + str(self.get_tbres())) - else: - print(" | Number of depths:........... " + str(self.get_depths())) - print(" | Top-Bottom resolution:...... " + str(self.get_tbres())) + def print_shell_info(self): + """Print information about this class in shell style""" + self._print_info_head(shell=True) + self._print_info_body(shell=True) + print("depths=" + str(self.get_depths())) + print("tbres=" + str(self.get_tbres())) ############################################################################### @@ -870,53 +895,40 @@ def get_number_of_volumes(self): number_of_holes = property(fget=get_number_of_holes, fset=set_number_of_holes) number_of_volumes = property(fget=get_number_of_volumes, fset=set_number_of_volumes) - def _print_info_body(self, shell=False): - """Print information about this class (body part). + def print_info(self): + """Print information about this class in human readable style""" + print( + " +-------------------- Metadata information ----------------------------------+" # noqa: E501 + ) + print(" | Is map 3d .................. " + str(self.get_3d_info())) + print(" | Number of points ........... " + str(self.get_number_of_points())) + print(" | Number of lines ............ " + str(self.get_number_of_lines())) + print(" | Number of boundaries ....... " + str(self.get_number_of_boundaries())) + print(" | Number of centroids ........ " + str(self.get_number_of_centroids())) + print(" | Number of faces ............ " + str(self.get_number_of_faces())) + print(" | Number of kernels .......... " + str(self.get_number_of_kernels())) + print(" | Number of primitives ....... " + str(self.get_number_of_primitives())) + print(" | Number of nodes ............ " + str(self.get_number_of_nodes())) + print(" | Number of areas ............ " + str(self.get_number_of_areas())) + print(" | Number of islands .......... " + str(self.get_number_of_islands())) + print(" | Number of holes ............ " + str(self.get_number_of_holes())) + print(" | Number of volumes .......... " + str(self.get_number_of_volumes())) - :param bool shell: True for human readable style otherwise shell style - """ - if shell: - print("is_3d=" + str(self.get_3d_info())) - print("points=" + str(self.get_number_of_points())) - print("lines=" + str(self.get_number_of_lines())) - print("boundaries=" + str(self.get_number_of_boundaries())) - print("centroids=" + str(self.get_number_of_centroids())) - print("faces=" + str(self.get_number_of_faces())) - print("kernels=" + str(self.get_number_of_kernels())) - print("primitives=" + str(self.get_number_of_primitives())) - print("nodes=" + str(self.get_number_of_nodes())) - print("areas=" + str(self.get_number_of_areas())) - print("islands=" + str(self.get_number_of_islands())) - print("holes=" + str(self.get_number_of_holes())) - print("volumes=" + str(self.get_number_of_volumes())) - else: - print(" | Is map 3d .................. " + str(self.get_3d_info())) - print(" | Number of points ........... " + str(self.get_number_of_points())) - print(" | Number of lines ............ " + str(self.get_number_of_lines())) - print( - " | Number of boundaries ....... " - + str(self.get_number_of_boundaries()) - ) - print( - " | Number of centroids ........ " + str(self.get_number_of_centroids()) - ) - print(" | Number of faces ............ " + str(self.get_number_of_faces())) - print( - " | Number of kernels .......... " + str(self.get_number_of_kernels()) - ) - print( - " | Number of primitives ....... " - + str(self.get_number_of_primitives()) - ) - print(" | Number of nodes ............ " + str(self.get_number_of_nodes())) - print(" | Number of areas ............ " + str(self.get_number_of_areas())) - print( - " | Number of islands .......... " + str(self.get_number_of_islands()) - ) - print(" | Number of holes ............ " + str(self.get_number_of_holes())) - print( - " | Number of volumes .......... " + str(self.get_number_of_volumes()) - ) + def print_shell_info(self): + """Print information about this class in shell style""" + print("is_3d=" + str(self.get_3d_info())) + print("points=" + str(self.get_number_of_points())) + print("lines=" + str(self.get_number_of_lines())) + print("boundaries=" + str(self.get_number_of_boundaries())) + print("centroids=" + str(self.get_number_of_centroids())) + print("faces=" + str(self.get_number_of_faces())) + print("kernels=" + str(self.get_number_of_kernels())) + print("primitives=" + str(self.get_number_of_primitives())) + print("nodes=" + str(self.get_number_of_nodes())) + print("areas=" + str(self.get_number_of_areas())) + print("islands=" + str(self.get_number_of_islands())) + print("holes=" + str(self.get_number_of_holes())) + print("volumes=" + str(self.get_number_of_volumes())) ############################################################################### @@ -1034,13 +1046,11 @@ def get_number_of_maps(self): def print_info(self): """Print information about this class in human readable style""" - self._print_info_head(shell=False) self._print_info_body(shell=False) self._print_info_tail(shell=False) def print_shell_info(self): """Print information about this class in shell style""" - self._print_info_head(shell=True) self._print_info_body(shell=True) self._print_info_tail(shell=True) @@ -1056,6 +1066,12 @@ def _print_info_head(self, shell=False): " +-------------------- Metadata information ----------------------------------+" # noqa: E501 ) + def _print_info_body(self, shell=False): + """Print information about this class (body part). + + :param bool shell: True for human readable style otherwise shell style + """ + def _print_info_tail(self, shell=False): """Print information about this class (tail part). @@ -1476,6 +1492,16 @@ def get_semantic_labels(self): number_of_semantic_labels = property(fget=get_number_of_semantic_labels) semantic_labels = property(fget=get_semantic_labels) + def print_info(self): + """Print information about this class in human readable style""" + self._print_info_head(shell=False) + super().print_info() + + def print_shell_info(self): + """Print information about this class in shell style""" + self._print_info_head(shell=True) + super().print_shell_info() + def _print_info_body(self, shell=False): """Print information about this class (body part). @@ -1562,6 +1588,8 @@ class STR3DSMetadata(STDSRasterMetadataBase): | Command history: >>> meta.print_shell_info() raster3d_register=None + tbres_min=None + tbres_max=None nsres_min=None nsres_max=None ewres_min=None @@ -1570,8 +1598,6 @@ class STR3DSMetadata(STDSRasterMetadataBase): min_max=None max_min=None max_max=None - tbres_min=None - tbres_max=None aggregation_type=None number_of_maps=None @@ -1624,6 +1650,16 @@ def get_tbres_max(self): tbres_min = property(fget=get_tbres_min) tbres_max = property(fget=get_tbres_max) + def print_info(self): + """Print information about this class in human readable style""" + self._print_info_head(shell=False) + super().print_info() + + def print_shell_info(self): + """Print information about this class in shell style""" + self._print_info_head(shell=True) + super().print_shell_info() + def _print_info_body(self, shell=False): """Print information about this class (body part). @@ -1889,6 +1925,16 @@ def get_number_of_volumes(self): number_of_holes = property(fget=get_number_of_holes) number_of_volumes = property(fget=get_number_of_volumes) + def print_info(self): + """Print information about this class in human readable style""" + self._print_info_head(shell=False) + super().print_info() + + def print_shell_info(self): + """Print information about this class in shell style""" + self._print_info_head(shell=True) + super().print_shell_info() + def _print_info_body(self, shell=False): """Print information about this class (body part). From bd39db7082f3b6d87c4066a6c1e1484974a10394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sun, 22 Sep 2024 18:34:00 -0400 Subject: [PATCH 081/209] grass.temporal: Remove expected failures for tests fixed by #4328 (#4364) --- temporal/t.connect/testsuite/test_distr_tgis_db_raster.py | 3 +-- temporal/t.connect/testsuite/test_distr_tgis_db_raster3d.py | 3 +-- temporal/t.connect/testsuite/test_distr_tgis_db_vector.py | 3 +-- temporal/t.rast.series/testsuite/test_series.py | 1 - 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/temporal/t.connect/testsuite/test_distr_tgis_db_raster.py b/temporal/t.connect/testsuite/test_distr_tgis_db_raster.py index 6e4d76b26c5..412a926f01d 100644 --- a/temporal/t.connect/testsuite/test_distr_tgis_db_raster.py +++ b/temporal/t.connect/testsuite/test_distr_tgis_db_raster.py @@ -13,7 +13,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule -from grass.gunittest.utils import silent_rmtree, xfail_windows +from grass.gunittest.utils import silent_rmtree class TestRasterExtraction(TestCase): @@ -254,7 +254,6 @@ def test_strds_info(self): module=info, reference=tinfo_string, precision=2, sep="=" ) - @xfail_windows def test_raster_info(self): self.runModule("g.mapset", mapset="test3") tinfo_string = """id=a1@test1 diff --git a/temporal/t.connect/testsuite/test_distr_tgis_db_raster3d.py b/temporal/t.connect/testsuite/test_distr_tgis_db_raster3d.py index f9b4df76d88..23bc11c271e 100644 --- a/temporal/t.connect/testsuite/test_distr_tgis_db_raster3d.py +++ b/temporal/t.connect/testsuite/test_distr_tgis_db_raster3d.py @@ -13,7 +13,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule -from grass.gunittest.utils import silent_rmtree, xfail_windows +from grass.gunittest.utils import silent_rmtree class testRaster3dExtraction(TestCase): @@ -242,7 +242,6 @@ def test_strds_info(self): module=info, reference=tinfo_string, precision=2, sep="=" ) - @xfail_windows def test_raster_info(self): self.runModule("g.mapset", mapset="test3d3") tinfo_string = """id=a1@test3d1 diff --git a/temporal/t.connect/testsuite/test_distr_tgis_db_vector.py b/temporal/t.connect/testsuite/test_distr_tgis_db_vector.py index 7184fd32cb5..fd26cc93e26 100644 --- a/temporal/t.connect/testsuite/test_distr_tgis_db_vector.py +++ b/temporal/t.connect/testsuite/test_distr_tgis_db_vector.py @@ -13,7 +13,7 @@ from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule -from grass.gunittest.utils import silent_rmtree, xfail_windows +from grass.gunittest.utils import silent_rmtree class TestRasterExtraction(TestCase): @@ -259,7 +259,6 @@ def test_stvds_info(self): module=info, reference=tinfo_string, precision=2, sep="=" ) - @xfail_windows def testv_vector_info(self): self.runModule("g.mapset", mapset="testvect3") tinfo_string = """id=a1@testvect1 diff --git a/temporal/t.rast.series/testsuite/test_series.py b/temporal/t.rast.series/testsuite/test_series.py index 8070b4de44b..99fe69d4352 100644 --- a/temporal/t.rast.series/testsuite/test_series.py +++ b/temporal/t.rast.series/testsuite/test_series.py @@ -67,7 +67,6 @@ def tearDownClass(cls): cls.runModule("g.remove", flags="f", type="raster", name="series_minimum_2") cls.runModule("g.remove", flags="f", type="raster", name="series_quantile") - @xfail_windows def test_time_stamp(self): self.assertModule( "t.rast.series", From 6325a18d5ffee998422fcf9d94f7b61f58281260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Mon, 23 Sep 2024 06:45:53 -0400 Subject: [PATCH 082/209] CI(OSGeo4W): Run pytest tests on Windows (#4366) --- .github/workflows/osgeo4w.yml | 17 +++++++++++++++++ .../tests/g_mapsets_list_format_test.py | 9 +++++++++ .../jupyter/tests/grass_jupyter_session_test.py | 10 ++++++++++ .../grass/jupyter/tests/timeseriesmap_test.py | 5 +++++ 4 files changed, 41 insertions(+) diff --git a/.github/workflows/osgeo4w.yml b/.github/workflows/osgeo4w.yml index 79a44937755..027cecebf21 100644 --- a/.github/workflows/osgeo4w.yml +++ b/.github/workflows/osgeo4w.yml @@ -66,9 +66,13 @@ jobs: pdal-devel pdcurses proj-devel + python3-core + python3-jupyter python3-matplotlib python3-numpy + python3-pip python3-ply + python3-pytest python3-pywin32 python3-wxpython regex-devel @@ -98,6 +102,19 @@ jobs: shell: msys2 {0} run: .github/workflows/test_simple.sh + - name: Install pytest plugins + run: python -m pip install pytest-timeout + shell: cmd /D /E:ON /V:OFF /S /C "CALL C:/OSGeo4W/OSGeo4W.bat "{0}"" + - name: Run pytest with a single worker + run: | + call %OSGEO4W_ROOT%\opt\grass\etc\env.bat + set PYTHONPATH=%GISBASE%\etc\python;%PYTHONPATH% + path %GISBASE%\lib;%GISBASE%\bin;%PATH% + pytest --verbose --color=yes ^ + --durations=0 --durations-min=0.5 ^ + -ra . + shell: cmd /D /E:ON /V:OFF /S /C "CALL C:/OSGeo4W/OSGeo4W.bat "{0}"" + - name: Run tests run: .github/workflows/test_thorough.bat 'C:\OSGeo4W\opt\grass\grass85.bat' 'C:\OSGeo4W\bin\python3' diff --git a/general/g.mapsets/tests/g_mapsets_list_format_test.py b/general/g.mapsets/tests/g_mapsets_list_format_test.py index 79555085bb0..05fe946a6ae 100644 --- a/general/g.mapsets/tests/g_mapsets_list_format_test.py +++ b/general/g.mapsets/tests/g_mapsets_list_format_test.py @@ -14,6 +14,7 @@ """Test parsing and structure of CSV and JSON outputs from g.mapsets""" import json +import sys import pytest import grass.script as gs from grass.script import utils as gutils @@ -30,6 +31,10 @@ def _check_parsed_list(mapsets, text, sep="|"): assert text == sep.join(mapsets) + "\n" +@pytest.mark.xfail( + sys.platform == "win32", + reason="universal_newlines or text subprocess option not used", +) @pytest.mark.parametrize("separator", SEPARATORS) def test_plain_list_output(simple_dataset, separator): """Test that the separators are properly applied with list flag""" @@ -38,6 +43,10 @@ def test_plain_list_output(simple_dataset, separator): _check_parsed_list(mapsets, text, gutils.separator(separator)) +@pytest.mark.xfail( + sys.platform == "win32", + reason="universal_newlines or text subprocess option not used", +) @pytest.mark.parametrize("separator", SEPARATORS) def test_plain_print_output(simple_dataset, separator): """Test that the separators are properly applied with print flag""" diff --git a/python/grass/jupyter/tests/grass_jupyter_session_test.py b/python/grass/jupyter/tests/grass_jupyter_session_test.py index 7b6bc89e4ed..fd725303844 100644 --- a/python/grass/jupyter/tests/grass_jupyter_session_test.py +++ b/python/grass/jupyter/tests/grass_jupyter_session_test.py @@ -4,6 +4,8 @@ import os import sys +import pytest + # All init tests change the global environment, but we use a separate process # only when it is necessary. @@ -20,6 +22,10 @@ def run_in_subprocess(file): return process.stdout +@pytest.mark.xfail( + sys.platform == "win32", + reason="tmp_path string in interpolated code should be escaped or use raw strings", +) def test_init_finish(tmp_path): """Check that init function works with an explicit session finish""" location = "test" @@ -42,6 +48,10 @@ def test_init_finish(tmp_path): assert not os.path.exists(session_file), f"Session file {session_file} not deleted" +@pytest.mark.xfail( + sys.platform == "win32", + reason="tmp_path string in interpolated code should be escaped or use raw strings", +) def test_init_with_auto_finish(tmp_path): """Check that init function works with an implicit session finish""" location = "test" diff --git a/python/grass/jupyter/tests/timeseriesmap_test.py b/python/grass/jupyter/tests/timeseriesmap_test.py index d65f7fcb700..c4e20f7704e 100644 --- a/python/grass/jupyter/tests/timeseriesmap_test.py +++ b/python/grass/jupyter/tests/timeseriesmap_test.py @@ -1,6 +1,7 @@ """Test TimeSeriesMap functions""" from pathlib import Path +import sys import pytest @@ -66,6 +67,10 @@ def test_render_layers(space_time_raster_dataset, fill_gaps): assert Path(filename).is_file() +@pytest.mark.xfail( + sys.platform == "win32", + reason="DejaVuSans.ttf file isn't found and not installed with GRASS", +) @pytest.mark.needs_solo_run def test_save(space_time_raster_dataset, tmp_path): """Test returns from animate and time_slider are correct object types""" From c32dd525746f0674617cb5595d93b9e3cb6d7677 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Mon, 23 Sep 2024 09:40:57 -0400 Subject: [PATCH 083/209] checks: Replace bare except (Flake8 E722) in po stats script (#4354) This addresses the PEP8 style error of mentioning specific exceptions (Flake8 E722) by specifying the exception type in the except clause within the writejson function in grass_po_stats.py. Now, bare except is replaced by OSError to catch only OS-related exceptions because os.remove() can raise various OS-related exceptions such as FileNotFoundError or PermissionError. Additionally, it confirms that no other common Flake8 errors (E122, E128, E231, E401) are present in the file by removing the other ignores. --- .flake8 | 1 - locale/grass_po_stats.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.flake8 b/.flake8 index ecea7b82a0b..7092b7d15e3 100644 --- a/.flake8 +++ b/.flake8 @@ -24,7 +24,6 @@ per-file-ignores = imagery/i.atcorr/create_iwave.py: F632, F821, W293 doc/python/m.distance.py: E501 doc/gui/wxpython/example/dialogs.py: F401 - locale/grass_po_stats.py: E122, E128, E231, E401, E722 gui/scripts/d.wms.py: E501 gui/wxpython/core/gconsole.py: E722 gui/wxpython/core/render.py: E722 diff --git a/locale/grass_po_stats.py b/locale/grass_po_stats.py index b5f15026691..32e3f449cb3 100644 --- a/locale/grass_po_stats.py +++ b/locale/grass_po_stats.py @@ -144,7 +144,7 @@ def writejson(stats, outfile): fout.close() try: os.remove("messages.mo") - except: + except OSError: pass From 25afbfbd0e6a80823827c3767920204f9bab123e Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 23 Sep 2024 10:56:28 -0400 Subject: [PATCH 084/209] g.version: Add tests covering different outputs (#4219) This adds tests for different outputs of the g.version tool using pytest. --- general/g.version/tests/conftest.py | 17 +++++ general/g.version/tests/g_version_test.py | 83 +++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 general/g.version/tests/conftest.py create mode 100644 general/g.version/tests/g_version_test.py diff --git a/general/g.version/tests/conftest.py b/general/g.version/tests/conftest.py new file mode 100644 index 00000000000..e4357b2f672 --- /dev/null +++ b/general/g.version/tests/conftest.py @@ -0,0 +1,17 @@ +import os +import pytest +import grass.script as gs + + +@pytest.fixture(scope="module") +def session(tmp_path_factory): + """Set up a GRASS session for the tests.""" + tmp_path = tmp_path_factory.mktemp("grass_session") + project = "test_project" + + # Create a test location + gs.create_project(tmp_path, project) + + # Initialize the GRASS session + with gs.setup.init(tmp_path / project, env=os.environ.copy()) as session: + yield session diff --git a/general/g.version/tests/g_version_test.py b/general/g.version/tests/g_version_test.py new file mode 100644 index 00000000000..805518382a2 --- /dev/null +++ b/general/g.version/tests/g_version_test.py @@ -0,0 +1,83 @@ +import grass.script as gs + + +def test_g_version_no_flag(session): + """Test that g.version output contains the word 'GRASS'.""" + output = gs.read_command("g.version", env=session.env).strip() + assert ( + "GRASS" in output + ), "Expected 'GRASS' in g.version output, but it was not found." + + +def test_c_flag(session): + """Test the output of g.version -c for Copyright and License Statement.""" + expected_text = "Copyright and License Statement" + output = gs.read_command("g.version", flags="c", env=session.env).strip() + assert ( + expected_text in output + ), f"Expected '{expected_text}' in g.version -c output, but got: '{output}'" + + +def test_e_flag(session): + """Test that g.version -e contains the expected keys.""" + expected_keys = ["PROJ:", "GDAL/OGR:", "SQLite:"] + output = gs.read_command("g.version", flags="e", env=session.env).strip() + for key in expected_keys: + assert ( + key in output + ), f"Expected key '{key}' in g.version -e output, but it was not found." + + +def test_b_flag(session): + """Test that g.version -b output contains the word 'GRASS'.""" + output = gs.read_command("g.version", flags="b", env=session.env).strip() + assert ( + "GRASS" in output + ), "Expected 'GRASS' in g.version -b output, but it was not found." + + +def test_g_flag(session): + """Test that g.version -g contains the expected keys.""" + expected_keys = [ + "version", + "date", + "revision", + "build_date", + "build_platform", + "build_off_t_size", + ] + output = gs.parse_command("g.version", flags="g", env=session.env) + for key in expected_keys: + assert ( + key in output + ), f"Expected key '{key}' in g.version -g output, but it was not found." + + +def test_r_flag(session): + """Test that g.version -r contains the expected keys.""" + expected_texts = ["libgis revision:", "libgis date:"] + output = gs.read_command("g.version", flags="r", env=session.env).strip() + for text in expected_texts: + assert ( + text in output + ), f"Expected key '{text}' in g.version -r output, but it was not found." + + +def test_x_flag(session): + """Test that g.version -x output has paired curly brackets.""" + output = gs.read_command("g.version", flags="x", env=session.env).strip() + + def curly_brackets_paired(text): + counter = 0 + for character in text: + if character == "{": + counter += 1 + elif character == "}": + counter -= 1 + if counter < 0: + return False + return counter == 0 + + assert curly_brackets_paired( + output + ), "Curly brackets are not properly paired in the g.version -x output." From 9e8874c5e7f8093ec9bd8d1590043e0f58c3671c Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 23 Sep 2024 16:59:17 -0400 Subject: [PATCH 085/209] ps.map: Fix memory leak issue (#4369) This addresses resource leak issue identified by Coverity Scan (CID : 1207906). Uses Vect_destroy_cats_struct() to destroy Cats and avoid the memory leak issue. --- ps/ps.map/ps_vpoints.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ps/ps.map/ps_vpoints.c b/ps/ps.map/ps_vpoints.c index 80b29a349b1..cd320b46f11 100644 --- a/ps/ps.map/ps_vpoints.c +++ b/ps/ps.map/ps_vpoints.c @@ -268,5 +268,6 @@ int PS_vpoints_plot(struct Map_info *P_map, int vec) } /* for (line) */ fprintf(PS.fp, "\n"); + Vect_destroy_cats_struct(Cats); return 0; } From b35b1c36db93f8c85d7a26b0cee3f7616f4e8b70 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 17:06:45 -0400 Subject: [PATCH 086/209] CI(deps): Lock file maintenance (#4365) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 257ec2317b7..fcda6ed01dd 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1725234343, - "narHash": "sha256-+ebgonl3NbiKD2UD0x4BszCZQ6sTfL4xioaM49o5B3Y=", + "lastModified": 1726153070, + "narHash": "sha256-HO4zgY0ekfwO5bX0QH/3kJ/h4KvUDFZg8YpkNwIbg1U=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "567b938d64d4b4112ee253b9274472dc3a346eb6", + "rev": "bcef6817a8b2aa20a5a6dbb19b43e63c5bf8619a", "type": "github" }, "original": { @@ -19,11 +19,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1725194671, - "narHash": "sha256-tLGCFEFTB5TaOKkpfw3iYT9dnk4awTP/q4w+ROpMfuw=", + "lastModified": 1726871744, + "narHash": "sha256-V5LpfdHyQkUF7RfOaDPrZDP+oqz88lTJrMT1+stXNwo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b833ff01a0d694b910daca6e2ff4a3f26dee478c", + "rev": "a1d92660c6b3b7c26fb883500a80ea9d33321be2", "type": "github" }, "original": { From c266f46ba50090bb4ad2f08ad4e3855ff42909c5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 21:28:14 +0000 Subject: [PATCH 087/209] CI(deps): Update dependency bandit to v1.7.10 (#4370) --- .github/workflows/python-code-quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 92ef7d788b2..aed00117956 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -34,7 +34,7 @@ jobs: # renovate: datasource=pypi depName=pylint PYLINT_VERSION: "2.12.2" # renovate: datasource=pypi depName=bandit - BANDIT_VERSION: "1.7.9" + BANDIT_VERSION: "1.7.10" # renovate: datasource=pypi depName=ruff RUFF_VERSION: "0.6.7" From c593eb02da0112e7b118904245c20915ccc4148e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Mon, 23 Sep 2024 20:56:39 -0400 Subject: [PATCH 088/209] docker: Add liblapacke-dev package to Ubuntu builds (#4371) Adds liblapacke-dev package that was added to the apt.txt of the grass-addons repo. --- Dockerfile | 1 + docker/ubuntu/Dockerfile | 1 + 2 files changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index c6366eeb873..6ea64aadab7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,6 +41,7 @@ ARG GRASS_RUN_PACKAGES="build-essential \ libgsl27 \ libjpeg-turbo8 \ libjsoncpp-dev \ + liblapacke-dev \ libmagic1 \ libmagic-mgc \ libncurses5 \ diff --git a/docker/ubuntu/Dockerfile b/docker/ubuntu/Dockerfile index c6366eeb873..6ea64aadab7 100644 --- a/docker/ubuntu/Dockerfile +++ b/docker/ubuntu/Dockerfile @@ -41,6 +41,7 @@ ARG GRASS_RUN_PACKAGES="build-essential \ libgsl27 \ libjpeg-turbo8 \ libjsoncpp-dev \ + liblapacke-dev \ libmagic1 \ libmagic-mgc \ libncurses5 \ From 16de4d31526a149f0f70e23ba50b85a223d351c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Mon, 23 Sep 2024 21:16:49 -0400 Subject: [PATCH 089/209] grass.jupyter: Fix session tests on Windows (#4368) The interpolated path strings aren't escaped when evaluated, so using a raw string allows C:\Users to not have an invalid \U escape sequence. --- .../tests/grass_jupyter_session_test.py | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/python/grass/jupyter/tests/grass_jupyter_session_test.py b/python/grass/jupyter/tests/grass_jupyter_session_test.py index fd725303844..17b6e7fbf5d 100644 --- a/python/grass/jupyter/tests/grass_jupyter_session_test.py +++ b/python/grass/jupyter/tests/grass_jupyter_session_test.py @@ -4,8 +4,6 @@ import os import sys -import pytest - # All init tests change the global environment, but we use a separate process # only when it is necessary. @@ -22,10 +20,6 @@ def run_in_subprocess(file): return process.stdout -@pytest.mark.xfail( - sys.platform == "win32", - reason="tmp_path string in interpolated code should be escaped or use raw strings", -) def test_init_finish(tmp_path): """Check that init function works with an explicit session finish""" location = "test" @@ -33,8 +27,8 @@ def test_init_finish(tmp_path): import os import grass.script as gs import grass.jupyter as gj -gs.core._create_location_xy("{tmp_path}", "{location}") -session = gj.init("{tmp_path / location}") +gs.core._create_location_xy(r"{tmp_path}", r"{location}") +session = gj.init(r"{tmp_path / location}") gs.read_command("g.region", flags="p") print(os.environ["GISRC"]) session.finish() @@ -48,10 +42,6 @@ def test_init_finish(tmp_path): assert not os.path.exists(session_file), f"Session file {session_file} not deleted" -@pytest.mark.xfail( - sys.platform == "win32", - reason="tmp_path string in interpolated code should be escaped or use raw strings", -) def test_init_with_auto_finish(tmp_path): """Check that init function works with an implicit session finish""" location = "test" @@ -59,8 +49,8 @@ def test_init_with_auto_finish(tmp_path): import os import grass.script as gs import grass.jupyter as gj -gs.core._create_location_xy("{tmp_path}", "{location}") -session = gj.init("{tmp_path / location}") +gs.core._create_location_xy(r"{tmp_path}", r"{location}") +session = gj.init(r"{tmp_path / location}") print(os.environ["GISRC"]) """ From 04cc9ead399a85475b5390741645a7e56b39f7a8 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Mon, 23 Sep 2024 21:41:28 -0400 Subject: [PATCH 090/209] checks: Replace bare except (Flake8 E722) in wxGUI/core (#4367) This addresses the PEP8 style error E722 by specifying exception types in all bare except clauses found in wxGUI/core. Unclear cases use Exception. --------- Co-authored-by: Vaclav Petras --- .flake8 | 6 ------ gui/wxpython/core/gconsole.py | 2 +- gui/wxpython/core/render.py | 2 +- gui/wxpython/core/settings.py | 4 ++-- gui/wxpython/core/toolboxes.py | 2 +- gui/wxpython/core/utils.py | 10 +++++----- gui/wxpython/core/workspace.py | 6 +++--- 7 files changed, 13 insertions(+), 19 deletions(-) diff --git a/.flake8 b/.flake8 index 7092b7d15e3..af8a021bd4c 100644 --- a/.flake8 +++ b/.flake8 @@ -25,12 +25,6 @@ per-file-ignores = doc/python/m.distance.py: E501 doc/gui/wxpython/example/dialogs.py: F401 gui/scripts/d.wms.py: E501 - gui/wxpython/core/gconsole.py: E722 - gui/wxpython/core/render.py: E722 - gui/wxpython/core/settings.py: E722 - gui/wxpython/core/toolboxes.py: E722 - gui/wxpython/core/utils.py: E722 - gui/wxpython/core/workspace.py: E722 gui/wxpython/datacatalog/tree.py: E731, E402 gui/wxpython/dbmgr/base.py: E722 gui/wxpython/dbmgr/dialogs.py: E722 diff --git a/gui/wxpython/core/gconsole.py b/gui/wxpython/core/gconsole.py index bad4aac29cd..7575c401c98 100644 --- a/gui/wxpython/core/gconsole.py +++ b/gui/wxpython/core/gconsole.py @@ -691,7 +691,7 @@ def load_source(modname, filename): if len(command) == 1 and not skipInterface: try: task = gtask.parse_interface(command[0]) - except: + except Exception: task = None else: task = None diff --git a/gui/wxpython/core/render.py b/gui/wxpython/core/render.py index b98e4323578..5b3e3096043 100644 --- a/gui/wxpython/core/render.py +++ b/gui/wxpython/core/render.py @@ -1237,7 +1237,7 @@ def SetRegion(self, windres=False, windres3=False): return grass_region - except: + except Exception: return None def GetListOfLayers( diff --git a/gui/wxpython/core/settings.py b/gui/wxpython/core/settings.py index 45620220aed..2b2d3b28526 100644 --- a/gui/wxpython/core/settings.py +++ b/gui/wxpython/core/settings.py @@ -110,7 +110,7 @@ def _generateLocale(self): self.locs.sort() # Add a default choice to not override system locale self.locs.insert(0, "system") - except: + except Exception: # No NLS self.locs = ["system"] @@ -992,7 +992,7 @@ def SaveToFile(self, settings=None): if not os.path.exists(dirPath): try: os.mkdir(dirPath) - except: + except OSError: GError(_("Unable to create settings directory")) return try: diff --git a/gui/wxpython/core/toolboxes.py b/gui/wxpython/core/toolboxes.py index ae6b1b6a0a6..e77010ff213 100644 --- a/gui/wxpython/core/toolboxes.py +++ b/gui/wxpython/core/toolboxes.py @@ -209,7 +209,7 @@ def getMenudataFile(userRootFile, newFile, fallback): fh.write(xml) fh.close() return menudataFile - except: + except Exception: _debug( 2, ( diff --git a/gui/wxpython/core/utils.py b/gui/wxpython/core/utils.py index 10d6dca2759..4be6c18e2a2 100644 --- a/gui/wxpython/core/utils.py +++ b/gui/wxpython/core/utils.py @@ -77,7 +77,7 @@ def GetTempfile(pref=None): return os.path.join(pref, file) else: return tempfile - except: + except Exception: return None @@ -255,7 +255,7 @@ def ListOfCatsToRange(cats): try: cats = list(map(int, cats)) - except: + except ValueError: return catstr i = 0 @@ -579,7 +579,7 @@ def GetListOfLocations(dbase): os.path.join(location, "*") ): listOfLocations.append(os.path.basename(location)) - except: + except OSError: pass ListSortLower(listOfLocations) @@ -632,7 +632,7 @@ def _getGDALFormats(): """Get dictionary of available GDAL drivers""" try: ret = grass.read_command("r.in.gdal", quiet=True, flags="f") - except: + except grass.CalledModuleError: ret = None return _parseFormats(ret), _parseFormats(ret, writableOnly=True) @@ -642,7 +642,7 @@ def _getOGRFormats(): """Get dictionary of available OGR drivers""" try: ret = grass.read_command("v.in.ogr", quiet=True, flags="f") - except: + except grass.CalledModuleError: ret = None return _parseFormats(ret), _parseFormats(ret, writableOnly=True) diff --git a/gui/wxpython/core/workspace.py b/gui/wxpython/core/workspace.py index 63f8b91cb89..9550aa73488 100644 --- a/gui/wxpython/core/workspace.py +++ b/gui/wxpython/core/workspace.py @@ -123,7 +123,7 @@ def __processFile(self): try: self.layerManager["pos"] = (posVal[0], posVal[1]) self.layerManager["size"] = (posVal[2], posVal[3]) - except: + except IndexError: pass # current working directory cwdPath = self.__getNodeText(node_lm, "cwd") @@ -155,7 +155,7 @@ def __processFile(self): try: pos = (posVal[0], posVal[1]) size = (posVal[2], posVal[3]) - except: + except IndexError: pos = None size = None # this happens on Windows when mapwindow is minimized when @@ -2019,7 +2019,7 @@ def _get_value(self, line): """Get value of element""" try: return line.strip(" ").split(" ")[1].strip(" ") - except: + except IndexError: return "" def _get_element(self, line): From ac664487845546c2b8b30ddbc15c503897eba262 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 07:15:05 -0400 Subject: [PATCH 091/209] CI(deps): Update pre-commit hook igorshubovych/markdownlint-cli to v0.42.0 (#4374) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e1f98c7a2a5..74423979b22 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -43,7 +43,7 @@ repos: - id: ruff args: [--fix, --preview] - repo: https://github.com/igorshubovych/markdownlint-cli - rev: v0.41.0 + rev: v0.42.0 hooks: - id: markdownlint-fix # Using this mirror lets us use mypyc-compiled black, which is about 2x faster From 234209ae04f45060534534a88c4eb377a9be131a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 17:04:38 -0400 Subject: [PATCH 092/209] CI(deps): Update github/codeql-action action to v3.26.9 (#4380) --- .github/workflows/codeql-analysis.yml | 4 ++-- .github/workflows/python-code-quality.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b4fb254d11d..bf07004bc82 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -56,7 +56,7 @@ jobs: if: ${{ matrix.language == 'c-cpp' }} - name: Initialize CodeQL - uses: github/codeql-action/init@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 + uses: github/codeql-action/init@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -81,6 +81,6 @@ jobs: run: .github/workflows/build_ubuntu-22.04.sh "${HOME}/install" - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 + uses: github/codeql-action/analyze@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index aed00117956..403d7393d0e 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -135,7 +135,7 @@ jobs: path: bandit.sarif - name: Upload SARIF File into Security Tab - uses: github/codeql-action/upload-sarif@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 + uses: github/codeql-action/upload-sarif@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 with: sarif_file: bandit.sarif From 8c671caeb0fa37744ff83e24645be0d8d40fff61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Tue, 24 Sep 2024 17:22:41 -0400 Subject: [PATCH 093/209] docker: Sort package lists and configure options in Dockerfiles (#4373) * docker: Sort packages and configure options in Ubuntu Dockerfiles * docker: Sort packages and configure options in debian Dockerfile * docker: Sort packages and configure options in Alpine Dockerfile * docker: Sort packages and configure options in Ubuntu wxgui Dockerfile --- Dockerfile | 104 +++++++++++++++++---------------- docker/alpine/Dockerfile | 36 ++++++------ docker/debian/Dockerfile | 24 ++++---- docker/ubuntu/Dockerfile | 104 +++++++++++++++++---------------- docker/ubuntu_wxgui/Dockerfile | 32 +++++----- 5 files changed, 156 insertions(+), 144 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6ea64aadab7..41fb3264c07 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,8 +19,9 @@ WORKDIR /tmp ARG GUI # Todo: re-consider required dev packages for addons (~400MB in dev packages) -ARG GRASS_RUN_PACKAGES="build-essential \ +ARG GRASS_RUN_PACKAGES="\ bison \ + build-essential \ bzip2 \ curl \ flex \ @@ -28,8 +29,6 @@ ARG GRASS_RUN_PACKAGES="build-essential \ gcc \ gdal-bin \ geos-bin \ - proj-bin \ - netcdf-bin \ git \ language-pack-en-base \ libcairo2 \ @@ -38,29 +37,29 @@ ARG GRASS_RUN_PACKAGES="build-essential \ libfftw3-dev \ libfreetype6 \ libgdal-dev \ + libgeos-dev \ + libgsl-dev \ libgsl27 \ libjpeg-turbo8 \ libjsoncpp-dev \ liblapacke-dev \ - libmagic1 \ libmagic-mgc \ + libmagic1 \ libncurses5 \ - libopenblas-dev \ + libomp-dev \ + libomp5 \ libopenblas-base \ + libopenblas-dev \ libopenjp2-7 \ - libomp5 \ - libomp-dev \ - libgeos-dev \ - libpdal-dev \ - libproj-dev \ - libpq-dev \ - libgsl-dev \ libpdal-base13 \ + libpdal-dev \ libpdal-plugin-hdf \ libpdal-plugins \ libpdal-util13 \ libpnglite0 \ + libpq-dev \ libpq5 \ + libproj-dev \ libpython3-all-dev \ libreadline8 \ libsqlite3-0 \ @@ -71,7 +70,9 @@ ARG GRASS_RUN_PACKAGES="build-essential \ mesa-utils \ moreutils \ ncurses-bin \ + netcdf-bin \ pdal \ + proj-bin \ proj-data \ python-is-python3 \ python3 \ @@ -87,56 +88,58 @@ ARG GRASS_RUN_PACKAGES="build-essential \ ENV GRASS_RUN_PACKAGES=${GRASS_RUN_PACKAGES} # Define build packages -ARG GRASS_BUILD_PACKAGES="cmake \ +ARG GRASS_BUILD_PACKAGES="\ + cmake \ libbz2-dev \ libcairo2-dev \ libfreetype6-dev \ - zlib1g-dev \ + libjpeg-dev \ + libncurses5-dev \ libnetcdf-dev \ libopenjp2-7-dev \ - libreadline-dev \ - libjpeg-dev \ libpnglite-dev \ + libreadline-dev \ libsqlite3-dev \ libtiff-dev \ libzstd-dev \ - libncurses5-dev \ mesa-common-dev \ zlib1g-dev \ " ENV GRASS_BUILD_PACKAGES=${GRASS_BUILD_PACKAGES} -ARG GRASS_CONFIG="--with-cxx \ +ARG GRASS_CONFIG="\ --enable-largefile \ - --with-proj-share=/usr/share/proj \ - --with-gdal=/usr/bin/gdal-config \ - --with-geos \ - --with-sqlite \ + --with-blas \ + --with-bzlib \ --with-cairo --with-cairo-ldflags=-lfontconfig \ - --with-freetype --with-freetype-includes=/usr/include/freetype2/ \ + --with-cxx \ --with-fftw \ - --with-postgres --with-postgres-includes=/usr/include/postgresql \ - --with-netcdf \ - --with-zstd \ - --with-bzlib \ - --with-pdal \ - --without-mysql \ - --with-blas \ + --with-freetype --with-freetype-includes=/usr/include/freetype2/ \ + --with-gdal=/usr/bin/gdal-config \ + --with-geos \ --with-lapack \ - --with-readline \ + --with-netcdf \ --with-odbc \ --with-openmp \ + --with-pdal \ + --with-postgres --with-postgres-includes=/usr/include/postgresql \ + --with-proj-share=/usr/share/proj \ + --with-readline \ + --with-sqlite \ + --with-zstd \ + --without-mysql \ " -ARG GRASS_PYTHON_PACKAGES="pip \ - setuptools \ - python-dateutil \ - python-magic \ - numpy \ +ARG GRASS_PYTHON_PACKAGES="\ Pillow \ - ply \ matplotlib \ + numpy \ + pip \ + ply \ psycopg2 \ + python-dateutil \ + python-magic \ + setuptools \ " ENV GRASS_PYTHON_PACKAGES=${GRASS_PYTHON_PACKAGES} @@ -148,31 +151,33 @@ ENV GRASS_CONFIG=${GRASS_CONFIG} FROM common_start as grass_with_gui -ARG GRASS_RUN_PACKAGES="${GRASS_RUN_PACKAGES} adwaita-icon-theme-full \ - libglu1-mesa \ - libgtk-3-0 \ - libnotify4 \ - libsdl2-2.0-0 \ - libxtst6 \ - librsvg2-common \ - gettext \ +ARG GRASS_RUN_PACKAGES="${GRASS_RUN_PACKAGES} \ + adwaita-icon-theme-full \ freeglut3 \ + gettext \ + libglu1-mesa \ libgstreamer-plugins-base1.0 \ + libgtk-3-0 \ libjpeg8 \ + libnotify4 \ libpng16-16 \ + librsvg2-common \ + libsdl2-2.0-0 \ libsm6 \ libtiff5 \ libwebkit2gtk-4.0 \ + libxtst6 \ " # librsvg2-common \ # (fix error (wxgui.py:7782): Gtk-WARNING **: 19:53:09.774: # Could not load a pixbuf from /org/gtk/libgtk/theme/Adwaita/assets/check-symbolic.svg. # This may indicate that pixbuf loaders or the mime database could not be found.) -ARG GRASS_BUILD_PACKAGES="${GRASS_BUILD_PACKAGES} adwaita-icon-theme-full \ +ARG GRASS_BUILD_PACKAGES="${GRASS_BUILD_PACKAGES} \ + adwaita-icon-theme-full \ + freeglut3-dev \ libgl1-mesa-dev \ libglu1-mesa-dev \ - freeglut3-dev \ libgstreamer-plugins-base1.0-dev \ libgtk-3-dev \ libjpeg-dev \ @@ -185,10 +190,11 @@ ARG GRASS_BUILD_PACKAGES="${GRASS_BUILD_PACKAGES} adwaita-icon-theme-full \ libxtst-dev \ " -ARG GRASS_CONFIG="${GRASS_CONFIG} --with-opengl \ - --with-x \ +ARG GRASS_CONFIG="${GRASS_CONFIG} \ --with-nls \ + --with-opengl \ --with-readline \ + --with-x \ " ARG GRASS_PYTHON_PACKAGES="${GRASS_PYTHON_PACKAGES} wxPython" # If you do not use any Gnome Accessibility features, to suppress warning diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index a099617759c..b6dbebf6666 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -11,9 +11,9 @@ ARG PYTHON_VERSION=3 # List of packages to be installed (proj-data omitted: 570.04 MB) ENV GRASS_RUN_PACKAGES="\ attr \ - build-base \ bash \ bison \ + build-base \ bzip2 \ cairo \ curl \ @@ -29,15 +29,15 @@ ENV GRASS_RUN_PACKAGES="\ gdal-driver-JP2OpenJPEG \ gdal-driver-LIBKML \ gdal-driver-MSSQLSpatial \ - gdal-driver-netCDF \ gdal-driver-ODBC \ gdal-driver-PG \ gdal-driver-PNG \ gdal-driver-WMS \ + gdal-driver-netCDF \ gdal-tools \ - gettext \ geos \ geos-dev \ + gettext \ git \ gnutls \ jsoncpp \ @@ -52,15 +52,15 @@ ENV GRASS_RUN_PACKAGES="\ musl \ musl-utils \ ncurses \ - openjpeg \ openblas \ - py3-numpy \ - py3-pillow \ - python3 \ + openjpeg \ pdal \ pdal-dev \ postgresql15-client \ proj-util \ + py3-numpy \ + py3-pillow \ + python3 \ sqlite \ sqlite-libs \ subversion \ @@ -89,23 +89,23 @@ FROM common as build # set configuration options, without wxGUI ENV GRASS_CONFIG="\ --enable-largefile \ + --with-bzlib \ + --with-cairo --with-cairo-ldflags=-lfontconfig \ --with-cxx \ - --with-proj-share=/usr/share/proj \ + --with-fftw \ --with-gdal \ - --with-pdal \ --with-geos \ + --with-openmp \ + --with-pdal \ + --with-postgres --with-postgres-includes=/usr/include/postgresql \ + --with-proj-share=/usr/share/proj \ --with-sqlite \ - --with-bzlib \ --with-zstd \ - --with-cairo --with-cairo-ldflags=-lfontconfig \ - --with-fftw \ - --with-postgres --with-postgres-includes=/usr/include/postgresql \ - --with-openmp \ --without-freetype \ - --without-opengl \ - --without-nls \ --without-mysql \ + --without-nls \ --without-odbc \ + --without-opengl \ " # Set environmental variables for GRASS GIS compilation, without debug symbols @@ -132,13 +132,13 @@ ENV GRASS_BUILD_PACKAGES="\ libjpeg-turbo-dev \ libpng-dev \ libpq-dev \ - openjpeg-dev \ openblas-dev \ + openjpeg-dev \ pdal \ pdal-dev \ proj-dev \ - python3-dev \ py3-numpy-dev \ + python3-dev \ sqlite-dev \ tar \ tiff-dev \ diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile index 2ed59e1482e..8021ccf409e 100644 --- a/docker/debian/Dockerfile +++ b/docker/debian/Dockerfile @@ -18,8 +18,8 @@ WORKDIR /tmp RUN apt-get update && apt-get upgrade -y && \ apt-get install -y --no-install-recommends --no-install-suggests \ - build-essential \ bison \ + build-essential \ bzip2 \ cmake \ curl \ @@ -40,8 +40,8 @@ RUN apt-get update && apt-get upgrade -y && \ libgsl0-dev \ libjpeg-dev \ libjsoncpp-dev \ - libnetcdf-dev \ libncurses-dev \ + libnetcdf-dev \ libopenblas-dev \ libopenjp2-7 \ libopenjp2-7-dev \ @@ -153,24 +153,24 @@ ENV CXXFLAGS "$MYCXXFLAGS" ENV NUMTHREADS=4 RUN make distclean || echo "nothing to clean" RUN /src/grass_build/configure \ - --with-cxx \ --enable-largefile \ - --with-proj-share=/usr/share/proj \ - --with-gdal=/usr/bin/gdal-config \ - --with-geos \ - --with-sqlite \ + --with-bzlib \ --with-cairo --with-cairo-ldflags=-lfontconfig \ - --with-freetype --with-freetype-includes="/usr/include/freetype2/" \ + --with-cxx \ --with-fftw \ - --with-postgres --with-postgres-includes="/usr/include/postgresql" \ + --with-freetype --with-freetype-includes="/usr/include/freetype2/" \ + --with-gdal=/usr/bin/gdal-config \ + --with-geos \ --with-netcdf \ - --with-zstd \ - --with-bzlib \ --with-pdal \ + --with-postgres --with-postgres-includes="/usr/include/postgresql" \ + --with-proj-share=/usr/share/proj \ + --with-sqlite \ + --with-zstd \ --without-mysql \ --without-odbc \ - --without-openmp \ --without-opengl \ + --without-openmp \ && make -j $NUMTHREADS \ && make install && ldconfig diff --git a/docker/ubuntu/Dockerfile b/docker/ubuntu/Dockerfile index 6ea64aadab7..41fb3264c07 100644 --- a/docker/ubuntu/Dockerfile +++ b/docker/ubuntu/Dockerfile @@ -19,8 +19,9 @@ WORKDIR /tmp ARG GUI # Todo: re-consider required dev packages for addons (~400MB in dev packages) -ARG GRASS_RUN_PACKAGES="build-essential \ +ARG GRASS_RUN_PACKAGES="\ bison \ + build-essential \ bzip2 \ curl \ flex \ @@ -28,8 +29,6 @@ ARG GRASS_RUN_PACKAGES="build-essential \ gcc \ gdal-bin \ geos-bin \ - proj-bin \ - netcdf-bin \ git \ language-pack-en-base \ libcairo2 \ @@ -38,29 +37,29 @@ ARG GRASS_RUN_PACKAGES="build-essential \ libfftw3-dev \ libfreetype6 \ libgdal-dev \ + libgeos-dev \ + libgsl-dev \ libgsl27 \ libjpeg-turbo8 \ libjsoncpp-dev \ liblapacke-dev \ - libmagic1 \ libmagic-mgc \ + libmagic1 \ libncurses5 \ - libopenblas-dev \ + libomp-dev \ + libomp5 \ libopenblas-base \ + libopenblas-dev \ libopenjp2-7 \ - libomp5 \ - libomp-dev \ - libgeos-dev \ - libpdal-dev \ - libproj-dev \ - libpq-dev \ - libgsl-dev \ libpdal-base13 \ + libpdal-dev \ libpdal-plugin-hdf \ libpdal-plugins \ libpdal-util13 \ libpnglite0 \ + libpq-dev \ libpq5 \ + libproj-dev \ libpython3-all-dev \ libreadline8 \ libsqlite3-0 \ @@ -71,7 +70,9 @@ ARG GRASS_RUN_PACKAGES="build-essential \ mesa-utils \ moreutils \ ncurses-bin \ + netcdf-bin \ pdal \ + proj-bin \ proj-data \ python-is-python3 \ python3 \ @@ -87,56 +88,58 @@ ARG GRASS_RUN_PACKAGES="build-essential \ ENV GRASS_RUN_PACKAGES=${GRASS_RUN_PACKAGES} # Define build packages -ARG GRASS_BUILD_PACKAGES="cmake \ +ARG GRASS_BUILD_PACKAGES="\ + cmake \ libbz2-dev \ libcairo2-dev \ libfreetype6-dev \ - zlib1g-dev \ + libjpeg-dev \ + libncurses5-dev \ libnetcdf-dev \ libopenjp2-7-dev \ - libreadline-dev \ - libjpeg-dev \ libpnglite-dev \ + libreadline-dev \ libsqlite3-dev \ libtiff-dev \ libzstd-dev \ - libncurses5-dev \ mesa-common-dev \ zlib1g-dev \ " ENV GRASS_BUILD_PACKAGES=${GRASS_BUILD_PACKAGES} -ARG GRASS_CONFIG="--with-cxx \ +ARG GRASS_CONFIG="\ --enable-largefile \ - --with-proj-share=/usr/share/proj \ - --with-gdal=/usr/bin/gdal-config \ - --with-geos \ - --with-sqlite \ + --with-blas \ + --with-bzlib \ --with-cairo --with-cairo-ldflags=-lfontconfig \ - --with-freetype --with-freetype-includes=/usr/include/freetype2/ \ + --with-cxx \ --with-fftw \ - --with-postgres --with-postgres-includes=/usr/include/postgresql \ - --with-netcdf \ - --with-zstd \ - --with-bzlib \ - --with-pdal \ - --without-mysql \ - --with-blas \ + --with-freetype --with-freetype-includes=/usr/include/freetype2/ \ + --with-gdal=/usr/bin/gdal-config \ + --with-geos \ --with-lapack \ - --with-readline \ + --with-netcdf \ --with-odbc \ --with-openmp \ + --with-pdal \ + --with-postgres --with-postgres-includes=/usr/include/postgresql \ + --with-proj-share=/usr/share/proj \ + --with-readline \ + --with-sqlite \ + --with-zstd \ + --without-mysql \ " -ARG GRASS_PYTHON_PACKAGES="pip \ - setuptools \ - python-dateutil \ - python-magic \ - numpy \ +ARG GRASS_PYTHON_PACKAGES="\ Pillow \ - ply \ matplotlib \ + numpy \ + pip \ + ply \ psycopg2 \ + python-dateutil \ + python-magic \ + setuptools \ " ENV GRASS_PYTHON_PACKAGES=${GRASS_PYTHON_PACKAGES} @@ -148,31 +151,33 @@ ENV GRASS_CONFIG=${GRASS_CONFIG} FROM common_start as grass_with_gui -ARG GRASS_RUN_PACKAGES="${GRASS_RUN_PACKAGES} adwaita-icon-theme-full \ - libglu1-mesa \ - libgtk-3-0 \ - libnotify4 \ - libsdl2-2.0-0 \ - libxtst6 \ - librsvg2-common \ - gettext \ +ARG GRASS_RUN_PACKAGES="${GRASS_RUN_PACKAGES} \ + adwaita-icon-theme-full \ freeglut3 \ + gettext \ + libglu1-mesa \ libgstreamer-plugins-base1.0 \ + libgtk-3-0 \ libjpeg8 \ + libnotify4 \ libpng16-16 \ + librsvg2-common \ + libsdl2-2.0-0 \ libsm6 \ libtiff5 \ libwebkit2gtk-4.0 \ + libxtst6 \ " # librsvg2-common \ # (fix error (wxgui.py:7782): Gtk-WARNING **: 19:53:09.774: # Could not load a pixbuf from /org/gtk/libgtk/theme/Adwaita/assets/check-symbolic.svg. # This may indicate that pixbuf loaders or the mime database could not be found.) -ARG GRASS_BUILD_PACKAGES="${GRASS_BUILD_PACKAGES} adwaita-icon-theme-full \ +ARG GRASS_BUILD_PACKAGES="${GRASS_BUILD_PACKAGES} \ + adwaita-icon-theme-full \ + freeglut3-dev \ libgl1-mesa-dev \ libglu1-mesa-dev \ - freeglut3-dev \ libgstreamer-plugins-base1.0-dev \ libgtk-3-dev \ libjpeg-dev \ @@ -185,10 +190,11 @@ ARG GRASS_BUILD_PACKAGES="${GRASS_BUILD_PACKAGES} adwaita-icon-theme-full \ libxtst-dev \ " -ARG GRASS_CONFIG="${GRASS_CONFIG} --with-opengl \ - --with-x \ +ARG GRASS_CONFIG="${GRASS_CONFIG} \ --with-nls \ + --with-opengl \ --with-readline \ + --with-x \ " ARG GRASS_PYTHON_PACKAGES="${GRASS_PYTHON_PACKAGES} wxPython" # If you do not use any Gnome Accessibility features, to suppress warning diff --git a/docker/ubuntu_wxgui/Dockerfile b/docker/ubuntu_wxgui/Dockerfile index 36d33ffeb20..e15d5dcf478 100644 --- a/docker/ubuntu_wxgui/Dockerfile +++ b/docker/ubuntu_wxgui/Dockerfile @@ -29,8 +29,8 @@ WORKDIR /tmp RUN apt-get update && apt-get upgrade -y && \ apt-get install -y --no-install-recommends --no-install-suggests \ adwaita-icon-theme-full \ - build-essential \ bison \ + build-essential \ bzip2 \ cmake \ curl \ @@ -48,17 +48,17 @@ RUN apt-get update && apt-get upgrade -y && \ libfftw3-bin \ libfftw3-dev \ libfreetype6-dev \ - libgl1-mesa-dev \ libgdal-dev \ libgeos-dev \ + libgl1-mesa-dev \ libglu1-mesa-dev \ libgsl0-dev \ libgtk-3-0 \ libgtk-3-dev \ libjpeg-dev \ libjsoncpp-dev \ - libnetcdf-dev \ libncurses5-dev \ + libnetcdf-dev \ libnotify4 \ libopenblas-base \ libopenblas-dev \ @@ -68,8 +68,8 @@ RUN apt-get update && apt-get upgrade -y && \ libpq-dev \ libproj-dev \ libpython3-all-dev \ - librsvg2-common \ libreadline-dev \ + librsvg2-common \ libsdl2-2.0-0 \ libsqlite3-dev \ libtiff-dev \ @@ -191,26 +191,26 @@ ENV CXXFLAGS "$MYCXXFLAGS" ENV NUMTHREADS=4 RUN make distclean || echo "nothing to clean" RUN /src/grass_build/configure \ - --with-cxx \ --enable-largefile \ - --with-proj-share=/usr/share/proj \ - --with-gdal=/usr/bin/gdal-config \ - --with-geos \ - --with-sqlite \ + --with-bzlib \ --with-cairo --with-cairo-ldflags=-lfontconfig \ - --with-freetype --with-freetype-includes="/usr/include/freetype2/" \ + --with-cxx \ --with-fftw \ - --with-postgres --with-postgres-includes="/usr/include/postgresql" \ + --with-freetype --with-freetype-includes="/usr/include/freetype2/" \ + --with-gdal=/usr/bin/gdal-config \ + --with-geos \ --with-netcdf \ - --with-zstd \ - --with-bzlib \ + --with-nls \ --with-pdal \ + --with-postgres --with-postgres-includes="/usr/include/postgresql" \ + --with-proj-share=/usr/share/proj \ + --with-readline \ + --with-sqlite \ + --with-x \ + --with-zstd \ --without-mysql \ --without-odbc \ --without-openmp \ - --with-x \ - --with-nls \ - --with-readline \ && make -j $NUMTHREADS \ && make install && ldconfig From d99d840c160c8e90411d077e751dca9d0051b7b9 Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Tue, 24 Sep 2024 22:38:14 -0400 Subject: [PATCH 094/209] grass.jupyter: fix interactivemap tests (#4379) --- .../jupyter/testsuite/interactivemap_test.py | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/python/grass/jupyter/testsuite/interactivemap_test.py b/python/grass/jupyter/testsuite/interactivemap_test.py index 6b8a7379548..493578596b5 100644 --- a/python/grass/jupyter/testsuite/interactivemap_test.py +++ b/python/grass/jupyter/testsuite/interactivemap_test.py @@ -103,24 +103,26 @@ def test_query_button(self): # Create InteractiveMap with ipyleaflet backend interactive_map = gj.InteractiveMap(map_backend="ipyleaflet") interactive_map.add_raster("elevation") - interactive_map.add_vector("roadsmajor") - interactive_map.add_query_button() - self.assertIsNotNone(interactive_map.map) - self.assertTrue(interactive_map.query_mode is False) - # Toggle query button to activate - interactive_map.query_mode = True - self.assertTrue(interactive_map.query_mode) - # Toggle query button to deactivate - interactive_map.query_mode = False - self.assertFalse(interactive_map.query_mode) + button = interactive_map.setup_query_interface() + self.assertIsNotNone(interactive_map._controllers[button].query_raster((0, 0))) + + @unittest.skipIf(not can_import_ipyleaflet(), "Cannot import ipyleaflet") + def test_draw(self): + """Test the draw_computational_region method.""" + # Create InteractiveMap + interactive_map = gj.InteractiveMap(map_backend="ipyleaflet") + button = interactive_map.setup_drawing_interface() + interactive_map._controllers[button].activate() + self.assertIsNotNone(interactive_map._controllers[button].save_button_control) @unittest.skipIf(not can_import_ipyleaflet(), "Cannot import ipyleaflet") def test_draw_computational_region(self): """Test the draw_computational_region method.""" # Create InteractiveMap - interactive_map = gj.InteractiveMap() - interactive_map.draw_computational_region() - self.assertTrue(callable(interactive_map.draw_computational_region)) + interactive_map = gj.InteractiveMap(map_backend="ipyleaflet") + button = interactive_map.setup_computational_region_interface() + interactive_map._controllers[button].activate() + self.assertIsNotNone(interactive_map._controllers[button].save_button_control) if __name__ == "__main__": From 45a0486cdbd5d7e930aca16c4a6a6397e7f6d221 Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Tue, 24 Sep 2024 23:45:39 -0400 Subject: [PATCH 095/209] grass.app: Move mapset locking to the library (#4158) This moves the lock_mapset function to the library. It introduces only small changes to the code, i.e., proper refactoring and de-duplication in relation to the code elsewhere is still needed. However, this unifies the error handling to always raising a custom exception. It also fixes the reported user using the mapset (before always the current user, now, the owner of the lock file; for that, lock file is removed only after getting its owner). This also removes the debug message which I don't find particularly useful, for example it is currently misleading on Windows and it is relatively easy to confirm the actual existence in process manager when debugging. Change message wording to add clarity. Fix translatable message are fixed. Uses format function everywhere. Gets install path (GISBASE) automatically (requires caller to have environment set up which is likely a reasonable requirement at this point). Fixes order of reporting owner and deleting the file. Cleans up order of paths. --- lib/init/grass.py | 69 ++++----------------------------------- python/grass/app/data.py | 70 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 63 deletions(-) diff --git a/lib/init/grass.py b/lib/init/grass.py index 30c0a1a68ba..40312471e44 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -1281,65 +1281,6 @@ def set_language(grass_config_dir): gettext.install("grasslibs", gpath("locale")) -def lock_mapset(mapset_path, force_gislock_removal, user): - """Lock the mapset and return name of the lock file - - Behavior on error must be changed somehow; now it fatals but GUI case is - unresolved. - """ - if not os.path.exists(mapset_path): - fatal(_("Path '%s' doesn't exist") % mapset_path) - if not os.access(mapset_path, os.W_OK): - error = _("Path '%s' not accessible.") % mapset_path - stat_info = os.stat(mapset_path) - mapset_uid = stat_info.st_uid - if mapset_uid != os.getuid(): - # GTC %s is mapset's folder path - error = "%s\n%s" % ( - error, - _("You are not the owner of '%s'.") % mapset_path, - ) - fatal(error) - # Check for concurrent use - lockfile = os.path.join(mapset_path, ".gislock") - ret = call([gpath("etc", "lock"), lockfile, "%d" % os.getpid()]) - msg = None - if ret == 2: - if not force_gislock_removal: - msg = _( - "%(user)s is currently running GRASS in selected mapset" - " (file %(file)s found). Concurrent use not allowed.\n" - "You can force launching GRASS using -f flag" - " (note that you need permission for this operation)." - " Have another look in the processor " - "manager just to be sure..." - ) % {"user": user, "file": lockfile} - - else: - try_remove(lockfile) - message( - _( - "%(user)s is currently running GRASS in selected mapset" - " (file %(file)s found). Forcing to launch GRASS..." - ) - % {"user": user, "file": lockfile} - ) - elif ret != 0: - msg = ( - _("Unable to properly access '%s'.\nPlease notify system personnel.") - % lockfile - ) - - if msg: - raise Exception(msg) - debug( - "Mapset <{mapset}> locked using '{lockfile}'".format( - mapset=mapset_path, lockfile=lockfile - ) - ) - return lockfile - - # TODO: the gisrcrc here does not make sense, remove it from load_gisrc def unlock_gisrc_mapset(gisrc, gisrcrc): """Unlock mapset from the gisrc file""" @@ -2421,14 +2362,16 @@ def main(): location = mapset_settings.full_mapset + from grass.app.data import lock_mapset, MapsetLockingException + try: # check and create .gislock file lock_mapset( - mapset_settings.full_mapset, - user=user, - force_gislock_removal=params.force_gislock_removal, + mapset_path=mapset_settings.full_mapset, + force_lock_removal=params.force_gislock_removal, + message_callback=message, ) - except Exception as e: + except MapsetLockingException as e: fatal(e.args[0]) sys.exit(_("Exiting...")) diff --git a/python/grass/app/data.py b/python/grass/app/data.py index 439a6c3c4d1..2853b573f9c 100644 --- a/python/grass/app/data.py +++ b/python/grass/app/data.py @@ -15,8 +15,12 @@ import os import tempfile import getpass +import subprocess import sys from shutil import copytree, ignore_patterns +from pathlib import Path + +import grass.script as gs import grass.grassdb.config as cfg from grass.grassdb.checks import is_location_valid @@ -162,3 +166,69 @@ def ensure_default_data_hierarchy(): mapset_path = os.path.join(gisdbase, location, mapset) return gisdbase, location, mapset, mapset_path + + +class MapsetLockingException(Exception): + pass + + +def lock_mapset(mapset_path, force_lock_removal, message_callback): + """Acquire a lock for a mapset and return name of new lock file + + Raises MapsetLockingException when it is not possible to acquire a lock for the + given mapset either because of existing lock or due to insufficient permissions. + A corresponding localized message is given in the exception. + + A *message_callback* is a function which will be called to report messages about + certain states. Specifically, the function is called when forcibly unlocking the + mapset. + + Assumes that the runtime is set up (specifically that GISBASE is in + the environment). + """ + if not os.path.exists(mapset_path): + raise MapsetLockingException(_("Path '{}' doesn't exist").format(mapset_path)) + if not os.access(mapset_path, os.W_OK): + error = _("Path '{}' not accessible.").format(mapset_path) + stat_info = os.stat(mapset_path) + mapset_uid = stat_info.st_uid + if mapset_uid != os.getuid(): + error = "{error}\n{detail}".format( + error=error, + detail=_("You are not the owner of '{}'.").format(mapset_path), + ) + raise MapsetLockingException(error) + # Check for concurrent use + lockfile = os.path.join(mapset_path, ".gislock") + locker_path = os.path.join(os.environ["GISBASE"], "etc", "lock") + ret = subprocess.run( + [locker_path, lockfile, "%d" % os.getpid()], check=False + ).returncode + msg = None + if ret == 2: + if not force_lock_removal: + msg = _( + "{user} is currently running GRASS in selected mapset" + " (file {file} found). Concurrent use of one mapset not allowed.\n" + "You can force launching GRASS using -f flag" + " (assuming your have sufficient access permissions)." + " Confirm in a process manager " + "that there is no other process using the mapset." + ).format(user=Path(lockfile).owner(), file=lockfile) + else: + message_callback( + _( + "{user} is currently running GRASS in selected mapset" + " (file {file} found), but forcing to launch GRASS anyway..." + ).format(user=Path(lockfile).owner(), file=lockfile) + ) + gs.try_remove(lockfile) + elif ret != 0: + msg = _( + "Unable to properly access lock file '{name}'.\n" + "Please resolve this with your system administrator." + ).format(name=lockfile) + + if msg: + raise MapsetLockingException(msg) + return lockfile From 68c72455d926019017d71b709a7a8d80c67ea270 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 03:56:23 +0000 Subject: [PATCH 096/209] CI(deps): Update alpine:3.20 Docker digest to e72ad07 (#4381) --- docker/alpine/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index b6dbebf6666..70c7e82afba 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.20@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d as common +FROM alpine:3.20@sha256:e72ad0747b9dc266fca31fb004580d316b6ae5b0fdbbb65f17bbe371a5b24cff as common # Based on: # https://github.com/mundialis/docker-grass-gis/blob/master/Dockerfile From 0f75c27476061785194994b43efecffc822e57de Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 07:19:59 -0400 Subject: [PATCH 097/209] CI(deps): Update alpine:3.20 Docker digest to beefdbd (#4384) --- docker/alpine/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index 70c7e82afba..b6dbebf6666 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.20@sha256:e72ad0747b9dc266fca31fb004580d316b6ae5b0fdbbb65f17bbe371a5b24cff as common +FROM alpine:3.20@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d as common # Based on: # https://github.com/mundialis/docker-grass-gis/blob/master/Dockerfile From 82613638c197b04735be5b83d01f9f91a94456f8 Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Wed, 25 Sep 2024 09:49:07 -0400 Subject: [PATCH 098/209] grass.jupyter: move save() to BaseSeriesMap class to reduce redundancy (#4378) --- python/grass/jupyter/baseseriesmap.py | 48 ++++++++++++++++++- python/grass/jupyter/seriesmap.py | 47 ------------------ .../grass/jupyter/tests/timeseriesmap_test.py | 5 -- python/grass/jupyter/timeseriesmap.py | 47 ------------------ 4 files changed, 47 insertions(+), 100 deletions(-) diff --git a/python/grass/jupyter/baseseriesmap.py b/python/grass/jupyter/baseseriesmap.py index 634e172f3c5..4497b16593d 100644 --- a/python/grass/jupyter/baseseriesmap.py +++ b/python/grass/jupyter/baseseriesmap.py @@ -25,7 +25,7 @@ import grass.script as gs from .map import Map -from .utils import get_number_of_cores +from .utils import get_number_of_cores, save_gif class BaseSeriesMap: @@ -210,3 +210,49 @@ def change_image(index): width="100%", display="inline-flex", flex_flow="row wrap" ) return widgets.HBox([play, slider, out_img], layout=layout) + + def save( + self, + filename, + duration=500, + label=True, + font=None, + text_size=12, + text_color="gray", + ): + """ + Creates a GIF animation of rendered layers. + + Text color must be in a format accepted by PIL ImageColor module. For supported + formats, visit: + https://pillow.readthedocs.io/en/stable/reference/ImageColor.html#color-names + + param str filename: name of output GIF file + param int duration: time to display each frame; milliseconds + param bool label: include label on each frame + param str font: font file + param int text_size: size of label text + param str text_color: color to use for the text. + """ + + # Render images if they have not been already + if not self._layers_rendered: + self.render() + + input_files = [] + for index in self._indices: + input_files.append(self._base_filename_dict[index]) + + save_gif( + input_files, + filename, + duration=duration, + label=label, + labels=self._labels, + font=font, + text_size=text_size, + text_color=text_color, + ) + + # Display the GIF + return filename diff --git a/python/grass/jupyter/seriesmap.py b/python/grass/jupyter/seriesmap.py index 8615ad488fb..ae6bde911b6 100644 --- a/python/grass/jupyter/seriesmap.py +++ b/python/grass/jupyter/seriesmap.py @@ -20,7 +20,6 @@ from .map import Map from .region import RegionManagerForSeries -from .utils import save_gif from .baseseriesmap import BaseSeriesMap @@ -165,49 +164,3 @@ def render(self): ) tasks = [(i,) for i in range(self.baseseries)] self._render(tasks) - - def save( - self, - filename, - duration=500, - label=True, - font=None, - text_size=12, - text_color="gray", - ): - """ - Creates a GIF animation of rendered layers. - - Text color must be in a format accepted by PIL ImageColor module. For supported - formats, visit: - https://pillow.readthedocs.io/en/stable/reference/ImageColor.html#color-names - - param str filename: name of output GIF file - param int duration: time to display each frame; milliseconds - param bool label: include label on each frame - param str font: font file - param int text_size: size of label text - param str text_color: color to use for the text - """ - - # Render images if they have not been already - if not self._layers_rendered: - self.render() - - tmp_files = [] - for file in self._base_filename_dict.values(): - tmp_files.append(file) - - save_gif( - tmp_files, - filename, - duration=duration, - label=label, - labels=self._labels, - font=font, - text_size=text_size, - text_color=text_color, - ) - - # Display the GIF - return filename diff --git a/python/grass/jupyter/tests/timeseriesmap_test.py b/python/grass/jupyter/tests/timeseriesmap_test.py index c4e20f7704e..d65f7fcb700 100644 --- a/python/grass/jupyter/tests/timeseriesmap_test.py +++ b/python/grass/jupyter/tests/timeseriesmap_test.py @@ -1,7 +1,6 @@ """Test TimeSeriesMap functions""" from pathlib import Path -import sys import pytest @@ -67,10 +66,6 @@ def test_render_layers(space_time_raster_dataset, fill_gaps): assert Path(filename).is_file() -@pytest.mark.xfail( - sys.platform == "win32", - reason="DejaVuSans.ttf file isn't found and not installed with GRASS", -) @pytest.mark.needs_solo_run def test_save(space_time_raster_dataset, tmp_path): """Test returns from animate and time_slider are correct object types""" diff --git a/python/grass/jupyter/timeseriesmap.py b/python/grass/jupyter/timeseriesmap.py index 3ac94bea93e..2acfa575126 100644 --- a/python/grass/jupyter/timeseriesmap.py +++ b/python/grass/jupyter/timeseriesmap.py @@ -20,7 +20,6 @@ from .map import Map from .region import RegionManagerForTimeSeries -from .utils import save_gif from .baseseriesmap import BaseSeriesMap @@ -312,49 +311,3 @@ def render(self): filename = os.path.join(self._tmpdir.name, f"{layer}.png") tasks.append((date, layer, filename)) self._render(tasks) - - def save( - self, - filename, - duration=500, - label=True, - font="DejaVuSans.ttf", - text_size=12, - text_color="gray", - ): - """ - Creates a GIF animation of rendered layers. - - Text color must be in a format accepted by PIL ImageColor module. For supported - formats, visit: - https://pillow.readthedocs.io/en/stable/reference/ImageColor.html#color-names - - param str filename: name of output GIF file - param int duration: time to display each frame; milliseconds - param bool label: include date/time stamp on each frame - param str font: font file - param int text_size: size of date/time text - param str text_color: color to use for the text. - """ - - # Render images if they have not been already - if not self._layers_rendered: - self.render() - - input_files = [] - for date in self._labels: - input_files.append(self._base_filename_dict[date]) - - save_gif( - input_files, - filename, - duration=duration, - label=label, - labels=self._labels, - font=font, - text_size=text_size, - text_color=text_color, - ) - - # Display the GIF - return filename From 7c651c3a672d5f36585cd6da2063654dea0e3b01 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Wed, 25 Sep 2024 10:40:06 -0400 Subject: [PATCH 099/209] wxGUI/datacatalog: Replace lambda expression with named Function to fix E731 (#4377) --- .flake8 | 1 - gui/wxpython/datacatalog/tree.py | 23 ++++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.flake8 b/.flake8 index af8a021bd4c..d570fac7990 100644 --- a/.flake8 +++ b/.flake8 @@ -25,7 +25,6 @@ per-file-ignores = doc/python/m.distance.py: E501 doc/gui/wxpython/example/dialogs.py: F401 gui/scripts/d.wms.py: E501 - gui/wxpython/datacatalog/tree.py: E731, E402 gui/wxpython/dbmgr/base.py: E722 gui/wxpython/dbmgr/dialogs.py: E722 gui/wxpython/dbmgr/sqlbuilder.py: E722 diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py index faa0a6aac73..9a460d05f53 100644 --- a/gui/wxpython/datacatalog/tree.py +++ b/gui/wxpython/datacatalog/tree.py @@ -1378,15 +1378,20 @@ def OnPasteMap(self, event): ) if not new_name: continue - callback = lambda gisrc2=gisrc2, gisrc=gisrc, cLayer=self.copy_layer[ - i - ], cMapset=self.copy_mapset[ - i - ], cMode=self.copy_mode, sMapset=self.selected_mapset[ - 0 - ], name=new_name: self._onDoneReprojection( - env2, gisrc2, gisrc, cLayer, cMapset, cMode, sMapset, name - ) + + def callback( + gisrc2=gisrc2, + gisrc=gisrc, + cLayer=self.copy_layer[i], + cMapset=self.copy_mapset[i], + cMode=self.copy_mode, + sMapset=self.selected_mapset[0], + name=new_name, + ): + self._onDoneReprojection( + env2, gisrc2, gisrc, cLayer, cMapset, cMode, sMapset, name + ) + dlg = CatalogReprojectionDialog( self, self._giface, From 09c629dee487247df4ac768294dd9bae5eb42b99 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:09:09 -0400 Subject: [PATCH 100/209] CI(deps): Update actions/checkout action to v4.2.0 (#4387) --- .github/workflows/additional_checks.yml | 2 +- .github/workflows/clang-format-check.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/coverity.yml | 2 +- .github/workflows/create_release_draft.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/gcc.yml | 2 +- .github/workflows/macos.yml | 2 +- .github/workflows/osgeo4w.yml | 2 +- .github/workflows/periodic_update.yml | 2 +- .github/workflows/pytest.yml | 2 +- .github/workflows/python-code-quality.yml | 2 +- .github/workflows/super-linter.yml | 2 +- .github/workflows/test-nix.yml | 2 +- .github/workflows/titles.yml | 2 +- .github/workflows/ubuntu.yml | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/additional_checks.yml b/.github/workflows/additional_checks.yml index d25cbb49194..1f8e355b487 100644 --- a/.github/workflows/additional_checks.yml +++ b/.github/workflows/additional_checks.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository contents - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: fetch-depth: 31 diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index 12b0b070ec9..f68483dea20 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -16,7 +16,7 @@ jobs: name: Formatting Check runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: persist-credentials: false - uses: DoozyX/clang-format-lint-action@c71d0bf4e21876ebec3e5647491186f8797fde31 # v0.18.2 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index bf07004bc82..14017253fd5 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -40,7 +40,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Python uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 with: diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index 9f1fc5d843c..24c98c96601 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-22.04 if: github.repository == 'OSGeo/grass' steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Get dependencies run: | diff --git a/.github/workflows/create_release_draft.yml b/.github/workflows/create_release_draft.yml index 09da8ad1317..4751c3c43a0 100644 --- a/.github/workflows/create_release_draft.yml +++ b/.github/workflows/create_release_draft.yml @@ -30,7 +30,7 @@ jobs: contents: write steps: - name: Checks-out repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: ref: ${{ github.ref }} fetch-depth: 0 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 1f60ed4c6d7..06b4c14ccbd 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -49,7 +49,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: fetch-depth: 0 - name: Docker meta diff --git a/.github/workflows/gcc.yml b/.github/workflows/gcc.yml index e3e23f43c04..24b9dcb4043 100644 --- a/.github/workflows/gcc.yml +++ b/.github/workflows/gcc.yml @@ -26,7 +26,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Get dependencies run: | sudo apt-get update -y diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 4fad9d315a7..664649fa5c6 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -44,7 +44,7 @@ jobs: -mindepth 1 -maxdepth 1 -type f -print -delete # Rehash to forget about the deleted files hash -r - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Get current date cache key segment id: date # Year and week of year so cache key changes weekly diff --git a/.github/workflows/osgeo4w.yml b/.github/workflows/osgeo4w.yml index 027cecebf21..d9c67cc37c9 100644 --- a/.github/workflows/osgeo4w.yml +++ b/.github/workflows/osgeo4w.yml @@ -31,7 +31,7 @@ jobs: run: | git config --global core.autocrlf false git config --global core.eol lf - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - uses: msys2/setup-msys2@ddf331adaebd714795f1042345e6ca57bd66cea8 # v2.24.1 with: path-type: inherit diff --git a/.github/workflows/periodic_update.yml b/.github/workflows/periodic_update.yml index bea3b53af4a..f5441297250 100644 --- a/.github/workflows/periodic_update.yml +++ b/.github/workflows/periodic_update.yml @@ -21,7 +21,7 @@ jobs: - name: Create URL to the run output id: vars run: echo "run-url=https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" >> $GITHUB_OUTPUT - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: "Check that autoconf scripts are up-to-date:" run: | rm -f config.guess config.sub diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 8e3b2286b1c..4ff31728abe 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -32,7 +32,7 @@ jobs: PYTHONWARNINGS: always steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Python uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 403d7393d0e..385ad6b9dd5 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -54,7 +54,7 @@ jobs: echo Bandit: ${{ env.BANDIT_VERSION }} echo Ruff: ${{ env.RUFF_VERSION }} - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Python uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 diff --git a/.github/workflows/super-linter.yml b/.github/workflows/super-linter.yml index 44da8d9acb7..117f5cd43fb 100644 --- a/.github/workflows/super-linter.yml +++ b/.github/workflows/super-linter.yml @@ -25,7 +25,7 @@ jobs: statuses: write steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: # super-linter needs the full git history to get the # list of files that changed across commits diff --git a/.github/workflows/test-nix.yml b/.github/workflows/test-nix.yml index 22fa4f0061f..03f767730a9 100644 --- a/.github/workflows/test-nix.yml +++ b/.github/workflows/test-nix.yml @@ -28,7 +28,7 @@ jobs: contents: read steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Install nix uses: DeterminateSystems/nix-installer-action@da36cb69b1c3247ad7a1f931ebfd954a1105ef14 # v14 diff --git a/.github/workflows/titles.yml b/.github/workflows/titles.yml index b8e33c2fb37..f90e7275a2e 100644 --- a/.github/workflows/titles.yml +++ b/.github/workflows/titles.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout base repository (doesn't include the PR changes) - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Call PR title validation function run: python utils/generate_release_notes.py check "${PR_TITLE}" "" "" env: diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 57b0821eec4..25ce2afdd67 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -59,7 +59,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Invert inclusion list to an exclusion list id: get-exclude From 20985774a0965549fcc43c500f697aac5172c546 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Thu, 26 Sep 2024 08:29:28 -0400 Subject: [PATCH 101/209] v.vol.rst: Fix resource leak issue in user1.c file (#4389) --- vector/v.vol.rst/user1.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vector/v.vol.rst/user1.c b/vector/v.vol.rst/user1.c index f47324dff36..6a1c2f441e6 100644 --- a/vector/v.vol.rst/user1.c +++ b/vector/v.vol.rst/user1.c @@ -220,6 +220,7 @@ int INPUT(struct Map_info *In, char *column, char *scol, char *wheresql) if (a < 0) { G_warning(_("Can't insert %lf,%lf,%lf,%lf,%lf a=%d"), x, y, z, w, sm, a); + Vect_destroy_field_info(Fi); return -1; } @@ -322,6 +323,7 @@ int INPUT(struct Map_info *In, char *column, char *scol, char *wheresql) } else { fprintf(stderr, "ERROR: zero points in the given region!\n"); + Vect_destroy_field_info(Fi); return -1; } } @@ -332,6 +334,7 @@ int INPUT(struct Map_info *In, char *column, char *scol, char *wheresql) KMIN, KMAX); fprintf(stderr, "for smooth connection of segments, npmin > segmax " "(see manual) \n"); + Vect_destroy_field_info(Fi); return -1; } @@ -382,6 +385,7 @@ int INPUT(struct Map_info *In, char *column, char *scol, char *wheresql) } G_message(_("Bitmap mask created")); } + Vect_destroy_field_info(Fi); return 1; } From 845dfd066146b40539a02b6952ac2ea4eb92a82d Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Thu, 26 Sep 2024 10:13:52 -0400 Subject: [PATCH 102/209] wxGUI: Refactored try-except block to be more robust in dialogs.py (#4383) --- .flake8 | 1 - gui/wxpython/dbmgr/dialogs.py | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.flake8 b/.flake8 index d570fac7990..93ed48e30a6 100644 --- a/.flake8 +++ b/.flake8 @@ -26,7 +26,6 @@ per-file-ignores = doc/gui/wxpython/example/dialogs.py: F401 gui/scripts/d.wms.py: E501 gui/wxpython/dbmgr/base.py: E722 - gui/wxpython/dbmgr/dialogs.py: E722 gui/wxpython/dbmgr/sqlbuilder.py: E722 gui/wxpython/dbmgr/manager.py: E722 gui/wxpython/docs/wxgui_sphinx/conf.py: E402, W291 diff --git a/gui/wxpython/dbmgr/dialogs.py b/gui/wxpython/dbmgr/dialogs.py index 26e6d876371..0d7c6e9e523 100644 --- a/gui/wxpython/dbmgr/dialogs.py +++ b/gui/wxpython/dbmgr/dialogs.py @@ -222,10 +222,11 @@ def GetSQLString(self, updateValues=False): ctype = columns[name]["ctype"] value = columns[name]["values"][idx] id = columns[name]["ids"][idx] + widget = self.FindWindowById(id) try: - newvalue = self.FindWindowById(id).GetValue() - except: - newvalue = self.FindWindowById(id).GetLabel() + newvalue = widget.GetValue() + except AttributeError: + newvalue = widget.GetLabel() if newvalue: try: From b835f4d82ac15bd5ac3c4ac8d5df46ccb1765714 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Thu, 26 Sep 2024 11:21:24 -0400 Subject: [PATCH 103/209] wxGUI: Fixed E266 - extra '#' for comments in gui_core/ (#4393) --- .flake8 | 7 +++---- gui/wxpython/gui_core/gselect.py | 2 +- gui/wxpython/gui_core/preferences.py | 8 ++++---- gui/wxpython/gui_core/widgets.py | 1 - 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/.flake8 b/.flake8 index 93ed48e30a6..f7949259d93 100644 --- a/.flake8 +++ b/.flake8 @@ -30,13 +30,12 @@ per-file-ignores = gui/wxpython/dbmgr/manager.py: E722 gui/wxpython/docs/wxgui_sphinx/conf.py: E402, W291 gui/wxpython/gcp/manager.py: E722 - gui/wxpython/gui_core/*: E266, E722 + gui/wxpython/gui_core/*: E722 gui/wxpython/gui_core/dialogs.py: E722 gui/wxpython/gui_core/forms.py: E722 gui/wxpython/gui_core/ghelp.py: E722 - gui/wxpython/gui_core/gselect.py: E266, E722 - gui/wxpython/gui_core/preferences.py: E266 - gui/wxpython/gui_core/widgets.py: E722, E266 + gui/wxpython/gui_core/gselect.py: E722 + gui/wxpython/gui_core/widgets.py: E722 gui/wxpython/image2target/*: F841, E722, E265 gui/wxpython/image2target/g.gui.image2target.py: E501, E265, F841 gui/wxpython/iscatt/*: F841, E722, F405, F403 diff --git a/gui/wxpython/gui_core/gselect.py b/gui/wxpython/gui_core/gselect.py index cec6963a527..6ad22403ecd 100644 --- a/gui/wxpython/gui_core/gselect.py +++ b/gui/wxpython/gui_core/gselect.py @@ -1289,7 +1289,7 @@ def __init__( style = 0 # disabled, read-only widget has no TextCtrl children (TODO: rewrite) # if not new and not multiple: - ### style = wx.CB_READONLY + # style = wx.CB_READONLY wx.ComboBox.__init__(self, parent, id, size=size, style=style, **kwargs) self.searchPath = searchPath diff --git a/gui/wxpython/gui_core/preferences.py b/gui/wxpython/gui_core/preferences.py index c2020b2ffba..a35d902bc7f 100644 --- a/gui/wxpython/gui_core/preferences.py +++ b/gui/wxpython/gui_core/preferences.py @@ -2419,7 +2419,7 @@ def LoadData(self): """Load data into list""" self.InsertColumn(0, _("Mapset")) self.InsertColumn(1, _("Owner")) - ### self.InsertColumn(2, _('Group')) + # self.InsertColumn(2, _('Group')) gisenv = gs.gisenv() locationPath = os.path.join(gisenv["GISDBASE"], gisenv["LOCATION_NAME"]) @@ -2433,14 +2433,14 @@ def LoadData(self): except KeyError: self.SetItem(index, 1, "nobody") # FIXME: get group name - ### self.SetStringItem(index, 2, "%-8s" % stat_info.st_gid) + # self.SetStringItem(index, 2, "%-8s" % stat_info.st_gid) else: # FIXME: no pwd under MS Windows (owner: 0, group: 0) self.SetItem(index, 1, "%-8s" % stat_info.st_uid) - ### self.SetStringItem(index, 2, "%-8s" % stat_info.st_gid) + # self.SetStringItem(index, 2, "%-8s" % stat_info.st_gid) self.SetColumnWidth(col=0, width=wx.LIST_AUTOSIZE) - ### self.SetColumnWidth(col = 1, width = wx.LIST_AUTOSIZE) + # self.SetColumnWidth(col = 1, width = wx.LIST_AUTOSIZE) def OnCheckItem(self, index, flag): """Mapset checked/unchecked""" diff --git a/gui/wxpython/gui_core/widgets.py b/gui/wxpython/gui_core/widgets.py index 0ec50553114..c959ebbbf50 100644 --- a/gui/wxpython/gui_core/widgets.py +++ b/gui/wxpython/gui_core/widgets.py @@ -435,7 +435,6 @@ class NumTextCtrl(TextCtrl): """Class derived from wx.TextCtrl for numerical values only""" def __init__(self, parent, **kwargs): - ## self.precision = kwargs.pop('prec') TextCtrl.__init__( self, parent=parent, validator=NTCValidator(flag="DIGIT_ONLY"), **kwargs ) From 549ea90713722361b7aa80f61016747e2e07ac80 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Thu, 26 Sep 2024 11:30:56 -0400 Subject: [PATCH 104/209] r3.in.v5d: Fix unchecked return value from lseek (#4141) This addresses an issue identified by Coverity Scan (CID: 1207300), where the return value of the lseek function is not checked. Functions return as in other error states after issuing a warning. Small step was taken towards consistency and simplification in another function which uses prints otherwise. --- raster3d/r3.in.v5d/v5d.c | 62 +++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/raster3d/r3.in.v5d/v5d.c b/raster3d/r3.in.v5d/v5d.c index 445d6f29b9f..54f75f2361a 100644 --- a/raster3d/r3.in.v5d/v5d.c +++ b/raster3d/r3.in.v5d/v5d.c @@ -63,6 +63,9 @@ #include #include #include +#include +#include + #include "binio.h" #include "v5d.h" #include "vis5d.h" @@ -1232,7 +1235,10 @@ static int read_comp_header(int f, v5dstruct *v) unsigned int id; /* reset file position to start of file */ - lseek(f, 0, SEEK_SET); + if (lseek(f, 0, SEEK_SET) == -1) { + G_warning(_("Unable to seek: %s"), strerror(errno)); + return 0; + } /* read file ID */ read_int4(f, (int *)&id); @@ -1334,8 +1340,8 @@ static int read_comp_header(int f, v5dstruct *v) /* skip ahead by 'gridsize' bytes */ if (lseek(f, gridsize, SEEK_CUR) == -1) { - printf("Error: Unexpected end of file, "); - printf("file may be corrupted.\n"); + G_warning(_("Error: Unexpected end of file, file may be " + "corrupted.")); return 0; } min = -(125.0 + gb) / ga; @@ -1478,7 +1484,10 @@ static int read_comp_grid(v5dstruct *v, int time, int var, float *ga, float *gb, /* move to position in file */ pos = grid_position(v, time, var); - lseek(f, pos, SEEK_SET); + if (lseek(f, pos, SEEK_SET) == -1) { + G_warning(_("Unable to seek: %s"), strerror(errno)); + return 0; + } if (v->FileFormat == 0x80808083) { /* read McIDAS grid and file numbers */ @@ -1551,7 +1560,13 @@ static int read_comp_grid(v5dstruct *v, int time, int var, float *ga, float *gb, */ static int read_v5d_header(v5dstruct *v) { -#define SKIP(N) lseek(f, N, SEEK_CUR) +#define SKIP(N) \ + do { \ + if (lseek(f, N, SEEK_CUR) == -1) { \ + G_warning(_("Unable to seek: %s"), strerror(errno)); \ + return 0; \ + } \ + } while (0) int end_of_header = 0; unsigned int id; int idlen, var, numargs; @@ -1870,13 +1885,19 @@ static int read_v5d_header(v5dstruct *v) case TAG_END: /* end of header */ end_of_header = 1; - lseek(f, length, SEEK_CUR); + if (lseek(f, length, SEEK_CUR) == -1) { + G_warning(_("Unable to seek: %s"), strerror(errno)); + return 0; + } break; default: /* unknown tag, skip to next tag */ printf("Unknown tag: %d length=%d\n", tag, length); - lseek(f, length, SEEK_CUR); + if (lseek(f, length, SEEK_CUR) == -1) { + G_warning(_("Unable to seek: %s"), strerror(errno)); + return 0; + } break; } } @@ -1966,7 +1987,10 @@ int v5dReadCompressedGrid(v5dstruct *v, int time, int var, float *ga, float *gb, /* move to position in file */ pos = grid_position(v, time, var); - lseek(v->FileDesc, pos, SEEK_SET); + if (lseek(v->FileDesc, pos, SEEK_SET) == -1) { + G_warning(_("Unable to seek: %s"), strerror(errno)); + return 0; + } /* read ga, gb arrays */ read_float4_array(v->FileDesc, ga, v->Nl[var]); @@ -2118,7 +2142,10 @@ static int write_v5d_header(v5dstruct *v) } /* set file pointer to start of file */ - lseek(f, 0, SEEK_SET); + if (lseek(f, 0, SEEK_SET) == -1) { + G_warning(_("Unable to seek: %s"), strerror(errno)); + return 0; + } v->CurPos = 0; /* @@ -2222,7 +2249,10 @@ static int write_v5d_header(v5dstruct *v) /* We're writing to a brand new file. Reserve 10000 bytes */ /* for future header growth. */ WRITE_TAG(v, TAG_END, 10000); - lseek(f, 10000, SEEK_CUR); + if (lseek(f, 10000, SEEK_CUR) == -1) { + G_warning(_("Unable to seek: %s"), strerror(errno)); + return 0; + } /* Let file pointer indicate where first grid is stored */ v->FirstGridPos = ltell(f); @@ -2336,7 +2366,7 @@ int v5dWriteCompressedGrid(const v5dstruct *v, int time, int var, pos = grid_position(v, time, var); if (lseek(v->FileDesc, pos, SEEK_SET) < 0) { /* lseek failed, return error */ - printf("Error in v5dWrite[Compressed]Grid: seek failed, disk full?\n"); + G_warning(_("Unable to seek: %s"), strerror(errno)); return 0; } @@ -2452,9 +2482,15 @@ int v5dCloseFile(v5dstruct *v) if (v->Mode == 'w') { /* rewrite header because writing grids updates the minval and */ /* maxval fields */ - lseek(v->FileDesc, 0, SEEK_SET); + if (lseek(v->FileDesc, 0, SEEK_SET) == -1) { + G_warning(_("Unable to seek: %s"), strerror(errno)); + return 0; + } status = write_v5d_header(v); - lseek(v->FileDesc, 0, SEEK_END); + if (lseek(v->FileDesc, 0, SEEK_END) == -1) { + G_warning(_("Unable to seek: %s"), strerror(errno)); + return 0; + } close(v->FileDesc); } else if (v->Mode == 'r') { From edea8103d927cf4a269fcdd12fbbab9aa4b66e3d Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Thu, 26 Sep 2024 12:55:56 -0400 Subject: [PATCH 105/209] wxGUI: Fix E722 Warnings by Specifying Exception Types in dbmgr/ (#4382) --- .flake8 | 3 --- gui/wxpython/dbmgr/base.py | 23 +++++++++++++++-------- gui/wxpython/dbmgr/manager.py | 2 +- gui/wxpython/dbmgr/sqlbuilder.py | 2 +- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/.flake8 b/.flake8 index f7949259d93..dd80ca9b6a0 100644 --- a/.flake8 +++ b/.flake8 @@ -25,9 +25,6 @@ per-file-ignores = doc/python/m.distance.py: E501 doc/gui/wxpython/example/dialogs.py: F401 gui/scripts/d.wms.py: E501 - gui/wxpython/dbmgr/base.py: E722 - gui/wxpython/dbmgr/sqlbuilder.py: E722 - gui/wxpython/dbmgr/manager.py: E722 gui/wxpython/docs/wxgui_sphinx/conf.py: E402, W291 gui/wxpython/gcp/manager.py: E722 gui/wxpython/gui_core/*: E722 diff --git a/gui/wxpython/dbmgr/base.py b/gui/wxpython/dbmgr/base.py index 66321fcafda..d7ea818da4c 100644 --- a/gui/wxpython/dbmgr/base.py +++ b/gui/wxpython/dbmgr/base.py @@ -208,7 +208,7 @@ def LoadData(self, layer, columns=None, where=None, sql=None): try: # for maps connected via v.external keyId = columns.index(keyColumn) - except: + except ValueError: keyId = -1 # read data @@ -961,7 +961,7 @@ def OnLayerPageChanged(self, event): self.layerPage[self.selLayer]["data"] ).GetItemCount() ) - except: + except Exception: pass if idCol: @@ -1640,7 +1640,7 @@ def OnDataItemAdd(self, event): if dlg.ShowModal() == wx.ID_OK: try: # get category number cat = int(dlg.GetValues(columns=[keyColumn])[0]) - except: + except ValueError: cat = -1 try: @@ -1672,7 +1672,7 @@ def OnDataItemAdd(self, event): values[i] = int(float(values[i])) elif tlist.columns[columnName[i]]["ctype"] == float: values[i] = float(values[i]) - except: + except ValueError: raise ValueError( _("Value '%(value)s' needs to be entered as %(type)s.") % { @@ -1680,6 +1680,13 @@ def OnDataItemAdd(self, event): "type": tlist.columns[columnName[i]]["type"], } ) + except KeyError: + raise KeyError( + _("Column '%(column)s' does not exist.") + % { + "column": columnName[i], + } + ) columnsString += "%s," % columnName[i] if tlist.columns[columnName[i]]["ctype"] == str: @@ -3809,7 +3816,7 @@ def OnDeleteLayer(self, event): """Delete layer""" try: layer = int(self.deleteLayer.GetValue()) - except: + except ValueError: return RunCommand( @@ -3856,10 +3863,10 @@ def OnChangeLayer(self, event): """Layer number of layer to be deleted is changed""" try: layer = int(event.GetString()) - except: + except ValueError: try: - layer = self.mapDBInfo.layers.keys()[0] - except: + layer = list(self.mapDBInfo.layers.keys())[0] + except IndexError: return if self.GetCurrentPage() == self.modifyPanel: diff --git a/gui/wxpython/dbmgr/manager.py b/gui/wxpython/dbmgr/manager.py index c866bd55650..b1cbd93ab71 100644 --- a/gui/wxpython/dbmgr/manager.py +++ b/gui/wxpython/dbmgr/manager.py @@ -70,7 +70,7 @@ def __init__( self.parent = parent try: mapdisplay = self.parent.GetMapDisplay() - except: + except AttributeError: mapdisplay = None DbMgrBase.__init__( diff --git a/gui/wxpython/dbmgr/sqlbuilder.py b/gui/wxpython/dbmgr/sqlbuilder.py index 36827698efc..5e6fe0e7706 100644 --- a/gui/wxpython/dbmgr/sqlbuilder.py +++ b/gui/wxpython/dbmgr/sqlbuilder.py @@ -359,7 +359,7 @@ def OnUniqueValues(self, event, justsample=False): try: idx = self.list_columns.GetSelections()[0] column = self.list_columns.GetString(idx) - except: + except IndexError: self.list_values.Clear() return From c502c1c05f7208a48f1b44b835ab23ac9d1708be Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Thu, 26 Sep 2024 18:35:30 -0400 Subject: [PATCH 106/209] checks: Fix E402 Flake8 in for wxGUI Sphinx doc (#4391) This fixes Flake8 E402 (Module level import not at top of file) for Sphinx documentation generator configuration script by removing import path manipulation block which was not properly working anyway. --- .flake8 | 1 - gui/wxpython/docs/wxgui_sphinx/conf.py | 12 ------------ 2 files changed, 13 deletions(-) diff --git a/.flake8 b/.flake8 index dd80ca9b6a0..7bad3afc185 100644 --- a/.flake8 +++ b/.flake8 @@ -25,7 +25,6 @@ per-file-ignores = doc/python/m.distance.py: E501 doc/gui/wxpython/example/dialogs.py: F401 gui/scripts/d.wms.py: E501 - gui/wxpython/docs/wxgui_sphinx/conf.py: E402, W291 gui/wxpython/gcp/manager.py: E722 gui/wxpython/gui_core/*: E722 gui/wxpython/gui_core/dialogs.py: E722 diff --git a/gui/wxpython/docs/wxgui_sphinx/conf.py b/gui/wxpython/docs/wxgui_sphinx/conf.py index 3641c2aab48..f0b61a31996 100644 --- a/gui/wxpython/docs/wxgui_sphinx/conf.py +++ b/gui/wxpython/docs/wxgui_sphinx/conf.py @@ -10,21 +10,9 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys -import os from datetime import date import string from shutil import copy - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -if not os.getenv("GISBASE"): - sys.exit("GISBASE not defined") -sys.path.insert( - 0, os.path.abspath(os.path.join(os.environ["GISBASE"], "etc", "python", "grass")) -) - from grass.script import core footer_tmpl = string.Template( From e4c87ece77a2f35784e344a08acf4257ccfd4d50 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 23:01:44 +0000 Subject: [PATCH 107/209] CI(deps): Update ruff to v0.6.8 (#4394) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * CI(deps): Update ruff to v0.6.8 * style: Use `kargs.get("layerTree")` instead of `kargs.get("layerTree", None)` (SIM910) * style: Simplify chained boolean comparison * Apply black formatting --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Edouard Choinière <27212526+echoix@users.noreply.github.com> --- .github/workflows/python-code-quality.yml | 2 +- .pre-commit-config.yaml | 2 +- gui/wxpython/gui_core/gselect.py | 2 +- scripts/r.in.wms/wms_drv.py | 8 ++------ 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 385ad6b9dd5..9febdd990e3 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.7.10" # renovate: datasource=pypi depName=ruff - RUFF_VERSION: "0.6.7" + RUFF_VERSION: "0.6.8" runs-on: ${{ matrix.os }} permissions: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 74423979b22..b7a517fba37 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: ) - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.6.7 + rev: v0.6.8 hooks: # Run the linter. - id: ruff diff --git a/gui/wxpython/gui_core/gselect.py b/gui/wxpython/gui_core/gselect.py index 6ad22403ecd..4bb9af5b50e 100644 --- a/gui/wxpython/gui_core/gselect.py +++ b/gui/wxpython/gui_core/gselect.py @@ -414,7 +414,7 @@ def SetData(self, **kargs): self.multiple = kargs["multiple"] if "onPopup" in kargs: self.onPopup = kargs["onPopup"] - if kargs.get("layerTree", None): + if kargs.get("layerTree"): self.filterItems = [] # reset ltype = kargs["type"] for layer in kargs["layerTree"].GetVisibleLayers(skipDigitized=True): diff --git a/scripts/r.in.wms/wms_drv.py b/scripts/r.in.wms/wms_drv.py index 186157ad6db..dd666573cfe 100644 --- a/scripts/r.in.wms/wms_drv.py +++ b/scripts/r.in.wms/wms_drv.py @@ -736,9 +736,7 @@ def _findTileMats(self, tile_mats, region, bbox): best_diff = best_scale_den - scale_den mat_diff = mat_scale_den - scale_den - if (best_diff < mat_diff and mat_diff < 0) or ( - best_diff > mat_diff and best_diff > 0 - ): + if (best_diff < mat_diff < 0) or (best_diff > mat_diff and best_diff > 0): best_t_mat = t_mat best_scale_den = mat_scale_den @@ -1020,9 +1018,7 @@ def _parseTilePattern(self, group_t_patts, bbox, region): best_diff = best_res - res[comp_res] tile_diff = t_res[comp_res] - res[comp_res] - if (best_diff < tile_diff and tile_diff < 0) or ( - best_diff > tile_diff and best_diff > 0 - ): + if (best_diff < tile_diff < 0) or (best_diff > tile_diff and best_diff > 0): best_res = t_res[comp_res] best_patt = pattern From bcb29389919dce73ccb9339a568b7bc6d5920a39 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 10:39:34 -0400 Subject: [PATCH 108/209] CI(deps): Update docker/build-push-action action to v6.8.0 (#4398) --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 06b4c14ccbd..824fbe18e1e 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -76,7 +76,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85 # v6.7.0 + uses: docker/build-push-action@32945a339266b759abcbdc89316275140b0fc960 # v6.8.0 with: push: true pull: true From 7f05bb3574f4fcd0cfc97dbb91d8fc9666b39661 Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Sat, 28 Sep 2024 05:39:56 -0400 Subject: [PATCH 109/209] style: Remove misleading author info from wxGUI photo and image code (#4403) Just to be clear that I did not create these files, I'm removing my name which was copy-pasted into these files while duplicating the code from somewhere else. --- gui/wxpython/image2target/g.gui.image2target.py | 2 -- gui/wxpython/image2target/ii2t_statusbar.py | 3 --- gui/wxpython/photo2image/g.gui.photo2image.py | 1 - gui/wxpython/photo2image/ip2i_statusbar.py | 3 --- 4 files changed, 9 deletions(-) diff --git a/gui/wxpython/image2target/g.gui.image2target.py b/gui/wxpython/image2target/g.gui.image2target.py index 97c67b20354..aabfbbe87d2 100755 --- a/gui/wxpython/image2target/g.gui.image2target.py +++ b/gui/wxpython/image2target/g.gui.image2target.py @@ -98,8 +98,6 @@ """ Module to run GCP management tool as stadalone application. - -@author Vaclav Petras (standalone module) """ import os diff --git a/gui/wxpython/image2target/ii2t_statusbar.py b/gui/wxpython/image2target/ii2t_statusbar.py index 3c5ee378a1e..7ff80e621d3 100644 --- a/gui/wxpython/image2target/ii2t_statusbar.py +++ b/gui/wxpython/image2target/ii2t_statusbar.py @@ -11,9 +11,6 @@ This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. - -@author Vaclav Petras (statusbar refactoring) -@author Anna Kratochvilova (statusbar refactoring) """ import wx diff --git a/gui/wxpython/photo2image/g.gui.photo2image.py b/gui/wxpython/photo2image/g.gui.photo2image.py index 21635175374..65b4141873e 100755 --- a/gui/wxpython/photo2image/g.gui.photo2image.py +++ b/gui/wxpython/photo2image/g.gui.photo2image.py @@ -68,7 +68,6 @@ """ Module to run GCP management tool as stadalone application. -@author Vaclav Petras (standalone module) """ import os import grass.script as gs diff --git a/gui/wxpython/photo2image/ip2i_statusbar.py b/gui/wxpython/photo2image/ip2i_statusbar.py index 336dcd6903f..75a39b8141e 100644 --- a/gui/wxpython/photo2image/ip2i_statusbar.py +++ b/gui/wxpython/photo2image/ip2i_statusbar.py @@ -11,9 +11,6 @@ This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. - -@author Vaclav Petras (statusbar refactoring) -@author Anna Kratochvilova (statusbar refactoring) """ import wx From 4f689febc42a95e7a8fb113122a43fa96596c0a2 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Sat, 28 Sep 2024 06:11:03 -0400 Subject: [PATCH 110/209] docs: fixed E265 from image2target/ (#4399) * removed e265 * update .flake8 * removed commented out parser code * removed parser code --- .flake8 | 4 +- .../image2target/g.gui.image2target.py | 111 ------------------ 2 files changed, 2 insertions(+), 113 deletions(-) diff --git a/.flake8 b/.flake8 index 7bad3afc185..c3256ec22bf 100644 --- a/.flake8 +++ b/.flake8 @@ -32,8 +32,8 @@ per-file-ignores = gui/wxpython/gui_core/ghelp.py: E722 gui/wxpython/gui_core/gselect.py: E722 gui/wxpython/gui_core/widgets.py: E722 - gui/wxpython/image2target/*: F841, E722, E265 - gui/wxpython/image2target/g.gui.image2target.py: E501, E265, F841 + gui/wxpython/image2target/*: F841, E722 + gui/wxpython/image2target/g.gui.image2target.py: E501, F841 gui/wxpython/iscatt/*: F841, E722, F405, F403 gui/wxpython/lmgr/frame.py: F841, E722 # layertree still includes some formatting issues (it is ignored by Black) diff --git a/gui/wxpython/image2target/g.gui.image2target.py b/gui/wxpython/image2target/g.gui.image2target.py index aabfbbe87d2..37d33c2d70e 100755 --- a/gui/wxpython/image2target/g.gui.image2target.py +++ b/gui/wxpython/image2target/g.gui.image2target.py @@ -30,71 +30,6 @@ # % keyword: GCP # %end -##%option G_OPT_M_LOCATION -##% key: source_project -##% label: The name of the source project (has no projection) -##% description: The source project (location) has no CRS -###% section: source -##% required: yes -##%end - -##%option G_OPT_M_MAPSET -##% key: source_mapset -##% label: The name of the source mapset (has no projection) -##% description: The name of the source mapset (has no projection) -###% section: source -##% required: yes -##%end - -##%option G_OPT_I_GROUP -##% key: source_group -##% required: yes -##% section: source -##%end - -##%option G_OPT_R_INPUT -##% key: source_image -##% required: yes -###% section: source -##%end - -##%option G_OPT_R_INPUT -##% key: target_image -##% label: The name of the image that is already georeferenced used to find location of GCPs -##% description: The name of the image that is already georeferenced used to find the location of GCPs -###% section: target -##% required: no -##%end - -##%option -##% key: camera -##% type: string -##% label: The name of the camera (generated in i.ortho.camera) -##% description: The name of the camera (generated in i.ortho.camera) -##% required: yes -###% section: parameters -##%end - -##%option -##% key: order -##% type: string -##% label: The rectification order -##% description: The rectification order -##% required: yes -##% answer: 1 -###% section: parameters -##%end - -##%option -##% key: extension -##% type: string -##% label: The name of the output files extension -##% description: The name of the output files extension -##% required: yes -##% answer: _ii2t_out -##% section: target -##%end - """ Module to run GCP management tool as stadalone application. @@ -127,54 +62,8 @@ def main(): else: os.environ["GRASS_RENDER_IMMEDIATE"] = "cairo" - # if options["source_location"]: - # src_loc = options["source_location"] - # else: - # gscript.fatal(_("No georeferenced source location provided")) - - # if options["source_mapset"]: - # src_mpt = options["source_mapset"] - # else: - # gscript.fatal(_("No georeferenced source mapset provided")) - - # if options["source_group"]: - # src_grp = options["source_group"] - # else: - # gscript.fatal(_("Please provide a source group name to process")) - - # if options['source_image']: - # src_ras = options["source_image"] - # else: - # gscript.fatal(_("Please provide a source image map name to process")) - - # if options["target_image"]: - # tgt_ras = options["target_image"] - # else: - # gscript.fatal(_("No georeferenced target map provided")) - - # if options["camera"]: - # camera = options["camera"] - # else: - # gscript.fatal(_( - # "Please provide a camera name (generated by i.ortho.camera)" - # )) - - # if options["order"]: - # order = options["order"] - # else: - # gscript.fatal(_("Please provive an order value")) - - # if options["extension"]: - # extension = options["extension"] - # else: - # gscript.fatal(_("Please provide an output file extension")) - app = wx.App() - # wizard = GCPWizard(parent=None, giface=StandaloneGrassInterface(), - # srcloc=src_loc,srcmpt=src_mpt,srcgrp=src_grp,srcras=src_ras, - # tgtras=tgt_ras,camera=camera, order=order, extension=extension) - wizard = GCPWizard(parent=None, giface=StandaloneGrassInterface()) app.MainLoop() From fee26ece86a1ee18a85528244bcc750b77e6b535 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hern=C3=A1n=20De=20Angelis?= <51515911+dhdeangelis@users.noreply.github.com> Date: Sat, 28 Sep 2024 19:44:32 +0200 Subject: [PATCH 111/209] g.gui.iclass: Add explanation of expected format for vector layers (#4411) --- gui/wxpython/iclass/g.gui.iclass.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/gui/wxpython/iclass/g.gui.iclass.html b/gui/wxpython/iclass/g.gui.iclass.html index f6169b1d8f6..dd789cd75b5 100644 --- a/gui/wxpython/iclass/g.gui.iclass.html +++ b/gui/wxpython/iclass/g.gui.iclass.html @@ -35,7 +35,6 @@

    DESCRIPTION

  • write signature file
  • import vector map
  • export vector map with attribute table
  • -
    @@ -62,6 +61,13 @@

    DESCRIPTION

    By doing this, the user can see how much of the image is likely to be put into the class associated with the signature. +

    wxIClass can also import training areas defined in a vector layer. In that case the program expects the vector layer to have the following columns defined: +

      +
    • cat: category value
    • +
    • class: a string with the class name
    • +
    • color: a color defined using format "RRR:GGG:BBB"
    • +
    +

    The spectral signatures are composed of region means and covariance matrices. These region means and covariance matrices are used in From 49f67fdf5355ad825e1849fe490021c30af7b673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 28 Sep 2024 15:11:20 -0400 Subject: [PATCH 112/209] style: Fix negate-equal-op (SIM201) (#4407) * style: Fix negate-equal-op (SIM201) Ruff rule: https://docs.astral.sh/ruff/rules/negate-equal-op/ * style: Fix repeated-equality-comparison (PLR1714) on changed code --- gui/wxpython/animation/dialogs.py | 2 +- gui/wxpython/gcp/manager.py | 10 +++++----- gui/wxpython/gcp/mapdisplay.py | 2 +- gui/wxpython/gui_core/vselect.py | 2 +- gui/wxpython/iclass/frame.py | 4 ++-- gui/wxpython/image2target/ii2t_manager.py | 6 +++--- gui/wxpython/image2target/ii2t_mapdisplay.py | 2 +- gui/wxpython/iscatt/plots.py | 10 +++++----- gui/wxpython/mapdisp/frame.py | 6 +++--- gui/wxpython/nviz/mapwindow.py | 4 ++-- gui/wxpython/nviz/wxnviz.py | 2 +- gui/wxpython/photo2image/ip2i_manager.py | 6 +++--- gui/wxpython/photo2image/ip2i_mapdisplay.py | 2 +- gui/wxpython/psmap/frame.py | 2 +- gui/wxpython/rdigit/dialogs.py | 2 +- gui/wxpython/vdigit/wxdigit.py | 4 ++-- gui/wxpython/vnet/widgets.py | 2 +- lib/init/grass.py | 4 ++-- man/build_keywords.py | 2 +- pyproject.toml | 1 - python/grass/gunittest/case.py | 2 +- python/grass/pygrass/modules/interface/parameter.py | 2 +- python/grass/temporal/spatial_extent.py | 4 ++-- scripts/g.extension.all/g.extension.all.py | 2 +- .../testsuite/test_r_semantic_label.py | 2 +- utils/mkhtml.py | 2 +- 26 files changed, 44 insertions(+), 45 deletions(-) diff --git a/gui/wxpython/animation/dialogs.py b/gui/wxpython/animation/dialogs.py index 3d70dbd2639..428abdb2626 100644 --- a/gui/wxpython/animation/dialogs.py +++ b/gui/wxpython/animation/dialogs.py @@ -1572,7 +1572,7 @@ def _export_file_validation(self, filebrowsebtn, file_path, file_postfix): caption=_("Overwrite?"), style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, ) - if not overwrite_dlg.ShowModal() == wx.ID_YES: + if overwrite_dlg.ShowModal() != wx.ID_YES: overwrite_dlg.Destroy() return False overwrite_dlg.Destroy() diff --git a/gui/wxpython/gcp/manager.py b/gui/wxpython/gcp/manager.py index e5e0dd37471..a96555fe271 100644 --- a/gui/wxpython/gcp/manager.py +++ b/gui/wxpython/gcp/manager.py @@ -1810,7 +1810,7 @@ def OnGeorect(self, event): overwrite=self.overwrite, ) if overwrite_dlg: - if not overwrite_dlg.ShowModal() == wx.ID_YES: + if overwrite_dlg.ShowModal() != wx.ID_YES: overwrite_dlg.Destroy() return overwrite_dlg.Destroy() @@ -1870,7 +1870,7 @@ def OnGeorect(self, event): overwrite=self.overwrite, ) if overwrite_dlg: - if not overwrite_dlg.ShowModal() == wx.ID_YES: + if overwrite_dlg.ShowModal() != wx.ID_YES: overwrite_dlg.Destroy() return overwrite_dlg.Destroy() @@ -2300,7 +2300,7 @@ def AdjustMap(self, newreg): def OnZoomToSource(self, event): """Set target map window to match extents of source map window""" - if not self.MapWindow == self.TgtMapWindow: + if self.MapWindow != self.TgtMapWindow: self.MapWindow = self.TgtMapWindow self.Map = self.TgtMap self.UpdateActive(self.TgtMapWindow) @@ -2313,7 +2313,7 @@ def OnZoomToSource(self, event): def OnZoomToTarget(self, event): """Set source map window to match extents of target map window""" - if not self.MapWindow == self.SrcMapWindow: + if self.MapWindow != self.SrcMapWindow: self.MapWindow = self.SrcMapWindow self.Map = self.SrcMap self.UpdateActive(self.SrcMapWindow) @@ -3323,7 +3323,7 @@ def OnSrcSelection(self, event): tmp_map = self.srcselection.GetValue() - if not tmp_map == "" and not tmp_map == src_map: + if tmp_map not in ("", src_map): self.new_src_map = tmp_map def OnTgtRastSelection(self, event): diff --git a/gui/wxpython/gcp/mapdisplay.py b/gui/wxpython/gcp/mapdisplay.py index 66daa70d2ca..0681b03e4e8 100644 --- a/gui/wxpython/gcp/mapdisplay.py +++ b/gui/wxpython/gcp/mapdisplay.py @@ -575,7 +575,7 @@ def GetMapToolbar(self): return self.toolbars["gcpdisp"] def _setActiveMapWindow(self, mapWindow): - if not self.MapWindow == mapWindow: + if self.MapWindow != mapWindow: self.MapWindow = mapWindow self.Map = mapWindow.Map self.UpdateActive(mapWindow) diff --git a/gui/wxpython/gui_core/vselect.py b/gui/wxpython/gui_core/vselect.py index 0ff30afaafd..16bb64b7a57 100644 --- a/gui/wxpython/gui_core/vselect.py +++ b/gui/wxpython/gui_core/vselect.py @@ -232,7 +232,7 @@ def AddVecInfo(self, vInfoDictTMP) -> bool: if self._dialog: self.slist.AddItem(vInfoDictTMP) - return not len(self.selectedFeatures) == 0 + return len(self.selectedFeatures) != 0 def _draw(self): """Call class 'VectorSelectHighlighter' to draw selected features""" diff --git a/gui/wxpython/iclass/frame.py b/gui/wxpython/iclass/frame.py index 69c18780249..606c364c76f 100644 --- a/gui/wxpython/iclass/frame.py +++ b/gui/wxpython/iclass/frame.py @@ -570,7 +570,7 @@ def OnZoomMenu(self, event): def OnZoomToTraining(self, event): """Set preview display to match extents of training display""" - if not self.MapWindow == self.GetSecondWindow(): + if self.MapWindow != self.GetSecondWindow(): self.MapWindow = self.GetSecondWindow() self.Map = self.GetSecondMap() self.UpdateActive(self.GetSecondWindow()) @@ -583,7 +583,7 @@ def OnZoomToTraining(self, event): def OnZoomToPreview(self, event): """Set preview display to match extents of training display""" - if not self.MapWindow == self.GetFirstWindow(): + if self.MapWindow != self.GetFirstWindow(): self.MapWindow = self.GetFirstWindow() self.Map = self.GetFirstMap() self.UpdateActive(self.GetFirstWindow()) diff --git a/gui/wxpython/image2target/ii2t_manager.py b/gui/wxpython/image2target/ii2t_manager.py index 17811ceceb1..1c9958c9cef 100644 --- a/gui/wxpython/image2target/ii2t_manager.py +++ b/gui/wxpython/image2target/ii2t_manager.py @@ -2245,7 +2245,7 @@ def AdjustMap(self, newreg): def OnZoomToSource(self, event): """Set target map window to match extents of source map window""" - if not self.MapWindow == self.TgtMapWindow: + if self.MapWindow != self.TgtMapWindow: self.MapWindow = self.TgtMapWindow self.Map = self.TgtMap self.UpdateActive(self.TgtMapWindow) @@ -2258,7 +2258,7 @@ def OnZoomToSource(self, event): def OnZoomToTarget(self, event): """Set source map window to match extents of target map window""" - if not self.MapWindow == self.SrcMapWindow: + if self.MapWindow != self.SrcMapWindow: self.MapWindow = self.SrcMapWindow self.Map = self.SrcMap self.UpdateActive(self.SrcMapWindow) @@ -3282,7 +3282,7 @@ def OnSrcSelection(self, event): tmp_map = self.srcselection.GetValue() - if not tmp_map == "" and not tmp_map == src_map: + if tmp_map not in ("", src_map): self.new_src_map = tmp_map def OnTgtRastSelection(self, event): diff --git a/gui/wxpython/image2target/ii2t_mapdisplay.py b/gui/wxpython/image2target/ii2t_mapdisplay.py index b85a70a152f..c148eb314d2 100644 --- a/gui/wxpython/image2target/ii2t_mapdisplay.py +++ b/gui/wxpython/image2target/ii2t_mapdisplay.py @@ -567,7 +567,7 @@ def GetMapToolbar(self): return self.toolbars["gcpdisp"] def _setActiveMapWindow(self, mapWindow): - if not self.MapWindow == mapWindow: + if self.MapWindow != mapWindow: self.MapWindow = mapWindow self.Map = mapWindow.Map self.UpdateActive(mapWindow) diff --git a/gui/wxpython/iscatt/plots.py b/gui/wxpython/iscatt/plots.py index 08afe5906ed..32ce111c428 100644 --- a/gui/wxpython/iscatt/plots.py +++ b/gui/wxpython/iscatt/plots.py @@ -168,7 +168,7 @@ def SetEmpty(self): return self.polygon_drawer.SetEmpty() def OnRelease(self, event): - if not self.mode == "zoom": + if self.mode != "zoom": return self.zoom_rect.set_visible(False) self.ZoomRectangle(event) @@ -348,7 +348,7 @@ def ZoomWheel(self, event): def ZoomRectangle(self, event): # get the current x and y limits - if not self.mode == "zoom": + if self.mode != "zoom": return if event.inaxes is None: return @@ -394,7 +394,7 @@ def OnCanvasLeave(self, event): def PanMotion(self, event): "on mouse movement" - if not self.mode == "pan": + if self.mode != "pan": return if event.inaxes is None: return @@ -426,7 +426,7 @@ def PanMotion(self, event): self.canvas.draw() def ZoomRectMotion(self, event): - if not self.mode == "zoom": + if self.mode != "zoom": return if event.inaxes is None: return @@ -866,7 +866,7 @@ def _addVertex(self, event): def motion_notify_callback(self, event): "on mouse movement" - if not self.mode == "move_vertex": + if self.mode != "move_vertex": return if not self.showverts: return diff --git a/gui/wxpython/mapdisp/frame.py b/gui/wxpython/mapdisp/frame.py index 0b948f63794..f13ffbe0a81 100644 --- a/gui/wxpython/mapdisp/frame.py +++ b/gui/wxpython/mapdisp/frame.py @@ -831,7 +831,7 @@ def _DToRastDone(): overwrite=overwrite, getErrorMsg=True, ) - if not returncode == 0: + if returncode != 0: self._giface.WriteError(_("Failed to run d.to.rast:\n") + messages) return # set region for composite @@ -839,7 +839,7 @@ def _DToRastDone(): returncode, messages = RunCommand( "g.region", raster=tmpName + ".red", quiet=True, getErrorMsg=True ) - if not returncode == 0: + if returncode != 0: gs.del_temp_region() self._giface.WriteError(_("Failed to run d.to.rast:\n") + messages) return @@ -862,7 +862,7 @@ def _DToRastDone(): quiet=True, name=[tmpName + ".red", tmpName + ".green", tmpName + ".blue"], ) - if not returncode == 0: + if returncode != 0: self._giface.WriteError(_("Failed to run d.to.rast:\n") + messages) gs.try_remove(pngFile) return diff --git a/gui/wxpython/nviz/mapwindow.py b/gui/wxpython/nviz/mapwindow.py index eaf0d266d4e..550939da7ce 100644 --- a/gui/wxpython/nviz/mapwindow.py +++ b/gui/wxpython/nviz/mapwindow.py @@ -534,7 +534,7 @@ def OnKeyDown(self, event): Used for fly-through mode. """ - if not self.mouse["use"] == "fly": + if self.mouse["use"] != "fly": return key = event.GetKeyCode() @@ -596,7 +596,7 @@ def OnKeyUp(self, event): Used for fly-through mode. """ - if not self.mouse["use"] == "fly": + if self.mouse["use"] != "fly": return key = event.GetKeyCode() diff --git a/gui/wxpython/nviz/wxnviz.py b/gui/wxpython/nviz/wxnviz.py index 8002d6f32d2..e80a9fc9382 100644 --- a/gui/wxpython/nviz/wxnviz.py +++ b/gui/wxpython/nviz/wxnviz.py @@ -83,7 +83,7 @@ def print_progress(value): """Redirect progress info""" global progress if progress: - if not progress.GetRange() == 100: + if progress.GetRange() != 100: progress.SetRange(100) progress.SetValue(value) else: diff --git a/gui/wxpython/photo2image/ip2i_manager.py b/gui/wxpython/photo2image/ip2i_manager.py index f251a1fa36e..e27e763fb2a 100644 --- a/gui/wxpython/photo2image/ip2i_manager.py +++ b/gui/wxpython/photo2image/ip2i_manager.py @@ -1531,7 +1531,7 @@ def AdjustMap(self, newreg): def OnZoomToSource(self, event): """Set target map window to match extents of source map window""" - if not self.MapWindow == self.TgtMapWindow: + if self.MapWindow != self.TgtMapWindow: self.MapWindow = self.TgtMapWindow self.Map = self.TgtMap self.UpdateActive(self.TgtMapWindow) @@ -1544,7 +1544,7 @@ def OnZoomToSource(self, event): def OnZoomToTarget(self, event): """Set source map window to match extents of target map window""" - if not self.MapWindow == self.SrcMapWindow: + if self.MapWindow != self.SrcMapWindow: self.MapWindow = self.SrcMapWindow self.Map = self.SrcMap self.UpdateActive(self.SrcMapWindow) @@ -2381,7 +2381,7 @@ def OnSrcSelection(self, event): tmp_map = self.srcselection.GetValue() - if not tmp_map == "" and not tmp_map == src_map: + if tmp_map not in ("", src_map): self.new_src_map = tmp_map def OnTgtRastSelection(self, event): diff --git a/gui/wxpython/photo2image/ip2i_mapdisplay.py b/gui/wxpython/photo2image/ip2i_mapdisplay.py index f85be35ec4a..aa085f2b43a 100644 --- a/gui/wxpython/photo2image/ip2i_mapdisplay.py +++ b/gui/wxpython/photo2image/ip2i_mapdisplay.py @@ -559,7 +559,7 @@ def GetMapToolbar(self): return self.toolbars["gcpdisp"] def _setActiveMapWindow(self, mapWindow): - if not self.MapWindow == mapWindow: + if self.MapWindow != mapWindow: self.MapWindow = mapWindow self.Map = mapWindow.Map self.UpdateActive(mapWindow) diff --git a/gui/wxpython/psmap/frame.py b/gui/wxpython/psmap/frame.py index 3effc33cd4d..fa4a150aa3b 100644 --- a/gui/wxpython/psmap/frame.py +++ b/gui/wxpython/psmap/frame.py @@ -308,7 +308,7 @@ def OnPsMapDialog(self, event): def OnPDFFile(self, event): """Generate PDF from PS with ps2pdf if available""" - if not sys.platform == "win32": + if sys.platform != "win32": try: p = gs.Popen(["ps2pdf"], stderr=gs.PIPE) p.stderr.close() diff --git a/gui/wxpython/rdigit/dialogs.py b/gui/wxpython/rdigit/dialogs.py index 650b75feb63..c632a84c0fe 100644 --- a/gui/wxpython/rdigit/dialogs.py +++ b/gui/wxpython/rdigit/dialogs.py @@ -114,7 +114,7 @@ def OnOK(self, event): caption=_("Overwrite?"), style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, ) - if not dlgOverwrite.ShowModal() == wx.ID_YES: + if dlgOverwrite.ShowModal() != wx.ID_YES: dlgOverwrite.Destroy() return else: diff --git a/gui/wxpython/vdigit/wxdigit.py b/gui/wxpython/vdigit/wxdigit.py index ddcdc5a2755..154d5ab7c81 100644 --- a/gui/wxpython/vdigit/wxdigit.py +++ b/gui/wxpython/vdigit/wxdigit.py @@ -1084,7 +1084,7 @@ def EditLine(self, line, coords): # apply snapping (node or vertex) snap = self._getSnapMode() if snap != NO_SNAP: - modeSnap = not (snap == SNAP) + modeSnap = snap != SNAP Vedit_snap_line( self.poMapInfo, self.popoBgMapInfo, @@ -1889,7 +1889,7 @@ def _addFeature(self, ftype, coords, layer, cat, snap, threshold): if snap != NO_SNAP: # apply snapping (node or vertex) - modeSnap = not (snap == SNAP) + modeSnap = snap != SNAP Vedit_snap_line( self.poMapInfo, self.popoBgMapInfo, diff --git a/gui/wxpython/vnet/widgets.py b/gui/wxpython/vnet/widgets.py index 12477cc93ea..ed1f2aa514c 100644 --- a/gui/wxpython/vnet/widgets.py +++ b/gui/wxpython/vnet/widgets.py @@ -542,7 +542,7 @@ def IsShown(self, colName) -> bool: :return: False - if is not shown """ - return not self._getColumnNum(colName) == -1 + return self._getColumnNum(colName) != -1 class EditItem(wx.Dialog): diff --git a/lib/init/grass.py b/lib/init/grass.py index 40312471e44..f32f290d090 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -400,7 +400,7 @@ def create_grass_config_dir(): os.makedirs(directory) except OSError as e: # Can happen as a race condition - if not e.errno == errno.EEXIST or not os.path.isdir(directory): + if e.errno != errno.EEXIST or not os.path.isdir(directory): fatal( _( "Failed to create configuration directory '{}' with error: {}" @@ -1631,7 +1631,7 @@ def sh_like_startup(location, location_name, grass_env_file, sh): # save command history in mapset dir and remember more # bash history file handled in specific_addition - if not sh == "bash": + if sh != "bash": os.environ["HISTFILE"] = os.path.join(location, sh_history) # instead of changing $HOME, start bash with: diff --git a/man/build_keywords.py b/man/build_keywords.py index 6070fad1a28..b0dfe95e0e3 100644 --- a/man/build_keywords.py +++ b/man/build_keywords.py @@ -158,7 +158,7 @@ def get_module_man_html_file_path(module): for k in sorted(char_list.keys()): test_length += 1 # toc += '

  • %s
  • ' % (char_list[k], k) - if test_length % 4 == 0 and not test_length == all_keys: + if test_length % 4 == 0 and test_length != all_keys: toc += '\n%s, ' % (char_list[k], k) elif test_length % 4 == 0 and test_length == all_keys: toc += '\n%s' % (char_list[k], k) diff --git a/pyproject.toml b/pyproject.toml index 649e309a73f..fa607b9a2b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -256,7 +256,6 @@ ignore = [ "SIM114", # if-with-same-arms "SIM116", # if-else-block-instead-of-dict-lookup "SIM118", # in-dict-keys - "SIM201", # negate-equal-op "SIM223", # expr-and-false "SIM401", # if-else-block-instead-of-dict-get "SLF001", # private-member-access diff --git a/python/grass/gunittest/case.py b/python/grass/gunittest/case.py index da2c7486d16..b5563e47e9e 100644 --- a/python/grass/gunittest/case.py +++ b/python/grass/gunittest/case.py @@ -695,7 +695,7 @@ def assertFileMd5(self, filename, md5, text=False, msg=None): actual = text_file_md5(filename) else: actual = file_md5(filename) - if not actual == md5: + if actual != md5: standardMsg = ( "File <{name}> does not have the right MD5 sum.\n" "Expected is <{expected}>," diff --git a/python/grass/pygrass/modules/interface/parameter.py b/python/grass/pygrass/modules/interface/parameter.py index 798efde56b7..3b58ea2b372 100644 --- a/python/grass/pygrass/modules/interface/parameter.py +++ b/python/grass/pygrass/modules/interface/parameter.py @@ -216,7 +216,7 @@ def __init__(self, xparameter=None, diz=None): # if "gisprompt" in diz and diz["gisprompt"]: self.typedesc = diz["gisprompt"].get("prompt", "") - self.input = not diz["gisprompt"]["age"] == "new" + self.input = diz["gisprompt"]["age"] != "new" else: self.input = True diff --git a/python/grass/temporal/spatial_extent.py b/python/grass/temporal/spatial_extent.py index 329a0a4a684..26498e0385e 100644 --- a/python/grass/temporal/spatial_extent.py +++ b/python/grass/temporal/spatial_extent.py @@ -875,7 +875,7 @@ def cover_2d(self, extent) -> bool: if eS > S and eS < N: edge_count += 1 - return not edge_count == 0 + return edge_count != 0 def cover(self, extent) -> bool: """Return True if this extent covers the provided spatial @@ -956,7 +956,7 @@ def cover(self, extent) -> bool: if eB > B and eB < T: edge_count += 1 - return not edge_count == 0 + return edge_count != 0 def covered_2d(self, extent): """Return True if this extent is covered by the provided spatial diff --git a/scripts/g.extension.all/g.extension.all.py b/scripts/g.extension.all/g.extension.all.py index 7f0b36f4dc6..43d50073178 100644 --- a/scripts/g.extension.all/g.extension.all.py +++ b/scripts/g.extension.all/g.extension.all.py @@ -104,7 +104,7 @@ def download_modules_xml_file(url, response_format, *args, **kwargs): try: response = urlopen(url, *args, **kwargs) - if not response.code == 200: + if response.code != 200: index = HTTP_STATUS_CODES.index(response.code) desc = HTTP_STATUS_CODES[index].description gs.fatal( diff --git a/scripts/r.semantic.label/testsuite/test_r_semantic_label.py b/scripts/r.semantic.label/testsuite/test_r_semantic_label.py index b7456e22633..990954dbb5f 100644 --- a/scripts/r.semantic.label/testsuite/test_r_semantic_label.py +++ b/scripts/r.semantic.label/testsuite/test_r_semantic_label.py @@ -27,7 +27,7 @@ def read_semantic_label(self): return rast.info.semantic_label def test_semantic_label_assign_not_current_mapset(self): - if not self.mapset == "PERMANENT": + if self.mapset != "PERMANENT": self.mapset.name = "PERMANENT" a_map = self.mapset.glist(type="raster")[0] module = SimpleModule( diff --git a/utils/mkhtml.py b/utils/mkhtml.py index d36ea78663d..54b2b80e87d 100644 --- a/utils/mkhtml.py +++ b/utils/mkhtml.py @@ -159,7 +159,7 @@ def download_git_commit(url, response_format, *args, **kwargs): """ try: response = urlopen(url, *args, **kwargs) - if not response.code == 200: + if response.code != 200: index = HTTP_STATUS_CODES.index(response.code) desc = HTTP_STATUS_CODES[index].description gs.fatal( From 5eca6d67a20d8b4d868952e57340f1beacf569d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 28 Sep 2024 15:11:39 -0400 Subject: [PATCH 113/209] style: Fix os-stat (PTH116) by replacing os.stat() calls with pathlib (#4412) * style: Fix os-stat (PTH116) by replacing os.stat() calls with pathlib Ruff rule: https://docs.astral.sh/ruff/rules/os-stat/ * Change remaining os.stat() usages * Fix Path join with a string --- gui/wxpython/core/watchdog.py | 5 ++++- gui/wxpython/gui_core/preferences.py | 5 +++-- imagery/i.gensig/testsuite/test_i_gensig.py | 3 ++- lib/imagery/testsuite/test_imagery_sigfile.py | 10 +++++----- lib/imagery/testsuite/test_imagery_sigsetfile.py | 8 ++++---- pyproject.toml | 1 - python/grass/app/data.py | 2 +- python/grass/grassdb/checks.py | 2 +- 8 files changed, 20 insertions(+), 16 deletions(-) diff --git a/gui/wxpython/core/watchdog.py b/gui/wxpython/core/watchdog.py index 652bc1d755d..591bb36b477 100644 --- a/gui/wxpython/core/watchdog.py +++ b/gui/wxpython/core/watchdog.py @@ -19,6 +19,9 @@ import os import time + +from pathlib import Path + import wx from wx.lib.newevent import NewEvent @@ -59,7 +62,7 @@ def on_modified(self, event): not event.is_directory and os.path.basename(event.src_path) == self.rcfile_name ): - timestamp = os.stat(event.src_path).st_mtime + timestamp = Path(event.src_path).stat().st_mtime if timestamp - self.modified_time < 0.5: return self.modified_time = timestamp diff --git a/gui/wxpython/gui_core/preferences.py b/gui/wxpython/gui_core/preferences.py index a35d902bc7f..724e4a5aec0 100644 --- a/gui/wxpython/gui_core/preferences.py +++ b/gui/wxpython/gui_core/preferences.py @@ -28,6 +28,8 @@ import os import sys +from pathlib import Path + try: import pwd @@ -2425,8 +2427,7 @@ def LoadData(self): for mapset in self.parent.all_mapsets_ordered: index = self.InsertItem(self.GetItemCount(), mapset) - mapsetPath = os.path.join(locationPath, mapset) - stat_info = os.stat(mapsetPath) + stat_info = Path(locationPath, mapset).stat() if havePwd: try: self.SetItem(index, 1, "%s" % pwd.getpwuid(stat_info.st_uid)[0]) diff --git a/imagery/i.gensig/testsuite/test_i_gensig.py b/imagery/i.gensig/testsuite/test_i_gensig.py index 0498cabaf79..d75e3da2af4 100644 --- a/imagery/i.gensig/testsuite/test_i_gensig.py +++ b/imagery/i.gensig/testsuite/test_i_gensig.py @@ -13,6 +13,7 @@ import stat import ctypes import shutil +from pathlib import Path from grass.pygrass import utils from grass.pygrass.gis import Mapset @@ -107,7 +108,7 @@ def test_creation(self): ) # File must be present - sig_stat = os.stat(f"{self.sig_dir1}/sig") + sig_stat = Path(self.sig_dir1, "sig").stat() self.assertTrue(stat.S_ISREG(sig_stat.st_mode)) # Compare values within sig file diff --git a/lib/imagery/testsuite/test_imagery_sigfile.py b/lib/imagery/testsuite/test_imagery_sigfile.py index 104cd5a59b4..8d0e288561d 100644 --- a/lib/imagery/testsuite/test_imagery_sigfile.py +++ b/lib/imagery/testsuite/test_imagery_sigfile.py @@ -9,10 +9,10 @@ for details """ -import os import stat import ctypes import shutil +from pathlib import Path from grass.gunittest.case import TestCase from grass.gunittest.main import test @@ -80,7 +80,7 @@ def test_roundtrip_signature_v1_norgb_one_label(self): # Write signatures to file p_new_sigfile = I_fopen_signature_file_new(self.sig_name) - sig_stat = os.stat(f"{self.sig_dir}/sig") + sig_stat = Path(self.sig_dir, "sig").stat() self.assertTrue(stat.S_ISREG(sig_stat.st_mode)) I_write_signatures(p_new_sigfile, ctypes.byref(So)) self.libc.fclose(p_new_sigfile) @@ -136,7 +136,7 @@ def test_broken_signature_v1_norgb(self): # Write signatures to file p_new_sigfile = I_fopen_signature_file_new(self.sig_name) - sig_stat = os.stat(f"{self.sig_dir}/sig") + sig_stat = Path(self.sig_dir, "sig").stat() self.assertTrue(stat.S_ISREG(sig_stat.st_mode)) I_write_signatures(p_new_sigfile, ctypes.byref(So)) self.libc.fclose(p_new_sigfile) @@ -188,7 +188,7 @@ def test_roundtrip_signature_v1_norgb_two_labelss(self): # Write signatures to file p_new_sigfile = I_fopen_signature_file_new(self.sig_name) - sig_stat = os.stat(f"{self.sig_dir}/sig") + sig_stat = Path(self.sig_dir, "sig").stat() self.assertTrue(stat.S_ISREG(sig_stat.st_mode)) I_write_signatures(p_new_sigfile, ctypes.byref(So)) self.libc.fclose(p_new_sigfile) @@ -277,7 +277,7 @@ def test_roundtrip_signature_v2_norgb_two_labels_oclass(self): # Write signatures to file p_new_sigfile = I_fopen_signature_file_new(self.sig_name) - sig_stat = os.stat(f"{self.sig_dir}/sig") + sig_stat = Path(self.sig_dir, "sig").stat() self.assertTrue(stat.S_ISREG(sig_stat.st_mode)) I_write_signatures(p_new_sigfile, ctypes.byref(So)) self.libc.fclose(p_new_sigfile) diff --git a/lib/imagery/testsuite/test_imagery_sigsetfile.py b/lib/imagery/testsuite/test_imagery_sigsetfile.py index b8bcb566520..d526e920885 100644 --- a/lib/imagery/testsuite/test_imagery_sigsetfile.py +++ b/lib/imagery/testsuite/test_imagery_sigsetfile.py @@ -9,10 +9,10 @@ for details """ -import os import stat import ctypes import shutil +from pathlib import Path from grass.gunittest.case import TestCase from grass.gunittest.main import test @@ -84,7 +84,7 @@ def test_roundtrip_sigset_v1_one_label(self): # Write signatures to file p_new_sigfile = I_fopen_sigset_file_new(self.sig_name) - sig_stat = os.stat(f"{self.sig_dir}/sig") + sig_stat = Path(self.sig_dir, "sig").stat() self.assertTrue(stat.S_ISREG(sig_stat.st_mode)) I_WriteSigSet(p_new_sigfile, ctypes.byref(So)) self.libc.fclose(p_new_sigfile) @@ -139,7 +139,7 @@ def test_read_fail_sigset_v1_one_label(self): # Write signatures to file p_new_sigfile = I_fopen_sigset_file_new(self.sig_name) - sig_stat = os.stat(f"{self.sig_dir}/sig") + sig_stat = Path(self.sig_dir, "sig").stat() self.assertTrue(stat.S_ISREG(sig_stat.st_mode)) I_WriteSigSet(p_new_sigfile, ctypes.byref(So)) self.libc.fclose(p_new_sigfile) @@ -183,7 +183,7 @@ def test_roundtrip_sigset_v1_two_labels(self): # Write signatures to file p_new_sigfile = I_fopen_sigset_file_new(self.sig_name) - sig_stat = os.stat(f"{self.sig_dir}/sig") + sig_stat = Path(self.sig_dir, "sig").stat() self.assertTrue(stat.S_ISREG(sig_stat.st_mode)) I_WriteSigSet(p_new_sigfile, ctypes.byref(So)) self.libc.fclose(p_new_sigfile) diff --git a/pyproject.toml b/pyproject.toml index fa607b9a2b1..d3aa0049c28 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -200,7 +200,6 @@ ignore = [ "PTH111", # os-path-expanduser "PTH112", # os-path-isdir "PTH113", # os-path-isfile - "PTH116", # os-stat "PTH117", # os-path-isabs "PTH118", # os-path-join "PTH119", # os-path-basename diff --git a/python/grass/app/data.py b/python/grass/app/data.py index 2853b573f9c..10997cd59e8 100644 --- a/python/grass/app/data.py +++ b/python/grass/app/data.py @@ -190,7 +190,7 @@ def lock_mapset(mapset_path, force_lock_removal, message_callback): raise MapsetLockingException(_("Path '{}' doesn't exist").format(mapset_path)) if not os.access(mapset_path, os.W_OK): error = _("Path '{}' not accessible.").format(mapset_path) - stat_info = os.stat(mapset_path) + stat_info = Path(mapset_path).stat() mapset_uid = stat_info.st_uid if mapset_uid != os.getuid(): error = "{error}\n{detail}".format( diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 4de65a4cba3..6bf77a3bf65 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -113,7 +113,7 @@ def is_current_user_mapset_owner(mapset_path): # Mapset needs to be owned by user. if sys.platform == "win32": return True - stat_info = os.stat(mapset_path) + stat_info = Path(mapset_path).stat() mapset_uid = stat_info.st_uid return mapset_uid == os.getuid() From ead659fc4262a72ceeeca4a051d5288aa91f1214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 28 Sep 2024 16:09:53 -0400 Subject: [PATCH 114/209] style: Fix os-getcwd (PTH109) by replacing `os.getcwd()` calls with `Path.cwd()` (#4413) --- gui/wxpython/animation/dialogs.py | 15 +++++++++------ gui/wxpython/datacatalog/catalog.py | 7 ++++++- gui/wxpython/gmodeler/panels.py | 8 +++++--- gui/wxpython/gui_core/forms.py | 7 ++++--- gui/wxpython/gui_core/gselect.py | 10 ++++++---- gui/wxpython/gui_core/pyedit.py | 4 ++-- gui/wxpython/image2target/ii2t_gis_set.py | 4 +++- gui/wxpython/lmgr/frame.py | 12 ++++++------ gui/wxpython/lmgr/workspace.py | 6 ++++-- gui/wxpython/location_wizard/wizard.py | 11 ++++++++--- gui/wxpython/main_window/frame.py | 12 ++++++------ gui/wxpython/modules/colorrules.py | 6 ++++-- gui/wxpython/modules/import_export.py | 4 +++- gui/wxpython/nviz/tools.py | 4 +++- gui/wxpython/psmap/dialogs.py | 3 ++- gui/wxpython/tplot/frame.py | 3 ++- gui/wxpython/wxplot/profile.py | 4 +++- lib/init/grass.py | 4 ++-- locale/grass_po_stats.py | 4 +++- pyproject.toml | 1 - python/grass/grassdb/checks.py | 2 +- python/grass/pygrass/tests/benchmark.py | 6 +++--- python/grass/script/core.py | 2 +- python/grass/script/utils.py | 12 +++++++----- python/grass/temporal/stds_export.py | 2 +- python/grass/temporal/stds_import.py | 2 +- scripts/r.pack/r.pack.py | 4 +++- scripts/v.pack/v.pack.py | 4 +++- utils/mkhtml.py | 2 +- 29 files changed, 102 insertions(+), 63 deletions(-) diff --git a/gui/wxpython/animation/dialogs.py b/gui/wxpython/animation/dialogs.py index 428abdb2626..f6e4db341c5 100644 --- a/gui/wxpython/animation/dialogs.py +++ b/gui/wxpython/animation/dialogs.py @@ -24,6 +24,9 @@ import wx import copy import datetime + +from pathlib import Path + import wx.lib.filebrowsebutton as filebrowse import wx.lib.scrolledpanel as SP import wx.lib.colourselect as csel @@ -488,7 +491,7 @@ def _create3DPanel(self, parent): labelText=_("Workspace file:"), dialogTitle=_("Choose workspace file to import 3D view parameters"), buttonText=_("Browse"), - startDirectory=os.getcwd(), + startDirectory=str(Path.cwd()), fileMode=0, fileMask="GRASS Workspace File (*.gxw)|*.gxw", ) @@ -1089,7 +1092,7 @@ def _createDecorationsProperties(self, panel): labelText=_("Image file:"), dialogTitle=_("Choose image file"), buttonText=_("Browse"), - startDirectory=os.getcwd(), + startDirectory=str(Path.cwd()), fileMode=wx.FD_OPEN, changeCallback=self.OnSetImage, ) @@ -1191,7 +1194,7 @@ def _createExportFormatPanel(self, notebook): labelText=_("Directory:"), dialogTitle=_("Choose directory for export"), buttonText=_("Browse"), - startDirectory=os.getcwd(), + startDirectory=str(Path.cwd()), ) dirGridSizer = wx.GridBagSizer(hgap=5, vgap=5) @@ -1219,7 +1222,7 @@ def _createExportFormatPanel(self, notebook): labelText=_("GIF file:"), dialogTitle=_("Choose file to save animation"), buttonText=_("Browse"), - startDirectory=os.getcwd(), + startDirectory=str(Path.cwd()), fileMode=wx.FD_SAVE, ) gifGridSizer = wx.GridBagSizer(hgap=5, vgap=5) @@ -1242,7 +1245,7 @@ def _createExportFormatPanel(self, notebook): labelText=_("SWF file:"), dialogTitle=_("Choose file to save animation"), buttonText=_("Browse"), - startDirectory=os.getcwd(), + startDirectory=str(Path.cwd()), fileMode=wx.FD_SAVE, ) swfGridSizer = wx.GridBagSizer(hgap=5, vgap=5) @@ -1273,7 +1276,7 @@ def _createExportFormatPanel(self, notebook): labelText=_("AVI file:"), dialogTitle=_("Choose file to save animation"), buttonText=_("Browse"), - startDirectory=os.getcwd(), + startDirectory=str(Path.cwd()), fileMode=wx.FD_SAVE, ) encodingLabel = StaticText( diff --git a/gui/wxpython/datacatalog/catalog.py b/gui/wxpython/datacatalog/catalog.py index 880190b0943..4835061d968 100644 --- a/gui/wxpython/datacatalog/catalog.py +++ b/gui/wxpython/datacatalog/catalog.py @@ -19,6 +19,8 @@ import wx import os +from pathlib import Path + from core.debug import Debug from datacatalog.tree import DataCatalogTree from datacatalog.toolbars import DataCatalogToolbar, DataCatalogSearch @@ -200,7 +202,10 @@ def OnReloadCurrentMapset(self, event): def OnAddGrassDB(self, event): """Add grass database""" dlg = wx.DirDialog( - self, _("Choose GRASS data directory:"), os.getcwd(), wx.DD_DEFAULT_STYLE + self, + _("Choose GRASS data directory:"), + str(Path.cwd()), + wx.DD_DEFAULT_STYLE, ) if dlg.ShowModal() == wx.ID_OK: grassdatabase = dlg.GetPath() diff --git a/gui/wxpython/gmodeler/panels.py b/gui/wxpython/gmodeler/panels.py index 93ef770efe1..416a9b85592 100644 --- a/gui/wxpython/gmodeler/panels.py +++ b/gui/wxpython/gmodeler/panels.py @@ -25,6 +25,8 @@ import random import math +from pathlib import Path + import wx from wx.lib import ogl @@ -834,7 +836,7 @@ def OnModelOpen(self, event): dlg = wx.FileDialog( parent=self, message=_("Choose model file"), - defaultDir=os.getcwd(), + defaultDir=str(Path.cwd()), wildcard=_("GRASS Model File (*.gxm)|*.gxm"), ) if dlg.ShowModal() == wx.ID_OK: @@ -892,7 +894,7 @@ def OnModelSaveAs(self, event=None): dlg = wx.FileDialog( parent=self, message=_("Choose file to save current model"), - defaultDir=os.getcwd(), + defaultDir=str(Path.cwd()), wildcard=_("GRASS Model File (*.gxm)|*.gxm"), style=wx.FD_SAVE, ) @@ -1740,7 +1742,7 @@ def SaveAs(self, force=False): parent=self, message=_("Choose file to save"), defaultFile=os.path.basename(self.parent.GetModelFile(ext=False)), - defaultDir=os.getcwd(), + defaultDir=str(Path.cwd()), wildcard=fn_wildcard, style=wx.FD_SAVE, ) diff --git a/gui/wxpython/gui_core/forms.py b/gui/wxpython/gui_core/forms.py index 84fd849908c..74bcc00f85a 100644 --- a/gui/wxpython/gui_core/forms.py +++ b/gui/wxpython/gui_core/forms.py @@ -58,6 +58,7 @@ import codecs from threading import Thread +from pathlib import Path import wx @@ -2034,7 +2035,7 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar dialogTitle=_("Choose %s") % p.get("description", _("file")).lower(), buttonText=_("Browse"), - startDirectory=os.getcwd(), + startDirectory=str(Path.cwd()), fileMode=fmode, changeCallback=self.OnSetValue, ) @@ -2145,7 +2146,7 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar dialogTitle=_("Choose %s") % p.get("description", _("Directory")), buttonText=_("Browse"), - startDirectory=os.getcwd(), + startDirectory=str(Path.cwd()), newDirectory=True, changeCallback=self.OnSetValue, ) @@ -2624,7 +2625,7 @@ def OnFileSave(self, event): dlg = wx.FileDialog( parent=self, message=_("Save input as..."), - defaultDir=os.getcwd(), + defaultDir=str(Path.cwd()), style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT, ) diff --git a/gui/wxpython/gui_core/gselect.py b/gui/wxpython/gui_core/gselect.py index 4bb9af5b50e..af71cc4f550 100644 --- a/gui/wxpython/gui_core/gselect.py +++ b/gui/wxpython/gui_core/gselect.py @@ -47,6 +47,8 @@ import glob import ctypes +from pathlib import Path + import wx from core import globalvar @@ -1558,7 +1560,7 @@ def __init__( labelText=_("File:"), dialogTitle=_("Choose file to import"), buttonText=_("Browse"), - startDirectory=os.getcwd(), + startDirectory=str(Path.cwd()), changeCallback=self.OnUpdate, fileMask=fileMask, ) @@ -1575,7 +1577,7 @@ def __init__( labelText=_("Directory:"), dialogTitle=_("Choose input directory"), buttonText=_("Browse"), - startDirectory=os.getcwd(), + startDirectory=str(Path.cwd()), changeCallback=self.OnUpdate, ) browse.GetChildren()[1].SetName("GdalSelectDataSource") @@ -1628,7 +1630,7 @@ def __init__( labelText=_("Name:"), dialogTitle=_("Choose file"), buttonText=_("Browse"), - startDirectory=os.getcwd(), + startDirectory=str(Path.cwd()), changeCallback=self.OnUpdate, ) browse.GetChildren()[1].SetName("GdalSelectDataSource") @@ -1663,7 +1665,7 @@ def __init__( labelText=_("Directory:"), dialogTitle=_("Choose input directory"), buttonText=_("Browse"), - startDirectory=os.getcwd(), + startDirectory=str(Path.cwd()), changeCallback=self.OnUpdate, ) self.dbWidgets["dirbrowse"] = browse diff --git a/gui/wxpython/gui_core/pyedit.py b/gui/wxpython/gui_core/pyedit.py index 2de2d45b066..5958ffb6d68 100644 --- a/gui/wxpython/gui_core/pyedit.py +++ b/gui/wxpython/gui_core/pyedit.py @@ -395,7 +395,7 @@ def SaveAs(self): dlg = wx.FileDialog( parent=self.guiparent, message=_("Choose file to save"), - defaultDir=os.getcwd(), + defaultDir=str(Path.cwd()), wildcard=_("Python script (*.py)|*.py"), style=wx.FD_SAVE, ) @@ -466,7 +466,7 @@ def Open(self): dlg = wx.FileDialog( parent=self.guiparent, message=_("Open file"), - defaultDir=os.getcwd(), + defaultDir=str(Path.cwd()), wildcard=_("Python script (*.py)|*.py"), style=wx.FD_OPEN, ) diff --git a/gui/wxpython/image2target/ii2t_gis_set.py b/gui/wxpython/image2target/ii2t_gis_set.py index 0f51d969e93..187b01d1740 100644 --- a/gui/wxpython/image2target/ii2t_gis_set.py +++ b/gui/wxpython/image2target/ii2t_gis_set.py @@ -27,6 +27,8 @@ import platform import getpass +from pathlib import Path + from core import globalvar import wx import wx.lib.mixins.listctrl as listmix @@ -315,7 +317,7 @@ def _set_properties(self, version, revision): if os.path.isdir(os.getenv("HOME")): self.gisdbase = os.getenv("HOME") else: - self.gisdbase = os.getcwd() + self.gisdbase = str(Path.cwd()) try: self.tgisdbase.SetValue(self.gisdbase) except UnicodeDecodeError: diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index a17b168f747..4eae371f68b 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -24,6 +24,8 @@ import platform import re +from pathlib import Path + from core import globalvar import wx import wx.aui @@ -848,7 +850,7 @@ def OnRunModel(self, event): dlg = wx.FileDialog( parent=self, message=_("Choose model to run"), - defaultDir=os.getcwd(), + defaultDir=str(Path.cwd()), wildcard=_("GRASS Model File (*.gxm)|*.gxm"), ) if dlg.ShowModal() == wx.ID_OK: @@ -1223,7 +1225,7 @@ def OnRunScript(self, event): dlg = wx.FileDialog( parent=self, message=_("Choose script file to run"), - defaultDir=os.getcwd(), + defaultDir=str(Path.cwd()), wildcard=_("Python script (*.py)|*.py|Bash script (*.sh)|*.sh"), ) @@ -1377,9 +1379,7 @@ def write_beginning(parameter=None, command=None): self._giface.WriteCmdLog(" ".join(command)) def write_changed(): - self._giface.WriteLog( - _('Working directory changed to:\n"%s"') % os.getcwd() - ) + self._giface.WriteLog(_('Working directory changed to:\n"%s"') % Path.cwd()) def write_end(): self._giface.WriteCmdLog(" ") @@ -1433,7 +1433,7 @@ def write_help(): dlg = wx.DirDialog( parent=self, message=_("Choose a working directory"), - defaultPath=os.getcwd(), + defaultPath=str(Path.cwd()), ) if dlg.ShowModal() == wx.ID_OK: diff --git a/gui/wxpython/lmgr/workspace.py b/gui/wxpython/lmgr/workspace.py index bb40469fa56..a593c19b19c 100644 --- a/gui/wxpython/lmgr/workspace.py +++ b/gui/wxpython/lmgr/workspace.py @@ -18,6 +18,8 @@ import xml.etree.ElementTree as ET +from pathlib import Path + import wx import wx.aui @@ -103,7 +105,7 @@ def Open(self): dlg = wx.FileDialog( parent=self.lmgr, message=_("Choose workspace file"), - defaultDir=os.getcwd(), + defaultDir=str(Path.cwd()), wildcard=_("GRASS Workspace File (*.gxw)|*.gxw"), ) @@ -362,7 +364,7 @@ def SaveAs(self): dlg = wx.FileDialog( parent=self.lmgr, message=_("Choose file to save current workspace"), - defaultDir=os.getcwd(), + defaultDir=str(Path.cwd()), wildcard=_("GRASS Workspace File (*.gxw)|*.gxw"), style=wx.FD_SAVE, ) diff --git a/gui/wxpython/location_wizard/wizard.py b/gui/wxpython/location_wizard/wizard.py index 7ba03ebee04..2cccdf5e301 100644 --- a/gui/wxpython/location_wizard/wizard.py +++ b/gui/wxpython/location_wizard/wizard.py @@ -38,6 +38,8 @@ import locale import functools +from pathlib import Path + import wx import wx.lib.mixins.listctrl as listmix from core import globalvar @@ -318,7 +320,10 @@ def OnChangeName(self, event): def OnBrowse(self, event): """Choose GRASS data directory""" dlg = wx.DirDialog( - self, _("Choose GRASS data directory:"), os.getcwd(), wx.DD_DEFAULT_STYLE + self, + _("Choose GRASS data directory:"), + str(Path.cwd()), + wx.DD_DEFAULT_STYLE, ) if dlg.ShowModal() == wx.ID_OK: self.grassdatabase = dlg.GetPath() @@ -1493,7 +1498,7 @@ def OnText(self, event): def OnBrowse(self, event): """Choose file""" dlg = wx.FileDialog( - self, _("Select georeferenced file"), os.getcwd(), "", "*.*", wx.FD_OPEN + self, _("Select georeferenced file"), str(Path.cwd()), "", "*.*", wx.FD_OPEN ) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() @@ -1977,7 +1982,7 @@ def OnBrowse(self, event): """Define path for IAU code file""" path = os.path.dirname(self.tfile.GetValue()) if not path: - path = os.getcwd() + path = str(Path.cwd()) dlg = wx.FileDialog( parent=self, diff --git a/gui/wxpython/main_window/frame.py b/gui/wxpython/main_window/frame.py index 3b9b7f50261..8fc8dc8dde7 100644 --- a/gui/wxpython/main_window/frame.py +++ b/gui/wxpython/main_window/frame.py @@ -25,6 +25,8 @@ import platform import re +from pathlib import Path + from core import globalvar try: @@ -971,7 +973,7 @@ def OnRunModel(self, event): dlg = wx.FileDialog( parent=self, message=_("Choose model to run"), - defaultDir=os.getcwd(), + defaultDir=str(Path.cwd()), wildcard=_("GRASS Model File (*.gxm)|*.gxm"), ) if dlg.ShowModal() == wx.ID_OK: @@ -1374,7 +1376,7 @@ def OnRunScript(self, event): dlg = wx.FileDialog( parent=self, message=_("Choose script file to run"), - defaultDir=os.getcwd(), + defaultDir=str(Path.cwd()), wildcard=_("Python script (*.py)|*.py|Bash script (*.sh)|*.sh"), ) @@ -1528,9 +1530,7 @@ def write_beginning(parameter=None, command=None): self._giface.WriteCmdLog(" ".join(command)) def write_changed(): - self._giface.WriteLog( - _('Working directory changed to:\n"%s"') % os.getcwd() - ) + self._giface.WriteLog(_('Working directory changed to:\n"%s"') % Path.cwd()) def write_end(): self._giface.WriteCmdLog(" ") @@ -1584,7 +1584,7 @@ def write_help(): dlg = wx.DirDialog( parent=self, message=_("Choose a working directory"), - defaultPath=os.getcwd(), + defaultPath=str(Path.cwd()), ) if dlg.ShowModal() == wx.ID_OK: diff --git a/gui/wxpython/modules/colorrules.py b/gui/wxpython/modules/colorrules.py index b5b1047382e..5093cd7cf25 100644 --- a/gui/wxpython/modules/colorrules.py +++ b/gui/wxpython/modules/colorrules.py @@ -27,6 +27,8 @@ import copy import tempfile +from pathlib import Path + import wx import wx.lib.colourselect as csel import wx.lib.scrolledpanel as scrolled @@ -448,7 +450,7 @@ def _createFileSelection(self, parent): dialogTitle=_("Choose file to load color table"), buttonText=_("Load"), toolTip=_("Type filename or click to choose file and load color table"), - startDirectory=os.getcwd(), + startDirectory=str(Path.cwd()), fileMode=wx.FD_OPEN, changeCallback=self.OnLoadRulesFile, ) @@ -460,7 +462,7 @@ def _createFileSelection(self, parent): dialogTitle=_("Choose file to save color table"), toolTip=_("Type filename or click to choose file and save color table"), buttonText=_("Save"), - startDirectory=os.getcwd(), + startDirectory=str(Path.cwd()), fileMode=wx.FD_SAVE, changeCallback=self.OnSaveRulesFile, ) diff --git a/gui/wxpython/modules/import_export.py b/gui/wxpython/modules/import_export.py index 15d4f76b586..03d179ffc2f 100644 --- a/gui/wxpython/modules/import_export.py +++ b/gui/wxpython/modules/import_export.py @@ -22,6 +22,8 @@ import os +from pathlib import Path + import wx from core import globalvar import wx.lib.filebrowsebutton as filebrowse @@ -836,7 +838,7 @@ def __init__(self, parent, giface): labelText="", dialogTitle=_("Choose DXF file to import"), buttonText=_("Browse"), - startDirectory=os.getcwd(), + startDirectory=str(Path.cwd()), fileMode=0, changeCallback=self.OnSetDsn, fileMask="DXF File (*.dxf)|*.dxf", diff --git a/gui/wxpython/nviz/tools.py b/gui/wxpython/nviz/tools.py index a1b0a9fcb1b..0659c5cc2ba 100644 --- a/gui/wxpython/nviz/tools.py +++ b/gui/wxpython/nviz/tools.py @@ -23,6 +23,8 @@ import sys import copy +from pathlib import Path + import wx import wx.lib.colourselect as csel import wx.lib.scrolledpanel as SP @@ -668,7 +670,7 @@ def _createAnimationPage(self): vSizer = wx.BoxSizer(wx.VERTICAL) gridSizer = wx.GridBagSizer(vgap=5, hgap=10) - pwd = os.getcwd() + pwd = str(Path.cwd()) dir = filebrowse.DirBrowseButton( parent=panel, id=wx.ID_ANY, diff --git a/gui/wxpython/psmap/dialogs.py b/gui/wxpython/psmap/dialogs.py index 216782037be..4eea798f731 100644 --- a/gui/wxpython/psmap/dialogs.py +++ b/gui/wxpython/psmap/dialogs.py @@ -37,6 +37,7 @@ import os import string from copy import deepcopy +from pathlib import Path import wx import wx.lib.agw.floatspin as fs @@ -5965,7 +5966,7 @@ def OnPositionType(self, event): def _getImageDirectory(self): """Default image directory""" - return os.getcwd() + return str(Path.cwd()) def _addConvergence(self, panel, gridBagSizer): pass diff --git a/gui/wxpython/tplot/frame.py b/gui/wxpython/tplot/frame.py index db21da4cd14..2c7d49c3d72 100755 --- a/gui/wxpython/tplot/frame.py +++ b/gui/wxpython/tplot/frame.py @@ -20,6 +20,7 @@ """ import os from itertools import cycle +from pathlib import Path import numpy as np import wx @@ -371,7 +372,7 @@ def _layout(self): labelText="", dialogTitle=_("CVS path"), buttonText=_("Browse"), - startDirectory=os.getcwd(), + startDirectory=str(Path.cwd()), fileMode=wx.FD_SAVE, ) self.headerLabel = StaticText( diff --git a/gui/wxpython/wxplot/profile.py b/gui/wxpython/wxplot/profile.py index 1d3de6681af..61efdcd67d0 100644 --- a/gui/wxpython/wxplot/profile.py +++ b/gui/wxpython/wxplot/profile.py @@ -20,6 +20,8 @@ import math import numpy as np +from pathlib import Path + import wx from wx.lib import plot @@ -410,7 +412,7 @@ def SaveProfileToFile(self, event): dlg = wx.FileDialog( parent=self, message=_("Choose prefix for file(s) where to save profile values..."), - defaultDir=os.getcwd(), + defaultDir=str(Path.cwd()), wildcard=_("Comma separated value (*.csv)|*.csv"), style=wx.FD_SAVE, ) diff --git a/lib/init/grass.py b/lib/init/grass.py index f32f290d090..25486d9426c 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -620,7 +620,7 @@ def create_initial_gisrc(filename): LOCATION_NAME: MAPSET: """ - % os.getcwd() + % Path.cwd() ) writefile(filename, s) @@ -789,7 +789,7 @@ def set_mapset( # non-empty element as the last element (which is good for both mapset # and location split) if arg == ".": - arg = os.getcwd() + arg = str(Path.cwd()) elif not os.path.isabs(arg): arg = os.path.abspath(arg) if arg.endswith(os.path.sep): diff --git a/locale/grass_po_stats.py b/locale/grass_po_stats.py index 32e3f449cb3..0c49e44bc8d 100644 --- a/locale/grass_po_stats.py +++ b/locale/grass_po_stats.py @@ -21,10 +21,12 @@ import subprocess import sys +from pathlib import Path + def read_po_files(inputdirpath): """Return a dictionary with for each language the list of *.po files""" - originalpath = os.getcwd() + originalpath = Path.cwd() os.chdir(inputdirpath) languages = {} for pofile in sorted(glob.glob("*.po")): diff --git a/pyproject.toml b/pyproject.toml index d3aa0049c28..2a3a4f68890 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -195,7 +195,6 @@ ignore = [ "PTH106", # os-rmdir "PTH107", # os-remove "PTH108", # os-unlink - "PTH109", # os-getcwd "PTH110", # os-path-exists "PTH111", # os-path-expanduser "PTH112", # os-path-isdir diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 6bf77a3bf65..6916ea2748a 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -159,7 +159,7 @@ def is_first_time_user(): genv = gisenv() if "LAST_MAPSET_PATH" in genv.keys(): return genv["LAST_MAPSET_PATH"] == os.path.join( - os.getcwd(), cfg.unknown_location, cfg.unknown_mapset + Path.cwd(), cfg.unknown_location, cfg.unknown_mapset ) return False diff --git a/python/grass/pygrass/tests/benchmark.py b/python/grass/pygrass/tests/benchmark.py index 75e32541a59..fa7f0c01a65 100644 --- a/python/grass/pygrass/tests/benchmark.py +++ b/python/grass/pygrass/tests/benchmark.py @@ -12,11 +12,11 @@ import copy import cProfile import sys -import os from jinja2 import Template +from pathlib import Path -sys.path.append(os.getcwd()) -sys.path.append("%s/.." % (os.getcwd())) +sys.path.append(str(Path.cwd())) +sys.path.append("%s/.." % (str(Path.cwd()))) import grass.lib.gis as libgis import grass.lib.raster as libraster diff --git a/python/grass/script/core.py b/python/grass/script/core.py index a86738926f0..40709a11e80 100644 --- a/python/grass/script/core.py +++ b/python/grass/script/core.py @@ -1894,7 +1894,7 @@ def _create_location_xy(database, location): :param database: GRASS database where to create new location :param location: location name """ - cur_dir = os.getcwd() + cur_dir = Path.cwd() try: os.chdir(database) os.mkdir(location) diff --git a/python/grass/script/utils.py b/python/grass/script/utils.py index 13d049412a4..3df6abc7016 100644 --- a/python/grass/script/utils.py +++ b/python/grass/script/utils.py @@ -28,6 +28,8 @@ import random import string +from pathlib import Path + def float_or_dms(s): """Convert DMS to float. @@ -383,7 +385,7 @@ def get_lib_path(modname, libname=None): path = join(os.getenv("GRASS_ADDON_BASE"), modname, modname) else: # used by g.extension compilation process - cwd = os.getcwd() + cwd = str(Path.cwd()) idx = cwd.find(modname) if idx < 0: return None @@ -463,10 +465,10 @@ def set_path(modulename, dirname=None, path="."): import sys # TODO: why dirname is checked first - the logic should be revised - pathlib = None + _pathlib = None if dirname: - pathlib = os.path.join(path, dirname) - if pathlib and os.path.exists(pathlib): + _pathlib = os.path.join(path, dirname) + if _pathlib and os.path.exists(_pathlib): # we are running the script from the script directory, therefore # we add the path to sys.path to reach the directory (dirname) sys.path.append(os.path.abspath(path)) @@ -477,7 +479,7 @@ def set_path(modulename, dirname=None, path="."): pathname = os.path.join(modulename, dirname) if dirname else modulename raise ImportError( "Not able to find the path '%s' directory " - "(current dir '%s')." % (pathname, os.getcwd()) + "(current dir '%s')." % (pathname, Path.cwd()) ) sys.path.insert(0, path) diff --git a/python/grass/temporal/stds_export.py b/python/grass/temporal/stds_export.py index ff2731b102a..a01b94e1071 100644 --- a/python/grass/temporal/stds_export.py +++ b/python/grass/temporal/stds_export.py @@ -348,7 +348,7 @@ def export_stds( """ # Save current working directory path - old_cwd = os.getcwd() + old_cwd = Path.cwd() # Create the temporary directory and jump into it new_cwd = tempfile.mkdtemp(dir=directory) diff --git a/python/grass/temporal/stds_import.py b/python/grass/temporal/stds_import.py index ae587cadb0f..b8223c8ee83 100644 --- a/python/grass/temporal/stds_import.py +++ b/python/grass/temporal/stds_import.py @@ -286,7 +286,7 @@ def import_stds( # We use a new list file name for map registration new_list_file_name = list_file_name + "_new" # Save current working directory path - old_cwd = os.getcwd() + old_cwd = Path.cwd() # Switch into the data directory os.chdir(directory) diff --git a/scripts/r.pack/r.pack.py b/scripts/r.pack/r.pack.py index eb11547322c..bb3332101ee 100644 --- a/scripts/r.pack/r.pack.py +++ b/scripts/r.pack/r.pack.py @@ -37,6 +37,8 @@ import atexit import tarfile +from pathlib import Path + from grass.script.utils import try_rmdir, try_remove from grass.script import core as grass @@ -80,7 +82,7 @@ def main(): 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() + olddir = Path.cwd() # copy elements info = grass.parse_command("r.info", flags="e", map=infile) diff --git a/scripts/v.pack/v.pack.py b/scripts/v.pack/v.pack.py index cd8d96b86cd..4468c888bcb 100755 --- a/scripts/v.pack/v.pack.py +++ b/scripts/v.pack/v.pack.py @@ -38,6 +38,8 @@ import tarfile import atexit +from pathlib import Path + from grass.script.utils import try_rmdir, try_remove from grass.script import core as grass from grass.script import vector @@ -128,7 +130,7 @@ def main(): tar.add(path, "PROJ_" + support) tar.close() - grass.message(_("Pack file <%s> created") % os.path.join(os.getcwd(), outfile)) + grass.message(_("Pack file <%s> created") % Path(outfile).resolve()) if __name__ == "__main__": diff --git a/utils/mkhtml.py b/utils/mkhtml.py index 54b2b80e87d..f64f6d7d97a 100644 --- a/utils/mkhtml.py +++ b/utils/mkhtml.py @@ -366,7 +366,7 @@ def has_src_code_git(src_dir, is_addon): if core module or addon source code has Git """ - actual_dir = os.getcwd() + actual_dir = Path.cwd() if is_addon: os.chdir(src_dir) else: From 70f35998766be162c7bc1e280c83997bd1c3e052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 28 Sep 2024 16:31:05 -0400 Subject: [PATCH 115/209] style: Fix if-with-same-arms (SIM114) (#4406) --- gui/wxpython/animation/controller.py | 4 +--- gui/wxpython/core/gcmd.py | 10 +++++----- gui/wxpython/iscatt/plots.py | 10 +++++----- gui/wxpython/mapwin/decorations.py | 14 ++++++-------- gui/wxpython/vdigit/wxdisplay.py | 5 +---- gui/wxpython/vnet/dialogs.py | 4 +--- gui/wxpython/vnet/vnet_core.py | 4 +--- pyproject.toml | 1 - python/grass/script/utils.py | 7 +++---- python/grass/temporal/temporal_algebra.py | 20 +++++--------------- utils/gitlog2changelog.py | 14 ++++++-------- 11 files changed, 34 insertions(+), 59 deletions(-) diff --git a/gui/wxpython/animation/controller.py b/gui/wxpython/animation/controller.py index 1a920f77de7..1a8cb1fe9cc 100644 --- a/gui/wxpython/animation/controller.py +++ b/gui/wxpython/animation/controller.py @@ -465,9 +465,7 @@ def EvaluateInput(self, animationData): mapCount.add(len(layer.maps)) windowIndex.append(anim.windowIndex) - if maps and stds: - temporalMode = TemporalMode.NONTEMPORAL - elif maps: + if (maps and stds) or maps: temporalMode = TemporalMode.NONTEMPORAL elif stds: temporalMode = TemporalMode.TEMPORAL diff --git a/gui/wxpython/core/gcmd.py b/gui/wxpython/core/gcmd.py index b93789f22f7..eb40ec57103 100644 --- a/gui/wxpython/core/gcmd.py +++ b/gui/wxpython/core/gcmd.py @@ -645,11 +645,11 @@ def _formatMsg(text): for line in text.splitlines(): if len(line) == 0: continue - elif "GRASS_INFO_MESSAGE" in line: - message += line.split(":", 1)[1].strip() + "\n" - elif "GRASS_INFO_WARNING" in line: - message += line.split(":", 1)[1].strip() + "\n" - elif "GRASS_INFO_ERROR" in line: + elif ( + "GRASS_INFO_MESSAGE" in line + or "GRASS_INFO_WARNING" in line + or "GRASS_INFO_ERROR" in line + ): message += line.split(":", 1)[1].strip() + "\n" elif "GRASS_INFO_END" in line: return message diff --git a/gui/wxpython/iscatt/plots.py b/gui/wxpython/iscatt/plots.py index 32ce111c428..a29098e8bcd 100644 --- a/gui/wxpython/iscatt/plots.py +++ b/gui/wxpython/iscatt/plots.py @@ -811,11 +811,11 @@ def _deleteVertex(self, event): coords = [] for i, tup in enumerate(self.pol.xy): - if i == ind: - continue - elif i == 0 and ind == len(self.pol.xy) - 1: - continue - elif i == len(self.pol.xy) - 1 and ind == 0: + if ( + i == ind + or (i == 0 and ind == len(self.pol.xy) - 1) + or (i == len(self.pol.xy) - 1 and ind == 0) + ): continue coords.append(tup) diff --git a/gui/wxpython/mapwin/decorations.py b/gui/wxpython/mapwin/decorations.py index 7ab010a1d3f..24db63d8492 100644 --- a/gui/wxpython/mapwin/decorations.py +++ b/gui/wxpython/mapwin/decorations.py @@ -209,9 +209,7 @@ def CmdIsValid(self) -> bool: inputs = 0 for param in self._cmd[1:]: param = param.split("=") - if len(param) == 1: - inputs += 1 - elif param[0] == "text" and len(param) == 2: + if len(param) == 1 or (param[0] == "text" and len(param) == 2): inputs += 1 return inputs >= 1 @@ -313,11 +311,11 @@ def CmdIsValid(self) -> bool: inputs = 0 for param in self._cmd[1:]: param = param.split("=") - if len(param) == 1: - inputs += 1 - elif param[0] == "raster" and len(param) == 2: - inputs += 1 - elif param[0] == "raster_3d" and len(param) == 2: + if ( + len(param) == 1 + or (param[0] == "raster" and len(param) == 2) + or (param[0] == "raster_3d" and len(param) == 2) + ): inputs += 1 return inputs == 1 diff --git a/gui/wxpython/vdigit/wxdisplay.py b/gui/wxpython/vdigit/wxdisplay.py index b747f3fa44f..9085aae8caf 100644 --- a/gui/wxpython/vdigit/wxdisplay.py +++ b/gui/wxpython/vdigit/wxdisplay.py @@ -868,10 +868,7 @@ def GetSelectedVertex(self, pos): pos[0], pos[1], 0.0, points.x[idx], points.y[idx], points.z[idx], 0 ) - if idx == 0: - minDist = dist - Gid = idx - elif minDist > dist: + if idx == 0 or minDist > dist: minDist = dist Gid = idx diff --git a/gui/wxpython/vnet/dialogs.py b/gui/wxpython/vnet/dialogs.py index 3d829ffd7be..a445b01e8eb 100644 --- a/gui/wxpython/vnet/dialogs.py +++ b/gui/wxpython/vnet/dialogs.py @@ -1952,9 +1952,7 @@ def SetVirtualData(self, row, column, text): text = DegreesToRadians(text) # Tested allowed range of values - if text > math.pi: - text = 0.0 - elif text < -math.pi: + if text > math.pi or text < -math.pi: text = 0.0 self.data.SetValue(text, row, column) diff --git a/gui/wxpython/vnet/vnet_core.py b/gui/wxpython/vnet/vnet_core.py index 17d85ef6ca4..ac7625a4c22 100644 --- a/gui/wxpython/vnet/vnet_core.py +++ b/gui/wxpython/vnet/vnet_core.py @@ -828,9 +828,7 @@ def _prepareCmd(self, cmd): if c.find("=") == -1: continue v = c.split("=") - if len(v) != 2: - cmd.remove(c) - elif not v[1].strip(): + if len(v) != 2 or not v[1].strip(): cmd.remove(c) def _setCmdForSpecificAn(self, cmdParams): diff --git a/pyproject.toml b/pyproject.toml index 2a3a4f68890..31ac12eaf24 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -251,7 +251,6 @@ ignore = [ "SIM109", # compare-with-tuple "SIM110", # reimplemented-builtin "SIM113", # enumerate-for-loop - "SIM114", # if-with-same-arms "SIM116", # if-else-block-instead-of-dict-lookup "SIM118", # in-dict-keys "SIM223", # expr-and-false diff --git a/python/grass/script/utils.py b/python/grass/script/utils.py index 3df6abc7016..2868e3111e6 100644 --- a/python/grass/script/utils.py +++ b/python/grass/script/utils.py @@ -373,10 +373,9 @@ def get_lib_path(modname, libname=None): getenv("GRASS_ADDON_BASE") and libname and isdir(join(getenv("GRASS_ADDON_BASE"), "etc", modname, libname)) - ): - path = join(getenv("GRASS_ADDON_BASE"), "etc", modname) - elif getenv("GRASS_ADDON_BASE") and isdir( - join(getenv("GRASS_ADDON_BASE"), "etc", modname) + ) or ( + getenv("GRASS_ADDON_BASE") + and isdir(join(getenv("GRASS_ADDON_BASE"), "etc", modname)) ): path = join(getenv("GRASS_ADDON_BASE"), "etc", modname) elif getenv("GRASS_ADDON_BASE") and isdir( diff --git a/python/grass/temporal/temporal_algebra.py b/python/grass/temporal/temporal_algebra.py index 1b9a126c635..1cf1cfd7366 100644 --- a/python/grass/temporal/temporal_algebra.py +++ b/python/grass/temporal/temporal_algebra.py @@ -1275,15 +1275,9 @@ def check_stds(self, input, clear=False, stds_type=None, check_type=True): self.temporaltype = "absolute" elif map_i.is_time_relative() and self.temporaltype is None: self.temporaltype = "relative" - elif map_i.is_time_absolute() and self.temporaltype == "relative": - self.msgr.fatal( - _( - "Wrong temporal type of space time dataset " - "<%s> <%s> time is required" - ) - % (id_input, self.temporaltype) - ) - elif map_i.is_time_relative() and self.temporaltype == "absolute": + elif ( + map_i.is_time_absolute() and self.temporaltype == "relative" + ) or (map_i.is_time_relative() and self.temporaltype == "absolute"): self.msgr.fatal( _( "Wrong temporal type of space time dataset " @@ -1299,13 +1293,9 @@ def check_stds(self, input, clear=False, stds_type=None, check_type=True): maplist = input # Create map_value as empty list item. for map_i in maplist: - if "map_value" not in dir(map_i): + if ("map_value" not in dir(map_i)) or clear: map_i.map_value = [] - elif clear: - map_i.map_value = [] - if "condition_value" not in dir(map_i): - map_i.condition_value = [] - elif clear: + if ("condition_value" not in dir(map_i)) or clear: map_i.condition_value = [] else: self.msgr.fatal(_("Wrong type of input " + str(input))) diff --git a/utils/gitlog2changelog.py b/utils/gitlog2changelog.py index 43aedcfb491..5ad459aa2b1 100755 --- a/utils/gitlog2changelog.py +++ b/utils/gitlog2changelog.py @@ -78,14 +78,12 @@ dateFound = True except Exception as e: print(f"Could not parse dateList = '{line}'. Error: {e!s}") - # The Fossil-IDs are ignored: - elif line.startswith((" Fossil-ID:", " [[SVN:")): - continue - # The svn-id lines are ignored - elif " git-svn-id:" in line: - continue - # The sign off line is ignored too - elif "Signed-off-by" in line: + # The Fossil-IDs, svn-id, ad sign off lines are ignored: + elif ( + line.startswith((" Fossil-ID:", " [[SVN:")) + or " git-svn-id:" in line + or "Signed-off-by" in line + ): continue # Extract the actual commit message for this commit elif authorFound & dateFound & messageFound is False: From ae5e4dd232230d32eadb49a7a0a71244f95c5972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 28 Sep 2024 16:32:29 -0400 Subject: [PATCH 116/209] style: Fix duplicate-isinstance-call (SIM101) (#4405) --- gui/wxpython/gmodeler/canvas.py | 12 ++++-------- gui/wxpython/gmodeler/model.py | 2 +- pyproject.toml | 1 - 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/gui/wxpython/gmodeler/canvas.py b/gui/wxpython/gmodeler/canvas.py index 7c604ec6624..bfe5f7a90af 100644 --- a/gui/wxpython/gmodeler/canvas.py +++ b/gui/wxpython/gmodeler/canvas.py @@ -320,19 +320,19 @@ def OnRightClick(self, x, y, keys=0, attachment=0): popupMenu = Menu() popupMenu.Append(self.popupID["remove"], _("Remove")) self.frame.Bind(wx.EVT_MENU, self.OnRemove, id=self.popupID["remove"]) - if isinstance(shape, ModelAction) or isinstance(shape, ModelLoop): + if isinstance(shape, (ModelAction, ModelLoop)): if shape.IsEnabled(): popupMenu.Append(self.popupID["enable"], _("Disable")) self.frame.Bind(wx.EVT_MENU, self.OnDisable, id=self.popupID["enable"]) else: popupMenu.Append(self.popupID["enable"], _("Enable")) self.frame.Bind(wx.EVT_MENU, self.OnEnable, id=self.popupID["enable"]) - if isinstance(shape, ModelAction) or isinstance(shape, ModelComment): + if isinstance(shape, (ModelAction, ModelComment)): popupMenu.AppendSeparator() if isinstance(shape, ModelAction): popupMenu.Append(self.popupID["label"], _("Set label")) self.frame.Bind(wx.EVT_MENU, self.OnSetLabel, id=self.popupID["label"]) - if isinstance(shape, ModelAction) or isinstance(shape, ModelComment): + if isinstance(shape, (ModelAction, ModelComment)): popupMenu.Append(self.popupID["comment"], _("Set comment")) self.frame.Bind(wx.EVT_MENU, self.OnSetComment, id=self.popupID["comment"]) @@ -377,11 +377,7 @@ def OnRightClick(self, x, y, keys=0, attachment=0): if self.GetShape().IsIntermediate(): popupMenu.Enable(self.popupID["display"], False) - if ( - isinstance(shape, ModelData) - or isinstance(shape, ModelAction) - or isinstance(shape, ModelLoop) - ): + if isinstance(shape, (ModelData, ModelAction, ModelLoop)): popupMenu.AppendSeparator() popupMenu.Append(self.popupID["props"], _("Properties")) self.frame.Bind(wx.EVT_MENU, self.OnProperties, id=self.popupID["props"]) diff --git a/gui/wxpython/gmodeler/model.py b/gui/wxpython/gmodeler/model.py index a609a1c8bd8..59ea791192c 100644 --- a/gui/wxpython/gmodeler/model.py +++ b/gui/wxpython/gmodeler/model.py @@ -2641,7 +2641,7 @@ def _writeItem(self, item, ignoreBlock=True, variables={}): self._writePythonAction( item, variables, self.model.GetIntermediateData()[:3] ) - elif isinstance(item, ModelLoop) or isinstance(item, ModelCondition): + elif isinstance(item, (ModelLoop, ModelCondition)): # substitute condition cond = item.GetLabel() for variable in self.model.GetVariables(): diff --git a/pyproject.toml b/pyproject.toml index 31ac12eaf24..e288be23f10 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -244,7 +244,6 @@ ignore = [ "S606", # start-process-with-no-shell "S607", # start-process-with-partial-path "S608", # hardcoded-sql-expression - "SIM101", # duplicate-isinstance-call "SIM102", # collapsible-if "SIM105", # suppressible-exception "SIM108", # if-else-block-instead-of-if-exp From 0ea5e37d4122cf9df540a324f74ad55836e27d1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 28 Sep 2024 17:58:09 -0400 Subject: [PATCH 117/209] style: Fix reimplemented-operator (FURB118) (#4408) * style: Fix reimplemented-operator (FURB118) Ruff rule: https://docs.astral.sh/ruff/rules/reimplemented-operator/ Replaced lambdas with `operator.itemgetter()` or `operator.add()`. These are implemented more efficiently in C and have a Python fallback. * utils/g.html2man: Replace children function with operator.itemgetter --- gui/wxpython/animation/temporal_manager.py | 5 +++-- gui/wxpython/gui_core/ghelp.py | 3 ++- gui/wxpython/mapwin/buffered.py | 10 ++++++---- gui/wxpython/psmap/dialogs.py | 7 +++---- gui/wxpython/timeline/frame.py | 5 ++--- gui/wxpython/tplot/frame.py | 5 ++--- man/build_full_index.py | 4 +++- pyproject.toml | 1 - python/grass/imaging/images2ims.py | 3 ++- scripts/g.search.modules/g.search.modules.py | 4 +++- scripts/v.report/v.report.py | 4 +++- utils/g.html2man/rest.py | 4 ++-- 12 files changed, 31 insertions(+), 24 deletions(-) diff --git a/gui/wxpython/animation/temporal_manager.py b/gui/wxpython/animation/temporal_manager.py index 150eeab510f..ef782543089 100644 --- a/gui/wxpython/animation/temporal_manager.py +++ b/gui/wxpython/animation/temporal_manager.py @@ -18,6 +18,7 @@ """ import datetime +from operator import itemgetter import grass.script as gs import grass.temporal as tgis @@ -195,9 +196,9 @@ def GetLabelsAndMaps(self): # by a temporary dataset, I don't know how it would work with point # data if self.temporalType == TemporalType.ABSOLUTE: - timestamps = sorted(list(labelListSet), key=lambda x: x[0]) + timestamps = sorted(list(labelListSet), key=itemgetter(0)) else: - timestamps = sorted(list(labelListSet), key=lambda x: x[0]) + timestamps = sorted(list(labelListSet), key=itemgetter(0)) newMapLists = [] for mapList, labelList in zip(mapLists, labelLists): diff --git a/gui/wxpython/gui_core/ghelp.py b/gui/wxpython/gui_core/ghelp.py index 93879998133..72e2564b74d 100644 --- a/gui/wxpython/gui_core/ghelp.py +++ b/gui/wxpython/gui_core/ghelp.py @@ -25,6 +25,7 @@ import sys import wx from wx.html import HtmlWindow +from operator import itemgetter try: from wx.lib.agw.hyperlink import HyperLinkCtrl @@ -450,7 +451,7 @@ def _pageContributors(self, extra=False): text = StaticText(parent=contribwin, id=wx.ID_ANY, label=item) text.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) contribBox.Add(text) - for vals in sorted(contribs, key=lambda x: x[0]): + for vals in sorted(contribs, key=itemgetter(0)): for item in vals: contribBox.Add( StaticText(parent=contribwin, id=wx.ID_ANY, label=item) diff --git a/gui/wxpython/mapwin/buffered.py b/gui/wxpython/mapwin/buffered.py index e0442ed94ae..d8c6413017b 100644 --- a/gui/wxpython/mapwin/buffered.py +++ b/gui/wxpython/mapwin/buffered.py @@ -28,6 +28,8 @@ import wx +from operator import itemgetter + from grass.pydispatch.signal import Signal from core.globalvar import wxPythonPhoenix @@ -462,10 +464,10 @@ def Draw( brush = wx.TRANSPARENT_BRUSH pdc.SetBrush(brush) pdc.DrawPolygon(points=coords) - x = min(coords, key=lambda x: x[0])[0] - y = min(coords, key=lambda x: x[1])[1] - w = max(coords, key=lambda x: x[0])[0] - x - h = max(coords, key=lambda x: x[1])[1] - y + x = min(coords, key=itemgetter(0))[0] + y = min(coords, key=itemgetter(1))[1] + w = max(coords, key=itemgetter(0))[0] - x + h = max(coords, key=itemgetter(1))[1] - y pdc.SetIdBounds(drawid, Rect(x, y, w, h)) elif pdctype == "circle": # draw circle diff --git a/gui/wxpython/psmap/dialogs.py b/gui/wxpython/psmap/dialogs.py index 4eea798f731..41493795893 100644 --- a/gui/wxpython/psmap/dialogs.py +++ b/gui/wxpython/psmap/dialogs.py @@ -37,6 +37,7 @@ import os import string from copy import deepcopy +from operator import itemgetter from pathlib import Path import wx @@ -3623,9 +3624,7 @@ def _vectorLegend(self, notebook): self.vectorListCtrl.InsertColumn(0, _("Vector map")) self.vectorListCtrl.InsertColumn(1, _("Label")) if self.vectorId: - vectors = sorted( - self.instruction[self.vectorId]["list"], key=lambda x: x[3] - ) + vectors = sorted(self.instruction[self.vectorId]["list"], key=itemgetter(3)) for vector in vectors: index = self.vectorListCtrl.InsertItem( @@ -4456,7 +4455,7 @@ def updateDialog(self): if self.instruction.FindInstructionByType("vector"): vectors = sorted( self.instruction.FindInstructionByType("vector")["list"], - key=lambda x: x[3], + key=itemgetter(3), ) self.vectorListCtrl.DeleteAllItems() for vector in vectors: diff --git a/gui/wxpython/timeline/frame.py b/gui/wxpython/timeline/frame.py index 3982034619c..9a783f4f5d5 100644 --- a/gui/wxpython/timeline/frame.py +++ b/gui/wxpython/timeline/frame.py @@ -22,6 +22,7 @@ import wx from functools import reduce +from operator import add try: import matplotlib as mpl @@ -495,9 +496,7 @@ def _checkDatasets(self, datasets): ] # flatten this list if allDatasets: - allDatasets = reduce( - lambda x, y: x + y, reduce(lambda x, y: x + y, allDatasets) - ) + allDatasets = reduce(add, reduce(add, allDatasets)) mapsets = tgis.get_tgis_c_library_interface().available_mapsets() allDatasets = [ i diff --git a/gui/wxpython/tplot/frame.py b/gui/wxpython/tplot/frame.py index 2c7d49c3d72..8994485dacc 100755 --- a/gui/wxpython/tplot/frame.py +++ b/gui/wxpython/tplot/frame.py @@ -69,6 +69,7 @@ from gui_core.widgets import GNotebook from gui_core.wrap import CheckBox, TextCtrl, Button, StaticText +from operator import add ALPHA = 0.5 COLORS = ["b", "g", "r", "c", "m", "y", "k"] @@ -1153,9 +1154,7 @@ def _checkDatasets(self, datasets, typ): ] # flatten this list if allDatasets: - allDatasets = reduce( - lambda x, y: x + y, reduce(lambda x, y: x + y, allDatasets) - ) + allDatasets = reduce(add, reduce(add, allDatasets)) mapsets = tgis.get_tgis_c_library_interface().available_mapsets() allDatasets = [ i diff --git a/man/build_full_index.py b/man/build_full_index.py index ead5167cbb1..7d2ce03e342 100644 --- a/man/build_full_index.py +++ b/man/build_full_index.py @@ -9,6 +9,8 @@ import sys import os +from operator import itemgetter + from build_html import ( html_dir, grass_version, @@ -50,7 +52,7 @@ prefix = cmd.split(".")[0] if prefix not in [item[0] for item in classes]: classes.append((prefix, class_labels.get(prefix, prefix))) -classes.sort(key=lambda tup: tup[0]) +classes.sort(key=itemgetter(0)) # begin full index: filename = "full_index.html" diff --git a/pyproject.toml b/pyproject.toml index e288be23f10..3a6d449ec1d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -145,7 +145,6 @@ ignore = [ "FBT001", # boolean-type-hint-positional-argument "FBT002", # boolean-default-value-positional-argument "FBT003", # boolean-positional-value-in-call - "FURB118", # reimplemented-operator "I001", # unsorted-imports "ISC003", # explicit-string-concatenation "PERF203", # try-except-in-loop diff --git a/python/grass/imaging/images2ims.py b/python/grass/imaging/images2ims.py index 31088a22f2e..662e3eb46e0 100644 --- a/python/grass/imaging/images2ims.py +++ b/python/grass/imaging/images2ims.py @@ -31,6 +31,7 @@ """ import os +from operator import itemgetter try: import numpy as np @@ -214,7 +215,7 @@ def readIms(filename, asNumpy=True): images.append((im.copy(), nr)) # Sort images - images.sort(key=lambda x: x[1]) + images.sort(key=itemgetter(1)) images = [im[0] for im in images] # Convert to numpy if needed diff --git a/scripts/g.search.modules/g.search.modules.py b/scripts/g.search.modules/g.search.modules.py index 85247517898..a3bab4325c2 100755 --- a/scripts/g.search.modules/g.search.modules.py +++ b/scripts/g.search.modules/g.search.modules.py @@ -66,6 +66,8 @@ import os import sys +from operator import itemgetter + from grass.script import core as grass from grass.exceptions import CalledModuleError @@ -283,7 +285,7 @@ def _search_module( } ) - return sorted(found_modules, key=lambda k: k["name"]) + return sorted(found_modules, key=itemgetter("name")) def _basic_search(pattern, name, description, module_keywords) -> bool: diff --git a/scripts/v.report/v.report.py b/scripts/v.report/v.report.py index 18752a697cb..9da9a8b1de7 100755 --- a/scripts/v.report/v.report.py +++ b/scripts/v.report/v.report.py @@ -55,6 +55,8 @@ import sys import os +from operator import itemgetter + import grass.script as gs from grass.script.utils import separator, decode @@ -134,7 +136,7 @@ def main(): if p.returncode != 0: sys.exit(1) - records1.sort(key=lambda r: r[catcol]) + records1.sort(key=itemgetter(catcol)) if len(records1) == 0: try: diff --git a/utils/g.html2man/rest.py b/utils/g.html2man/rest.py index 2df87db8e27..c320f18e397 100644 --- a/utils/g.html2man/rest.py +++ b/utils/g.html2man/rest.py @@ -1,4 +1,5 @@ import sys +from operator import itemgetter def match(node, tag, attr=None, val=None): @@ -26,8 +27,7 @@ def find(node, tag, attr=None, val=None): raise ValueError("child not found") -def children(node): - return node[2] +children = itemgetter(2) def text(node): From 16c87b1d0d780fab1cb4025babf6f7db4530a8e5 Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Sun, 29 Sep 2024 10:18:54 +0200 Subject: [PATCH 118/209] lib/shapelib: sync upstream with shapelib 1.6.0 and GDAL 3.9.2 (#4395) * fix win runner (-Wincompatible-pointer-types warnings) * remove patch of http://trac.osgeo.org/gdal/ticket/809 --- lib/external/shapelib/README.md | 44 +- lib/external/shapelib/dbfopen.c | 344 ++++---- lib/external/shapelib/safileio.c | 195 +---- lib/external/shapelib/shapefil.h | 170 ++-- lib/external/shapelib/shapefil_private.h | 115 +++ lib/external/shapelib/shpopen.c | 980 ++++++++++++----------- 6 files changed, 933 insertions(+), 915 deletions(-) create mode 100644 lib/external/shapelib/shapefil_private.h diff --git a/lib/external/shapelib/README.md b/lib/external/shapelib/README.md index e004d2d0419..d446eccd014 100644 --- a/lib/external/shapelib/README.md +++ b/lib/external/shapelib/README.md @@ -1,12 +1,13 @@ # Update history of SHAPELIB copy -* files `shpopen.c`, `shapefil.h`, `dbfopen.c` +* files `shpopen.c`, `shapefil.h`, `dbfopen.c`, `shapefil_private.h` from GDAL [ogr/ogrsf_frmts/shape/](https://github.com/OSGeo/gdal/tree/master/ogr/ogrsf_frmts/shape) * file `safileio.c` from [SHAPELIB](http://download.osgeo.org/shapelib/) ## Last update +* taken from GDAL 3.9.2 and SHAPELIB 1.6.0 (Sep 2024) * taken from GDAL 3.5.3 and SHAPELIB 1.5.0 (Dec 2022) * taken from GDAL 2.1.2 and SHAPELIB 1.3.0 (Thu Nov 24 10:45:41 CET 2016) * taken from GDAL 1.5.1-SVN (Sun Mar 30 11:20:43 CEST 2008) @@ -15,44 +16,5 @@ ## Summary of fixes -* dbfopen.c - around line 1229: GDAL bug [ticket-#809](http://trac.osgeo.org/gdal/ticket/809) - * safileio.c - SHP_CVSID: ISO C does not allow extra ‘;’ outside of a function - -## Full fix - -```diff -diff --git a/lib/external/shapelib/dbfopen.c b/lib/external/shapelib/dbfopen.c -index 5380e3e20b..5151148d33 100644 ---- a/lib/external/shapelib/dbfopen.c -+++ b/lib/external/shapelib/dbfopen.c -@@ -1226,9 +1226,10 @@ DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName, - else if( psDBF->pachFieldType[iField] == 'N' - || psDBF->pachFieldType[iField] == 'F' ) - { -- if( psDBF->panFieldDecimals[iField] > 0 -- || psDBF->panFieldSize[iField] >= 10 ) -+ if( psDBF->panFieldDecimals[iField] > 0 ) { -+ /* || psDBF->panFieldSize[iField] >= 10 ) */ /* GDAL bug #809 */ - return( FTDouble ); -+ } - else - return( FTInteger ); - } -diff --git a/lib/external/shapelib/safileio.c b/lib/external/shapelib/safileio.c -index 289d347eaf..7a614a5806 100644 ---- a/lib/external/shapelib/safileio.c -+++ b/lib/external/shapelib/safileio.c -@@ -74,7 +74,7 @@ - #include - #include - --SHP_CVSID("$Id: safileio.c,v 1.6 2018-06-15 19:56:32 erouault Exp $"); -+SHP_CVSID("$Id: safileio.c,v 1.6 2018-06-15 19:56:32 erouault Exp $") - - #ifdef SHPAPI_UTF8_HOOKS - # ifdef SHPAPI_WINDOWS - -``` + [shapelib commit 316ff87](https://github.com/OSGeo/shapelib/commit/316ff872566ea0d91d6b62fe01bfe39931db39aa#diff-f068bc465ca1a32e1b9c214d4eb9504ef9e0f3c4cabc1aa4bab8aa41e2248cc6R153) diff --git a/lib/external/shapelib/dbfopen.c b/lib/external/shapelib/dbfopen.c index 2bbba339e21..9078a29ba95 100644 --- a/lib/external/shapelib/dbfopen.c +++ b/lib/external/shapelib/dbfopen.c @@ -1,5 +1,4 @@ /****************************************************************************** - * $Id$ * * Project: Shapelib * Purpose: Implementation of .dbf access API documented in dbf_api.html. @@ -9,32 +8,10 @@ * Copyright (c) 1999, Frank Warmerdam * Copyright (c) 2012-2019, Even Rouault * - * This software is available under the following "MIT Style" license, - * or at the option of the licensee under the LGPL (see COPYING). This - * option is discussed in more detail in shapelib.html. - * - * -- - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * SPDX-License-Identifier: MIT OR LGPL-2.0-or-later ******************************************************************************/ -#include "shapefil.h" +#include "shapefil_private.h" #include #include @@ -47,7 +24,9 @@ #include "cpl_string.h" #else -#if defined(WIN32) || defined(_WIN32) +#if defined(_MSC_VER) +#define STRCASECMP(a, b) (_stricmp(a, b)) +#elif defined(_WIN32) #define STRCASECMP(a, b) (stricmp(a, b)) #else #include @@ -58,7 +37,7 @@ #if _MSC_VER < 1900 #define snprintf _snprintf #endif -#elif defined(WIN32) || defined(_WIN32) +#elif defined(_WIN32) #ifndef snprintf #define snprintf _snprintf #endif @@ -68,8 +47,6 @@ #define CPLsnprintf snprintf #endif -SHP_CVSID("$Id$") - #ifndef FALSE #define FALSE 0 #define TRUE 1 @@ -91,33 +68,6 @@ CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused) #define CPL_IGNORE_RET_VAL_INT(x) x #endif -#ifdef __cplusplus -#define STATIC_CAST(type, x) static_cast(x) -#define REINTERPRET_CAST(type, x) reinterpret_cast(x) -#define CONST_CAST(type, x) const_cast(x) -#define SHPLIB_NULLPTR nullptr -#else -#define STATIC_CAST(type, x) ((type)(x)) -#define REINTERPRET_CAST(type, x) ((type)(x)) -#define CONST_CAST(type, x) ((type)(x)) -#define SHPLIB_NULLPTR NULL -#endif - -/************************************************************************/ -/* SfRealloc() */ -/* */ -/* A realloc cover function that will access a NULL pointer as */ -/* a valid input. */ -/************************************************************************/ - -static void *SfRealloc(void *pMem, int nNewSize) -{ - if (pMem == SHPLIB_NULLPTR) - return malloc(nNewSize); - else - return realloc(pMem, nNewSize); -} - /************************************************************************/ /* DBFWriteHeader() */ /* */ @@ -137,9 +87,9 @@ static void DBFWriteHeader(DBFHandle psDBF) psDBF->bNoHeader = FALSE; /* -------------------------------------------------------------------- */ - /* Initialize the file header information. */ + /* Initialize the file header information. */ /* -------------------------------------------------------------------- */ - abyHeader[0] = 0x03; /* memo field? - just copying */ + abyHeader[0] = 0x03; /* memo field? - just copying */ /* write out update date */ abyHeader[1] = STATIC_CAST(unsigned char, psDBF->nUpdateYearSince1900); @@ -158,7 +108,7 @@ static void DBFWriteHeader(DBFHandle psDBF) /* -------------------------------------------------------------------- */ /* Write the initial 32 byte file header, and all the field */ - /* descriptions. */ + /* descriptions. */ /* -------------------------------------------------------------------- */ psDBF->sHooks.FSeek(psDBF->fp, 0, 0); psDBF->sHooks.FWrite(abyHeader, XBASE_FILEHDR_SZ, 1, psDBF->fp); @@ -344,7 +294,6 @@ void SHPAPI_CALL DBFSetLastModifiedDate(DBFHandle psDBF, int nYYSince1900, /************************************************************************/ DBFHandle SHPAPI_CALL DBFOpen(const char *pszFilename, const char *pszAccess) - { SAHooks sHooks; @@ -376,7 +325,7 @@ static int DBFGetLenWithoutExtension(const char *pszBasename) /************************************************************************/ DBFHandle SHPAPI_CALL DBFOpenLL(const char *pszFilename, const char *pszAccess, - SAHooks *psHooks) + const SAHooks *psHooks) { /* -------------------------------------------------------------------- */ /* We only allow the access strings "rb" and "r+". */ @@ -393,8 +342,8 @@ DBFHandle SHPAPI_CALL DBFOpenLL(const char *pszFilename, const char *pszAccess, pszAccess = "rb+"; /* -------------------------------------------------------------------- */ - /* Compute the base (layer) name. If there is any extension */ - /* on the passed in filename we will strip it off. */ + /* Compute the base (layer) name. If there is any extension */ + /* on the passed in filename we will strip it off. */ /* -------------------------------------------------------------------- */ const int nLenWithoutExtension = DBFGetLenWithoutExtension(pszFilename); char *pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5)); @@ -402,19 +351,20 @@ DBFHandle SHPAPI_CALL DBFOpenLL(const char *pszFilename, const char *pszAccess, memcpy(pszFullname + nLenWithoutExtension, ".dbf", 5); DBFHandle psDBF = STATIC_CAST(DBFHandle, calloc(1, sizeof(DBFInfo))); - psDBF->fp = psHooks->FOpen(pszFullname, pszAccess); + psDBF->fp = psHooks->FOpen(pszFullname, pszAccess, psHooks->pvUserData); memcpy(&(psDBF->sHooks), psHooks, sizeof(SAHooks)); if (psDBF->fp == SHPLIB_NULLPTR) { memcpy(pszFullname + nLenWithoutExtension, ".DBF", 5); - psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess); + psDBF->fp = + psDBF->sHooks.FOpen(pszFullname, pszAccess, psHooks->pvUserData); } memcpy(pszFullname + nLenWithoutExtension, ".cpg", 5); - SAFile pfCPG = psHooks->FOpen(pszFullname, "r"); + SAFile pfCPG = psHooks->FOpen(pszFullname, "r", psHooks->pvUserData); if (pfCPG == SHPLIB_NULLPTR) { memcpy(pszFullname + nLenWithoutExtension, ".CPG", 5); - pfCPG = psHooks->FOpen(pszFullname, "r"); + pfCPG = psHooks->FOpen(pszFullname, "r", psHooks->pvUserData); } free(pszFullname); @@ -495,7 +445,7 @@ DBFHandle SHPAPI_CALL DBFOpenLL(const char *pszFilename, const char *pszAccess, /* -------------------------------------------------------------------- */ /* Read in Field Definitions */ /* -------------------------------------------------------------------- */ - pabyBuf = STATIC_CAST(unsigned char *, SfRealloc(pabyBuf, nHeadLen)); + pabyBuf = STATIC_CAST(unsigned char *, realloc(pabyBuf, nHeadLen)); psDBF->pszHeader = REINTERPRET_CAST(char *, pabyBuf); psDBF->sHooks.FSeek(psDBF->fp, XBASE_FILEHDR_SZ, 0); @@ -583,8 +533,8 @@ void SHPAPI_CALL DBFClose(DBFHandle psDBF) CPL_IGNORE_RET_VAL_INT(DBFFlushRecord(psDBF)); /* -------------------------------------------------------------------- */ - /* Update last access date, and number of records if we have */ - /* write access. */ + /* Update last access date, and number of records if we have */ + /* write access. */ /* -------------------------------------------------------------------- */ if (psDBF->bUpdated) DBFUpdateHeader(psDBF); @@ -645,11 +595,12 @@ DBFHandle SHPAPI_CALL DBFCreateEx(const char *pszFilename, /************************************************************************/ DBFHandle SHPAPI_CALL DBFCreateLL(const char *pszFilename, - const char *pszCodePage, SAHooks *psHooks) + const char *pszCodePage, + const SAHooks *psHooks) { /* -------------------------------------------------------------------- */ - /* Compute the base (layer) name. If there is any extension */ - /* on the passed in filename we will strip it off. */ + /* Compute the base (layer) name. If there is any extension */ + /* on the passed in filename we will strip it off. */ /* -------------------------------------------------------------------- */ const int nLenWithoutExtension = DBFGetLenWithoutExtension(pszFilename); char *pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5)); @@ -659,17 +610,7 @@ DBFHandle SHPAPI_CALL DBFCreateLL(const char *pszFilename, /* -------------------------------------------------------------------- */ /* Create the file. */ /* -------------------------------------------------------------------- */ - SAFile fp = psHooks->FOpen(pszFullname, "wb"); - if (fp == SHPLIB_NULLPTR) { - free(pszFullname); - return SHPLIB_NULLPTR; - } - - char chZero = '\0'; - psHooks->FWrite(&chZero, 1, 1, fp); - psHooks->FClose(fp); - - fp = psHooks->FOpen(pszFullname, "rb+"); + SAFile fp = psHooks->FOpen(pszFullname, "wb+", psHooks->pvUserData); if (fp == SHPLIB_NULLPTR) { free(pszFullname); return SHPLIB_NULLPTR; @@ -685,7 +626,8 @@ DBFHandle SHPAPI_CALL DBFCreateLL(const char *pszFilename, // a valid one } if (ldid < 0) { - SAFile fpCPG = psHooks->FOpen(pszFullname, "w"); + SAFile fpCPG = + psHooks->FOpen(pszFullname, "w", psHooks->pvUserData); psHooks->FWrite( CONST_CAST(void *, STATIC_CAST(const void *, pszCodePage)), strlen(pszCodePage), 1, fpCPG); @@ -693,13 +635,13 @@ DBFHandle SHPAPI_CALL DBFCreateLL(const char *pszFilename, } } if (pszCodePage == SHPLIB_NULLPTR || ldid >= 0) { - psHooks->Remove(pszFullname); + psHooks->Remove(pszFullname, psHooks->pvUserData); } free(pszFullname); /* -------------------------------------------------------------------- */ - /* Create the info structure. */ + /* Create the info structure. */ /* -------------------------------------------------------------------- */ DBFHandle psDBF = STATIC_CAST(DBFHandle, calloc(1, sizeof(DBFInfo))); @@ -829,23 +771,22 @@ int SHPAPI_CALL DBFAddNativeFieldType(DBFHandle psDBF, const char *pszFieldName, const int nOldHeaderLength = psDBF->nHeaderLength; /* -------------------------------------------------------------------- */ - /* SfRealloc all the arrays larger to hold the additional field */ + /* realloc all the arrays larger to hold the additional field */ /* information. */ /* -------------------------------------------------------------------- */ psDBF->nFields++; psDBF->panFieldOffset = STATIC_CAST( - int *, SfRealloc(psDBF->panFieldOffset, sizeof(int) * psDBF->nFields)); + int *, realloc(psDBF->panFieldOffset, sizeof(int) * psDBF->nFields)); psDBF->panFieldSize = STATIC_CAST( - int *, SfRealloc(psDBF->panFieldSize, sizeof(int) * psDBF->nFields)); + int *, realloc(psDBF->panFieldSize, sizeof(int) * psDBF->nFields)); - psDBF->panFieldDecimals = - STATIC_CAST(int *, SfRealloc(psDBF->panFieldDecimals, - sizeof(int) * psDBF->nFields)); + psDBF->panFieldDecimals = STATIC_CAST( + int *, realloc(psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields)); psDBF->pachFieldType = STATIC_CAST( - char *, SfRealloc(psDBF->pachFieldType, sizeof(char) * psDBF->nFields)); + char *, realloc(psDBF->pachFieldType, sizeof(char) * psDBF->nFields)); /* -------------------------------------------------------------------- */ /* Assign the new field information fields. */ @@ -863,7 +804,7 @@ int SHPAPI_CALL DBFAddNativeFieldType(DBFHandle psDBF, const char *pszFieldName, psDBF->bUpdated = FALSE; psDBF->pszHeader = STATIC_CAST( - char *, SfRealloc(psDBF->pszHeader, psDBF->nFields * XBASE_FLDHDR_SZ)); + char *, realloc(psDBF->pszHeader, psDBF->nFields * XBASE_FLDHDR_SZ)); char *pszFInfo = psDBF->pszHeader + XBASE_FLDHDR_SZ * (psDBF->nFields - 1); @@ -887,7 +828,7 @@ int SHPAPI_CALL DBFAddNativeFieldType(DBFHandle psDBF, const char *pszFieldName, /* Make the current record buffer appropriately larger. */ /* -------------------------------------------------------------------- */ psDBF->pszCurrentRecord = STATIC_CAST( - char *, SfRealloc(psDBF->pszCurrentRecord, psDBF->nRecordLength)); + char *, realloc(psDBF->pszCurrentRecord, psDBF->nRecordLength)); /* we're done if dealing with new .dbf */ if (psDBF->bNoHeader) @@ -971,13 +912,13 @@ static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField, return SHPLIB_NULLPTR; /* -------------------------------------------------------------------- */ - /* Have we read the record? */ + /* Have we read the record? */ /* -------------------------------------------------------------------- */ if (!DBFLoadRecord(psDBF, hEntity)) return SHPLIB_NULLPTR; - unsigned char *pabyRec = - REINTERPRET_CAST(unsigned char *, psDBF->pszCurrentRecord); + const unsigned char *pabyRec = + REINTERPRET_CAST(const unsigned char *, psDBF->pszCurrentRecord); /* -------------------------------------------------------------------- */ /* Ensure we have room to extract the target field. */ @@ -993,7 +934,7 @@ static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField, } /* -------------------------------------------------------------------- */ - /* Extract the requested field. */ + /* Extract the requested field. */ /* -------------------------------------------------------------------- */ memcpy(psDBF->pszWorkField, REINTERPRET_CAST(const char *, pabyRec) + @@ -1085,7 +1026,6 @@ double SHPAPI_CALL DBFReadDoubleAttribute(DBFHandle psDBF, int iRecord, const char SHPAPI_CALL1(*) DBFReadStringAttribute(DBFHandle psDBF, int iRecord, int iField) - { return STATIC_CAST(const char *, DBFReadAttribute(psDBF, iRecord, iField, 'C')); @@ -1099,12 +1039,40 @@ const char SHPAPI_CALL1(*) const char SHPAPI_CALL1(*) DBFReadLogicalAttribute(DBFHandle psDBF, int iRecord, int iField) - { return STATIC_CAST(const char *, DBFReadAttribute(psDBF, iRecord, iField, 'L')); } +/************************************************************************/ +/* DBFReadDateAttribute() */ +/* */ +/* Read a date attribute. */ +/************************************************************************/ + +SHPDate SHPAPI_CALL DBFReadDateAttribute(DBFHandle psDBF, int iRecord, + int iField) +{ + const char *pdateValue = STATIC_CAST( + const char *, DBFReadAttribute(psDBF, iRecord, iField, 'D')); + + SHPDate date; + + if (pdateValue == SHPLIB_NULLPTR) { + date.year = 0; + date.month = 0; + date.day = 0; + } + else if (3 != sscanf(pdateValue, "%4d%2d%2d", &date.year, &date.month, + &date.day)) { + date.year = 0; + date.month = 0; + date.day = 0; + } + + return date; +} + /************************************************************************/ /* DBFIsValueNULL() */ /* */ @@ -1135,7 +1103,16 @@ static bool DBFIsValueNULL(char chType, const char *pszValue) case 'D': /* NULL date fields have value "00000000" */ - return strncmp(pszValue, "00000000", 8) == 0; + /* Some DBF files have fields filled with spaces */ + /* (trimmed by DBFReadStringAttribute) to indicate null */ + /* values for dates (#4265). */ + /* And others have ' 0': + * https://lists.osgeo.org/pipermail/gdal-dev/2023-November/058010.html + */ + /* And others just empty string: + * https://github.com/OSGeo/gdal/issues/10405 */ + return pszValue[0] == 0 || strncmp(pszValue, "00000000", 8) == 0 || + strcmp(pszValue, " ") == 0 || strcmp(pszValue, "0") == 0; case 'L': /* NULL boolean fields have value "?" */ @@ -1155,7 +1132,8 @@ static bool DBFIsValueNULL(char chType, const char *pszValue) /* Contributed by Jim Matthews. */ /************************************************************************/ -int SHPAPI_CALL DBFIsAttributeNULL(DBFHandle psDBF, int iRecord, int iField) +int SHPAPI_CALL DBFIsAttributeNULL(const DBFHandle psDBF, int iRecord, + int iField) { const char *pszValue = DBFReadStringAttribute(psDBF, iRecord, iField); @@ -1171,8 +1149,7 @@ int SHPAPI_CALL DBFIsAttributeNULL(DBFHandle psDBF, int iRecord, int iField) /* Return the number of fields in this table. */ /************************************************************************/ -int SHPAPI_CALL DBFGetFieldCount(DBFHandle psDBF) - +int SHPAPI_CALL DBFGetFieldCount(const DBFHandle psDBF) { return (psDBF->nFields); } @@ -1183,8 +1160,7 @@ int SHPAPI_CALL DBFGetFieldCount(DBFHandle psDBF) /* Return the number of records in this table. */ /************************************************************************/ -int SHPAPI_CALL DBFGetRecordCount(DBFHandle psDBF) - +int SHPAPI_CALL DBFGetRecordCount(const DBFHandle psDBF) { return (psDBF->nRecords); } @@ -1197,10 +1173,9 @@ int SHPAPI_CALL DBFGetRecordCount(DBFHandle psDBF) /* bytes long. */ /************************************************************************/ -DBFFieldType SHPAPI_CALL DBFGetFieldInfo(DBFHandle psDBF, int iField, +DBFFieldType SHPAPI_CALL DBFGetFieldInfo(const DBFHandle psDBF, int iField, char *pszFieldName, int *pnWidth, int *pnDecimals) - { if (iField < 0 || iField >= psDBF->nFields) return (FTInvalid); @@ -1230,10 +1205,9 @@ DBFFieldType SHPAPI_CALL DBFGetFieldInfo(DBFHandle psDBF, int iField, else if (psDBF->pachFieldType[iField] == 'N' || psDBF->pachFieldType[iField] == 'F') { - if (psDBF->panFieldDecimals[iField] > 0) { - /* || psDBF->panFieldSize[iField] >= 10 ) */ /* GDAL bug #809 */ + if (psDBF->panFieldDecimals[iField] > 0 || + psDBF->panFieldSize[iField] >= 10) return (FTDouble); - } else return (FTInteger); } @@ -1244,15 +1218,15 @@ DBFFieldType SHPAPI_CALL DBFGetFieldInfo(DBFHandle psDBF, int iField, /************************************************************************/ /* DBFWriteAttribute() */ -/* */ -/* Write an attribute record to the file. */ +/* */ +/* Write an attribute record to the file. */ /************************************************************************/ static bool DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, void *pValue) { /* -------------------------------------------------------------------- */ - /* Is this a valid record? */ + /* Is this a valid record? */ /* -------------------------------------------------------------------- */ if (hEntity < 0 || hEntity > psDBF->nRecords) return false; @@ -1333,9 +1307,13 @@ static bool DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, case 'L': if (psDBF->panFieldSize[iField] >= 1 && (*STATIC_CAST(char *, pValue) == 'F' || - *STATIC_CAST(char *, pValue) == 'T')) + *STATIC_CAST(char *, pValue) == 'T')) { *(pabyRec + psDBF->panFieldOffset[iField]) = *STATIC_CAST(char *, pValue); + } + else { + nRetResult = false; + } break; default: { @@ -1370,10 +1348,10 @@ static bool DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, /************************************************************************/ int SHPAPI_CALL DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, - int iField, void *pValue) + int iField, const void *pValue) { /* -------------------------------------------------------------------- */ - /* Is this a valid record? */ + /* Is this a valid record? */ /* -------------------------------------------------------------------- */ if (hEntity < 0 || hEntity > psDBF->nRecords) return (FALSE); @@ -1402,24 +1380,29 @@ int SHPAPI_CALL DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, if (!DBFLoadRecord(psDBF, hEntity)) return FALSE; - unsigned char *pabyRec = - REINTERPRET_CAST(unsigned char *, psDBF->pszCurrentRecord); + if (iField >= 0) { + unsigned char *pabyRec = + REINTERPRET_CAST(unsigned char *, psDBF->pszCurrentRecord); - /* -------------------------------------------------------------------- */ - /* Assign all the record fields. */ - /* -------------------------------------------------------------------- */ - int j; - if (STATIC_CAST(int, strlen(STATIC_CAST(char *, pValue))) > - psDBF->panFieldSize[iField]) - j = psDBF->panFieldSize[iField]; - else { - memset(pabyRec + psDBF->panFieldOffset[iField], ' ', - psDBF->panFieldSize[iField]); - j = STATIC_CAST(int, strlen(STATIC_CAST(char *, pValue))); - } + /* -------------------------------------------------------------------- + */ + /* Assign all the record fields. */ + /* -------------------------------------------------------------------- + */ + int j; + if (STATIC_CAST(int, strlen(STATIC_CAST(const char *, pValue))) > + psDBF->panFieldSize[iField]) + j = psDBF->panFieldSize[iField]; + else { + memset(pabyRec + psDBF->panFieldOffset[iField], ' ', + psDBF->panFieldSize[iField]); + j = STATIC_CAST(int, strlen(STATIC_CAST(const char *, pValue))); + } - strncpy(REINTERPRET_CAST(char *, pabyRec + psDBF->panFieldOffset[iField]), + memcpy( + REINTERPRET_CAST(char *, pabyRec + psDBF->panFieldOffset[iField]), STATIC_CAST(const char *, pValue), j); + } psDBF->bCurrentRecordModified = TRUE; psDBF->bUpdated = TRUE; @@ -1443,7 +1426,7 @@ int SHPAPI_CALL DBFWriteDoubleAttribute(DBFHandle psDBF, int iRecord, /************************************************************************/ /* DBFWriteIntegerAttribute() */ /* */ -/* Write a integer attribute. */ +/* Write an integer attribute. */ /************************************************************************/ int SHPAPI_CALL DBFWriteIntegerAttribute(DBFHandle psDBF, int iRecord, @@ -1463,7 +1446,6 @@ int SHPAPI_CALL DBFWriteIntegerAttribute(DBFHandle psDBF, int iRecord, int SHPAPI_CALL DBFWriteStringAttribute(DBFHandle psDBF, int iRecord, int iField, const char *pszValue) - { return ( DBFWriteAttribute(psDBF, iRecord, iField, @@ -1473,11 +1455,10 @@ int SHPAPI_CALL DBFWriteStringAttribute(DBFHandle psDBF, int iRecord, /************************************************************************/ /* DBFWriteNULLAttribute() */ /* */ -/* Write a string attribute. */ +/* Write a NULL attribute. */ /************************************************************************/ int SHPAPI_CALL DBFWriteNULLAttribute(DBFHandle psDBF, int iRecord, int iField) - { return (DBFWriteAttribute(psDBF, iRecord, iField, SHPLIB_NULLPTR)); } @@ -1490,23 +1471,47 @@ int SHPAPI_CALL DBFWriteNULLAttribute(DBFHandle psDBF, int iRecord, int iField) int SHPAPI_CALL DBFWriteLogicalAttribute(DBFHandle psDBF, int iRecord, int iField, const char lValue) - { return ( DBFWriteAttribute(psDBF, iRecord, iField, STATIC_CAST(void *, CONST_CAST(char *, &lValue)))); } +/************************************************************************/ +/* DBFWriteDateAttribute() */ +/* */ +/* Write a date attribute. */ +/************************************************************************/ + +int SHPAPI_CALL DBFWriteDateAttribute(DBFHandle psDBF, int iRecord, int iField, + const SHPDate *lValue) +{ + if (SHPLIB_NULLPTR == lValue) + return false; + /* check for supported digit range, but do not check for valid date */ + if (lValue->year < 0 || lValue->year > 9999) + return false; + if (lValue->month < 0 || lValue->month > 99) + return false; + if (lValue->day < 0 || lValue->day > 99) + return false; + char dateValue[9]; /* "yyyyMMdd\0" */ + snprintf(dateValue, sizeof(dateValue), "%04d%02d%02d", lValue->year, + lValue->month, lValue->day); + return (DBFWriteAttributeDirectly(psDBF, iRecord, iField, dateValue)); +} + /************************************************************************/ /* DBFWriteTuple() */ -/* */ -/* Write an attribute record to the file. */ +/* */ +/* Write an attribute record to the file. */ /************************************************************************/ -int SHPAPI_CALL DBFWriteTuple(DBFHandle psDBF, int hEntity, void *pRawTuple) +int SHPAPI_CALL DBFWriteTuple(DBFHandle psDBF, int hEntity, + const void *pRawTuple) { /* -------------------------------------------------------------------- */ - /* Is this a valid record? */ + /* Is this a valid record? */ /* -------------------------------------------------------------------- */ if (hEntity < 0 || hEntity > psDBF->nRecords) return (FALSE); @@ -1554,7 +1559,6 @@ int SHPAPI_CALL DBFWriteTuple(DBFHandle psDBF, int hEntity, void *pRawTuple) /************************************************************************/ const char SHPAPI_CALL1(*) DBFReadTuple(DBFHandle psDBF, int hEntity) - { if (hEntity < 0 || hEntity >= psDBF->nRecords) return SHPLIB_NULLPTR; @@ -1566,14 +1570,17 @@ const char SHPAPI_CALL1(*) DBFReadTuple(DBFHandle psDBF, int hEntity) } /************************************************************************/ -/* DBFCloneEmpty() */ +/* DBFCloneEmpty() */ /* */ -/* Read one of the attribute fields of a record. */ +/* Create a new .dbf file with same code page and field */ +/* definitions as the given handle. */ /************************************************************************/ -DBFHandle SHPAPI_CALL DBFCloneEmpty(DBFHandle psDBF, const char *pszFilename) +DBFHandle SHPAPI_CALL DBFCloneEmpty(const DBFHandle psDBF, + const char *pszFilename) { - DBFHandle newDBF = DBFCreateEx(pszFilename, psDBF->pszCodePage); + DBFHandle newDBF = + DBFCreateLL(pszFilename, psDBF->pszCodePage, &psDBF->sHooks); if (newDBF == SHPLIB_NULLPTR) return SHPLIB_NULLPTR; @@ -1629,8 +1636,7 @@ DBFHandle SHPAPI_CALL DBFCloneEmpty(DBFHandle psDBF, const char *pszFilename) /* 'M' (Memo: 10 digits .DBT block ptr) */ /************************************************************************/ -char SHPAPI_CALL DBFGetNativeFieldType(DBFHandle psDBF, int iField) - +char SHPAPI_CALL DBFGetNativeFieldType(const DBFHandle psDBF, int iField) { if (iField >= 0 && iField < psDBF->nFields) return psDBF->pachFieldType[iField]; @@ -1646,7 +1652,8 @@ char SHPAPI_CALL DBFGetNativeFieldType(DBFHandle psDBF, int iField) /* Contributed by Jim Matthews. */ /************************************************************************/ -int SHPAPI_CALL DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName) +int SHPAPI_CALL DBFGetFieldIndex(const DBFHandle psDBF, + const char *pszFieldName) { char name[XBASE_FLDNAME_LEN_READ + 1]; @@ -1665,7 +1672,7 @@ int SHPAPI_CALL DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName) /* it returns FALSE. */ /************************************************************************/ -int SHPAPI_CALL DBFIsRecordDeleted(DBFHandle psDBF, int iShape) +int SHPAPI_CALL DBFIsRecordDeleted(const DBFHandle psDBF, int iShape) { /* -------------------------------------------------------------------- */ /* Verify selection. */ @@ -1674,7 +1681,7 @@ int SHPAPI_CALL DBFIsRecordDeleted(DBFHandle psDBF, int iShape) return TRUE; /* -------------------------------------------------------------------- */ - /* Have we read the record? */ + /* Have we read the record? */ /* -------------------------------------------------------------------- */ if (!DBFLoadRecord(psDBF, iShape)) return FALSE; @@ -1727,7 +1734,7 @@ int SHPAPI_CALL DBFMarkRecordDeleted(DBFHandle psDBF, int iShape, /* DBFGetCodePage */ /************************************************************************/ -const char SHPAPI_CALL1(*) DBFGetCodePage(DBFHandle psDBF) +const char SHPAPI_CALL1(*) DBFGetCodePage(const DBFHandle psDBF) { if (psDBF == SHPLIB_NULLPTR) return SHPLIB_NULLPTR; @@ -1768,17 +1775,16 @@ int SHPAPI_CALL DBFDeleteField(DBFHandle psDBF, int iField) psDBF->nFields--; psDBF->panFieldOffset = STATIC_CAST( - int *, SfRealloc(psDBF->panFieldOffset, sizeof(int) * psDBF->nFields)); + int *, realloc(psDBF->panFieldOffset, sizeof(int) * psDBF->nFields)); psDBF->panFieldSize = STATIC_CAST( - int *, SfRealloc(psDBF->panFieldSize, sizeof(int) * psDBF->nFields)); + int *, realloc(psDBF->panFieldSize, sizeof(int) * psDBF->nFields)); - psDBF->panFieldDecimals = - STATIC_CAST(int *, SfRealloc(psDBF->panFieldDecimals, - sizeof(int) * psDBF->nFields)); + psDBF->panFieldDecimals = STATIC_CAST( + int *, realloc(psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields)); psDBF->pachFieldType = STATIC_CAST( - char *, SfRealloc(psDBF->pachFieldType, sizeof(char) * psDBF->nFields)); + char *, realloc(psDBF->pachFieldType, sizeof(char) * psDBF->nFields)); /* update header information */ psDBF->nHeaderLength -= XBASE_FLDHDR_SZ; @@ -1790,11 +1796,11 @@ int SHPAPI_CALL DBFDeleteField(DBFHandle psDBF, int iField) sizeof(char) * (psDBF->nFields - iField) * XBASE_FLDHDR_SZ); psDBF->pszHeader = STATIC_CAST( - char *, SfRealloc(psDBF->pszHeader, psDBF->nFields * XBASE_FLDHDR_SZ)); + char *, realloc(psDBF->pszHeader, psDBF->nFields * XBASE_FLDHDR_SZ)); /* update size of current record appropriately */ psDBF->pszCurrentRecord = STATIC_CAST( - char *, SfRealloc(psDBF->pszCurrentRecord, psDBF->nRecordLength)); + char *, realloc(psDBF->pszCurrentRecord, psDBF->nRecordLength)); /* we're done if we're dealing with not yet created .dbf */ if (psDBF->bNoHeader && psDBF->nRecords == 0) @@ -1866,7 +1872,7 @@ int SHPAPI_CALL DBFDeleteField(DBFHandle psDBF, int iField) /* code of DBFReorderFields. */ /************************************************************************/ -int SHPAPI_CALL DBFReorderFields(DBFHandle psDBF, int *panMap) +int SHPAPI_CALL DBFReorderFields(DBFHandle psDBF, const int *panMap) { if (psDBF->nFields == 0) return TRUE; @@ -1878,13 +1884,13 @@ int SHPAPI_CALL DBFReorderFields(DBFHandle psDBF, int *panMap) /* a simple malloc() would be enough, but calloc() helps clang static * analyzer */ int *panFieldOffsetNew = - STATIC_CAST(int *, calloc(sizeof(int), psDBF->nFields)); + STATIC_CAST(int *, calloc(psDBF->nFields, sizeof(int))); int *panFieldSizeNew = - STATIC_CAST(int *, calloc(sizeof(int), psDBF->nFields)); + STATIC_CAST(int *, calloc(psDBF->nFields, sizeof(int))); int *panFieldDecimalsNew = - STATIC_CAST(int *, calloc(sizeof(int), psDBF->nFields)); + STATIC_CAST(int *, calloc(psDBF->nFields, sizeof(int))); char *pachFieldTypeNew = - STATIC_CAST(char *, calloc(sizeof(char), psDBF->nFields)); + STATIC_CAST(char *, calloc(psDBF->nFields, sizeof(char))); char *pszHeaderNew = STATIC_CAST( char *, malloc(sizeof(char) * XBASE_FLDHDR_SZ * psDBF->nFields)); @@ -2050,7 +2056,7 @@ int SHPAPI_CALL DBFAlterFieldDefn(DBFHandle psDBF, int iField, psDBF->nRecordLength += nWidth - nOldWidth; psDBF->pszCurrentRecord = STATIC_CAST( - char *, SfRealloc(psDBF->pszCurrentRecord, psDBF->nRecordLength)); + char *, realloc(psDBF->pszCurrentRecord, psDBF->nRecordLength)); } /* we're done if we're dealing with not yet created .dbf */ @@ -2069,7 +2075,6 @@ int SHPAPI_CALL DBFAlterFieldDefn(DBFHandle psDBF, int iField, char *pszOldField = STATIC_CAST(char *, malloc(sizeof(char) * (nOldWidth + 1))); - /* cppcheck-suppress uninitdata */ pszOldField[nOldWidth] = 0; /* move records to their new positions */ @@ -2139,7 +2144,6 @@ int SHPAPI_CALL DBFAlterFieldDefn(DBFHandle psDBF, int iField, char *pszOldField = STATIC_CAST(char *, malloc(sizeof(char) * (nOldWidth + 1))); - /* cppcheck-suppress uninitdata */ pszOldField[nOldWidth] = 0; /* move records to their new positions */ diff --git a/lib/external/shapelib/safileio.c b/lib/external/shapelib/safileio.c index 3377642e4d4..e13f1f29acf 100644 --- a/lib/external/shapelib/safileio.c +++ b/lib/external/shapelib/safileio.c @@ -1,5 +1,4 @@ /****************************************************************************** - * $Id: safileio.c,v 1.6 2018-06-15 19:56:32 erouault Exp $ * * Project: Shapelib * Purpose: Default implementation of file io based on stdio. @@ -8,74 +7,19 @@ ****************************************************************************** * Copyright (c) 2007, Frank Warmerdam * - * This software is available under the following "MIT Style" license, - * or at the option of the licensee under the LGPL (see COPYING). This - * option is discussed in more detail in shapelib.html. - * - * -- - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * SPDX-License-Identifier: MIT OR LGPL-2.0-or-later ****************************************************************************** * - * $Log: safileio.c,v $ - * Revision 1.6 2018-06-15 19:56:32 erouault - * * safileio.c: remove duplicate test. Patch by Jaroslav Fojtik. - * Fixes http://bugzilla.maptools.org/show_bug.cgi?id=2744 - * - * Revision 1.5 2016-12-05 12:44:05 erouault - * * Major overhaul of Makefile build system to use autoconf/automake. - * - * * Warning fixes in contrib/ - * - * Revision 1.4 2008-01-16 20:05:14 bram - * Add file hooks that accept UTF-8 encoded filenames on some platforms. Use - *SASetupUtf8Hooks tosetup the hooks and check SHPAPI_UTF8_HOOKS for its - *availability. Currently, this is only available on the Windows platform that - *decodes the UTF-8 filenames to wide character strings and feeds them to - *_wfopen and _wremove. - * - * Revision 1.3 2007/12/18 18:28:11 bram - * - create hook for client specific atof (bugzilla ticket 1615) - * - check for NULL handle before closing cpCPG file, and close after reading. - * - * Revision 1.2 2007/12/15 20:25:30 bram - * dbfopen.c now reads the Code Page information from the DBF file, and exports - * this information as a string through the DBFGetCodePage function. This is - * either the number from the LDID header field ("LDID/") or as the - * content of an accompanying .CPG file. When creating a DBF file, the code can - * be set using DBFCreateEx. - * - * Revision 1.1 2007/12/06 06:56:41 fwarmerdam - * new - * */ #include "shapefil.h" +#include #include #include -#include +#include #include #include -#include - -SHP_CVSID("$Id: safileio.c,v 1.6 2018-06-15 19:56:32 erouault Exp $") #ifdef SHPAPI_UTF8_HOOKS #ifdef SHPAPI_WINDOWS @@ -86,102 +30,64 @@ SHP_CVSID("$Id: safileio.c,v 1.6 2018-06-15 19:56:32 erouault Exp $") #endif #endif -/************************************************************************/ -/* SADFOpen() */ -/************************************************************************/ - -SAFile SADFOpen(const char *pszFilename, const char *pszAccess) - +static SAFile SADFOpen(const char *pszFilename, const char *pszAccess, + void *pvUserData) { + (void)pvUserData; return (SAFile)fopen(pszFilename, pszAccess); } -/************************************************************************/ -/* SADFRead() */ -/************************************************************************/ - -SAOffset SADFRead(void *p, SAOffset size, SAOffset nmemb, SAFile file) - +static SAOffset SADFRead(void *p, SAOffset size, SAOffset nmemb, SAFile file) { return (SAOffset)fread(p, (size_t)size, (size_t)nmemb, (FILE *)file); } -/************************************************************************/ -/* SADFWrite() */ -/************************************************************************/ - -SAOffset SADFWrite(void *p, SAOffset size, SAOffset nmemb, SAFile file) - +static SAOffset SADFWrite(const void *p, SAOffset size, SAOffset nmemb, + SAFile file) { return (SAOffset)fwrite(p, (size_t)size, (size_t)nmemb, (FILE *)file); } -/************************************************************************/ -/* SADFSeek() */ -/************************************************************************/ - -SAOffset SADFSeek(SAFile file, SAOffset offset, int whence) - +static SAOffset SADFSeek(SAFile file, SAOffset offset, int whence) { +#if defined(_MSC_VER) && _MSC_VER >= 1400 + return (SAOffset)_fseeki64((FILE *)file, (__int64)offset, whence); +#else return (SAOffset)fseek((FILE *)file, (long)offset, whence); +#endif } -/************************************************************************/ -/* SADFTell() */ -/************************************************************************/ - -SAOffset SADFTell(SAFile file) - +static SAOffset SADFTell(SAFile file) { +#if defined(_MSC_VER) && _MSC_VER >= 1400 + return (SAOffset)_ftelli64((FILE *)file); +#else return (SAOffset)ftell((FILE *)file); +#endif } -/************************************************************************/ -/* SADFFlush() */ -/************************************************************************/ - -int SADFFlush(SAFile file) - +static int SADFFlush(SAFile file) { return fflush((FILE *)file); } -/************************************************************************/ -/* SADFClose() */ -/************************************************************************/ - -int SADFClose(SAFile file) - +static int SADFClose(SAFile file) { return fclose((FILE *)file); } -/************************************************************************/ -/* SADFClose() */ -/************************************************************************/ - -int SADRemove(const char *filename) - +static int SADRemove(const char *filename, void *pvUserData) { + (void)pvUserData; return remove(filename); } -/************************************************************************/ -/* SADError() */ -/************************************************************************/ - -void SADError(const char *message) - +static void SADError(const char *message) { fprintf(stderr, "%s\n", message); } -/************************************************************************/ -/* SASetupDefaultHooks() */ -/************************************************************************/ - void SASetupDefaultHooks(SAHooks *psHooks) - { psHooks->FOpen = SADFOpen; psHooks->FRead = SADFRead; @@ -194,25 +100,20 @@ void SASetupDefaultHooks(SAHooks *psHooks) psHooks->Error = SADError; psHooks->Atof = atof; + psHooks->pvUserData = NULL; } #ifdef SHPAPI_WINDOWS -/************************************************************************/ -/* Utf8ToWideChar */ -/************************************************************************/ - -const wchar_t *Utf8ToWideChar(const char *pszFilename) +static wchar_t *Utf8ToWideChar(const char *pszFilename) { - int nMulti, nWide; - wchar_t *pwszFileName; - - nMulti = strlen(pszFilename) + 1; - nWide = MultiByteToWideChar(CP_UTF8, 0, pszFilename, nMulti, 0, 0); + const int nMulti = (int)strlen(pszFilename) + 1; + const int nWide = + MultiByteToWideChar(CP_UTF8, 0, pszFilename, nMulti, 0, 0); if (nWide == 0) { return NULL; } - pwszFileName = (wchar_t *)malloc(nWide * sizeof(wchar_t)); + wchar_t *pwszFileName = (wchar_t *)malloc(nWide * sizeof(wchar_t)); if (pwszFileName == NULL) { return NULL; } @@ -228,51 +129,44 @@ const wchar_t *Utf8ToWideChar(const char *pszFilename) /* SAUtf8WFOpen */ /************************************************************************/ -SAFile SAUtf8WFOpen(const char *pszFilename, const char *pszAccess) +static SAFile SAUtf8WFOpen(const char *pszFilename, const char *pszAccess, + void *pvUserData) { + (void)pvUserData; SAFile file = NULL; - const wchar_t *pwszFileName, *pwszAccess; - pwszFileName = Utf8ToWideChar(pszFilename); - pwszAccess = Utf8ToWideChar(pszAccess); + wchar_t *pwszFileName = Utf8ToWideChar(pszFilename); + wchar_t *pwszAccess = Utf8ToWideChar(pszAccess); if (pwszFileName != NULL && pwszAccess != NULL) { file = (SAFile)_wfopen(pwszFileName, pwszAccess); } - free((wchar_t *)pwszFileName); - free((wchar_t *)pwszAccess); + free(pwszFileName); + free(pwszAccess); return file; } -/************************************************************************/ -/* SAUtf8WRemove() */ -/************************************************************************/ - -int SAUtf8WRemove(const char *pszFilename) +static int SAUtf8WRemove(const char *pszFilename, void *pvUserData) { - const wchar_t *pwszFileName = Utf8ToWideChar(pszFilename); + (void)pvUserData; + wchar_t *pwszFileName = Utf8ToWideChar(pszFilename); int rc = -1; if (pwszFileName != NULL) { rc = _wremove(pwszFileName); } - free((wchar_t *)pwszFileName); + free(pwszFileName); return rc; } #endif #ifdef SHPAPI_UTF8_HOOKS - -/************************************************************************/ -/* SASetupUtf8Hooks() */ -/************************************************************************/ +#ifndef SHPAPI_WINDOWS +#error "no implementations of UTF-8 hooks available for this platform" +#endif void SASetupUtf8Hooks(SAHooks *psHooks) { -#ifdef SHPAPI_WINDOWS psHooks->FOpen = SAUtf8WFOpen; psHooks->Remove = SAUtf8WRemove; -#else -#error "no implementations of UTF-8 hooks available for this platform" -#endif psHooks->FRead = SADFRead; psHooks->FWrite = SADFWrite; psHooks->FSeek = SADFSeek; @@ -283,5 +177,4 @@ void SASetupUtf8Hooks(SAHooks *psHooks) psHooks->Error = SADError; psHooks->Atof = atof; } - #endif diff --git a/lib/external/shapelib/shapefil.h b/lib/external/shapelib/shapefil.h index cd4ef54aa56..c11632fa6ba 100644 --- a/lib/external/shapelib/shapefil.h +++ b/lib/external/shapelib/shapefil.h @@ -2,7 +2,6 @@ #define SHAPEFILE_H_INCLUDED /****************************************************************************** - * $Id$ * * Project: Shapelib * Purpose: Primary include file for Shapelib. @@ -12,29 +11,7 @@ * Copyright (c) 1999, Frank Warmerdam * Copyright (c) 2012-2016, Even Rouault * - * This software is available under the following "MIT Style" license, - * or at the option of the licensee under the LGPL (see COPYING). This - * option is discussed in more detail in shapelib.html. - * - * -- - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * SPDX-License-Identifier: MIT OR LGPL-2.0-or-later ****************************************************************************** * */ @@ -49,6 +26,26 @@ extern "C" { #endif +/************************************************************************/ +/* Version related macros (added in 1.6.0) */ +/************************************************************************/ + +#define SHAPELIB_VERSION_MAJOR 1 +#define SHAPELIB_VERSION_MINOR 6 +#define SHAPELIB_VERSION_MICRO 0 + +#define SHAPELIB_MAKE_VERSION_NUMBER(major, minor, micro) \ + ((major) * 10000 + (minor) * 100 + (micro)) + +#define SHAPELIB_VERSION_NUMBER \ + SHAPELIB_MAKE_VERSION_NUMBER(SHAPELIB_VERSION_MAJOR, \ + SHAPELIB_VERSION_MINOR, \ + SHAPELIB_VERSION_MICRO) + +#define SHAPELIB_AT_LEAST(major, minor, micro) \ + (SHAPELIB_VERSION_NUMBER >= \ + SHAPELIB_MAKE_VERSION_NUMBER(major, minor, micro)) + /************************************************************************/ /* Configuration options. */ /************************************************************************/ @@ -73,7 +70,7 @@ extern "C" { /* various calling conventions on the Shapelib API. */ /* */ /* To force __stdcall conventions (needed to call Shapelib */ -/* from Visual Basic and/or Dephi I believe) the makefile could */ +/* from Visual Basic and/or Delphi I believe) the makefile could */ /* be modified to define: */ /* */ /* /DSHPAPI_CALL=__stdcall */ @@ -113,31 +110,11 @@ extern "C" { #define SHPAPI_CALL1(x) x SHPAPI_CALL #endif -/* -------------------------------------------------------------------- */ -/* Macros for controlling CVSID and ensuring they don't appear */ -/* as unreferenced variables resulting in lots of warnings. */ -/* -------------------------------------------------------------------- */ -#ifndef DISABLE_CVSID -#if defined(__GNUC__) && __GNUC__ >= 4 -#define SHP_CVSID(string) \ - static const char cpl_cvsid[] __attribute__((used)) = string; -#else -#define SHP_CVSID(string) \ - static const char cpl_cvsid[] = string; \ - static const char *cvsid_aw() \ - { \ - return (cvsid_aw() ? NULL : cpl_cvsid); \ - } -#endif -#else -#define SHP_CVSID(string) -#endif - /* -------------------------------------------------------------------- */ /* On some platforms, additional file IO hooks are defined that */ /* UTF-8 encoded filenames Unicode filenames */ /* -------------------------------------------------------------------- */ -#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +#if defined(_WIN32) #define SHPAPI_WINDOWS #define SHPAPI_UTF8_HOOKS #endif @@ -148,21 +125,27 @@ extern "C" { typedef int *SAFile; #ifndef SAOffset +#if defined(_MSC_VER) && _MSC_VER >= 1400 +typedef unsigned __int64 SAOffset; +#else typedef unsigned long SAOffset; #endif +#endif typedef struct { - SAFile (*FOpen)(const char *filename, const char *access); + SAFile (*FOpen)(const char *filename, const char *access, void *pvUserData); SAOffset (*FRead)(void *p, SAOffset size, SAOffset nmemb, SAFile file); - SAOffset (*FWrite)(void *p, SAOffset size, SAOffset nmemb, SAFile file); + SAOffset (*FWrite)(const void *p, SAOffset size, SAOffset nmemb, + SAFile file); SAOffset (*FSeek)(SAFile file, SAOffset offset, int whence); SAOffset (*FTell)(SAFile file); int (*FFlush)(SAFile file); int (*FClose)(SAFile file); - int (*Remove)(const char *filename); + int (*Remove)(const char *filename, void *pvUserData); void (*Error)(const char *message); double (*Atof)(const char *str); + void *pvUserData; } SAHooks; void SHPAPI_CALL SASetupDefaultHooks(SAHooks *psHooks); @@ -206,6 +189,12 @@ typedef struct { typedef SHPInfo *SHPHandle; +typedef struct { + int year; + int month; + int day; +} SHPDate; + /* -------------------------------------------------------------------- */ /* Shape types (nSHPType) */ /* -------------------------------------------------------------------- */ @@ -277,13 +266,13 @@ struct tagSHPObject { /* will be NULL as it is not necessary to keep the SHX file open */ SHPHandle SHPAPI_CALL SHPOpen(const char *pszShapeFile, const char *pszAccess); SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszShapeFile, const char *pszAccess, - SAHooks *psHooks); + const SAHooks *psHooks); SHPHandle SHPAPI_CALL SHPOpenLLEx(const char *pszShapeFile, - const char *pszAccess, SAHooks *psHooks, + const char *pszAccess, const SAHooks *psHooks, int bRestoreSHX); int SHPAPI_CALL SHPRestoreSHX(const char *pszShapeFile, const char *pszAccess, - SAHooks *psHooks); + const SAHooks *psHooks); /* If setting bFastMode = TRUE, the content of SHPReadObject() is owned by the * SHPHandle. */ @@ -296,12 +285,14 @@ void SHPAPI_CALL SHPSetFastModeReadObject(SHPHandle hSHP, int bFastMode); SHPHandle SHPAPI_CALL SHPCreate(const char *pszShapeFile, int nShapeType); SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszShapeFile, int nShapeType, - SAHooks *psHooks); -void SHPAPI_CALL SHPGetInfo(SHPHandle hSHP, int *pnEntities, int *pnShapeType, - double *padfMinBound, double *padfMaxBound); + const SAHooks *psHooks); +void SHPAPI_CALL SHPGetInfo(const SHPHandle hSHP, int *pnEntities, + int *pnShapeType, double *padfMinBound, + double *padfMaxBound); -SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle hSHP, int iShape); -int SHPAPI_CALL SHPWriteObject(SHPHandle hSHP, int iShape, SHPObject *psObject); +SHPObject SHPAPI_CALL1(*) SHPReadObject(const SHPHandle hSHP, int iShape); +int SHPAPI_CALL SHPWriteObject(SHPHandle hSHP, int iShape, + const SHPObject *psObject); void SHPAPI_CALL SHPDestroyObject(SHPObject *psObject); void SHPAPI_CALL SHPComputeExtents(SHPObject *psObject); @@ -314,7 +305,7 @@ SHPObject SHPAPI_CALL1(*) SHPCreateSimpleObject(int nSHPType, int nVertices, const double *padfX, const double *padfY, const double *padfZ); -int SHPAPI_CALL SHPRewindObject(SHPHandle hSHP, SHPObject *psObject); +int SHPAPI_CALL SHPRewindObject(const SHPHandle hSHP, SHPObject *psObject); void SHPAPI_CALL SHPClose(SHPHandle hSHP); void SHPAPI_CALL SHPWriteHeader(SHPHandle hSHP); @@ -360,21 +351,20 @@ typedef struct { SHPTree SHPAPI_CALL1(*) SHPCreateTree(SHPHandle hSHP, int nDimension, int nMaxDepth, - double *padfBoundsMin, double *padfBoundsMax); + const double *padfBoundsMin, const double *padfBoundsMax); void SHPAPI_CALL SHPDestroyTree(SHPTree *hTree); int SHPAPI_CALL SHPWriteTree(SHPTree *hTree, const char *pszFilename); int SHPAPI_CALL SHPTreeAddShapeId(SHPTree *hTree, SHPObject *psObject); -int SHPAPI_CALL SHPTreeRemoveShapeId(SHPTree *hTree, int nShapeId); void SHPAPI_CALL SHPTreeTrimExtraNodes(SHPTree *hTree); int SHPAPI_CALL1(*) - SHPTreeFindLikelyShapes(SHPTree *hTree, double *padfBoundsMin, + SHPTreeFindLikelyShapes(const SHPTree *hTree, double *padfBoundsMin, double *padfBoundsMax, int *); -int SHPAPI_CALL SHPCheckBoundsOverlap(double *, double *, double *, double *, - int); +int SHPAPI_CALL SHPCheckBoundsOverlap(const double *, const double *, + const double *, const double *, int); int SHPAPI_CALL1(*) SHPSearchDiskTree(FILE *fp, double *padfBoundsMin, double *padfBoundsMax, int *pnShapeCount); @@ -382,16 +372,17 @@ int SHPAPI_CALL1(*) SHPSearchDiskTree(FILE *fp, double *padfBoundsMin, typedef struct SHPDiskTreeInfo *SHPTreeDiskHandle; SHPTreeDiskHandle SHPAPI_CALL SHPOpenDiskTree(const char *pszQIXFilename, - SAHooks *psHooks); + const SAHooks *psHooks); void SHPAPI_CALL SHPCloseDiskTree(SHPTreeDiskHandle hDiskTree); int SHPAPI_CALL1(*) - SHPSearchDiskTreeEx(SHPTreeDiskHandle hDiskTree, double *padfBoundsMin, - double *padfBoundsMax, int *pnShapeCount); + SHPSearchDiskTreeEx(const SHPTreeDiskHandle hDiskTree, + double *padfBoundsMin, double *padfBoundsMax, + int *pnShapeCount); int SHPAPI_CALL SHPWriteTreeLL(SHPTree *hTree, const char *pszFilename, - SAHooks *psHooks); + const SAHooks *psHooks); /* -------------------------------------------------------------------- */ /* SBN Search API */ @@ -400,16 +391,16 @@ int SHPAPI_CALL SHPWriteTreeLL(SHPTree *hTree, const char *pszFilename, typedef struct SBNSearchInfo *SBNSearchHandle; SBNSearchHandle SHPAPI_CALL SBNOpenDiskTree(const char *pszSBNFilename, - SAHooks *psHooks); + const SAHooks *psHooks); void SHPAPI_CALL SBNCloseDiskTree(SBNSearchHandle hSBN); int SHPAPI_CALL1(*) - SBNSearchDiskTree(SBNSearchHandle hSBN, double *padfBoundsMin, - double *padfBoundsMax, int *pnShapeCount); + SBNSearchDiskTree(const SBNSearchHandle hSBN, const double *padfBoundsMin, + const double *padfBoundsMax, int *pnShapeCount); int SHPAPI_CALL1(*) - SBNSearchDiskTreeInteger(SBNSearchHandle hSBN, int bMinX, int bMinY, + SBNSearchDiskTreeInteger(const SBNSearchHandle hSBN, int bMinX, int bMinY, int bMaxX, int bMaxY, int *pnShapeCount); void SHPAPI_CALL SBNSearchFreeIds(int *panShapeId); @@ -485,15 +476,16 @@ typedef enum { DBFHandle SHPAPI_CALL DBFOpen(const char *pszDBFFile, const char *pszAccess); DBFHandle SHPAPI_CALL DBFOpenLL(const char *pszDBFFile, const char *pszAccess, - SAHooks *psHooks); + const SAHooks *psHooks); DBFHandle SHPAPI_CALL DBFCreate(const char *pszDBFFile); DBFHandle SHPAPI_CALL DBFCreateEx(const char *pszDBFFile, const char *pszCodePage); DBFHandle SHPAPI_CALL DBFCreateLL(const char *pszDBFFile, - const char *pszCodePage, SAHooks *psHooks); + const char *pszCodePage, + const SAHooks *psHooks); -int SHPAPI_CALL DBFGetFieldCount(DBFHandle psDBF); -int SHPAPI_CALL DBFGetRecordCount(DBFHandle psDBF); +int SHPAPI_CALL DBFGetFieldCount(const DBFHandle psDBF); +int SHPAPI_CALL DBFGetRecordCount(const DBFHandle psDBF); int SHPAPI_CALL DBFAddField(DBFHandle hDBF, const char *pszFieldName, DBFFieldType eType, int nWidth, int nDecimals); @@ -502,17 +494,18 @@ int SHPAPI_CALL DBFAddNativeFieldType(DBFHandle hDBF, const char *pszFieldName, int SHPAPI_CALL DBFDeleteField(DBFHandle hDBF, int iField); -int SHPAPI_CALL DBFReorderFields(DBFHandle psDBF, int *panMap); +int SHPAPI_CALL DBFReorderFields(DBFHandle psDBF, const int *panMap); int SHPAPI_CALL DBFAlterFieldDefn(DBFHandle psDBF, int iField, const char *pszFieldName, char chType, int nWidth, int nDecimals); -DBFFieldType SHPAPI_CALL DBFGetFieldInfo(DBFHandle psDBF, int iField, +DBFFieldType SHPAPI_CALL DBFGetFieldInfo(const DBFHandle psDBF, int iField, char *pszFieldName, int *pnWidth, int *pnDecimals); -int SHPAPI_CALL DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName); +int SHPAPI_CALL DBFGetFieldIndex(const DBFHandle psDBF, + const char *pszFieldName); int SHPAPI_CALL DBFReadIntegerAttribute(DBFHandle hDBF, int iShape, int iField); double SHPAPI_CALL DBFReadDoubleAttribute(DBFHandle hDBF, int iShape, @@ -521,7 +514,10 @@ const char SHPAPI_CALL1(*) DBFReadStringAttribute(DBFHandle hDBF, int iShape, int iField); const char SHPAPI_CALL1(*) DBFReadLogicalAttribute(DBFHandle hDBF, int iShape, int iField); -int SHPAPI_CALL DBFIsAttributeNULL(DBFHandle hDBF, int iShape, int iField); +SHPDate SHPAPI_CALL DBFReadDateAttribute(DBFHandle hDBF, int iShape, + int iField); +int SHPAPI_CALL DBFIsAttributeNULL(const DBFHandle hDBF, int iShape, + int iField); int SHPAPI_CALL DBFWriteIntegerAttribute(DBFHandle hDBF, int iShape, int iField, int nFieldValue); @@ -533,22 +529,26 @@ int SHPAPI_CALL DBFWriteNULLAttribute(DBFHandle hDBF, int iShape, int iField); int SHPAPI_CALL DBFWriteLogicalAttribute(DBFHandle hDBF, int iShape, int iField, const char lFieldValue); +int SHPAPI_CALL DBFWriteDateAttribute(DBFHandle hDBF, int iShape, int iField, + const SHPDate *dateFieldValue); int SHPAPI_CALL DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, - int iField, void *pValue); + int iField, const void *pValue); const char SHPAPI_CALL1(*) DBFReadTuple(DBFHandle psDBF, int hEntity); -int SHPAPI_CALL DBFWriteTuple(DBFHandle psDBF, int hEntity, void *pRawTuple); +int SHPAPI_CALL DBFWriteTuple(DBFHandle psDBF, int hEntity, + const void *pRawTuple); -int SHPAPI_CALL DBFIsRecordDeleted(DBFHandle psDBF, int iShape); +int SHPAPI_CALL DBFIsRecordDeleted(const DBFHandle psDBF, int iShape); int SHPAPI_CALL DBFMarkRecordDeleted(DBFHandle psDBF, int iShape, int bIsDeleted); -DBFHandle SHPAPI_CALL DBFCloneEmpty(DBFHandle psDBF, const char *pszFilename); +DBFHandle SHPAPI_CALL DBFCloneEmpty(const DBFHandle psDBF, + const char *pszFilename); void SHPAPI_CALL DBFClose(DBFHandle hDBF); void SHPAPI_CALL DBFUpdateHeader(DBFHandle hDBF); -char SHPAPI_CALL DBFGetNativeFieldType(DBFHandle hDBF, int iField); +char SHPAPI_CALL DBFGetNativeFieldType(const DBFHandle hDBF, int iField); -const char SHPAPI_CALL1(*) DBFGetCodePage(DBFHandle psDBF); +const char SHPAPI_CALL1(*) DBFGetCodePage(const DBFHandle psDBF); void SHPAPI_CALL DBFSetLastModifiedDate(DBFHandle psDBF, int nYYSince1900, int nMM, int nDD); diff --git a/lib/external/shapelib/shapefil_private.h b/lib/external/shapelib/shapefil_private.h new file mode 100644 index 00000000000..1bed49e7cce --- /dev/null +++ b/lib/external/shapelib/shapefil_private.h @@ -0,0 +1,115 @@ +#ifndef SHAPEFILE_PRIVATE_H_INCLUDED +#define SHAPEFILE_PRIVATE_H_INCLUDED + +/****************************************************************************** + * + * Project: Shapelib + * Purpose: Private include file for Shapelib. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 1999, Frank Warmerdam + * Copyright (c) 2012-2016, Even Rouault + * + * SPDX-License-Identifier: MIT OR LGPL-2.0-or-later + ****************************************************************************** + * + */ + +#ifdef __cplusplus +#define STATIC_CAST(type, x) static_cast(x) +#define REINTERPRET_CAST(type, x) reinterpret_cast(x) +#define CONST_CAST(type, x) const_cast(x) +#define SHPLIB_NULLPTR nullptr +#else +#define STATIC_CAST(type, x) ((type)(x)) +#define REINTERPRET_CAST(type, x) ((type)(x)) +#define CONST_CAST(type, x) ((type)(x)) +#define SHPLIB_NULLPTR NULL +#endif + +#if !defined(SHP_BIG_ENDIAN) +#if defined(CPL_MSB) +#define SHP_BIG_ENDIAN 1 +#elif (defined(__GNUC__) && __GNUC__ >= 5) || \ + (defined(__GNUC__) && defined(__GNUC_MINOR__) && __GNUC__ == 4 && \ + __GNUC_MINOR__ >= 6) +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define SHP_BIG_ENDIAN 1 +#endif +#elif defined(__GLIBC__) +#if __BYTE_ORDER == __BIG_ENDIAN +#define SHP_BIG_ENDIAN 1 +#endif +#elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) +#define SHP_BIG_ENDIAN 1 +#elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) +#elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || \ + defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || \ + defined(_MIPSEB) || defined(_POWER) || defined(__s390__) +#define SHP_BIG_ENDIAN 1 +#endif +#endif + +#include "shapefil.h" +#include +#include + +/************************************************************************/ +/* Little endian <==> big endian byte swap macros. */ +/************************************************************************/ + +#if (defined(__GNUC__) && __GNUC__ >= 5) || \ + (defined(__GNUC__) && defined(__GNUC_MINOR__) && __GNUC__ == 4 && \ + __GNUC_MINOR__ >= 8) +#define _SHP_SWAP32(x) \ + STATIC_CAST(uint32_t, __builtin_bswap32(STATIC_CAST(uint32_t, x))) +#define _SHP_SWAP64(x) \ + STATIC_CAST(uint64_t, __builtin_bswap64(STATIC_CAST(uint64_t, x))) +#elif defined(_MSC_VER) +#define _SHP_SWAP32(x) \ + STATIC_CAST(uint32_t, _byteswap_ulong(STATIC_CAST(uint32_t, x))) +#define _SHP_SWAP64(x) \ + STATIC_CAST(uint64_t, _byteswap_uint64(STATIC_CAST(uint64_t, x))) +#else +#define _SHP_SWAP32(x) \ + STATIC_CAST(uint32_t, \ + ((STATIC_CAST(uint32_t, x) & 0x000000ffU) << 24) | \ + ((STATIC_CAST(uint32_t, x) & 0x0000ff00U) << 8) | \ + ((STATIC_CAST(uint32_t, x) & 0x00ff0000U) >> 8) | \ + ((STATIC_CAST(uint32_t, x) & 0xff000000U) >> 24)) +#define _SHP_SWAP64(x) \ + ((STATIC_CAST(uint64_t, _SHP_SWAP32(STATIC_CAST(uint32_t, x))) << 32) | \ + (STATIC_CAST(uint64_t, _SHP_SWAP32(STATIC_CAST( \ + uint32_t, STATIC_CAST(uint64_t, x) >> 32))))) + +#endif + +/* in-place uint32_t* swap */ +#define SHP_SWAP32(p) \ + *REINTERPRET_CAST(uint32_t *, p) = \ + _SHP_SWAP32(*REINTERPRET_CAST(uint32_t *, p)) +/* in-place uint64_t* swap */ +#define SHP_SWAP64(p) \ + *REINTERPRET_CAST(uint64_t *, p) = \ + _SHP_SWAP64(*REINTERPRET_CAST(uint64_t *, p)) +/* in-place double* swap */ +#define SHP_SWAPDOUBLE(x) \ + do { \ + uint64_t _n64; \ + void *_lx = x; \ + memcpy(&_n64, _lx, 8); \ + _n64 = _SHP_SWAP64(_n64); \ + memcpy(_lx, &_n64, 8); \ + } while (0) +/* copy double* swap*/ +#define SHP_SWAPDOUBLE_CPY(dst, src) \ + do { \ + uint64_t _n64; \ + const void *_ls = src; \ + void *_ld = dst; \ + memcpy(&_n64, _ls, 8); \ + _n64 = _SHP_SWAP64(_n64); \ + memcpy(_ld, &_n64, 8); \ + } while (0) +#endif /* ndef SHAPEFILE_PRIVATE_H_INCLUDED */ diff --git a/lib/external/shapelib/shpopen.c b/lib/external/shapelib/shpopen.c index e63cf768d25..b2eeb3614fb 100644 --- a/lib/external/shapelib/shpopen.c +++ b/lib/external/shapelib/shpopen.c @@ -8,52 +8,21 @@ * Copyright (c) 1999, 2001, Frank Warmerdam * Copyright (c) 2011-2019, Even Rouault * - * This software is available under the following "MIT Style" license, - * or at the option of the licensee under the LGPL (see COPYING). This - * option is discussed in more detail in shapelib.html. - * - * -- - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * SPDX-License-Identifier: MIT OR LGPL-2.0-or-later ******************************************************************************/ -#include "shapefil.h" +#include "shapefil_private.h" #include #include #include #include #include +#include #include #include #include -SHP_CVSID("$Id$") - -typedef unsigned char uchar; - -#if UINT_MAX == 65535 -typedef unsigned long int32; -#else -typedef unsigned int int32; -#endif - #ifndef FALSE #define FALSE 0 #define TRUE 1 @@ -70,73 +39,18 @@ typedef unsigned int int32; #if _MSC_VER < 1900 #define snprintf _snprintf #endif -#elif defined(WIN32) || defined(_WIN32) +#elif defined(_WIN32) #ifndef snprintf #define snprintf _snprintf #endif #endif #endif -#ifndef CPL_UNUSED -#if defined(__GNUC__) && __GNUC__ >= 4 -#define CPL_UNUSED __attribute((__unused__)) -#else -#define CPL_UNUSED -#endif -#endif - -#if defined(CPL_LSB) -#define bBigEndian false -#elif defined(CPL_MSB) -#define bBigEndian true -#else -static bool bBigEndian; -#endif - -#ifdef __cplusplus -#define STATIC_CAST(type, x) static_cast(x) -#define SHPLIB_NULLPTR nullptr -#else -#define STATIC_CAST(type, x) ((type)(x)) -#define SHPLIB_NULLPTR NULL -#endif - -/************************************************************************/ -/* SwapWord() */ -/* */ -/* Swap a 2, 4 or 8 byte word. */ -/************************************************************************/ - -static void SwapWord(int length, void *wordP) -{ - for (int i = 0; i < length / 2; i++) { - const uchar temp = STATIC_CAST(uchar *, wordP)[i]; - STATIC_CAST(uchar *, wordP) - [i] = STATIC_CAST(uchar *, wordP)[length - i - 1]; - STATIC_CAST(uchar *, wordP)[length - i - 1] = temp; - } -} - -/************************************************************************/ -/* SfRealloc() */ -/* */ -/* A realloc cover function that will access a NULL pointer as */ -/* a valid input. */ -/************************************************************************/ - -static void *SfRealloc(void *pMem, int nNewSize) -{ - if (pMem == SHPLIB_NULLPTR) - return malloc(nNewSize); - else - return realloc(pMem, nNewSize); -} - /************************************************************************/ /* SHPWriteHeader() */ /* */ -/* Write out a header for the .shp and .shx files as well as the */ -/* contents of the index (.shx) file. */ +/* Write out a header for the .shp and .shx files as well as the */ +/* contents of the index (.shx) file. */ /************************************************************************/ void SHPAPI_CALL SHPWriteHeader(SHPHandle psSHP) @@ -150,64 +64,73 @@ void SHPAPI_CALL SHPWriteHeader(SHPHandle psSHP) /* Prepare header block for .shp file. */ /* -------------------------------------------------------------------- */ - uchar abyHeader[100] = {0}; + unsigned char abyHeader[100] = {0}; abyHeader[2] = 0x27; /* magic cookie */ abyHeader[3] = 0x0a; - int32 i32 = psSHP->nFileSize / 2; /* file size */ + uint32_t i32 = psSHP->nFileSize / 2; /* file size */ ByteCopy(&i32, abyHeader + 24, 4); - if (!bBigEndian) - SwapWord(4, abyHeader + 24); +#if !defined(SHP_BIG_ENDIAN) + SHP_SWAP32(abyHeader + 24); +#endif i32 = 1000; /* version */ ByteCopy(&i32, abyHeader + 28, 4); - if (bBigEndian) - SwapWord(4, abyHeader + 28); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP32(abyHeader + 28); +#endif i32 = psSHP->nShapeType; /* shape type */ ByteCopy(&i32, abyHeader + 32, 4); - if (bBigEndian) - SwapWord(4, abyHeader + 32); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP32(abyHeader + 32); +#endif double dValue = psSHP->adBoundsMin[0]; /* set bounds */ ByteCopy(&dValue, abyHeader + 36, 8); - if (bBigEndian) - SwapWord(8, abyHeader + 36); - +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(abyHeader + 36); +#endif dValue = psSHP->adBoundsMin[1]; ByteCopy(&dValue, abyHeader + 44, 8); - if (bBigEndian) - SwapWord(8, abyHeader + 44); - +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(abyHeader + 44); +#endif dValue = psSHP->adBoundsMax[0]; ByteCopy(&dValue, abyHeader + 52, 8); - if (bBigEndian) - SwapWord(8, abyHeader + 52); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(abyHeader + 52); +#endif dValue = psSHP->adBoundsMax[1]; ByteCopy(&dValue, abyHeader + 60, 8); - if (bBigEndian) - SwapWord(8, abyHeader + 60); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(abyHeader + 60); +#endif dValue = psSHP->adBoundsMin[2]; /* z */ ByteCopy(&dValue, abyHeader + 68, 8); - if (bBigEndian) - SwapWord(8, abyHeader + 68); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(abyHeader + 68); +#endif dValue = psSHP->adBoundsMax[2]; ByteCopy(&dValue, abyHeader + 76, 8); - if (bBigEndian) - SwapWord(8, abyHeader + 76); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(abyHeader + 76); +#endif dValue = psSHP->adBoundsMin[3]; /* m */ ByteCopy(&dValue, abyHeader + 84, 8); - if (bBigEndian) - SwapWord(8, abyHeader + 84); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(abyHeader + 84); +#endif dValue = psSHP->adBoundsMax[3]; ByteCopy(&dValue, abyHeader + 92, 8); - if (bBigEndian) - SwapWord(8, abyHeader + 92); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(abyHeader + 92); +#endif /* -------------------------------------------------------------------- */ /* Write .shp file header. */ @@ -226,10 +149,11 @@ void SHPAPI_CALL SHPWriteHeader(SHPHandle psSHP) /* -------------------------------------------------------------------- */ /* Prepare, and write .shx file header. */ /* -------------------------------------------------------------------- */ - i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100) / 2; /* file size */ + i32 = (psSHP->nRecords * 2 * sizeof(uint32_t) + 100) / 2; /* file size */ ByteCopy(&i32, abyHeader + 24, 4); - if (!bBigEndian) - SwapWord(4, abyHeader + 24); +#if !defined(SHP_BIG_ENDIAN) + SHP_SWAP32(abyHeader + 24); +#endif if (psSHP->sHooks.FSeek(psSHP->fpSHX, 0, 0) != 0 || psSHP->sHooks.FWrite(abyHeader, 100, 1, psSHP->fpSHX) != 1) { @@ -246,8 +170,8 @@ void SHPAPI_CALL SHPWriteHeader(SHPHandle psSHP) /* -------------------------------------------------------------------- */ /* Write out the .shx contents. */ /* -------------------------------------------------------------------- */ - int32 *panSHX = - STATIC_CAST(int32 *, malloc(sizeof(int32) * 2 * psSHP->nRecords)); + uint32_t *panSHX = + STATIC_CAST(uint32_t *, malloc(sizeof(uint32_t) * 2 * psSHP->nRecords)); if (panSHX == SHPLIB_NULLPTR) { psSHP->sHooks.Error("Failure allocatin panSHX"); return; @@ -256,13 +180,13 @@ void SHPAPI_CALL SHPWriteHeader(SHPHandle psSHP) for (int i = 0; i < psSHP->nRecords; i++) { panSHX[i * 2] = psSHP->panRecOffset[i] / 2; panSHX[i * 2 + 1] = psSHP->panRecSize[i] / 2; - if (!bBigEndian) - SwapWord(4, panSHX + i * 2); - if (!bBigEndian) - SwapWord(4, panSHX + i * 2 + 1); +#if !defined(SHP_BIG_ENDIAN) + SHP_SWAP32(panSHX + i * 2); + SHP_SWAP32(panSHX + i * 2 + 1); +#endif } - if (STATIC_CAST(int, psSHP->sHooks.FWrite(panSHX, sizeof(int32) * 2, + if (STATIC_CAST(int, psSHP->sHooks.FWrite(panSHX, sizeof(uint32_t) * 2, psSHP->nRecords, psSHP->fpSHX)) != psSHP->nRecords) { char szErrorMsg[200]; @@ -319,7 +243,7 @@ static int SHPGetLenWithoutExtension(const char *pszBasename) /************************************************************************/ SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszLayer, const char *pszAccess, - SAHooks *psHooks) + const SAHooks *psHooks) { /* -------------------------------------------------------------------- */ /* Ensure the access string is one of the legal ones. We */ @@ -336,23 +260,10 @@ SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszLayer, const char *pszAccess, pszAccess = "rb"; } -/* -------------------------------------------------------------------- */ -/* Establish the byte order on this machine. */ -/* -------------------------------------------------------------------- */ -#if !defined(bBigEndian) - { - int i = 1; - if (*((uchar *)&i) == 1) - bBigEndian = false; - else - bBigEndian = true; - } -#endif - /* -------------------------------------------------------------------- */ /* Initialize the info structure. */ /* -------------------------------------------------------------------- */ - SHPHandle psSHP = STATIC_CAST(SHPHandle, calloc(sizeof(SHPInfo), 1)); + SHPHandle psSHP = STATIC_CAST(SHPHandle, calloc(1, sizeof(SHPInfo))); psSHP->bUpdated = FALSE; memcpy(&(psSHP->sHooks), psHooks, sizeof(SAHooks)); @@ -365,18 +276,21 @@ SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszLayer, const char *pszAccess, char *pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5)); memcpy(pszFullname, pszLayer, nLenWithoutExtension); memcpy(pszFullname + nLenWithoutExtension, ".shp", 5); - psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess); + psSHP->fpSHP = + psSHP->sHooks.FOpen(pszFullname, pszAccess, psSHP->sHooks.pvUserData); if (psSHP->fpSHP == SHPLIB_NULLPTR) { memcpy(pszFullname + nLenWithoutExtension, ".SHP", 5); - psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess); + psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess, + psSHP->sHooks.pvUserData); } if (psSHP->fpSHP == SHPLIB_NULLPTR) { const size_t nMessageLen = strlen(pszFullname) * 2 + 256; char *pszMessage = STATIC_CAST(char *, malloc(nMessageLen)); pszFullname[nLenWithoutExtension] = 0; - snprintf(pszMessage, nMessageLen, "Unable to open %s.shp or %s.SHP.", - pszFullname, pszFullname); + snprintf(pszMessage, nMessageLen, + "Unable to open %s.shp or %s.SHP in %s mode.", pszFullname, + pszFullname, pszAccess); psHooks->Error(pszMessage); free(pszMessage); @@ -387,10 +301,12 @@ SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszLayer, const char *pszAccess, } memcpy(pszFullname + nLenWithoutExtension, ".shx", 5); - psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess); + psSHP->fpSHX = + psSHP->sHooks.FOpen(pszFullname, pszAccess, psSHP->sHooks.pvUserData); if (psSHP->fpSHX == SHPLIB_NULLPTR) { memcpy(pszFullname + nLenWithoutExtension, ".SHX", 5); - psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess); + psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess, + psSHP->sHooks.pvUserData); } if (psSHP->fpSHX == SHPLIB_NULLPTR) { @@ -416,7 +332,7 @@ SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszLayer, const char *pszAccess, /* -------------------------------------------------------------------- */ /* Read the file size from the SHP file. */ /* -------------------------------------------------------------------- */ - uchar *pabyBuf = STATIC_CAST(uchar *, malloc(100)); + unsigned char *pabyBuf = STATIC_CAST(unsigned char *, malloc(100)); if (psSHP->sHooks.FRead(pabyBuf, 100, 1, psSHP->fpSHP) != 1) { psSHP->sHooks.Error(".shp file is unreadable, or corrupt."); psSHP->sHooks.FClose(psSHP->fpSHP); @@ -489,43 +405,51 @@ SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszLayer, const char *pszAccess, /* -------------------------------------------------------------------- */ double dValue; - if (bBigEndian) - SwapWord(8, pabyBuf + 36); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyBuf + 36); +#endif memcpy(&dValue, pabyBuf + 36, 8); psSHP->adBoundsMin[0] = dValue; - if (bBigEndian) - SwapWord(8, pabyBuf + 44); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyBuf + 44); +#endif memcpy(&dValue, pabyBuf + 44, 8); psSHP->adBoundsMin[1] = dValue; - if (bBigEndian) - SwapWord(8, pabyBuf + 52); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyBuf + 52); +#endif memcpy(&dValue, pabyBuf + 52, 8); psSHP->adBoundsMax[0] = dValue; - if (bBigEndian) - SwapWord(8, pabyBuf + 60); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyBuf + 60); +#endif memcpy(&dValue, pabyBuf + 60, 8); psSHP->adBoundsMax[1] = dValue; - if (bBigEndian) - SwapWord(8, pabyBuf + 68); /* z */ +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyBuf + 68); /* z */ +#endif memcpy(&dValue, pabyBuf + 68, 8); psSHP->adBoundsMin[2] = dValue; - if (bBigEndian) - SwapWord(8, pabyBuf + 76); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyBuf + 76); +#endif memcpy(&dValue, pabyBuf + 76, 8); psSHP->adBoundsMax[2] = dValue; - if (bBigEndian) - SwapWord(8, pabyBuf + 84); /* z */ +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyBuf + 84); /* z */ +#endif memcpy(&dValue, pabyBuf + 84, 8); psSHP->adBoundsMin[3] = dValue; - if (bBigEndian) - SwapWord(8, pabyBuf + 92); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyBuf + 92); +#endif memcpy(&dValue, pabyBuf + 92, 8); psSHP->adBoundsMax[3] = dValue; @@ -546,7 +470,8 @@ SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszLayer, const char *pszAccess, if (bLazySHXLoading) pabyBuf = SHPLIB_NULLPTR; else - pabyBuf = STATIC_CAST(uchar *, malloc(8 * MAX(1, psSHP->nRecords))); + pabyBuf = + STATIC_CAST(unsigned char *, malloc(8 * MAX(1, psSHP->nRecords))); if (psSHP->panRecOffset == SHPLIB_NULLPTR || psSHP->panRecSize == SHPLIB_NULLPTR || @@ -612,13 +537,15 @@ SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszLayer, const char *pszAccess, for (int i = 0; i < psSHP->nRecords; i++) { unsigned int nOffset; memcpy(&nOffset, pabyBuf + i * 8, 4); - if (!bBigEndian) - SwapWord(4, &nOffset); +#if !defined(SHP_BIG_ENDIAN) + SHP_SWAP32(&nOffset); +#endif unsigned int nLength; memcpy(&nLength, pabyBuf + i * 8 + 4, 4); - if (!bBigEndian) - SwapWord(4, &nLength); +#if !defined(SHP_BIG_ENDIAN) + SHP_SWAP32(&nLength); +#endif if (nOffset > STATIC_CAST(unsigned int, INT_MAX)) { char str[128]; @@ -657,7 +584,7 @@ SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszLayer, const char *pszAccess, /************************************************************************/ SHPHandle SHPAPI_CALL SHPOpenLLEx(const char *pszLayer, const char *pszAccess, - SAHooks *psHooks, int bRestoreSHX) + const SAHooks *psHooks, int bRestoreSHX) { if (!bRestoreSHX) return SHPOpenLL(pszLayer, pszAccess, psHooks); @@ -678,7 +605,7 @@ SHPHandle SHPAPI_CALL SHPOpenLLEx(const char *pszLayer, const char *pszAccess, /************************************************************************/ int SHPAPI_CALL SHPRestoreSHX(const char *pszLayer, const char *pszAccess, - SAHooks *psHooks) + const SAHooks *psHooks) { /* -------------------------------------------------------------------- */ /* Ensure the access string is one of the legal ones. We */ @@ -693,19 +620,6 @@ int SHPAPI_CALL SHPRestoreSHX(const char *pszLayer, const char *pszAccess, pszAccess = "rb"; } -/* -------------------------------------------------------------------- */ -/* Establish the byte order on this machine. */ -/* -------------------------------------------------------------------- */ -#if !defined(bBigEndian) - { - int i = 1; - if (*((uchar *)&i) == 1) - bBigEndian = false; - else - bBigEndian = true; - } -#endif - /* -------------------------------------------------------------------- */ /* Open the .shp file. Note that files pulled from */ /* a PC to Unix with upper case filenames won't work! */ @@ -714,10 +628,10 @@ int SHPAPI_CALL SHPRestoreSHX(const char *pszLayer, const char *pszAccess, char *pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5)); memcpy(pszFullname, pszLayer, nLenWithoutExtension); memcpy(pszFullname + nLenWithoutExtension, ".shp", 5); - SAFile fpSHP = psHooks->FOpen(pszFullname, pszAccess); + SAFile fpSHP = psHooks->FOpen(pszFullname, pszAccess, psHooks->pvUserData); if (fpSHP == SHPLIB_NULLPTR) { memcpy(pszFullname + nLenWithoutExtension, ".SHP", 5); - fpSHP = psHooks->FOpen(pszFullname, pszAccess); + fpSHP = psHooks->FOpen(pszFullname, pszAccess, psHooks->pvUserData); } if (fpSHP == SHPLIB_NULLPTR) { @@ -738,7 +652,7 @@ int SHPAPI_CALL SHPRestoreSHX(const char *pszLayer, const char *pszAccess, /* -------------------------------------------------------------------- */ /* Read the file size from the SHP file. */ /* -------------------------------------------------------------------- */ - uchar *pabyBuf = STATIC_CAST(uchar *, malloc(100)); + unsigned char *pabyBuf = STATIC_CAST(unsigned char *, malloc(100)); if (psHooks->FRead(pabyBuf, 100, 1, fpSHP) != 1) { psHooks->Error(".shp file is unreadable, or corrupt."); psHooks->FClose(fpSHP); @@ -759,7 +673,8 @@ int SHPAPI_CALL SHPRestoreSHX(const char *pszLayer, const char *pszAccess, memcpy(pszFullname + nLenWithoutExtension, ".shx", 5); const char pszSHXAccess[] = "w+b"; - SAFile fpSHX = psHooks->FOpen(pszFullname, pszSHXAccess); + SAFile fpSHX = + psHooks->FOpen(pszFullname, pszSHXAccess, psHooks->pvUserData); if (fpSHX == SHPLIB_NULLPTR) { size_t nMessageLen = strlen(pszFullname) * 2 + 256; char *pszMessage = STATIC_CAST(char *, malloc(nMessageLen)); @@ -789,25 +704,70 @@ int SHPAPI_CALL SHPRestoreSHX(const char *pszLayer, const char *pszAccess, // unsigned int nCurrentRecordOffset = 0; unsigned int nCurrentSHPOffset = 100; unsigned int nRealSHXContentSize = 100; - unsigned int niRecord = 0; - unsigned int nRecordLength = 0; + int nRetCode = TRUE; unsigned int nRecordOffset = 50; - char abyReadRecord[8]; while (nCurrentSHPOffset < nSHPFilesize) { + unsigned int niRecord = 0; + unsigned int nRecordLength = 0; + int nSHPType; + if (psHooks->FRead(&niRecord, 4, 1, fpSHP) == 1 && - psHooks->FRead(&nRecordLength, 4, 1, fpSHP) == 1) { - if (!bBigEndian) - SwapWord(4, &nRecordOffset); - memcpy(abyReadRecord, &nRecordOffset, 4); + psHooks->FRead(&nRecordLength, 4, 1, fpSHP) == 1 && + psHooks->FRead(&nSHPType, 4, 1, fpSHP) == 1) { + char abyReadRecord[8]; + unsigned int nRecordOffsetBE = nRecordOffset; + +#if !defined(SHP_BIG_ENDIAN) + SHP_SWAP32(&nRecordOffsetBE); +#endif + memcpy(abyReadRecord, &nRecordOffsetBE, 4); memcpy(abyReadRecord + 4, &nRecordLength, 4); +#if !defined(SHP_BIG_ENDIAN) + SHP_SWAP32(&nRecordLength); +#endif +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP32(&nSHPType); +#endif + + // Sanity check on record length + if (nRecordLength < 1 || + nRecordLength > (nSHPFilesize - (nCurrentSHPOffset + 8)) / 2) { + char szErrorMsg[200]; + snprintf(szErrorMsg, sizeof(szErrorMsg), + "Error parsing .shp to restore .shx. " + "Invalid record length = %u at record starting at " + "offset %u", + nRecordLength, nCurrentSHPOffset); + psHooks->Error(szErrorMsg); + + nRetCode = FALSE; + break; + } + + // Sanity check on record type + if (nSHPType != SHPT_NULL && nSHPType != SHPT_POINT && + nSHPType != SHPT_ARC && nSHPType != SHPT_POLYGON && + nSHPType != SHPT_MULTIPOINT && nSHPType != SHPT_POINTZ && + nSHPType != SHPT_ARCZ && nSHPType != SHPT_POLYGONZ && + nSHPType != SHPT_MULTIPOINTZ && nSHPType != SHPT_POINTM && + nSHPType != SHPT_ARCM && nSHPType != SHPT_POLYGONM && + nSHPType != SHPT_MULTIPOINTM && nSHPType != SHPT_MULTIPATCH) { + char szErrorMsg[200]; + snprintf(szErrorMsg, sizeof(szErrorMsg), + "Error parsing .shp to restore .shx. " + "Invalid shape type = %d at record starting at " + "offset %u", + nSHPType, nCurrentSHPOffset); + psHooks->Error(szErrorMsg); + + nRetCode = FALSE; + break; + } + psHooks->FWrite(abyReadRecord, 8, 1, fpSHX); - if (!bBigEndian) - SwapWord(4, &nRecordOffset); - if (!bBigEndian) - SwapWord(4, &nRecordLength); nRecordOffset += nRecordLength + 4; // nCurrentRecordOffset += 8; nCurrentSHPOffset += 8 + nRecordLength * 2; @@ -816,21 +776,30 @@ int SHPAPI_CALL SHPRestoreSHX(const char *pszLayer, const char *pszAccess, nRealSHXContentSize += 8; } else { - psHooks->Error("Error parsing .shp to restore .shx"); - - psHooks->FClose(fpSHX); - psHooks->FClose(fpSHP); - - free(pabySHXHeader); - free(pszFullname); + char szErrorMsg[200]; + snprintf(szErrorMsg, sizeof(szErrorMsg), + "Error parsing .shp to restore .shx. " + "Cannot read first bytes of record starting at " + "offset %u", + nCurrentSHPOffset); + psHooks->Error(szErrorMsg); - return (0); + nRetCode = FALSE; + break; } } + if (nRetCode && nCurrentSHPOffset != nSHPFilesize) { + psHooks->Error("Error parsing .shp to restore .shx. " + "Not expected number of bytes"); + + nRetCode = FALSE; + } nRealSHXContentSize /= 2; // Bytes counted -> WORDs - if (!bBigEndian) - SwapWord(4, &nRealSHXContentSize); +#if !defined(SHP_BIG_ENDIAN) + SHP_SWAP32(&nRealSHXContentSize); +#endif + psHooks->FSeek(fpSHX, 24, 0); psHooks->FWrite(&nRealSHXContentSize, 4, 1, fpSHX); @@ -840,13 +809,13 @@ int SHPAPI_CALL SHPRestoreSHX(const char *pszLayer, const char *pszAccess, free(pszFullname); free(pabySHXHeader); - return (1); + return nRetCode; } /************************************************************************/ /* SHPClose() */ -/* */ -/* Close the .shp and .shx files. */ +/* */ +/* Close the .shp and .shx files. */ /************************************************************************/ void SHPAPI_CALL SHPClose(SHPHandle psSHP) @@ -855,7 +824,7 @@ void SHPAPI_CALL SHPClose(SHPHandle psSHP) return; /* -------------------------------------------------------------------- */ - /* Update the header if we have modified anything. */ + /* Update the header if we have modified anything. */ /* -------------------------------------------------------------------- */ if (psSHP->bUpdated) SHPWriteHeader(psSHP); @@ -914,8 +883,9 @@ void SHPAPI_CALL SHPSetFastModeReadObject(SHPHandle hSHP, int bFastMode) /* Fetch general information about the shape file. */ /************************************************************************/ -void SHPAPI_CALL SHPGetInfo(SHPHandle psSHP, int *pnEntities, int *pnShapeType, - double *padfMinBound, double *padfMaxBound) +void SHPAPI_CALL SHPGetInfo(const SHPHandle psSHP, int *pnEntities, + int *pnShapeType, double *padfMinBound, + double *padfMaxBound) { if (psSHP == SHPLIB_NULLPTR) return; @@ -958,21 +928,8 @@ SHPHandle SHPAPI_CALL SHPCreate(const char *pszLayer, int nShapeType) /************************************************************************/ SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszLayer, int nShapeType, - SAHooks *psHooks) + const SAHooks *psHooks) { -/* -------------------------------------------------------------------- */ -/* Establish the byte order on this system. */ -/* -------------------------------------------------------------------- */ -#if !defined(bBigEndian) - { - int i = 1; - if (*((uchar *)&i) == 1) - bBigEndian = false; - else - bBigEndian = true; - } -#endif - /* -------------------------------------------------------------------- */ /* Open the two files so we can write their headers. */ /* -------------------------------------------------------------------- */ @@ -980,7 +937,7 @@ SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszLayer, int nShapeType, char *pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5)); memcpy(pszFullname, pszLayer, nLenWithoutExtension); memcpy(pszFullname + nLenWithoutExtension, ".shp", 5); - SAFile fpSHP = psHooks->FOpen(pszFullname, "wb"); + SAFile fpSHP = psHooks->FOpen(pszFullname, "w+b", psHooks->pvUserData); if (fpSHP == SHPLIB_NULLPTR) { char szErrorMsg[200]; snprintf(szErrorMsg, sizeof(szErrorMsg), "Failed to create file %s: %s", @@ -988,11 +945,11 @@ SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszLayer, int nShapeType, psHooks->Error(szErrorMsg); free(pszFullname); - return NULL; + return SHPLIB_NULLPTR; } memcpy(pszFullname + nLenWithoutExtension, ".shx", 5); - SAFile fpSHX = psHooks->FOpen(pszFullname, "wb"); + SAFile fpSHX = psHooks->FOpen(pszFullname, "w+b", psHooks->pvUserData); if (fpSHX == SHPLIB_NULLPTR) { char szErrorMsg[200]; snprintf(szErrorMsg, sizeof(szErrorMsg), "Failed to create file %s: %s", @@ -1001,7 +958,7 @@ SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszLayer, int nShapeType, free(pszFullname); psHooks->FClose(fpSHP); - return NULL; + return SHPLIB_NULLPTR; } free(pszFullname); @@ -1010,26 +967,29 @@ SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszLayer, int nShapeType, /* -------------------------------------------------------------------- */ /* Prepare header block for .shp file. */ /* -------------------------------------------------------------------- */ - uchar abyHeader[100]; + unsigned char abyHeader[100]; memset(abyHeader, 0, sizeof(abyHeader)); abyHeader[2] = 0x27; /* magic cookie */ abyHeader[3] = 0x0a; - int32 i32 = 50; /* file size */ + uint32_t i32 = 50; /* file size */ ByteCopy(&i32, abyHeader + 24, 4); - if (!bBigEndian) - SwapWord(4, abyHeader + 24); +#if !defined(SHP_BIG_ENDIAN) + SHP_SWAP32(abyHeader + 24); +#endif i32 = 1000; /* version */ ByteCopy(&i32, abyHeader + 28, 4); - if (bBigEndian) - SwapWord(4, abyHeader + 28); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP32(abyHeader + 28); +#endif i32 = nShapeType; /* shape type */ ByteCopy(&i32, abyHeader + 32, 4); - if (bBigEndian) - SwapWord(4, abyHeader + 32); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP32(abyHeader + 32); +#endif double dValue = 0.0; /* set bounds */ ByteCopy(&dValue, abyHeader + 36, 8); @@ -1051,7 +1011,7 @@ SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszLayer, int nShapeType, free(pszFullname); psHooks->FClose(fpSHP); psHooks->FClose(fpSHX); - return NULL; + return SHPLIB_NULLPTR; } /* -------------------------------------------------------------------- */ @@ -1059,8 +1019,9 @@ SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszLayer, int nShapeType, /* -------------------------------------------------------------------- */ i32 = 50; /* file size */ ByteCopy(&i32, abyHeader + 24, 4); - if (!bBigEndian) - SwapWord(4, abyHeader + 24); +#if !defined(SHP_BIG_ENDIAN) + SHP_SWAP32(abyHeader + 24); +#endif if (psHooks->FWrite(abyHeader, 100, 1, fpSHX) != 1) { char szErrorMsg[200]; @@ -1073,16 +1034,37 @@ SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszLayer, int nShapeType, free(pszFullname); psHooks->FClose(fpSHP); psHooks->FClose(fpSHX); - return NULL; + return SHPLIB_NULLPTR; } - /* -------------------------------------------------------------------- */ - /* Close the files, and then open them as regular existing files. */ - /* -------------------------------------------------------------------- */ - psHooks->FClose(fpSHP); - psHooks->FClose(fpSHX); + SHPHandle psSHP = STATIC_CAST(SHPHandle, calloc(1, sizeof(SHPInfo))); - return (SHPOpenLL(pszLayer, "r+b", psHooks)); + psSHP->bUpdated = FALSE; + memcpy(&(psSHP->sHooks), psHooks, sizeof(SAHooks)); + + psSHP->fpSHP = fpSHP; + psSHP->fpSHX = fpSHX; + psSHP->nShapeType = nShapeType; + psSHP->nFileSize = 100; + psSHP->panRecOffset = + STATIC_CAST(unsigned int *, malloc(sizeof(unsigned int))); + psSHP->panRecSize = + STATIC_CAST(unsigned int *, malloc(sizeof(unsigned int))); + + if (psSHP->panRecOffset == SHPLIB_NULLPTR || + psSHP->panRecSize == SHPLIB_NULLPTR) { + psSHP->sHooks.Error("Not enough memory to allocate requested memory"); + psSHP->sHooks.FClose(psSHP->fpSHP); + psSHP->sHooks.FClose(psSHP->fpSHX); + if (psSHP->panRecOffset) + free(psSHP->panRecOffset); + if (psSHP->panRecSize) + free(psSHP->panRecSize); + free(psSHP); + return SHPLIB_NULLPTR; + } + + return psSHP; } /************************************************************************/ @@ -1092,19 +1074,19 @@ SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszLayer, int nShapeType, /* indicated location in the record. */ /************************************************************************/ -static void _SHPSetBounds(uchar *pabyRec, SHPObject *psShape) +static void _SHPSetBounds(unsigned char *pabyRec, const SHPObject *psShape) { ByteCopy(&(psShape->dfXMin), pabyRec + 0, 8); ByteCopy(&(psShape->dfYMin), pabyRec + 8, 8); ByteCopy(&(psShape->dfXMax), pabyRec + 16, 8); ByteCopy(&(psShape->dfYMax), pabyRec + 24, 8); - if (bBigEndian) { - SwapWord(8, pabyRec + 0); - SwapWord(8, pabyRec + 8); - SwapWord(8, pabyRec + 16); - SwapWord(8, pabyRec + 24); - } +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + 0); + SHP_SWAP64(pabyRec + 8); + SHP_SWAP64(pabyRec + 16); + SHP_SWAP64(pabyRec + 24); +#endif } /************************************************************************/ @@ -1159,7 +1141,7 @@ SHPObject SHPAPI_CALL1(*) psObject->bMeasureIsUsed = FALSE; /* -------------------------------------------------------------------- */ - /* Establish whether this shape type has M, and Z values. */ + /* Establish whether this shape type has M, and Z values. */ /* -------------------------------------------------------------------- */ bool bHasM; bool bHasZ; @@ -1191,7 +1173,7 @@ SHPObject SHPAPI_CALL1(*) psObject->nParts = MAX(1, nParts); psObject->panPartStart = - STATIC_CAST(int *, calloc(sizeof(int), psObject->nParts)); + STATIC_CAST(int *, calloc(psObject->nParts, sizeof(int))); psObject->panPartType = STATIC_CAST(int *, malloc(sizeof(int) * psObject->nParts)); @@ -1208,8 +1190,7 @@ SHPObject SHPAPI_CALL1(*) psObject->panPartType[i] = SHPP_RING; } - if (psObject->panPartStart[0] != 0) - psObject->panPartStart[0] = 0; + psObject->panPartStart[0] = 0; } /* -------------------------------------------------------------------- */ @@ -1219,16 +1200,16 @@ SHPObject SHPAPI_CALL1(*) const size_t nSize = sizeof(double) * nVertices; psObject->padfX = STATIC_CAST(double *, padfX ? malloc(nSize) - : calloc(sizeof(double), nVertices)); + : calloc(nVertices, sizeof(double))); psObject->padfY = STATIC_CAST(double *, padfY ? malloc(nSize) - : calloc(sizeof(double), nVertices)); + : calloc(nVertices, sizeof(double))); psObject->padfZ = STATIC_CAST( double *, - padfZ &&bHasZ ? malloc(nSize) : calloc(sizeof(double), nVertices)); + padfZ &&bHasZ ? malloc(nSize) : calloc(nVertices, sizeof(double))); psObject->padfM = STATIC_CAST( double *, - padfM &&bHasM ? malloc(nSize) : calloc(sizeof(double), nVertices)); + padfM &&bHasM ? malloc(nSize) : calloc(nVertices, sizeof(double))); if (padfX != SHPLIB_NULLPTR) memcpy(psObject->padfX, padfX, nSize); if (padfY != SHPLIB_NULLPTR) @@ -1273,7 +1254,7 @@ SHPObject SHPAPI_CALL1(*) /************************************************************************/ int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, - SHPObject *psObject) + const SHPObject *psObject) { psSHP->bUpdated = TRUE; @@ -1298,22 +1279,32 @@ int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, /* Add the new entity to the in memory index. */ /* -------------------------------------------------------------------- */ if (nShapeId == -1 && psSHP->nRecords + 1 > psSHP->nMaxRecords) { + /* This cannot overflow given that we check that the file size does + * not grow over 4 GB, and the minimum size of a record is 12 bytes, + * hence the maximm value for nMaxRecords is 357,913,941 + */ int nNewMaxRecords = psSHP->nMaxRecords + psSHP->nMaxRecords / 3 + 100; unsigned int *panRecOffsetNew; unsigned int *panRecSizeNew; panRecOffsetNew = STATIC_CAST( - unsigned int *, SfRealloc(psSHP->panRecOffset, - sizeof(unsigned int) * nNewMaxRecords)); - if (panRecOffsetNew == SHPLIB_NULLPTR) + unsigned int *, realloc(psSHP->panRecOffset, + sizeof(unsigned int) * nNewMaxRecords)); + if (panRecOffsetNew == SHPLIB_NULLPTR) { + psSHP->sHooks.Error("Failed to write shape object. " + "Memory allocation error."); return -1; + } psSHP->panRecOffset = panRecOffsetNew; panRecSizeNew = STATIC_CAST( - unsigned int *, SfRealloc(psSHP->panRecSize, - sizeof(unsigned int) * nNewMaxRecords)); - if (panRecSizeNew == SHPLIB_NULLPTR) + unsigned int *, + realloc(psSHP->panRecSize, sizeof(unsigned int) * nNewMaxRecords)); + if (panRecSizeNew == SHPLIB_NULLPTR) { + psSHP->sHooks.Error("Failed to write shape object. " + "Memory allocation error."); return -1; + } psSHP->panRecSize = panRecSizeNew; psSHP->nMaxRecords = nNewMaxRecords; @@ -1322,14 +1313,28 @@ int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, /* -------------------------------------------------------------------- */ /* Initialize record. */ /* -------------------------------------------------------------------- */ - uchar *pabyRec = - STATIC_CAST(uchar *, malloc(psObject->nVertices * 4 * sizeof(double) + - psObject->nParts * 8 + 128)); - if (pabyRec == SHPLIB_NULLPTR) + + /* The following computation cannot overflow on 32-bit platforms given that + * the user had to allocate arrays of at least that size. */ + size_t nRecMaxSize = + psObject->nVertices * 4 * sizeof(double) + psObject->nParts * 8; + /* But the following test could trigger on 64-bit platforms on huge + * geometries. */ + const unsigned nExtraSpaceForGeomHeader = 128; + if (nRecMaxSize > UINT_MAX - nExtraSpaceForGeomHeader) { + psSHP->sHooks.Error("Failed to write shape object. Too big geometry."); return -1; + } + nRecMaxSize += nExtraSpaceForGeomHeader; + unsigned char *pabyRec = STATIC_CAST(unsigned char *, malloc(nRecMaxSize)); + if (pabyRec == SHPLIB_NULLPTR) { + psSHP->sHooks.Error("Failed to write shape object. " + "Memory allocation error."); + return -1; + } /* -------------------------------------------------------------------- */ - /* Extract vertices for a Polygon or Arc. */ + /* Extract vertices for a Polygon or Arc. */ /* -------------------------------------------------------------------- */ unsigned int nRecordSize = 0; const bool bFirstFeature = psSHP->nRecords == 0; @@ -1339,15 +1344,15 @@ int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, psObject->nSHPType == SHPT_POLYGONM || psObject->nSHPType == SHPT_ARC || psObject->nSHPType == SHPT_ARCZ || psObject->nSHPType == SHPT_ARCM || psObject->nSHPType == SHPT_MULTIPATCH) { - int32 nPoints = psObject->nVertices; - int32 nParts = psObject->nParts; + uint32_t nPoints = psObject->nVertices; + uint32_t nParts = psObject->nParts; _SHPSetBounds(pabyRec + 12, psObject); - if (bBigEndian) - SwapWord(4, &nPoints); - if (bBigEndian) - SwapWord(4, &nParts); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP32(&nPoints); + SHP_SWAP32(&nParts); +#endif ByteCopy(&nPoints, pabyRec + 40 + 8, 4); ByteCopy(&nParts, pabyRec + 36 + 8, 4); @@ -1360,8 +1365,9 @@ int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, ByteCopy(psObject->panPartStart, pabyRec + 44 + 8, 4 * psObject->nParts); for (int i = 0; i < psObject->nParts; i++) { - if (bBigEndian) - SwapWord(4, pabyRec + 44 + 8 + 4 * i); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP32(pabyRec + 44 + 8 + 4 * i); +#endif nRecordSize += 4; } @@ -1372,8 +1378,9 @@ int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, memcpy(pabyRec + nRecordSize, psObject->panPartType, 4 * psObject->nParts); for (int i = 0; i < psObject->nParts; i++) { - if (bBigEndian) - SwapWord(4, pabyRec + nRecordSize); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP32(pabyRec + nRecordSize); +#endif nRecordSize += 4; } } @@ -1385,11 +1392,10 @@ int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, ByteCopy(psObject->padfX + i, pabyRec + nRecordSize, 8); ByteCopy(psObject->padfY + i, pabyRec + nRecordSize + 8, 8); - if (bBigEndian) - SwapWord(8, pabyRec + nRecordSize); - - if (bBigEndian) - SwapWord(8, pabyRec + nRecordSize + 8); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + nRecordSize); + SHP_SWAP64(pabyRec + nRecordSize + 8); +#endif nRecordSize += 2 * 8; } @@ -1401,19 +1407,22 @@ int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, psObject->nSHPType == SHPT_ARCZ || psObject->nSHPType == SHPT_MULTIPATCH) { ByteCopy(&(psObject->dfZMin), pabyRec + nRecordSize, 8); - if (bBigEndian) - SwapWord(8, pabyRec + nRecordSize); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + nRecordSize); +#endif nRecordSize += 8; ByteCopy(&(psObject->dfZMax), pabyRec + nRecordSize, 8); - if (bBigEndian) - SwapWord(8, pabyRec + nRecordSize); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + nRecordSize); +#endif nRecordSize += 8; for (int i = 0; i < psObject->nVertices; i++) { ByteCopy(psObject->padfZ + i, pabyRec + nRecordSize, 8); - if (bBigEndian) - SwapWord(8, pabyRec + nRecordSize); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + nRecordSize); +#endif nRecordSize += 8; } } @@ -1430,65 +1439,72 @@ int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, || psObject->nSHPType == SHPT_POLYGONZ || psObject->nSHPType == SHPT_ARCZ)) { ByteCopy(&(psObject->dfMMin), pabyRec + nRecordSize, 8); - if (bBigEndian) - SwapWord(8, pabyRec + nRecordSize); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + nRecordSize); +#endif nRecordSize += 8; ByteCopy(&(psObject->dfMMax), pabyRec + nRecordSize, 8); - if (bBigEndian) - SwapWord(8, pabyRec + nRecordSize); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + nRecordSize); +#endif nRecordSize += 8; for (int i = 0; i < psObject->nVertices; i++) { ByteCopy(psObject->padfM + i, pabyRec + nRecordSize, 8); - if (bBigEndian) - SwapWord(8, pabyRec + nRecordSize); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + nRecordSize); +#endif nRecordSize += 8; } } } /* -------------------------------------------------------------------- */ - /* Extract vertices for a MultiPoint. */ + /* Extract vertices for a MultiPoint. */ /* -------------------------------------------------------------------- */ else if (psObject->nSHPType == SHPT_MULTIPOINT || psObject->nSHPType == SHPT_MULTIPOINTZ || psObject->nSHPType == SHPT_MULTIPOINTM) { - int32 nPoints = psObject->nVertices; + uint32_t nPoints = psObject->nVertices; _SHPSetBounds(pabyRec + 12, psObject); - if (bBigEndian) - SwapWord(4, &nPoints); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP32(&nPoints); +#endif ByteCopy(&nPoints, pabyRec + 44, 4); for (int i = 0; i < psObject->nVertices; i++) { ByteCopy(psObject->padfX + i, pabyRec + 48 + i * 16, 8); ByteCopy(psObject->padfY + i, pabyRec + 48 + i * 16 + 8, 8); - if (bBigEndian) - SwapWord(8, pabyRec + 48 + i * 16); - if (bBigEndian) - SwapWord(8, pabyRec + 48 + i * 16 + 8); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + 48 + i * 16); + SHP_SWAP64(pabyRec + 48 + i * 16 + 8); +#endif } nRecordSize = 48 + 16 * psObject->nVertices; if (psObject->nSHPType == SHPT_MULTIPOINTZ) { ByteCopy(&(psObject->dfZMin), pabyRec + nRecordSize, 8); - if (bBigEndian) - SwapWord(8, pabyRec + nRecordSize); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + nRecordSize); +#endif nRecordSize += 8; ByteCopy(&(psObject->dfZMax), pabyRec + nRecordSize, 8); - if (bBigEndian) - SwapWord(8, pabyRec + nRecordSize); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + nRecordSize); +#endif nRecordSize += 8; for (int i = 0; i < psObject->nVertices; i++) { ByteCopy(psObject->padfZ + i, pabyRec + nRecordSize, 8); - if (bBigEndian) - SwapWord(8, pabyRec + nRecordSize); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + nRecordSize); +#endif nRecordSize += 8; } } @@ -1497,26 +1513,29 @@ int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, (psObject->nSHPType == SHPT_MULTIPOINTZ || psObject->nSHPType == SHPT_MULTIPOINTM)) { ByteCopy(&(psObject->dfMMin), pabyRec + nRecordSize, 8); - if (bBigEndian) - SwapWord(8, pabyRec + nRecordSize); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + nRecordSize); +#endif nRecordSize += 8; ByteCopy(&(psObject->dfMMax), pabyRec + nRecordSize, 8); - if (bBigEndian) - SwapWord(8, pabyRec + nRecordSize); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + nRecordSize); +#endif nRecordSize += 8; for (int i = 0; i < psObject->nVertices; i++) { ByteCopy(psObject->padfM + i, pabyRec + nRecordSize, 8); - if (bBigEndian) - SwapWord(8, pabyRec + nRecordSize); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + nRecordSize); +#endif nRecordSize += 8; } } } /* -------------------------------------------------------------------- */ - /* Write point. */ + /* Write point. */ /* -------------------------------------------------------------------- */ else if (psObject->nSHPType == SHPT_POINT || psObject->nSHPType == SHPT_POINTZ || @@ -1524,25 +1543,27 @@ int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, ByteCopy(psObject->padfX, pabyRec + 12, 8); ByteCopy(psObject->padfY, pabyRec + 20, 8); - if (bBigEndian) - SwapWord(8, pabyRec + 12); - if (bBigEndian) - SwapWord(8, pabyRec + 20); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + 12); + SHP_SWAP64(pabyRec + 20); +#endif nRecordSize = 28; if (psObject->nSHPType == SHPT_POINTZ) { ByteCopy(psObject->padfZ, pabyRec + nRecordSize, 8); - if (bBigEndian) - SwapWord(8, pabyRec + nRecordSize); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + nRecordSize); +#endif nRecordSize += 8; } if (psObject->bMeasureIsUsed && (psObject->nSHPType == SHPT_POINTZ || psObject->nSHPType == SHPT_POINTM)) { ByteCopy(psObject->padfM, pabyRec + nRecordSize, 8); - if (bBigEndian) - SwapWord(8, pabyRec + nRecordSize); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP64(pabyRec + nRecordSize); +#endif nRecordSize += 8; } } @@ -1598,20 +1619,23 @@ int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, /* -------------------------------------------------------------------- */ /* Set the shape type, record number, and record size. */ /* -------------------------------------------------------------------- */ - int32 i32 = + uint32_t i32 = (nShapeId < 0) ? psSHP->nRecords + 1 : nShapeId + 1; /* record # */ - if (!bBigEndian) - SwapWord(4, &i32); +#if !defined(SHP_BIG_ENDIAN) + SHP_SWAP32(&i32); +#endif ByteCopy(&i32, pabyRec, 4); i32 = (nRecordSize - 8) / 2; /* record size */ - if (!bBigEndian) - SwapWord(4, &i32); +#if !defined(SHP_BIG_ENDIAN) + SHP_SWAP32(&i32); +#endif ByteCopy(&i32, pabyRec + 4, 4); i32 = psObject->nSHPType; /* shape type */ - if (bBigEndian) - SwapWord(4, &i32); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP32(&i32); +#endif ByteCopy(&i32, pabyRec + 8, 4); /* -------------------------------------------------------------------- */ @@ -1666,7 +1690,7 @@ int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, psSHP->panRecSize[nShapeId] = nRecordSize - 8; /* -------------------------------------------------------------------- */ - /* Expand file wide bounds based on this shape. */ + /* Expand file wide bounds based on this shape. */ /* -------------------------------------------------------------------- */ if (bFirstFeature) { if (psObject->nSHPType == SHPT_NULL || psObject->nVertices == 0) { @@ -1754,11 +1778,11 @@ static unsigned char *SHPReallocObjectBufIfNecessary(SHPHandle psSHP, /************************************************************************/ /* SHPReadObject() */ /* */ -/* Read the vertices, parts, and other non-attribute information */ -/* for one shape. */ +/* Read the vertices, parts, and other non-attribute information */ +/* for one shape. */ /************************************************************************/ -SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) +SHPObject SHPAPI_CALL1(*) SHPReadObject(const SHPHandle psSHP, int hEntity) { /* -------------------------------------------------------------------- */ /* Validate the record/entity number. */ @@ -1786,10 +1810,10 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) psSHP->sHooks.Error(str); return SHPLIB_NULLPTR; } - if (!bBigEndian) - SwapWord(4, &nOffset); - if (!bBigEndian) - SwapWord(4, &nLength); +#if !defined(SHP_BIG_ENDIAN) + SHP_SWAP32(&nOffset); + SHP_SWAP32(&nLength); +#endif if (nOffset > STATIC_CAST(unsigned int, INT_MAX)) { char str[128]; @@ -1859,8 +1883,8 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) } } - uchar *pabyRecNew = - STATIC_CAST(uchar *, SfRealloc(psSHP->pabyRec, nNewBufSize)); + unsigned char *pabyRecNew = + STATIC_CAST(unsigned char *, realloc(psSHP->pabyRec, nNewBufSize)); if (pabyRecNew == SHPLIB_NULLPTR) { char szErrorMsg[160]; snprintf(szErrorMsg, sizeof(szErrorMsg), @@ -1919,8 +1943,9 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) /* Do a sanity check */ int nSHPContentLength; memcpy(&nSHPContentLength, psSHP->pabyRec + 4, 4); - if (!bBigEndian) - SwapWord(4, &(nSHPContentLength)); +#if !defined(SHP_BIG_ENDIAN) + SHP_SWAP32(&(nSHPContentLength)); +#endif if (nSHPContentLength < 0 || nSHPContentLength > INT_MAX / 2 - 4 || 2 * nSHPContentLength + 8 != nBytesRead) { char str[128]; @@ -1962,11 +1987,12 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) int nSHPType; memcpy(&nSHPType, psSHP->pabyRec + 8, 4); - if (bBigEndian) - SwapWord(4, &(nSHPType)); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP32(&(nSHPType)); +#endif /* -------------------------------------------------------------------- */ - /* Allocate and minimally initialize the object. */ + /* Allocate and minimally initialize the object. */ /* -------------------------------------------------------------------- */ SHPObject *psShape; if (psSHP->bFastModeReadObject) { @@ -1988,7 +2014,7 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) psShape->bFastModeReadObject = psSHP->bFastModeReadObject; /* ==================================================================== */ - /* Extract vertices for a Polygon or Arc. */ + /* Extract vertices for a Polygon or Arc. */ /* ==================================================================== */ if (psShape->nSHPType == SHPT_POLYGON || psShape->nSHPType == SHPT_ARC || psShape->nSHPType == SHPT_POLYGONZ || @@ -2007,22 +2033,20 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) } /* -------------------------------------------------------------------- */ - /* Get the X/Y bounds. */ + /* Get the X/Y bounds. */ /* -------------------------------------------------------------------- */ - memcpy(&(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8); - memcpy(&(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8); - memcpy(&(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8); - memcpy(&(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8); - - if (bBigEndian) - SwapWord(8, &(psShape->dfXMin)); - if (bBigEndian) - SwapWord(8, &(psShape->dfYMin)); - if (bBigEndian) - SwapWord(8, &(psShape->dfXMax)); - if (bBigEndian) - SwapWord(8, &(psShape->dfYMax)); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAPDOUBLE_CPY(&psShape->dfXMin, psSHP->pabyRec + 8 + 4); + SHP_SWAPDOUBLE_CPY(&psShape->dfYMin, psSHP->pabyRec + 8 + 12); + SHP_SWAPDOUBLE_CPY(&psShape->dfXMax, psSHP->pabyRec + 8 + 20); + SHP_SWAPDOUBLE_CPY(&psShape->dfYMax, psSHP->pabyRec + 8 + 28); +#else + memcpy(&psShape->dfXMin, psSHP->pabyRec + 8 + 4, 8); + memcpy(&psShape->dfYMin, psSHP->pabyRec + 8 + 12, 8); + memcpy(&psShape->dfXMax, psSHP->pabyRec + 8 + 20, 8); + memcpy(&psShape->dfYMax, psSHP->pabyRec + 8 + 28, 8); +#endif /* -------------------------------------------------------------------- */ @@ -2030,15 +2054,15 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) /* to proper size. */ /* -------------------------------------------------------------------- */ - int32 nPoints; + uint32_t nPoints; memcpy(&nPoints, psSHP->pabyRec + 40 + 8, 4); - int32 nParts; + uint32_t nParts; memcpy(&nParts, psSHP->pabyRec + 36 + 8, 4); - if (bBigEndian) - SwapWord(4, &nPoints); - if (bBigEndian) - SwapWord(4, &nParts); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP32(&nPoints); + SHP_SWAP32(&nParts); +#endif /* nPoints and nParts are unsigned */ if (/* nPoints < 0 || nParts < 0 || */ @@ -2121,7 +2145,7 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) return SHPLIB_NULLPTR; } - for (int i = 0; STATIC_CAST(int32, i) < nParts; i++) + for (int i = 0; STATIC_CAST(uint32_t, i) < nParts; i++) psShape->panPartType[i] = SHPP_RING; /* -------------------------------------------------------------------- @@ -2130,9 +2154,10 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) /* -------------------------------------------------------------------- */ memcpy(psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts); - for (int i = 0; STATIC_CAST(int32, i) < nParts; i++) { - if (bBigEndian) - SwapWord(4, psShape->panPartStart + i); + for (int i = 0; STATIC_CAST(uint32_t, i) < nParts; i++) { +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP32(psShape->panPartStart + i); +#endif /* We check that the offset is inside the vertex array */ if (psShape->panPartStart[i] < 0 || @@ -2174,9 +2199,10 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) */ if (psShape->nSHPType == SHPT_MULTIPATCH) { memcpy(psShape->panPartType, psSHP->pabyRec + nOffset, 4 * nParts); - for (int i = 0; STATIC_CAST(int32, i) < nParts; i++) { - if (bBigEndian) - SwapWord(4, psShape->panPartType + i); + for (int i = 0; STATIC_CAST(uint32_t, i) < nParts; i++) { +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP32(psShape->panPartType + i); +#endif } nOffset += 4 * nParts; @@ -2187,16 +2213,17 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) /* Copy out the vertices from the record. */ /* -------------------------------------------------------------------- */ - for (int i = 0; STATIC_CAST(int32, i) < nPoints; i++) { + for (int i = 0; STATIC_CAST(uint32_t, i) < nPoints; i++) { +#if defined(SHP_BIG_ENDIAN) + SHP_SWAPDOUBLE_CPY(psShape->padfX + i, + psSHP->pabyRec + nOffset + i * 16); + SHP_SWAPDOUBLE_CPY(psShape->padfY + i, + psSHP->pabyRec + nOffset + i * 16 + 8); +#else memcpy(psShape->padfX + i, psSHP->pabyRec + nOffset + i * 16, 8); - memcpy(psShape->padfY + i, psSHP->pabyRec + nOffset + i * 16 + 8, 8); - - if (bBigEndian) - SwapWord(8, psShape->padfX + i); - if (bBigEndian) - SwapWord(8, psShape->padfY + i); +#endif } nOffset += 16 * nPoints; @@ -2209,19 +2236,23 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) if (psShape->nSHPType == SHPT_POLYGONZ || psShape->nSHPType == SHPT_ARCZ || psShape->nSHPType == SHPT_MULTIPATCH) { - memcpy(&(psShape->dfZMin), psSHP->pabyRec + nOffset, 8); - memcpy(&(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAPDOUBLE_CPY(&psShape->dfZMin, psSHP->pabyRec + nOffset); + SHP_SWAPDOUBLE_CPY(&psShape->dfZMax, psSHP->pabyRec + nOffset + 8); +#else + memcpy(&psShape->dfZMin, psSHP->pabyRec + nOffset, 8); + memcpy(&psShape->dfZMax, psSHP->pabyRec + nOffset + 8, 8); - if (bBigEndian) - SwapWord(8, &(psShape->dfZMin)); - if (bBigEndian) - SwapWord(8, &(psShape->dfZMax)); +#endif - for (int i = 0; STATIC_CAST(int32, i) < nPoints; i++) { + for (int i = 0; STATIC_CAST(uint32_t, i) < nPoints; i++) { +#if defined(SHP_BIG_ENDIAN) + SHP_SWAPDOUBLE_CPY(psShape->padfZ + i, + psSHP->pabyRec + nOffset + 16 + i * 8); +#else memcpy(psShape->padfZ + i, psSHP->pabyRec + nOffset + 16 + i * 8, 8); - if (bBigEndian) - SwapWord(8, psShape->padfZ + i); +#endif } nOffset += 16 + 8 * nPoints; @@ -2239,19 +2270,22 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) /* -------------------------------------------------------------------- */ if (nEntitySize >= STATIC_CAST(int, nOffset + 16 + 8 * nPoints)) { - memcpy(&(psShape->dfMMin), psSHP->pabyRec + nOffset, 8); - memcpy(&(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8); - - if (bBigEndian) - SwapWord(8, &(psShape->dfMMin)); - if (bBigEndian) - SwapWord(8, &(psShape->dfMMax)); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAPDOUBLE_CPY(&psShape->dfMMin, psSHP->pabyRec + nOffset); + SHP_SWAPDOUBLE_CPY(&psShape->dfMMax, psSHP->pabyRec + nOffset + 8); +#else + memcpy(&psShape->dfMMin, psSHP->pabyRec + nOffset, 8); + memcpy(&psShape->dfMMax, psSHP->pabyRec + nOffset + 8, 8); +#endif - for (int i = 0; STATIC_CAST(int32, i) < nPoints; i++) { + for (int i = 0; STATIC_CAST(uint32_t, i) < nPoints; i++) { +#if defined(SHP_BIG_ENDIAN) + SHP_SWAPDOUBLE_CPY(psShape->padfM + i, + psSHP->pabyRec + nOffset + 16 + i * 8); +#else memcpy(psShape->padfM + i, psSHP->pabyRec + nOffset + 16 + i * 8, 8); - if (bBigEndian) - SwapWord(8, psShape->padfM + i); +#endif } psShape->bMeasureIsUsed = TRUE; } @@ -2261,7 +2295,7 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) } /* ==================================================================== */ - /* Extract vertices for a MultiPoint. */ + /* Extract vertices for a MultiPoint. */ /* ==================================================================== */ else if (psShape->nSHPType == SHPT_MULTIPOINT || psShape->nSHPType == SHPT_MULTIPOINTM || @@ -2276,11 +2310,12 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) SHPDestroyObject(psShape); return SHPLIB_NULLPTR; } - int32 nPoints; + uint32_t nPoints; memcpy(&nPoints, psSHP->pabyRec + 44, 4); - if (bBigEndian) - SwapWord(4, &nPoints); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAP32(&nPoints); +#endif /* nPoints is unsigned */ if (/* nPoints < 0 || */ nPoints > 50 * 1000 * 1000) { @@ -2346,36 +2381,36 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) return SHPLIB_NULLPTR; } - for (int i = 0; STATIC_CAST(int32, i) < nPoints; i++) { + for (int i = 0; STATIC_CAST(uint32_t, i) < nPoints; i++) { +#if defined(SHP_BIG_ENDIAN) + SHP_SWAPDOUBLE_CPY(psShape->padfX + i, + psSHP->pabyRec + 48 + 16 * i); + SHP_SWAPDOUBLE_CPY(psShape->padfY + i, + psSHP->pabyRec + 48 + 16 * i + 8); +#else memcpy(psShape->padfX + i, psSHP->pabyRec + 48 + 16 * i, 8); memcpy(psShape->padfY + i, psSHP->pabyRec + 48 + 16 * i + 8, 8); - - if (bBigEndian) - SwapWord(8, psShape->padfX + i); - if (bBigEndian) - SwapWord(8, psShape->padfY + i); +#endif } int nOffset = 48 + 16 * nPoints; /* -------------------------------------------------------------------- */ - /* Get the X/Y bounds. */ + /* Get the X/Y bounds. */ /* -------------------------------------------------------------------- */ - memcpy(&(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8); - memcpy(&(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8); - memcpy(&(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8); - memcpy(&(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8); - - if (bBigEndian) - SwapWord(8, &(psShape->dfXMin)); - if (bBigEndian) - SwapWord(8, &(psShape->dfYMin)); - if (bBigEndian) - SwapWord(8, &(psShape->dfXMax)); - if (bBigEndian) - SwapWord(8, &(psShape->dfYMax)); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAPDOUBLE_CPY(&psShape->dfXMin, psSHP->pabyRec + 8 + 4); + SHP_SWAPDOUBLE_CPY(&psShape->dfYMin, psSHP->pabyRec + 8 + 12); + SHP_SWAPDOUBLE_CPY(&psShape->dfXMax, psSHP->pabyRec + 8 + 20); + SHP_SWAPDOUBLE_CPY(&psShape->dfYMax, psSHP->pabyRec + 8 + 28); +#else + memcpy(&psShape->dfXMin, psSHP->pabyRec + 8 + 4, 8); + memcpy(&psShape->dfYMin, psSHP->pabyRec + 8 + 12, 8); + memcpy(&psShape->dfXMax, psSHP->pabyRec + 8 + 20, 8); + memcpy(&psShape->dfYMax, psSHP->pabyRec + 8 + 28, 8); +#endif /* -------------------------------------------------------------------- */ @@ -2383,19 +2418,22 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) /* -------------------------------------------------------------------- */ if (psShape->nSHPType == SHPT_MULTIPOINTZ) { - memcpy(&(psShape->dfZMin), psSHP->pabyRec + nOffset, 8); - memcpy(&(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8); - - if (bBigEndian) - SwapWord(8, &(psShape->dfZMin)); - if (bBigEndian) - SwapWord(8, &(psShape->dfZMax)); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAPDOUBLE_CPY(&psShape->dfZMin, psSHP->pabyRec + nOffset); + SHP_SWAPDOUBLE_CPY(&psShape->dfZMax, psSHP->pabyRec + nOffset + 8); +#else + memcpy(&psShape->dfZMin, psSHP->pabyRec + nOffset, 8); + memcpy(&psShape->dfZMax, psSHP->pabyRec + nOffset + 8, 8); +#endif - for (int i = 0; STATIC_CAST(int32, i) < nPoints; i++) { + for (int i = 0; STATIC_CAST(uint32_t, i) < nPoints; i++) { +#if defined(SHP_BIG_ENDIAN) + SHP_SWAPDOUBLE_CPY(psShape->padfZ + i, + psSHP->pabyRec + nOffset + 16 + i * 8); +#else memcpy(psShape->padfZ + i, psSHP->pabyRec + nOffset + 16 + i * 8, 8); - if (bBigEndian) - SwapWord(8, psShape->padfZ + i); +#endif } nOffset += 16 + 8 * nPoints; @@ -2412,19 +2450,22 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) /* -------------------------------------------------------------------- */ if (nEntitySize >= STATIC_CAST(int, nOffset + 16 + 8 * nPoints)) { - memcpy(&(psShape->dfMMin), psSHP->pabyRec + nOffset, 8); - memcpy(&(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8); - - if (bBigEndian) - SwapWord(8, &(psShape->dfMMin)); - if (bBigEndian) - SwapWord(8, &(psShape->dfMMax)); +#if defined(SHP_BIG_ENDIAN) + SHP_SWAPDOUBLE_CPY(&psShape->dfMMin, psSHP->pabyRec + nOffset); + SHP_SWAPDOUBLE_CPY(&psShape->dfMMax, psSHP->pabyRec + nOffset + 8); +#else + memcpy(&psShape->dfMMin, psSHP->pabyRec + nOffset, 8); + memcpy(&psShape->dfMMax, psSHP->pabyRec + nOffset + 8, 8); +#endif - for (int i = 0; STATIC_CAST(int32, i) < nPoints; i++) { + for (int i = 0; STATIC_CAST(uint32_t, i) < nPoints; i++) { +#if defined(SHP_BIG_ENDIAN) + SHP_SWAPDOUBLE_CPY(psShape->padfM + i, + psSHP->pabyRec + nOffset + 16 + i * 8); +#else memcpy(psShape->padfM + i, psSHP->pabyRec + nOffset + 16 + i * 8, 8); - if (bBigEndian) - SwapWord(8, psShape->padfM + i); +#endif } psShape->bMeasureIsUsed = TRUE; } @@ -2465,13 +2506,13 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) SHPDestroyObject(psShape); return SHPLIB_NULLPTR; } +#if defined(SHP_BIG_ENDIAN) + SHP_SWAPDOUBLE_CPY(psShape->padfX, psSHP->pabyRec + 12); + SHP_SWAPDOUBLE_CPY(psShape->padfY, psSHP->pabyRec + 20); +#else memcpy(psShape->padfX, psSHP->pabyRec + 12, 8); memcpy(psShape->padfY, psSHP->pabyRec + 20, 8); - - if (bBigEndian) - SwapWord(8, psShape->padfX); - if (bBigEndian) - SwapWord(8, psShape->padfY); +#endif int nOffset = 20 + 8; @@ -2481,10 +2522,11 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) /* -------------------------------------------------------------------- */ if (psShape->nSHPType == SHPT_POINTZ) { +#if defined(SHP_BIG_ENDIAN) + SHP_SWAPDOUBLE_CPY(psShape->padfZ, psSHP->pabyRec + nOffset); +#else memcpy(psShape->padfZ, psSHP->pabyRec + nOffset, 8); - - if (bBigEndian) - SwapWord(8, psShape->padfZ); +#endif nOffset += 8; } @@ -2498,10 +2540,11 @@ SHPObject SHPAPI_CALL1(*) SHPReadObject(SHPHandle psSHP, int hEntity) /* -------------------------------------------------------------------- */ if (nEntitySize >= nOffset + 8) { +#if defined(SHP_BIG_ENDIAN) + SHP_SWAPDOUBLE_CPY(psShape->padfM, psSHP->pabyRec + nOffset); +#else memcpy(psShape->padfM, psSHP->pabyRec + nOffset, 8); - - if (bBigEndian) - SwapWord(8, psShape->padfM); +#endif psShape->bMeasureIsUsed = TRUE; } @@ -2739,8 +2782,9 @@ static int SHPRewindIsInnerRing(const SHPObject *psObject, int iOpRing, /* specification. */ /************************************************************************/ -int SHPAPI_CALL SHPRewindObject(CPL_UNUSED SHPHandle hSHP, SHPObject *psObject) +int SHPAPI_CALL SHPRewindObject(const SHPHandle hSHP, SHPObject *psObject) { + (void)hSHP; /* -------------------------------------------------------------------- */ /* Do nothing if this is not a polygon object. */ /* -------------------------------------------------------------------- */ From e82663c25232be28cc768789ed7a1a586f20354c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sun, 29 Sep 2024 05:44:15 -0400 Subject: [PATCH 119/209] style: Use `any` or `all` instead of `for` loop (SIM110) (#4404) --- gui/wxpython/psmap/instructions.py | 5 +---- man/build_class_graphical.py | 5 +---- man/build_manual_gallery.py | 5 +---- pyproject.toml | 2 -- python/grass/pygrass/gis/region.py | 5 +---- python/grass/pygrass/raster/history.py | 5 +---- python/grass/pygrass/vector/table.py | 5 +---- python/grass/script/task.py | 6 +----- scripts/g.search.modules/g.search.modules.py | 5 +---- 9 files changed, 8 insertions(+), 35 deletions(-) diff --git a/gui/wxpython/psmap/instructions.py b/gui/wxpython/psmap/instructions.py index 8a535b96704..693e8024b57 100644 --- a/gui/wxpython/psmap/instructions.py +++ b/gui/wxpython/psmap/instructions.py @@ -86,10 +86,7 @@ def __getitem__(self, id): def __contains__(self, id): """Test if instruction is included""" - for each in self.instruction: - if each.id == id: - return True - return False + return any(each.id == id for each in self.instruction) def __delitem__(self, id): """Delete instruction""" diff --git a/man/build_class_graphical.py b/man/build_class_graphical.py index 35b2a731cfe..554c950d3a8 100644 --- a/man/build_class_graphical.py +++ b/man/build_class_graphical.py @@ -91,10 +91,7 @@ def file_matches(filename, patterns): - for pattern in patterns: - if fnmatch.fnmatch(filename, pattern): - return True - return False + return any(fnmatch.fnmatch(filename, pattern) for pattern in patterns) def starts_with_module(string, module) -> bool: diff --git a/man/build_manual_gallery.py b/man/build_manual_gallery.py index 3d381e27877..51a6fbcd312 100755 --- a/man/build_manual_gallery.py +++ b/man/build_manual_gallery.py @@ -102,10 +102,7 @@ def img_in_html(filename, imagename) -> bool: def file_matches(filename, patterns): - for pattern in patterns: - if fnmatch.fnmatch(filename, pattern): - return True - return False + return any(fnmatch.fnmatch(filename, pattern) for pattern in patterns) def get_files(directory, patterns, exclude_patterns): diff --git a/pyproject.toml b/pyproject.toml index 3a6d449ec1d..9e430071afc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -246,8 +246,6 @@ ignore = [ "SIM102", # collapsible-if "SIM105", # suppressible-exception "SIM108", # if-else-block-instead-of-if-exp - "SIM109", # compare-with-tuple - "SIM110", # reimplemented-builtin "SIM113", # enumerate-for-loop "SIM116", # if-else-block-instead-of-dict-lookup "SIM118", # in-dict-keys diff --git a/python/grass/pygrass/gis/region.py b/python/grass/pygrass/gis/region.py index 98c75a15631..892a3664b49 100644 --- a/python/grass/pygrass/gis/region.py +++ b/python/grass/pygrass/gis/region.py @@ -331,10 +331,7 @@ def __eq__(self, reg): "zone", "proj", ] - for attr in attrs: - if getattr(self, attr) != getattr(reg, attr): - return False - return True + return all(getattr(self, attr) == getattr(reg, attr) for attr in attrs) def __ne__(self, other): return not self == other diff --git a/python/grass/pygrass/raster/history.py b/python/grass/pygrass/raster/history.py index 5ec855cf1bb..8f227affabc 100644 --- a/python/grass/pygrass/raster/history.py +++ b/python/grass/pygrass/raster/history.py @@ -59,10 +59,7 @@ def __del__(self): """Rast_free_history""" def __eq__(self, hist): - for attr in self.attrs: - if getattr(self, attr) != getattr(hist, attr): - return False - return True + return all(getattr(self, attr) == getattr(hist, attr) for attr in self.attrs) def __len__(self): return self.length() diff --git a/python/grass/pygrass/vector/table.py b/python/grass/pygrass/vector/table.py index 4b7e99c0a83..634c440a583 100644 --- a/python/grass/pygrass/vector/table.py +++ b/python/grass/pygrass/vector/table.py @@ -791,10 +791,7 @@ def __eq__(self, link): False """ attrs = ["layer", "name", "table_name", "key", "driver"] - for attr in attrs: - if getattr(self, attr) != getattr(link, attr): - return False - return True + return all(getattr(self, attr) == getattr(link, attr) for attr in attrs) def __ne__(self, other): return not self == other diff --git a/python/grass/script/task.py b/python/grass/script/task.py index 35234ba65e6..8e1f0a12844 100644 --- a/python/grass/script/task.py +++ b/python/grass/script/task.py @@ -247,11 +247,7 @@ def get_options(self): def has_required(self): """Check if command has at least one required parameter""" - for p in self.params: - if p.get("required", False): - return True - - return False + return any(p.get("required", False) for p in self.params) def set_param(self, aParam, aValue, element="value"): """Set param value/values.""" diff --git a/scripts/g.search.modules/g.search.modules.py b/scripts/g.search.modules/g.search.modules.py index a3bab4325c2..574b8133a9e 100755 --- a/scripts/g.search.modules/g.search.modules.py +++ b/scripts/g.search.modules/g.search.modules.py @@ -313,10 +313,7 @@ def _exact_search(keyword, module_keywords): :param module_keywords: comma separated list of keywords """ module_keywords = module_keywords.split(",") - for current in module_keywords: - if keyword == current: - return True - return False + return keyword in module_keywords def _manpage_search(pattern, name): From 108e5e4fa06ab8b2d8178597145b6abcdab871b5 Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Mon, 30 Sep 2024 10:23:19 -0400 Subject: [PATCH 120/209] raster: Add library function to ask for mask presence (#4402) To avoid asking about presence of the MASK raster, add a library function which checks for presence of the raster hiding its name in the library. Motivation for this is a greater mask abstraction. Some code needs to link to newly raster library (which was previously used transitively). --- include/grass/defs/raster.h | 1 + lib/raster/mask_info.c | 10 ++++++++++ raster/r.mfilter/main.c | 4 ++-- raster/r.neighbors/main.c | 4 ++-- raster/r.patch/main.c | 4 ++-- raster/r.resamp.filter/main.c | 4 ++-- raster/r.resamp.interp/main.c | 4 ++-- raster/r.series/main.c | 4 ++-- raster/r.sim/r.sim.sediment/Makefile | 4 ++-- raster/r.sim/r.sim.sediment/main.c | 5 +++-- raster/r.sim/r.sim.water/Makefile | 4 ++-- raster/r.sim/r.sim.water/main.c | 5 +++-- raster/r.slope.aspect/main.c | 4 ++-- raster/r.sun/main.c | 4 ++-- raster/r.univar/r.univar_main.c | 4 ++-- vector/v.surf.rst/Makefile | 4 ++-- vector/v.surf.rst/main.c | 5 +++-- 17 files changed, 44 insertions(+), 30 deletions(-) diff --git a/include/grass/defs/raster.h b/include/grass/defs/raster.h index 7244da2a354..c2d26ccdccc 100644 --- a/include/grass/defs/raster.h +++ b/include/grass/defs/raster.h @@ -393,6 +393,7 @@ int Rast_option_to_interp_type(const struct Option *); /* mask_info.c */ char *Rast_mask_info(void); int Rast__mask_info(char *, char *); +bool Rast_mask_is_present(void); /* maskfd.c */ int Rast_maskfd(void); diff --git a/lib/raster/mask_info.c b/lib/raster/mask_info.c index 792510879dc..1a11da972f8 100644 --- a/lib/raster/mask_info.c +++ b/lib/raster/mask_info.c @@ -70,3 +70,13 @@ int Rast__mask_info(char *name, char *mapset) return 1; } + +/** + * @brief Check presence of 2D raster mask + * + * @return true if mask is present, false otherwise + */ +bool Rast_mask_is_present(void) +{ + return G_find_raster("MASK", G_mapset()) != NULL; +} diff --git a/raster/r.mfilter/main.c b/raster/r.mfilter/main.c index 17ecd2182be..ad0a9dd35ae 100644 --- a/raster/r.mfilter/main.c +++ b/raster/r.mfilter/main.c @@ -132,8 +132,8 @@ int main(int argc, char **argv) "threads setting.")); nprocs = 1; #endif - if (nprocs > 1 && G_find_raster("MASK", G_mapset()) != NULL) { - G_warning(_("Parallel processing disabled due to active MASK.")); + if (nprocs > 1 && Rast_mask_is_present()) { + G_warning(_("Parallel processing disabled due to active mask.")); nprocs = 1; } out_name = opt2->answer; diff --git a/raster/r.neighbors/main.c b/raster/r.neighbors/main.c index 93cbaa9e3da..8885460a564 100644 --- a/raster/r.neighbors/main.c +++ b/raster/r.neighbors/main.c @@ -310,8 +310,8 @@ int main(int argc, char *argv[]) "threads setting.")); ncb.threads = 1; #endif - if (ncb.threads > 1 && G_find_raster("MASK", G_mapset()) != NULL) { - G_warning(_("Parallel processing disabled due to active MASK.")); + if (ncb.threads > 1 && Rast_mask_is_present()) { + G_warning(_("Parallel processing disabled due to active mask.")); ncb.threads = 1; } if (strcmp(parm.weighting_function->answer, "none") && flag.circle->answer) diff --git a/raster/r.patch/main.c b/raster/r.patch/main.c index 3835e287440..c54482db13a 100644 --- a/raster/r.patch/main.c +++ b/raster/r.patch/main.c @@ -113,8 +113,8 @@ int main(int argc, char *argv[]) "threads setting.")); nprocs = 1; #endif - if (nprocs > 1 && G_find_raster("MASK", G_mapset()) != NULL) { - G_warning(_("Parallel processing disabled due to active MASK.")); + if (nprocs > 1 && Rast_mask_is_present()) { + G_warning(_("Parallel processing disabled due to active mask.")); nprocs = 1; } diff --git a/raster/r.resamp.filter/main.c b/raster/r.resamp.filter/main.c index b1f6ed3e530..e74f3598629 100644 --- a/raster/r.resamp.filter/main.c +++ b/raster/r.resamp.filter/main.c @@ -494,8 +494,8 @@ int main(int argc, char *argv[]) "threads setting.")); nprocs = 1; #endif - if (nprocs > 1 && G_find_raster("MASK", G_mapset()) != NULL) { - G_warning(_("Parallel processing disabled due to active MASK.")); + if (nprocs > 1 && Rast_mask_is_present()) { + G_warning(_("Parallel processing disabled due to active make.")); nprocs = 1; } if (parm.radius->answer) { diff --git a/raster/r.resamp.interp/main.c b/raster/r.resamp.interp/main.c index 734f3306bf8..2319400b0fc 100644 --- a/raster/r.resamp.interp/main.c +++ b/raster/r.resamp.interp/main.c @@ -132,8 +132,8 @@ int main(int argc, char *argv[]) "threads setting.")); threads = 1; #endif - if (threads > 1 && G_find_raster("MASK", G_mapset()) != NULL) { - G_warning(_("Parallel processing disabled due to active MASK.")); + if (threads > 1 && Rast_mask_is_present()) { + G_warning(_("Parallel processing disabled due to active mask.")); threads = 1; } bufrows = atoi(memory->answer) * (((1 << 20) / sizeof(DCELL)) / dst_w.cols); diff --git a/raster/r.series/main.c b/raster/r.series/main.c index bfecbf117c0..ade93d8f185 100644 --- a/raster/r.series/main.c +++ b/raster/r.series/main.c @@ -227,8 +227,8 @@ int main(int argc, char *argv[]) "threads setting.")); nprocs = 1; #endif - if (nprocs > 1 && G_find_raster("MASK", G_mapset()) != NULL) { - G_warning(_("Parallel processing disabled due to active MASK.")); + if (nprocs > 1 && Rast_mask_is_present()) { + G_warning(_("Parallel processing disabled due to active mask.")); nprocs = 1; } lo = -INFINITY; diff --git a/raster/r.sim/r.sim.sediment/Makefile b/raster/r.sim/r.sim.sediment/Makefile index 4bc07478ec9..13ca19d09dc 100644 --- a/raster/r.sim/r.sim.sediment/Makefile +++ b/raster/r.sim/r.sim.sediment/Makefile @@ -4,8 +4,8 @@ PGM=r.sim.sediment EXTRA_CLEAN_DIRS=doxygenhtml -LIBES = $(SIMLIB) $(GMATHLIB) $(GISLIB) $(OPENMP_LIBPATH) $(OPENMP_LIB) -DEPENDENCIES = $(SIMDEP) $(GMATHDEP) $(GISDEP) +LIBES = $(SIMLIB) $(GMATHLIB) $(GISLIB) $(RASTERLIB) $(OPENMP_LIBPATH) $(OPENMP_LIB) +DEPENDENCIES = $(SIMDEP) $(GMATHDEP) $(GISDEP) $(RASTERDEP) EXTRA_INC = $(OPENMP_INCPATH) $(VECT_INC) EXTRA_CFLAGS = -I ../simlib $(VECT_CFLAGS) $(OPENMP_CFLAGS) diff --git a/raster/r.sim/r.sim.sediment/main.c b/raster/r.sim/r.sim.sediment/main.c index fcdd9e98f89..dd082fe0f81 100644 --- a/raster/r.sim/r.sim.sediment/main.c +++ b/raster/r.sim/r.sim.sediment/main.c @@ -70,6 +70,7 @@ #endif #include #include +#include #include #include #include @@ -380,8 +381,8 @@ int main(int argc, char *argv[]) #else threads = 1; #endif - if (threads > 1 && G_find_raster("MASK", G_mapset()) != NULL) { - G_warning(_("Parallel processing disabled due to active MASK.")); + if (threads > 1 && Rast_mask_is_present()) { + G_warning(_("Parallel processing disabled due to active mask.")); threads = 1; } G_message(_("Number of threads: %d"), threads); diff --git a/raster/r.sim/r.sim.water/Makefile b/raster/r.sim/r.sim.water/Makefile index 36121ebf82e..47037823fae 100644 --- a/raster/r.sim/r.sim.water/Makefile +++ b/raster/r.sim/r.sim.water/Makefile @@ -4,8 +4,8 @@ PGM=r.sim.water EXTRA_CLEAN_DIRS=doxygenhtml -LIBES = $(SIMLIB) $(GMATHLIB) $(GISLIB) $(OPENMP_LIBPATH) $(OPENMP_LIB) -DEPENDENCIES = $(SIMDEP) $(GMATHDEP) $(GISDEP) +LIBES = $(SIMLIB) $(GMATHLIB) $(GISLIB) $(RASTERLIB) $(OPENMP_LIBPATH) $(OPENMP_LIB) +DEPENDENCIES = $(SIMDEP) $(GMATHDEP) $(GISDEP) $(RASTERDEP) EXTRA_INC = $(VECT_INC) $(OPENMP_INCPATH) EXTRA_CFLAGS = -I ../simlib $(VECT_CFLAGS) $(OPENMP_CFLAGS) diff --git a/raster/r.sim/r.sim.water/main.c b/raster/r.sim/r.sim.water/main.c index 3998e5524ac..61f128f5504 100644 --- a/raster/r.sim/r.sim.water/main.c +++ b/raster/r.sim/r.sim.water/main.c @@ -77,6 +77,7 @@ #endif #include #include +#include #include #include #include @@ -407,8 +408,8 @@ int main(int argc, char *argv[]) #else threads = 1; #endif - if (threads > 1 && G_find_raster("MASK", G_mapset()) != NULL) { - G_warning(_("Parallel processing disabled due to active MASK.")); + if (threads > 1 && Rast_mask_is_present()) { + G_warning(_("Parallel processing disabled due to active mask.")); threads = 1; } G_message(_("Number of threads: %d"), threads); diff --git a/raster/r.slope.aspect/main.c b/raster/r.slope.aspect/main.c index 86b4d5f5607..d302e02b22c 100644 --- a/raster/r.slope.aspect/main.c +++ b/raster/r.slope.aspect/main.c @@ -305,8 +305,8 @@ int main(int argc, char *argv[]) "threads setting.")); nprocs = 1; #endif - if (nprocs > 1 && G_find_raster("MASK", G_mapset()) != NULL) { - G_warning(_("Parallel processing disabled due to active MASK.")); + if (nprocs > 1 && Rast_mask_is_present()) { + G_warning(_("Parallel processing disabled due to active mask.")); nprocs = 1; } radians_to_degrees = 180.0 / M_PI; diff --git a/raster/r.sun/main.c b/raster/r.sun/main.c index 9e45e184dac..e325cb637f0 100644 --- a/raster/r.sun/main.c +++ b/raster/r.sun/main.c @@ -591,8 +591,8 @@ int main(int argc, char *argv[]) #else threads = 1; #endif - if (threads > 1 && G_find_raster("MASK", G_mapset()) != NULL) { - G_warning(_("Parallel processing disabled due to active MASK.")); + if (threads > 1 && Rast_mask_is_present()) { + G_warning(_("Parallel processing disabled due to active mask.")); threads = 1; } G_message(_("Number of threads <%d>"), threads); diff --git a/raster/r.univar/r.univar_main.c b/raster/r.univar/r.univar_main.c index 805acfff27b..e56301a1364 100644 --- a/raster/r.univar/r.univar_main.c +++ b/raster/r.univar/r.univar_main.c @@ -192,8 +192,8 @@ int main(int argc, char *argv[]) sscanf(param.nprocs->answer, "%d", &nprocs); if (nprocs < 1) G_fatal_error(_("<%d> is not valid number of nprocs."), nprocs); - if (nprocs > 1 && G_find_raster("MASK", G_mapset()) != NULL) { - G_warning(_("Parallel processing disabled due to active MASK.")); + if (nprocs > 1 && Rast_mask_is_present()) { + G_warning(_("Parallel processing disabled due to active mask.")); nprocs = 1; } #if defined(_OPENMP) diff --git a/vector/v.surf.rst/Makefile b/vector/v.surf.rst/Makefile index 3b5d8eca836..414ebbd85a0 100644 --- a/vector/v.surf.rst/Makefile +++ b/vector/v.surf.rst/Makefile @@ -4,9 +4,9 @@ PGM=v.surf.rst EXTRA_CLEAN_DIRS=doxygenhtml -LIBES = $(INTERPFLLIB) $(QTREELIB) $(INTERPDATALIB) $(GMATHLIB) $(VECTORLIB) $(DBMILIB) $(GISLIB) $(MATHLIB) +LIBES = $(INTERPFLLIB) $(QTREELIB) $(INTERPDATALIB) $(GMATHLIB) $(RASTERLIB) $(VECTORLIB) $(DBMILIB) $(GISLIB) $(MATHLIB) EXTRA_LIBS = $(OPENMP_LIBPATH) $(OPENMP_LIB) -DEPENDENCIES = $(INTERPFLDEP) $(QTREEDEP) $(INTERPDATADEP) $(GMATHDEP) $(VECTORDEP) $(DBMIDEP) $(GISDEP) +DEPENDENCIES = $(INTERPFLDEP) $(QTREEDEP) $(INTERPDATADEP) $(GMATHDEP) $(RASTERDEP) $(VECTORDEP) $(DBMIDEP) $(GISDEP) EXTRA_INC = $(VECT_INC) $(OPENMP_INCPATH) EXTRA_CFLAGS = $(VECT_CFLAGS) $(OPENMP_CFLAGS) diff --git a/vector/v.surf.rst/main.c b/vector/v.surf.rst/main.c index c4581737eed..7b42e269d0f 100644 --- a/vector/v.surf.rst/main.c +++ b/vector/v.surf.rst/main.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -419,8 +420,8 @@ int main(int argc, char *argv[]) G_warning(_("GRASS GIS is not compiled with OpenMP support, parallel " "computation is disabled.")); #endif - if (threads > 1 && G_find_raster("MASK", G_mapset()) != NULL) { - G_warning(_("Parallel processing disabled due to active MASK.")); + if (threads > 1 && Rast_mask_is_present()) { + G_warning(_("Parallel processing disabled due to active mask.")); threads = 1; } if (devi) { From 808acd35c85c8dfbf21081e141e002f89103a9ae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 13:25:14 -0400 Subject: [PATCH 121/209] CI(deps): Update docker/build-push-action action to v6.9.0 (#4420) --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 824fbe18e1e..f8440e8e71f 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -76,7 +76,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@32945a339266b759abcbdc89316275140b0fc960 # v6.8.0 + uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 with: push: true pull: true From e02b921e45649c2473370b083aded4dd5a5545d4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 13:25:51 -0400 Subject: [PATCH 122/209] CI(deps): Update github/codeql-action action to v3.26.10 (#4419) --- .github/workflows/codeql-analysis.yml | 4 ++-- .github/workflows/python-code-quality.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 14017253fd5..84d857a3505 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -56,7 +56,7 @@ jobs: if: ${{ matrix.language == 'c-cpp' }} - name: Initialize CodeQL - uses: github/codeql-action/init@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 + uses: github/codeql-action/init@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -81,6 +81,6 @@ jobs: run: .github/workflows/build_ubuntu-22.04.sh "${HOME}/install" - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 + uses: github/codeql-action/analyze@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 9febdd990e3..2e156b08417 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -135,7 +135,7 @@ jobs: path: bandit.sarif - name: Upload SARIF File into Security Tab - uses: github/codeql-action/upload-sarif@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 + uses: github/codeql-action/upload-sarif@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 with: sarif_file: bandit.sarif From 33d0d15dee425df2062cd0a28399272a290174e1 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 30 Sep 2024 13:34:30 -0400 Subject: [PATCH 123/209] v.transform: Fix Copy into fix Buffer size issue (#4415) --- vector/v.transform/main.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/vector/v.transform/main.c b/vector/v.transform/main.c index 400cd3ded91..06a7d105881 100644 --- a/vector/v.transform/main.c +++ b/vector/v.transform/main.c @@ -188,8 +188,17 @@ int main(int argc, char *argv[]) if (G_parser(argc, argv)) exit(EXIT_FAILURE); - strcpy(Current.name, vold->answer); - strcpy(Trans.name, vnew->answer); + if (G_strlcpy(Current.name, vold->answer, sizeof(Current.name)) >= + sizeof(Current.name)) { + G_fatal_error(_("Input vector map name <%s> is too long"), + vold->answer); + } + + if (G_strlcpy(Trans.name, vnew->answer, sizeof(Trans.name)) >= + sizeof(Trans.name)) { + G_fatal_error(_("Output vector map name <%s> is too long"), + vnew->answer); + } Vect_check_input_output_name(vold->answer, vnew->answer, G_FATAL_EXIT); From 480e050b206f6239f9a6f67fd9d176f1c83e3ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Mon, 30 Sep 2024 18:50:15 -0400 Subject: [PATCH 124/209] style: Fix redundant-open-modes (UP015) (#4410) --- display/d.mon/render_cmd.py | 2 +- gui/wxpython/core/gconsole.py | 2 +- gui/wxpython/core/render.py | 2 +- gui/wxpython/core/settings.py | 4 ++-- gui/wxpython/core/watchdog.py | 2 +- gui/wxpython/core/workspace.py | 2 +- gui/wxpython/gcp/manager.py | 4 ++-- gui/wxpython/gmodeler/model.py | 2 +- gui/wxpython/gui_core/forms.py | 2 +- gui/wxpython/gui_core/ghelp.py | 4 ++-- gui/wxpython/gui_core/widgets.py | 2 +- gui/wxpython/image2target/ii2t_gis_set.py | 2 +- gui/wxpython/image2target/ii2t_manager.py | 4 ++-- gui/wxpython/location_wizard/wizard.py | 12 +++++------- gui/wxpython/mapdisp/main.py | 4 ++-- gui/wxpython/modules/colorrules.py | 2 +- gui/wxpython/modules/mcalc_builder.py | 2 +- gui/wxpython/photo2image/ip2i_manager.py | 8 ++++---- gui/wxpython/psmap/instructions.py | 2 +- gui/wxpython/vnet/vnet_data.py | 2 +- imagery/i.atcorr/create_iwave.py | 2 +- lib/init/grass.py | 8 ++++---- man/build_html.py | 4 ++-- man/build_rest.py | 4 ++-- pyproject.toml | 1 - python/grass/grassdb/history.py | 6 ++---- python/grass/gunittest/checkers.py | 2 +- python/grass/gunittest/reporters.py | 2 +- python/grass/jupyter/interactivemap.py | 2 +- python/grass/pygrass/gis/__init__.py | 2 +- python/grass/pygrass/modules/grid/grid.py | 2 +- python/grass/pygrass/modules/interface/env.py | 2 +- python/grass/pygrass/raster/category.py | 2 +- python/grass/pygrass/tests/set_mapset.py | 2 +- python/grass/script/core.py | 4 ++-- python/grass/script/utils.py | 4 ++-- python/grass/temporal/register.py | 2 +- python/grass/temporal/stds_import.py | 4 ++-- raster/r.contour/testsuite/test_r_contour.py | 4 ++-- raster/r.in.gdal/testsuite/test_r_in_gdal.py | 2 +- raster/r.what/testsuite/test_r_what.py | 2 +- scripts/d.correlate/d.correlate.py | 4 ++-- scripts/d.frame/d.frame.py | 2 +- scripts/db.univar/db.univar.py | 2 +- scripts/g.extension.all/g.extension.all.py | 2 +- scripts/g.search.modules/g.search.modules.py | 6 +++--- scripts/r.in.wms/wms_gdal_drv.py | 2 +- scripts/r.pack/r.pack.py | 2 +- scripts/v.unpack/v.unpack.py | 2 +- temporal/t.rast.what/t.rast.what.py | 6 +++--- temporal/t.remove/t.remove.py | 2 +- temporal/t.unregister/t.unregister.py | 2 +- 52 files changed, 78 insertions(+), 83 deletions(-) diff --git a/display/d.mon/render_cmd.py b/display/d.mon/render_cmd.py index 7678a1442e4..cf153c0b017 100644 --- a/display/d.mon/render_cmd.py +++ b/display/d.mon/render_cmd.py @@ -39,7 +39,7 @@ def remove_mapfile(mapfile): # read environment variables from file def read_env_file(env_file): width = height = legfile = None - fd = open(env_file, "r") + fd = open(env_file) if fd is None: grass.fatal("Unable to open file '{0}'".format(env_file)) lines = fd.readlines() diff --git a/gui/wxpython/core/gconsole.py b/gui/wxpython/core/gconsole.py index 7575c401c98..092f9bc704a 100644 --- a/gui/wxpython/core/gconsole.py +++ b/gui/wxpython/core/gconsole.py @@ -678,7 +678,7 @@ def load_source(modname, filename): skipInterface = True if os.path.splitext(command[0])[1] in {".py", ".sh"}: try: - with open(command[0], "r") as sfile: + with open(command[0]) as sfile: for line in sfile: if len(line) < 3: continue diff --git a/gui/wxpython/core/render.py b/gui/wxpython/core/render.py index 5b3e3096043..1d4ed6f5386 100644 --- a/gui/wxpython/core/render.py +++ b/gui/wxpython/core/render.py @@ -896,7 +896,7 @@ def GetWindow(self): env["GISDBASE"], env["LOCATION_NAME"], env["MAPSET"], "WIND" ) try: - windfile = open(filename, "r") + windfile = open(filename) except OSError as e: sys.exit( _("Error: Unable to open '%(file)s'. Reason: %(ret)s. wxGUI exited.\n") diff --git a/gui/wxpython/core/settings.py b/gui/wxpython/core/settings.py index 2b2d3b28526..ef3a3031cee 100644 --- a/gui/wxpython/core/settings.py +++ b/gui/wxpython/core/settings.py @@ -922,7 +922,7 @@ def update_nested_dict_by_dict(dictionary, update): return dictionary try: - with open(self.filePath, "r") as f: + with open(self.filePath) as f: update = json.load(f, object_hook=settings_JSON_decode_hook) update_nested_dict_by_dict(settings, update) except json.JSONDecodeError as e: @@ -942,7 +942,7 @@ def _readLegacyFile(self, settings=None): settings = self.userSettings try: - fd = open(self.legacyFilePath, "r") + fd = open(self.legacyFilePath) except OSError: sys.stderr.write( _("Unable to read settings file <%s>\n") % self.legacyFilePath diff --git a/gui/wxpython/core/watchdog.py b/gui/wxpython/core/watchdog.py index 591bb36b477..76302aeea0a 100644 --- a/gui/wxpython/core/watchdog.py +++ b/gui/wxpython/core/watchdog.py @@ -68,7 +68,7 @@ def on_modified(self, event): self.modified_time = timestamp # wait to make sure file writing is done time.sleep(0.1) - with open(event.src_path, "r") as f: + with open(event.src_path) as f: gisrc = {} for line in f: key, val = line.split(":") diff --git a/gui/wxpython/core/workspace.py b/gui/wxpython/core/workspace.py index 9550aa73488..be4eb1fda37 100644 --- a/gui/wxpython/core/workspace.py +++ b/gui/wxpython/core/workspace.py @@ -1742,7 +1742,7 @@ def read(self, parent): :return: list of map layers """ try: - file = open(self.filename, "r") + file = open(self.filename) except OSError: wx.MessageBox( parent=parent, diff --git a/gui/wxpython/gcp/manager.py b/gui/wxpython/gcp/manager.py index a96555fe271..528d710f72c 100644 --- a/gui/wxpython/gcp/manager.py +++ b/gui/wxpython/gcp/manager.py @@ -119,7 +119,7 @@ def __init__(self, parent, giface): self.target_gisrc = os.environ["GISRC"] self.gisrc_dict = {} try: - f = open(self.target_gisrc, "r") + f = open(self.target_gisrc) for line in f: line = line.replace("\n", "").strip() if len(line) < 1: @@ -1603,7 +1603,7 @@ def ReadGCPs(self): GError(parent=self, message=_("target mapwin not defined")) try: - f = open(self.file["points"], "r") + f = open(self.file["points"]) GCPcnt = 0 for line in f: diff --git a/gui/wxpython/gmodeler/model.py b/gui/wxpython/gmodeler/model.py index 59ea791192c..98a7204abbe 100644 --- a/gui/wxpython/gmodeler/model.py +++ b/gui/wxpython/gmodeler/model.py @@ -546,7 +546,7 @@ def _substituteFile(self, item, params=None, checkOnly=False): for finput in self.fileInput: # read lines - fd = open(finput, "r") + fd = open(finput) try: data = self.fileInput[finput] = fd.read() finally: diff --git a/gui/wxpython/gui_core/forms.py b/gui/wxpython/gui_core/forms.py index 74bcc00f85a..1ef623feaf7 100644 --- a/gui/wxpython/gui_core/forms.py +++ b/gui/wxpython/gui_core/forms.py @@ -2588,7 +2588,7 @@ def OnFileLoad(self, event): data = "" try: - f = open(path, "r") + f = open(path) except OSError as e: gcmd.GError( parent=self, diff --git a/gui/wxpython/gui_core/ghelp.py b/gui/wxpython/gui_core/ghelp.py index 72e2564b74d..6713dbcc0a3 100644 --- a/gui/wxpython/gui_core/ghelp.py +++ b/gui/wxpython/gui_core/ghelp.py @@ -274,7 +274,7 @@ def _pageCopyright(self): """Copyright information""" copyfile = os.path.join(os.getenv("GISBASE"), "COPYING") if os.path.exists(copyfile): - copyrightFile = open(copyfile, "r") + copyrightFile = open(copyfile) copytext = copyrightFile.read() copyrightFile.close() else: @@ -303,7 +303,7 @@ def _pageLicense(self): """Licence about""" licfile = os.path.join(os.getenv("GISBASE"), "GPL.TXT") if os.path.exists(licfile): - licenceFile = open(licfile, "r") + licenceFile = open(licfile) license = "".join(licenceFile.readlines()) licenceFile.close() else: diff --git a/gui/wxpython/gui_core/widgets.py b/gui/wxpython/gui_core/widgets.py index c959ebbbf50..5f2582f9b1e 100644 --- a/gui/wxpython/gui_core/widgets.py +++ b/gui/wxpython/gui_core/widgets.py @@ -1566,7 +1566,7 @@ def _loadSettings(self): return data try: - fd = open(self.settingsFile, "r") + fd = open(self.settingsFile) except OSError: return data diff --git a/gui/wxpython/image2target/ii2t_gis_set.py b/gui/wxpython/image2target/ii2t_gis_set.py index 187b01d1740..e63e39ba365 100644 --- a/gui/wxpython/image2target/ii2t_gis_set.py +++ b/gui/wxpython/image2target/ii2t_gis_set.py @@ -543,7 +543,7 @@ def _readGisRC(self): if gisrc and os.path.isfile(gisrc): try: - rc = open(gisrc, "r") + rc = open(gisrc) for line in rc: try: key, val = line.split(":", 1) diff --git a/gui/wxpython/image2target/ii2t_manager.py b/gui/wxpython/image2target/ii2t_manager.py index 1c9958c9cef..06693926ec3 100644 --- a/gui/wxpython/image2target/ii2t_manager.py +++ b/gui/wxpython/image2target/ii2t_manager.py @@ -159,7 +159,7 @@ def __init__(self, parent, giface): self.target_gisrc = os.environ["GISRC"] self.gisrc_dict = {} try: - f = open(self.target_gisrc, "r") + f = open(self.target_gisrc) for line in f: line = line.replace("\n", "").strip() if len(line) < 1: @@ -1627,7 +1627,7 @@ def ReadGCPs(self): GError(parent=self, message=_("target mapwin not defined")) try: - f = open(self.file["control_points"], "r") + f = open(self.file["control_points"]) GCPcnt = 0 for line in f: diff --git a/gui/wxpython/location_wizard/wizard.py b/gui/wxpython/location_wizard/wizard.py index 2cccdf5e301..28ce94fbc48 100644 --- a/gui/wxpython/location_wizard/wizard.py +++ b/gui/wxpython/location_wizard/wizard.py @@ -2543,7 +2543,7 @@ def __readData(self): """Get georeferencing information from tables in $GISBASE/etc/proj""" # read projection and parameters - f = open(os.path.join(globalvar.ETCDIR, "proj", "parms.table"), "r") + f = open(os.path.join(globalvar.ETCDIR, "proj", "parms.table")) self.projections = {} self.projdesc = {} for line in f: @@ -2566,7 +2566,7 @@ def __readData(self): f.close() # read datum definitions - f = open(os.path.join(globalvar.ETCDIR, "proj", "datum.table"), "r") + f = open(os.path.join(globalvar.ETCDIR, "proj", "datum.table")) self.datums = {} paramslist = [] for line in f: @@ -2584,7 +2584,7 @@ def __readData(self): f.close() # read Earth-based ellipsiod definitions - f = open(os.path.join(globalvar.ETCDIR, "proj", "ellipse.table"), "r") + f = open(os.path.join(globalvar.ETCDIR, "proj", "ellipse.table")) self.ellipsoids = {} for line in f: line = line.expandtabs(1) @@ -2600,9 +2600,7 @@ def __readData(self): f.close() # read Planetary ellipsiod definitions - f = open( - os.path.join(globalvar.ETCDIR, "proj", "ellipse.table.solar.system"), "r" - ) + f = open(os.path.join(globalvar.ETCDIR, "proj", "ellipse.table.solar.system")) self.planetary_ellipsoids = {} for line in f: line = line.expandtabs(1) @@ -2618,7 +2616,7 @@ def __readData(self): f.close() # read projection parameter description and parsing table - f = open(os.path.join(globalvar.ETCDIR, "proj", "desc.table"), "r") + f = open(os.path.join(globalvar.ETCDIR, "proj", "desc.table")) self.paramdesc = {} for line in f: line = line.strip() diff --git a/gui/wxpython/mapdisp/main.py b/gui/wxpython/mapdisp/main.py index 1e94d3d8ba2..016261d248d 100644 --- a/gui/wxpython/mapdisp/main.py +++ b/gui/wxpython/mapdisp/main.py @@ -108,7 +108,7 @@ def __init__(self, giface, cmdfile=None, mapfile=None): self.renderMgr = RenderMapMgr(self) # update legend file variable with the one d.mon uses - with open(monFile["env"], "r") as f: + with open(monFile["env"]) as f: lines = f.readlines() for line in lines: if "GRASS_LEGEND_FILE" in line: @@ -123,7 +123,7 @@ def GetLayersFromCmdFile(self): nlayers = 0 try: - fd = open(self.cmdfile, "r") + fd = open(self.cmdfile) lines = fd.readlines() fd.close() # detect d.out.file, delete the line from the cmd file and export diff --git a/gui/wxpython/modules/colorrules.py b/gui/wxpython/modules/colorrules.py index 5093cd7cf25..cad74f38c4b 100644 --- a/gui/wxpython/modules/colorrules.py +++ b/gui/wxpython/modules/colorrules.py @@ -700,7 +700,7 @@ def OnLoadRulesFile(self, event): self.rulesPanel.Clear() - fd = open(path, "r") + fd = open(path) self.ReadColorTable(ctable=fd.read()) fd.close() diff --git a/gui/wxpython/modules/mcalc_builder.py b/gui/wxpython/modules/mcalc_builder.py index e157375b4a4..b0f2f280409 100644 --- a/gui/wxpython/modules/mcalc_builder.py +++ b/gui/wxpython/modules/mcalc_builder.py @@ -759,7 +759,7 @@ def OnLoadExpression(self, event): return try: - fobj = open(path, "r") + fobj = open(path) mctxt = fobj.read() finally: fobj.close() diff --git a/gui/wxpython/photo2image/ip2i_manager.py b/gui/wxpython/photo2image/ip2i_manager.py index e27e763fb2a..5a2a1f14f21 100644 --- a/gui/wxpython/photo2image/ip2i_manager.py +++ b/gui/wxpython/photo2image/ip2i_manager.py @@ -118,7 +118,7 @@ def __init__( self.source_gisrc = os.environ["GISRC"] self.gisrc_dict = {} try: - f = open(self.target_gisrc, "r") + f = open(self.target_gisrc) for line in f: line = line.replace("\n", "").strip() if len(line) < 1: @@ -429,7 +429,7 @@ def __init__( import re try: - fc = open(self.file["camera"], mode="r") + fc = open(self.file["camera"]) fc_count = 0 for line in fc: fc_count += 1 @@ -438,7 +438,7 @@ def __init__( numberOfFiducial = int(line.split()[-1]) dataFiducialX = [] dataFiducialY = [] - fc = open(self.file["camera"], mode="r") + fc = open(self.file["camera"]) fc_count = 0 for line in fc: fc_count += 1 @@ -955,7 +955,7 @@ def ReadGCPs(self): GError(parent=self, message=_("target mapwin not defined")) try: - f = open(self.file["points"], "r") + f = open(self.file["points"]) GCPcnt = 0 for line in f: diff --git a/gui/wxpython/psmap/instructions.py b/gui/wxpython/psmap/instructions.py index 693e8024b57..3c1b2e6d7bb 100644 --- a/gui/wxpython/psmap/instructions.py +++ b/gui/wxpython/psmap/instructions.py @@ -1208,7 +1208,7 @@ def GetImageOrigSize(self, imagePath): # if eps, read info from header if os.path.splitext(fileName)[1].lower() == ".eps": bbInfo = "%%BoundingBox" - file = open(imagePath, "r") + file = open(imagePath) w = h = 0 while file: line = file.readline() diff --git a/gui/wxpython/vnet/vnet_data.py b/gui/wxpython/vnet/vnet_data.py index 6404fcac5c0..9c5b592e043 100644 --- a/gui/wxpython/vnet/vnet_data.py +++ b/gui/wxpython/vnet/vnet_data.py @@ -1070,7 +1070,7 @@ def GetLastModified(self): "head", ) try: - head = open(headPath, "r") + head = open(headPath) for line in head: i = line.find( "MAP DATE:", diff --git a/imagery/i.atcorr/create_iwave.py b/imagery/i.atcorr/create_iwave.py index 8afc6bebd36..a575d8089cd 100644 --- a/imagery/i.atcorr/create_iwave.py +++ b/imagery/i.atcorr/create_iwave.py @@ -59,7 +59,7 @@ def read_input(csvfile): first column is wavelength values are those of the discrete band filter functions """ - infile = open(csvfile, "r") + infile = open(csvfile) # get number of bands and band names bands = infile.readline().split(",") diff --git a/lib/init/grass.py b/lib/init/grass.py index 25486d9426c..233bcf53460 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -496,7 +496,7 @@ def create_gisrc(tmpdir, gisrcrc): def read_gisrc(filename): kv = {} try: - f = open(filename, "r") + f = open(filename) except OSError: return kv @@ -522,7 +522,7 @@ def write_gisrcrc(gisrcrc, gisrc, skip_variable=None): """Reads gisrc file and write to gisrcrc""" debug("Reading %s" % gisrc) number = 0 - with open(gisrc, "r") as f: + with open(gisrc) as f: lines = f.readlines() for line in lines: if skip_variable in line: @@ -535,7 +535,7 @@ def write_gisrcrc(gisrcrc, gisrc, skip_variable=None): def read_env_file(path): kv = {} - f = open(path, "r") + f = open(path) for line in f: k, v = line.split(":", 1) kv[k.strip()] = v.strip() @@ -1098,7 +1098,7 @@ def set_language(grass_config_dir): # Override value is stored in wxGUI preferences file. try: - with open(os.path.join(grass_config_dir, "wx.json"), "r") as json_file: + with open(os.path.join(grass_config_dir, "wx.json")) as json_file: try: language = json.load(json_file)["language"]["locale"]["lc_all"] except KeyError: diff --git a/man/build_html.py b/man/build_html.py index daa38b557f4..c89df29e290 100644 --- a/man/build_html.py +++ b/man/build_html.py @@ -393,7 +393,7 @@ def check_for_desc_override(basename): def read_file(name): - f = open(name, "r") + f = open(name) s = f.read() f.close() return s @@ -476,7 +476,7 @@ def write_html_footer(f, index_url, year=None): def get_desc(cmd): - f = open(cmd, "r") + f = open(cmd) while True: line = f.readline() if not line: diff --git a/man/build_rest.py b/man/build_rest.py index ea1dd7692d2..473827fcc86 100644 --- a/man/build_rest.py +++ b/man/build_rest.py @@ -271,7 +271,7 @@ def check_for_desc_override(basename): def read_file(name): - f = open(name, "r") + f = open(name) s = f.read() f.close() return s @@ -337,7 +337,7 @@ def write_rest_footer(f, index_url): def get_desc(cmd): - f = open(cmd, "r") + f = open(cmd) while True: line = f.readline() if not line: diff --git a/pyproject.toml b/pyproject.toml index 9e430071afc..c6cfac4185b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -258,7 +258,6 @@ ignore = [ "TRY201", # verbose-raise "TRY300", # try-consider-else "TRY301", # raise-within-try - "UP015", # redundant-open-modes "UP030", # format-literals "UP031", # printf-string-formatting "UP032", # f-string diff --git a/python/grass/grassdb/history.py b/python/grass/grassdb/history.py index 60b5459700d..d7c22eb36fc 100644 --- a/python/grass/grassdb/history.py +++ b/python/grass/grassdb/history.py @@ -81,9 +81,7 @@ def _read_from_plain_text(history_path): stores only executed commands.""" content_list = [] try: - with open( - history_path, encoding="utf-8", mode="r", errors="replace" - ) as file_history: + with open(history_path, encoding="utf-8", errors="replace") as file_history: content_list = [ {"command": line.strip(), "command_info": None} for line in file_history ] @@ -287,7 +285,7 @@ def _add_entry_to_JSON(history_path, entry): :param dict entry: entry consisting of 'command' and 'command_info' keys """ try: - with open(history_path, encoding="utf-8", mode="r") as file_history: + with open(history_path, encoding="utf-8") as file_history: existing_data = json.load(file_history) except (OSError, ValueError): existing_data = [] diff --git a/python/grass/gunittest/checkers.py b/python/grass/gunittest/checkers.py index fb46a1deb66..c63f6d08ff0 100644 --- a/python/grass/gunittest/checkers.py +++ b/python/grass/gunittest/checkers.py @@ -638,7 +638,7 @@ def text_file_md5( if prepend_lines: for line in prepend_lines: hasher.update(encode(line)) - with open(filename, "r") as f: + with open(filename) as f: for line in f: # replace platform newlines by standard newline if os.linesep != "\n": diff --git a/python/grass/gunittest/reporters.py b/python/grass/gunittest/reporters.py index 650480a234c..9535e07f871 100644 --- a/python/grass/gunittest/reporters.py +++ b/python/grass/gunittest/reporters.py @@ -51,7 +51,7 @@ def replace_in_file(file_path, pattern, repl): """ # using tmp file to store the replaced content tmp_file_path = file_path + ".tmp" - with open(file_path, "r") as old_file, open(tmp_file_path, "w") as new_file: + with open(file_path) as old_file, open(tmp_file_path, "w") as new_file: for line in old_file: new_file.write(re.sub(pattern=pattern, string=line, repl=repl)) # remove old file since it must not exist for rename/move diff --git a/python/grass/jupyter/interactivemap.py b/python/grass/jupyter/interactivemap.py index 085c2843fe7..d843ac3b6b6 100644 --- a/python/grass/jupyter/interactivemap.py +++ b/python/grass/jupyter/interactivemap.py @@ -178,7 +178,7 @@ def add_to(self, interactive_map): else: import ipyleaflet # pylint: disable=import-outside-toplevel - with open(self._filename, "r", encoding="utf-8") as file: + with open(self._filename, encoding="utf-8") as file: data = json.load(file) # allow using opacity directly to keep interface # consistent for both backends diff --git a/python/grass/pygrass/gis/__init__.py b/python/grass/pygrass/gis/__init__.py index 3f380368d28..d31bc31b972 100644 --- a/python/grass/pygrass/gis/__init__.py +++ b/python/grass/pygrass/gis/__init__.py @@ -430,7 +430,7 @@ def __iter__(self): def read(self): """Return the mapsets in the search path""" try: - with open(self.spath, "r") as f: + with open(self.spath) as f: lines = f.readlines() if lines: return [line.strip() for line in lines] diff --git a/python/grass/pygrass/modules/grid/grid.py b/python/grass/pygrass/modules/grid/grid.py index fb338ca973a..e0dbd309656 100644 --- a/python/grass/pygrass/modules/grid/grid.py +++ b/python/grass/pygrass/modules/grid/grid.py @@ -121,7 +121,7 @@ def read_gisrc(gisrc): ... genv['GISDBASE'])) True """ - with open(gisrc, "r") as gfile: + with open(gisrc) as gfile: gis = dict( [(k.strip(), v.strip()) for k, v in [row.split(":", 1) for row in gfile]] ) diff --git a/python/grass/pygrass/modules/interface/env.py b/python/grass/pygrass/modules/interface/env.py index ad6e4c4800e..1f0519d23c5 100644 --- a/python/grass/pygrass/modules/interface/env.py +++ b/python/grass/pygrass/modules/interface/env.py @@ -13,7 +13,7 @@ def get_env(): gisrc = os.environ.get("GISRC") if gisrc is None: raise RuntimeError("You are not in a GRASS session, GISRC not found.") - with open(gisrc, mode="r") as grc: + with open(gisrc) as grc: return dict( [ (k.strip(), v.strip()) diff --git a/python/grass/pygrass/raster/category.py b/python/grass/pygrass/raster/category.py index cfeb84ddde2..f439d51dcdf 100644 --- a/python/grass/pygrass/raster/category.py +++ b/python/grass/pygrass/raster/category.py @@ -299,7 +299,7 @@ def read_rules(self, filename, sep=":"): """ self.reset() - with open(filename, "r") as f: + with open(filename) as f: for row in f: cat = row.strip().split(sep) if len(cat) == 2: diff --git a/python/grass/pygrass/tests/set_mapset.py b/python/grass/pygrass/tests/set_mapset.py index f9d4a96fabf..105735efa5a 100644 --- a/python/grass/pygrass/tests/set_mapset.py +++ b/python/grass/pygrass/tests/set_mapset.py @@ -13,7 +13,7 @@ def read_gisrc(gisrcpath): - gisrc = open(gisrcpath, "r") + gisrc = open(gisrcpath) diz = {} for row in gisrc: key, val = row.split(":") diff --git a/python/grass/script/core.py b/python/grass/script/core.py index 40709a11e80..ee90a41d4ef 100644 --- a/python/grass/script/core.py +++ b/python/grass/script/core.py @@ -1066,7 +1066,7 @@ def _text_to_key_value_dict( {'a': ['Hello'], 'c': [1, 2, 3, 4, 5], 'b': [1.0], 'd': ['hello', 8, 0.1]} """ - text = open(filename, "r").readlines() + text = open(filename).readlines() kvdict = KeyValue() for line in text: @@ -1276,7 +1276,7 @@ def region_env(region3d=False, flags=None, env=None, **kwargs): windfile = os.path.join( gis_env["GISDBASE"], gis_env["LOCATION_NAME"], gis_env["MAPSET"], "WIND" ) - with open(windfile, "r") as fd: + with open(windfile) as fd: grass_region = "" for line in fd: key, value = (x.strip() for x in line.split(":", 1)) diff --git a/python/grass/script/utils.py b/python/grass/script/utils.py index 2868e3111e6..aa7d53375dd 100644 --- a/python/grass/script/utils.py +++ b/python/grass/script/utils.py @@ -91,8 +91,8 @@ def diff_files(filename_a, filename_b): import difflib differ = difflib.Differ() - fh_a = open(filename_a, "r") - fh_b = open(filename_b, "r") + fh_a = open(filename_a) + fh_b = open(filename_b) return list(differ.compare(fh_a.readlines(), fh_b.readlines())) diff --git a/python/grass/temporal/register.py b/python/grass/temporal/register.py index 0cd339946b9..8b7852ab557 100644 --- a/python/grass/temporal/register.py +++ b/python/grass/temporal/register.py @@ -161,7 +161,7 @@ def register_maps_in_space_time_dataset( if hasattr(file, "readline"): fd = file else: - fd = open(file, "r") + fd = open(file) line = True while True: diff --git a/python/grass/temporal/stds_import.py b/python/grass/temporal/stds_import.py index b8223c8ee83..006ee6a387e 100644 --- a/python/grass/temporal/stds_import.py +++ b/python/grass/temporal/stds_import.py @@ -372,7 +372,7 @@ def import_stds( fs = "|" maplist = [] mapset = get_current_mapset() - list_file = open(list_file_name, "r") + list_file = open(list_file_name) new_list_file = open(new_list_file_name, "w") # get number of lines to correctly form the suffix @@ -426,7 +426,7 @@ def import_stds( # Read the init file fs = "=" init = {} - init_file = open(init_file_name, "r") + init_file = open(init_file_name) while True: line = init_file.readline() if not line: diff --git a/raster/r.contour/testsuite/test_r_contour.py b/raster/r.contour/testsuite/test_r_contour.py index 9fc0fc17469..c9ee4c9876a 100644 --- a/raster/r.contour/testsuite/test_r_contour.py +++ b/raster/r.contour/testsuite/test_r_contour.py @@ -62,7 +62,7 @@ def test_raster_contour(self): self.assertModule("v.db.select", map=self.output, file="testReport") self.assertFileExists("testReport", msg="testReport file was not created") if os.path.isfile("testReport"): - file = open("testReport", "r") + file = open("testReport") fileData = file.read() self.assertMultiLineEqual(fileData, self.test_ref_str) file.close() @@ -87,7 +87,7 @@ def test_raster_contour_cut(self): self.assertModule("v.db.select", map=self.output + "_cut", file="testReportCut") self.assertFileExists("testReportCut", msg="testReportCut file was not created") if os.path.isfile("testReportCut"): - file = open("testReportCut", "r") + file = open("testReportCut") fileData = file.read() self.assertMultiLineEqual(fileData, self.test_ref_str) file.close() diff --git a/raster/r.in.gdal/testsuite/test_r_in_gdal.py b/raster/r.in.gdal/testsuite/test_r_in_gdal.py index 2390e9838cd..477ffca89c8 100644 --- a/raster/r.in.gdal/testsuite/test_r_in_gdal.py +++ b/raster/r.in.gdal/testsuite/test_r_in_gdal.py @@ -307,7 +307,7 @@ def test_netCDF_3d_5(self): test_gdal_import_map.0000000105 """ - text_from_file = open("map_names_file.txt", "r").read() + text_from_file = open("map_names_file.txt").read() self.assertLooksLike(map_list, text_from_file) diff --git a/raster/r.what/testsuite/test_r_what.py b/raster/r.what/testsuite/test_r_what.py index fcc312e6284..68bfdeea376 100644 --- a/raster/r.what/testsuite/test_r_what.py +++ b/raster/r.what/testsuite/test_r_what.py @@ -510,7 +510,7 @@ def test_raster_what_csv(self): ) self.assertFileExists(filename="result.csv", msg="CSV file was not created") if os.path.isfile("result.csv"): - file = open("result.csv", "r") + file = open("result.csv") fileData = file.read() self.assertLooksLike( actual=fileData, diff --git a/scripts/d.correlate/d.correlate.py b/scripts/d.correlate/d.correlate.py index af681cce545..1068733a11b 100755 --- a/scripts/d.correlate/d.correlate.py +++ b/scripts/d.correlate/d.correlate.py @@ -73,7 +73,7 @@ def main(): gcore.run_command("r.stats", flags="cnA", input=(i, j), stdout=ofile) ofile.close() - ifile = open(tmpfile, "r") + ifile = open(tmpfile) first = True for line in ifile: f = line.rstrip("\r\n").split(" ") @@ -95,7 +95,7 @@ def main(): p = gcore.feed_command("d.graph", color=color) ofile = p.stdin - ifile = open(tmpfile, "r") + ifile = open(tmpfile) for line in ifile: f = line.rstrip("\r\n").split(" ") x = float(f[0]) diff --git a/scripts/d.frame/d.frame.py b/scripts/d.frame/d.frame.py index e9b44b21650..ff77316f0ec 100755 --- a/scripts/d.frame/d.frame.py +++ b/scripts/d.frame/d.frame.py @@ -91,7 +91,7 @@ def check_monitor(): def read_monitor_file(monitor, ftype="env"): mfile = check_monitor_file(monitor, ftype) try: - fd = open(mfile, "r") + fd = open(mfile) except OSError as e: fatal(_("Unable to get monitor info. %s"), e) diff --git a/scripts/db.univar/db.univar.py b/scripts/db.univar/db.univar.py index f941be42140..97dfbdb7dbe 100755 --- a/scripts/db.univar/db.univar.py +++ b/scripts/db.univar/db.univar.py @@ -77,7 +77,7 @@ def cleanup(): def sortfile(infile, outfile): - inf = open(infile, "r") + inf = open(infile) outf = open(outfile, "w") if gs.find_program("sort", "--help"): diff --git a/scripts/g.extension.all/g.extension.all.py b/scripts/g.extension.all/g.extension.all.py index 43d50073178..1b0a2a88108 100644 --- a/scripts/g.extension.all/g.extension.all.py +++ b/scripts/g.extension.all/g.extension.all.py @@ -64,7 +64,7 @@ def get_extensions(): return [] # read XML file - fo = open(fXML, "r") + fo = open(fXML) try: tree = ET.fromstring(fo.read()) except Exception as e: diff --git a/scripts/g.search.modules/g.search.modules.py b/scripts/g.search.modules/g.search.modules.py index 574b8133a9e..cb40cbdced5 100755 --- a/scripts/g.search.modules/g.search.modules.py +++ b/scripts/g.search.modules/g.search.modules.py @@ -201,7 +201,7 @@ def _search_module( WXGUIDIR = os.path.join(os.getenv("GISBASE"), "gui", "wxpython") filename = os.path.join(WXGUIDIR, "xml", "module_items.xml") - menudata_file = open(filename, "r") + menudata_file = open(filename) menudata = ET.parse(menudata_file) menudata_file.close() @@ -212,7 +212,7 @@ def _search_module( if os.getenv("GRASS_ADDON_BASE"): 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) addon_menudata = ET.parse(addon_menudata_file) addon_menudata_file.close() addon_items = addon_menudata.findall("task") @@ -221,7 +221,7 @@ def _search_module( # add system-wide installed addons to modules list 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) addon_menudata_s = ET.parse(addon_menudata_file_s) addon_menudata_file_s.close() addon_items_s = addon_menudata_s.findall("task") diff --git a/scripts/r.in.wms/wms_gdal_drv.py b/scripts/r.in.wms/wms_gdal_drv.py index 69a49ca5429..830be2b593e 100644 --- a/scripts/r.in.wms/wms_gdal_drv.py +++ b/scripts/r.in.wms/wms_gdal_drv.py @@ -155,7 +155,7 @@ def _download(self): xml_file = self._createXML() # print xml file content for debug level 1 - file = open(xml_file, "r") + file = open(xml_file) gs.debug("WMS request XML:\n%s" % file.read(), 1) file.close() diff --git a/scripts/r.pack/r.pack.py b/scripts/r.pack/r.pack.py index bb3332101ee..5029f93c6d2 100644 --- a/scripts/r.pack/r.pack.py +++ b/scripts/r.pack/r.pack.py @@ -95,7 +95,7 @@ def main(): 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) as f: for r in f: map, mapset = r.split("@") map_basedir = os.path.sep.join( diff --git a/scripts/v.unpack/v.unpack.py b/scripts/v.unpack/v.unpack.py index 419e133b195..ea75d443b57 100644 --- a/scripts/v.unpack/v.unpack.py +++ b/scripts/v.unpack/v.unpack.py @@ -218,7 +218,7 @@ def main(): todb = dbconn["database"] # return the list of old connection for extract layer number and key - dbln = open(os.path.join(new_dir, "dbln"), "r") + dbln = open(os.path.join(new_dir, "dbln")) dbnlist = dbln.readlines() dbln.close() # check if dbf or sqlite directory exists diff --git a/temporal/t.rast.what/t.rast.what.py b/temporal/t.rast.what/t.rast.what.py index 39e63180abf..b3cec73a538 100755 --- a/temporal/t.rast.what/t.rast.what.py +++ b/temporal/t.rast.what/t.rast.what.py @@ -389,7 +389,7 @@ def one_point_per_row_output( file_name = output_files[count] gs.verbose(_("Transforming r.what output file %s") % (file_name)) map_list = output_time_list[count] - in_file = open(file_name, "r") + in_file = open(file_name) for line in in_file: line = line.split(separator) if vcat: @@ -466,7 +466,7 @@ def one_point_per_col_output( for count in range(len(output_files)): file_name = output_files[count] gs.verbose(_("Transforming r.what output file %s") % (file_name)) - in_file = open(file_name, "r") + in_file = open(file_name) lines = in_file.readlines() matrix = [] @@ -563,7 +563,7 @@ def one_point_per_timerow_output( file_name = output_files[count] gs.verbose("Transforming r.what output file %s" % (file_name)) map_list = output_time_list[count] - in_file = open(file_name, "r") + in_file = open(file_name) if write_header: if first is True: diff --git a/temporal/t.remove/t.remove.py b/temporal/t.remove/t.remove.py index b5c1164cef4..91fa58dde7a 100755 --- a/temporal/t.remove/t.remove.py +++ b/temporal/t.remove/t.remove.py @@ -102,7 +102,7 @@ def main(): # Read the dataset list from file if file: - fd = open(file, "r") + fd = open(file) line = True while True: diff --git a/temporal/t.unregister/t.unregister.py b/temporal/t.unregister/t.unregister.py index 7aef44ed12b..b39b7b9819f 100755 --- a/temporal/t.unregister/t.unregister.py +++ b/temporal/t.unregister/t.unregister.py @@ -108,7 +108,7 @@ def main(): # Read the map list from file if file: - fd = open(file, "r") + fd = open(file) line = True while True: From afbc3ae7b441575faa633ac7f409e3bda3c9dd9a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 23:38:10 +0000 Subject: [PATCH 125/209] CI(deps): Lock file maintenance (#4416) --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index fcda6ed01dd..51f61fb86f9 100644 --- a/flake.lock +++ b/flake.lock @@ -19,11 +19,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1726871744, - "narHash": "sha256-V5LpfdHyQkUF7RfOaDPrZDP+oqz88lTJrMT1+stXNwo=", + "lastModified": 1727648392, + "narHash": "sha256-VTlVv1nSxImFxY6RPQpNZxvEOQ0u5s1wBFDgixySNDo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "a1d92660c6b3b7c26fb883500a80ea9d33321be2", + "rev": "4e0c36e4dd53f35d5a6385bdae88895ec5832f70", "type": "github" }, "original": { From e427da09ba2e56d6d75bdd1d8dc5235fc31d6384 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Mon, 30 Sep 2024 19:44:38 -0400 Subject: [PATCH 126/209] wxGUI: Fixed flake8 E722: bare 'except' in wxpython/gcp/ (#4392) --- .flake8 | 1 - gui/wxpython/gcp/manager.py | 14 -------------- 2 files changed, 15 deletions(-) diff --git a/.flake8 b/.flake8 index c3256ec22bf..ceee4512ca2 100644 --- a/.flake8 +++ b/.flake8 @@ -25,7 +25,6 @@ per-file-ignores = doc/python/m.distance.py: E501 doc/gui/wxpython/example/dialogs.py: F401 gui/scripts/d.wms.py: E501 - gui/wxpython/gcp/manager.py: E722 gui/wxpython/gui_core/*: E722 gui/wxpython/gui_core/dialogs.py: E722 gui/wxpython/gui_core/forms.py: E722 diff --git a/gui/wxpython/gcp/manager.py b/gui/wxpython/gcp/manager.py index 528d710f72c..3b6dd398b51 100644 --- a/gui/wxpython/gcp/manager.py +++ b/gui/wxpython/gcp/manager.py @@ -880,20 +880,6 @@ def OnSrcSelection(self, event): else: wx.FindWindowById(wx.ID_FORWARD).Enable(True) - try: - # set computational region to match selected map and zoom display - # to region - if maptype == "raster": - p = RunCommand("g.region", "raster=src_map") - elif maptype == "vector": - p = RunCommand("g.region", "vector=src_map") - - if p.returncode == 0: - print("returncode = ", str(p.returncode)) - self.parent.Map.region = self.parent.Map.GetRegion() - except: - pass - def OnTgtRastSelection(self, event): """Source map to display selected""" global tgt_map From 3e53e34a922c51fd84b39e2cb6569070cf8761eb Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Mon, 30 Sep 2024 23:58:29 -0400 Subject: [PATCH 127/209] wxGUI: Fixed F841 in ii2t_manager.py (#4418) * fixed e722 in ii2t_manager * revert * fixed F841 in iit2t_manager.py * removed point from ii2t_mapdisplay * updated BusyInfo to use context manager --- gui/wxpython/image2target/ii2t_manager.py | 62 +++++++++----------- gui/wxpython/image2target/ii2t_mapdisplay.py | 2 - 2 files changed, 27 insertions(+), 37 deletions(-) diff --git a/gui/wxpython/image2target/ii2t_manager.py b/gui/wxpython/image2target/ii2t_manager.py index 06693926ec3..9284c3a2b2a 100644 --- a/gui/wxpython/image2target/ii2t_manager.py +++ b/gui/wxpython/image2target/ii2t_manager.py @@ -1781,22 +1781,20 @@ def OnGeorect(self, event): else: flags = "a" - busy = wx.BusyInfo(_("Rectifying images, please wait..."), parent=self) - wx.GetApp().Yield() - - ret, msg = RunCommand( - "i.ortho.rectify", - parent=self, - getErrorMsg=True, - quiet=True, - group=self.xygroup, - extension=self.extension, - method=self.gr_method, - angle=self.grwiz.cam_angle, - flags=flags, - ) + with wx.BusyInfo(_("Rectifying images, please wait..."), parent=self): + wx.GetApp().Yield() - del busy + ret, msg = RunCommand( + "i.ortho.rectify", + parent=self, + getErrorMsg=True, + quiet=True, + group=self.xygroup, + extension=self.extension, + method=self.gr_method, + angle=self.grwiz.cam_angle, + flags=flags, + ) # provide feedback on failure if ret != 0: @@ -1828,23 +1826,21 @@ def OnGeorect(self, event): ) ret = msg = "" - busy = wx.BusyInfo( + with wx.BusyInfo( _("Rectifying vector map <%s>, please wait...") % vect, parent=self - ) - wx.GetApp().Yield() - - ret, msg = RunCommand( - "v.rectify", - parent=self, - getErrorMsg=True, - quiet=True, - input=vect, - output=self.outname, - group=self.xygroup, - order=self.gr_order, - ) - - del busy + ): + wx.GetApp().Yield() + + ret, msg = RunCommand( + "v.rectify", + parent=self, + getErrorMsg=True, + quiet=True, + input=vect, + output=self.outname, + group=self.xygroup, + order=self.gr_order, + ) # provide feedback on failure if ret != 0: @@ -1971,7 +1967,6 @@ def OnGROrder(self, event): elif self.gr_order == 2: minNumOfItems = 6 - diff = 6 - numOfItems # self.SetStatusText(_( # "Insufficient points, 6+ points needed for 2nd order")) @@ -2270,7 +2265,6 @@ def OnZoomToTarget(self, event): def OnZoomMenuGCP(self, event): """Popup Zoom menu""" - point = wx.GetMousePosition() zoommenu = Menu() # Add items to the menu @@ -3376,7 +3370,6 @@ def UpdateSettings(self): srcrenderVector = False tgtrender = False tgtrenderVector = False - reload_target = False if self.new_src_map != src_map: # remove old layer layers = self.parent.grwiz.SrcMap.GetListOfLayers() @@ -3414,7 +3407,6 @@ def UpdateSettings(self): del layers[0] layers = self.parent.grwiz.TgtMap.GetListOfLayers() # self.parent.grwiz.TgtMap.DeleteAllLayers() - reload_target = True tgt_map["raster"] = self.new_tgt_map["raster"] tgt_map["vector"] = self.new_tgt_map["vector"] diff --git a/gui/wxpython/image2target/ii2t_mapdisplay.py b/gui/wxpython/image2target/ii2t_mapdisplay.py index c148eb314d2..9ee3b77d118 100644 --- a/gui/wxpython/image2target/ii2t_mapdisplay.py +++ b/gui/wxpython/image2target/ii2t_mapdisplay.py @@ -474,7 +474,6 @@ def PrintMenu(self, event): """ Print options and output menu for map display """ - point = wx.GetMousePosition() printmenu = Menu() # Add items to the menu setup = wx.MenuItem(printmenu, wx.ID_ANY, _("Page setup")) @@ -518,7 +517,6 @@ def SaveDisplayRegion(self, event): def OnZoomMenu(self, event): """Popup Zoom menu""" - point = wx.GetMousePosition() zoommenu = Menu() # Add items to the menu From 25619dd06a5dba16414d279c9d895b7e7f444450 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Tue, 1 Oct 2024 01:36:16 -0400 Subject: [PATCH 128/209] wxGUI: Fix E722 do not use bare 'except' warnings in `gui_core/` (#4396) * updated 722 from gui_core * updated flake8 * updated ghelp v2 * updated ghelp v3 * Update gui/wxpython/gui_core/dialogs.py Co-authored-by: Anna Petrasova * removed prints * Update dialogs.py * updated indexerror * updated exception * Update .flake8 * Update .flake8 --------- Co-authored-by: Anna Petrasova --- .flake8 | 6 ------ gui/wxpython/gui_core/dialogs.py | 4 ++-- gui/wxpython/gui_core/forms.py | 2 +- gui/wxpython/gui_core/ghelp.py | 14 +++++++------- gui/wxpython/gui_core/gselect.py | 2 +- gui/wxpython/gui_core/widgets.py | 2 +- 6 files changed, 12 insertions(+), 18 deletions(-) diff --git a/.flake8 b/.flake8 index ceee4512ca2..580aa6670a1 100644 --- a/.flake8 +++ b/.flake8 @@ -25,12 +25,6 @@ per-file-ignores = doc/python/m.distance.py: E501 doc/gui/wxpython/example/dialogs.py: F401 gui/scripts/d.wms.py: E501 - gui/wxpython/gui_core/*: E722 - gui/wxpython/gui_core/dialogs.py: E722 - gui/wxpython/gui_core/forms.py: E722 - gui/wxpython/gui_core/ghelp.py: E722 - gui/wxpython/gui_core/gselect.py: E722 - gui/wxpython/gui_core/widgets.py: E722 gui/wxpython/image2target/*: F841, E722 gui/wxpython/image2target/g.gui.image2target.py: E501, F841 gui/wxpython/iscatt/*: F841, E722, F405, F403 diff --git a/gui/wxpython/gui_core/dialogs.py b/gui/wxpython/gui_core/dialogs.py index f7c7711cadf..cd2a8dcc24d 100644 --- a/gui/wxpython/gui_core/dialogs.py +++ b/gui/wxpython/gui_core/dialogs.py @@ -1213,7 +1213,7 @@ def _filter(self, data): try: if re.compile(self.flt_pattern).search(dt): flt_data.append(dt) - except: + except re.error: pass return flt_data @@ -1656,7 +1656,7 @@ def OnFilter(self, event): try: if re.compile(event.GetString()).search(layer): list.append(layer) - except: + except re.error: pass list = naturally_sorted(list) diff --git a/gui/wxpython/gui_core/forms.py b/gui/wxpython/gui_core/forms.py index 1ef623feaf7..c1123497abf 100644 --- a/gui/wxpython/gui_core/forms.py +++ b/gui/wxpython/gui_core/forms.py @@ -2016,7 +2016,7 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar # check wildcard try: fExt = os.path.splitext(p.get("key_desc", ["*.*"])[0])[1] - except: + except IndexError: fExt = None if not fExt: fMask = "*" diff --git a/gui/wxpython/gui_core/ghelp.py b/gui/wxpython/gui_core/ghelp.py index 6713dbcc0a3..0c4f6cdadfb 100644 --- a/gui/wxpython/gui_core/ghelp.py +++ b/gui/wxpython/gui_core/ghelp.py @@ -566,15 +566,15 @@ def _langString(self, k, v): allStr = "%s :" % k.upper() try: allStr += _(" %d translated") % v["good"] - except: + except KeyError: pass try: allStr += _(" %d fuzzy") % v["fuzzy"] - except: + except KeyError: pass try: allStr += _(" %d untranslated") % v["bad"] - except: + except KeyError: pass return allStr @@ -589,7 +589,7 @@ def _langBox(self, par, k, v): ) tgood.SetForegroundColour(wx.Colour(35, 142, 35)) langBox.Add(tgood) - except: + except KeyError: tgood = StaticText(parent=par, id=wx.ID_ANY, label="") langBox.Add(tgood) try: @@ -598,7 +598,7 @@ def _langBox(self, par, k, v): ) tfuzzy.SetForegroundColour(wx.Colour(255, 142, 0)) langBox.Add(tfuzzy) - except: + except KeyError: tfuzzy = StaticText(parent=par, id=wx.ID_ANY, label="") langBox.Add(tfuzzy) try: @@ -607,7 +607,7 @@ def _langBox(self, par, k, v): ) tbad.SetForegroundColour(wx.Colour(255, 0, 0)) langBox.Add(tbad) - except: + except KeyError: tbad = StaticText(parent=par, id=wx.ID_ANY, label="") langBox.Add(tbad) return langBox @@ -844,7 +844,7 @@ def fillContentsFromFile(self, htmlFile, skipDescription=True): contents.append(line) self.SetPage("".join(contents)) self.loaded = True - except: # The Manual file was not found + except Exception: # The Manual file was not found self.loaded = False diff --git a/gui/wxpython/gui_core/gselect.py b/gui/wxpython/gui_core/gselect.py index af71cc4f550..ec873f60eb4 100644 --- a/gui/wxpython/gui_core/gselect.py +++ b/gui/wxpython/gui_core/gselect.py @@ -484,7 +484,7 @@ def GetElementList(self, elements=None, exclude=False): try: self.seltree.EnsureVisible(item) self.seltree.SelectItem(item) - except: + except Exception: pass def _getElementList(self, element, mapsets=None, elements=None, exclude=False): diff --git a/gui/wxpython/gui_core/widgets.py b/gui/wxpython/gui_core/widgets.py index 5f2582f9b1e..dc9041e3578 100644 --- a/gui/wxpython/gui_core/widgets.py +++ b/gui/wxpython/gui_core/widgets.py @@ -752,7 +752,7 @@ def _validate(self, win): if text: try: datetime.strptime(text, "%Y-%m-%d") - except: + except ValueError: self._notvalid() return False From 63829498814e0716fb6d26fe1442d81ddd82cb9d Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Tue, 1 Oct 2024 10:48:54 -0400 Subject: [PATCH 129/209] v.generalize: Fix Resource Leak issue in displacement.c (#4422) * fix Resource Leak * fix for points --- vector/v.generalize/displacement.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vector/v.generalize/displacement.c b/vector/v.generalize/displacement.c index bc7a3f15170..a4d599080e4 100644 --- a/vector/v.generalize/displacement.c +++ b/vector/v.generalize/displacement.c @@ -310,6 +310,8 @@ int snakes_displacement(struct Map_info *In, struct Map_info *Out, matrix_free(&fy); matrix_free(&dx_old); matrix_free(&dy_old); + Vect_destroy_cats_struct(Cats); + Vect_destroy_line_struct(Points); return 0; } From 13cda735ce297be1f45aca9da5c9995413a94abb Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Tue, 1 Oct 2024 14:34:29 -0400 Subject: [PATCH 130/209] wxGUI: Fixed unused 'wizard' variable - F841 in image2target/ (#4400) --- .flake8 | 2 +- gui/wxpython/image2target/g.gui.image2target.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.flake8 b/.flake8 index 580aa6670a1..d704112048f 100644 --- a/.flake8 +++ b/.flake8 @@ -26,7 +26,7 @@ per-file-ignores = doc/gui/wxpython/example/dialogs.py: F401 gui/scripts/d.wms.py: E501 gui/wxpython/image2target/*: F841, E722 - gui/wxpython/image2target/g.gui.image2target.py: E501, F841 + gui/wxpython/image2target/g.gui.image2target.py: E501 gui/wxpython/iscatt/*: F841, E722, F405, F403 gui/wxpython/lmgr/frame.py: F841, E722 # layertree still includes some formatting issues (it is ignored by Black) diff --git a/gui/wxpython/image2target/g.gui.image2target.py b/gui/wxpython/image2target/g.gui.image2target.py index 37d33c2d70e..e2704dc371b 100755 --- a/gui/wxpython/image2target/g.gui.image2target.py +++ b/gui/wxpython/image2target/g.gui.image2target.py @@ -64,7 +64,8 @@ def main(): app = wx.App() - wizard = GCPWizard(parent=None, giface=StandaloneGrassInterface()) + GCPWizard(parent=None, giface=StandaloneGrassInterface()) + app.MainLoop() From ed10037b84e790b32cfabee62ab61c45be6ac875 Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Tue, 1 Oct 2024 14:48:11 -0400 Subject: [PATCH 131/209] tests: fix tests that were actually not testing anything (#4349) --- .../v.centroids/testsuite/test_v_centroids.py | 34 ++++++++++++------- .../v.what.vect/testsuite/test_v_what_vect.py | 17 +++++----- vector/v.select/testsuite/test_v_select.py | 33 +++++------------- 3 files changed, 39 insertions(+), 45 deletions(-) diff --git a/scripts/v.centroids/testsuite/test_v_centroids.py b/scripts/v.centroids/testsuite/test_v_centroids.py index 4b0654748a5..a7f56464ef6 100644 --- a/scripts/v.centroids/testsuite/test_v_centroids.py +++ b/scripts/v.centroids/testsuite/test_v_centroids.py @@ -12,37 +12,47 @@ class TestVCentroids(TestCase): """Test v.centroids script""" - mapName = "busroute11" - outRouteMap = "busroute11_boundary" - fromType = "line" - toType = "boundary" - outAreaMap = "busroute11_area" + region_line = "region_line" + region_boundary = "region_boundary" + region_area = "region_area" + output = "output" @classmethod def setUpClass(cls): """Create an area from a closed line""" + cls.runModule("v.in.region", output=cls.region_line, type="line") + cls.runModule("v.in.region", output=cls.region_area, type="area") cls.runModule( "v.type", - input=cls.mapName, - output=cls.outRouteMap, - from_type=cls.fromType, - to_type=cls.toType, + input=cls.region_line, + output=cls.region_boundary, + from_type="line", + to_type="boundary", ) @classmethod def tearDownClass(cls): """Remove the generated maps""" cls.runModule( - "g.remove", flags="f", type="vector", name=(cls.outRouteMap, cls.outAreaMap) + "g.remove", + flags="f", + type="vector", + name=(cls.region_line, cls.region_area, cls.region_boundary), ) + def tearDown(self): + """Remove the generated maps""" + self.runModule("g.remove", flags="f", type="vector", name=self.output) + def test_area(self): """Adds missing centroids to closed boundaries test""" module = SimpleModule( - "v.centroids", input=self.outRouteMap, output=self.outAreaMap + "v.centroids", input=self.region_boundary, output=self.output ) self.assertModule(module) - self.assertVectorExists(self.outAreaMap) + self.assertVectorInfoEqualsVectorInfo( + self.output, self.region_area, precision=1e-6 + ) if __name__ == "__main__": diff --git a/scripts/v.what.vect/testsuite/test_v_what_vect.py b/scripts/v.what.vect/testsuite/test_v_what_vect.py index 09ade33668f..2385a71c400 100644 --- a/scripts/v.what.vect/testsuite/test_v_what_vect.py +++ b/scripts/v.what.vect/testsuite/test_v_what_vect.py @@ -9,7 +9,6 @@ from grass.gunittest.gmodules import SimpleModule from grass.script.core import run_command -from grass.script.utils import decode class TestVWhatVect(TestCase): @@ -29,20 +28,20 @@ def tearDownClass(cls): def test_what_vect(self): """Uploads vector values""" - run_command("v.db.addcolumn", map=self.mapName, columns="urb_name varchar(25)") + run_command("v.db.addcolumn", map=self.mapName, columns="geology_cat integer") module = SimpleModule( "v.what.vect", map=self.mapName, - query_map="urbanarea", - column="urb_name", - query_column="NAME", + query_map="geology", + column="geology_cat", + query_column="cat", ) self.assertModule(module) - - m = SimpleModule("v.db.select", map=self.mapName) - self.assertModule(m) - self.assertRegex(decode(m.outputs.stdout), "urb_name") + minmax = "min=11\nmax=1810" + self.assertVectorFitsUnivar( + map=self.mapName, column="geology_cat", reference=minmax + ) if __name__ == "__main__": diff --git a/vector/v.select/testsuite/test_v_select.py b/vector/v.select/testsuite/test_v_select.py index c74cdb53761..b8564505a6a 100644 --- a/vector/v.select/testsuite/test_v_select.py +++ b/vector/v.select/testsuite/test_v_select.py @@ -13,22 +13,9 @@ class TestRasterReport(TestCase): - binput = "bridges" + binput = "zipcodes" ainput = "geology" output = "testvselect" - overlap = "geonames_wake" - disjoint = "schools_wake" - equals = "streets_wake" - touches = "zipcodes_wake" - within = "geonames_wake" - - @classmethod - def setUpClass(cls): - cls.use_temp_region() - - @classmethod - def tearDownClass(cls): - cls.del_temp_region() def tearDown(cls): cls.runModule("g.remove", type="vector", flags="f", name=cls.output) @@ -42,8 +29,8 @@ def test_opo(self): output=self.output, operator="overlap", ) - topology = {"points": 1088, "lines": 0, "areas": 0} - self.assertVectorFitsTopoInfo(self.overlap, topology) + topology = {"areas": 97} + self.assertVectorFitsTopoInfo(self.output, topology) def test_opd(self): """Testign operator disjoint""" @@ -54,8 +41,8 @@ def test_opd(self): output=self.output, operator="disjoint", ) - topology = {"points": 167, "lines": 0, "areas": 0} - self.assertVectorFitsTopoInfo(self.disjoint, topology) + topology = {"areas": 1770} + self.assertVectorFitsTopoInfo(self.output, topology) def test_ope(self): """Testing operator equals""" @@ -66,8 +53,7 @@ def test_ope(self): output=self.output, operator="equals", ) - topology = {"points": 0, "lines": 49746, "areas": 0} - self.assertVectorFitsTopoInfo(self.equals, topology) + self.assertVectorDoesNotExist(self.output) def test_opt(self): """Testing operator touches""" @@ -78,8 +64,7 @@ def test_opt(self): output=self.output, operator="touches", ) - topology = {"points": 0, "lines": 0, "areas": 48} - self.assertVectorFitsTopoInfo(self.touches, topology) + self.assertVectorDoesNotExist(self.output) def test_opw(self): """Testing operator within""" @@ -90,8 +75,8 @@ def test_opw(self): output=self.output, operator="within", ) - topology = {"points": 1088, "lines": 0, "areas": 0} - self.assertVectorFitsTopoInfo(self.within, topology) + topology = {"areas": 17} + self.assertVectorFitsTopoInfo(self.output, topology) if __name__ == "__main__": From e9768eb98006d002cc92e9d047e17797a4d7a79b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 14:52:28 -0400 Subject: [PATCH 132/209] CI(deps): Update codecov/codecov-action action to v4.6.0 (#4425) --- .github/workflows/pytest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 4ff31728abe..0123b01fc0e 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -108,7 +108,7 @@ jobs: coverage html - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 + uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0 with: verbose: true flags: pytest-python-${{ matrix.python-version }} From 3f61cd7625f728ff0795023e97529e2ec896c5cc Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Tue, 1 Oct 2024 17:01:55 -0400 Subject: [PATCH 133/209] wxGUI: Fixed E722 in ii2t_gis_set.py (#4417) * fix 722 in iit2t_gis_set * added ii2t-manager * Update ii2t_gis_set.py * Update ii2t_manager.py * Update ii2t_gis_set.py --- gui/wxpython/image2target/ii2t_gis_set.py | 12 ++++++------ gui/wxpython/image2target/ii2t_manager.py | 14 -------------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/gui/wxpython/image2target/ii2t_gis_set.py b/gui/wxpython/image2target/ii2t_gis_set.py index e63e39ba365..4e5a5aee200 100644 --- a/gui/wxpython/image2target/ii2t_gis_set.py +++ b/gui/wxpython/image2target/ii2t_gis_set.py @@ -96,7 +96,7 @@ def __init__(self, parent=None, id=wx.ID_ANY, style=wx.DEFAULT_FRAME_STYLE): self.hbitmap = wx.StaticBitmap( self.panel, wx.ID_ANY, wx.Bitmap(name=name, type=wx.BITMAP_TYPE_PNG) ) - except: + except Exception: self.hbitmap = wx.StaticBitmap( self.panel, wx.ID_ANY, BitmapFromImage(wx.EmptyImage(530, 150)) ) @@ -824,8 +824,8 @@ def DeleteMapset(self, event): shutil.rmtree(os.path.join(self.gisdbase, location, mapset)) self.OnSelectLocation(None) self.lbmapsets.SetSelection(0) - except: - wx.MessageBox(message=_("Unable to delete mapset")) + except OSError as e: + wx.MessageBox(message=_("Unable to delete mapset: %s") % str(e)) dlg.Destroy() @@ -856,8 +856,8 @@ def DeleteLocation(self, event): self.lblocations.SetSelection(0) self.OnSelectLocation(None) self.lbmapsets.SetSelection(0) - except: - wx.MessageBox(message=_("Unable to delete location")) + except OSError as e: + wx.MessageBox(message=_("Unable to delete location: %s") % str(e)) dlg.Destroy() @@ -1163,7 +1163,7 @@ def _getDefaultMapsetName(self): defaultName = getpass.getuser() # raise error if not ascii (not valid mapset name) defaultName.encode("ascii") - except: # whatever might go wrong + except Exception: # whatever might go wrong defaultName = "user" return defaultName diff --git a/gui/wxpython/image2target/ii2t_manager.py b/gui/wxpython/image2target/ii2t_manager.py index 9284c3a2b2a..3adcf5ef9bd 100644 --- a/gui/wxpython/image2target/ii2t_manager.py +++ b/gui/wxpython/image2target/ii2t_manager.py @@ -884,20 +884,6 @@ def OnSrcSelection(self, event): else: wx.FindWindowById(wx.ID_FORWARD).Enable(True) - try: - # set computational region to match selected map and zoom display - # to region - if maptype == "raster": - p = RunCommand("g.region", "raster=src_map") - elif maptype == "vector": - p = RunCommand("g.region", "vector=src_map") - - if p.returncode == 0: - print("returncode = ", str(p.returncode)) - self.parent.Map.region = self.parent.Map.GetRegion() - except: - pass - def OnTgtRastSelection(self, event): """Source map to display selected""" global tgt_map From 61407f0e853ec967bf3afdf5870fc377a52c7bf6 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Wed, 2 Oct 2024 12:07:52 -0400 Subject: [PATCH 134/209] wxGUI: Fixed E722: bare 'except' in iscatt/ (#4427) --- .flake8 | 4 ++-- gui/wxpython/iscatt/controllers.py | 4 ++-- gui/wxpython/iscatt/frame.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.flake8 b/.flake8 index d704112048f..32b0191e00c 100644 --- a/.flake8 +++ b/.flake8 @@ -26,8 +26,8 @@ per-file-ignores = doc/gui/wxpython/example/dialogs.py: F401 gui/scripts/d.wms.py: E501 gui/wxpython/image2target/*: F841, E722 - gui/wxpython/image2target/g.gui.image2target.py: E501 - gui/wxpython/iscatt/*: F841, E722, F405, F403 + gui/wxpython/image2target/g.gui.image2target.py: E501, F841 + gui/wxpython/iscatt/*: F841, F405, F403 gui/wxpython/lmgr/frame.py: F841, E722 # layertree still includes some formatting issues (it is ignored by Black) gui/wxpython/lmgr/layertree.py: E722, E266, W504, E225 diff --git a/gui/wxpython/iscatt/controllers.py b/gui/wxpython/iscatt/controllers.py index e8884f4f78b..aed917aacad 100644 --- a/gui/wxpython/iscatt/controllers.py +++ b/gui/wxpython/iscatt/controllers.py @@ -597,7 +597,7 @@ def _renderscattplts(self, scatt_ids, cats, cats_attrs): try: self.cat_ids.remove(c) scatt_dt[c]["render"] = True - except: + except ValueError: scatt_dt[c]["render"] = False if self.scatt_mgr.pol_sel_mode[0]: @@ -674,7 +674,7 @@ def ChangePosition(self, cat_id, new_pos): try: pos = self.cats_ids.index(cat_id) - except: + except ValueError: return False if pos > new_pos: diff --git a/gui/wxpython/iscatt/frame.py b/gui/wxpython/iscatt/frame.py index 45f50622d2f..803b2344144 100644 --- a/gui/wxpython/iscatt/frame.py +++ b/gui/wxpython/iscatt/frame.py @@ -249,7 +249,7 @@ def CursorPlotMove(self, x, y, scatt_id): x = int(round(x)) y = int(round(y)) coords = True - except: + except TypeError: coords = False pane = self._getPane(scatt_id) From fa3042417609aedb31739056e19fbe89c0675dfe Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2024 13:08:36 -0400 Subject: [PATCH 135/209] CI(deps): Update mamba-org/setup-micromamba action to v1.10.0 (#4429) --- .github/workflows/macos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 664649fa5c6..e1166cdacc2 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -50,7 +50,7 @@ jobs: # Year and week of year so cache key changes weekly run: echo "date=$(date +%Y-%U)" >> "${GITHUB_OUTPUT}" - name: Setup Mamba - uses: mamba-org/setup-micromamba@f8b8a1e23a26f60a44c853292711bacfd3eac822 # v1.9.0 + uses: mamba-org/setup-micromamba@59b11321ffd9186cd5165633a02c5bba47de6d13 # v1.10.0 with: init-shell: bash environment-file: .github/workflows/macos_dependencies.txt From 1b639db7bcc630ed2e04332bcd5b9231300ce862 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Wed, 2 Oct 2024 13:39:26 -0400 Subject: [PATCH 136/209] wxGUI: Fix F405 error by explicitly importing required modules in iscatt/ (#4426) * update 405 in core_c * updated flake8 * support explicit imports * ran isort to make sort imports --- .flake8 | 2 +- gui/wxpython/iscatt/core_c.py | 27 +++++++++++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/.flake8 b/.flake8 index 32b0191e00c..09706c297d9 100644 --- a/.flake8 +++ b/.flake8 @@ -27,7 +27,7 @@ per-file-ignores = gui/scripts/d.wms.py: E501 gui/wxpython/image2target/*: F841, E722 gui/wxpython/image2target/g.gui.image2target.py: E501, F841 - gui/wxpython/iscatt/*: F841, F405, F403 + gui/wxpython/iscatt/*: F841, E722 gui/wxpython/lmgr/frame.py: F841, E722 # layertree still includes some formatting issues (it is ignored by Black) gui/wxpython/lmgr/layertree.py: E722, E266, W504, E225 diff --git a/gui/wxpython/iscatt/core_c.py b/gui/wxpython/iscatt/core_c.py index a2a3d5da9da..4678d2654b1 100644 --- a/gui/wxpython/iscatt/core_c.py +++ b/gui/wxpython/iscatt/core_c.py @@ -11,15 +11,34 @@ @author Stepan Turek (mentor: Martin Landa) """ +import ctypes import sys -import numpy as np +from ctypes import POINTER, c_char_p, c_double, c_int, c_uint8, pointer from multiprocessing import Process, Queue -from ctypes import * +import numpy as np try: - from grass.lib.imagery import * from grass.lib.gis import G_get_window + from grass.lib.imagery import ( + SC_SCATT_CONDITIONS, + SC_SCATT_DATA, + I_apply_colormap, + I_compute_scatts, + I_create_cat_rast, + I_insert_patch_to_cat_rast, + I_merge_arrays, + I_rasterize, + I_sc_add_cat, + I_sc_free_cats, + I_sc_init_cats, + I_sc_insert_scatt_data, + I_scd_init_scatt_data, + scdScattData, + struct_Cell_head, + struct_Range, + struct_scCats, + ) except ImportError as e: sys.stderr.write(_("Loading ctypes libs failed")) @@ -238,7 +257,7 @@ def _getComputationStruct(cats, cats_rasts, cats_type, n_bands): scatt_vals = scdScattData() - c_void_p = ctypes.POINTER(ctypes.c_void_p) + c_void_p = POINTER(ctypes.c_void_p) if cats_type == SC_SCATT_DATA: vals[:] = 0 From f0a997ca86ff93740e1549fbd6dc5bbf40b19441 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Wed, 2 Oct 2024 17:52:05 -0400 Subject: [PATCH 137/209] wxGUI: FIxed F841 is iscatt/core_c.py (#4430) * fixed 841 * updated flake8 --- .flake8 | 2 +- gui/wxpython/iscatt/core_c.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.flake8 b/.flake8 index 09706c297d9..0a48712c808 100644 --- a/.flake8 +++ b/.flake8 @@ -27,7 +27,7 @@ per-file-ignores = gui/scripts/d.wms.py: E501 gui/wxpython/image2target/*: F841, E722 gui/wxpython/image2target/g.gui.image2target.py: E501, F841 - gui/wxpython/iscatt/*: F841, E722 + gui/wxpython/iscatt/*: F841 gui/wxpython/lmgr/frame.py: F841, E722 # layertree still includes some formatting issues (it is ignored by Black) gui/wxpython/lmgr/layertree.py: E722, E266, W504, E225 diff --git a/gui/wxpython/iscatt/core_c.py b/gui/wxpython/iscatt/core_c.py index 4678d2654b1..8be04964b90 100644 --- a/gui/wxpython/iscatt/core_c.py +++ b/gui/wxpython/iscatt/core_c.py @@ -40,7 +40,7 @@ struct_scCats, ) except ImportError as e: - sys.stderr.write(_("Loading ctypes libs failed")) + sys.stderr.write(_("Loading ctypes libs failed: %s") % e) from core.gcmd import GException from grass.script import encode @@ -288,7 +288,6 @@ def _updateCatRastProcess(patch_rast, region, cat_rast, output_queue): def _rasterize(polygon, rast, region, value, output_queue): - pol_size = len(polygon) * 2 pol = np.array(polygon, dtype=float) c_uint8_p = POINTER(c_uint8) From aa1c32a59a029d0f78c00452f9085a0bac379144 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Wed, 2 Oct 2024 21:46:53 -0400 Subject: [PATCH 138/209] wxGUI: Fixed F841 in dialogs.py, frame.py (#4431) * fixed 841 * removed dlgSize comments --- gui/wxpython/iscatt/dialogs.py | 3 --- gui/wxpython/iscatt/frame.py | 3 --- 2 files changed, 6 deletions(-) diff --git a/gui/wxpython/iscatt/dialogs.py b/gui/wxpython/iscatt/dialogs.py index 3e2d7fa7a59..a2d054b64a4 100644 --- a/gui/wxpython/iscatt/dialogs.py +++ b/gui/wxpython/iscatt/dialogs.py @@ -90,8 +90,6 @@ def _layout(self): border = wx.BoxSizer(wx.VERTICAL) dialogSizer = wx.BoxSizer(wx.VERTICAL) - regionSizer = wx.BoxSizer(wx.HORIZONTAL) - dialogSizer.Add( self._addSelectSizer(title=self.band_1_label, sel=self.band_1_ch) ) @@ -356,7 +354,6 @@ def __init__( self.scatt_mgr = scatt_mgr - maxValue = 1e8 self.parent = parent self.settings = {} diff --git a/gui/wxpython/iscatt/frame.py b/gui/wxpython/iscatt/frame.py index 803b2344144..122aa053b9b 100644 --- a/gui/wxpython/iscatt/frame.py +++ b/gui/wxpython/iscatt/frame.py @@ -221,9 +221,6 @@ def __init__(self, parent, scatt_mgr, id=wx.ID_ANY): self.Bind(aui.EVT_AUI_PANE_CLOSE, self.OnPlotPaneClosed) - dlgSize = (-1, 400) - # self.SetBestSize(dlgSize) - # self.SetInitialSize(dlgSize) self.SetAutoLayout(1) # fix goutput's pane size (required for Mac OSX) # if self.gwindow: From a4d3ceacd3885463334972db327ac4310e180e74 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Wed, 2 Oct 2024 21:50:15 -0400 Subject: [PATCH 139/209] v.colors: Fix resource leak issue in scan_attr.c file (#4423) * fix resource leak * close database driver --- vector/v.colors/scan_attr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vector/v.colors/scan_attr.c b/vector/v.colors/scan_attr.c index 18c51635f81..e805cd74a7f 100644 --- a/vector/v.colors/scan_attr.c +++ b/vector/v.colors/scan_attr.c @@ -42,6 +42,8 @@ int scan_attr(struct Map_info *Map, int layer, const char *column_name, &cvarr); if (nrec < 1) { G_important_message(_("No data selected")); + Vect_destroy_field_info(fi); + db_close_database(driver); return 0; } @@ -100,6 +102,7 @@ int scan_attr(struct Map_info *Map, int layer, const char *column_name, } db_close_database(driver); + Vect_destroy_field_info(fi); return is_fp; } From 617828d7f4f363006010734126b4104a0b389fc5 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Wed, 2 Oct 2024 21:51:20 -0400 Subject: [PATCH 140/209] r.fill.dir: Fix unchecked return value in filldir.c (#4433) * fix unchecked value * Update raster/r.fill.dir/filldir.c * G_fatal --- raster/r.fill.dir/filldir.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/raster/r.fill.dir/filldir.c b/raster/r.fill.dir/filldir.c index 55380b7dfc5..cfe0ae69586 100644 --- a/raster/r.fill.dir/filldir.c +++ b/raster/r.fill.dir/filldir.c @@ -145,14 +145,20 @@ void filldir(int fe, int fd, int nl, struct band3 *bnd) CELL *dir; /* fill single-cell depressions, except on outer rows and columns */ - lseek(fe, 0, SEEK_SET); + if (lseek(fe, 0, SEEK_SET) == -1) { + G_fatal_error(_("Unable to seek: %s"), strerror(errno)); + } advance_band3(fe, bnd); advance_band3(fe, bnd); for (i = 1; i < nl - 1; i += 1) { - lseek(fe, (off_t)(i + 1) * bnd->sz, SEEK_SET); + if (lseek(fe, (off_t)(i + 1) * bnd->sz, SEEK_SET) == -1) { + G_fatal_error(_("Unable to seek: %s"), strerror(errno)); + } advance_band3(fe, bnd); if (fill_row(nl, bnd->ns, bnd)) { - lseek(fe, (off_t)i * bnd->sz, SEEK_SET); + if (lseek(fe, (off_t)i * bnd->sz, SEEK_SET) == -1) { + G_fatal_error(_("Unable to seek: %s"), strerror(errno)); + } if (write(fe, bnd->b[1], bnd->sz) < 0) G_fatal_error(_("File writing error in %s() %d:%s"), __func__, errno, strerror(errno)); @@ -172,8 +178,12 @@ void filldir(int fe, int fd, int nl, struct band3 *bnd) dir = G_calloc(bnd->ns, sizeof(CELL)); bufsz = bnd->ns * sizeof(CELL); - lseek(fe, 0, SEEK_SET); - lseek(fd, 0, SEEK_SET); + if (lseek(fe, 0, SEEK_SET) == -1) { + G_fatal_error(_("Unable to seek: %s"), strerror(errno)); + } + if (lseek(fd, 0, SEEK_SET) == -1) { + G_fatal_error(_("Unable to seek: %s"), strerror(errno)); + } advance_band3(fe, bnd); for (i = 0; i < nl; i += 1) { advance_band3(fe, bnd); From 4bec7147e29fc81951498e38e382df140be6956d Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Wed, 2 Oct 2024 21:53:02 -0400 Subject: [PATCH 141/209] r.thin: Fix unchecked return value in io.c (#4434) check return value --- raster/r.thin/io.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/raster/r.thin/io.c b/raster/r.thin/io.c index d5ba76245c3..3b2d0bd8aa3 100644 --- a/raster/r.thin/io.c +++ b/raster/r.thin/io.c @@ -67,13 +67,17 @@ int put_a_row(int row, CELL *buf) static int read_row(int file, void *buf, int row, int buf_len) { - lseek(file, ((off_t)row) * buf_len, 0); + if (lseek(file, ((off_t)row) * buf_len, 0) == -1) { + G_fatal_error(_("Unable to seek: %s"), strerror(errno)); + } return (read(file, buf, buf_len) == buf_len); } static int write_row(int file, const void *buf, int row, int buf_len) { - lseek(file, ((off_t)row) * buf_len, 0); + if (lseek(file, ((off_t)row) * buf_len, 0) == -1) { + G_fatal_error(_("Unable to seek: %s"), strerror(errno)); + } return (write(file, buf, buf_len) == buf_len); } From de8a6fd631409a9c50f22fd31e149f9251a26c55 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 02:57:17 +0000 Subject: [PATCH 142/209] CI(deps): Update rui314/setup-mold digest to c49f92e (#4435) --- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/pytest.yml | 2 +- .github/workflows/python-code-quality.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 84d857a3505..acafe77daea 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -52,7 +52,7 @@ jobs: sudo apt-get install -y wget git gawk findutils xargs -a <(awk '! /^ *(#|$)/' ".github/workflows/apt.txt") -r -- \ sudo apt-get install -y --no-install-recommends --no-install-suggests - - uses: rui314/setup-mold@0bf4f07ef9048ec62a45f9dbf2f098afa49695f0 # v1 + - uses: rui314/setup-mold@c49f92ee787f4e2bba3330d01755ef8c7221699a # v1 if: ${{ matrix.language == 'c-cpp' }} - name: Initialize CodeQL diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 0123b01fc0e..cb724086ea0 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -48,7 +48,7 @@ jobs: xargs -a <(awk '! /^ *(#|$)/' ".github/workflows/apt.txt") -r -- \ sudo apt-get install -y --no-install-recommends --no-install-suggests - - uses: rui314/setup-mold@0bf4f07ef9048ec62a45f9dbf2f098afa49695f0 # v1 + - uses: rui314/setup-mold@c49f92ee787f4e2bba3330d01755ef8c7221699a # v1 - name: Install Python dependencies run: | diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 2e156b08417..92c647875b0 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -147,7 +147,7 @@ jobs: run: | echo "MAKEFLAGS=-j$(nproc)" >> $GITHUB_ENV - - uses: rui314/setup-mold@0bf4f07ef9048ec62a45f9dbf2f098afa49695f0 # v1 + - uses: rui314/setup-mold@c49f92ee787f4e2bba3330d01755ef8c7221699a # v1 - name: Build run: .github/workflows/build_${{ matrix.os }}.sh $HOME/install From d7c79a87a790ef58ef4f727cafd89cbb5111d0f2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 10:29:53 -0400 Subject: [PATCH 143/209] CI(deps): Update docker/setup-buildx-action action to v3.7.0 (#4436) --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index f8440e8e71f..4056ed63ea4 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -68,7 +68,7 @@ jobs: - name: Set up QEMU uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1 + uses: docker/setup-buildx-action@8026d2bc3645ea78b0d2544766a1225eb5691f89 # v3.7.0 - name: Login to DockerHub uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: From 7b73900583bb79181ccc78d69da8f455dbae4f05 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 12:31:36 -0400 Subject: [PATCH 144/209] CI(deps): Update mamba-org/setup-micromamba action to v1.11.0 (#4437) --- .github/workflows/macos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index e1166cdacc2..d9fdca6b058 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -50,7 +50,7 @@ jobs: # Year and week of year so cache key changes weekly run: echo "date=$(date +%Y-%U)" >> "${GITHUB_OUTPUT}" - name: Setup Mamba - uses: mamba-org/setup-micromamba@59b11321ffd9186cd5165633a02c5bba47de6d13 # v1.10.0 + uses: mamba-org/setup-micromamba@4b9113af4fba0e9e1124b252dd6497a419e7396d # v1.11.0 with: init-shell: bash environment-file: .github/workflows/macos_dependencies.txt From d4e46dcf52169167f6d490dae5ec823ffdb89914 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:03:28 -0400 Subject: [PATCH 145/209] CI(deps): Update docker/setup-buildx-action action to v3.7.1 (#4448) --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 4056ed63ea4..8a23d8e200b 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -68,7 +68,7 @@ jobs: - name: Set up QEMU uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8026d2bc3645ea78b0d2544766a1225eb5691f89 # v3.7.0 + uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 - name: Login to DockerHub uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: From a96c073c137924d9146f89ab3d859e1659c92d01 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:09:30 -0400 Subject: [PATCH 146/209] CI(deps): Update rui314/setup-mold digest to b015f7e (#4447) --- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/pytest.yml | 2 +- .github/workflows/python-code-quality.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index acafe77daea..1e163b5ad98 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -52,7 +52,7 @@ jobs: sudo apt-get install -y wget git gawk findutils xargs -a <(awk '! /^ *(#|$)/' ".github/workflows/apt.txt") -r -- \ sudo apt-get install -y --no-install-recommends --no-install-suggests - - uses: rui314/setup-mold@c49f92ee787f4e2bba3330d01755ef8c7221699a # v1 + - uses: rui314/setup-mold@b015f7e3f2938ad3a5ed6e5111a8c6c7c1d6db6e # v1 if: ${{ matrix.language == 'c-cpp' }} - name: Initialize CodeQL diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index cb724086ea0..f0cda6a95f5 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -48,7 +48,7 @@ jobs: xargs -a <(awk '! /^ *(#|$)/' ".github/workflows/apt.txt") -r -- \ sudo apt-get install -y --no-install-recommends --no-install-suggests - - uses: rui314/setup-mold@c49f92ee787f4e2bba3330d01755ef8c7221699a # v1 + - uses: rui314/setup-mold@b015f7e3f2938ad3a5ed6e5111a8c6c7c1d6db6e # v1 - name: Install Python dependencies run: | diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 92c647875b0..d83747a43bd 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -147,7 +147,7 @@ jobs: run: | echo "MAKEFLAGS=-j$(nproc)" >> $GITHUB_ENV - - uses: rui314/setup-mold@c49f92ee787f4e2bba3330d01755ef8c7221699a # v1 + - uses: rui314/setup-mold@b015f7e3f2938ad3a5ed6e5111a8c6c7c1d6db6e # v1 - name: Build run: .github/workflows/build_${{ matrix.os }}.sh $HOME/install From a186638d1c939d203bb0ba830d6bf951cca2767f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:12:15 -0400 Subject: [PATCH 147/209] CI(deps): Update github/codeql-action action to v3.26.11 (#4442) --- .github/workflows/codeql-analysis.yml | 4 ++-- .github/workflows/python-code-quality.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 1e163b5ad98..64994f93535 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -56,7 +56,7 @@ jobs: if: ${{ matrix.language == 'c-cpp' }} - name: Initialize CodeQL - uses: github/codeql-action/init@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 + uses: github/codeql-action/init@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -81,6 +81,6 @@ jobs: run: .github/workflows/build_ubuntu-22.04.sh "${HOME}/install" - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 + uses: github/codeql-action/analyze@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index d83747a43bd..744ad9a3012 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -135,7 +135,7 @@ jobs: path: bandit.sarif - name: Upload SARIF File into Security Tab - uses: github/codeql-action/upload-sarif@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 + uses: github/codeql-action/upload-sarif@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11 with: sarif_file: bandit.sarif From 359a62bb9a0e82d29a8b7626ad40b945ea58996c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:17:38 -0400 Subject: [PATCH 148/209] CI(deps): Update mamba-org/setup-micromamba action to v2 (#4438) --- .github/workflows/macos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index d9fdca6b058..a90cdcd7ad5 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -50,7 +50,7 @@ jobs: # Year and week of year so cache key changes weekly run: echo "date=$(date +%Y-%U)" >> "${GITHUB_OUTPUT}" - name: Setup Mamba - uses: mamba-org/setup-micromamba@4b9113af4fba0e9e1124b252dd6497a419e7396d # v1.11.0 + uses: mamba-org/setup-micromamba@617811f69075e3fd3ae68ca64220ad065877f246 # v2.0.0 with: init-shell: bash environment-file: .github/workflows/macos_dependencies.txt From 7f81c6dc5053b97560b66bee3db41f69e79035ca Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Fri, 4 Oct 2024 10:21:27 -0400 Subject: [PATCH 149/209] wxGUI: Fixed F841 in iscatt/ (#4432) * fixed all F841 * updated flake8 * reverted add_callback * Update plots.py --- .flake8 | 1 - gui/wxpython/iscatt/controllers.py | 3 --- gui/wxpython/iscatt/plots.py | 8 +------- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/.flake8 b/.flake8 index 0a48712c808..737d8880c4f 100644 --- a/.flake8 +++ b/.flake8 @@ -27,7 +27,6 @@ per-file-ignores = gui/scripts/d.wms.py: E501 gui/wxpython/image2target/*: F841, E722 gui/wxpython/image2target/g.gui.image2target.py: E501, F841 - gui/wxpython/iscatt/*: F841 gui/wxpython/lmgr/frame.py: F841, E722 # layertree still includes some formatting issues (it is ignored by Black) gui/wxpython/lmgr/layertree.py: E722, E266, W504, E225 diff --git a/gui/wxpython/iscatt/controllers.py b/gui/wxpython/iscatt/controllers.py index aed917aacad..4cd1c3c66f6 100644 --- a/gui/wxpython/iscatt/controllers.py +++ b/gui/wxpython/iscatt/controllers.py @@ -192,9 +192,7 @@ def SetDataDone(self, event): del self.busy self.data_set = True - todo = event.ret self.bad_bands = event.ret - bands = self.core.GetBands() self.bad_rasts = event.ret self.cats_mgr.SetData() @@ -809,7 +807,6 @@ def ExportCatRast(self, cat_id): def OnExportCatRastDone(self, event): ret, err = event.ret if ret == 0: - cat_attrs = self.GetCategoryAttrs(event.kwds["cat_id"]) GMessage( _("Scatter plot raster of class <%s> exported to raster map <%s>.") % (event.userdata["name"], event.kwds["rast_name"]) diff --git a/gui/wxpython/iscatt/plots.py b/gui/wxpython/iscatt/plots.py index a29098e8bcd..9c6f50b3b9f 100644 --- a/gui/wxpython/iscatt/plots.py +++ b/gui/wxpython/iscatt/plots.py @@ -255,7 +255,6 @@ def Plot(self, cats_order, scatts, ellipses, styles): if not e: continue - colors = styles[cat_id]["color"].split(":") if self.transpose: e["theta"] = 360 - e["theta"] + 90 if e["theta"] >= 360: @@ -355,9 +354,6 @@ def ZoomRectangle(self, event): if event.button != 1: return - cur_xlim = self.axes.get_xlim() - cur_ylim = self.axes.get_ylim() - x1, y1 = event.xdata, event.ydata x2 = deepcopy(self.zoom_rect_coords["x"]) y2 = deepcopy(self.zoom_rect_coords["y"]) @@ -651,13 +647,11 @@ def __init__(self, ax, pol, empty_pol): x, y = zip(*self.pol.xy) - style = self._getPolygonStyle() - self.line = Line2D(x, y, marker="o", markerfacecolor="r", animated=True) self.ax.add_line(self.line) # self._update_line(pol) - cid = self.pol.add_callback(self.poly_changed) + self.pol.add_callback(self.poly_changed) self.moving_ver_idx = None # the active vert self.mode = None From 60f71359cefb75de467f8b026407cfc98179e50c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 18:54:21 +0000 Subject: [PATCH 150/209] CI(deps): Update ruff to v0.6.9 (#4449) --- .github/workflows/python-code-quality.yml | 2 +- .pre-commit-config.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 744ad9a3012..ac9fa5ea4cc 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.7.10" # renovate: datasource=pypi depName=ruff - RUFF_VERSION: "0.6.8" + RUFF_VERSION: "0.6.9" runs-on: ${{ matrix.os }} permissions: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b7a517fba37..f51f1637422 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: ) - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.6.8 + rev: v0.6.9 hooks: # Run the linter. - id: ruff From 1e866290b8fa0e226ec4fede4697656df30b8705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Fri, 4 Oct 2024 16:17:58 -0400 Subject: [PATCH 151/209] style: Fix invalid-escape-sequence (W605) (#4409) * style: Fix invalid-escape-sequence (W605) Ruff rule: https://docs.astral.sh/ruff/rules/invalid-escape-sequence/ * r.in.ascii: Remove test_csv and test_uncommon_delims --- imagery/i.pca/testsuite/test_pca.py | 2 +- pyproject.toml | 1 - .../r.in.ascii/testsuite/test_r_in_ascii.py | 70 ------------------- 3 files changed, 1 insertion(+), 72 deletions(-) diff --git a/imagery/i.pca/testsuite/test_pca.py b/imagery/i.pca/testsuite/test_pca.py index 8e9df84f2eb..f42fc6ddcc0 100644 --- a/imagery/i.pca/testsuite/test_pca.py +++ b/imagery/i.pca/testsuite/test_pca.py @@ -48,7 +48,7 @@ def test_pca_sample(self): cells=250325 datatype=CELL ncats=0 - comments=\"Eigen values, (vectors), and [percent importance]:PC1 4334.35 ( 0.2824, 0.3342, 0.5092,-0.0087, 0.5264, 0.5217) [83.04%]PC2 588.31 ( 0.2541, 0.1885, 0.2923,-0.7428,-0.5110,-0.0403) [11.27%]PC3 239.22 ( 0.3801, 0.3819, 0.2681, 0.6238,-0.4000,-0.2980) [ 4.58%]PC4 32.85 ( 0.1752,-0.0191,-0.4053, 0.1593,-0.4435, 0.7632) [ 0.63%]PC5 20.73 (-0.6170,-0.2514, 0.6059, 0.1734,-0.3235, 0.2330) [ 0.40%]PC6 4.08 (-0.5475, 0.8021,-0.2282,-0.0607,-0.0208, 0.0252) [ 0.08%]i.pca input=\"lsat7_2002_10,lsat7_2002_20,lsat7_2002_30,lsat7_2002_40\,lsat7_2002_50,lsat7_2002_70\" output=\"lsat7_2002_pca\" rescale=0,255 \percent=99" """ + comments=\"Eigen values, (vectors), and [percent importance]:PC1 4334.35 ( 0.2824, 0.3342, 0.5092,-0.0087, 0.5264, 0.5217) [83.04%]PC2 588.31 ( 0.2541, 0.1885, 0.2923,-0.7428,-0.5110,-0.0403) [11.27%]PC3 239.22 ( 0.3801, 0.3819, 0.2681, 0.6238,-0.4000,-0.2980) [ 4.58%]PC4 32.85 ( 0.1752,-0.0191,-0.4053, 0.1593,-0.4435, 0.7632) [ 0.63%]PC5 20.73 (-0.6170,-0.2514, 0.6059, 0.1734,-0.3235, 0.2330) [ 0.40%]PC6 4.08 (-0.5475, 0.8021,-0.2282,-0.0607,-0.0208, 0.0252) [ 0.08%]i.pca input=\"lsat7_2002_10,lsat7_2002_20,lsat7_2002_30,lsat7_2002_40\\,lsat7_2002_50,lsat7_2002_70\" output=\"lsat7_2002_pca\" rescale=0,255 \\percent=99" """ lsat7_2002_pca_univar_out = [ """n=250325 diff --git a/pyproject.toml b/pyproject.toml index c6cfac4185b..18dbdd75067 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -262,7 +262,6 @@ ignore = [ "UP031", # printf-string-formatting "UP032", # f-string "UP036", # outdated-version-block - "W605", # invalid-escape-sequence ] diff --git a/raster/r.in.ascii/testsuite/test_r_in_ascii.py b/raster/r.in.ascii/testsuite/test_r_in_ascii.py index 20e0c2a8f9e..cff31b7b3e2 100644 --- a/raster/r.in.ascii/testsuite/test_r_in_ascii.py +++ b/raster/r.in.ascii/testsuite/test_r_in_ascii.py @@ -32,44 +32,6 @@ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 """ -INPUT_TSV = """north: 4299000.00 -south: 4247000.00 -east: 528000.00 -west: 500000.00 -rows: 10 -cols: 15 -null: -9999 - -1\ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ 10\ 11\ 12\ 13\ 14\ 15 -1\ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ 10\ 11\ 12\ 13\ 14\ 15 -1\ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ 10\ 11\ 12\ 13\ 14\ 15 -1\ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ 10\ 11\ 12\ 13\ 14\ 15 -1\ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ 10\ 11\ 12\ 13\ 14\ 15 -1\ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ 10\ 11\ 12\ 13\ 14\ 15 -1\ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ 10\ 11\ 12\ 13\ 14\ 15 -1\ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ 10\ 11\ 12\ 13\ 14\ 15 -1\ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ 10\ 11\ 12\ 13\ 14\ 15 -1\ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ 10\ 11\ 12\ 13\ 14\ 15 """ - -INPUT_UNCOMMON = """north: 4299000.00 -south: 4247000.00 -east: 528000.00 -west: 500000.00 -rows: 10 -cols: 15 -null: -9999 - -1@ 2@ 3@ 4@ 5@ 6@ 7@ 8@ 9@ 10@ 11@ 12@ 13@ 14@ 15 -1@ 2@ 3@ 4@ 5@ 6@ 7@ 8@ 9@ 10@ 11@ 12@ 13@ 14@ 15 -1@ 2@ 3@ 4@ 5@ 6@ 7@ 8@ 9@ 10@ 11@ 12@ 13@ 14@ 15 -1@ 2@ 3@ 4@ 5@ 6@ 7@ 8@ 9@ 10@ 11@ 12@ 13@ 14@ 15 -1@ 2@ 3@ 4@ 5@ 6@ 7@ 8@ 9@ 10@ 11@ 12@ 13@ 14@ 15 -1@ 2@ 3@ 4@ 5@ 6@ 7@ 8@ 9@ 10@ 11@ 12@ 13@ 14@ 15 -1@ 2@ 3@ 4@ 5@ 6@ 7@ 8@ 9@ 10@ 11@ 12@ 13@ 14@ 15 -1@ 2@ 3@ 4@ 5@ 6@ 7@ 8@ 9@ 10@ 11@ 12@ 13@ 14@ 15 -1@ 2@ 3@ 4@ 5@ 6@ 7@ 8@ 9@ 10@ 11@ 12@ 13@ 14@ 15 -1@ 2@ 3@ 4@ 5@ 6@ 7@ 8@ 9@ 10@ 11@ 12@ 13@ 14@ 15 """ - class SimpleCsvTestCase(TestCase): ascii_test = "ascii" @@ -119,38 +81,6 @@ def test_text_delimeter(self): msg="ascii_test in degrees must be between 1 and 5", ) - def test_tsv(self): - """Test loading TSV""" - self.assertModule( - "r.in.ascii", - input="-", - output=self.ascii_test, - type="CELL", - stdin_=INPUT_TSV, - ) - self.assertRasterMinMax( - map=self.ascii_test, - refmin=1, - refmax=15, - msg="ascii_test in degrees must be between 1 and 15", - ) - - def test_uncommon_delims(self): - """Test loading with uncommon delimiters""" - self.assertModule( - "r.in.ascii", - input="-", - output=self.ascii_test, - type="CELL", - stdin_=INPUT_UNCOMMON, - ) - self.assertRasterMinMax( - map=self.ascii_test, - refmin=1, - refmax=15, - msg="ascii_test in degrees must be between 1 and 15", - ) - if __name__ == "__main__": test() From eebf3692cc6c18560c8d0b8b6f6f4468df0abeb1 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Fri, 4 Oct 2024 17:37:43 -0400 Subject: [PATCH 152/209] wxGUI: Fixed F841 and E266 in lmgr/ (#4439) fixed f841 and e266 --- .flake8 | 5 ++--- gui/wxpython/lmgr/frame.py | 2 +- gui/wxpython/lmgr/layertree.py | 2 +- gui/wxpython/lmgr/workspace.py | 11 ++++++++--- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.flake8 b/.flake8 index 737d8880c4f..5126c042439 100644 --- a/.flake8 +++ b/.flake8 @@ -27,10 +27,9 @@ per-file-ignores = gui/scripts/d.wms.py: E501 gui/wxpython/image2target/*: F841, E722 gui/wxpython/image2target/g.gui.image2target.py: E501, F841 - gui/wxpython/lmgr/frame.py: F841, E722 + gui/wxpython/lmgr/frame.py: E722 # layertree still includes some formatting issues (it is ignored by Black) - gui/wxpython/lmgr/layertree.py: E722, E266, W504, E225 - gui/wxpython/lmgr/workspace.py: F841 + gui/wxpython/lmgr/layertree.py: E722 gui/wxpython/modules/*: F841, E722 gui/wxpython/nviz/*: F841, E266, E722, F403, F405 gui/wxpython/photo2image/*: F841, E722, E265 diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 4eae371f68b..f9ce45c813b 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -1950,7 +1950,7 @@ def AddMaps(self, mapLayers, ltype, check=False): ) return - newItem = maptree.AddLayer( + maptree.AddLayer( ltype=ltype, lname=layerName, lchecked=check, diff --git a/gui/wxpython/lmgr/layertree.py b/gui/wxpython/lmgr/layertree.py index 4779a40db9b..52dc0115480 100644 --- a/gui/wxpython/lmgr/layertree.py +++ b/gui/wxpython/lmgr/layertree.py @@ -756,7 +756,7 @@ def OnLayerContextMenu(self, event): # self.popupMenu.Enable(self.popupID['bgmap'], False) self.popupMenu.Enable(self.popupID["topo"], False) # else: - ### self.popupMenu.Enable(self.popupID['bgmap'], True) + # self.popupMenu.Enable(self.popupID['bgmap'], True) item = wx.MenuItem( self.popupMenu, id=self.popupID["meta"], text=_("Metadata") diff --git a/gui/wxpython/lmgr/workspace.py b/gui/wxpython/lmgr/workspace.py index a593c19b19c..774c22bf4ed 100644 --- a/gui/wxpython/lmgr/workspace.py +++ b/gui/wxpython/lmgr/workspace.py @@ -179,9 +179,10 @@ def Load(self, filename): parent=self.lmgr, message=_( "Reading workspace file <%s> failed.\n" - "Invalid file, unable to parse XML document." + "Invalid file, unable to parse XML document.\n" + "Error details: %s" ) - % filename, + % (filename, str(e)), ) return False @@ -436,7 +437,11 @@ def SaveToFile(self, filename): except Exception as e: GError( parent=self.lmgr, - message=_("Writing current settings to workspace file failed."), + message=_( + "Writing current settings to workspace file <%s> failed.\n" + "Error details: %s" + ) + % (tmpfile, str(e)), ) return False From a16a02f7eb1aec90bcf7055858ee729e45905b67 Mon Sep 17 00:00:00 2001 From: Yann Chemin Date: Sat, 5 Oct 2024 01:36:07 +0200 Subject: [PATCH 153/209] i.atcorr: update man page to fix numbering of AVIRIS bands and make style consistent (#4445) --- imagery/i.atcorr/i.atcorr.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imagery/i.atcorr/i.atcorr.html b/imagery/i.atcorr/i.atcorr.html index 7808705d440..7c0b772e089 100644 --- a/imagery/i.atcorr/i.atcorr.html +++ b/imagery/i.atcorr/i.atcorr.html @@ -786,13 +786,13 @@

    F. Sensor band

    - - + + - + From 093411be44f55657177cc9aab719e1e62df7b20b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 5 Oct 2024 15:49:22 -0400 Subject: [PATCH 154/209] style: Fix all remaining `PT` flake8-pytest-style issues (#4452) * style: Fix pytest-parametrize-names-wrong-type (PT006) Ruff rule: https://docs.astral.sh/ruff/rules/pytest-parametrize-names-wrong-type/ * style: Fix pytest-composite-assertion (PT018) Ruff rule: https://docs.astral.sh/ruff/rules/pytest-composite-assertion/ * style: Remove unneeded exclusions of pytest rules * style: Fix pytest-incorrect-pytest-import (PT013) Ruff rule: https://docs.astral.sh/ruff/rules/pytest-incorrect-pytest-import/ * Move PT009 exclusion to only exclude on python/grass/gunittest/case.py * grass.script: Ignore pytest-raises-too-broad (PT011) in grass_script_setup_test.py::test_init_session_finish --- pyproject.toml | 9 +-------- .../tests/grass_script_mapset_session_test.py | 12 ++++++++---- .../jupyter/tests/reprojection_renderer_test.py | 6 +++--- .../pygrass/modules/tests/grass_pygrass_grid_test.py | 4 ++-- python/grass/script/tests/grass_script_setup_test.py | 2 +- temporal/t.rast.list/tests/t_rast_list_test.py | 2 +- 6 files changed, 16 insertions(+), 19 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 18dbdd75067..5a4bd25283f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -179,13 +179,6 @@ ignore = [ "PLW1641", # eq-without-hash "PLW2901", # redefined-loop-name "PLW3201", # bad-dunder-method-name - "PT001", # pytest-fixture-incorrect-parentheses-style - "PT004", # pytest-missing-fixture-name-underscore - "PT006", # pytest-parametrize-names-wrong-type - "PT009", # pytest-unittest-assertion - "PT011", # pytest-raises-too-broad - "PT018", # pytest-composite-assertion - "PT023", # pytest-incorrect-mark-parentheses-style "PTH100", # os-path-abspath "PTH101", # os-chmod "PTH102", # os-mkdir @@ -313,12 +306,12 @@ ignore = [ "python/grass/__init__.py" = ["PYI056"] "python/grass/exp*/tests/grass_script_mapset_session_test.py" = ["SIM117"] "python/grass/exp*/tests/grass_script_tmp_mapset_session_test.py" = ["SIM117"] +"python/grass/gunittest/case.py" = ["PT009"] "python/grass/gunittest/loader.py" = ["PYI024"] "python/grass/gunittest/multireport.py" = ["PYI024"] "python/grass/gunittest/testsu*/d*/s*/s*/subsub*/t*/test_segfaut.py" = ["B018"] "python/grass/gunittest/testsuite/test_assertions_rast3d.py" = ["FLY002"] "python/grass/imaging/images2*.py" = ["SIM115"] -"python/grass/jupyter/tests/reprojection_renderer_test.py" = ["PT013"] "python/grass/jupyter/testsuite/interactivemap_test.py" = ["PGH004"] "python/grass/jupyter/testsuite/map_test.py" = ["PGH004"] "python/grass/pydispatch/signal.py" = ["A005"] diff --git a/python/grass/experimental/tests/grass_script_mapset_session_test.py b/python/grass/experimental/tests/grass_script_mapset_session_test.py index 3877e61576e..740770937dd 100644 --- a/python/grass/experimental/tests/grass_script_mapset_session_test.py +++ b/python/grass/experimental/tests/grass_script_mapset_session_test.py @@ -68,7 +68,8 @@ def test_create_overwrite(xy_session): .strip() .split() ) - assert len(rasters) == 1 and rasters[0] == "a" + assert len(rasters) == 1 + assert rasters[0] == "a" with experimental.MapsetSession( name, create=True, overwrite=True, env=xy_session.env ) as session: @@ -86,7 +87,8 @@ def test_create_overwrite(xy_session): .strip() .split() ) - assert len(rasters) == 1 and rasters[0] == "a" + assert len(rasters) == 1 + assert rasters[0] == "a" assert os.path.exists(session_file) @@ -103,7 +105,8 @@ def test_ensure(xy_session): .strip() .split() ) - assert len(rasters) == 1 and rasters[0] == "a" + assert len(rasters) == 1 + assert rasters[0] == "a" with experimental.MapsetSession(name, ensure=True, env=xy_session.env) as session: session_mapset = gs.read_command("g.mapset", flags="p", env=session.env).strip() assert name == session_mapset @@ -112,7 +115,8 @@ def test_ensure(xy_session): .strip() .split() ) - assert len(rasters) == 1 and rasters[0] == "a" + assert len(rasters) == 1 + assert rasters[0] == "a" gs.run_command("r.mapcalc", expression="b = 1", env=session.env) rasters = ( gs.read_command("g.list", type="raster", mapset=".", env=session.env) diff --git a/python/grass/jupyter/tests/reprojection_renderer_test.py b/python/grass/jupyter/tests/reprojection_renderer_test.py index 907522ab2f8..f9ef7888110 100644 --- a/python/grass/jupyter/tests/reprojection_renderer_test.py +++ b/python/grass/jupyter/tests/reprojection_renderer_test.py @@ -1,7 +1,7 @@ """Test ReprojectionRenderer functions""" from pathlib import Path -from pytest import approx +import pytest from grass.jupyter.reprojection_renderer import ReprojectionRenderer @@ -21,8 +21,8 @@ def test_render_raster(simple_dataset): assert Path(filename).exists() # Test bounding box is correct # Raster is same extent as region so no need to test bbox for use_region=True - assert bbox[0] == approx([0.00072155, -85.48874388]) - assert bbox[1] == approx([0.00000000, -85.48766880]) + assert bbox[0] == pytest.approx([0.00072155, -85.48874388]) + assert bbox[1] == pytest.approx([0.00000000, -85.48766880]) # render_vector produces json diff --git a/python/grass/pygrass/modules/tests/grass_pygrass_grid_test.py b/python/grass/pygrass/modules/tests/grass_pygrass_grid_test.py index 6a9915b6a14..c4ada9c4667 100644 --- a/python/grass/pygrass/modules/tests/grass_pygrass_grid_test.py +++ b/python/grass/pygrass/modules/tests/grass_pygrass_grid_test.py @@ -210,7 +210,7 @@ def run_grid_module(): @xfail_mp_spawn @pytest.mark.parametrize( - "width, height, processes", + ("width", "height", "processes"), [ (None, None, max_processes()), (10, None, max_processes()), @@ -249,7 +249,7 @@ def run_grid_module(): @xfail_mp_spawn @pytest.mark.needs_solo_run @pytest.mark.parametrize( - "processes, backend", + ("processes", "backend"), [ (1, "RasterRow"), (9, "RasterRow"), diff --git a/python/grass/script/tests/grass_script_setup_test.py b/python/grass/script/tests/grass_script_setup_test.py index 62a0ca37b74..36dfbb77dbb 100644 --- a/python/grass/script/tests/grass_script_setup_test.py +++ b/python/grass/script/tests/grass_script_setup_test.py @@ -51,7 +51,7 @@ def test_init_session_finish(tmp_path): gs.run_command("g.region", flags="p", env=session.env) session_file = session.env["GISRC"] session.finish() - with pytest.raises(ValueError): + with pytest.raises(ValueError): # noqa: PT011 session.finish() assert not session.active assert not os.path.exists(session_file) diff --git a/temporal/t.rast.list/tests/t_rast_list_test.py b/temporal/t.rast.list/tests/t_rast_list_test.py index fbc092175db..86e539467cd 100644 --- a/temporal/t.rast.list/tests/t_rast_list_test.py +++ b/temporal/t.rast.list/tests/t_rast_list_test.py @@ -83,7 +83,7 @@ def test_yaml(space_time_raster_dataset): @pytest.mark.needs_solo_run @pytest.mark.parametrize( - "separator,delimiter", [(None, ","), (",", ","), (";", ";"), ("tab", "\t")] + ("separator", "delimiter"), [(None, ","), (",", ","), (";", ";"), ("tab", "\t")] ) def test_csv(space_time_raster_dataset, separator, delimiter): """Check CSV can be parsed with different separators""" From 528160218c184121f854674f6b011ba5bdc18630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 5 Oct 2024 16:38:06 -0400 Subject: [PATCH 155/209] style: Fix unnecessary-list-comprehension-dict (C404) (#4454) --- pyproject.toml | 1 - python/grass/pydispatch/robustapply.py | 2 +- python/grass/pygrass/modules/grid/grid.py | 6 ++---- python/grass/pygrass/modules/interface/env.py | 9 +++------ utils/g.html2man/ghtml.py | 2 +- 5 files changed, 7 insertions(+), 13 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5a4bd25283f..3495f022052 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,7 +98,6 @@ ignore = [ "B904", # raise-without-from-inside-except "B909", # loop-iterator-mutation "BLE001", # blind-except - "C404", # unnecessary-list-comprehension-dict "C414", # unnecessary-double-cast-or-process "C416", # unnecessary-comprehension "COM812", # missing-trailing-comma diff --git a/python/grass/pydispatch/robustapply.py b/python/grass/pydispatch/robustapply.py index a050f54341a..cd52f74c22e 100644 --- a/python/grass/pydispatch/robustapply.py +++ b/python/grass/pydispatch/robustapply.py @@ -86,5 +86,5 @@ def robustApply(receiver, *arguments, **named): ) # fc does not have a **kwds type parameter, therefore # remove unacceptable arguments. - named = dict([(k, v) for k, v in named.items() if k in acceptable]) + named = {k: v for k, v in named.items() if k in acceptable} return receiver(*arguments, **named) diff --git a/python/grass/pygrass/modules/grid/grid.py b/python/grass/pygrass/modules/grid/grid.py index e0dbd309656..661d5a3df64 100644 --- a/python/grass/pygrass/modules/grid/grid.py +++ b/python/grass/pygrass/modules/grid/grid.py @@ -122,9 +122,7 @@ def read_gisrc(gisrc): True """ with open(gisrc) as gfile: - gis = dict( - [(k.strip(), v.strip()) for k, v in [row.split(":", 1) for row in gfile]] - ) + gis = {k.strip(): v.strip() for k, v in [row.split(":", 1) for row in gfile]} return gis["MAPSET"], gis["LOCATION_NAME"], gis["GISDBASE"] @@ -603,7 +601,7 @@ def get_works(self): indx = row * cols + col inms[key] = "%s@%s" % (self.inlist[key][indx], self.mset.name) # set the computational region, prepare the region parameters - bbox = dict([(k[0], str(v)) for k, v in box.items()[:-2]]) + bbox = {k[0]: str(v) for k, v in box.items()[:-2]} bbox["nsres"] = "%f" % reg.nsres bbox["ewres"] = "%f" % reg.ewres new_mset = ( diff --git a/python/grass/pygrass/modules/interface/env.py b/python/grass/pygrass/modules/interface/env.py index 1f0519d23c5..d3d6e371238 100644 --- a/python/grass/pygrass/modules/interface/env.py +++ b/python/grass/pygrass/modules/interface/env.py @@ -14,12 +14,9 @@ def get_env(): if gisrc is None: raise RuntimeError("You are not in a GRASS session, GISRC not found.") with open(gisrc) as grc: - return dict( - [ - (k.strip(), v.strip()) - for k, v in [row.split(":", 1) for row in grc if row] - ] - ) + return { + k.strip(): v.strip() for k, v in [row.split(":", 1) for row in grc if row] + } def get_debug_level(): diff --git a/utils/g.html2man/ghtml.py b/utils/g.html2man/ghtml.py index eabb494198d..1a36fd3af06 100644 --- a/utils/g.html2man/ghtml.py +++ b/utils/g.html2man/ghtml.py @@ -95,7 +95,7 @@ def setify(d): - return dict([(key, frozenset(val)) for key, val in d.items()]) + return {key: frozenset(val) for key, val in d.items()} def omit(allowed, tags): From 209739a4dfffa6a08efbfeb6dc92c17b91b0cb35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 5 Oct 2024 17:22:59 -0400 Subject: [PATCH 156/209] style: Fix unnecessary-range-start (PIE808) (#4455) As 0 is the default start value, it can be safely omitted. Ruff rule: https://docs.astral.sh/ruff/rules/unnecessary-range-start/ --- general/g.remove/testsuite/test_g_remove.py | 2 +- gui/wxpython/core/workspace.py | 2 +- gui/wxpython/gui_core/gselect.py | 2 +- gui/wxpython/gui_core/menu.py | 2 +- gui/wxpython/lmgr/frame.py | 4 ++-- gui/wxpython/main_window/frame.py | 4 ++-- gui/wxpython/mapdisp/statusbar.py | 2 +- gui/wxpython/vdigit/wxdisplay.py | 2 +- pyproject.toml | 1 - .../tests/grass_script_tmp_mapset_session_test.py | 4 ++-- scripts/d.polar/d.polar.py | 4 ++-- scripts/i.oif/i.oif.py | 2 +- scripts/i.pansharpen/i.pansharpen.py | 2 +- scripts/i.tasscap/i.tasscap.py | 2 +- scripts/v.report/v.report.py | 2 +- 15 files changed, 18 insertions(+), 19 deletions(-) diff --git a/general/g.remove/testsuite/test_g_remove.py b/general/g.remove/testsuite/test_g_remove.py index 955466f29ca..10c3018f67a 100644 --- a/general/g.remove/testsuite/test_g_remove.py +++ b/general/g.remove/testsuite/test_g_remove.py @@ -52,7 +52,7 @@ def tearDownClass(cls): def test_remove_procedure(self): """Test that maps are removed only with -f""" - for i in range(0, 10): + for i in range(10): rmapcalc("test_map_%i = 100" % i) rmapcalc("test_two = 2") diff --git a/gui/wxpython/core/workspace.py b/gui/wxpython/core/workspace.py index be4eb1fda37..22aa56bfe62 100644 --- a/gui/wxpython/core/workspace.py +++ b/gui/wxpython/core/workspace.py @@ -933,7 +933,7 @@ def __init__(self, lmgr, file): file.write("{indent}\n".format(indent=" " * self.indent)) # list of displays - for page in range(0, self.lmgr.GetLayerNotebook().GetPageCount()): + for page in range(self.lmgr.GetLayerNotebook().GetPageCount()): dispName = self.lmgr.GetLayerNotebook().GetPageText(page) mapTree = self.lmgr.GetLayerNotebook().GetPage(page).maptree region = mapTree.GetMap().GetCurrentRegion() diff --git a/gui/wxpython/gui_core/gselect.py b/gui/wxpython/gui_core/gselect.py index ec873f60eb4..86683476c2e 100644 --- a/gui/wxpython/gui_core/gselect.py +++ b/gui/wxpython/gui_core/gselect.py @@ -2745,7 +2745,7 @@ def __init__( if elements: values = [] valuesDesc = [] - for idx in range(0, len(self.values)): + for idx in range(len(self.values)): value = self.values[idx] if value in elements: values.append(value) diff --git a/gui/wxpython/gui_core/menu.py b/gui/wxpython/gui_core/menu.py index de6b49b7e93..b284461af0a 100644 --- a/gui/wxpython/gui_core/menu.py +++ b/gui/wxpython/gui_core/menu.py @@ -444,7 +444,7 @@ def RemoveFileFromHistory(self, file_index): def RemoveNonExistentFiles(self): """Remove non existent files from the history""" - for i in reversed(range(0, self._filehistory.GetCount())): + for i in reversed(range(self._filehistory.GetCount())): file = self._filehistory.GetHistoryFile(index=i) if not os.path.exists(file): self._filehistory.RemoveFileFromHistory(i=i) diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index f9ce45c813b..9673ab0f1e5 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -1093,7 +1093,7 @@ def GetMapDisplay(self, onlyCurrent=True): return None else: # -> return list of all mapdisplays mlist = [] - for idx in range(0, self.notebookLayers.GetPageCount()): + for idx in range(self.notebookLayers.GetPageCount()): mlist.append(self.notebookLayers.GetPage(idx).maptree.GetMapDisplay()) return mlist @@ -1906,7 +1906,7 @@ def _onMapDisplayStarting3dMode(self, mapDisplayPage): """Disables 3D mode for all map displays except for @p mapDisplay""" # TODO: it should be disabled also for newly created map windows # moreover mapdisp.Disable3dMode() does not work properly - for page in range(0, self.GetLayerNotebook().GetPageCount()): + for page in range(self.GetLayerNotebook().GetPageCount()): mapdisp = self.GetLayerNotebook().GetPage(page).maptree.GetMapDisplay() if self.GetLayerNotebook().GetPage(page) != mapDisplayPage: mapdisp.Disable3dMode() diff --git a/gui/wxpython/main_window/frame.py b/gui/wxpython/main_window/frame.py index 8fc8dc8dde7..0bb28afd883 100644 --- a/gui/wxpython/main_window/frame.py +++ b/gui/wxpython/main_window/frame.py @@ -1244,7 +1244,7 @@ def GetMapDisplay(self, onlyCurrent=True): return None else: # -> return list of all mapdisplays mlist = [] - for idx in range(0, self.notebookLayers.GetPageCount()): + for idx in range(self.notebookLayers.GetPageCount()): mlist.append(self.notebookLayers.GetPage(idx).maptree.GetMapDisplay()) return mlist @@ -2054,7 +2054,7 @@ def _onStarting3dMode(self, mapDisplayPage): """Disables 3D mode for all map displays except for @p mapDisplay""" # TODO: it should be disabled also for newly created map windows # moreover mapdisp.Disable3dMode() does not work properly - for page in range(0, self.GetLayerNotebook().GetPageCount()): + for page in range(self.GetLayerNotebook().GetPageCount()): mapdisp = self.GetLayerNotebook().GetPage(page).maptree.GetMapDisplay() if self.GetLayerNotebook().GetPage(page) != mapDisplayPage: mapdisp.Disable3dMode() diff --git a/gui/wxpython/mapdisp/statusbar.py b/gui/wxpython/mapdisp/statusbar.py index 72e9d0afdbc..649baebc18d 100644 --- a/gui/wxpython/mapdisp/statusbar.py +++ b/gui/wxpython/mapdisp/statusbar.py @@ -138,7 +138,7 @@ def DisableStatusbarItemsByClass(self, itemClasses): :param itemClasses list of classes of items to be disabled """ for itemClass in itemClasses: - for i in range(0, len(self.statusbarItems.values())): + for i in range(len(self.statusbarItems.values())): item = list(self.statusbarItems.values())[i] if item.__class__ == itemClass: self.disabledItems[i] = item diff --git a/gui/wxpython/vdigit/wxdisplay.py b/gui/wxpython/vdigit/wxdisplay.py index 9085aae8caf..d8e4d0a14bf 100644 --- a/gui/wxpython/vdigit/wxdisplay.py +++ b/gui/wxpython/vdigit/wxdisplay.py @@ -824,7 +824,7 @@ def SetSelected(self, ids, layer=-1): found = False cats = self.poCats.contents - for i in range(0, cats.n_cats): + for i in range(cats.n_cats): for cat in self.selected["cats"]: if cats.cat[i] == cat: found = True diff --git a/pyproject.toml b/pyproject.toml index 3495f022052..59fc30964b8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -151,7 +151,6 @@ ignore = [ "PERF402", # manual-list-copy "PERF403", # manual-dict-comprehension "PIE794", # duplicate-class-field-definition - "PIE808", # unnecessary-range-start "PLC0415", # import-outside-top-level "PLC1901", # compare-to-empty-string "PLC2701", # import-private-name diff --git a/python/grass/experimental/tests/grass_script_tmp_mapset_session_test.py b/python/grass/experimental/tests/grass_script_tmp_mapset_session_test.py index 744becc1e7b..f7098004527 100644 --- a/python/grass/experimental/tests/grass_script_tmp_mapset_session_test.py +++ b/python/grass/experimental/tests/grass_script_tmp_mapset_session_test.py @@ -74,7 +74,7 @@ def test_without_context_manager(xy_session): def test_multiple_sequential_with_context_manager(xy_session): """Session creates, starts, and finishes""" session_file = xy_session.env["GISRC"] - for i in range(0, 5): + for i in range(5): with experimental.TemporaryMapsetSession(env=xy_session.env) as session: assert session.active gs.run_command("g.region", flags="p", env=session.env) @@ -104,7 +104,7 @@ def test_multiple_parallel_without_context_manager(xy_session): """Session creates, starts, and finishes""" session_file = xy_session.env["GISRC"] sessions = [] - for i in range(0, 5): + for i in range(5): session_file = xy_session.env["GISRC"] session = experimental.TemporaryMapsetSession(env=xy_session.env) gs.run_command("g.region", flags="p", env=session.env) diff --git a/scripts/d.polar/d.polar.py b/scripts/d.polar/d.polar.py index 915177e94d4..d7e67486a0e 100755 --- a/scripts/d.polar/d.polar.py +++ b/scripts/d.polar/d.polar.py @@ -112,7 +112,7 @@ def plot_dgraph(): 50 * (1 + ring * math.sin(math.radians(i))), 50 * (1 + ring * math.cos(math.radians(i))), ) - for i in range(0, 361) + for i in range(361) ] # trend vector @@ -512,7 +512,7 @@ def main(): outercircle = [] outercircle.append('"All Data incl. NULLs') scale = 1.0 * totalnumber / totalvalidnumber * maxradius - for i in range(0, 361): + for i in range(361): a = math.radians(i) x = math.cos(a) * scale y = math.sin(a) * scale diff --git a/scripts/i.oif/i.oif.py b/scripts/i.oif/i.oif.py index aea65197954..64dffcf70b9 100755 --- a/scripts/i.oif/i.oif.py +++ b/scripts/i.oif/i.oif.py @@ -63,7 +63,7 @@ def oifcalc(sdev, corr, k1, k2, k3): def perms(bands): n = len(bands) - for i in range(0, n - 2): + for i in range(n - 2): for j in range(i + 1, n - 1): for k in range(j + 1, n): yield (bands[i], bands[j], bands[k]) diff --git a/scripts/i.pansharpen/i.pansharpen.py b/scripts/i.pansharpen/i.pansharpen.py index c62a53a536a..bb271c07deb 100755 --- a/scripts/i.pansharpen/i.pansharpen.py +++ b/scripts/i.pansharpen/i.pansharpen.py @@ -749,7 +749,7 @@ def matchhist(original, target, matched): 0 # cumulative total of cells for sum of current and all lower grey values ) - for n in range(0, 256): + for n in range(256): if str(n) in stats_dict: num_cells = stats_dict[str(n)] else: diff --git a/scripts/i.tasscap/i.tasscap.py b/scripts/i.tasscap/i.tasscap.py index 4c68c234c73..dc767fd3f19 100755 --- a/scripts/i.tasscap/i.tasscap.py +++ b/scripts/i.tasscap/i.tasscap.py @@ -352,7 +352,7 @@ def main(): # assign "Data Description" field in all four component maps num_comp = len(parms[satellites.index(satellite)]) - for i in range(0, num_comp): + for i in range(num_comp): comp = names[i] gs.run_command( "r.support", diff --git a/scripts/v.report/v.report.py b/scripts/v.report/v.report.py index 9da9a8b1de7..cec84582155 100755 --- a/scripts/v.report/v.report.py +++ b/scripts/v.report/v.report.py @@ -116,7 +116,7 @@ def main(): cols = decode(line).rstrip("\r\n").split("|") if catcol == -1: ncols = len(cols) - for i in range(0, ncols): + for i in range(ncols): if cols[i] == f["key"]: catcol = i break From cd9e0a48caecd9ff59b1d20ce32b76a374835db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sat, 5 Oct 2024 17:39:13 -0400 Subject: [PATCH 157/209] style: Fix unnecessary-comprehension (C416) (#4453) --- gui/wxpython/lmgr/giface.py | 6 +++--- gui/wxpython/timeline/frame.py | 9 +++------ gui/wxpython/tplot/frame.py | 9 +++------ gui/wxpython/web_services/widgets.py | 2 +- pyproject.toml | 1 - python/grass/imaging/images2gif.py | 4 ++-- python/grass/imaging/images2swf.py | 2 +- python/grass/pygrass/gis/__init__.py | 2 +- python/grass/pygrass/modules/grid/grid.py | 12 ++++++------ python/grass/pygrass/vector/basic.py | 2 +- python/grass/pygrass/vector/table.py | 2 +- python/grass/pygrass/vector/testsuite/test_table.py | 2 +- scripts/i.oif/i.oif.py | 4 +--- 13 files changed, 24 insertions(+), 33 deletions(-) diff --git a/gui/wxpython/lmgr/giface.py b/gui/wxpython/lmgr/giface.py index aa5af7223aa..484a32e8c2d 100644 --- a/gui/wxpython/lmgr/giface.py +++ b/gui/wxpython/lmgr/giface.py @@ -54,7 +54,7 @@ def __init__(self, tree): self._tree = tree def __len__(self): - return len([layer for layer in self]) + return len(list(self)) def __iter__(self): """Iterates over the contents of the list.""" @@ -66,11 +66,11 @@ def __iter__(self): def __getitem__(self, index): """Select a layer from the LayerList using the index.""" - return [layer for layer in self][index] + return list(self)[index] def __repr__(self): """Return a representation of the object.""" - return "LayerList(%r)" % [layer for layer in self] + return "LayerList(%r)" % list(self) def GetSelectedLayers(self, checkedOnly=True): items = self._tree.GetSelectedLayer(multi=True, checkedOnly=checkedOnly) diff --git a/gui/wxpython/timeline/frame.py b/gui/wxpython/timeline/frame.py index 9a783f4f5d5..7ca51cd8989 100644 --- a/gui/wxpython/timeline/frame.py +++ b/gui/wxpython/timeline/frame.py @@ -498,12 +498,9 @@ def _checkDatasets(self, datasets): if allDatasets: allDatasets = reduce(add, reduce(add, allDatasets)) mapsets = tgis.get_tgis_c_library_interface().available_mapsets() - allDatasets = [ - i - for i in sorted( - allDatasets, key=lambda dataset_info: mapsets.index(dataset_info[1]) - ) - ] + allDatasets = sorted( + allDatasets, key=lambda dataset_info: mapsets.index(dataset_info[1]) + ) for dataset in datasets: errorMsg = _("Space time dataset <%s> not found.") % dataset diff --git a/gui/wxpython/tplot/frame.py b/gui/wxpython/tplot/frame.py index 8994485dacc..f52c5a4d190 100755 --- a/gui/wxpython/tplot/frame.py +++ b/gui/wxpython/tplot/frame.py @@ -1156,12 +1156,9 @@ def _checkDatasets(self, datasets, typ): if allDatasets: allDatasets = reduce(add, reduce(add, allDatasets)) mapsets = tgis.get_tgis_c_library_interface().available_mapsets() - allDatasets = [ - i - for i in sorted( - allDatasets, key=lambda dataset_info: mapsets.index(dataset_info[1]) - ) - ] + allDatasets = sorted( + allDatasets, key=lambda dataset_info: mapsets.index(dataset_info[1]) + ) for dataset in datasets: errorMsg = _("Space time dataset <%s> not found.") % dataset diff --git a/gui/wxpython/web_services/widgets.py b/gui/wxpython/web_services/widgets.py index 3cb3af18068..473a8fb58a2 100644 --- a/gui/wxpython/web_services/widgets.py +++ b/gui/wxpython/web_services/widgets.py @@ -633,7 +633,7 @@ def UpdateWidgetsByCmd(self, cmd): # WMS standard - first layer in params is most bottom... # therefore layers order need to be reversed - l_st_list = [layer for layer in reversed(l_st_list)] + l_st_list.reverse() self.list.SelectLayers(l_st_list) params = {} diff --git a/pyproject.toml b/pyproject.toml index 59fc30964b8..f1a5aec9a1c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,7 +99,6 @@ ignore = [ "B909", # loop-iterator-mutation "BLE001", # blind-except "C414", # unnecessary-double-cast-or-process - "C416", # unnecessary-comprehension "COM812", # missing-trailing-comma "COM818", # trailing-comma-on-bare-tuple "D1", diff --git a/python/grass/imaging/images2gif.py b/python/grass/imaging/images2gif.py index a4dc2dc0824..fdb6423eec3 100644 --- a/python/grass/imaging/images2gif.py +++ b/python/grass/imaging/images2gif.py @@ -265,7 +265,7 @@ def handleSubRectangles(self, images, subRectangles): xy = (0, 0) if hasattr(xy, "__len__"): if len(xy) == len(images): - xy = [xxyy for xxyy in xy] + xy = list(xy) else: raise ValueError("len(xy) doesn't match amount of images.") else: @@ -594,7 +594,7 @@ def writeGifVisvis( # Check duration if hasattr(duration, "__len__"): if len(duration) == len(images): - duration = [d for d in duration] + duration = list(duration) else: raise ValueError("len(duration) doesn't match amount of images.") else: diff --git a/python/grass/imaging/images2swf.py b/python/grass/imaging/images2swf.py index 0a08ed9d46d..60352a48f5f 100644 --- a/python/grass/imaging/images2swf.py +++ b/python/grass/imaging/images2swf.py @@ -796,7 +796,7 @@ def writeSwf(filename, images, duration=0.1, repeat=True): # Check duration if hasattr(duration, "__len__"): if len(duration) == len(images2): - duration = [d for d in duration] + duration = list(duration) else: raise ValueError("len(duration) doesn't match amount of images.") else: diff --git a/python/grass/pygrass/gis/__init__.py b/python/grass/pygrass/gis/__init__.py index d31bc31b972..61768859231 100644 --- a/python/grass/pygrass/gis/__init__.py +++ b/python/grass/pygrass/gis/__init__.py @@ -271,7 +271,7 @@ def mapsets(self, pattern=None, permissions=True): [...] """ - mapsets = [mapset for mapset in self] + mapsets = [mapset for mapset in self] # noqa: C416 if permissions: mapsets = [ mapset diff --git a/python/grass/pygrass/modules/grid/grid.py b/python/grass/pygrass/modules/grid/grid.py index 661d5a3df64..ffae173ca79 100644 --- a/python/grass/pygrass/modules/grid/grid.py +++ b/python/grass/pygrass/modules/grid/grid.py @@ -145,7 +145,7 @@ def get_mapset(gisrc_src, gisrc_dst): copy_special_mapset_files(path_src, path_dst) src = Mapset(msrc, lsrc, gsrc) dst = Mapset(mdst, ldst, gdst) - visible = [m for m in src.visible] + visible = list(src.visible) if src.name not in visible: visible.append(src.name) dst.visible.extend(visible) @@ -187,7 +187,7 @@ def rmloc(r): # change gisdbase to src env["GISRC"] = gisrc_src get_grp(group=grp, env_=env) - rasts = [r for r in get_grp.outputs.stdout.split()] + rasts = list(get_grp.outputs.stdout.split()) # change gisdbase to dst env["GISRC"] = gisrc_dst rast2cp = [r for r in rasts if rmloc(r) not in all_rasts] @@ -495,15 +495,15 @@ def __init__( self.gisrc_dst = write_gisrc( self.n_mset.gisdbase, self.n_mset.location, self.n_mset.name ) - rasters = [r for r in select(self.module.inputs, "raster")] + rasters = list(select(self.module.inputs, "raster")) if rasters: copy_rasters( rasters, self.gisrc_src, self.gisrc_dst, region=self.region ) - vectors = [v for v in select(self.module.inputs, "vector")] + vectors = list(select(self.module.inputs, "vector")) if vectors: copy_vectors(vectors, self.gisrc_src, self.gisrc_dst) - groups = [g for g in select(self.module.inputs, "group")] + groups = list(select(self.module.inputs, "group")) if groups: copy_groups(groups, self.gisrc_src, self.gisrc_dst, region=self.region) self.bboxes = split_region_in_overlapping_tiles( @@ -590,7 +590,7 @@ def get_works(self): else: ldst, gdst = self.mset.location, self.mset.gisdbase cmd = self.module.get_dict() - groups = [g for g in select(self.module.inputs, "group")] + groups = list(select(self.module.inputs, "group")) for row, box_row in enumerate(self.bboxes): for col, box in enumerate(box_row): inms = None diff --git a/python/grass/pygrass/vector/basic.py b/python/grass/pygrass/vector/basic.py index 079f7ac829f..b86ae3edb4e 100644 --- a/python/grass/pygrass/vector/basic.py +++ b/python/grass/pygrass/vector/basic.py @@ -329,7 +329,7 @@ def __iter__(self): return (self.c_ilist.contents.value[i] for i in range(self.__len__())) def __repr__(self): - return "Ilist(%r)" % [i for i in self.__iter__()] + return "Ilist(%r)" % list(self.__iter__()) def __contains__(self, item): return item in self.__iter__() diff --git a/python/grass/pygrass/vector/table.py b/python/grass/pygrass/vector/table.py index 634c440a583..78c1c8709b4 100644 --- a/python/grass/pygrass/vector/table.py +++ b/python/grass/pygrass/vector/table.py @@ -944,7 +944,7 @@ def __getitem__(self, item): return self.by_name(item) def __repr__(self): - return "DBlinks(%r)" % [link for link in self.__iter__()] + return "DBlinks(%r)" % list(self.__iter__()) def by_index(self, indx): """Return a Link object by index diff --git a/python/grass/pygrass/vector/testsuite/test_table.py b/python/grass/pygrass/vector/testsuite/test_table.py index 1acb410a10f..d87786fb3bd 100644 --- a/python/grass/pygrass/vector/testsuite/test_table.py +++ b/python/grass/pygrass/vector/testsuite/test_table.py @@ -65,7 +65,7 @@ def get_table_random_values(nrows, columns): raise TypeError("Unknown column type %s for: %s" % (ctype, cname)) vals.append(COL2VALS[ctype](nrows)) dtype.append((cname, vals[-1].dtype.str)) - return np.array([v for v in zip(*vals)], dtype=dtype) + return np.array(list(zip(*vals)), dtype=dtype) class DBconnection: diff --git a/scripts/i.oif/i.oif.py b/scripts/i.oif/i.oif.py index 64dffcf70b9..0dabbe7cb38 100755 --- a/scripts/i.oif/i.oif.py +++ b/scripts/i.oif/i.oif.py @@ -122,9 +122,7 @@ def main(): 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=list(bands), quiet=True) # We need to skip the first line, since r.covar prints the number of values lines = s.splitlines() From 6596d49e636060ac9e92f3dd44fff2c51fc5007f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 5 Oct 2024 23:25:13 +0000 Subject: [PATCH 158/209] CI(deps): Update pre-commit hook pre-commit/pre-commit-hooks to v5 (#4460) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f51f1637422..60865cd3432 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ ci: skip: [flake8] repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: trailing-whitespace exclude: | From 3932773e292e6ea2f3030d79fac15061f985fdd8 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 7 Oct 2024 08:16:02 -0400 Subject: [PATCH 159/209] lib/lidar: Fix resource leak issue in raster.c (#4458) Fix resource leak --- lib/lidar/raster.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/lidar/raster.c b/lib/lidar/raster.c index 4d7305c9a9b..ad531865df7 100644 --- a/lib/lidar/raster.c +++ b/lib/lidar/raster.c @@ -3,6 +3,7 @@ #include #include #include +#include /*------------------------------------------------------------------------------------------------*/ void P_Sparse_Points(struct Map_info *Out, struct Cell_head *Elaboration, @@ -187,6 +188,7 @@ void P_Sparse_Points(struct Map_info *Out, struct Cell_head *Elaboration, } /*IF*/} /*FOR*/ db_commit_transaction(driver); + Vect_destroy_line_struct(point); return; } From aa0b4979e0ff65725c799f2f4630462a5646d238 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 7 Oct 2024 08:16:32 -0400 Subject: [PATCH 160/209] v.reclass: Fix Resource Leak issue in reclass.c (#4457) fix Resource Leak --- vector/v.reclass/reclass.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vector/v.reclass/reclass.c b/vector/v.reclass/reclass.c index 5af40e5473e..4300f4216ff 100644 --- a/vector/v.reclass/reclass.c +++ b/vector/v.reclass/reclass.c @@ -79,6 +79,9 @@ int reclass(struct Map_info *In, struct Map_info *Out, int type, int field, G_warning("For %d elements requested negative category (ignored, no " "category in output)", negative); + Vect_destroy_cats_struct(Cats); + Vect_destroy_cats_struct(NewCats); + Vect_destroy_line_struct(Points); return (rclelem); } From b5c4a273418060c820cad6552a82fdd085a680e6 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 7 Oct 2024 08:40:44 -0400 Subject: [PATCH 161/209] v.rectify: Fix Copy into fix Buffer size issue (#4463) --- vector/v.rectify/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vector/v.rectify/main.c b/vector/v.rectify/main.c index b02630c88ae..86999d6286d 100644 --- a/vector/v.rectify/main.c +++ b/vector/v.rectify/main.c @@ -126,7 +126,9 @@ int main(int argc, char *argv[]) if (grp->answer) { G_strip(grp->answer); - strcpy(group, grp->answer); + if (G_strlcpy(group, grp->answer, sizeof(group)) >= sizeof(group)) { + G_fatal_error(_("Group name <%s> is too long"), grp->answer); + } } else group[0] = '\0'; From de39e1c264c745553948f313e6e0716fcc6a7e19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:39:48 -0400 Subject: [PATCH 162/209] style: Fix unnecessary-paren-on-raise-exception (RSE102) (#4456) Ruff rule: https://docs.astral.sh/ruff/rules/unnecessary-paren-on-raise-exception/ --- gui/wxpython/core/giface.py | 40 ++++++++++++------------- gui/wxpython/core/gthread.py | 2 +- gui/wxpython/core/layerlist.py | 2 +- gui/wxpython/mapwin/analysis.py | 8 ++--- gui/wxpython/mapwin/base.py | 8 ++--- gui/wxpython/modules/import_export.py | 6 ++-- pyproject.toml | 1 - python/grass/imaging/images2swf.py | 2 +- python/grass/pygrass/vector/geometry.py | 2 +- 9 files changed, 35 insertions(+), 36 deletions(-) diff --git a/gui/wxpython/core/giface.py b/gui/wxpython/core/giface.py index 864044593c0..3a1d8c61612 100644 --- a/gui/wxpython/core/giface.py +++ b/gui/wxpython/core/giface.py @@ -60,7 +60,7 @@ def GetSelectedLayers(self, checkedOnly=True): However, this may be the same for some implementations (e.g. it d.mon has all layers checked and selected). """ - raise NotImplementedError() + raise NotImplementedError def GetSelectedLayer(self, checkedOnly=False): """Returns selected layer or None when there is no selected layer. @@ -69,7 +69,7 @@ def GetSelectedLayer(self, checkedOnly=False): Parameter checkedOnly is here False by default. This might change if we find the right way of handling unchecked layers. """ - raise NotImplementedError() + raise NotImplementedError def AddLayer(self, ltype, name=None, checked=None, opacity=1.0, cmd=None): """Adds a new layer to the layer list. @@ -82,7 +82,7 @@ def AddLayer(self, ltype, name=None, checked=None, opacity=1.0, cmd=None): :param opacity: layer opacity level :param cmd: command (given as a list) """ - raise NotImplementedError() + raise NotImplementedError def GetLayersByName(self, name): """Returns list of layers with a given name. @@ -93,7 +93,7 @@ def GetLayersByName(self, name): if common usage is just to check the presence of layer, intoroduce a new method ContainsLayerByName(name) """ - raise NotImplementedError() + raise NotImplementedError def GetLayerByData(self, key, value): """Returns layer with specified. @@ -104,7 +104,7 @@ def GetLayerByData(self, key, value): .. warning:: Avoid using this method, it might be removed in the future. """ - raise NotImplementedError() + raise NotImplementedError class GrassInterface: @@ -118,31 +118,31 @@ class GrassInterface: def RunCmd(self, *args, **kwargs): """Executes a command.""" - raise NotImplementedError() + raise NotImplementedError def Help(self, entry): """Shows a manual page for a given entry.""" - raise NotImplementedError() + raise NotImplementedError def WriteLog(self, text, wrap=None, notification=Notification.HIGHLIGHT): """Writes log message.""" - raise NotImplementedError() + raise NotImplementedError def WriteCmdLog(self, text, pid=None, notification=Notification.MAKE_VISIBLE): """Writes message related to start or end of the command.""" - raise NotImplementedError() + raise NotImplementedError def WriteWarning(self, text): """Writes warning message for the user.""" - raise NotImplementedError() + raise NotImplementedError def WriteError(self, text): """Writes error message for the user.""" - raise NotImplementedError() + raise NotImplementedError def GetLog(self, err=False): """Returns file-like object for writing.""" - raise NotImplementedError() + raise NotImplementedError def GetLayerTree(self): """Returns LayerManager's tree GUI object. @@ -150,11 +150,11 @@ def GetLayerTree(self): Will be removed from the interface. """ - raise NotImplementedError() + raise NotImplementedError def GetLayerList(self): """Returns a layer management object.""" - raise NotImplementedError() + raise NotImplementedError def GetMapDisplay(self): """Returns current map display. @@ -166,7 +166,7 @@ def GetMapDisplay(self): :return: MapFrame instance :return: None when no mapdisplay open """ - raise NotImplementedError() + raise NotImplementedError def GetAllMapDisplays(self): """Get list of all map displays. @@ -177,7 +177,7 @@ def GetAllMapDisplays(self): :return: list of MapFrame instances """ - raise NotImplementedError() + raise NotImplementedError def GetMapWindow(self): """Returns current map window. @@ -186,7 +186,7 @@ def GetMapWindow(self): For layer related tasks use GetLayerList(). """ - raise NotImplementedError() + raise NotImplementedError def GetProgress(self): """Returns object which shows the progress. @@ -195,7 +195,7 @@ def GetProgress(self): Some implementations may not implement this method. """ - raise NotImplementedError() + raise NotImplementedError class StandaloneGrassInterface(GrassInterface): @@ -343,9 +343,9 @@ def GetAllMapDisplays(self): return [] def GetMapWindow(self): - raise NotImplementedError() + raise NotImplementedError def GetProgress(self): # TODO: implement some progress with same inface as gui one # (probably using g.message or similarly to Write... functions) - raise NotImplementedError() + raise NotImplementedError diff --git a/gui/wxpython/core/gthread.py b/gui/wxpython/core/gthread.py index 44a938f335a..1e8e006a969 100644 --- a/gui/wxpython/core/gthread.py +++ b/gui/wxpython/core/gthread.py @@ -160,7 +160,7 @@ def localtrace(self, frame, event, arg): if event == "line": # Send event wx.PostEvent(self, self._terminate_evt) - raise SystemExit() + raise SystemExit return self.localtrace def OnTerminate(self, event): diff --git a/gui/wxpython/core/layerlist.py b/gui/wxpython/core/layerlist.py index b1a9448227d..5b14a4039fd 100644 --- a/gui/wxpython/core/layerlist.py +++ b/gui/wxpython/core/layerlist.py @@ -125,7 +125,7 @@ def GetLayerByData(self, key, value): .. warning:: Avoid using this method, it might be removed in the future. """ - raise NotImplementedError() + raise NotImplementedError def GetLayerIndex(self, layer): """Get index of layer.""" diff --git a/gui/wxpython/mapwin/analysis.py b/gui/wxpython/mapwin/analysis.py index d0a7be1bc0c..4c9ac37a5e0 100644 --- a/gui/wxpython/mapwin/analysis.py +++ b/gui/wxpython/mapwin/analysis.py @@ -93,20 +93,20 @@ def _doAnalysis(self, coords): :param coords: EN coordinates """ - raise NotImplementedError() + raise NotImplementedError def _disconnectAll(self): """Disconnect all mouse signals to stop drawing.""" - raise NotImplementedError() + raise NotImplementedError def _connectAll(self): """Connect all mouse signals to draw.""" - raise NotImplementedError() + raise NotImplementedError def _getPen(self): """Returns wx.Pen instance.""" - raise NotImplementedError() + raise NotImplementedError def Stop(self, restore=True): """Analysis mode is stopped. diff --git a/gui/wxpython/mapwin/base.py b/gui/wxpython/mapwin/base.py index e9752caf953..c05cc8f840b 100644 --- a/gui/wxpython/mapwin/base.py +++ b/gui/wxpython/mapwin/base.py @@ -370,10 +370,10 @@ def UnregisterMouseEventHandler(self, event, handler): return True def Pixel2Cell(self, xyCoords): - raise NotImplementedError() + raise NotImplementedError def Cell2Pixel(self, enCoords): - raise NotImplementedError() + raise NotImplementedError def OnMotion(self, event): """Tracks mouse motion and update statusbar @@ -453,8 +453,8 @@ def SetModeQuery(self): def DisactivateWin(self): """Use when the class instance is hidden in MapFrame.""" - raise NotImplementedError() + raise NotImplementedError def ActivateWin(self): """Used when the class instance is activated in MapFrame.""" - raise NotImplementedError() + raise NotImplementedError diff --git a/gui/wxpython/modules/import_export.py b/gui/wxpython/modules/import_export.py index 03d179ffc2f..43115c943da 100644 --- a/gui/wxpython/modules/import_export.py +++ b/gui/wxpython/modules/import_export.py @@ -236,15 +236,15 @@ def doLayout(self): def _getCommand(self): """Get command""" - raise NotImplementedError() + raise NotImplementedError def _getBlackListedParameters(self): """Get parameters which will not be showed in Settings page""" - raise NotImplementedError() + raise NotImplementedError def _getBlackListedFlags(self): """Get flags which will not be showed in Settings page""" - raise NotImplementedError() + raise NotImplementedError def _nameValidationFailed(self, layers_list): """Output map name validation callback diff --git a/pyproject.toml b/pyproject.toml index f1a5aec9a1c..ce708210d5b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -204,7 +204,6 @@ ignore = [ "RET506", # superfluous-else-raise "RET507", # superfluous-else-continue "RET508", # superfluous-else-break - "RSE102", # unnecessary-paren-on-raise-exception "RUF003", # ambiguous-unicode-character-comment "RUF005", # collection-literal-concatenation "RUF012", # mutable-class-default diff --git a/python/grass/imaging/images2swf.py b/python/grass/imaging/images2swf.py index 60352a48f5f..7d6f5a25f9b 100644 --- a/python/grass/imaging/images2swf.py +++ b/python/grass/imaging/images2swf.py @@ -392,7 +392,7 @@ def __init__(self): def ProcessTag(self): """Implement this to create the tag.""" - raise NotImplementedError() + raise NotImplementedError def GetTag(self): """Calls processTag and attaches the header.""" diff --git a/python/grass/pygrass/vector/geometry.py b/python/grass/pygrass/vector/geometry.py index 1c5d378e6ef..2ff4cb1bb8f 100644 --- a/python/grass/pygrass/vector/geometry.py +++ b/python/grass/pygrass/vector/geometry.py @@ -1869,7 +1869,7 @@ def c_read_next_line(c_mapinfo, c_points, c_cats): v_id = v_id if v_id != 0 else None ftype = libvect.Vect_read_next_line(c_mapinfo, c_points, c_cats) if ftype == -2: - raise StopIteration() + raise StopIteration if ftype == -1: raise return ftype, v_id, c_points, c_cats From 703d9f8bddbc436181c05299d84b18313e1cfb82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:53:02 -0400 Subject: [PATCH 163/209] style: Fix superfluous-else-return (RET505) (#4459) * style: Fix superfluous-else-return (RET505) Ruff rule: https://docs.astral.sh/ruff/rules/superfluous-else-return/ When there is an if with a return, the next `elif:` or `else:` can be flattened with one less nested level. This kind of early-return pattern is common in C#. Having simpler conditions that return, then the rest of flow continues otherwise * Apply black --- gui/wxpython/animation/dialogs.py | 57 +++-- gui/wxpython/animation/provider.py | 5 +- gui/wxpython/animation/utils.py | 3 +- gui/wxpython/core/gcmd.py | 12 +- gui/wxpython/core/gconsole.py | 199 +++++++++--------- gui/wxpython/core/gthread.py | 3 +- gui/wxpython/core/menutree.py | 7 +- gui/wxpython/core/render.py | 12 +- gui/wxpython/core/settings.py | 3 +- gui/wxpython/core/toolboxes.py | 5 +- gui/wxpython/core/treemodel.py | 5 +- gui/wxpython/core/utils.py | 67 +++--- gui/wxpython/datacatalog/tree.py | 11 +- gui/wxpython/dbmgr/base.py | 120 +++++------ gui/wxpython/dbmgr/vinfo.py | 3 +- gui/wxpython/gmodeler/model.py | 24 +-- gui/wxpython/gui_core/dialogs.py | 5 +- gui/wxpython/gui_core/forms.py | 6 +- gui/wxpython/gui_core/gselect.py | 10 +- gui/wxpython/gui_core/mapdisp.py | 3 +- gui/wxpython/gui_core/treeview.py | 3 +- gui/wxpython/gui_core/widgets.py | 15 +- gui/wxpython/gui_core/wrap.py | 102 ++++----- gui/wxpython/history/browser.py | 6 +- gui/wxpython/history/tree.py | 36 ++-- gui/wxpython/image2target/ii2t_gis_set.py | 6 +- gui/wxpython/iscatt/controllers.py | 4 +- gui/wxpython/iscatt/iscatt_core.py | 8 +- gui/wxpython/lmgr/frame.py | 16 +- gui/wxpython/lmgr/giface.py | 22 +- gui/wxpython/lmgr/layertree.py | 3 +- gui/wxpython/location_wizard/wizard.py | 126 ++++++----- gui/wxpython/main_window/frame.py | 13 +- gui/wxpython/mapdisp/frame.py | 3 +- gui/wxpython/mapdisp/main.py | 11 +- gui/wxpython/mapdisp/statusbar.py | 46 ++-- gui/wxpython/mapswipe/dialogs.py | 3 +- gui/wxpython/mapswipe/mapwindow.py | 6 +- gui/wxpython/mapwin/buffered.py | 6 +- gui/wxpython/modules/import_export.py | 6 +- gui/wxpython/nviz/mapwindow.py | 4 +- gui/wxpython/nviz/tools.py | 8 +- gui/wxpython/nviz/wxnviz.py | 6 +- gui/wxpython/psmap/dialogs.py | 3 +- gui/wxpython/psmap/frame.py | 3 +- gui/wxpython/psmap/instructions.py | 6 +- gui/wxpython/psmap/utils.py | 41 ++-- gui/wxpython/rdigit/controller.py | 40 ++-- gui/wxpython/rdigit/dialogs.py | 5 +- gui/wxpython/rlisetup/functions.py | 5 +- gui/wxpython/rlisetup/sampling_frame.py | 55 +++-- gui/wxpython/rlisetup/wizard.py | 18 +- gui/wxpython/startup/locdownload.py | 8 +- gui/wxpython/vdigit/wxdigit.py | 18 +- gui/wxpython/vnet/dialogs.py | 4 +- gui/wxpython/vnet/vnet_core.py | 36 ++-- gui/wxpython/vnet/vnet_data.py | 10 +- gui/wxpython/web_services/cap_interface.py | 25 +-- gui/wxpython/wxplot/histogram.py | 3 +- gui/wxpython/wxplot/profile.py | 3 +- lib/init/grass.py | 17 +- locale/grass_po_stats.py | 5 +- man/build_html.py | 3 +- man/build_manual_gallery.py | 3 +- man/build_rest.py | 3 +- pyproject.toml | 1 - python/grass/grassdb/checks.py | 6 +- python/grass/gunittest/case.py | 7 +- python/grass/gunittest/multireport.py | 3 +- python/grass/gunittest/multirunner.py | 6 +- python/grass/gunittest/reporters.py | 47 ++--- python/grass/gunittest/runner.py | 3 +- python/grass/imaging/images2avi.py | 12 +- python/grass/imaging/images2gif.py | 5 +- python/grass/imaging/images2ims.py | 3 +- python/grass/pydispatch/robustapply.py | 2 +- python/grass/pydispatch/saferef.py | 12 +- python/grass/pygrass/errors.py | 15 +- python/grass/pygrass/gis/__init__.py | 6 +- .../pygrass/modules/interface/docstring.py | 3 +- .../grass/pygrass/modules/interface/flag.py | 6 +- .../grass/pygrass/modules/interface/module.py | 22 +- python/grass/pygrass/raster/__init__.py | 7 +- python/grass/pygrass/raster/abstract.py | 13 +- python/grass/pygrass/raster/buffer.py | 9 +- python/grass/pygrass/raster/category.py | 2 +- python/grass/pygrass/utils.py | 28 ++- python/grass/pygrass/vector/__init__.py | 37 ++-- python/grass/pygrass/vector/abstract.py | 3 +- python/grass/pygrass/vector/basic.py | 8 +- python/grass/pygrass/vector/find.py | 43 ++-- python/grass/pygrass/vector/geometry.py | 27 +-- python/grass/pygrass/vector/table.py | 26 +-- python/grass/script/core.py | 8 +- python/grass/script/db.py | 3 +- python/grass/script/raster.py | 3 +- python/grass/script/raster3d.py | 3 +- python/grass/script/task.py | 9 +- python/grass/script/utils.py | 8 +- python/grass/temporal/abstract_dataset.py | 8 +- python/grass/temporal/abstract_map_dataset.py | 50 ++--- .../temporal/abstract_space_time_dataset.py | 3 +- python/grass/temporal/base.py | 57 ++--- .../grass/temporal/c_libraries_interface.py | 99 +++++---- python/grass/temporal/core.py | 101 +++++---- python/grass/temporal/metadata.py | 178 ++++++---------- python/grass/temporal/space_time_datasets.py | 30 +-- python/grass/temporal/spatial_extent.py | 21 +- python/grass/temporal/temporal_algebra.py | 9 +- python/grass/temporal/temporal_extent.py | 32 ++- python/grass/temporal/temporal_granularity.py | 65 +++--- .../temporal/temporal_raster_base_algebra.py | 2 +- raster/r.topidx/arc_to_gridatb.py | 5 +- scripts/g.extension/g.extension.py | 40 ++-- scripts/g.search.modules/g.search.modules.py | 3 +- scripts/i.image.mosaic/i.image.mosaic.py | 5 +- scripts/r.in.wms/wms_base.py | 3 +- scripts/r.in.wms/wms_drv.py | 2 +- temporal/t.info/t.info.py | 2 +- utils/g.html2man/g.html2man.py | 8 +- utils/g.html2man/ggroff.py | 3 +- utils/g.html2man/ghtml.py | 3 +- utils/mkhtml.py | 10 +- 123 files changed, 1054 insertions(+), 1414 deletions(-) diff --git a/gui/wxpython/animation/dialogs.py b/gui/wxpython/animation/dialogs.py index f6e4db341c5..bc7e7fe2482 100644 --- a/gui/wxpython/animation/dialogs.py +++ b/gui/wxpython/animation/dialogs.py @@ -1548,37 +1548,36 @@ def _export_file_validation(self, filebrowsebtn, file_path, file_postfix): if not file_path: GError(parent=self, message=_("Export file is missing.")) return False - else: - if not file_path.endswith(file_postfix): - filebrowsebtn.SetValue(file_path + file_postfix) - file_path += file_postfix - - base_dir = os.path.dirname(file_path) - if not os.path.exists(base_dir): - GError( - parent=self, - message=file_path_does_not_exist_err_message.format( - base_dir=base_dir, - ), - ) - return False + if not file_path.endswith(file_postfix): + filebrowsebtn.SetValue(file_path + file_postfix) + file_path += file_postfix - if os.path.exists(file_path): - overwrite_dlg = wx.MessageDialog( - self.GetParent(), - message=_( - "Exported animation file <{file}> exists. " - "Do you want to overwrite it?" - ).format( - file=file_path, - ), - caption=_("Overwrite?"), - style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, - ) - if overwrite_dlg.ShowModal() != wx.ID_YES: - overwrite_dlg.Destroy() - return False + base_dir = os.path.dirname(file_path) + if not os.path.exists(base_dir): + GError( + parent=self, + message=file_path_does_not_exist_err_message.format( + base_dir=base_dir, + ), + ) + return False + + if os.path.exists(file_path): + overwrite_dlg = wx.MessageDialog( + self.GetParent(), + message=_( + "Exported animation file <{file}> exists. " + "Do you want to overwrite it?" + ).format( + file=file_path, + ), + caption=_("Overwrite?"), + style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, + ) + if overwrite_dlg.ShowModal() != wx.ID_YES: overwrite_dlg.Destroy() + return False + overwrite_dlg.Destroy() return True diff --git a/gui/wxpython/animation/provider.py b/gui/wxpython/animation/provider.py index fd966219407..43929a1873d 100644 --- a/gui/wxpython/animation/provider.py +++ b/gui/wxpython/animation/provider.py @@ -328,9 +328,8 @@ def LoadOverlay(self, cmd): if returncode == 0: return BitmapFromImage(autoCropImageFromFile(filename)) - else: - os.remove(filename) - raise GException(messages) + os.remove(filename) + raise GException(messages) class BitmapRenderer: diff --git a/gui/wxpython/animation/utils.py b/gui/wxpython/animation/utils.py index 9e5f685545e..5f69bc40d35 100644 --- a/gui/wxpython/animation/utils.py +++ b/gui/wxpython/animation/utils.py @@ -69,8 +69,7 @@ def validateTimeseriesName(timeseries, etype="strds"): nameShort, mapset = timeseries.split("@", 1) if nameShort in trastDict[mapset]: return timeseries - else: - raise GException(_("Space time dataset <%s> not found.") % timeseries) + raise GException(_("Space time dataset <%s> not found.") % timeseries) mapsets = tgis.get_tgis_c_library_interface().available_mapsets() for mapset in mapsets: diff --git a/gui/wxpython/core/gcmd.py b/gui/wxpython/core/gcmd.py index eb40ec57103..a173e28c7f8 100644 --- a/gui/wxpython/core/gcmd.py +++ b/gui/wxpython/core/gcmd.py @@ -202,11 +202,10 @@ def kill(self): handle = win32api.OpenProcess(1, 0, self.pid) return win32api.TerminateProcess(handle, 0) != 0 - else: - try: - os.kill(-self.pid, signal.SIGTERM) # kill whole group - except OSError: - pass + try: + os.kill(-self.pid, signal.SIGTERM) # kill whole group + except OSError: + pass if sys.platform == "win32": @@ -750,8 +749,7 @@ def RunCommand( if not read: if not getErrorMsg: return ret - else: - return ret, _formatMsg(stderr) + return ret, _formatMsg(stderr) if stdout: Debug.msg(3, "gcmd.RunCommand(): return stdout\n'%s'" % stdout) diff --git a/gui/wxpython/core/gconsole.py b/gui/wxpython/core/gconsole.py index 092f9bc704a..a4b58435cf4 100644 --- a/gui/wxpython/core/gconsole.py +++ b/gui/wxpython/core/gconsole.py @@ -552,114 +552,111 @@ def RunCmd( wx.PostEvent(self, event) return - else: - # other GRASS commands (r|v|g|...) - try: - task = GUI(show=None).ParseCommand(command) - except GException as e: - GError(parent=self._guiparent, message=str(e), showTraceback=False) - return - - hasParams = False - if task: - options = task.get_options() - hasParams = options["params"] and options["flags"] - # check for =- - for p in options["params"]: - if ( - p.get("prompt", "") == "input" - and p.get("element", "") == "file" - and p.get("age", "new") == "old" - and p.get("value", "") == "-" - ): - GError( - parent=self._guiparent, - message=_( - "Unable to run command:\n%(cmd)s\n\n" - "Option <%(opt)s>: read from standard input is not " - "supported by wxGUI" - ) - % {"cmd": " ".join(command), "opt": p.get("name", "")}, - ) - return - - if len(command) == 1: - if command[0].startswith("g.gui."): - import inspect - import importlib.util - import importlib.machinery + # other GRASS commands (r|v|g|...) + try: + task = GUI(show=None).ParseCommand(command) + except GException as e: + GError(parent=self._guiparent, message=str(e), showTraceback=False) + return - def load_source(modname, filename): - loader = importlib.machinery.SourceFileLoader( - modname, filename - ) - spec = importlib.util.spec_from_file_location( - modname, filename, loader=loader - ) - module = importlib.util.module_from_spec(spec) - # Module is always executed and not cached in sys.modules. - # Uncomment the following line to cache the module. - # sys.modules[module.__name__] = module - loader.exec_module(module) - return module - - pyFile = command[0] - if sys.platform == "win32": - pyFile += ".py" - pyPath = os.path.join(os.environ["GISBASE"], "scripts", pyFile) - if not os.path.exists(pyPath): - pyPath = os.path.join( - os.environ["GRASS_ADDON_BASE"], "scripts", pyFile - ) - if not os.path.exists(pyPath): - GError( - parent=self._guiparent, - message=_("Module <%s> not found.") % command[0], + hasParams = False + if task: + options = task.get_options() + hasParams = options["params"] and options["flags"] + # check for =- + for p in options["params"]: + if ( + p.get("prompt", "") == "input" + and p.get("element", "") == "file" + and p.get("age", "new") == "old" + and p.get("value", "") == "-" + ): + GError( + parent=self._guiparent, + message=_( + "Unable to run command:\n%(cmd)s\n\n" + "Option <%(opt)s>: read from standard input is not " + "supported by wxGUI" ) - pymodule = load_source(command[0].replace(".", "_"), pyPath) - pymain = inspect.getfullargspec(pymodule.main) - if pymain and "giface" in pymain.args: - pymodule.main(self._giface) - return - - # no arguments given - if hasParams and not isinstance(self._guiparent, FormNotebook): - # also parent must be checked, see #3135 for details - try: - GUI( - parent=self._guiparent, giface=self._giface - ).ParseCommand(command) - self.UpdateHistory(status=Status.SUCCESS) - except GException as e: - print(e, file=sys.stderr) + % {"cmd": " ".join(command), "opt": p.get("name", "")}, + ) + return + if len(command) == 1: + if command[0].startswith("g.gui."): + import inspect + import importlib.util + import importlib.machinery + + def load_source(modname, filename): + loader = importlib.machinery.SourceFileLoader(modname, filename) + spec = importlib.util.spec_from_file_location( + modname, filename, loader=loader + ) + module = importlib.util.module_from_spec(spec) + # Module is always executed and not cached in sys.modules. + # Uncomment the following line to cache the module. + # sys.modules[module.__name__] = module + loader.exec_module(module) + return module + + pyFile = command[0] + if sys.platform == "win32": + pyFile += ".py" + pyPath = os.path.join(os.environ["GISBASE"], "scripts", pyFile) + if not os.path.exists(pyPath): + pyPath = os.path.join( + os.environ["GRASS_ADDON_BASE"], "scripts", pyFile + ) + if not os.path.exists(pyPath): + GError( + parent=self._guiparent, + message=_("Module <%s> not found.") % command[0], + ) + pymodule = load_source(command[0].replace(".", "_"), pyPath) + pymain = inspect.getfullargspec(pymodule.main) + if pymain and "giface" in pymain.args: + pymodule.main(self._giface) return - if env: - env = env.copy() - else: - env = os.environ.copy() - # activate computational region (set with g.region) - # for all non-display commands. - if compReg and "GRASS_REGION" in env: - del env["GRASS_REGION"] + # no arguments given + if hasParams and not isinstance(self._guiparent, FormNotebook): + # also parent must be checked, see #3135 for details + try: + GUI(parent=self._guiparent, giface=self._giface).ParseCommand( + command + ) + self.UpdateHistory(status=Status.SUCCESS) + except GException as e: + print(e, file=sys.stderr) - # process GRASS command with argument - self.cmdThread.RunCmd( - command, - stdout=self.cmdStdOut, - stderr=self.cmdStdErr, - onDone=onDone, - onPrepare=onPrepare, - userData=userData, - addLayer=addLayer, - env=env, - notification=notification, - ) - self.cmdOutputTimer.Start(50) + return + + if env: + env = env.copy() + else: + env = os.environ.copy() + # activate computational region (set with g.region) + # for all non-display commands. + if compReg and "GRASS_REGION" in env: + del env["GRASS_REGION"] + + # process GRASS command with argument + self.cmdThread.RunCmd( + command, + stdout=self.cmdStdOut, + stderr=self.cmdStdErr, + onDone=onDone, + onPrepare=onPrepare, + userData=userData, + addLayer=addLayer, + env=env, + notification=notification, + ) + self.cmdOutputTimer.Start(50) - # we don't need to change computational region settings - # because we work on a copy + # we don't need to change computational region settings + # because we work on a copy else: # Send any other command to the shell. Send output to # console output window diff --git a/gui/wxpython/core/gthread.py b/gui/wxpython/core/gthread.py index 1e8e006a969..3437d04bf56 100644 --- a/gui/wxpython/core/gthread.py +++ b/gui/wxpython/core/gthread.py @@ -152,8 +152,7 @@ def __run(self): def globaltrace(self, frame, event, arg): if event == "call": return self.localtrace - else: - return None + return None def localtrace(self, frame, event, arg): if self.terminate: diff --git a/gui/wxpython/core/menutree.py b/gui/wxpython/core/menutree.py index 4c55d7e9521..fba33daf705 100644 --- a/gui/wxpython/core/menutree.py +++ b/gui/wxpython/core/menutree.py @@ -160,10 +160,9 @@ def GetModel(self, separators=False): """ if separators: return copy.deepcopy(self.model) - else: - model = copy.deepcopy(self.model) - removeSeparators(model) - return model + model = copy.deepcopy(self.model) + removeSeparators(model) + return model def PrintTree(self, fh): for child in self.model.root.children: diff --git a/gui/wxpython/core/render.py b/gui/wxpython/core/render.py index 1d4ed6f5386..2db3287bf78 100644 --- a/gui/wxpython/core/render.py +++ b/gui/wxpython/core/render.py @@ -229,10 +229,8 @@ def GetCmd(self, string=False): scmd.append(utils.GetCmdString(c)) return ";".join(scmd) - else: - return utils.GetCmdString(self.cmd) - else: - return self.cmd + return utils.GetCmdString(self.cmd) + return self.cmd def GetType(self): """Get map layer type""" @@ -462,8 +460,7 @@ def _render(self, cmd, env): stdout, stderr = p.communicate() if p.returncode: return grass.decode(stderr) - else: - return None + return None def Abort(self): """Abort rendering process""" @@ -1690,8 +1687,7 @@ def GetOverlay(self, id, list=False): if not list: if len(ovl) != 1: return None - else: - return ovl[0] + return ovl[0] return ovl diff --git a/gui/wxpython/core/settings.py b/gui/wxpython/core/settings.py index ef3a3031cee..5cc2fddaf44 100644 --- a/gui/wxpython/core/settings.py +++ b/gui/wxpython/core/settings.py @@ -59,8 +59,7 @@ def color(item): return [color(e) for e in item] if isinstance(item, dict): return {key: color(value) for key, value in item.items()} - else: - return item + return item return super().iterencode(color(obj)) diff --git a/gui/wxpython/core/toolboxes.py b/gui/wxpython/core/toolboxes.py index e77010ff213..46b886e4996 100644 --- a/gui/wxpython/core/toolboxes.py +++ b/gui/wxpython/core/toolboxes.py @@ -861,9 +861,8 @@ def module_test(): if someDiff: print("Difference between files.") return 1 - else: - print("OK") - return 0 + print("OK") + return 0 def validate_file(filename): diff --git a/gui/wxpython/core/treemodel.py b/gui/wxpython/core/treemodel.py index dd84fed7bf9..fb18384ba36 100644 --- a/gui/wxpython/core/treemodel.py +++ b/gui/wxpython/core/treemodel.py @@ -137,8 +137,7 @@ def GetChildrenByIndex(self, index): def _getNode(self, node, index): if len(index) == 1: return node.children[index[0]] - else: - return self._getNode(node.children[index[0]], index[1:]) + return self._getNode(node.children[index[0]], index[1:]) def RemoveNode(self, node): """Removes node. If node is root, removes root's children, root is kept.""" @@ -257,7 +256,7 @@ def match(self, method="exact", **kwargs): if method == "exact": return self._match_exact(**kwargs) - elif method == "filtering": + if method == "filtering": return self._match_filtering(**kwargs) def _match_exact(self, **kwargs): diff --git a/gui/wxpython/core/utils.py b/gui/wxpython/core/utils.py index 4be6c18e2a2..3c1b4a7dd14 100644 --- a/gui/wxpython/core/utils.py +++ b/gui/wxpython/core/utils.py @@ -45,8 +45,7 @@ def split(s): try: if sys.platform == "win32": return shlex.split(s.replace("\\", r"\\")) - else: - return shlex.split(s) + return shlex.split(s) except ValueError as e: sys.stderr.write(_("Syntax error: %s") % e) @@ -75,8 +74,7 @@ def GetTempfile(pref=None): path, file = os.path.split(tempfile) if pref: return os.path.join(pref, file) - else: - return tempfile + return tempfile except Exception: return None @@ -341,8 +339,7 @@ def GetVectorNumberOfLayers(vector): _("Vector map <%(map)s>: %(msg)s\n") % {"map": fullname, "msg": msg} ) return layers - else: - Debug.msg(1, "GetVectorNumberOfLayers(): ret %s" % ret) + Debug.msg(1, "GetVectorNumberOfLayers(): ret %s" % ret) for layer in out.splitlines(): layers.append(layer) @@ -374,8 +371,7 @@ def Deg2DMS(lon, lat, string=True, hemisphere=True, precision=3): except ValueError: if string: return "" - else: - return None + return None # fix longitude while flon > 180.0: @@ -457,38 +453,38 @@ def __ll_parts(value, reverse=False, precision=3): s = "%.*f" % (precision, s) return str(d) + ":" + m + ":" + s - else: # -> reverse + # -> reverse + try: + d, m, s = value.split(":") + hs = s[-1] + s = s[:-1] + except ValueError: try: - d, m, s = value.split(":") - hs = s[-1] - s = s[:-1] + d, m = value.split(":") + hs = m[-1] + m = m[:-1] + s = "0.0" except ValueError: try: - d, m = value.split(":") - hs = m[-1] - m = m[:-1] + d = value + hs = d[-1] + d = d[:-1] + m = "0" s = "0.0" except ValueError: - try: - d = value - hs = d[-1] - d = d[:-1] - m = "0" - s = "0.0" - except ValueError: - raise ValueError + raise ValueError - if hs not in {"N", "S", "E", "W"}: - raise ValueError + if hs not in {"N", "S", "E", "W"}: + raise ValueError - coef = 1.0 - if hs in {"S", "W"}: - coef = -1.0 + coef = 1.0 + if hs in {"S", "W"}: + coef = -1.0 - fm = int(m) / 60.0 - fs = float(s) / (60 * 60) + fm = int(m) / 60.0 + fs = float(s) / (60 * 60) - return coef * (float(d) + fm + fs) + return coef * (float(d) + fm + fs) def GetCmdString(cmd): @@ -555,11 +551,10 @@ def ReprojectCoordinates(coord, projOut, projIn=None, flags=""): proj = "" if proj in {"ll", "latlong", "longlat"} and "d" not in flags: return (proj, (e, n)) - else: - try: - return (proj, (float(e), float(n))) - except ValueError: - return (None, None) + try: + return (proj, (float(e), float(n))) + except ValueError: + return (None, None) return (None, None) diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py index 9a460d05f53..176f5231712 100644 --- a/gui/wxpython/datacatalog/tree.py +++ b/gui/wxpython/datacatalog/tree.py @@ -184,13 +184,13 @@ def label(self): owner = data["owner"] or _("name unknown") if data["current"]: return _("{name} (current)").format(**data) - elif data["is_different_owner"] and data["lock"]: + if data["is_different_owner"] and data["lock"]: return _("{name} (in use, owner: {owner})").format( name=data["name"], owner=owner ) - elif data["lock"]: + if data["lock"]: return _("{name} (in use)").format(**data) - elif data["is_different_owner"]: + if data["is_different_owner"]: return _("{name} (owner: {owner})").format( name=data["name"], owner=owner ) @@ -957,7 +957,7 @@ def OnGetItemTextColour(self, index): if node.data["type"] == "mapset": if node.data["current"]: return wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT) - elif node.data["lock"] or node.data["is_different_owner"]: + if node.data["lock"] or node.data["is_different_owner"]: return wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT) return wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT) @@ -2052,8 +2052,7 @@ def _isCurrent(self, genv): currentMapset = False break return currentGrassDb, currentLocation, currentMapset - else: - return True, True, True + return True, True, True def _popupMenuLayer(self): """Create popup menu for layers""" diff --git a/gui/wxpython/dbmgr/base.py b/gui/wxpython/dbmgr/base.py index d7ea818da4c..1af8d6fccb1 100644 --- a/gui/wxpython/dbmgr/base.py +++ b/gui/wxpython/dbmgr/base.py @@ -706,8 +706,7 @@ def Sorter(self, key1, key2): if ascending: return cmpVal - else: - return -cmpVal + return -cmpVal def GetSortImages(self): """Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py""" @@ -2004,37 +2003,36 @@ def OnExtractSelected(self, event): if len(cats) == 0: GMessage(parent=self, message=_("Nothing to extract.")) return - else: - # dialog to get file name - dlg = CreateNewVector( - parent=self, - title=_("Extract selected features"), - giface=self.giface, - cmd=( - ( - "v.extract", - { - "input": self.dbMgrData["vectName"], - "cats": ListOfCatsToRange(cats), - }, - "output", - ) - ), - disableTable=True, - ) - if not dlg: - return + # dialog to get file name + dlg = CreateNewVector( + parent=self, + title=_("Extract selected features"), + giface=self.giface, + cmd=( + ( + "v.extract", + { + "input": self.dbMgrData["vectName"], + "cats": ListOfCatsToRange(cats), + }, + "output", + ) + ), + disableTable=True, + ) + if not dlg: + return - name = dlg.GetName(full=True) + name = dlg.GetName(full=True) - if not self.mapdisplay and self.mapdisplay.tree: - pass - elif name and dlg.IsChecked("add"): - # add layer to map layer tree - self.mapdisplay.tree.AddLayer( - ltype="vector", lname=name, lcmd=["d.vect", "map=%s" % name] - ) - dlg.Destroy() + if not self.mapdisplay and self.mapdisplay.tree: + pass + elif name and dlg.IsChecked("add"): + # add layer to map layer tree + self.mapdisplay.tree.AddLayer( + ltype="vector", lname=name, lcmd=["d.vect", "map=%s" % name] + ) + dlg.Destroy() def OnDeleteSelected(self, event): """Delete vector objects selected in attribute browse window @@ -2606,43 +2604,41 @@ def OnTableItemChange(self, event): message=_("Unable to rename column. No column name defined."), ) return - else: - item = tlist.FindItem(start=-1, str=name) - if item > -1: - if tlist.FindItem(start=-1, str=nameTo) > -1: - GError( - parent=self, - message=_( - "Unable to rename column <%(column)s> to " - "<%(columnTo)s>. Column already exists " - "in the table <%(table)s>." - ) - % {"column": name, "columnTo": nameTo, "table": table}, - ) - return - else: - tlist.SetItemText(item, nameTo) - - self.listOfCommands.append( - ( - "v.db.renamecolumn", - { - "map": self.dbMgrData["vectName"], - "layer": self.selLayer, - "column": "%s,%s" % (name, nameTo), - }, - ) - ) - else: + item = tlist.FindItem(start=-1, str=name) + if item > -1: + if tlist.FindItem(start=-1, str=nameTo) > -1: GError( parent=self, message=_( - "Unable to rename column. " - "Column <%(column)s> doesn't exist in the table <%(table)s>." + "Unable to rename column <%(column)s> to " + "<%(columnTo)s>. Column already exists " + "in the table <%(table)s>." ) - % {"column": name, "table": table}, + % {"column": name, "columnTo": nameTo, "table": table}, ) return + tlist.SetItemText(item, nameTo) + + self.listOfCommands.append( + ( + "v.db.renamecolumn", + { + "map": self.dbMgrData["vectName"], + "layer": self.selLayer, + "column": "%s,%s" % (name, nameTo), + }, + ) + ) + else: + GError( + parent=self, + message=_( + "Unable to rename column. " + "Column <%(column)s> doesn't exist in the table <%(table)s>." + ) + % {"column": name, "table": table}, + ) + return # apply changes self.ApplyCommands(self.listOfCommands, self.listOfSQLStatements) diff --git a/gui/wxpython/dbmgr/vinfo.py b/gui/wxpython/dbmgr/vinfo.py index 6b04ee7a64e..c32ac5572b4 100644 --- a/gui/wxpython/dbmgr/vinfo.py +++ b/gui/wxpython/dbmgr/vinfo.py @@ -37,8 +37,7 @@ def GetUnicodeValue(value): if isinstance(value, bytes): enc = GetDbEncoding() return str(value, enc, errors="replace") - else: - return str(value) + return str(value) def GetDbEncoding(): diff --git a/gui/wxpython/gmodeler/model.py b/gui/wxpython/gmodeler/model.py index 98a7204abbe..23e308037ff 100644 --- a/gui/wxpython/gmodeler/model.py +++ b/gui/wxpython/gmodeler/model.py @@ -1233,8 +1233,7 @@ def GetLog(self, string=True, substitute=None): if string: if cmd is None: return "" - else: - return " ".join(cmd) + return " ".join(cmd) return cmd @@ -1420,8 +1419,7 @@ def GetLog(self, string=True): name.append(rel.GetLabel()) if name: return "/".join(name) + "=" + self.value + " (" + self.prompt + ")" - else: - return self.value + " (" + self.prompt + ")" + return self.value + " (" + self.prompt + ")" def GetLabel(self): """Get list of names""" @@ -1672,7 +1670,7 @@ def GetData(self): """ if isinstance(self.fromShape, ModelData): return self.fromShape - elif isinstance(self.toShape, ModelData): + if isinstance(self.toShape, ModelData): return self.toShape return None @@ -1743,8 +1741,7 @@ def GetLog(self): """Get log info""" if self.label: return _("Condition: ") + self.label - else: - return _("Condition: not defined") + return _("Condition: not defined") def AddRelation(self, rel): """Record relation""" @@ -2024,8 +2021,7 @@ def _getNodeText(self, node, tag, default=""): if p is not None: if p.text: return utils.normalize_whitespace(p.text) - else: - return "" + return "" return default @@ -3322,15 +3318,15 @@ def _getStandardizedOption(self, string): """ if string == "raster": return "G_OPT_R_MAP" - elif string == "vector": + if string == "vector": return "G_OPT_V_MAP" - elif string == "mapset": + if string == "mapset": return "G_OPT_M_MAPSET" - elif string == "file": + if string == "file": return "G_OPT_F_INPUT" - elif string == "dir": + if string == "dir": return "G_OPT_M_DIR" - elif string == "region": + if string == "region": return "G_OPT_M_REGION" return None diff --git a/gui/wxpython/gui_core/dialogs.py b/gui/wxpython/gui_core/dialogs.py index cd2a8dcc24d..a38836ac23e 100644 --- a/gui/wxpython/gui_core/dialogs.py +++ b/gui/wxpython/gui_core/dialogs.py @@ -283,8 +283,7 @@ def GetName(self, full=False): if full: if "@" in name: return name - else: - return name + "@" + grass.gisenv()["MAPSET"] + return name + "@" + grass.gisenv()["MAPSET"] return name.split("@", 1)[0] @@ -427,7 +426,7 @@ def IsChecked(self, key): """ if key == "add": return self.addbox.IsChecked() - elif key == "table": + if key == "table": return self.table.IsChecked() return None diff --git a/gui/wxpython/gui_core/forms.py b/gui/wxpython/gui_core/forms.py index c1123497abf..2636b213df3 100644 --- a/gui/wxpython/gui_core/forms.py +++ b/gui/wxpython/gui_core/forms.py @@ -140,8 +140,7 @@ def text_beautify(someString, width=70): textwrap.wrap(utils.normalize_whitespace(someString), width) ).strip(".,;:") ) - else: - return escape_ampersand(utils.normalize_whitespace(someString).strip(".,;:")) + return escape_ampersand(utils.normalize_whitespace(someString).strip(".,;:")) def escape_ampersand(text): @@ -3206,8 +3205,7 @@ def ParseCommand(self, cmd, completed=None): if self.checkError: return self.grass_task, err - else: - return self.grass_task + return self.grass_task def GetCommandInputMapParamKey(self, cmd): """Get parameter key for input raster/vector map diff --git a/gui/wxpython/gui_core/gselect.py b/gui/wxpython/gui_core/gselect.py index 86683476c2e..ff256803a97 100644 --- a/gui/wxpython/gui_core/gselect.py +++ b/gui/wxpython/gui_core/gselect.py @@ -281,8 +281,7 @@ def GetControl(self): def GetComboCtrl(self): if globalvar.wxPythonPhoenix: return super().GetComboCtrl() - else: - return self.GetCombo() + return self.GetCombo() def GetStringValue(self): """Get value as a string separated by commas""" @@ -524,8 +523,7 @@ def _getElementList(self, element, mapsets=None, elements=None, exclude=False): if elem not in elementdict: self.AddItem(_("Not selectable element"), node=False) return - else: - renamed_elements.append(elementdict[elem]) + renamed_elements.append(elementdict[elem]) if element in {"stds", "strds", "str3ds", "stvds"}: if not self.tgis_error: @@ -2805,9 +2803,9 @@ def GetType(self): sel = self.ftype.GetSelection() if sel == 0: return "point" - elif sel == 1: + if sel == 1: return "line" - elif sel == 2: + if sel == 2: return "boundary" diff --git a/gui/wxpython/gui_core/mapdisp.py b/gui/wxpython/gui_core/mapdisp.py index 4fe1c25ac18..a2810c9892b 100644 --- a/gui/wxpython/gui_core/mapdisp.py +++ b/gui/wxpython/gui_core/mapdisp.py @@ -176,8 +176,7 @@ def GetProperty(self, name): """Returns property""" if hasattr(self.mapWindowProperties, name): return getattr(self.mapWindowProperties, name) - else: - return self.statusbarManager.GetProperty(name) + return self.statusbarManager.GetProperty(name) def HasProperty(self, name): """Checks whether object has property""" diff --git a/gui/wxpython/gui_core/treeview.py b/gui/wxpython/gui_core/treeview.py index b5ee50a7822..a7660308843 100644 --- a/gui/wxpython/gui_core/treeview.py +++ b/gui/wxpython/gui_core/treeview.py @@ -256,8 +256,7 @@ def OnGetItemText(self, index, column=0): # remove & because of & needed in menu (&Files) if column > 0: return node.data.get(self._columns[column], "") - else: - return node.label.replace("&", "") + return node.label.replace("&", "") def OnRightClick(self, event): """Select item on right click. diff --git a/gui/wxpython/gui_core/widgets.py b/gui/wxpython/gui_core/widgets.py index dc9041e3578..87a09a590d8 100644 --- a/gui/wxpython/gui_core/widgets.py +++ b/gui/wxpython/gui_core/widgets.py @@ -188,8 +188,7 @@ def DeletePage(self, page): if ret: del self.notebookPages[page] return ret - else: - return False + return False def RemovePage(self, page): """Delete page without deleting the associated window. @@ -203,8 +202,7 @@ def RemovePage(self, page): if ret: del self.notebookPages[page] return ret - else: - return False + return False def SetSelectionByName(self, page): """Set active notebook page. @@ -814,8 +812,7 @@ def Validate(self, win): if len(text) == 0: self.callback(ctrl) return False - else: - return True + return True def TransferToWindow(self): """Transfer data from validator to window. @@ -865,8 +862,7 @@ def Validate(self, win): if not self._condition(text): self._callback(ctrl) return False - else: - return True + return True def TransferToWindow(self): """Transfer data from validator to window.""" @@ -1183,8 +1179,7 @@ def GetData(self, checked=None): if checked is not None: return tuple(data) - else: - return (tuple(data), tuple(checkedList)) + return (tuple(data), tuple(checkedList)) def LoadData(self, data=None, selectOne=True): """Load data into list""" diff --git a/gui/wxpython/gui_core/wrap.py b/gui/wxpython/gui_core/wrap.py index 29299bbbbe2..b971e5e6eab 100644 --- a/gui/wxpython/gui_core/wrap.py +++ b/gui/wxpython/gui_core/wrap.py @@ -99,36 +99,31 @@ def luminance(c): def BitmapFromImage(image, depth=-1): if wxPythonPhoenix: return wx.Bitmap(img=image, depth=depth) - else: - return wx.BitmapFromImage(image, depth=depth) + return wx.BitmapFromImage(image, depth=depth) def ImageFromBitmap(bitmap): if wxPythonPhoenix: return bitmap.ConvertToImage() - else: - return wx.ImageFromBitmap(bitmap) + return wx.ImageFromBitmap(bitmap) def EmptyBitmap(width, height, depth=-1): if wxPythonPhoenix: return wx.Bitmap(width=width, height=height, depth=depth) - else: - return wx.EmptyBitmap(width=width, height=height, depth=depth) + return wx.EmptyBitmap(width=width, height=height, depth=depth) def EmptyImage(width, height, clear=True): if wxPythonPhoenix: return wx.Image(width=width, height=height, clear=clear) - else: - return wx.EmptyImage(width=width, height=height, clear=clear) + return wx.EmptyImage(width=width, height=height, clear=clear) def StockCursor(cursorId): if wxPythonPhoenix: return wx.Cursor(cursorId=cursorId) - else: - return wx.StockCursor(cursorId) + return wx.StockCursor(cursorId) class Window(wx.Window): @@ -437,20 +432,18 @@ def InsertItem(self, index, label, imageIndex=-1): return wx.ListCtrl.InsertItem( self, index=index, label=label, imageIndex=imageIndex ) - else: - return wx.ListCtrl.InsertStringItem( - self, index=index, label=label, imageIndex=imageIndex - ) + return wx.ListCtrl.InsertStringItem( + self, index=index, label=label, imageIndex=imageIndex + ) def SetItem(self, index, column, label, imageId=-1): if wxPythonPhoenix: return wx.ListCtrl.SetItem( self, index=index, column=column, label=label, imageId=imageId ) - else: - return wx.ListCtrl.SetStringItem( - self, index=index, col=column, label=label, imageId=imageId - ) + return wx.ListCtrl.SetStringItem( + self, index=index, col=column, label=label, imageId=imageId + ) def CheckItem(self, item, check=True): """Uses either deprecated listmix.CheckListCtrlMixin @@ -463,8 +456,7 @@ def CheckItem(self, item, check=True): def IsItemChecked(self, item): if hasattr(self, "HasCheckBoxes"): return wx.ListCtrl.IsItemChecked(self, item) - else: - return super().IsChecked(item) + return super().IsChecked(item) if CheckWxVersion([4, 1, 0]): @@ -497,16 +489,14 @@ def __init__(self, *args, **kwargs): def AppendItem(self, parent, text, image=-1, selImage=-1, data=None): if wxPythonPhoenix: return wx.TreeCtrl.AppendItem(self, parent, text, image, selImage, data) - else: - return wx.TreeCtrl.AppendItem( - self, parent, text, image, selImage, wx.TreeItemData(data) - ) + return wx.TreeCtrl.AppendItem( + self, parent, text, image, selImage, wx.TreeItemData(data) + ) def GetItemData(self, item): if wxPythonPhoenix: return wx.TreeCtrl.GetItemData(self, item) - else: - return wx.TreeCtrl.GetPyData(self, item) + return wx.TreeCtrl.GetPyData(self, item) class CustomTreeCtrl(CT.CustomTreeCtrl): @@ -553,18 +543,17 @@ def AddLabelTool( longHelp=longHelpString, clientData=clientData, ) - else: - return wx.ToolBar.AddLabelTool( - self, - toolId, - label, - bitmap, - bmpDisabled, - kind, - shortHelpString, - longHelpString, - clientData, - ) + return wx.ToolBar.AddLabelTool( + self, + toolId, + label, + bitmap, + bmpDisabled, + kind, + shortHelpString, + longHelpString, + clientData, + ) def InsertLabelTool( self, @@ -591,19 +580,18 @@ def InsertLabelTool( longHelp=longHelpString, clientData=clientData, ) - else: - return wx.ToolBar.InsertLabelTool( - self, - pos, - toolId, - label, - bitmap, - bmpDisabled, - kind, - shortHelpString, - longHelpString, - clientData, - ) + return wx.ToolBar.InsertLabelTool( + self, + pos, + toolId, + label, + bitmap, + bmpDisabled, + kind, + shortHelpString, + longHelpString, + clientData, + ) class Menu(wx.Menu): @@ -689,8 +677,7 @@ def __init__(self, *args, **kwargs): def GetFullMultiLineTextExtent(self, string, font=None): if wxPythonPhoenix: return super().GetFullMultiLineTextExtent(string, font) - else: - return super().GetMultiLineTextExtent(string, font) + return super().GetMultiLineTextExtent(string, font) class Rect(wx.Rect): @@ -705,20 +692,17 @@ def __init__(self, *args, **kwargs): def ContainsXY(self, x, y): if wxPythonPhoenix: return wx.Rect.Contains(self, x=int(x), y=int(y)) - else: - return wx.Rect.ContainsXY(self, int(x), int(y)) + return wx.Rect.ContainsXY(self, int(x), int(y)) def ContainsRect(self, rect): if wxPythonPhoenix: return wx.Rect.Contains(self, rect=rect) - else: - return wx.Rect.ContainsRect(self, rect) + return wx.Rect.ContainsRect(self, rect) def OffsetXY(self, dx, dy): if wxPythonPhoenix: return wx.Rect.Offset(self, int(dx), int(dy)) - else: - return wx.Rect.OffsetXY(self, int(dx), int(dy)) + return wx.Rect.OffsetXY(self, int(dx), int(dy)) class CheckBox(wx.CheckBox): diff --git a/gui/wxpython/history/browser.py b/gui/wxpython/history/browser.py index 422d6dcc9c2..03e39a884a3 100644 --- a/gui/wxpython/history/browser.py +++ b/gui/wxpython/history/browser.py @@ -59,11 +59,11 @@ def get_translated_value(key, value): if key == "timestamp": exec_datetime = datetime.fromisoformat(value) return exec_datetime.strftime("%Y-%m-%d %H:%M:%S") - elif key == "runtime": + if key == "runtime": return _("{} sec").format(value) - elif key == "status": + if key == "status": return _(value.capitalize()) - elif key in {"mask2d", "mask3d"}: + if key in {"mask2d", "mask3d"}: return _(str(value)) diff --git a/gui/wxpython/history/tree.py b/gui/wxpython/history/tree.py index 74c321aeb67..3701fefb001 100644 --- a/gui/wxpython/history/tree.py +++ b/gui/wxpython/history/tree.py @@ -62,8 +62,7 @@ def __init__(self, data=None): def label(self): if "day" in self.data.keys(): return self.dayToLabel(self.data["day"]) - else: - return self.data["name"] + return self.data["name"] @property def time_sort(self): @@ -91,14 +90,13 @@ def dayToLabel(self, day): if day == current_date: return _("{base_date} (today)").format(base_date=base_date) - elif day == current_date - datetime.timedelta(days=1): + if day == current_date - datetime.timedelta(days=1): return _("{base_date} (yesterday)").format(base_date=base_date) - elif day >= (current_date - datetime.timedelta(days=current_date.weekday())): + if day >= (current_date - datetime.timedelta(days=current_date.weekday())): return _("{base_date} (this week)").format(base_date=base_date) - elif day.year == current_date.year: + if day.year == current_date.year: return _("{base_date}").format(base_date=base_date) - else: - return _("{base_date}, {year}").format(base_date=base_date, year=day.year) + return _("{base_date}, {year}").format(base_date=base_date, year=day.year) class HistoryTreeModel(TreeModel): @@ -338,12 +336,11 @@ def _getIndexFromFile(self, command_node): """ if not command_node.data["timestamp"]: return self._model.GetIndexOfNode(command_node)[1] - else: - return history.filter( - json_data=self.ReadFromHistory(), - command=command_node.data["name"], - timestamp=self._timestampToISO(command_node.data["timestamp"]), - ) + return history.filter( + json_data=self.ReadFromHistory(), + command=command_node.data["name"], + timestamp=self._timestampToISO(command_node.data["timestamp"]), + ) def ReadFromHistory(self): """Read content of command history log. @@ -409,13 +406,10 @@ def GetHistoryNode(self, entry, command_index=None): if command_index is None: # If no command index is specified, return the first found day node return day_nodes[0] - else: - # Search for command nodes under the first day node - command_nodes = self._model.SearchNodes( - parent=day_nodes[0], type=COMMAND - ) - if 0 <= command_index < len(command_nodes): - return command_nodes[command_index] + # Search for command nodes under the first day node + command_nodes = self._model.SearchNodes(parent=day_nodes[0], type=COMMAND) + if 0 <= command_index < len(command_nodes): + return command_nodes[command_index] return None @@ -585,7 +579,7 @@ def OnGetItemImage(self, index, which=wx.TreeItemIcon_Normal, column=0): try: if node.data["type"] == TIME_PERIOD: return self._iconTypes.index(node.data["type"]) - elif node.data["type"] == COMMAND: + if node.data["type"] == COMMAND: return self._iconTypes.index(node.data["status"]) except ValueError: return 0 diff --git a/gui/wxpython/image2target/ii2t_gis_set.py b/gui/wxpython/image2target/ii2t_gis_set.py index 4e5a5aee200..6ed97bc46c1 100644 --- a/gui/wxpython/image2target/ii2t_gis_set.py +++ b/gui/wxpython/image2target/ii2t_gis_set.py @@ -596,8 +596,7 @@ def GetRCValue(self, value): """Return GRASS variable (read from GISRC)""" if value in self.grassrc: return self.grassrc[value] - else: - return None + return None def OnWizard(self, event): """Location wizard started""" @@ -1046,8 +1045,7 @@ def OnCreateMapset(self, event): if dlg.ShowModal() == wx.ID_OK: mapset = dlg.GetValue() return self.CreateNewMapset(mapset=mapset) - else: - return False + return False def CreateNewMapset(self, mapset): if mapset in self.listOfMapsets: diff --git a/gui/wxpython/iscatt/controllers.py b/gui/wxpython/iscatt/controllers.py index 4cd1c3c66f6..fef4e95505e 100644 --- a/gui/wxpython/iscatt/controllers.py +++ b/gui/wxpython/iscatt/controllers.py @@ -238,7 +238,7 @@ def AddScattPlot(self): ) ) return - elif ncells > WARN_NCELLS: + if ncells > WARN_NCELLS: dlg = wx.MessageDialog( parent=self.guiparent, message=_( @@ -344,7 +344,7 @@ def CheckBands(self, b_1, b_2): ), ) return False - elif mrange > WARN_SCATT_SIZE: + if mrange > WARN_SCATT_SIZE: dlg = wx.MessageDialog( parent=self.guiparent, message=_( diff --git a/gui/wxpython/iscatt/iscatt_core.py b/gui/wxpython/iscatt/iscatt_core.py index a881fab5845..86321ed2ff1 100644 --- a/gui/wxpython/iscatt/iscatt_core.py +++ b/gui/wxpython/iscatt/iscatt_core.py @@ -323,7 +323,7 @@ def _create_grass_region_env(self, bbox): if bbox["maxy"] <= r["s"]: return 0 - elif bbox["maxy"] >= r["n"]: + if bbox["maxy"] >= r["n"]: new_r["n"] = bbox["maxy"] else: new_r["n"] = ( @@ -332,7 +332,7 @@ def _create_grass_region_env(self, bbox): if bbox["miny"] >= r["n"]: return 0 - elif bbox["miny"] <= r["s"]: + if bbox["miny"] <= r["s"]: new_r["s"] = bbox["miny"] else: new_r["s"] = ( @@ -341,7 +341,7 @@ def _create_grass_region_env(self, bbox): if bbox["maxx"] <= r["w"]: return 0 - elif bbox["maxx"] >= r["e"]: + if bbox["maxx"] >= r["e"]: new_r["e"] = bbox["maxx"] else: new_r["e"] = ( @@ -350,7 +350,7 @@ def _create_grass_region_env(self, bbox): if bbox["minx"] >= r["e"]: return 0 - elif bbox["minx"] <= r["w"]: + if bbox["minx"] <= r["w"]: new_r["w"] = bbox["minx"] else: new_r["w"] = ( diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 9673ab0f1e5..80f373239f8 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -385,8 +385,7 @@ def _createNotebook(self): """Initialize notebook widget""" if sys.platform == "win32": return GNotebook(parent=self, style=globalvar.FNPageDStyle) - else: - return FormNotebook(parent=self, style=wx.NB_BOTTOM) + return FormNotebook(parent=self, style=wx.NB_BOTTOM) def _createDataCatalog(self, parent): """Initialize Data Catalog widget""" @@ -1089,14 +1088,13 @@ def GetMapDisplay(self, onlyCurrent=True): if onlyCurrent: if self.currentPage: return self.GetLayerTree().GetMapDisplay() - else: - return None - else: # -> return list of all mapdisplays - mlist = [] - for idx in range(self.notebookLayers.GetPageCount()): - mlist.append(self.notebookLayers.GetPage(idx).maptree.GetMapDisplay()) + return None + # -> return list of all mapdisplays + mlist = [] + for idx in range(self.notebookLayers.GetPageCount()): + mlist.append(self.notebookLayers.GetPage(idx).maptree.GetMapDisplay()) - return mlist + return mlist def GetAllMapDisplays(self): """Get all (open) map displays""" diff --git a/gui/wxpython/lmgr/giface.py b/gui/wxpython/lmgr/giface.py index 484a32e8c2d..eac9a7fb2d8 100644 --- a/gui/wxpython/lmgr/giface.py +++ b/gui/wxpython/lmgr/giface.py @@ -86,9 +86,8 @@ def GetSelectedLayer(self, checkedOnly=False): item = self._tree.GetSelectedLayer(multi=False, checkedOnly=checkedOnly) if item is None: return None - else: - data = self._tree.GetPyData(item) - return Layer(item, data) + data = self._tree.GetPyData(item) + return Layer(item, data) def GetLayerInfo(self, layer): """For compatibility only, will be removed.""" @@ -147,12 +146,11 @@ def GetLayersByName(self, name): items = self._tree.FindItemByData(key="name", value=name) if items is None: return [] - else: - layers = [] - for item in items: - layer = Layer(item, self._tree.GetPyData(item)) - layers.append(layer) - return layers + layers = [] + for item in items: + layer = Layer(item, self._tree.GetPyData(item)) + layers.append(layer) + return layers def GetLayerByData(self, key, value): """Returns layer with specified. @@ -168,8 +166,7 @@ def GetLayerByData(self, key, value): item = self._tree.FindItemByData(key=key, value=value) if item is None: return None - else: - return Layer(item, self._tree.GetPyData(item)) + return Layer(item, self._tree.GetPyData(item)) class LayerManagerGrassInterface: @@ -268,8 +265,7 @@ def GetAllMapDisplays(self): def GetMapWindow(self): if self.lmgr.GetMapDisplay(onlyCurrent=True): return self.lmgr.GetMapDisplay(onlyCurrent=True).GetMapWindow() - else: - return None + return None def GetProgress(self): return self.lmgr.goutput.GetProgressBar() diff --git a/gui/wxpython/lmgr/layertree.py b/gui/wxpython/lmgr/layertree.py index 52dc0115480..daefab44223 100644 --- a/gui/wxpython/lmgr/layertree.py +++ b/gui/wxpython/lmgr/layertree.py @@ -2336,8 +2336,7 @@ def FindItemByData(self, key, value): item = self.GetFirstChild(self.root)[0] if key == "name": return self.__FindSubItemByName(item, value) - else: - return self.__FindSubItemByData(item, key, value) + return self.__FindSubItemByData(item, key, value) def FindItemByIndex(self, index): """Find item by index (starting at 0) diff --git a/gui/wxpython/location_wizard/wizard.py b/gui/wxpython/location_wizard/wizard.py index 28ce94fbc48..d8b6b4180ba 100644 --- a/gui/wxpython/location_wizard/wizard.py +++ b/gui/wxpython/location_wizard/wizard.py @@ -591,7 +591,7 @@ def OnText(self, event): self.tproj.SetValue(self.proj) nextButton.Enable(False) return - elif self.proj.lower() == "ll": + if self.proj.lower() == "ll": self.p4proj = "+proj=longlat" else: self.p4proj = "+proj=" + self.proj.lower() @@ -771,8 +771,7 @@ def Sorter(self, key1, key2): if ascending: return cmpVal - else: - return -cmpVal + return -cmpVal def GetListCtrl(self): """Used by listmix.ColumnSorterMixin""" @@ -804,12 +803,10 @@ def Search(self, index, pattern, firstOnly=True): if len(data) > 0: if firstOnly: return data[0] - else: - return data - elif firstOnly: + return data + if firstOnly: return None - else: - return [] + return [] class ProjParamsPage(TitledPage): @@ -1660,29 +1657,28 @@ def OnPageChanging(self, event): if not self.epsgcode: event.Veto() return - else: - # check for datum transforms - ret = RunCommand( - "g.proj", read=True, epsg=self.epsgcode, datum_trans="-1", flags="t" - ) + # check for datum transforms + ret = RunCommand( + "g.proj", read=True, epsg=self.epsgcode, datum_trans="-1", flags="t" + ) - if ret != "": - dtrans = "" - # open a dialog to select datum transform number - dlg = SelectTransformDialog(self.parent.parent, transforms=ret) + if ret != "": + dtrans = "" + # open a dialog to select datum transform number + dlg = SelectTransformDialog(self.parent.parent, transforms=ret) - if dlg.ShowModal() == wx.ID_OK: - dtrans = dlg.GetTransform() - if dtrans == "": - dlg.Destroy() - event.Veto() - return "Datum transform is required." - else: + if dlg.ShowModal() == wx.ID_OK: + dtrans = dlg.GetTransform() + if dtrans == "": dlg.Destroy() event.Veto() return "Datum transform is required." + else: + dlg.Destroy() + event.Veto() + return "Datum transform is required." - self.parent.datum_trans = dtrans + self.parent.datum_trans = dtrans self.GetNext().SetPrev(self) def EnableNext(self, enable=True): @@ -1880,55 +1876,51 @@ def OnPageChanging(self, event): if not self.epsgcode: event.Veto() return - else: - # check for datum transforms - ret = RunCommand( - "g.proj", - read=True, - proj4=self.epsgparams, - datum_trans="-1", - flags="t", - ) + # check for datum transforms + ret = RunCommand( + "g.proj", + read=True, + proj4=self.epsgparams, + datum_trans="-1", + flags="t", + ) - if ret != "": - dtrans = "" - # open a dialog to select datum transform number - dlg = SelectTransformDialog(self.parent.parent, transforms=ret) + if ret != "": + dtrans = "" + # open a dialog to select datum transform number + dlg = SelectTransformDialog(self.parent.parent, transforms=ret) - if dlg.ShowModal() == wx.ID_OK: - dtrans = dlg.GetTransform() - if dtrans == "": - dlg.Destroy() - event.Veto() - return "Datum transform is required." - else: + if dlg.ShowModal() == wx.ID_OK: + dtrans = dlg.GetTransform() + if dtrans == "": dlg.Destroy() event.Veto() return "Datum transform is required." + else: + dlg.Destroy() + event.Veto() + return "Datum transform is required." - self.parent.datum_trans = dtrans - self.parent.epsgcode = self.epsgcode - self.parent.epsgdesc = self.epsgdesc + self.parent.datum_trans = dtrans + self.parent.epsgcode = self.epsgcode + self.parent.epsgdesc = self.epsgdesc - # prepare +nadgrids or +towgs84 terms for Summary page. first - # convert them: - ret, projlabel, err = RunCommand( - "g.proj", - flags="jft", - proj4=self.epsgparams, - datum_trans=self.parent.datum_trans, - getErrorMsg=True, - read=True, - ) - # splitting on space alone would break for grid files with - # space in pathname - for projterm in projlabel.split(" +"): - if ( - projterm.find("towgs84=") != -1 - or projterm.find("nadgrids=") != -1 - ): - self.custom_dtrans_string = " +%s" % projterm - break + # prepare +nadgrids or +towgs84 terms for Summary page. first + # convert them: + ret, projlabel, err = RunCommand( + "g.proj", + flags="jft", + proj4=self.epsgparams, + datum_trans=self.parent.datum_trans, + getErrorMsg=True, + read=True, + ) + # splitting on space alone would break for grid files with + # space in pathname + for projterm in projlabel.split(" +"): + if projterm.find("towgs84=") != -1 or projterm.find("nadgrids=") != -1: + self.custom_dtrans_string = " +%s" % projterm + break self.GetNext().SetPrev(self) diff --git a/gui/wxpython/main_window/frame.py b/gui/wxpython/main_window/frame.py index 0bb28afd883..cef4aee7121 100644 --- a/gui/wxpython/main_window/frame.py +++ b/gui/wxpython/main_window/frame.py @@ -1240,14 +1240,13 @@ def GetMapDisplay(self, onlyCurrent=True): if onlyCurrent: if self.currentPage: return self.GetLayerTree().GetMapDisplay() - else: - return None - else: # -> return list of all mapdisplays - mlist = [] - for idx in range(self.notebookLayers.GetPageCount()): - mlist.append(self.notebookLayers.GetPage(idx).maptree.GetMapDisplay()) + return None + # -> return list of all mapdisplays + mlist = [] + for idx in range(self.notebookLayers.GetPageCount()): + mlist.append(self.notebookLayers.GetPage(idx).maptree.GetMapDisplay()) - return mlist + return mlist def GetAllMapDisplays(self): """Get all (open) map displays""" diff --git a/gui/wxpython/mapdisp/frame.py b/gui/wxpython/mapdisp/frame.py index f13ffbe0a81..c9b5d86e4ba 100644 --- a/gui/wxpython/mapdisp/frame.py +++ b/gui/wxpython/mapdisp/frame.py @@ -1230,8 +1230,7 @@ def AddTmpVectorMapLayer(self, name, cats, useId=False, addLayer=True): render=True, **args, ) - else: - return cmd + return cmd def OnMeasureDistance(self, event): self._onMeasure(MeasureDistanceController) diff --git a/gui/wxpython/mapdisp/main.py b/gui/wxpython/mapdisp/main.py index 016261d248d..6449bc35d7c 100644 --- a/gui/wxpython/mapdisp/main.py +++ b/gui/wxpython/mapdisp/main.py @@ -334,14 +334,14 @@ def __init__(self, maplayer): def __getattr__(self, name): if name == "cmd": return cmdtuple_to_list(self._maplayer.GetCmd()) - elif hasattr(self._maplayer, name): + if hasattr(self._maplayer, name): return getattr(self._maplayer, name) - elif name == "maplayer": + if name == "maplayer": return self._maplayer - elif name == "type": + if name == "type": return self._maplayer.GetType() # elif name == 'ctrl': - elif name == "label": + if name == "label": return self._maplayer.GetName() # elif name == 'propwin': @@ -386,8 +386,7 @@ def GetSelectedLayer(self, checkedOnly=False): layers = self.GetSelectedLayers() if len(layers) > 0: return layers[0] - else: - return None + return None def AddLayer(self, ltype, name=None, checked=None, opacity=1.0, cmd=None): """Adds a new layer to the layer list. diff --git a/gui/wxpython/mapdisp/statusbar.py b/gui/wxpython/mapdisp/statusbar.py index 649baebc18d..4fea1ffcc81 100644 --- a/gui/wxpython/mapdisp/statusbar.py +++ b/gui/wxpython/mapdisp/statusbar.py @@ -631,10 +631,8 @@ def GetCenterString(self, map): return "%s" % utils.Deg2DMS( coord[0], coord[1], precision=precision ) - else: - return "%.*f; %.*f" % (precision, coord[0], precision, coord[1]) - else: - raise SbException(_("Error in projection (check the settings)")) + return "%.*f; %.*f" % (precision, coord[0], precision, coord[1]) + raise SbException(_("Error in projection (check the settings)")) elif self.mapFrame.GetMap().projinfo["proj"] == "ll" and format == "DMS": return "%s" % utils.Deg2DMS( region["center_easting"], @@ -806,10 +804,8 @@ def ReprojectENFromMap(self, e, n, useDefinedProjection, precision, format): e, n = coord if proj in {"ll", "latlong", "longlat"} and format == "DMS": return utils.Deg2DMS(e, n, precision=precision) - else: - return "%.*f; %.*f" % (precision, e, precision, n) - else: - raise SbException(_("Error in projection (check the settings)")) + return "%.*f; %.*f" % (precision, e, precision, n) + raise SbException(_("Error in projection (check the settings)")) elif self.mapFrame.GetMap().projinfo["proj"] == "ll" and format == "DMS": return utils.Deg2DMS(e, n, precision=precision) else: @@ -860,8 +856,7 @@ def _formatRegion(self, w, e, s, n, nsres, ewres, precision=None): precision, n, ) - else: - return "%s - %s, %s - %s" % (w, e, s, n) + return "%s - %s, %s - %s" % (w, e, s, n) def ReprojectRegionFromMap(self, region, useDefinedProjection, precision, format): """Reproject region values @@ -910,21 +905,19 @@ def ReprojectRegionFromMap(self, region, useDefinedProjection, precision, format return self._formatRegion( w=w, s=s, e=e, n=n, ewres=ewres, nsres=nsres ) - else: - w, s = coord1 - e, n = coord2 - ewres, nsres = coord3 - return self._formatRegion( - w=w, - s=s, - e=e, - n=n, - ewres=ewres, - nsres=nsres, - precision=precision, - ) - else: - raise SbException(_("Error in projection (check the settings)")) + w, s = coord1 + e, n = coord2 + ewres, nsres = coord3 + return self._formatRegion( + w=w, + s=s, + e=e, + n=n, + ewres=ewres, + nsres=nsres, + precision=precision, + ) + raise SbException(_("Error in projection (check the settings)")) elif self.mapFrame.GetMap().projinfo["proj"] == "ll" and format == "DMS": w, s = utils.Deg2DMS( @@ -971,8 +964,7 @@ def _formatRegion(self, w, e, s, n, ewres, nsres, precision=None): precision, nsres, ) - else: - return "%s - %s, %s - %s (%s, %s)" % (w, e, s, n, ewres, nsres) + return "%s - %s, %s - %s (%s, %s)" % (w, e, s, n, ewres, nsres) def _getRegion(self): """Returns computational region.""" diff --git a/gui/wxpython/mapswipe/dialogs.py b/gui/wxpython/mapswipe/dialogs.py index 945aee590ea..a765f3774ce 100644 --- a/gui/wxpython/mapswipe/dialogs.py +++ b/gui/wxpython/mapswipe/dialogs.py @@ -241,8 +241,7 @@ def GetValues(self): """Get raster maps""" if self.IsSimpleMode(): return (self._firstRaster.GetValue(), self._secondRaster.GetValue()) - else: - return (self._firstLayerList, self._secondLayerList) + return (self._firstLayerList, self._secondLayerList) def IsSimpleMode(self) -> bool: return bool(self._switchSizer.IsShown(self._firstPanel)) diff --git a/gui/wxpython/mapswipe/mapwindow.py b/gui/wxpython/mapswipe/mapwindow.py index dbb181eb62b..a203ef2e6d1 100644 --- a/gui/wxpython/mapswipe/mapwindow.py +++ b/gui/wxpython/mapswipe/mapwindow.py @@ -81,8 +81,7 @@ def GetClientSize(self): """Overridden method which returns simulated window size.""" if self._mode == "swipe": return self.specialSize - else: - return super().GetClientSize() + return super().GetClientSize() def SetClientSize(self, size): """Overridden method which sets simulated window size.""" @@ -100,8 +99,7 @@ def GetImageCoords(self): """Returns coordinates of rendered image""" if self._mode == "swipe": return self.specialCoords - else: - return (0, 0) + return (0, 0) def SetImageCoords(self, coords): """Sets coordinates of rendered image""" diff --git a/gui/wxpython/mapwin/buffered.py b/gui/wxpython/mapwin/buffered.py index d8c6413017b..c4b07a94fd2 100644 --- a/gui/wxpython/mapwin/buffered.py +++ b/gui/wxpython/mapwin/buffered.py @@ -560,8 +560,7 @@ def TextBounds(self, textinfo, relcoords=False): bbox[2], bbox[3] = w, h if relcoords: return coords, bbox, relCoords - else: - return coords, bbox + return coords, bbox boxh = math.fabs(math.sin(math.radians(rotation)) * w) + h boxw = math.fabs(math.cos(math.radians(rotation)) * w) + h @@ -580,8 +579,7 @@ def TextBounds(self, textinfo, relcoords=False): bbox.Inflate(h, h) if relcoords: return coords, bbox, relCoords - else: - return coords, bbox + return coords, bbox def OnPaint(self, event): """Draw PseudoDC's to buffered paint DC diff --git a/gui/wxpython/modules/import_export.py b/gui/wxpython/modules/import_export.py index 43115c943da..f2f70e47831 100644 --- a/gui/wxpython/modules/import_export.py +++ b/gui/wxpython/modules/import_export.py @@ -538,8 +538,7 @@ def _getCommand(self): """Get command""" if self.link: return "r.external" - else: - return "r.import" + return "r.import" def _getBlackListedParameters(self): """Get flags which will not be showed in Settings page""" @@ -693,8 +692,7 @@ def _getCommand(self): """Get command""" if self.link: return "v.external" - else: - return "v.import" + return "v.import" def _getBlackListedParameters(self): """Get parametrs which will not be showed in Settings page""" diff --git a/gui/wxpython/nviz/mapwindow.py b/gui/wxpython/nviz/mapwindow.py index 550939da7ce..8cf972704e2 100644 --- a/gui/wxpython/nviz/mapwindow.py +++ b/gui/wxpython/nviz/mapwindow.py @@ -2358,10 +2358,10 @@ def GetLayerId(self, type, name, vsubtyp=None): try: if type == "raster": return data["surface"]["object"]["id"] - elif type == "vector": + if type == "vector": if vsubtyp == "vpoint": return data["vector"]["points"]["object"]["id"] - elif vsubtyp == "vline": + if vsubtyp == "vline": return data["vector"]["lines"]["object"]["id"] elif type == "raster_3d": return data["volume"]["object"]["id"] diff --git a/gui/wxpython/nviz/tools.py b/gui/wxpython/nviz/tools.py index 0659c5cc2ba..20b1df1ffbd 100644 --- a/gui/wxpython/nviz/tools.py +++ b/gui/wxpython/nviz/tools.py @@ -2646,9 +2646,9 @@ def GetLayerData(self, nvizType, nameOnly=False): if nvizType in {"surface", "fringe"}: return self._getLayerPropertiesByName(name, mapType="raster") - elif nvizType == "vector": + if nvizType == "vector": return self._getLayerPropertiesByName(name, mapType="vector") - elif nvizType == "volume": + if nvizType == "volume": return self._getLayerPropertiesByName(name, mapType="raster_3d") return None @@ -2857,7 +2857,7 @@ def OnSaveAnimation(self, event): if not prefix: GMessage(parent=self, message=_("No file prefix given.")) return - elif not os.path.exists(dir): + if not os.path.exists(dir): GMessage(parent=self, message=_("Directory %s does not exist.") % dir) return @@ -4576,7 +4576,7 @@ def OnVolumeSelect(self, event): selection = event.GetSelection() if selection == -1: return - elif selection == 0: + if selection == 0: winUp.Enable(False) if not winDown.IsEnabled(): winDown.Enable() diff --git a/gui/wxpython/nviz/wxnviz.py b/gui/wxpython/nviz/wxnviz.py index e80a9fc9382..47cf99c079d 100644 --- a/gui/wxpython/nviz/wxnviz.py +++ b/gui/wxpython/nviz/wxnviz.py @@ -246,8 +246,7 @@ def GetFocus(self): z = c_float() Nviz_get_focus(self.data, byref(x), byref(y), byref(z)) return x.value, y.value, z.value - else: - return -1, -1, -1 + return -1, -1, -1 def SetFocus(self, x, y, z): """Set focus""" @@ -1873,8 +1872,7 @@ def SetCPlaneInteractively(self, x, y): Nviz_draw_cplane(self.data, -1, -1) x, y, z = self.GetCPlaneTranslation() return x, y, z - else: - return None, None, None + return None, None, None def SelectCPlane(self, index): """Select cutting plane diff --git a/gui/wxpython/psmap/dialogs.py b/gui/wxpython/psmap/dialogs.py index 41493795893..66ac66d9348 100644 --- a/gui/wxpython/psmap/dialogs.py +++ b/gui/wxpython/psmap/dialogs.py @@ -526,8 +526,7 @@ def OnApply(self, event): if ok: self.parent.DialogDataChanged(id=self.id) return True - else: - return False + return False def OnOK(self, event): """Apply changes, close dialog""" diff --git a/gui/wxpython/psmap/frame.py b/gui/wxpython/psmap/frame.py index fa4a150aa3b..b3196d348fa 100644 --- a/gui/wxpython/psmap/frame.py +++ b/gui/wxpython/psmap/frame.py @@ -994,8 +994,7 @@ def getModifiedTextBounds(self, x, y, textExtent, rotation): Y = y - H if rotation == 0: return Rect(x, y, *textExtent) - else: - return Rect(X, Y, abs(W), abs(H)).Inflate(h, h) + return Rect(X, Y, abs(W), abs(H)).Inflate(h, h) def makePSFont(self, textDict): """creates a wx.Font object from selected postscript font. To be diff --git a/gui/wxpython/psmap/instructions.py b/gui/wxpython/psmap/instructions.py index 3c1b2e6d7bb..9db64679422 100644 --- a/gui/wxpython/psmap/instructions.py +++ b/gui/wxpython/psmap/instructions.py @@ -1217,9 +1217,9 @@ def GetImageOrigSize(self, imagePath): break file.close() return float(w), float(h) - else: # we can use wx.Image - img = wx.Image(fileName, type=wx.BITMAP_TYPE_ANY) - return img.GetWidth(), img.GetHeight() + # we can use wx.Image + img = wx.Image(fileName, type=wx.BITMAP_TYPE_ANY) + return img.GetWidth(), img.GetHeight() class NorthArrow(Image): diff --git a/gui/wxpython/psmap/utils.py b/gui/wxpython/psmap/utils.py index d54a45a52be..6bb53acd9f0 100644 --- a/gui/wxpython/psmap/utils.py +++ b/gui/wxpython/psmap/utils.py @@ -162,17 +162,15 @@ def convertRGB(rgb): return name return str(rgb.Red()) + ":" + str(rgb.Green()) + ":" + str(rgb.Blue()) # transform a GRASS named color or an r:g:b string into a wx.Colour tuple - else: - color = ( - int(gs.parse_color(rgb)[0] * 255), - int(gs.parse_color(rgb)[1] * 255), - int(gs.parse_color(rgb)[2] * 255), - ) - color = wx.Colour(*color) - if color.IsOk(): - return color - else: - return None + color = ( + int(gs.parse_color(rgb)[0] * 255), + int(gs.parse_color(rgb)[1] * 255), + int(gs.parse_color(rgb)[2] * 255), + ) + color = wx.Colour(*color) + if color.IsOk(): + return color + return None def PaperMapCoordinates(mapInstr, x, y, paperToMap=True, env=None): @@ -198,18 +196,16 @@ def PaperMapCoordinates(mapInstr, x, y, paperToMap=True, env=None): if projInfo()["proj"] == "ll": return e, n - else: - return int(e), int(n) + return int(e), int(n) - else: - diffEW = x - region["w"] - diffNS = region["n"] - y - diffX = mapWidthPaper * diffEW / mapWidthEN - diffY = mapHeightPaper * diffNS / mapHeightEN - xPaper = mapInstr["rect"].GetX() + diffX - yPaper = mapInstr["rect"].GetY() + diffY + diffEW = x - region["w"] + diffNS = region["n"] - y + diffX = mapWidthPaper * diffEW / mapWidthEN + diffY = mapHeightPaper * diffNS / mapHeightEN + xPaper = mapInstr["rect"].GetX() + diffX + yPaper = mapInstr["rect"].GetY() + diffY - return xPaper, yPaper + return xPaper, yPaper def AutoAdjust(self, scaleType, rect, env, map=None, mapType=None, region=None): @@ -403,8 +399,7 @@ def getRasterType(map): file = gs.find_file(name=map, element="cell") if file.get("file"): return gs.raster_info(map)["datatype"] - else: - return None + return None def BBoxAfterRotation(w, h, angle): diff --git a/gui/wxpython/rdigit/controller.py b/gui/wxpython/rdigit/controller.py index 2e98ca32ccc..8018ee04e5c 100644 --- a/gui/wxpython/rdigit/controller.py +++ b/gui/wxpython/rdigit/controller.py @@ -421,28 +421,26 @@ def SelectNewMap( ) return False return True - else: - dlg = NewRasterDialog(parent=self._mapWindow) - dlg.CenterOnParent() - if dlg.ShowModal() == wx.ID_OK: - try: - self._createNewMap( - mapName=dlg.GetMapName(), - backgroundMap=dlg.GetBackgroundMapName(), - mapType=dlg.GetMapType(), - ) - except ScriptError: - GError( - parent=self._mapWindow, - message=_("Failed to create new raster map."), - ) - return False - finally: - dlg.Destroy() - return True - else: - dlg.Destroy() + dlg = NewRasterDialog(parent=self._mapWindow) + dlg.CenterOnParent() + if dlg.ShowModal() == wx.ID_OK: + try: + self._createNewMap( + mapName=dlg.GetMapName(), + backgroundMap=dlg.GetBackgroundMapName(), + mapType=dlg.GetMapType(), + ) + except ScriptError: + GError( + parent=self._mapWindow, + message=_("Failed to create new raster map."), + ) return False + finally: + dlg.Destroy() + return True + dlg.Destroy() + return False def _createNewMap(self, mapName, backgroundMap, mapType): """Creates a new raster map based on specified background and type.""" diff --git a/gui/wxpython/rdigit/dialogs.py b/gui/wxpython/rdigit/dialogs.py index c632a84c0fe..fa9f57b8253 100644 --- a/gui/wxpython/rdigit/dialogs.py +++ b/gui/wxpython/rdigit/dialogs.py @@ -117,9 +117,8 @@ def OnOK(self, event): if dlgOverwrite.ShowModal() != wx.ID_YES: dlgOverwrite.Destroy() return - else: - dlgOverwrite.Destroy() - self.EndModal(wx.ID_OK) + dlgOverwrite.Destroy() + self.EndModal(wx.ID_OK) else: self.EndModal(wx.ID_OK) diff --git a/gui/wxpython/rlisetup/functions.py b/gui/wxpython/rlisetup/functions.py index 2ce0b747dcd..fc9d3c3d202 100644 --- a/gui/wxpython/rlisetup/functions.py +++ b/gui/wxpython/rlisetup/functions.py @@ -60,9 +60,8 @@ def retRLiPath(): rlipath = os.path.join(grass_config_dir, "r.li") if os.path.exists(rlipath): return rlipath - else: - os.mkdir(rlipath) - return rlipath + os.mkdir(rlipath) + return rlipath def checkMapExists(name, typ="raster") -> bool: diff --git a/gui/wxpython/rlisetup/sampling_frame.py b/gui/wxpython/rlisetup/sampling_frame.py index 860c0b91d8f..a379ef8c09c 100644 --- a/gui/wxpython/rlisetup/sampling_frame.py +++ b/gui/wxpython/rlisetup/sampling_frame.py @@ -550,33 +550,32 @@ def _toolbarData(self): ), ) ) - else: - return self._getToolbarData( + return self._getToolbarData( + ( + drawTool, + (None,), ( - drawTool, - (None,), - ( - ("pan", BaseIcons["pan"].label), - BaseIcons["pan"], - self.parent.OnPan, - wx.ITEM_CHECK, - ), - ( - ("zoomIn", BaseIcons["zoomIn"].label), - BaseIcons["zoomIn"], - self.parent.OnZoomIn, - wx.ITEM_CHECK, - ), - ( - ("zoomOut", BaseIcons["zoomOut"].label), - BaseIcons["zoomOut"], - self.parent.OnZoomOut, - wx.ITEM_CHECK, - ), - ( - ("zoomExtent", BaseIcons["zoomExtent"].label), - BaseIcons["zoomExtent"], - self.parent.OnZoomToMap, - ), - ) + ("pan", BaseIcons["pan"].label), + BaseIcons["pan"], + self.parent.OnPan, + wx.ITEM_CHECK, + ), + ( + ("zoomIn", BaseIcons["zoomIn"].label), + BaseIcons["zoomIn"], + self.parent.OnZoomIn, + wx.ITEM_CHECK, + ), + ( + ("zoomOut", BaseIcons["zoomOut"].label), + BaseIcons["zoomOut"], + self.parent.OnZoomOut, + wx.ITEM_CHECK, + ), + ( + ("zoomExtent", BaseIcons["zoomExtent"].label), + BaseIcons["zoomExtent"], + self.parent.OnZoomToMap, + ), ) + ) diff --git a/gui/wxpython/rlisetup/wizard.py b/gui/wxpython/rlisetup/wizard.py index 4ecbb60e188..6fb7988159d 100644 --- a/gui/wxpython/rlisetup/wizard.py +++ b/gui/wxpython/rlisetup/wizard.py @@ -720,13 +720,12 @@ def CheckVector(self, vector): % vector ) return False, [] - elif links > 0: + if links > 0: layers = [] for i in range(1, links + 1): layers.append(str(i)) return True, layers - else: - return False, [] + return False, [] def CheckInput(self): """Check input fields. @@ -1819,14 +1818,13 @@ def afterRegionDrawn(self): self.areaOK.Enable(False) self.areaNO.Enable(False) return True - else: - self.title.SetLabel( - _("Select sample area {areas_count} of {area_num}").format( - areas_count=self.areascount + 1, area_num=self.areanum - ) + self.title.SetLabel( + _("Select sample area {areas_count} of {area_num}").format( + areas_count=self.areascount + 1, area_num=self.areanum ) - wx.FindWindowById(wx.ID_FORWARD).Enable(False) - return False + ) + wx.FindWindowById(wx.ID_FORWARD).Enable(False) + return False def OnYes(self, event): """Function to create the string for the conf file if the area diff --git a/gui/wxpython/startup/locdownload.py b/gui/wxpython/startup/locdownload.py index 75eae560244..ccbeaa8fb0c 100644 --- a/gui/wxpython/startup/locdownload.py +++ b/gui/wxpython/startup/locdownload.py @@ -386,8 +386,7 @@ def CheckItem(self, item): ) self.parent.download_button.SetLabel(label=_("Download")) return - else: - self._clearMessage() + self._clearMessage() def GetLocation(self): """Get the name of the last location downloaded by the user""" @@ -496,9 +495,8 @@ def OnCancel(self, event=None): if ret == wx.ID_NO: return - else: - self.panel.thread.Terminate() - self.panel._change_download_btn_label() + self.panel.thread.Terminate() + self.panel._change_download_btn_label() if event: self.EndModal(wx.ID_CANCEL) diff --git a/gui/wxpython/vdigit/wxdigit.py b/gui/wxpython/vdigit/wxdigit.py index 154d5ab7c81..eda912284a0 100644 --- a/gui/wxpython/vdigit/wxdigit.py +++ b/gui/wxpython/vdigit/wxdigit.py @@ -294,10 +294,8 @@ def _getSnapMode(self): if threshold > 0.0: if UserSettings.Get(group="vdigit", key="snapToVertex", subkey="enabled"): return SNAPVERTEX - else: - return SNAP - else: - return NO_SNAP + return SNAP + return NO_SNAP def _getNewFeaturesLayer(self): """Returns layer of new feature (from settings)""" @@ -672,8 +670,7 @@ def _getLineAreaBboxCats(self, ln_id): # TODO centroid opttimization, can be edited also its area -> it # will appear two times in new_ lists return self._getCentroidAreaBboxCats(ln_id) - else: - return [self._getBbox(ln_id)], [self._getLineAreasCategories(ln_id)] + return [self._getBbox(ln_id)], [self._getLineAreasCategories(ln_id)] def _getCentroidAreaBboxCats(self, centroid): """Helper function @@ -688,8 +685,7 @@ def _getCentroidAreaBboxCats(self, centroid): area = Vect_get_centroid_area(self.poMapInfo, centroid) if area > 0: return self._getaAreaBboxCats(area) - else: - return None + return None def _getaAreaBboxCats(self, area): """Helper function @@ -1946,8 +1942,7 @@ def _addFeature(self, ftype, coords, layer, cat, snap, threshold): if newc < 0: self._error.WriteLine() return (len(fids), fids) - else: - fids.append(newc) + fids.append(newc) if right > 0 and Vect_get_area_centroid(self.poMapInfo, right) == 0: # if Vect_get_area_points(byref(self.poMapInfo), right, bpoints) > 0 and @@ -1964,8 +1959,7 @@ def _addFeature(self, ftype, coords, layer, cat, snap, threshold): if newc < 0: self._error.WriteLine() return len(fids, fids) - else: - fids.append(newc) + fids.append(newc) Vect_destroy_line_struct(bpoints) diff --git a/gui/wxpython/vnet/dialogs.py b/gui/wxpython/vnet/dialogs.py index a445b01e8eb..39cf2e4ae84 100644 --- a/gui/wxpython/vnet/dialogs.py +++ b/gui/wxpython/vnet/dialogs.py @@ -766,7 +766,7 @@ def OnVectSel(self, event): for sel in ["arc_column", "arc_backward_column", "node_column"]: self.inputData[sel].SetValue("") return - elif itemsLen == 1: + if itemsLen == 1: self.inputData["arc_layer"].SetSelection(0) self.inputData["node_layer"].SetSelection(0) elif itemsLen >= 1: @@ -1648,7 +1648,7 @@ def InputSel(self): self._updateInputDbMgrPage(show=False) self.inputData["arc_layer"].SetValue("") return - elif itemsLen == 1: + if itemsLen == 1: self.inputData["arc_layer"].SetSelection(0) elif itemsLen >= 1: if "1" in items: diff --git a/gui/wxpython/vnet/vnet_core.py b/gui/wxpython/vnet/vnet_core.py index ac7625a4c22..8dda73b6770 100644 --- a/gui/wxpython/vnet/vnet_core.py +++ b/gui/wxpython/vnet/vnet_core.py @@ -144,8 +144,7 @@ def RunAnalysis(self): ) if not ret: return -3 - else: - return 1 + return 1 def RunAnDone(self, cmd, returncode, results): self.results["analysis"] = cmd[0] @@ -307,19 +306,18 @@ def _createTtbDone(self, event): if event.returncode != 0: GMessage(parent=self.guiparent, message=_("Creation of turntable failed.")) return - else: - params = {} - for c in event.cmd: - spl_c = c.split("=") - if len(spl_c) != 2: - continue + params = {} + for c in event.cmd: + spl_c = c.split("=") + if len(spl_c) != 2: + continue - if spl_c[0] and spl_c != "input": - params[spl_c[0]] = spl_c[1] - if spl_c[0] == "output": - params["input"] = spl_c[1] + if spl_c[0] and spl_c != "input": + params[spl_c[0]] = spl_c[1] + if spl_c[0] == "output": + params["input"] = spl_c[1] - self.vnet_data.SetParams(params, {}) + self.vnet_data.SetParams(params, {}) self.ttbCreated.emit(returncode=event.returncode) @@ -1147,14 +1145,10 @@ def ComputeNodes(self, activate): return 0 # map is already created and up to date for input data - else: - self.snapPts.AddRenderLayer() - - self.giface.updateMap.emit(render=True, renderVector=True) - - self.snapping.emit(evt="computing_points_done") - - return 1 + self.snapPts.AddRenderLayer() + self.giface.updateMap.emit(render=True, renderVector=True) + self.snapping.emit(evt="computing_points_done") + return 1 def _onNodesDone(self, event): """Update map window, when map with nodes to snap is created""" diff --git a/gui/wxpython/vnet/vnet_data.py b/gui/wxpython/vnet/vnet_data.py index 9c5b592e043..3adc5fa64e9 100644 --- a/gui/wxpython/vnet/vnet_data.py +++ b/gui/wxpython/vnet/vnet_data.py @@ -78,16 +78,14 @@ def GetGlobalTurnsData(self): def GetRelevantParams(self, analysis=None): if analysis: return self.an_props.GetRelevantParams(analysis) - else: - analysis, valid = self.an_params.GetParam("analysis") - return self.an_props.GetRelevantParams(analysis) + analysis, valid = self.an_params.GetParam("analysis") + return self.an_props.GetRelevantParams(analysis) def GetAnalysisProperties(self, analysis=None): if analysis: return self.an_props[analysis] - else: - analysis, valid = self.an_params.GetParam("analysis") - return self.an_props[analysis] + analysis, valid = self.an_params.GetParam("analysis") + return self.an_props[analysis] def GetParam(self, param): return self.an_params.GetParam(param) diff --git a/gui/wxpython/web_services/cap_interface.py b/gui/wxpython/web_services/cap_interface.py index 4287375dd47..38cc7c3c72f 100644 --- a/gui/wxpython/web_services/cap_interface.py +++ b/gui/wxpython/web_services/cap_interface.py @@ -49,8 +49,7 @@ def GetRootLayer(self): """Get children layers""" if self.layers_by_id: return self.layers_by_id[0] - else: - return None + return None class LayerBase: @@ -137,15 +136,13 @@ def GetLayerData(self, param): title_node = self.layer_node.find(title) if title_node is not None: return title_node.text - else: - return None + return None if param == "name": name_node = self.layer_node.find(name) if name_node is not None: return name_node.text - else: - return None + return None if param == "format": return self.cap.GetFormats() @@ -228,22 +225,20 @@ def GetLayerData(self, param): if self.layer_node is None and param in {"title", "name"}: return None - elif self.layer_node is None: + if self.layer_node is None: return [] if param == "title": title_node = self.layer_node.find(title) if title_node is not None: return title_node.text - else: - return None + return None if param == "name": name_node = self.layer_node.find(name) if name_node is not None: return name_node.text - else: - return None + return None if param == "styles": styles = [] @@ -366,22 +361,20 @@ def GetLayerData(self, param): """Get layer data""" if self.layer_node is None and param in {"title", "name"}: return None - elif self.layer_node is None: + if self.layer_node is None: return [] if param == "title": title_node = self.layer_node.find("Title") if title_node is not None: return title_node.text - else: - return None + return None if param == "name": name_node = self.layer_node.find("Name") if name_node is not None: return name_node.text - else: - return None + return None if param == "styles": return [] diff --git a/gui/wxpython/wxplot/histogram.py b/gui/wxpython/wxplot/histogram.py index f8319747dab..ef252f0b052 100644 --- a/gui/wxpython/wxplot/histogram.py +++ b/gui/wxpython/wxplot/histogram.py @@ -243,8 +243,7 @@ def CreatePlotList(self): if len(self.plotlist) > 0: return self.plotlist - else: - return None + return None def Update(self): """Update histogram after changing options""" diff --git a/gui/wxpython/wxplot/profile.py b/gui/wxpython/wxplot/profile.py index 61efdcd67d0..240290e5b7b 100644 --- a/gui/wxpython/wxplot/profile.py +++ b/gui/wxpython/wxplot/profile.py @@ -398,8 +398,7 @@ def CreatePlotList(self): if len(self.plotlist) > 0: return self.plotlist - else: - return None + return None def Update(self): """Update profile after changing options""" diff --git a/lib/init/grass.py b/lib/init/grass.py index 233bcf53460..f489ad1fe53 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -737,22 +737,21 @@ def cannot_create_location_reason(gisdbase, location): " the project <{location}>" " already exists." ).format(**locals()) - elif os.path.isfile(path): + if os.path.isfile(path): return _( "Unable to create new project <{location}> because <{path}> is a file." ).format(**locals()) - elif os.path.isdir(path): + if os.path.isdir(path): return _( "Unable to create new project <{location}> because" " the directory <{path}>" " already exists." ).format(**locals()) - else: - return _( - "Unable to create new project in" - " the directory <{path}>" - " for an unknown reason." - ).format(**locals()) + return _( + "Unable to create new project in" + " the directory <{path}>" + " for an unknown reason." + ).format(**locals()) def set_mapset( @@ -1419,7 +1418,7 @@ def script_path(batch_job): if script_in_addon_path and os.path.exists(script_in_addon_path): batch_job[0] = script_in_addon_path return script_in_addon_path - elif os.path.exists(batch_job[0]): + if os.path.exists(batch_job[0]): return batch_job[0] try: diff --git a/locale/grass_po_stats.py b/locale/grass_po_stats.py index 0c49e44bc8d..bfae49629d3 100644 --- a/locale/grass_po_stats.py +++ b/locale/grass_po_stats.py @@ -81,10 +81,9 @@ def langDefinition(fil): f.close() if len(lang) == 2: return " ".join(lang) - elif len(lang) == 1: + if len(lang) == 1: return lang[0] - else: - return "" + return "" def get_stats(languages, directory): diff --git a/man/build_html.py b/man/build_html.py index c89df29e290..0ef860d42f3 100644 --- a/man/build_html.py +++ b/man/build_html.py @@ -494,8 +494,7 @@ def get_desc(cmd): sp = line.split("-", 1) if len(sp) > 1: return sp[1].strip() - else: - return None + return None return "" diff --git a/man/build_manual_gallery.py b/man/build_manual_gallery.py index 51a6fbcd312..a8b077be8f9 100755 --- a/man/build_manual_gallery.py +++ b/man/build_manual_gallery.py @@ -132,8 +132,7 @@ def title_from_names(module_name, img_name): img_name = img_name.strip() if img_name: return "{name} ({desc})".format(name=module_name, desc=img_name) - else: - return "{name}".format(name=module_name) + return "{name}".format(name=module_name) def get_module_name(filename): diff --git a/man/build_rest.py b/man/build_rest.py index 473827fcc86..a98a099a076 100644 --- a/man/build_rest.py +++ b/man/build_rest.py @@ -355,8 +355,7 @@ def get_desc(cmd): sp = line.split("-", 1) if len(sp) > 1: return sp[1].strip() - else: - return None + return None return "" diff --git a/pyproject.toml b/pyproject.toml index ce708210d5b..6147e2db897 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -200,7 +200,6 @@ ignore = [ "RET501", # unnecessary-return-none "RET502", # implicit-return-value "RET503", # implicit-return - "RET505", # superfluous-else-return "RET506", # superfluous-else-raise "RET507", # superfluous-else-continue "RET508", # superfluous-else-break diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 6916ea2748a..369cdf60e62 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -222,13 +222,13 @@ def get_reason_id_mapset_not_usable(mapset_path): if not os.path.exists(mapset_path): return "non-existent" # Check whether mapset is valid - elif not is_mapset_valid(mapset_path): + if not is_mapset_valid(mapset_path): return "invalid" # Check whether mapset is owned by current user - elif not is_current_user_mapset_owner(mapset_path): + if not is_current_user_mapset_owner(mapset_path): return "different-owner" # Check whether mapset is locked - elif is_mapset_locked(mapset_path): + if is_mapset_locked(mapset_path): return "locked" return None diff --git a/python/grass/gunittest/case.py b/python/grass/gunittest/case.py index b5563e47e9e..1277ee542b5 100644 --- a/python/grass/gunittest/case.py +++ b/python/grass/gunittest/case.py @@ -736,10 +736,9 @@ def _get_unique_name(self, name): # and ensure uniqueness by add UUID if self.readable_names: return "tmp_" + self.id().replace(".", "_") + "_" + name - else: - # UUID might be overkill (and expensive) but it's safe and simple - # alternative is to create hash from the readable name - return "tmp_" + str(uuid.uuid4()).replace("-", "") + # UUID might be overkill (and expensive) but it's safe and simple + # alternative is to create hash from the readable name + return "tmp_" + str(uuid.uuid4()).replace("-", "") def _compute_difference_raster(self, first, second, name_part): """Compute difference of two rasters (first - second) diff --git a/python/grass/gunittest/multireport.py b/python/grass/gunittest/multireport.py index f183d4e0219..c5f36a6e0db 100644 --- a/python/grass/gunittest/multireport.py +++ b/python/grass/gunittest/multireport.py @@ -104,8 +104,7 @@ def median(values): sorted_values = sorted(values) if n % 2 == 0: return (sorted_values[n / 2 - 1] + sorted_values[n / 2]) / 2 - else: - return sorted_values[n / 2] + return sorted_values[n / 2] # this is useful for debugging or some other stat # cmeans = [] diff --git a/python/grass/gunittest/multirunner.py b/python/grass/gunittest/multirunner.py index fd648406332..ebb9e80049a 100644 --- a/python/grass/gunittest/multirunner.py +++ b/python/grass/gunittest/multirunner.py @@ -30,15 +30,13 @@ def _get_encoding(): def decode(bytes_, encoding=None): if isinstance(bytes_, bytes): return bytes_.decode(_get_encoding()) - else: - return bytes_ + return bytes_ def encode(string, encoding=None): if isinstance(string, str): return string.encode(_get_encoding()) - else: - return string + return string def text_to_string(text): diff --git a/python/grass/gunittest/reporters.py b/python/grass/gunittest/reporters.py index 9535e07f871..09f371dfffc 100644 --- a/python/grass/gunittest/reporters.py +++ b/python/grass/gunittest/reporters.py @@ -110,8 +110,7 @@ def get_source_url(path, revision, line=None): tracurl = "http://trac.osgeo.org/grass/browser/" if line: return "{tracurl}{path}?rev={revision}#L{line}".format(**locals()) - else: - return "{tracurl}{path}?rev={revision}".format(**locals()) + return "{tracurl}{path}?rev={revision}".format(**locals()) def html_escape(text): @@ -150,8 +149,7 @@ def to_web_path(path): """ if os.path.sep != "/": return path.replace(os.path.sep, "/") - else: - return path + return path def get_svn_revision(): @@ -174,8 +172,7 @@ def get_svn_revision(): # the first one is the one of source code stdout = stdout.split(":")[0] return stdout - else: - return None + return None def get_svn_info(): @@ -436,9 +433,9 @@ def end_file_test(self, returncode, **kwargs): def percent_to_html(percent): if percent is None: return 'unknown percentage' - elif percent > 100 or percent < 0: + if percent > 100 or percent < 0: return "? {:.2f}% ?".format(percent) - elif percent < 40: + if percent < 40: color = "red" elif percent < 70: color = "orange" @@ -495,9 +492,8 @@ def returncode_to_html_text(returncode, timed_out=None): else: extra = "" return f'FAILED{extra}' - else: - # alternatives: SUCCEEDED, passed, OK - return 'succeeded' + # alternatives: SUCCEEDED, passed, OK + return 'succeeded' # not used @@ -507,31 +503,28 @@ def returncode_to_html_sentence(returncode): '' " Test failed (return code %d)" % (returncode) ) - else: - return ( - '' - " Test succeeded (return code %d)" % (returncode) - ) + return ( + '' + " Test succeeded (return code %d)" % (returncode) + ) def returncode_to_success_html_par(returncode): if returncode: return '

    Test failed

    ' - else: - return '

    Test succeeded

    ' + return '

    Test succeeded

    ' def success_to_html_text(total, successes): if successes < total: return 'FAILED' - elif successes == total: + if successes == total: # alternatives: SUCCEEDED, passed, OK return 'succeeded' - else: - return ( - '' - "? more successes than total ?" - ) + return ( + '' + "? more successes than total ?" + ) UNKNOWN_NUMBER_HTML = 'unknown' @@ -627,8 +620,7 @@ def finish(self): def format_percentage(percentage): if percentage is not None: return "{nsper:.0f}%".format(nsper=percentage) - else: - return "unknown percentage" + return "unknown percentage" summary_sentence = ( "\nExecuted {nfiles} test files in {time:}." @@ -985,8 +977,7 @@ def finish(self): def format_percentage(percentage): if percentage is not None: return "{nsper:.0f}%".format(nsper=percentage) - else: - return "unknown percentage" + return "unknown percentage" summary_sentence = ( "\nExecuted {nfiles} test files in {time:}." diff --git a/python/grass/gunittest/runner.py b/python/grass/gunittest/runner.py index b99c6704c89..0bbd0f361b9 100644 --- a/python/grass/gunittest/runner.py +++ b/python/grass/gunittest/runner.py @@ -83,8 +83,7 @@ def getDescription(self, test): doc_first_line = test.shortDescription() if self.descriptions and doc_first_line: return "\n".join((str(test), doc_first_line)) - else: - return str(test) + return str(test) def startTest(self, test): super().startTest(test) diff --git a/python/grass/imaging/images2avi.py b/python/grass/imaging/images2avi.py index f0b1904823d..1b0d9d8cd20 100644 --- a/python/grass/imaging/images2avi.py +++ b/python/grass/imaging/images2avi.py @@ -137,11 +137,10 @@ def writeAvi( + "\n" + _("Could not write avi.") ) - else: - # An error occurred, show - print(gs.decode(outPut)) - print(gs.decode(S.stderr.read())) - raise RuntimeError(_("Could not write avi.")) + # An error occurred, show + print(gs.decode(outPut)) + print(gs.decode(S.stderr.read())) + raise RuntimeError(_("Could not write avi.")) else: try: # Copy avi @@ -151,8 +150,7 @@ def writeAvi( _cleanDir(tempDir) if bg_task: return str(err) - else: - raise + raise # Clean up _cleanDir(tempDir) diff --git a/python/grass/imaging/images2gif.py b/python/grass/imaging/images2gif.py index fdb6423eec3..4084dade509 100644 --- a/python/grass/imaging/images2gif.py +++ b/python/grass/imaging/images2gif.py @@ -1060,9 +1060,8 @@ def quantize(self, image): """ if get_cKDTree(): return self.quantize_with_scipy(image) - else: - print("Scipy not available, falling back to slower version.") - return self.quantize_without_scipy(image) + print("Scipy not available, falling back to slower version.") + return self.quantize_without_scipy(image) def quantize_with_scipy(self, image): w, h = image.size diff --git a/python/grass/imaging/images2ims.py b/python/grass/imaging/images2ims.py index 662e3eb46e0..a5cee9b49de 100644 --- a/python/grass/imaging/images2ims.py +++ b/python/grass/imaging/images2ims.py @@ -93,8 +93,7 @@ def checkImages(images): def _getFilenameParts(filename): if "*" in filename: return tuple(filename.split("*", 1)) - else: - return os.path.splitext(filename) + return os.path.splitext(filename) def _getFilenameWithFormatter(filename, N): diff --git a/python/grass/pydispatch/robustapply.py b/python/grass/pydispatch/robustapply.py index cd52f74c22e..2ec88443a1a 100644 --- a/python/grass/pydispatch/robustapply.py +++ b/python/grass/pydispatch/robustapply.py @@ -35,7 +35,7 @@ def function(receiver): if hasattr(receiver, im_func): # an instance-method... return receiver, getattr(getattr(receiver, im_func), func_code), 1 - elif not hasattr(receiver, func_code): + if not hasattr(receiver, func_code): raise ValueError("unknown receiver type %s %s" % (receiver, type(receiver))) return receiver, getattr(receiver, func_code), 0 diff --git a/python/grass/pydispatch/saferef.py b/python/grass/pydispatch/saferef.py index a802a1982c1..90769c46b36 100644 --- a/python/grass/pydispatch/saferef.py +++ b/python/grass/pydispatch/saferef.py @@ -35,8 +35,7 @@ def safeRef(target, onDelete=None): return BoundMethodWeakref(target=target, onDelete=onDelete) if onDelete is not None: return weakref.ref(target, onDelete) - else: - return weakref.ref(target) + return weakref.ref(target) class BoundMethodWeakref: @@ -92,11 +91,10 @@ def __new__(cls, target, onDelete=None, *arguments, **named): if current is not None: current.deletionMethods.append(onDelete) return current - else: - base = super().__new__(cls) - cls._allInstances[key] = base - base.__init__(target, onDelete, *arguments, **named) - return base + base = super().__new__(cls) + cls._allInstances[key] = base + base.__init__(target, onDelete, *arguments, **named) + return base def __init__(self, target, onDelete=None): """Return a weak-reference-like instance for a bound method diff --git a/python/grass/pygrass/errors.py b/python/grass/pygrass/errors.py index a63b300a862..a017b85b33f 100644 --- a/python/grass/pygrass/errors.py +++ b/python/grass/pygrass/errors.py @@ -11,9 +11,8 @@ def must_be_open(method): def wrapper(self, *args, **kargs): if self.is_open(): return method(self, *args, **kargs) - else: - msgr = get_msgr() - msgr.warning(_("The map is close!")) + msgr = get_msgr() + msgr.warning(_("The map is close!")) return wrapper @@ -23,10 +22,7 @@ def mapinfo_must_be_set(method): def wrapper(self, *args, **kargs): if self.c_mapinfo: return method(self, *args, **kargs) - else: - raise GrassError( - _("The self.c_mapinfo pointer must be correctly initiated") - ) + raise GrassError(_("The self.c_mapinfo pointer must be correctly initiated")) return wrapper @@ -36,9 +32,6 @@ def must_be_in_current_mapset(method): def wrapper(self, *args, **kargs): if self.mapset == libgis.G_mapset().decode(): return method(self, *args, **kargs) - else: - raise GrassError( - _("Map <{}> not found in current mapset").format(self.name) - ) + raise GrassError(_("Map <{}> not found in current mapset").format(self.name)) return wrapper diff --git a/python/grass/pygrass/gis/__init__.py b/python/grass/pygrass/gis/__init__.py index 61768859231..597c4bf75fa 100644 --- a/python/grass/pygrass/gis/__init__.py +++ b/python/grass/pygrass/gis/__init__.py @@ -162,8 +162,7 @@ def __getitem__(self, location): """ if location in self.locations(): return Location(location, self.name) - else: - raise KeyError("Location: %s does not exist" % location) + raise KeyError("Location: %s does not exist" % location) def __iter__(self): for loc in self.locations(): @@ -234,8 +233,7 @@ def _set_name(self, name): def __getitem__(self, mapset): if mapset in self.mapsets(): return Mapset(mapset) - else: - raise KeyError("Mapset: %s does not exist" % mapset) + raise KeyError("Mapset: %s does not exist" % mapset) def __iter__(self): lpath = self.path() diff --git a/python/grass/pygrass/modules/interface/docstring.py b/python/grass/pygrass/modules/interface/docstring.py index 2fde05f73de..397338fcbb8 100644 --- a/python/grass/pygrass/modules/interface/docstring.py +++ b/python/grass/pygrass/modules/interface/docstring.py @@ -44,8 +44,7 @@ def __init__(self, class_doc, fget): def __get__(self, obj, type=None): if obj is None: return self.class_doc - else: - return self.fget(obj) + return self.fget(obj) def __set__(self, obj, value): raise AttributeError("can't set attribute") diff --git a/python/grass/pygrass/modules/interface/flag.py b/python/grass/pygrass/modules/interface/flag.py index b2e78e30717..b6f00fdb744 100644 --- a/python/grass/pygrass/modules/interface/flag.py +++ b/python/grass/pygrass/modules/interface/flag.py @@ -52,10 +52,8 @@ def get_bash(self): if self.value: if self.special: return "--%s" % self.name[0] - else: - return "-%s" % self.name - else: - return "" + return "-%s" % self.name + return "" def get_python(self): """Return the python representation of a flag. diff --git a/python/grass/pygrass/modules/interface/module.py b/python/grass/pygrass/modules/interface/module.py index c8a1e723a05..392d7571015 100644 --- a/python/grass/pygrass/modules/interface/module.py +++ b/python/grass/pygrass/modules/interface/module.py @@ -720,12 +720,11 @@ def get_python(self): # pre name par flg special if flags and special: return "%s.%s(%s, flags=%r, %s)" % (prefix, name, params, flags, special) - elif flags: + if flags: return "%s.%s(%s, flags=%r)" % (prefix, name, params, flags) - elif special: + if special: return "%s.%s(%s, %s)" % (prefix, name, params, special) - else: - return "%s.%s(%s)" % (prefix, name, params) + return "%s.%s(%s)" % (prefix, name, params) def __str__(self): """Return the command string that can be executed in a shell""" @@ -1026,16 +1025,15 @@ def run(self): module.finish_ = True module.run() return None + if self.set_temp_region is True: + self.p = Process( + target=run_modules_in_temp_region, args=[self.module_list, self.q] + ) else: - if self.set_temp_region is True: - self.p = Process( - target=run_modules_in_temp_region, args=[self.module_list, self.q] - ) - else: - self.p = Process(target=run_modules, args=[self.module_list, self.q]) - self.p.start() + self.p = Process(target=run_modules, args=[self.module_list, self.q]) + self.p.start() - return self.p + return self.p def wait(self): """Wait for all processes to finish. Call this method diff --git a/python/grass/pygrass/raster/__init__.py b/python/grass/pygrass/raster/__init__.py index 0356513e017..61ec85841cb 100644 --- a/python/grass/pygrass/raster/__init__.py +++ b/python/grass/pygrass/raster/__init__.py @@ -327,17 +327,16 @@ def __setitem__(self, key, row): if isinstance(key, slice): # Get the start, stop, and step from the slice return [self.put_row(ii, row) for ii in range(*key.indices(len(self)))] - elif isinstance(key, tuple): + if isinstance(key, tuple): x, y = key return self.put(x, y, row) - elif isinstance(key, int): + if isinstance(key, int): if key < 0: # Handle negative indices key += self._rows if key >= self._rows: raise IndexError(_("Index out of range: %r.") % key) return self.put_row(key, row) - else: - raise TypeError("Invalid argument type.") + raise TypeError("Invalid argument type.") @must_be_open def map2segment(self): diff --git a/python/grass/pygrass/raster/abstract.py b/python/grass/pygrass/raster/abstract.py index edea42e7bdd..68b5e501ed4 100644 --- a/python/grass/pygrass/raster/abstract.py +++ b/python/grass/pygrass/raster/abstract.py @@ -393,10 +393,10 @@ def __getitem__(self, key): if isinstance(key, slice): # Get the start, stop, and step from the slice return (self.get_row(ii) for ii in range(*key.indices(len(self)))) - elif isinstance(key, tuple): + if isinstance(key, tuple): x, y = key return self.get(x, y) - elif isinstance(key, int): + if isinstance(key, int): if not self.is_open(): raise IndexError("Can not operate on a closed map. Call open() first.") if key < 0: # Handle negative indices @@ -408,8 +408,7 @@ def __getitem__(self, key): ) ) return self.get_row(key) - else: - fatal("Invalid argument type.") + fatal("Invalid argument type.") def __iter__(self): """Return a constructor of the class""" @@ -434,8 +433,7 @@ def exist(self): self.mapset = mapset or "" return bool(mapset) return bool(utils.get_mapset_raster(self.name, self.mapset)) - else: - return False + return False def is_open(self): """Return True if the map is open False otherwise. @@ -485,8 +483,7 @@ def name_mapset(self, name=None, mapset=None): if mapset and mapset != gis_env["MAPSET"]: return "{name}@{mapset}".format(name=name, mapset=mapset) - else: - return name + return name def rename(self, newname): """Rename the map""" diff --git a/python/grass/pygrass/raster/buffer.py b/python/grass/pygrass/raster/buffer.py index 51420f16610..0e34ac84159 100644 --- a/python/grass/pygrass/raster/buffer.py +++ b/python/grass/pygrass/raster/buffer.py @@ -20,13 +20,12 @@ class Buffer(np.ndarray): def mtype(self): if self.dtype in CELL: return "CELL" - elif self.dtype in FCELL: + if self.dtype in FCELL: return "FCELL" - elif self.dtype in DCELL: + if self.dtype in DCELL: return DCELL - else: - err = "Raster type: %r not supported by GRASS." - raise TypeError(err % self.dtype) + err = "Raster type: %r not supported by GRASS." + raise TypeError(err % self.dtype) def __new__( cls, shape, mtype="FCELL", buffer=None, offset=0, strides=None, order=None diff --git a/python/grass/pygrass/raster/category.py b/python/grass/pygrass/raster/category.py index f439d51dcdf..fa4e8d37b12 100644 --- a/python/grass/pygrass/raster/category.py +++ b/python/grass/pygrass/raster/category.py @@ -187,7 +187,7 @@ def _set_c_cat(self, label, min_cat, max_cat=None): # Manage C function Errors if err == 1: return None - elif err == 0: + if err == 0: raise GrassError(_("Null value detected")) elif err == -1: raise GrassError(_("Error executing: Rast_set_cat")) diff --git a/python/grass/pygrass/utils.py b/python/grass/pygrass/utils.py index a04e3936a64..d8804665b1e 100644 --- a/python/grass/pygrass/utils.py +++ b/python/grass/pygrass/utils.py @@ -83,24 +83,23 @@ def find_in_gisdbase(type, pattern, gisdbase): (m, mset.name, mset.location, mset.gisdbase) for m in mset.glist(type, pattern) ] - elif gisdbase and location: + if gisdbase and location: loc = Location(location, gisdbase) return find_in_location(type, pattern, loc) - elif gisdbase: + if gisdbase: gis = Gisdbase(gisdbase) return find_in_gisdbase(type, pattern, gis) - elif location: + if location: loc = Location(location) return find_in_location(type, pattern, loc) - elif mapset: + if mapset: mset = Mapset(mapset) return [ (m, mset.name, mset.location, mset.gisdbase) for m in mset.glist(type, pattern) ] - else: - gis = Gisdbase() - return find_in_gisdbase(type, pattern, gis) + gis = Gisdbase() + return find_in_gisdbase(type, pattern, gis) def remove(oldname, maptype): @@ -136,11 +135,10 @@ def decode(obj, encoding=None): """ if isinstance(obj, String): return grassutils.decode(obj.data, encoding=encoding) - elif isinstance(obj, bytes): + if isinstance(obj, bytes): return grassutils.decode(obj) - else: - # eg None - return obj + # eg None + return obj def getenv(env): @@ -337,9 +335,8 @@ def get_raster_for_points(poi_vector, raster, column=None, region=None): result.append((poi.id, poi.x, poi.y, None)) if not column: return result - else: - poi.attrs.commit() - return True + poi.attrs.commit() + return True def r_export(rast, output="", fmt="png", **kargs): @@ -355,8 +352,7 @@ def r_export(rast, output="", fmt="png", **kargs): **kargs, ) return output - else: - raise ValueError("Raster map does not exist.") + raise ValueError("Raster map does not exist.") def get_lib_path(modname, libname=None): diff --git a/python/grass/pygrass/vector/__init__.py b/python/grass/pygrass/vector/__init__.py index b5a24e8d9c1..461050807b0 100644 --- a/python/grass/pygrass/vector/__init__.py +++ b/python/grass/pygrass/vector/__init__.py @@ -70,8 +70,7 @@ def __init__(self, name, mapset="", *args, **kwargs): def __repr__(self): if self.exist(): return "%s(%r, %r)" % (self._class_name, self.name, self.mapset) - else: - return "%s(%r)" % (self._class_name, self.name) + return "%s(%r)" % (self._class_name, self.name) def __iter__(self): """:: @@ -315,10 +314,9 @@ def __getitem__(self, key): key.step or 1, ) ] - elif isinstance(key, int): + if isinstance(key, int): return self.read(key) - else: - raise ValueError("Invalid argument type: %r." % key) + raise ValueError("Invalid argument type: %r." % key) @must_be_open def num_primitive_of(self, primitive): @@ -392,11 +390,9 @@ def number_of(self, vtype): if isinstance(_NUMOF[vtype], tuple): fn, ptype = _NUMOF[vtype] return fn(self.c_mapinfo, ptype) - else: - return _NUMOF[vtype](self.c_mapinfo) - else: - keys = "', '".join(sorted(_NUMOF.keys())) - raise ValueError("vtype not supported, use one of: '%s'" % keys) + return _NUMOF[vtype](self.c_mapinfo) + keys = "', '".join(sorted(_NUMOF.keys())) + raise ValueError("vtype not supported, use one of: '%s'" % keys) @must_be_open def num_primitives(self): @@ -526,17 +522,16 @@ def cat(self, cat_id, vtype, layer=None, generator=False, geo=None): ) for v_id in ilist ) - else: - return [ - read_line( - feature_id=v_id, - c_mapinfo=self.c_mapinfo, - table=self.table, - writeable=self.writeable, - is2D=is2D, - ) - for v_id in ilist - ] + return [ + read_line( + feature_id=v_id, + c_mapinfo=self.c_mapinfo, + table=self.table, + writeable=self.writeable, + is2D=is2D, + ) + for v_id in ilist + ] @must_be_open def read(self, feature_id): diff --git a/python/grass/pygrass/vector/abstract.py b/python/grass/pygrass/vector/abstract.py index 3929006ef25..6700dca8e4c 100644 --- a/python/grass/pygrass/vector/abstract.py +++ b/python/grass/pygrass/vector/abstract.py @@ -299,8 +299,7 @@ def exist(self): self.mapset = mapset or "" return bool(mapset) return bool(utils.get_mapset_vector(self.name, self.mapset)) - else: - return False + return False def is_open(self): """Return if the Vector is open""" diff --git a/python/grass/pygrass/vector/basic.py b/python/grass/pygrass/vector/basic.py index b86ae3edb4e..f031e23ff98 100644 --- a/python/grass/pygrass/vector/basic.py +++ b/python/grass/pygrass/vector/basic.py @@ -149,8 +149,7 @@ def nsewtb(self, tb=True): """ if tb: return (self.north, self.south, self.east, self.west, self.top, self.bottom) - else: - return (self.north, self.south, self.east, self.west) + return (self.north, self.south, self.east, self.west) class BoxList: @@ -308,14 +307,13 @@ def __getitem__(self, key): self.c_ilist.contents.value[indx] for indx in range(*key.indices(len(self))) ] - elif isinstance(key, int): + if isinstance(key, int): if key < 0: # Handle negative indices key += self.c_ilist.contents.n_values if key >= self.c_ilist.contents.n_values: raise IndexError("Index out of range") return self.c_ilist.contents.value[key] - else: - raise ValueError("Invalid argument type: %r." % key) + raise ValueError("Invalid argument type: %r." % key) def __setitem__(self, key, value): if self.contains(value): diff --git a/python/grass/pygrass/vector/find.py b/python/grass/pygrass/vector/find.py index 9333497f110..25ce9aca8f4 100644 --- a/python/grass/pygrass/vector/find.py +++ b/python/grass/pygrass/vector/find.py @@ -490,11 +490,10 @@ def geos(self, bbox, type="all", bboxlist_only=False): ): if bboxlist_only: return found - else: - return ( - read_line(f_id, self.c_mapinfo, self.table, self.writeable) - for f_id in found.ids - ) + return ( + read_line(f_id, self.c_mapinfo, self.table, self.writeable) + for f_id in found.ids + ) @must_be_open def nodes(self, bbox): @@ -592,16 +591,15 @@ def areas(self, bbox, boxlist=None, bboxlist_only=False): ): if bboxlist_only: return boxlist - else: - return ( - Area( - v_id=a_id, - c_mapinfo=self.c_mapinfo, - table=self.table, - writeable=self.writeable, - ) - for a_id in boxlist.ids + return ( + Area( + v_id=a_id, + c_mapinfo=self.c_mapinfo, + table=self.table, + writeable=self.writeable, ) + for a_id in boxlist.ids + ) @must_be_open def islands(self, bbox, bboxlist_only=False): @@ -652,16 +650,15 @@ def islands(self, bbox, bboxlist_only=False): ): if bboxlist_only: return found - else: - return ( - Isle( - v_id=i_id, - c_mapinfo=self.c_mapinfo, - table=self.table, - writeable=self.writeable, - ) - for i_id in found.ids + return ( + Isle( + v_id=i_id, + c_mapinfo=self.c_mapinfo, + table=self.table, + writeable=self.writeable, ) + for i_id in found.ids + ) class PolygonFinder(AbstractFinder): diff --git a/python/grass/pygrass/vector/geometry.py b/python/grass/pygrass/vector/geometry.py index 2ff4cb1bb8f..10ecb1d2d13 100644 --- a/python/grass/pygrass/vector/geometry.py +++ b/python/grass/pygrass/vector/geometry.py @@ -94,8 +94,7 @@ def intersects(lineA, lineB, with_z=False): lineA.c_points, lineB.c_points, line.c_points, int(with_z) ): return line - else: - return [] + return [] # ============================================= @@ -370,8 +369,7 @@ def cat(self): def has_topology(self): if self.c_mapinfo is not None: return self.c_mapinfo.contents.level == 2 - else: - return False + return False @mapinfo_must_be_set def read(self): @@ -539,8 +537,7 @@ def coords(self): """ if self.is2D: return self.x, self.y - else: - return self.x, self.y, self.z + return self.x, self.y, self.z def to_wkt_p(self): """Return a "well know text" (WKT) geometry string Python implementation. :: @@ -577,10 +574,9 @@ def distance(self, pnt): """ if self.is2D or pnt.is2D: return libvect.Vect_points_distance(self.x, self.y, 0, pnt.x, pnt.y, 0, 0) - else: - return libvect.Vect_points_distance( - self.x, self.y, self.z, pnt.x, pnt.y, pnt.z, 1 - ) + return libvect.Vect_points_distance( + self.x, self.y, self.z, pnt.x, pnt.y, pnt.z, 1 + ) def buffer( self, dist=None, dist_x=None, dist_y=None, angle=0, round_=True, tol=0.1 @@ -675,7 +671,7 @@ def __getitem__(self, key): ) for indx in range(*key.indices(len(self))) ] - elif isinstance(key, int): + if isinstance(key, int): if key < 0: # Handle negative indices key += self.c_points.contents.n_points if key >= self.c_points.contents.n_points: @@ -685,8 +681,7 @@ def __getitem__(self, key): self.c_points.contents.y[key], None if self.is2D else self.c_points.contents.z[key], ) - else: - raise ValueError("Invalid argument type: %r." % key) + raise ValueError("Invalid argument type: %r." % key) def __setitem__(self, indx, pnt): """Change the coordinate of point. :: @@ -1373,8 +1368,7 @@ def _centroid(self, side, idonly=False): v_id = v_id or None if idonly: return v_id - else: - return Centroid(v_id=v_id, c_mapinfo=self.c_mapinfo) + return Centroid(v_id=v_id, c_mapinfo=self.c_mapinfo) def left_centroid(self, idonly=False): """Return left centroid @@ -1914,8 +1908,7 @@ def c_read_line(feature_id, c_mapinfo, c_points, c_cats): if feature_id > 0: ftype = libvect.Vect_read_line(c_mapinfo, c_points, c_cats, feature_id) return feature_id, ftype, c_points, c_cats - else: - raise ValueError("The index must be >0, %r given." % feature_id) + raise ValueError("The index must be >0, %r given." % feature_id) def read_line( diff --git a/python/grass/pygrass/vector/table.py b/python/grass/pygrass/vector/table.py index 78c1c8709b4..9c8d0c3f9a2 100644 --- a/python/grass/pygrass/vector/table.py +++ b/python/grass/pygrass/vector/table.py @@ -65,14 +65,13 @@ def get_path(path, vect_name=None): """ if "$" not in path: return path - else: - mapset = Mapset() - path = path.replace("$GISDBASE", mapset.gisdbase) - path = path.replace("$LOCATION_NAME", mapset.location) - path = path.replace("$MAPSET", mapset.name) - if vect_name is not None: - path = path.replace("$MAP", vect_name) - return path + mapset = Mapset() + path = path.replace("$GISDBASE", mapset.gisdbase) + path = path.replace("$LOCATION_NAME", mapset.location) + path = path.replace("$MAPSET", mapset.name) + if vect_name is not None: + path = path.replace("$MAP", vect_name) + return path class Filters: @@ -326,8 +325,7 @@ def sql_descr(self, remove=None): return ", ".join( ["%s %s" % (key, val) for key, val in self.items() if key != remove] ) - else: - return ", ".join(["%s %s" % (key, val) for key, val in self.items()]) + return ", ".join(["%s %s" % (key, val) for key, val in self.items()]) def types(self): """Return a list with the column types. @@ -372,8 +370,7 @@ def names(self, remove=None, unicod=True): nams = list(self.odict.keys()) if unicod: return nams - else: - return [str(name) for name in nams] + return [str(name) for name in nams] def items(self): """Return a list of tuple with column name and column type. @@ -847,7 +844,7 @@ def connection(self): if not os.path.exists(dbdirpath): os.mkdir(dbdirpath) return sqlite3.connect(dbpath) - elif driver == "pg": + if driver == "pg": try: import psycopg2 @@ -940,8 +937,7 @@ def __iter__(self): def __getitem__(self, item): if isinstance(item, int): return self.by_index(item) - else: - return self.by_name(item) + return self.by_name(item) def __repr__(self): return "DBlinks(%r)" % list(self.__iter__()) diff --git a/python/grass/script/core.py b/python/grass/script/core.py index ee90a41d4ef..4f70f525133 100644 --- a/python/grass/script/core.py +++ b/python/grass/script/core.py @@ -127,8 +127,7 @@ def _make_unicode(val, enc): if enc == "default": return decode(val) - else: - return decode(val, encoding=enc) + return decode(val, encoding=enc) def get_commands(*, env=None): @@ -349,7 +348,7 @@ def get_module_and_code(args, kwargs): return result if handler.lower() == "ignore": return result - elif handler.lower() == "fatal": + if handler.lower() == "fatal": module, code = get_module_and_code(args, kwargs) fatal( _( @@ -1650,8 +1649,7 @@ def verbosity(): vbstr = os.getenv("GRASS_VERBOSE") if vbstr: return int(vbstr) - else: - return 2 + return 2 # Various utilities, not specific to GRASS diff --git a/python/grass/script/db.py b/python/grass/script/db.py index 2725ff06ebe..60813379501 100644 --- a/python/grass/script/db.py +++ b/python/grass/script/db.py @@ -229,8 +229,7 @@ def db_table_in_vector(table, mapset=".", env=None): break if len(used) > 0: return used - else: - return None + return None def db_begin_transaction(driver): diff --git a/python/grass/script/raster.py b/python/grass/script/raster.py index 32c0639b32f..bcaab7ef596 100644 --- a/python/grass/script/raster.py +++ b/python/grass/script/raster.py @@ -88,8 +88,7 @@ def raster_info(map, env=None): def float_or_null(s): if s == "NULL": return None - else: - return float(s) + return float(s) s = read_command("r.info", flags="gre", map=map, env=env) kv = parse_key_val(s) diff --git a/python/grass/script/raster3d.py b/python/grass/script/raster3d.py index 3b89b4fb707..e3db5398158 100644 --- a/python/grass/script/raster3d.py +++ b/python/grass/script/raster3d.py @@ -47,8 +47,7 @@ def raster3d_info(map, env=None): def float_or_null(s): if s == "NULL": return None - else: - return float(s) + return float(s) s = read_command("r3.info", flags="rg", map=map, env=env) kv = parse_key_val(s) diff --git a/python/grass/script/task.py b/python/grass/script/task.py index 8e1f0a12844..cf398c59214 100644 --- a/python/grass/script/task.py +++ b/python/grass/script/task.py @@ -90,8 +90,7 @@ def get_name(self): name, ext = os.path.splitext(self.name) if ext in {".py", ".sh"}: return name - else: - return self.name + return self.name return self.name @@ -103,10 +102,8 @@ def get_description(self, full=True): if self.label: if full: return self.label + " " + self.description - else: - return self.label - else: - return self.description + return self.label + return self.description def get_keywords(self): """Get module's keywords""" diff --git a/python/grass/script/utils.py b/python/grass/script/utils.py index aa7d53375dd..448289b57aa 100644 --- a/python/grass/script/utils.py +++ b/python/grass/script/utils.py @@ -69,13 +69,13 @@ def separator(sep): """ if sep == "pipe": return "|" - elif sep == "comma": + if sep == "comma": return "," - elif sep == "space": + if sep == "space": return " " - elif sep in {"tab", "\\t"}: + if sep in {"tab", "\\t"}: return "\t" - elif sep in {"newline", "\\n"}: + if sep in {"newline", "\\n"}: return "\n" return sep diff --git a/python/grass/temporal/abstract_dataset.py b/python/grass/temporal/abstract_dataset.py index cfe3c83a841..bf30afa21dd 100644 --- a/python/grass/temporal/abstract_dataset.py +++ b/python/grass/temporal/abstract_dataset.py @@ -76,7 +76,7 @@ def get_number_of_relations(self): """ if self.is_temporal_topology_build() and not self.is_spatial_topology_build(): return self.get_number_of_temporal_relations() - elif self.is_spatial_topology_build() and not self.is_temporal_topology_build(): + if self.is_spatial_topology_build() and not self.is_temporal_topology_build(): self.get_number_of_spatial_relations() else: return ( @@ -511,8 +511,7 @@ def is_time_absolute(self): """ if "temporal_type" in self.base.D: return self.base.get_ttype() == "absolute" - else: - return None + return None def is_time_relative(self): """Return True in case the temporal type is relative @@ -521,8 +520,7 @@ def is_time_relative(self): """ if "temporal_type" in self.base.D: return self.base.get_ttype() == "relative" - else: - return None + return None def get_temporal_extent(self): """Return the temporal extent of the correct internal type""" diff --git a/python/grass/temporal/abstract_map_dataset.py b/python/grass/temporal/abstract_map_dataset.py index f58bcb82d66..ecbf761d139 100644 --- a/python/grass/temporal/abstract_map_dataset.py +++ b/python/grass/temporal/abstract_map_dataset.py @@ -232,8 +232,7 @@ def build_id_from_search_path(name, element): if layer is not None: return f"{name}:{layer}@{mapset}" - else: - return f"{name}@{mapset}" + return f"{name}@{mapset}" @staticmethod def build_id(name, mapset, layer=None): @@ -258,8 +257,7 @@ def build_id(name, mapset, layer=None): if layer is not None: return f"{name}:{layer}@{mapset}" - else: - return f"{name}@{mapset}" + return f"{name}@{mapset}" def get_layer(self): """Return the layer of the map @@ -443,15 +441,11 @@ def set_absolute_time(self, start_time, end_time=None): } ) return False - else: - self.msgr.error( - _( - "Start time must be of type datetime for " - "%(type)s map <%(id)s>" - ) - % {"type": self.get_type(), "id": self.get_map_id()} - ) - return False + self.msgr.error( + _("Start time must be of type datetime for %(type)s map <%(id)s>") + % {"type": self.get_type(), "id": self.get_map_id()} + ) + return False if end_time and not isinstance(end_time, datetime): if self.get_layer(): @@ -467,12 +461,11 @@ def set_absolute_time(self, start_time, end_time=None): } ) return False - else: - self.msgr.error( - _("End time must be of type datetime for %(type)s map <%(id)s>") - % {"type": self.get_type(), "id": self.get_map_id()} - ) - return False + self.msgr.error( + _("End time must be of type datetime for %(type)s map <%(id)s>") + % {"type": self.get_type(), "id": self.get_map_id()} + ) + return False if start_time is not None and end_time is not None: if start_time > end_time: @@ -490,17 +483,16 @@ def set_absolute_time(self, start_time, end_time=None): } ) return False - else: - self.msgr.error( - _( - "End time must be greater than start " - "time for %(type)s map <%(id)s>" - ) - % {"type": self.get_type(), "id": self.get_map_id()} + self.msgr.error( + _( + "End time must be greater than start " + "time for %(type)s map <%(id)s>" ) - return False + % {"type": self.get_type(), "id": self.get_map_id()} + ) + return False # Do not create an interval in case start and end time are equal - elif start_time == end_time: + if start_time == end_time: end_time = None self.base.set_ttype("absolute") @@ -618,7 +610,7 @@ def set_relative_time(self, start_time, end_time, unit): ) return False # Do not create an interval in case start and end time are equal - elif start_time == end_time: + if start_time == end_time: end_time = None self.base.set_ttype("relative") diff --git a/python/grass/temporal/abstract_space_time_dataset.py b/python/grass/temporal/abstract_space_time_dataset.py index fc154270f59..d17baaab6ae 100644 --- a/python/grass/temporal/abstract_space_time_dataset.py +++ b/python/grass/temporal/abstract_space_time_dataset.py @@ -1626,8 +1626,7 @@ def leading_zero(value): try: if value.startswith("0"): return value.lstrip("0") - else: - return "{0:02d}".format(int(value)) + return "{0:02d}".format(int(value)) except ValueError: return None diff --git a/python/grass/temporal/base.py b/python/grass/temporal/base.py index 9296a22dfa1..ebb4b715e29 100644 --- a/python/grass/temporal/base.py +++ b/python/grass/temporal/base.py @@ -466,10 +466,9 @@ def get_update_statement(self, ident=None): return self.serialize( "UPDATE", self.get_table_name(), "WHERE id = '" + str(ident) + "'" ) - else: - return self.serialize( - "UPDATE", self.get_table_name(), "WHERE id = '" + str(self.ident) + "'" - ) + return self.serialize( + "UPDATE", self.get_table_name(), "WHERE id = '" + str(self.ident) + "'" + ) def get_update_statement_mogrified(self, dbif=None, ident=None): """Return the update statement as mogrified string @@ -529,12 +528,11 @@ def get_update_all_statement(self, ident=None): return self.serialize( "UPDATE ALL", self.get_table_name(), "WHERE id = '" + str(ident) + "'" ) - else: - return self.serialize( - "UPDATE ALL", - self.get_table_name(), - "WHERE id = '" + str(self.ident) + "'", - ) + return self.serialize( + "UPDATE ALL", + self.get_table_name(), + "WHERE id = '" + str(self.ident) + "'", + ) def get_update_all_statement_mogrified(self, dbif=None, ident=None): """Return the update all statement as mogrified string @@ -749,8 +747,7 @@ def get_id(self): """ if "id" in self.D: return self.D["id"] - else: - return None + return None def get_map_id(self): """Convenient method to get the unique map identifier @@ -763,10 +760,8 @@ def get_map_id(self): if self.id.find(":") >= 0: # Remove the layer identifier from the id return self.id.split("@")[0].split(":")[0] + "@" + self.id.split("@")[1] - else: - return self.id - else: - return None + return self.id + return None def get_layer(self): """Convenient method to get the layer of the map (part of primary key) @@ -777,48 +772,42 @@ def get_layer(self): """ if "layer" in self.D: return self.D["layer"] - else: - return None + return None def get_name(self): """Get the name of the dataset :return: None if not found""" if "name" in self.D: return self.D["name"] - else: - return None + return None def get_mapset(self): """Get the name of mapset of this dataset :return: None if not found""" if "mapset" in self.D: return self.D["mapset"] - else: - return None + return None def get_creator(self): """Get the creator of the dataset :return: None if not found""" if "creator" in self.D: return self.D["creator"] - else: - return None + return None def get_ctime(self): """Get the creation time of the dataset, datatype is datetime :return: None if not found""" if "creation_time" in self.D: return self.D["creation_time"] - else: - return None + return None def get_ttype(self): """Get the temporal type of the map :return: None if not found""" if "temporal_type" in self.D: return self.D["temporal_type"] - else: - return None + return None # Properties of this class id = property(fget=get_id, fset=set_id) @@ -1027,8 +1016,7 @@ def get_semantic_type(self): """ if "semantic_type" in self.D: return self.D["semantic_type"] - else: - return None + return None def get_mtime(self): """Get the modification time of the space time dataset, datatype is @@ -1038,8 +1026,7 @@ def get_mtime(self): """ if "modification_time" in self.D: return self.D["modification_time"] - else: - return None + return None semantic_type = property(fget=get_semantic_type, fset=set_semantic_type) @@ -1201,8 +1188,7 @@ def get_id(self): """ if "id" in self.D: return self.D["id"] - else: - return None + return None def get_registered_stds(self): """Get the comma separated list of space time datasets ids @@ -1212,8 +1198,7 @@ def get_registered_stds(self): """ if "registered_stds" in self.D: return self.D["registered_stds"] - else: - return None + return None # Properties of this class id = property(fget=get_id, fset=set_id) diff --git a/python/grass/temporal/c_libraries_interface.py b/python/grass/temporal/c_libraries_interface.py index 27e0ff62238..85a19a3ec6e 100644 --- a/python/grass/temporal/c_libraries_interface.py +++ b/python/grass/temporal/c_libraries_interface.py @@ -1011,13 +1011,12 @@ def _read_raster_history(name, mapset): if ret < 0: logging.warning(_("Unable to read history file")) return None - else: - kvp["creation_time"] = decode( - libraster.Rast_get_history(byref(hist), libraster.HIST_MAPID) - ) - kvp["creator"] = decode( - libraster.Rast_get_history(byref(hist), libraster.HIST_CREATOR) - ) + kvp["creation_time"] = decode( + libraster.Rast_get_history(byref(hist), libraster.HIST_MAPID) + ) + kvp["creator"] = decode( + libraster.Rast_get_history(byref(hist), libraster.HIST_CREATOR) + ) return kvp @@ -1049,13 +1048,12 @@ def _read_raster3d_history(name, mapset): if ret < 0: logging.warning(_("Unable to read history file")) return None - else: - kvp["creation_time"] = decode( - libraster.Rast_get_history(byref(hist), libraster3d.HIST_MAPID) - ) - kvp["creator"] = decode( - libraster.Rast_get_history(byref(hist), libraster3d.HIST_CREATOR) - ) + kvp["creation_time"] = decode( + libraster.Rast_get_history(byref(hist), libraster3d.HIST_MAPID) + ) + kvp["creator"] = decode( + libraster.Rast_get_history(byref(hist), libraster3d.HIST_CREATOR) + ) return kvp @@ -1142,43 +1140,42 @@ def _convert_timestamp_from_grass(ts): # ATTENTION: We ignore the time zone # TODO: Write time zone support return (pdt1, pdt2) - else: - unit = None - start = None - end = None - if count.value >= 1: - if dt1.year > 0: - unit = "years" - start = dt1.year - elif dt1.month > 0: - unit = "months" - start = dt1.month - elif dt1.day > 0: - unit = "days" - start = dt1.day - elif dt1.hour > 0: - unit = "hours" - start = dt1.hour - elif dt1.minute > 0: - unit = "minutes" - start = dt1.minute - elif dt1.second > 0: - unit = "seconds" - start = dt1.second - if count.value == 2: - if dt2.year > 0: - end = dt2.year - elif dt2.month > 0: - end = dt2.month - elif dt2.day > 0: - end = dt2.day - elif dt2.hour > 0: - end = dt2.hour - elif dt2.minute > 0: - end = dt2.minute - elif dt2.second > 0: - end = dt2.second - return (start, end, unit) + unit = None + start = None + end = None + if count.value >= 1: + if dt1.year > 0: + unit = "years" + start = dt1.year + elif dt1.month > 0: + unit = "months" + start = dt1.month + elif dt1.day > 0: + unit = "days" + start = dt1.day + elif dt1.hour > 0: + unit = "hours" + start = dt1.hour + elif dt1.minute > 0: + unit = "minutes" + start = dt1.minute + elif dt1.second > 0: + unit = "seconds" + start = dt1.second + if count.value == 2: + if dt2.year > 0: + end = dt2.year + elif dt2.month > 0: + end = dt2.month + elif dt2.day > 0: + end = dt2.day + elif dt2.hour > 0: + end = dt2.hour + elif dt2.minute > 0: + end = dt2.minute + elif dt2.second > 0: + end = dt2.second + return (start, end, unit) ############################################################################### diff --git a/python/grass/temporal/core.py b/python/grass/temporal/core.py index 0448ff2371d..321c73d5408 100644 --- a/python/grass/temporal/core.py +++ b/python/grass/temporal/core.py @@ -1376,7 +1376,7 @@ def mogrify_sql_statement(self, content): if self.dbmi.__name__ == "psycopg2": if len(args) == 0: return sql - elif self.connected: + if self.connected: try: return self.cursor.mogrify(sql, args) except Exception as exc: @@ -1391,57 +1391,56 @@ def mogrify_sql_statement(self, content): elif self.dbmi.__name__ == "sqlite3": if len(args) == 0: return sql - else: - # Unfortunately as sqlite does not support - # the transformation of sql strings and qmarked or - # named arguments we must make our hands dirty - # and do it by ourself. :( - # Doors are open for SQL injection because of the - # limited python sqlite3 implementation!!! - pos = 0 - count = 0 - maxcount = 100 - statement = sql - - while count < maxcount: - pos = statement.find("?", pos + 1) - if pos == -1: - break - - if args[count] is None: - statement = "%sNULL%s" % ( - statement[0:pos], - statement[pos + 1 :], - ) - elif isinstance(args[count], int): - statement = "%s%d%s" % ( - statement[0:pos], - args[count], - statement[pos + 1 :], - ) - elif isinstance(args[count], float): - statement = "%s%f%s" % ( - statement[0:pos], - args[count], - statement[pos + 1 :], - ) - elif isinstance(args[count], datetime): - statement = "%s'%s'%s" % ( - statement[0:pos], - str(args[count]), - statement[pos + 1 :], - ) - else: - # Default is a string, this works for datetime - # objects too - statement = "%s'%s'%s" % ( - statement[0:pos], - str(args[count]), - statement[pos + 1 :], - ) - count += 1 + # Unfortunately as sqlite does not support + # the transformation of sql strings and qmarked or + # named arguments we must make our hands dirty + # and do it by ourself. :( + # Doors are open for SQL injection because of the + # limited python sqlite3 implementation!!! + pos = 0 + count = 0 + maxcount = 100 + statement = sql + + while count < maxcount: + pos = statement.find("?", pos + 1) + if pos == -1: + break + + if args[count] is None: + statement = "%sNULL%s" % ( + statement[0:pos], + statement[pos + 1 :], + ) + elif isinstance(args[count], int): + statement = "%s%d%s" % ( + statement[0:pos], + args[count], + statement[pos + 1 :], + ) + elif isinstance(args[count], float): + statement = "%s%f%s" % ( + statement[0:pos], + args[count], + statement[pos + 1 :], + ) + elif isinstance(args[count], datetime): + statement = "%s'%s'%s" % ( + statement[0:pos], + str(args[count]), + statement[pos + 1 :], + ) + else: + # Default is a string, this works for datetime + # objects too + statement = "%s'%s'%s" % ( + statement[0:pos], + str(args[count]), + statement[pos + 1 :], + ) + count += 1 - return statement + return statement def check_table(self, table_name): """Check if a table exists in the temporal database diff --git a/python/grass/temporal/metadata.py b/python/grass/temporal/metadata.py index 369fadc03cf..4be4c568a76 100644 --- a/python/grass/temporal/metadata.py +++ b/python/grass/temporal/metadata.py @@ -174,72 +174,63 @@ def get_id(self): """ if "id" in self.D: return self.D["id"] - else: - return None + return None def get_datatype(self): """Get the map type :return: None if not found""" if "datatype" in self.D: return self.D["datatype"] - else: - return None + return None def get_cols(self): """Get number of cols :return: None if not found""" if "cols" in self.D: return self.D["cols"] - else: - return None + return None def get_rows(self): """Get number of rows :return: None if not found""" if "rows" in self.D: return self.D["rows"] - else: - return None + return None def get_number_of_cells(self): """Get number of cells :return: None if not found""" if "number_of_cells" in self.D: return self.D["number_of_cells"] - else: - return None + return None def get_nsres(self): """Get the north-south resolution :return: None if not found""" if "nsres" in self.D: return self.D["nsres"] - else: - return None + return None def get_ewres(self): """Get east-west resolution :return: None if not found""" if "ewres" in self.D: return self.D["ewres"] - else: - return None + return None def get_min(self): """Get the minimum cell value :return: None if not found""" if "min" in self.D: return self.D["min"] - else: - return None + return None def get_max(self): """Get the maximum cell value :return: None if not found""" if "max" in self.D: return self.D["max"] - else: - return None + return None # Properties datatype = property(fget=get_datatype, fset=set_datatype) @@ -401,8 +392,7 @@ def get_semantic_label(self): :return: None if not found""" if "semantic_label" in self.D: return self.D["semantic_label"] - else: - return None + return None semantic_label = property(fget=get_semantic_label, fset=set_semantic_label) @@ -549,16 +539,14 @@ def get_depths(self): :return: None if not found""" if "depths" in self.D: return self.D["depths"] - else: - return None + return None def get_tbres(self): """Get top-bottom resolution :return: None if not found""" if "tbres" in self.D: return self.D["tbres"] - else: - return None + return None depths = property(fget=get_depths, fset=set_depths) tbres = property(fget=get_tbres, fset=set_tbres) @@ -766,112 +754,98 @@ def get_id(self): """ if "id" in self.D: return self.D["id"] - else: - return None + return None def get_3d_info(self): """Return True if the map is three dimensional, False if not and None if not info was found""" if "is_3d" in self.D: return self.D["is_3d"] - else: - return None + return None def get_number_of_points(self): """Get the number of points of the vector map :return: None if not found""" if "points" in self.D: return self.D["points"] - else: - return None + return None def get_number_of_lines(self): """Get the number of lines of the vector map :return: None if not found""" if "lines" in self.D: return self.D["lines"] - else: - return None + return None def get_number_of_boundaries(self): """Get the number of boundaries of the vector map :return: None if not found""" if "boundaries" in self.D: return self.D["boundaries"] - else: - return None + return None def get_number_of_centroids(self): """Get the number of centroids of the vector map :return: None if not found""" if "centroids" in self.D: return self.D["centroids"] - else: - return None + return None def get_number_of_faces(self): """Get the number of faces of the vector map :return: None if not found""" if "faces" in self.D: return self.D["faces"] - else: - return None + return None def get_number_of_kernels(self): """Get the number of kernels of the vector map :return: None if not found""" if "kernels" in self.D: return self.D["kernels"] - else: - return None + return None def get_number_of_primitives(self): """Get the number of primitives of the vector map :return: None if not found""" if "primitives" in self.D: return self.D["primitives"] - else: - return None + return None def get_number_of_nodes(self): """Get the number of nodes of the vector map :return: None if not found""" if "nodes" in self.D: return self.D["nodes"] - else: - return None + return None def get_number_of_areas(self): """Get the number of areas of the vector map :return: None if not found""" if "areas" in self.D: return self.D["areas"] - else: - return None + return None def get_number_of_islands(self): """Get the number of islands of the vector map :return: None if not found""" if "islands" in self.D: return self.D["islands"] - else: - return None + return None def get_number_of_holes(self): """Get the number of holes of the vector map :return: None if not found""" if "holes" in self.D: return self.D["holes"] - else: - return None + return None def get_number_of_volumes(self): """Get the number of volumes of the vector map :return: None if not found""" if "volumes" in self.D: return self.D["volumes"] - else: - return None + return None # Set the properties id = property(fget=get_id, fset=set_id) @@ -1002,32 +976,28 @@ def get_id(self): """ if "id" in self.D: return self.D["id"] - else: - return None + return None def get_title(self): """Get the title :return: None if not found""" if "title" in self.D: return self.D["title"] - else: - return None + return None def get_description(self): """Get description :return: None if not found""" if "description" in self.D: return self.D["description"] - else: - return None + return None def get_command(self): """Get command :return: None if not found""" if "command" in self.D: return self.D["command"] - else: - return None + return None def get_number_of_maps(self): """Get the number of registered maps, @@ -1036,8 +1006,7 @@ def get_number_of_maps(self): :return: None if not found""" if "number_of_maps" in self.D: return self.D["number_of_maps"] - else: - return None + return None id = property(fget=get_id, fset=set_id) title = property(fget=get_title, fset=set_title) @@ -1220,8 +1189,7 @@ def get_aggregation_type(self): """ if "aggregation_type" in self.D: return self.D["aggregation_type"] - else: - return None + return None def get_max_min(self): """Get the minimal maximum of all registered maps, @@ -1230,8 +1198,7 @@ def get_max_min(self): :return: None if not found""" if "max_min" in self.D: return self.D["max_min"] - else: - return None + return None def get_min_min(self): """Get the minimal minimum of all registered maps, @@ -1240,8 +1207,7 @@ def get_min_min(self): :return: None if not found""" if "min_min" in self.D: return self.D["min_min"] - else: - return None + return None def get_max_max(self): """Get the maximal maximum of all registered maps, @@ -1250,8 +1216,7 @@ def get_max_max(self): :return: None if not found""" if "max_max" in self.D: return self.D["max_max"] - else: - return None + return None def get_min_max(self): """Get the maximal minimum of all registered maps, @@ -1260,8 +1225,7 @@ def get_min_max(self): :return: None if not found""" if "min_max" in self.D: return self.D["min_max"] - else: - return None + return None def get_nsres_min(self): """Get the minimal north-south resolution of all registered maps, @@ -1270,8 +1234,7 @@ def get_nsres_min(self): :return: None if not found""" if "nsres_min" in self.D: return self.D["nsres_min"] - else: - return None + return None def get_nsres_max(self): """Get the maximal north-south resolution of all registered maps, @@ -1280,8 +1243,7 @@ def get_nsres_max(self): :return: None if not found""" if "nsres_max" in self.D: return self.D["nsres_max"] - else: - return None + return None def get_ewres_min(self): """Get the minimal east-west resolution of all registered maps, @@ -1290,8 +1252,7 @@ def get_ewres_min(self): :return: None if not found""" if "ewres_min" in self.D: return self.D["ewres_min"] - else: - return None + return None def get_ewres_max(self): """Get the maximal east-west resolution of all registered maps, @@ -1300,8 +1261,7 @@ def get_ewres_max(self): :return: None if not found""" if "ewres_max" in self.D: return self.D["ewres_max"] - else: - return None + return None nsres_min = property(fget=get_nsres_min) nsres_max = property(fget=get_nsres_max) @@ -1435,8 +1395,7 @@ def get_raster_register(self): :return: None if not found""" if "raster_register" in self.D: return self.D["raster_register"] - else: - return None + return None def get_number_of_semantic_labels(self): """Get the number of registered semantic labels @@ -1444,8 +1403,7 @@ def get_number_of_semantic_labels(self): """ if "number_of_semantic_labels" in self.D: return self.D["number_of_semantic_labels"] - else: - return None + return None def get_semantic_labels(self): """Get the distinct semantic labels of registered maps @@ -1483,10 +1441,8 @@ def get_semantic_labels(self): if count > 0: return string - else: - return None - else: return None + return None raster_register = property(fget=get_raster_register, fset=set_raster_register) number_of_semantic_labels = property(fget=get_number_of_semantic_labels) @@ -1623,8 +1579,7 @@ def get_raster3d_register(self): :return: None if not found""" if "raster3d_register" in self.D: return self.D["raster3d_register"] - else: - return None + return None def get_tbres_min(self): """Get the minimal top-bottom resolution of all registered maps, @@ -1633,8 +1588,7 @@ def get_tbres_min(self): :return: None if not found""" if "tbres_min" in self.D: return self.D["tbres_min"] - else: - return None + return None def get_tbres_max(self): """Get the maximal top-bottom resolution of all registered maps, @@ -1643,8 +1597,7 @@ def get_tbres_max(self): :return: None if not found""" if "tbres_max" in self.D: return self.D["tbres_max"] - else: - return None + return None raster3d_register = property(fget=get_raster3d_register, fset=set_raster3d_register) tbres_min = property(fget=get_tbres_min) @@ -1787,8 +1740,7 @@ def get_vector_register(self): :return: None if not found""" if "vector_register" in self.D: return self.D["vector_register"] - else: - return None + return None def get_number_of_points(self): """Get the number of points of all registered maps, @@ -1797,8 +1749,7 @@ def get_number_of_points(self): :return: None if not found""" if "points" in self.D: return self.D["points"] - else: - return None + return None def get_number_of_lines(self): """Get the number of lines of all registered maps, @@ -1807,8 +1758,7 @@ def get_number_of_lines(self): :return: None if not found""" if "lines" in self.D: return self.D["lines"] - else: - return None + return None def get_number_of_boundaries(self): """Get the number of boundaries of all registered maps, @@ -1817,8 +1767,7 @@ def get_number_of_boundaries(self): :return: None if not found""" if "boundaries" in self.D: return self.D["boundaries"] - else: - return None + return None def get_number_of_centroids(self): """Get the number of centroids of all registered maps, @@ -1827,8 +1776,7 @@ def get_number_of_centroids(self): :return: None if not found""" if "centroids" in self.D: return self.D["centroids"] - else: - return None + return None def get_number_of_faces(self): """Get the number of faces of all registered maps, @@ -1837,8 +1785,7 @@ def get_number_of_faces(self): :return: None if not found""" if "faces" in self.D: return self.D["faces"] - else: - return None + return None def get_number_of_kernels(self): """Get the number of kernels of all registered maps, @@ -1847,8 +1794,7 @@ def get_number_of_kernels(self): :return: None if not found""" if "kernels" in self.D: return self.D["kernels"] - else: - return None + return None def get_number_of_primitives(self): """Get the number of primitives of all registered maps, @@ -1857,8 +1803,7 @@ def get_number_of_primitives(self): :return: None if not found""" if "primitives" in self.D: return self.D["primitives"] - else: - return None + return None def get_number_of_nodes(self): """Get the number of nodes of all registered maps, @@ -1867,8 +1812,7 @@ def get_number_of_nodes(self): :return: None if not found""" if "nodes" in self.D: return self.D["nodes"] - else: - return None + return None def get_number_of_areas(self): """Get the number of areas of all registered maps, @@ -1877,8 +1821,7 @@ def get_number_of_areas(self): :return: None if not found""" if "areas" in self.D: return self.D["areas"] - else: - return None + return None def get_number_of_islands(self): """Get the number of islands of all registered maps, @@ -1887,8 +1830,7 @@ def get_number_of_islands(self): :return: None if not found""" if "islands" in self.D: return self.D["islands"] - else: - return None + return None def get_number_of_holes(self): """Get the number of holes of all registered maps, @@ -1897,8 +1839,7 @@ def get_number_of_holes(self): :return: None if not found""" if "holes" in self.D: return self.D["holes"] - else: - return None + return None def get_number_of_volumes(self): """Get the number of volumes of all registered maps, @@ -1907,8 +1848,7 @@ def get_number_of_volumes(self): :return: None if not found""" if "volumes" in self.D: return self.D["volumes"] - else: - return None + return None # Set the properties vector_register = property(fget=get_vector_register, fset=set_vector_register) diff --git a/python/grass/temporal/space_time_datasets.py b/python/grass/temporal/space_time_datasets.py index ec01bf45baa..92721277c9e 100644 --- a/python/grass/temporal/space_time_datasets.py +++ b/python/grass/temporal/space_time_datasets.py @@ -633,15 +633,13 @@ def spatial_overlapping(self, dataset): """Return True if the spatial extents overlap""" if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds": return self.spatial_extent.overlapping(dataset.spatial_extent) - else: - return self.spatial_extent.overlapping_2d(dataset.spatial_extent) + return self.spatial_extent.overlapping_2d(dataset.spatial_extent) def spatial_relation(self, dataset): """Return the two or three dimensional spatial relation""" if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds": return self.spatial_extent.spatial_relation(dataset.spatial_extent) - else: - return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent) + return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent) def spatial_intersection(self, dataset): """Return the three or two dimensional intersection as spatial_extent @@ -652,8 +650,7 @@ def spatial_intersection(self, dataset): """ if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds": return self.spatial_extent.intersect(dataset.spatial_extent) - else: - return self.spatial_extent.intersect_2d(dataset.spatial_extent) + return self.spatial_extent.intersect_2d(dataset.spatial_extent) def spatial_union(self, dataset): """Return the three or two dimensional union as spatial_extent @@ -664,8 +661,7 @@ def spatial_union(self, dataset): """ if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds": return self.spatial_extent.union(dataset.spatial_extent) - else: - return self.spatial_extent.union_2d(dataset.spatial_extent) + return self.spatial_extent.union_2d(dataset.spatial_extent) def spatial_disjoint_union(self, dataset): """Return the three or two dimensional union as spatial_extent object. @@ -675,8 +671,7 @@ def spatial_disjoint_union(self, dataset): """ if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds": return self.spatial_extent.disjoint_union(dataset.spatial_extent) - else: - return self.spatial_extent.disjoint_union_2d(dataset.spatial_extent) + return self.spatial_extent.disjoint_union_2d(dataset.spatial_extent) def get_np_array(self): """Return this 3D raster map as memmap numpy style array to access the @@ -1386,16 +1381,14 @@ def spatial_overlapping(self, dataset): if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds": return self.spatial_extent.overlapping(dataset.spatial_extent) - else: - return self.spatial_extent.overlapping_2d(dataset.spatial_extent) + return self.spatial_extent.overlapping_2d(dataset.spatial_extent) def spatial_relation(self, dataset): """Return the two or three dimensional spatial relation""" if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds": return self.spatial_extent.spatial_relation(dataset.spatial_extent) - else: - return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent) + return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent) def spatial_intersection(self, dataset): """Return the three or two dimensional intersection as spatial_extent @@ -1406,8 +1399,7 @@ def spatial_intersection(self, dataset): """ if self.get_type() == dataset.get_type() or dataset.get_type() == "raster3d": return self.spatial_extent.intersect(dataset.spatial_extent) - else: - return self.spatial_extent.intersect_2d(dataset.spatial_extent) + return self.spatial_extent.intersect_2d(dataset.spatial_extent) def spatial_union(self, dataset): """Return the three or two dimensional union as spatial_extent @@ -1418,8 +1410,7 @@ def spatial_union(self, dataset): """ if self.get_type() == dataset.get_type() or dataset.get_type() == "raster3d": return self.spatial_extent.union(dataset.spatial_extent) - else: - return self.spatial_extent.union_2d(dataset.spatial_extent) + return self.spatial_extent.union_2d(dataset.spatial_extent) def spatial_disjoint_union(self, dataset): """Return the three or two dimensional union as spatial_extent object. @@ -1429,8 +1420,7 @@ def spatial_disjoint_union(self, dataset): """ if self.get_type() == dataset.get_type() or dataset.get_type() == "raster3d": return self.spatial_extent.disjoint_union(dataset.spatial_extent) - else: - return self.spatial_extent.disjoint_union_2d(dataset.spatial_extent) + return self.spatial_extent.disjoint_union_2d(dataset.spatial_extent) def reset(self, ident): """Reset the internal structure and set the identifier""" diff --git a/python/grass/temporal/spatial_extent.py b/python/grass/temporal/spatial_extent.py index 26498e0385e..7bec3bc35e7 100644 --- a/python/grass/temporal/spatial_extent.py +++ b/python/grass/temporal/spatial_extent.py @@ -1787,8 +1787,7 @@ def get_id(self): """ if "id" in self.D: return self.D["id"] - else: - return None + return None def get_projection(self): """Get the projection of the spatial extent""" @@ -1840,48 +1839,42 @@ def get_north(self): :return: None if not found""" if "north" in self.D: return self.D["north"] - else: - return None + return None def get_south(self): """Get the southern edge of the map :return: None if not found""" if "south" in self.D: return self.D["south"] - else: - return None + return None def get_east(self): """Get the eastern edge of the map :return: None if not found""" if "east" in self.D: return self.D["east"] - else: - return None + return None def get_west(self): """Get the western edge of the map :return: None if not found""" if "west" in self.D: return self.D["west"] - else: - return None + return None def get_top(self): """Get the top edge of the map :return: None if not found""" if "top" in self.D: return self.D["top"] - else: - return None + return None def get_bottom(self): """Get the bottom edge of the map :return: None if not found""" if "bottom" in self.D: return self.D["bottom"] - else: - return None + return None id = property(fget=get_id, fset=set_id) north = property(fget=get_north, fset=set_north) diff --git a/python/grass/temporal/temporal_algebra.py b/python/grass/temporal/temporal_algebra.py index 1cf1cfd7366..e4717eb3326 100644 --- a/python/grass/temporal/temporal_algebra.py +++ b/python/grass/temporal/temporal_algebra.py @@ -727,11 +727,11 @@ def get_type(self): and self.value is not None ): return "global" - elif self.boolean is not None: + if self.boolean is not None: return "boolean" - elif self.relationop is not None and self.topology != []: + if self.relationop is not None and self.topology != []: return "operator" - elif self.td is not None: + if self.td is not None: return "timediff" def get_type_value(self): @@ -2336,8 +2336,7 @@ def recurse_compare(conditionlist): inverselist.append(map_i) if inverse: return inverselist - else: - return resultlist + return resultlist def p_statement_assign(self, t): # The expression should always return a list of maps diff --git a/python/grass/temporal/temporal_extent.py b/python/grass/temporal/temporal_extent.py index 42cce4599b1..29594ea8b72 100644 --- a/python/grass/temporal/temporal_extent.py +++ b/python/grass/temporal/temporal_extent.py @@ -202,9 +202,9 @@ def intersect(self, extent): return RelativeTemporalExtent( start_time=start, end_time=end, unit=self.get_unit() ) - elif issubclass(type(self), AbsoluteTemporalExtent): + if issubclass(type(self), AbsoluteTemporalExtent): return AbsoluteTemporalExtent(start_time=start, end_time=end) - elif issubclass(type(self), TemporalExtent): + if issubclass(type(self), TemporalExtent): return TemporalExtent(start_time=start, end_time=end) def disjoint_union(self, extent): @@ -391,9 +391,9 @@ def disjoint_union(self, extent): return RelativeTemporalExtent( start_time=start, end_time=end, unit=self.get_unit() ) - elif issubclass(type(self), AbsoluteTemporalExtent): + if issubclass(type(self), AbsoluteTemporalExtent): return AbsoluteTemporalExtent(start_time=start, end_time=end) - elif issubclass(type(self), TemporalExtent): + if issubclass(type(self), TemporalExtent): return TemporalExtent(start_time=start, end_time=end) def union(self, extent): @@ -986,24 +986,21 @@ def get_id(self): """ if "id" in self.D: return self.D["id"] - else: - return None + return None def get_start_time(self): """Get the valid start time of the extent :return: None if not found""" if "start_time" in self.D: return self.D["start_time"] - else: - return None + return None def get_end_time(self): """Get the valid end time of the extent :return: None if not found""" if "end_time" in self.D: return self.D["end_time"] - else: - return None + return None # Set the properties id = property(fget=get_id, fset=set_id) @@ -1153,8 +1150,7 @@ def get_granularity(self): :return: None if not found""" if "granularity" in self.D: return self.D["granularity"] - else: - return None + return None def get_map_time(self): """Get the type of the map time @@ -1169,8 +1165,7 @@ def get_map_time(self): """ if "map_time" in self.D: return self.D["map_time"] - else: - return None + return None # Properties granularity = property(fget=get_granularity, fset=set_granularity) @@ -1277,8 +1272,7 @@ def get_unit(self): :return: None if not found""" if "unit" in self.D: return self.D["unit"] - else: - return None + return None def temporal_relation(self, map): """Returns the temporal relation between temporal objects @@ -1427,8 +1421,7 @@ def get_granularity(self): :return: None if not found""" if "granularity" in self.D: return self.D["granularity"] - else: - return None + return None def get_map_time(self): """Get the type of the map time @@ -1443,8 +1436,7 @@ def get_map_time(self): """ if "map_time" in self.D: return self.D["map_time"] - else: - return None + return None # Properties granularity = property(fget=get_granularity, fset=set_granularity) diff --git a/python/grass/temporal/temporal_granularity.py b/python/grass/temporal/temporal_granularity.py index c3920b8b00b..b4043054520 100644 --- a/python/grass/temporal/temporal_granularity.py +++ b/python/grass/temporal/temporal_granularity.py @@ -146,8 +146,7 @@ def _get_row_time_tuple(db_table_row): # Check if input is list of MapDataset objects or SQLite rows if issubclass(maps[0].__class__, AbstractMapDataset): return _get_map_time_tuple - else: - return _get_row_time_tuple + return _get_row_time_tuple def _is_after(start, start1, end1) -> bool: @@ -777,8 +776,7 @@ def compute_common_absolute_time_granularity(gran_list, start_date_list=None): if int(num) > 60: if int(num) % 60 == 0: return "60 seconds" - else: - return "1 second" + return "1 second" if granule in {"minutes", "minute"}: # If the start minutes are different between the start dates @@ -790,8 +788,7 @@ def compute_common_absolute_time_granularity(gran_list, start_date_list=None): if int(num) > 60: if int(num) % 60 == 0: return "60 minutes" - else: - return "1 minute" + return "1 minute" if granule in {"hours", "hour"}: # If the start hours are different between the start dates @@ -803,8 +800,7 @@ def compute_common_absolute_time_granularity(gran_list, start_date_list=None): if int(num) > 24: if int(num) % 24 == 0: return "24 hours" - else: - return "1 hour" + return "1 hour" if granule in {"days", "day"}: # If the start days are different between the start dates @@ -816,8 +812,7 @@ def compute_common_absolute_time_granularity(gran_list, start_date_list=None): if int(num) > 365: if int(num) % 365 == 0: return "365 days" - else: - return "1 day" + return "1 day" if granule in {"months", "month"}: # If the start months are different between the start dates @@ -829,8 +824,7 @@ def compute_common_absolute_time_granularity(gran_list, start_date_list=None): if int(num) > 12: if int(num) % 12 == 0: return "12 months" - else: - return "1 month" + return "1 month" return common_granule @@ -1125,20 +1119,18 @@ def gran_singular_unit(gran): output, unit = gran.split(" ") if unit in PLURAL_GRAN: return unit[:-1] - elif unit in SINGULAR_GRAN: + if unit in SINGULAR_GRAN: return unit - else: - lists = "{gr}".format(gr=SUPPORTED_GRAN).replace("[", "").replace("]", "") - print( - _( - "Output granularity seems not to be valid. Please use " - "one of the following values : {gr}" - ).format(gr=lists) - ) - return False - else: - print(_("Invalid absolute granularity")) + lists = "{gr}".format(gr=SUPPORTED_GRAN).replace("[", "").replace("]", "") + print( + _( + "Output granularity seems not to be valid. Please use " + "one of the following values : {gr}" + ).format(gr=lists) + ) return False + print(_("Invalid absolute granularity")) + return False ####################################################################### @@ -1170,16 +1162,15 @@ def gran_plural_unit(gran): output, unit = gran.split(" ") if unit in PLURAL_GRAN: return unit - elif unit in SINGULAR_GRAN: + if unit in SINGULAR_GRAN: return f"{unit}s" - else: - lists = ", ".join(SUPPORTED_GRAN) - print( - _( - "Output granularity seems not to be valid. Please use " - "one of the following values : {gr}" - ).format(gr=lists) - ) + lists = ", ".join(SUPPORTED_GRAN) + print( + _( + "Output granularity seems not to be valid. Please use " + "one of the following values : {gr}" + ).format(gr=lists) + ) else: print(_("Invalid absolute granularity")) return False @@ -1234,8 +1225,7 @@ def _return(output, tounit, shell): if output == 1: return f"{output} {tounit}" - else: - return f"{output} {tounit}s" + return f"{output} {tounit}s" # TODO check the leap second if check_granularity_string(from_gran, "absolute"): @@ -1256,9 +1246,8 @@ def _return(output, tounit, shell): return _return(output, tounit, shell) print(_("Probably you need to invert 'from_gran' and 'to_gran'")) return False - else: - print(_("Invalid absolute granularity")) - return False + print(_("Invalid absolute granularity")) + return False ############################################################################### diff --git a/python/grass/temporal/temporal_raster_base_algebra.py b/python/grass/temporal/temporal_raster_base_algebra.py index 3424110803f..8ff156cbed5 100644 --- a/python/grass/temporal/temporal_raster_base_algebra.py +++ b/python/grass/temporal/temporal_raster_base_algebra.py @@ -727,7 +727,7 @@ def build_condition_cmd_list( # Append map to result map list. resultlist.append(map_i) return resultlist - elif isinstance(conclusionlist, list): + if isinstance(conclusionlist, list): # Build result command map list between conditions and conclusions. if self.debug: print("build_condition_cmd_list", condition_topolist) diff --git a/raster/r.topidx/arc_to_gridatb.py b/raster/r.topidx/arc_to_gridatb.py index 17e49365697..3eba7114430 100755 --- a/raster/r.topidx/arc_to_gridatb.py +++ b/raster/r.topidx/arc_to_gridatb.py @@ -9,9 +9,8 @@ def match(pattern, string): if m: match.value = m.group(1) return True - else: - match.value = None - return False + match.value = None + return False if len(sys.argv) != 3 or re.match("^-*help", sys.argv[1]): diff --git a/scripts/g.extension/g.extension.py b/scripts/g.extension/g.extension.py index ed0544ee2c4..194f498d49c 100644 --- a/scripts/g.extension/g.extension.py +++ b/scripts/g.extension/g.extension.py @@ -508,24 +508,23 @@ def get_version_branch(major_version): version_branch = f"grass{major_version}" if sys.platform == "win32": return version_branch - else: - branch = gs.Popen( - ["git", "ls-remote", "--heads", GIT_URL, f"refs/heads/{version_branch}"], - stdout=PIPE, - stderr=PIPE, - ) - branch, stderr = branch.communicate() - if stderr: - gs.fatal( - _( - "Failed to get branch from the Git repository <{repo_path}>.\n" - "{error}" - ).format( - repo_path=GIT_URL, - error=gs.decode(stderr), - ) + branch = gs.Popen( + ["git", "ls-remote", "--heads", GIT_URL, f"refs/heads/{version_branch}"], + stdout=PIPE, + stderr=PIPE, + ) + branch, stderr = branch.communicate() + if stderr: + gs.fatal( + _( + "Failed to get branch from the Git repository <{repo_path}>.\n" + "{error}" + ).format( + repo_path=GIT_URL, + error=gs.decode(stderr), ) - branch = gs.decode(branch) + ) + branch = gs.decode(branch) if version_branch not in branch: version_branch = "grass{}".format(int(major_version) - 1) return version_branch @@ -2595,8 +2594,7 @@ def resolve_known_host_service(url, name, branch): ) gs.verbose(_("Will use the following URL for download: {0}").format(url)) return "remote_zip", url - else: - return None, None + return None, None def validate_url(url): @@ -2720,7 +2718,7 @@ def resolve_source_code(url=None, name=None, branch=None, fork=False): # Handle local URLs if os.path.isdir(url): return "dir", os.path.abspath(url) - elif os.path.exists(url): + if os.path.exists(url): if url.endswith(".zip"): return "zip", os.path.abspath(url) for suffix in extract_tar.supported_formats: @@ -2823,7 +2821,7 @@ def main(): xmlurl = resolve_xmlurl_prefix(original_url, source=source) list_available_extensions(xmlurl) return 0 - elif flags["a"]: + if flags["a"]: list_installed_extensions(toolboxes=flags["t"]) return 0 diff --git a/scripts/g.search.modules/g.search.modules.py b/scripts/g.search.modules/g.search.modules.py index cb40cbdced5..5777b4bd033 100755 --- a/scripts/g.search.modules/g.search.modules.py +++ b/scripts/g.search.modules/g.search.modules.py @@ -184,8 +184,7 @@ def colored(pattern, attrs): if pattern: return text.replace(pattern, colored(pattern, attrs=attrs)) - else: - return colored(text, attrs=attrs) + return colored(text, attrs=attrs) def _search_module( diff --git a/scripts/i.image.mosaic/i.image.mosaic.py b/scripts/i.image.mosaic/i.image.mosaic.py index df194c49c8f..fc342a3ed96 100755 --- a/scripts/i.image.mosaic/i.image.mosaic.py +++ b/scripts/i.image.mosaic/i.image.mosaic.py @@ -56,9 +56,8 @@ def get_limit(map): def make_expression(i, count): if i > count: return "null()" - else: - e = make_expression(i + 1, count) - return "if(isnull($image%d),%s,$image%d+$offset%d)" % (i, e, i, i) + e = make_expression(i + 1, count) + return "if(isnull($image%d),%s,$image%d+$offset%d)" % (i, e, i, i) def main(): diff --git a/scripts/r.in.wms/wms_base.py b/scripts/r.in.wms/wms_base.py index 234456f1518..2d959289b23 100644 --- a/scripts/r.in.wms/wms_base.py +++ b/scripts/r.in.wms/wms_base.py @@ -782,8 +782,7 @@ def GetSRSParamVal(srs): if srs in {84, 83, 27}: return "OGC:CRS{}".format(srs) - else: - return "EPSG:{}".format(srs) + return "EPSG:{}".format(srs) def GetEpsg(srs): diff --git a/scripts/r.in.wms/wms_drv.py b/scripts/r.in.wms/wms_drv.py index dd666573cfe..531112a1a6c 100644 --- a/scripts/r.in.wms/wms_drv.py +++ b/scripts/r.in.wms/wms_drv.py @@ -587,7 +587,7 @@ def _getQueryBbox(self, bbox, proj, srs_param, version): # CRS:84 and CRS:83 are exception (CRS:83 and CRS:27 need to be tested) if srs_param in {84, 83} or version != "1.3.0": return bbox - elif Srs(GetSRSParamVal(srs_param)).axisorder == "yx": + if Srs(GetSRSParamVal(srs_param)).axisorder == "yx": return self._flipBbox(bbox) return bbox diff --git a/temporal/t.info/t.info.py b/temporal/t.info/t.info.py index 2f0b0d528ec..575446030a1 100755 --- a/temporal/t.info/t.info.py +++ b/temporal/t.info/t.info.py @@ -91,7 +91,7 @@ def main(): " +----------------------------------------------------------------------------+" # noqa: E501 ) return - elif system and not history: + if system and not history: print("dbmi_python_interface='" + str(dbif.get_dbmi().__name__) + "'") print("dbmi_string='" + str(tgis.get_tgis_database_string()) + "'") print("sql_template_path='" + str(tgis.get_sql_template_path()) + "'") diff --git a/utils/g.html2man/g.html2man.py b/utils/g.html2man/g.html2man.py index 498ce34dfe1..58ffb2f7bca 100755 --- a/utils/g.html2man/g.html2man.py +++ b/utils/g.html2man/g.html2man.py @@ -17,12 +17,10 @@ def fix(content): tag, attrs, body = content if tag == "div" and ("class", "toc") in attrs: return None - else: - return (tag, attrs, fix(body)) - elif isinstance(content, list): + return (tag, attrs, fix(body)) + if isinstance(content, list): return [fixed for item in content for fixed in [fix(item)] if fixed is not None] - else: - return content + return content def main(): diff --git a/utils/g.html2man/ggroff.py b/utils/g.html2man/ggroff.py index 49c16f19f44..e62c5ec2b1c 100644 --- a/utils/g.html2man/ggroff.py +++ b/utils/g.html2man/ggroff.py @@ -253,8 +253,7 @@ def pp_text(self, content): for line in lines: self.pp_text(line) return - else: - content = lines[0] + content = lines[0] if self.at_bol and not self.get("preformat"): content = self.strip_re.sub("", content) self.pp_string(content) diff --git a/utils/g.html2man/ghtml.py b/utils/g.html2man/ghtml.py index 1a36fd3af06..4b30950ff0e 100644 --- a/utils/g.html2man/ghtml.py +++ b/utils/g.html2man/ghtml.py @@ -225,8 +225,7 @@ def __init__(self, entities=None): def top(self): if self.tag_stack == []: return None - else: - return self.tag_stack[-1][0] + return self.tag_stack[-1][0] def pop(self): self.excluded = self.excluded_stack.pop() diff --git a/utils/mkhtml.py b/utils/mkhtml.py index f64f6d7d97a..39a5e6e26eb 100644 --- a/utils/mkhtml.py +++ b/utils/mkhtml.py @@ -406,15 +406,14 @@ def get_last_git_commit(src_dir, addon_path, is_addon): commit=process_result.stdout.decode(), src_dir=src_dir, ) - elif gs: + if gs: # Addons installation return get_git_commit_from_rest_api_for_addon_repo( addon_path=addon_path, src_dir=src_dir, ) # During GRASS GIS compilation from source code without Git - else: - return get_git_commit_from_file(src_dir=src_dir) + return get_git_commit_from_file(src_dir=src_dir) html_page_footer_pages_path = os.getenv("HTML_PAGE_FOOTER_PAGES_PATH") or "" @@ -849,10 +848,9 @@ def to_title(name): """Convert name of command class/family to form suitable for title""" if name == "raster3d": return "3D raster" - elif name == "postscript": + if name == "postscript": return "PostScript" - else: - return name.capitalize() + return name.capitalize() index_titles = {} From 5e5f30e3ac67c24f8aa0cb6df0448002dc390533 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 12:33:11 -0400 Subject: [PATCH 164/209] CI(deps): Lock file maintenance (#4465) From 56ba44c512682774d2c586b9df66aa5ba5e41343 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:01:40 +0000 Subject: [PATCH 165/209] CI(deps): Update actions/upload-artifact action to v4.4.1 (#4466) --- .github/actions/create-upload-suggestions/action.yml | 4 ++-- .github/workflows/macos.yml | 2 +- .github/workflows/osgeo4w.yml | 2 +- .github/workflows/pytest.yml | 2 +- .github/workflows/python-code-quality.yml | 4 ++-- .github/workflows/ubuntu.yml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/actions/create-upload-suggestions/action.yml b/.github/actions/create-upload-suggestions/action.yml index 2493fba2573..3bc93a41a92 100644 --- a/.github/actions/create-upload-suggestions/action.yml +++ b/.github/actions/create-upload-suggestions/action.yml @@ -177,7 +177,7 @@ runs: echo "diff-file-name=${INPUT_DIFF_FILE_NAME}" >> "${GITHUB_OUTPUT}" env: INPUT_DIFF_FILE_NAME: ${{ steps.tool-name-safe.outputs.diff-file-name }} - - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 id: upload-diff if: >- ${{ (steps.files_changed.outputs.files_changed == 'true') && @@ -200,7 +200,7 @@ runs: echo 'Suggestions can only be added near to lines changed in this PR.' echo 'If any fixes can be added as code suggestions, they will be added shortly from another workflow.' } >> "${GITHUB_STEP_SUMMARY}" - - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 id: upload-changes if: >- ${{ always() && diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index a90cdcd7ad5..b3f7aa0954e 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -107,7 +107,7 @@ jobs: nc_spm_full_v2alpha2.tar.gz" - name: Make HTML test report available if: ${{ !cancelled() }} - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 with: name: testreport-macOS path: testreport diff --git a/.github/workflows/osgeo4w.yml b/.github/workflows/osgeo4w.yml index d9c67cc37c9..54f2d3c7bdb 100644 --- a/.github/workflows/osgeo4w.yml +++ b/.github/workflows/osgeo4w.yml @@ -120,7 +120,7 @@ jobs: - name: Make HTML test report available if: ${{ always() }} - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 with: name: testreport-${{ matrix.os }} path: testreport diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index f0cda6a95f5..62f097b6621 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -116,7 +116,7 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} - name: Make python-only code coverage test report available if: ${{ !cancelled() }} - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 with: name: python-codecoverage-report-${{ matrix.os }}-${{ matrix.python-version }} path: coverage_html_report diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index ac9fa5ea4cc..5a740498c2f 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -129,7 +129,7 @@ jobs: bandit -c pyproject.toml -iii -r . -f sarif -o bandit.sarif --exit-zero - name: Upload Bandit Scan Results - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 with: name: bandit.sarif path: bandit.sarif @@ -201,7 +201,7 @@ jobs: cp -rp dist.$ARCH/docs/html/libpython sphinx-grass - name: Make Sphinx documentation available - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 with: name: sphinx-grass path: sphinx-grass diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 25ce2afdd67..2b51971518f 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -149,7 +149,7 @@ jobs: - name: Make HTML test report available if: ${{ always() }} - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 with: name: testreport-${{ matrix.os }}-${{ matrix.config }}-${{ matrix.extra-include }} path: testreport From 368f0eb4ca748c4e3aa4490223d4739e78db8d9c Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 7 Oct 2024 15:49:40 -0400 Subject: [PATCH 166/209] v.to.db: Fix resource Leak issue in update.c (#4461) --- vector/v.to.db/update.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vector/v.to.db/update.c b/vector/v.to.db/update.c index dd63ef78d35..972fd6be93e 100644 --- a/vector/v.to.db/update.c +++ b/vector/v.to.db/update.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "global.h" static int srch(const void *, const void *); @@ -297,6 +298,8 @@ int update(struct Map_info *Map) db_close_database_shutdown_driver(driver); db_free_string(&stmt); + Vect_destroy_field_info(Fi); + Vect_destroy_field_info(qFi); return 0; } From 573d54ae4a43f390334780d060a4191fc006acb2 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 7 Oct 2024 15:50:42 -0400 Subject: [PATCH 167/209] ps.map: Fix Resource Leak issue in ps_vareas.c (#4464) --- ps/ps.map/ps_vareas.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ps/ps.map/ps_vareas.c b/ps/ps.map/ps_vareas.c index 5cd3471a6a8..3968140bd25 100644 --- a/ps/ps.map/ps_vareas.c +++ b/ps/ps.map/ps_vareas.c @@ -65,6 +65,7 @@ static int plot_area(struct Map_info *P_map, int area, double shift) if (0 > (ret = Vect_get_area_points(P_map, area, Points))) { if (ret == -1) G_warning(_("Read error in vector map")); + Vect_destroy_line_struct(Points); return 0; } construct_path(Points, shift, WHOLE_PATH); @@ -76,10 +77,12 @@ static int plot_area(struct Map_info *P_map, int area, double shift) if (0 > (ret = Vect_get_isle_points(P_map, island, Points))) { if (ret == -1) G_warning(_("Read error in vector map")); + Vect_destroy_line_struct(Points); return -1; } construct_path(Points, shift, WHOLE_PATH); } + Vect_destroy_line_struct(Points); return 1; } From 3f6a6e42057e1eb8116a23c5fb30c795a0c4d3b1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 21:17:34 +0000 Subject: [PATCH 168/209] CI(deps): Update actions/checkout action to v4.2.1 (#4468) --- .github/workflows/additional_checks.yml | 2 +- .github/workflows/clang-format-check.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/coverity.yml | 2 +- .github/workflows/create_release_draft.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/gcc.yml | 2 +- .github/workflows/macos.yml | 2 +- .github/workflows/osgeo4w.yml | 2 +- .github/workflows/periodic_update.yml | 2 +- .github/workflows/pytest.yml | 2 +- .github/workflows/python-code-quality.yml | 2 +- .github/workflows/super-linter.yml | 2 +- .github/workflows/test-nix.yml | 2 +- .github/workflows/titles.yml | 2 +- .github/workflows/ubuntu.yml | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/additional_checks.yml b/.github/workflows/additional_checks.yml index 1f8e355b487..a91d221f1e4 100644 --- a/.github/workflows/additional_checks.yml +++ b/.github/workflows/additional_checks.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository contents - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: fetch-depth: 31 diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index f68483dea20..13ba5bb3cd9 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -16,7 +16,7 @@ jobs: name: Formatting Check runs-on: ubuntu-latest steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: persist-credentials: false - uses: DoozyX/clang-format-lint-action@c71d0bf4e21876ebec3e5647491186f8797fde31 # v0.18.2 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 64994f93535..a8237e5838d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -40,7 +40,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Set up Python uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 with: diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index 24c98c96601..22a6b7a42a8 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-22.04 if: github.repository == 'OSGeo/grass' steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Get dependencies run: | diff --git a/.github/workflows/create_release_draft.yml b/.github/workflows/create_release_draft.yml index 4751c3c43a0..3112fb8b33f 100644 --- a/.github/workflows/create_release_draft.yml +++ b/.github/workflows/create_release_draft.yml @@ -30,7 +30,7 @@ jobs: contents: write steps: - name: Checks-out repository - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: ref: ${{ github.ref }} fetch-depth: 0 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 8a23d8e200b..4de674ee9a2 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -49,7 +49,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: fetch-depth: 0 - name: Docker meta diff --git a/.github/workflows/gcc.yml b/.github/workflows/gcc.yml index 24b9dcb4043..651cb272fba 100644 --- a/.github/workflows/gcc.yml +++ b/.github/workflows/gcc.yml @@ -26,7 +26,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Get dependencies run: | sudo apt-get update -y diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index b3f7aa0954e..71453cf1e5e 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -44,7 +44,7 @@ jobs: -mindepth 1 -maxdepth 1 -type f -print -delete # Rehash to forget about the deleted files hash -r - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Get current date cache key segment id: date # Year and week of year so cache key changes weekly diff --git a/.github/workflows/osgeo4w.yml b/.github/workflows/osgeo4w.yml index 54f2d3c7bdb..36395262a92 100644 --- a/.github/workflows/osgeo4w.yml +++ b/.github/workflows/osgeo4w.yml @@ -31,7 +31,7 @@ jobs: run: | git config --global core.autocrlf false git config --global core.eol lf - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: msys2/setup-msys2@ddf331adaebd714795f1042345e6ca57bd66cea8 # v2.24.1 with: path-type: inherit diff --git a/.github/workflows/periodic_update.yml b/.github/workflows/periodic_update.yml index f5441297250..17855d6149e 100644 --- a/.github/workflows/periodic_update.yml +++ b/.github/workflows/periodic_update.yml @@ -21,7 +21,7 @@ jobs: - name: Create URL to the run output id: vars run: echo "run-url=https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" >> $GITHUB_OUTPUT - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: "Check that autoconf scripts are up-to-date:" run: | rm -f config.guess config.sub diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 62f097b6621..bc66914dad8 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -32,7 +32,7 @@ jobs: PYTHONWARNINGS: always steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Set up Python uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 5a740498c2f..7e7626e3108 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -54,7 +54,7 @@ jobs: echo Bandit: ${{ env.BANDIT_VERSION }} echo Ruff: ${{ env.RUFF_VERSION }} - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Set up Python uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 diff --git a/.github/workflows/super-linter.yml b/.github/workflows/super-linter.yml index 117f5cd43fb..62328723f77 100644 --- a/.github/workflows/super-linter.yml +++ b/.github/workflows/super-linter.yml @@ -25,7 +25,7 @@ jobs: statuses: write steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: # super-linter needs the full git history to get the # list of files that changed across commits diff --git a/.github/workflows/test-nix.yml b/.github/workflows/test-nix.yml index 03f767730a9..ba14e0747ab 100644 --- a/.github/workflows/test-nix.yml +++ b/.github/workflows/test-nix.yml @@ -28,7 +28,7 @@ jobs: contents: read steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Install nix uses: DeterminateSystems/nix-installer-action@da36cb69b1c3247ad7a1f931ebfd954a1105ef14 # v14 diff --git a/.github/workflows/titles.yml b/.github/workflows/titles.yml index f90e7275a2e..f202fdafe02 100644 --- a/.github/workflows/titles.yml +++ b/.github/workflows/titles.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout base repository (doesn't include the PR changes) - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Call PR title validation function run: python utils/generate_release_notes.py check "${PR_TITLE}" "" "" env: diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 2b51971518f..05488c1936b 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -59,7 +59,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Invert inclusion list to an exclusion list id: get-exclude From 3ce2a0fe4885334c41a6de1f33e1877a670249dd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 21:43:30 +0000 Subject: [PATCH 169/209] CI(deps): Update github/codeql-action action to v3.26.12 (#4469) --- .github/workflows/codeql-analysis.yml | 4 ++-- .github/workflows/python-code-quality.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index a8237e5838d..88158341f13 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -56,7 +56,7 @@ jobs: if: ${{ matrix.language == 'c-cpp' }} - name: Initialize CodeQL - uses: github/codeql-action/init@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11 + uses: github/codeql-action/init@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -81,6 +81,6 @@ jobs: run: .github/workflows/build_ubuntu-22.04.sh "${HOME}/install" - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11 + uses: github/codeql-action/analyze@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 7e7626e3108..a71c579e7de 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -135,7 +135,7 @@ jobs: path: bandit.sarif - name: Upload SARIF File into Security Tab - uses: github/codeql-action/upload-sarif@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11 + uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 with: sarif_file: bandit.sarif From b4187339ee5bcf91db6425931d0774dd0f48ad33 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 22:43:02 +0000 Subject: [PATCH 170/209] CI(deps): Update black to v24.10.0 (#4473) --- .github/workflows/python-code-quality.yml | 2 +- .pre-commit-config.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index a71c579e7de..5103166b353 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -28,7 +28,7 @@ jobs: PYTHON_VERSION: "3.10" MIN_PYTHON_VERSION: "3.8" # renovate: datasource=pypi depName=black - BLACK_VERSION: "24.8.0" + BLACK_VERSION: "24.10.0" # renovate: datasource=pypi depName=flake8 FLAKE8_VERSION: "7.1.1" # renovate: datasource=pypi depName=pylint diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 60865cd3432..2c136da40ff 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -48,7 +48,7 @@ repos: - id: markdownlint-fix # Using this mirror lets us use mypyc-compiled black, which is about 2x faster - repo: https://github.com/psf/black-pre-commit-mirror - rev: 24.8.0 + rev: 24.10.0 hooks: - id: black-jupyter exclude: | From 498676c5266d15bcad76727ce087671502a03104 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 06:40:59 -0400 Subject: [PATCH 171/209] CI(deps): Update actions/upload-artifact action to v4.4.2 (#4477) --- .github/actions/create-upload-suggestions/action.yml | 4 ++-- .github/workflows/macos.yml | 2 +- .github/workflows/osgeo4w.yml | 2 +- .github/workflows/pytest.yml | 2 +- .github/workflows/python-code-quality.yml | 4 ++-- .github/workflows/ubuntu.yml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/actions/create-upload-suggestions/action.yml b/.github/actions/create-upload-suggestions/action.yml index 3bc93a41a92..181babe11e9 100644 --- a/.github/actions/create-upload-suggestions/action.yml +++ b/.github/actions/create-upload-suggestions/action.yml @@ -177,7 +177,7 @@ runs: echo "diff-file-name=${INPUT_DIFF_FILE_NAME}" >> "${GITHUB_OUTPUT}" env: INPUT_DIFF_FILE_NAME: ${{ steps.tool-name-safe.outputs.diff-file-name }} - - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 + - uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 id: upload-diff if: >- ${{ (steps.files_changed.outputs.files_changed == 'true') && @@ -200,7 +200,7 @@ runs: echo 'Suggestions can only be added near to lines changed in this PR.' echo 'If any fixes can be added as code suggestions, they will be added shortly from another workflow.' } >> "${GITHUB_STEP_SUMMARY}" - - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 + - uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 id: upload-changes if: >- ${{ always() && diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 71453cf1e5e..7b4e7eb18e2 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -107,7 +107,7 @@ jobs: nc_spm_full_v2alpha2.tar.gz" - name: Make HTML test report available if: ${{ !cancelled() }} - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 + uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 with: name: testreport-macOS path: testreport diff --git a/.github/workflows/osgeo4w.yml b/.github/workflows/osgeo4w.yml index 36395262a92..180cc79ec08 100644 --- a/.github/workflows/osgeo4w.yml +++ b/.github/workflows/osgeo4w.yml @@ -120,7 +120,7 @@ jobs: - name: Make HTML test report available if: ${{ always() }} - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 + uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 with: name: testreport-${{ matrix.os }} path: testreport diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index bc66914dad8..60ddb223074 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -116,7 +116,7 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} - name: Make python-only code coverage test report available if: ${{ !cancelled() }} - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 + uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 with: name: python-codecoverage-report-${{ matrix.os }}-${{ matrix.python-version }} path: coverage_html_report diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 5103166b353..5da86464470 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -129,7 +129,7 @@ jobs: bandit -c pyproject.toml -iii -r . -f sarif -o bandit.sarif --exit-zero - name: Upload Bandit Scan Results - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 + uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 with: name: bandit.sarif path: bandit.sarif @@ -201,7 +201,7 @@ jobs: cp -rp dist.$ARCH/docs/html/libpython sphinx-grass - name: Make Sphinx documentation available - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 + uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 with: name: sphinx-grass path: sphinx-grass diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 05488c1936b..88ddd0d31b2 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -149,7 +149,7 @@ jobs: - name: Make HTML test report available if: ${{ always() }} - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 + uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 with: name: testreport-${{ matrix.os }}-${{ matrix.config }}-${{ matrix.extra-include }} path: testreport From cbe2b9eaa9c8d5614c1170a7da508221361d6aef Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Thu, 10 Oct 2024 12:23:44 -0400 Subject: [PATCH 172/209] wxGUI: Fixed E722 in frame.py (#4440) --- .flake8 | 3 --- gui/wxpython/lmgr/frame.py | 12 ++++++------ gui/wxpython/lmgr/layertree.py | 11 ++++------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/.flake8 b/.flake8 index 5126c042439..313241f2d9d 100644 --- a/.flake8 +++ b/.flake8 @@ -27,9 +27,6 @@ per-file-ignores = gui/scripts/d.wms.py: E501 gui/wxpython/image2target/*: F841, E722 gui/wxpython/image2target/g.gui.image2target.py: E501, F841 - gui/wxpython/lmgr/frame.py: E722 - # layertree still includes some formatting issues (it is ignored by Black) - gui/wxpython/lmgr/layertree.py: E722 gui/wxpython/modules/*: F841, E722 gui/wxpython/nviz/*: F841, E266, E722, F403, F405 gui/wxpython/photo2image/*: F841, E722, E265 diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 80f373239f8..2413d3b7c4a 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -271,7 +271,7 @@ def show_menu_errors(messages): y = client_disp[1] self.SetPosition((x, y)) self.SetSize((w, h)) - except: + except (ValueError, IndexError): pass else: # does center (of screen) make sense for lmgr? @@ -884,7 +884,7 @@ def OnCBPageChanged(self, event): try: self.GetMapDisplay().SetFocus() self.GetMapDisplay().Raise() - except: + except AttributeError: pass event.Skip() @@ -1123,7 +1123,7 @@ def GetMenuCmd(self, event): try: cmdlist = cmd.split(" ") - except: # already list? + except AttributeError: # already list? cmdlist = cmd # check list of dummy commands for GUI modules that do not have GRASS @@ -1135,7 +1135,7 @@ def GetMenuCmd(self, event): layer = self.GetLayerTree().layer_selected name = self.GetLayerTree().GetLayerInfo(layer, key="maplayer").name type = self.GetLayerTree().GetLayerInfo(layer, key="type") - except: + except AttributeError: layer = None if layer and len(cmdlist) == 1: # only if no parameters given @@ -1183,7 +1183,7 @@ def OnVDigit(self, event): # available only for vector map layers try: mapLayer = tree.GetLayerInfo(layer, key="maplayer") - except: + except AttributeError: mapLayer = None if not mapLayer or mapLayer.GetType() != "vector": @@ -1860,7 +1860,7 @@ def OnShowAttributeTable(self, event, selection=None): # available only for vector map layers try: maptype = tree.GetLayerInfo(layer, key="maplayer").type - except: + except AttributeError: maptype = None if not maptype or maptype != "vector": diff --git a/gui/wxpython/lmgr/layertree.py b/gui/wxpython/lmgr/layertree.py index daefab44223..86531bcb5ad 100644 --- a/gui/wxpython/lmgr/layertree.py +++ b/gui/wxpython/lmgr/layertree.py @@ -1742,7 +1742,7 @@ def OnDeleteLayer(self, event): try: item.properties.Close(True) - except: + except AttributeError: pass if item != self.root: @@ -1758,7 +1758,7 @@ def OnDeleteLayer(self, event): try: if self.GetLayerInfo(item, key="type") != "group": self.Map.DeleteLayer(self.GetLayerInfo(item, key="maplayer")) - except: + except AttributeError: pass # redraw map if auto-rendering is enabled @@ -1997,10 +1997,7 @@ def OnEndDrag(self, event): def OnDrop(self, dropTarget, dragItem): # save everything associated with item to drag - try: - old = dragItem # make sure this member exists - except: - return + old = dragItem # make sure this member exists Debug.msg(4, "LayerTree.OnDrop(): layer=%s" % (self.GetItemText(dragItem))) @@ -2046,7 +2043,7 @@ def RecreateItem(self, dragItem, dropTarget, parent=None): newctrl.SetValue( self.GetLayerInfo(dragItem, key="maplayer").GetCmd(string=True) ) - except: + except Exception: pass newctrl.Bind(wx.EVT_TEXT_ENTER, self.OnCmdChanged) data = self.GetPyData(dragItem) From 400b0df4a7823b1f767294dd567f16d226e80dcc Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Thu, 10 Oct 2024 20:41:09 +0200 Subject: [PATCH 173/209] docs: minor fixes to g.gisenv, i.atcorr, v.centroids, v.overlay, v.type (#4484) - g.gisenv.html: add EXAMPLES section (MEMORYMB, NPROCS) - i.atcorr.html: explain missing acronyms - v.centroids.html: start intro with what a centroid means - v.out.svg: fix GRASS_NS URL (fixes #4474) - v.overlay figures: colorize selected polygon in yellow color, not grey (sync to v.select) - v.type.html: explain vector object types in intro Note that the v.overlay figures should be redone to improve their quality (in a different PR). Co-authored-by: Anna Petrasova --- general/g.gisenv/g.gisenv.html | 29 +++++++++++++++++++++++++- imagery/i.atcorr/i.atcorr.html | 12 ++++++++++- scripts/v.centroids/v.centroids.html | 12 ++++++----- vector/v.out.svg/main.c | 2 +- vector/v.overlay/v.overlay.html | 8 +++---- vector/v.overlay/v_overlay_op_and.png | Bin 48720 -> 56006 bytes vector/v.overlay/v_overlay_op_not.png | Bin 33159 -> 40911 bytes vector/v.overlay/v_overlay_op_or.png | Bin 53214 -> 63574 bytes vector/v.overlay/v_overlay_op_xor.png | Bin 42262 -> 50253 bytes vector/v.type/v.type.html | 21 +++++++++++++++++++ 10 files changed, 72 insertions(+), 12 deletions(-) diff --git a/general/g.gisenv/g.gisenv.html b/general/g.gisenv/g.gisenv.html index 833e5051b36..4f5d9e165b3 100644 --- a/general/g.gisenv/g.gisenv.html +++ b/general/g.gisenv/g.gisenv.html @@ -149,6 +149,32 @@

    NOTES

    variables are stored in <gisdbase>/<project>/<mapset>/VAR after the current GRASS session is closed. +

    EXAMPLES

    + +

    Cache for raster operations

    + +The maximum memory to be used, i.e. the cache size for raster rows, is set +to 300 MB by default (GRASS variable MEMORYMB). To speed up +raster operations, it is recommended to increase this setting if enough RAM +is available. It is important to note that parallel processes will each +consume this amount of RAM. + +Set the maximum memory to be used (in MB), i.e. the cache size for raster rows: + +
    +# set to 6 GB (default: 300 MB)
    +g.gisenv set="MEMORYMB=6000"
    +
    + +

    Number of threads for parallel computing

    + +Set the number of threads for parallel computing: + +
    +# set to use 12 threads (default: 1)
    +g.gisenv set="NPROCS=12"
    +
    +

    GRASS Debugging

    To print debugging messages, the variable DEBUG must be set to level @@ -189,7 +215,8 @@

    SEE ALSO

    -See also variables list +See also +list of selected GRASS gisenv variables

    AUTHOR

    diff --git a/imagery/i.atcorr/i.atcorr.html b/imagery/i.atcorr/i.atcorr.html index 7c0b772e089..779ca7c7ef7 100644 --- a/imagery/i.atcorr/i.atcorr.html +++ b/imagery/i.atcorr/i.atcorr.html @@ -4,7 +4,7 @@

    DESCRIPTION

    map using the 6S algorithm (Second Simulation of Satellite Signal in the Solar Spectrum). A detailed algorithm description is available at the -Land Surface +Land Surface Reflectance Science Computing Facility website.

    Important: Current region settings are ignored! The @@ -507,6 +507,16 @@

    F. Sensor band

    Define your own spectral conditions: +Note that "wlinf" and "wlsup" refer to the limits of the wavelength range +defined by the user for a given simulation. Specifically: + +

      +
    • wlinf: This represents the lower wavelength limit (or minimum wavelength) + of the spectral band for which the simulation is being performed.
    • +
    • wlsup: This represents the upper wavelength limit (or maximum wavelength) + of the spectral band for the simulation.
    • +
    +
    FailedPercent successful
    207Worldview4 Red band (639nm - 711nm)
    208Worldview4 NIR1 band (732nm - 962nm)
    208AVIRIS b1 band (365nm)
    209AVIRIS b2 band (375nm)
    209AVIRIS b1 band (365nm)
    210AVIRIS b2 band (375nm)
    .AVIRIS b. band (+10nm)
    431AVIRIS b223 band (2486nm)
    432AVIRIS b224 band (2496nm)
    433Hyperion VNIR b8 band (427nm)
    433Hyperion VNIR b8 band (427nm)
    434Hyperion VNIR b9 band (437.16326nm)
    .Hyperion VNIR b. band (+10.16326nm)
    480Hyperion VNIR b56 band (914.83648nm)
    diff --git a/scripts/v.centroids/v.centroids.html b/scripts/v.centroids/v.centroids.html index 2bebed24e97..b814b702bab 100644 --- a/scripts/v.centroids/v.centroids.html +++ b/scripts/v.centroids/v.centroids.html @@ -1,11 +1,13 @@

    DESCRIPTION

    -GRASS defines vector areas as composite entities consisting of a set of +In GRASS GIS, a centroid is a point within a closed ring of boundaries. +A vector area is defined as composite entity consisting of a set of closed boundaries and a centroid. The attribute information associated -with that area is linked to the centroid. The v.centroids module -adds centroids to closed boundaries in the input file and assigns a -category number to them. The starting value as well as the increment size -may be set using optional parameters. +with this area is linked to the centroid. + +The v.centroids module adds centroids to closed boundaries in +the input file and assigns a category number to them. The starting +value as well as the increment size may be set using optional parameters.

    Multiple attributes may be linked to a single vector entity through numbered fields referred to as layers. Refer to v.category for more details, as v.centroids is simply a frontend to that diff --git a/vector/v.out.svg/main.c b/vector/v.out.svg/main.c index 4c99d148d04..4d29f845b29 100644 --- a/vector/v.out.svg/main.c +++ b/vector/v.out.svg/main.c @@ -25,7 +25,7 @@ #define SVG_NS "http://www.w3.org/2000/svg" #define XLINK_NS "http://www.w3.org/1999/xlink" -#define GRASS_NS "http:/grass.itc.it/2006/gg" +#define GRASS_NS "http://grass.itc.it/2006/gg" #define RADIUS_SCALE .003 #define WIDTH_SCALE .001 #define G_Areas "G_Areas" diff --git a/vector/v.overlay/v.overlay.html b/vector/v.overlay/v.overlay.html index 2b2a35be8c8..0077f2915f5 100644 --- a/vector/v.overlay/v.overlay.html +++ b/vector/v.overlay/v.overlay.html @@ -97,7 +97,7 @@

    AND operator

    v.overlay with AND operator
    -Figure: v.overlay with AND operator (selected polygons in grey color) +Figure: v.overlay with AND operator (selected polygons in yellow color)

    OR operator

    @@ -113,7 +113,7 @@

    OR operator

    v.overlay with OR operator
    -Figure: v.overlay with OR operator (selected polygons in grey color) +Figure: v.overlay with OR operator (selected polygons in yellow color)

    XOR operator

    @@ -129,7 +129,7 @@

    XOR operator

    v.overlay with XOR operator
    -Figure: v.overlay with XOR operator (selected polygons in grey color) +Figure: v.overlay with XOR operator (selected polygons in yellow color)

    NOT operator

    @@ -145,7 +145,7 @@

    NOT operator

    v.overlay with NOT operator
    -Figure: v.overlay with NOT operator (selected polygon in grey color) +Figure: v.overlay with NOT operator (selected polygon in yellow color)

    Overlay operations: AND, OR, NOT, XOR

    diff --git a/vector/v.overlay/v_overlay_op_and.png b/vector/v.overlay/v_overlay_op_and.png index 3d4bb3a07ffa2b09a6a6e1191549f12d994f925c..c545f2140ad461fc5d436123d2a902b9d336713b 100644 GIT binary patch literal 56006 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�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 KgCc}!@c#iUi@)~( literal 48720 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 diff --git a/vector/v.overlay/v_overlay_op_not.png b/vector/v.overlay/v_overlay_op_not.png index ac7eb441bbcb8da3025e231801337d5c28c8337b..2c903f22d6071a1357a3ab3b90942bfc8ef99a5e 100644 GIT binary patch literal 40911 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
    #=g&t)Ma9L%MJGmQ)@QbuTU0NV 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 KF?nW$#{559Z_b1O diff --git a/vector/v.overlay/v_overlay_op_or.png b/vector/v.overlay/v_overlay_op_or.png index c19bd32ce9f09244b0523d36220c0e9afbda6ff4..bbde7b06eb1eaa3f6e76eb190e805459bbcd6dc6 100644 GIT binary patch literal 63574 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

    2b;;H($19zc;m^mN#p>juk$~^5Qd?|N9jant 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 L&5iCG*oXZeHz)d< diff --git a/vector/v.overlay/v_overlay_op_xor.png b/vector/v.overlay/v_overlay_op_xor.png index 446624f36ec744c8ccc50c73eeb3da975955d58d..bf5bd5b8e4581c26e1c0ef2d6f66b5259f2dc647 100644 GIT binary patch literal 50253 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 literal 42262 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 diff --git a/vector/v.type/v.type.html b/vector/v.type/v.type.html index 8e6d5806db8..124f8f39fe0 100644 --- a/vector/v.type/v.type.html +++ b/vector/v.type/v.type.html @@ -2,6 +2,27 @@

    DESCRIPTION

    v.type changes the type of geometry primitives. +

    +The following vector object types are defined in GRASS GIS: + +

      +
    • point: a point;
    • +
    • line: a directed sequence of connected vertices with two endpoints called nodes;
    • +
    • boundary: the border line describing an area;
    • +
    • centroid: a point within a closed ring of boundaries;
    • +
    • area: the topological composition of a closed ring of boundaries and a centroid;
    • +
    • face: a 3D area;
    • +
    • kernel: a 3D centroid in a volume (not yet implemented);
    • +
    • volume: a 3D corpus, the topological composition of faces and kernel (not yet implemented).
    • +
    +

    +Lines and boundaries can be composed of multiple vertices. +

    +Area topology also holds information about isles. These isles are located +within that area, not touching the boundaries of the outer area. Isles +are holes inside the area, and can consist of one or more areas. They are +used internally to maintain correct topology for areas. +

    EXAMPLES

    Convert lines to area boundaries
    From 3a95b7a4e6412510d64b4a36a0a18bd7e7843d31 Mon Sep 17 00:00:00 2001 From: Mohan Yelugoti Date: Fri, 11 Oct 2024 02:32:11 -0400 Subject: [PATCH 174/209] raster/raster3d: Initialize Cell_head structure contents before use --- raster/r.in.lidar/main.c | 6 +++--- raster/r.in.pdal/main.cpp | 6 +++--- raster/r.in.xyz/main.c | 2 +- raster3d/r3.in.lidar/main.c | 7 +++---- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/raster/r.in.lidar/main.c b/raster/r.in.lidar/main.c index 68d3a0fcd1b..96f562167b6 100644 --- a/raster/r.in.lidar/main.c +++ b/raster/r.in.lidar/main.c @@ -51,8 +51,8 @@ int main(int argc, char *argv[]) struct PointBinning point_binning; void *base_array; void *raster_row; - struct Cell_head region; - struct Cell_head input_region; + struct Cell_head region = {0}; + struct Cell_head input_region = {0}; int rows, last_rows, row0, cols; /* scan box size */ int row; /* counters */ @@ -100,7 +100,7 @@ int main(int argc, char *argv[]) int return_filter; const char *projstr; - struct Cell_head cellhd, loc_wind; + struct Cell_head cellhd = {0}, loc_wind = {0}; unsigned int n_filtered; diff --git a/raster/r.in.pdal/main.cpp b/raster/r.in.pdal/main.cpp index da32dcb5484..36d09558eea 100644 --- a/raster/r.in.pdal/main.cpp +++ b/raster/r.in.pdal/main.cpp @@ -69,8 +69,8 @@ int main(int argc, char *argv[]) SEGMENT base_segment; struct PointBinning point_binning; void *raster_row; - struct Cell_head region; - struct Cell_head input_region; + struct Cell_head region = {}; + struct Cell_head input_region = {}; int rows, cols; /* scan box size */ char buff[BUFFSIZE]; @@ -81,7 +81,7 @@ int main(int argc, char *argv[]) bin_index_nodes.max_nodes = 0; bin_index_nodes.nodes = NULL; - struct Cell_head loc_wind; + struct Cell_head loc_wind = {}; G_gisinit(argv[0]); diff --git a/raster/r.in.xyz/main.c b/raster/r.in.xyz/main.c index a4c7dfde6ed..b3c3fb380cf 100644 --- a/raster/r.in.xyz/main.c +++ b/raster/r.in.xyz/main.c @@ -112,7 +112,7 @@ int main(int argc, char *argv[]) char *n_array, *min_array, *max_array, *sum_array, *sumsq_array, *index_array; void *raster_row, *ptr; - struct Cell_head region; + struct Cell_head region = {0}; int rows, last_rows, row0, cols; /* scan box size */ int row, col; /* counters */ diff --git a/raster3d/r3.in.lidar/main.c b/raster3d/r3.in.lidar/main.c index 6170a3f50ba..3cf91189d24 100644 --- a/raster3d/r3.in.lidar/main.c +++ b/raster3d/r3.in.lidar/main.c @@ -361,13 +361,12 @@ int main(int argc, char *argv[]) /* for the CRS info */ const char *projstr; - struct Cell_head current_region; - struct Cell_head file_region; - + struct Cell_head current_region = {0}; + struct Cell_head file_region = {0}; G_get_set_window(¤t_region); /* extent for all data */ - struct Cell_head data_region; + struct Cell_head data_region = {0}; long unsigned header_count = 0; int i; From b9a6b6883899e7611a2d65b63a1c02d6a50d59e4 Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Fri, 11 Oct 2024 10:21:22 -0400 Subject: [PATCH 175/209] doc: Use lowercase for 2D raster mask (#4401) On many places (more than covered here), 2D raster mask is called MASK conflating the concept (mask) and the implementation (MASK raster). Users using the r.mask tool may not interact with the underlying raster directly, so there is no reason to use MASK over mask. This is changing MASK to mask and modifies related wording. However, this is also leaving many places as they are with MASK. Some will be better revisited with or after #2390 and #2392 when a more comprehensive solution is available. This fixes and keeps in sync wording in r.null and r.external, and moves r.circle comment documenting the interface to a flag description. --- display/d.histogram/d.histogram.html | 2 +- raster/r.circle/main.c | 6 ++++-- raster/r.external/r.external.html | 8 +++++--- raster/r.null/r.null.html | 10 ++++++---- raster/r.stream.extract/r.stream.extract.html | 4 +++- raster3d/raster3dintro.html | 2 +- scripts/r.out.xyz/r.out.xyz.html | 2 +- 7 files changed, 21 insertions(+), 13 deletions(-) diff --git a/display/d.histogram/d.histogram.html b/display/d.histogram/d.histogram.html index 6e99c940290..43cca2d7223 100644 --- a/display/d.histogram/d.histogram.html +++ b/display/d.histogram/d.histogram.html @@ -10,7 +10,7 @@

    DESCRIPTION

    NOTES

    d.histogram respects the current geographic region settings -and the current MASK (if one exists). +and the current raster mask (if mask is active).

    d.histogram uses the colors in the map's color look-up table (i.e., the map's colr or colr2 file). diff --git a/raster/r.circle/main.c b/raster/r.circle/main.c index 4b41a78c7c6..bd99a292f71 100644 --- a/raster/r.circle/main.c +++ b/raster/r.circle/main.c @@ -79,7 +79,9 @@ int main(int argc, char *argv[]) flag = G_define_flag(); flag->key = 'b'; - flag->description = _("Generate binary raster map"); + flag->label = _("Generate binary raster map"); + flag->description = + _("Generate binary pattern only (useful for creating mask)"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); @@ -114,7 +116,7 @@ int main(int argc, char *argv[]) "using the binary flag")); if (flag->answer) - binary = 1; /* generate binary pattern only, useful for MASK */ + binary = 1; else binary = 0; diff --git a/raster/r.external/r.external.html b/raster/r.external/r.external.html index 797cc5ea605..f20c3e059d6 100644 --- a/raster/r.external/r.external.html +++ b/raster/r.external/r.external.html @@ -17,10 +17,12 @@

    NULL data handling

    NULL cells are those whose value matches the value reported by the GDALGetRasterNoDataValue() function. -To apply the GDAL-linked the user need to either create a MASK (e.g. -with r.mask) and then "apply" it using e.g. r.resample, +

    +To introduce additional NULL values to a computation based on a GDAL-linked +raster, the user needs to either create a mask with with r.mask and +then "apply" it using e.g. r.resample or r.mapcalc, or use r.mapcalc to create a copy with the appropriate categories -changed to NULL (if() condition). +changed to NULL (if() condition).

    EXAMPLES

    diff --git a/raster/r.null/r.null.html b/raster/r.null/r.null.html index 0a98907af5f..4d92b027d65 100644 --- a/raster/r.null/r.null.html +++ b/raster/r.null/r.null.html @@ -49,10 +49,12 @@

    External maps

    From the r.external documentation: GDAL-linked (r.external) maps do not have or use a NULL bitmap, hence r.null cannot manipulate them directly. Here NULL cells are those whose value matches -the value reported by the GDALGetRasterNoDataValue() function. To apply the -GDAL-linked the user need to either create a MASK (e.g. with r.mask) and -then "apply" it using e.g. r.resample, or use r.mapcalc to create a copy -with the appropriate categories changed to NULL (if() condition). +the value reported by the GDALGetRasterNoDataValue() function. +To introduce additional NULL values to a computation based on a GDAL-linked +raster, the user needs to either create a mask with with r.mask and +then "apply" it using e.g. r.resample or r.mapcalc, +or use r.mapcalc to create a copy with the appropriate categories +changed to NULL (if() condition).

    EXAMPLES

    diff --git a/raster/r.stream.extract/r.stream.extract.html b/raster/r.stream.extract/r.stream.extract.html index e1c427599e8..22877936c93 100644 --- a/raster/r.stream.extract/r.stream.extract.html +++ b/raster/r.stream.extract/r.stream.extract.html @@ -126,7 +126,9 @@

    Defining a region of interest

    The stream extraction procedure can be restricted to a certain region of interest, e.g. a subbasin, by setting the computational region with -g.region and/or creating a MASK. Such region of interest should +g.region and/or creating a mask +with r.mask. +Such region of interest should be a complete catchment area, complete in the sense that the complete area upstream of an outlet point is included and buffered with at least one cell. diff --git a/raster3d/raster3dintro.html b/raster3d/raster3dintro.html index ac476b974b2..b51748b4dd8 100644 --- a/raster3d/raster3dintro.html +++ b/raster3d/raster3dintro.html @@ -115,7 +115,7 @@

    Conversion from 2D raster maps

    2D rasters are considered as slices in this case and merged into one 3D raster map (r.to.rast3). -

    3D region settings and 3D MASK

    +

    3D region settings and 3D mask

    GRASS GIS 3D raster map processing is always performed in the current 3D region settings (see g.region, -p3 flags), i.e. diff --git a/scripts/r.out.xyz/r.out.xyz.html b/scripts/r.out.xyz/r.out.xyz.html index c9b2b6510be..e603c592e32 100644 --- a/scripts/r.out.xyz/r.out.xyz.html +++ b/scripts/r.out.xyz/r.out.xyz.html @@ -6,7 +6,7 @@

    DESCRIPTION

    NOTES

    This module will by default not export x,y coordinates for raster cells -containing a NULL value. This includes cells masked by a raster MASK. +containing a NULL value. This includes cells masked by a raster mask. Using the flag -i also these raster cells will be included in the exported data.

    From 2e0a8fa3359d062472fdf1a915be55f355e469d3 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Fri, 11 Oct 2024 10:48:51 -0400 Subject: [PATCH 176/209] tools: FIxed unused variable in imagery/ (#4487) fixed 821 --- .flake8 | 1 - imagery/i.atcorr/create_iwave.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.flake8 b/.flake8 index 313241f2d9d..1f5f4c9c040 100644 --- a/.flake8 +++ b/.flake8 @@ -21,7 +21,6 @@ per-file-ignores = # E741 ambiguous variable name 'l' __init__.py: F401, F403 man/build_html.py: E501 - imagery/i.atcorr/create_iwave.py: F632, F821, W293 doc/python/m.distance.py: E501 doc/gui/wxpython/example/dialogs.py: F401 gui/scripts/d.wms.py: E501 diff --git a/imagery/i.atcorr/create_iwave.py b/imagery/i.atcorr/create_iwave.py index a575d8089cd..21faa21ac2c 100644 --- a/imagery/i.atcorr/create_iwave.py +++ b/imagery/i.atcorr/create_iwave.py @@ -235,7 +235,7 @@ def write_cpp(bands, values, sensor, folder): while c < len(fi) - 1 and fi[c + 1] > rthresh: c += 1 max_wavelength = np.floor(li[0] * 1000 + (2.5 * c)) - print(" %s (%inm - %inm)" % (bands[b], min_wavelength, max_wavelength)) + print(" %s (%inm - %inm)" % (bands[0], min_wavelength, max_wavelength)) else: filter_f = [] From 21606ad863060c018e8b1b26f0fef4f693ae97da Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Fri, 11 Oct 2024 10:50:31 -0400 Subject: [PATCH 177/209] doc: Ignore F401 in dialogs.py (#4488) dialogs.py has an instance of F401 error for unused import of grass library. However as mentioned in the comment and post discussion with @wenzeslaus I decided it would be better to ignore this error for now in case it breaks any underlying dependencies regarding gettext.install() --- .flake8 | 1 - doc/gui/wxpython/example/dialogs.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.flake8 b/.flake8 index 1f5f4c9c040..f0c1f634e81 100644 --- a/.flake8 +++ b/.flake8 @@ -22,7 +22,6 @@ per-file-ignores = __init__.py: F401, F403 man/build_html.py: E501 doc/python/m.distance.py: E501 - doc/gui/wxpython/example/dialogs.py: F401 gui/scripts/d.wms.py: E501 gui/wxpython/image2target/*: F841, E722 gui/wxpython/image2target/g.gui.image2target.py: E501, F841 diff --git a/doc/gui/wxpython/example/dialogs.py b/doc/gui/wxpython/example/dialogs.py index 425ea57a4b2..98760e7202d 100644 --- a/doc/gui/wxpython/example/dialogs.py +++ b/doc/gui/wxpython/example/dialogs.py @@ -20,7 +20,7 @@ # So we need to import it before any of the GUI code. # NOTE: in this particular case, we don't really need the grass library; # NOTE: we import it just for the side effects of gettext.install() -import grass +import grass # noqa: F401 from core import globalvar from gui_core.dialogs import SimpleDialog From 426bf742123680c4067ab930a758cdb1ddbc9624 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Fri, 11 Oct 2024 10:51:20 -0400 Subject: [PATCH 178/209] checks: update .flake8 to reflect correct status in image2target (#4489) --- .flake8 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.flake8 b/.flake8 index f0c1f634e81..c01dc46b255 100644 --- a/.flake8 +++ b/.flake8 @@ -23,8 +23,7 @@ per-file-ignores = man/build_html.py: E501 doc/python/m.distance.py: E501 gui/scripts/d.wms.py: E501 - gui/wxpython/image2target/*: F841, E722 - gui/wxpython/image2target/g.gui.image2target.py: E501, F841 + gui/wxpython/image2target/g.gui.image2target.py: E501 gui/wxpython/modules/*: F841, E722 gui/wxpython/nviz/*: F841, E266, E722, F403, F405 gui/wxpython/photo2image/*: F841, E722, E265 From cbc3ff4f349d258b875a23ce2c8a92f069a79226 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Fri, 11 Oct 2024 10:51:40 -0400 Subject: [PATCH 179/209] wxGUI: FIxed F841 in colorrules.py (#4490) --- gui/wxpython/modules/colorrules.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/gui/wxpython/modules/colorrules.py b/gui/wxpython/modules/colorrules.py index cad74f38c4b..3dfdde8c42b 100644 --- a/gui/wxpython/modules/colorrules.py +++ b/gui/wxpython/modules/colorrules.py @@ -318,7 +318,9 @@ def LoadRules(self): int, self.ruleslines[item][self.attributeType].split(":") ) except ValueError as e: - message = _("Bad color format. Use color format '0:0:0'") + message = ( + _("Bad color format '%s'. Use color format '0:0:0'") % e + ) self.mainPanel.FindWindowById(item + 2000).SetValue((r, g, b)) else: value = float(self.ruleslines[item][self.attributeType]) @@ -410,7 +412,6 @@ def _initLayer(self): if layer: mapLayer = self.layerTree.GetLayerInfo(layer, key="maplayer") name = mapLayer.GetName() - type = mapLayer.GetType() self.selectionInput.SetValue(name) self.inmap = name @@ -1412,7 +1413,7 @@ def AddTemporaryColumn(self, type): modul = "v.db.addcolumn" else: modul = "v.db.addcol" - ret = RunCommand( + RunCommand( modul, parent=self, map=self.inmap, @@ -1430,7 +1431,7 @@ def DeleteTemporaryColumn(self): modul = "v.db.dropcolumn" else: modul = "v.db.dropcol" - ret = RunCommand( + RunCommand( modul, map=self.inmap, layer=self.properties["layer"], @@ -1505,7 +1506,7 @@ def OnAddColumn(self, event): modul = "v.db.addcolumn" else: modul = "v.db.addcol" - ret = RunCommand( + RunCommand( modul, map=self.inmap, layer=self.properties["layer"], From 1d42e580e25d62dee5f3e2653f7bcb5241855f71 Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Fri, 11 Oct 2024 16:25:56 -0400 Subject: [PATCH 180/209] r.mask.status: Check mask status through a tool and function (#2390) Instead of using low-level test of file existence with hardcoded raster path and name, this offers a new tool to retrieve status of the raster mask. The new r.mask.status tool reports presence or absence of the 2D raster mask and provides additional details about the mask. There is one usage of this now and that's the one for a shell prompt. The prompt no longer relies on testing the file presence with the test program, but uses a GRASS tool to find out. The code goes out of its way to report both mask name (currently always MASK) and the underlying raster name if it is a reclassified (without rewriting the current C API). This is to mimic the existing C functions which are returning the underlying raster if MASK is a reclass. The tool and the new C API function return both preparing a way for using an arbitrary name for the mask while having the option to look at the underlying reclassified raster map. --- include/grass/defs/raster.h | 1 + lib/init/grass.py | 2 +- lib/raster/mask_info.c | 120 +++++++++--- raster/Makefile | 1 + raster/r.mask.status/Makefile | 10 + raster/r.mask.status/main.c | 184 ++++++++++++++++++ raster/r.mask.status/r.mask.status.html | 65 +++++++ raster/r.mask.status/tests/conftest.py | 25 +++ .../r.mask.status/tests/r_mask_status_test.py | 126 ++++++++++++ 9 files changed, 507 insertions(+), 27 deletions(-) create mode 100644 raster/r.mask.status/Makefile create mode 100644 raster/r.mask.status/main.c create mode 100644 raster/r.mask.status/r.mask.status.html create mode 100644 raster/r.mask.status/tests/conftest.py create mode 100644 raster/r.mask.status/tests/r_mask_status_test.py diff --git a/include/grass/defs/raster.h b/include/grass/defs/raster.h index c2d26ccdccc..7f358562c72 100644 --- a/include/grass/defs/raster.h +++ b/include/grass/defs/raster.h @@ -392,6 +392,7 @@ int Rast_option_to_interp_type(const struct Option *); /* mask_info.c */ char *Rast_mask_info(void); +bool Rast_mask_status(char *, char *, bool *, char *, char *); int Rast__mask_info(char *, char *); bool Rast_mask_is_present(void); diff --git a/lib/init/grass.py b/lib/init/grass.py index f489ad1fe53..d2d8301c52b 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -1667,8 +1667,8 @@ def sh_like_startup(location, location_name, grass_env_file, sh): ) ) + mask2d_test = "r.mask.status -t" # TODO: have a function and/or module to test this - mask2d_test = 'test -f "$MAPSET_PATH/cell/MASK"' mask3d_test = 'test -d "$MAPSET_PATH/grid3/RASTER3D_MASK"' specific_addition = "" diff --git a/lib/raster/mask_info.c b/lib/raster/mask_info.c index 1a11da972f8..42102de86dd 100644 --- a/lib/raster/mask_info.c +++ b/lib/raster/mask_info.c @@ -1,30 +1,17 @@ -/* - ************************************************************* - * char * Rast_mask_info () - * - * returns a printable text of mask information - * - ************************************************************ - * Rast__mask_info (name, mapset) - * - * char name[GNAME_MAX], mapset[GMAPSET_MAX]; - * - * function: - * determine the status off the automatic masking - * and the name of the cell file which forms the mask +/** + * \file lib/raster/mask_info.c * - * (the mask file is actually MASK in the current mapset, - * but is usually a reclassed cell file, and the reclass - * name and mapset are returned) + * \brief Raster Library - Get mask information * - * returns: - * -1 no masking (name, mapset undefined) - * name, mapset are undefined + * (C) 1999-2024 by Vaclav Petras and the GRASS Development Team * - * 1 mask file present, masking on - * name, mapset hold mask file name, mapset + * This program is free software under the GNU General Public + * License (>=v2). Read the file COPYING that comes with GRASS + * for details. * - ***************************************************************/ + * \author CERL + * \author Vaclav Petras, NC State University, Center for Geospatial Analytics + */ #include @@ -32,6 +19,15 @@ #include #include +/** + * @brief Get a printable text with information about raster mask + * + * Determines if 2D raster mask is present and returns textual information about + * the mask suitable for end-user display. The resulting text is translated. + * Caller is responsible for freeing the memory of the returned string. + * + * @return New string with textual information + */ char *Rast_mask_info(void) { char text[GNAME_MAX + GMAPSET_MAX + 16]; @@ -53,16 +49,88 @@ char *Rast_mask_info(void) return G_store(text); } +/** + * @brief Get raster mask status information + * + * _is_mask_reclass_ is a pointer to a bool variable which + * will be set to true if mask raster is a reclass and false otherwise. + * + * If you are not interested in the underlying reclassified raster map, + * pass NULL pointers for the three reclass parameters: + * + * ``` + * Rast_mask_status(name, mapset, NULL, NULL, NULL); + * ``` + * + * @param[out] name Name of the raster map used as mask + * @param[out] mapset Name of the mapset the raster is in + * @param[out] is_mask_reclass Will be set to true if mask raster is a reclass + * @param[out] reclass_name Name of the underlying reclassified raster map + * @param[out] reclass_mapset Name of the mapset the reclassified raster is in + * + * @return true if mask is present, false otherwise + */ +bool Rast_mask_status(char *name, char *mapset, bool *is_mask_reclass, + char *reclass_name, char *reclass_mapset) +{ + int present = Rast__mask_info(name, mapset); + + if (is_mask_reclass && reclass_name && reclass_mapset) { + if (present) { + *is_mask_reclass = Rast_is_reclass("MASK", G_mapset(), reclass_name, + reclass_mapset) > 0; + if (*is_mask_reclass) { + // The original mask values were overwritten in the initial + // info call. Put back the original values, so that we can + // report them to the caller. + strcpy(name, "MASK"); + strcpy(mapset, G_mapset()); + } + } + else { + *is_mask_reclass = false; + } + } + + if (present == 1) + return true; + else + return false; +} + +/** + * @brief Get information about the current mask + * + * Determines the status of the automatic masking and the name of the 2D + * raster which forms the mask. Typically, mask is raster called MASK in the + * current mapset, but when used with r.mask, it is usually a reclassed + * raster, and so when a MASK raster is present and it is a reclass raster, + * the name and mapset of the underlying reclassed raster are returned. + * + * The name and mapset is written to the parameter which need to be defined + * with a sufficient size, least as `char name[GNAME_MAX], mapset[GMAPSET_MAX]`. + * + * When the masking is not active, -1 is returned and name and mapset are + * undefined. When the masking is active, 1 is returned and name and mapset + * will hold the name and mapset of the underlying raster. + * + * @param[out] name Name of the raster map used as mask + * @param[out] mapset Name of the map's mapset + * + * @return 1 if mask is present, -1 otherwise + */ int Rast__mask_info(char *name, char *mapset) { char rname[GNAME_MAX], rmapset[GMAPSET_MAX]; - strcpy(name, "MASK"); - strcpy(mapset, G_mapset()); + strcpy(rname, "MASK"); + strcpy(rmapset, G_mapset()); - if (!G_find_raster(name, mapset)) + if (!G_find_raster(rname, rmapset)) return -1; + strcpy(name, rname); + strcpy(mapset, rmapset); if (Rast_is_reclass(name, mapset, rname, rmapset) > 0) { strcpy(name, rname); strcpy(mapset, rmapset); diff --git a/raster/Makefile b/raster/Makefile index bcd07660238..91ff54d0863 100644 --- a/raster/Makefile +++ b/raster/Makefile @@ -45,6 +45,7 @@ SUBDIRS = \ r.lake \ r.li \ r.mapcalc \ + r.mask.status \ r.mfilter \ r.mode \ r.neighbors \ diff --git a/raster/r.mask.status/Makefile b/raster/r.mask.status/Makefile new file mode 100644 index 00000000000..62c968d044e --- /dev/null +++ b/raster/r.mask.status/Makefile @@ -0,0 +1,10 @@ +MODULE_TOPDIR = ../.. + +PGM = r.mask.status + +LIBES = $(MANAGELIB) $(RASTERLIB) $(GISLIB) $(PARSONLIB) +DEPENDENCIES = $(MANAGEDEP) $(RASTERDEP) $(GISDEP) + +include $(MODULE_TOPDIR)/include/Make/Module.make + +default: cmd diff --git a/raster/r.mask.status/main.c b/raster/r.mask.status/main.c new file mode 100644 index 00000000000..5eb32300240 --- /dev/null +++ b/raster/r.mask.status/main.c @@ -0,0 +1,184 @@ +/**************************************************************************** + * + * MODULE: r.mask.status + * AUTHORS: Vaclav Petras + * PURPOSE: Report status of raster mask + * COPYRIGHT: (C) 2024 by Vaclav Petras 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. + * + *****************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include +#include + +struct Parameters { + struct Option *format; + struct Flag *like_test; +}; + +void parse_parameters(struct Parameters *params, int argc, char **argv) +{ + struct GModule *module; + + module = G_define_module(); + G_add_keyword(_("raster")); + G_add_keyword(_("mask")); + G_add_keyword(_("reclassification")); + module->label = _("Reports presence or absence of a raster mask"); + module->description = + _("Provides information about the presence of a 2D raster mask" + " as text output or return code"); + + params->format = G_define_option(); + params->format->key = "format"; + params->format->type = TYPE_STRING; + params->format->required = NO; + params->format->answer = "plain"; + params->format->options = "plain,json,shell,yaml"; + params->format->descriptions = + "plain;Plain text output;" + "json;JSON (JavaScript Object Notation);" + "shell;Shell script style output;" + "yaml;YAML (human-friendly data serialization language)"; + params->format->description = _("Format for reporting"); + + params->like_test = G_define_flag(); + params->like_test->key = 't'; + params->like_test->label = + _("Return code 0 when mask present, 1 otherwise"); + params->like_test->description = + _("Behave like the test utility, 0 for true, 1 for false, no output"); + // suppress_required is not required given the default value for format. + // Both no parameters and only -t work as expected. + + if (G_parser(argc, argv)) + exit(EXIT_FAILURE); +} + +int report_status(struct Parameters *params) +{ + + char name[GNAME_MAX]; + char mapset[GMAPSET_MAX]; + char reclass_name[GNAME_MAX]; + char reclass_mapset[GMAPSET_MAX]; + + bool is_mask_reclass; + bool present = Rast_mask_status(name, mapset, &is_mask_reclass, + reclass_name, reclass_mapset); + + // This does not have to be exclusive with the printing, but leaving this + // to a different boolean flag which could do the return code and printing. + // The current implementation really behaves like the test utility which + // facilitates the primary usage of this which is prompt building + // (and there any output would be noise). + if (params->like_test->answer) { + if (present) + return 0; + return 1; + } + + // Mask raster + char *full_mask = G_fully_qualified_name(name, mapset); + // Underlying raster if applicable + char *full_underlying = NULL; + if (is_mask_reclass) + full_underlying = G_fully_qualified_name(reclass_name, reclass_mapset); + + if (strcmp(params->format->answer, "json") == 0) { + JSON_Value *root_value = json_value_init_object(); + JSON_Object *root_object = json_object(root_value); + json_object_set_boolean(root_object, "present", present); + if (present) + json_object_set_string(root_object, "full_name", full_mask); + else + json_object_set_null(root_object, "full_name"); + if (is_mask_reclass) + json_object_set_string(root_object, "is_reclass_of", + full_underlying); + else + json_object_set_null(root_object, "is_reclass_of"); + char *serialized_string = json_serialize_to_string_pretty(root_value); + puts(serialized_string); + json_free_serialized_string(serialized_string); + json_value_free(root_value); + } + else if (strcmp(params->format->answer, "shell") == 0) { + printf("present="); + if (present) + printf("1"); + else + printf("0"); + printf("\nfull_name="); + if (present) + printf("%s", full_mask); + printf("\nis_reclass_of="); + if (is_mask_reclass) + printf("%s", full_underlying); + printf("\n"); + } + else if (strcmp(params->format->answer, "yaml") == 0) { + printf("present: "); + if (present) + printf("true"); + else + printf("false"); + printf("\nfull_name: "); + if (present) + printf("|-\n %s", full_mask); + else + printf("null"); + // Null values in YAML can be an empty (no) value (rather than null), + // so we could use that, but using the explicit null as a reasonable + // starting point. + printf("\nis_reclass_of: "); + // Using block scalar with |- to avoid need for escaping. + // Alternatively, we could check mapset naming limits against YAML + // escaping needs for different types of strings and do the necessary + // escaping here. + if (is_mask_reclass) + printf("|-\n %s", full_underlying); + else + printf("null"); + printf("\n"); + } + else { + if (present) + printf(_("Mask is active")); + else + printf(_("Mask is not present")); + if (present) { + printf("\n"); + printf(_("Mask name: %s"), full_mask); + } + if (is_mask_reclass) { + printf("\n"); + printf(_("Mask is a raster reclassified from: %s"), + full_underlying); + } + printf("\n"); + } + + G_free(full_mask); + G_free(full_underlying); + return EXIT_SUCCESS; +} + +int main(int argc, char **argv) +{ + struct Parameters params; + + G_gisinit(argv[0]); + parse_parameters(¶ms, argc, argv); + return report_status(¶ms); +} diff --git a/raster/r.mask.status/r.mask.status.html b/raster/r.mask.status/r.mask.status.html new file mode 100644 index 00000000000..248ee3ea317 --- /dev/null +++ b/raster/r.mask.status/r.mask.status.html @@ -0,0 +1,65 @@ +

    DESCRIPTION

    + +The r.mask.status reports information about the 2D raster mask and its +status. If the mask is present, the tool reports a full name of the raster (name +including the mapset) which represents the mask. It can also report full name of +the underlying raster if the mask is reclassified from another raster. + +

    +With the -t flag, no output is printed, instead a return code is used to +indicate presence or absence. The convention is the same same the POSIX +test utility, so r.mask.status returns 0 when the mask is +present and 1 otherwise. + +

    EXAMPLES

    + +

    Generate JSON output

    + +To generate JSON output in Bash, use the format option: + +
    +r.mask.status format=json
    +
    + +In Python, use: + +
    +import grass.script as gs
    +gs.parse_command("r.mask.status", format="json")
    +
    + +This returns a dictionary with keys present, +full_name, and is_reclass_of. + +

    Use as the test utility

    + +The POSIX test utility uses return code 0 to indicate presence +and 1 to indicate absence of a file, so testing existence of a file with +test -f gives return code 0 when the file exists. +r.mask.status can be used in the same with the the -t flag: + +
    +r.mask.status -t
    +
    + +In a Bash script: + +
    +# Bash
    +if r.mask.status -t; then
    +    echo "Masking is active"
    +else
    +    echo "Masking is not active"
    +fi
    +
    + +

    SEE ALSO

    + + +r.mask, +g.region + + +

    AUTHORS

    + +Vaclav Petras, NC State University, Center for Geospatial Analytics diff --git a/raster/r.mask.status/tests/conftest.py b/raster/r.mask.status/tests/conftest.py new file mode 100644 index 00000000000..e8e27315845 --- /dev/null +++ b/raster/r.mask.status/tests/conftest.py @@ -0,0 +1,25 @@ +"""Fixtures for simple sessions""" + +import os +import pytest +import grass.script as gs + + +@pytest.fixture +def session_no_data(tmp_path): + """Set up a GRASS session for the tests.""" + project = "test_project" + gs.create_project(tmp_path, project) + with gs.setup.init(tmp_path / project, env=os.environ.copy()) as session: + yield session + + +@pytest.fixture +def session_with_data(tmp_path): + """Set up a GRASS session for the tests.""" + project = tmp_path / "test_project" + gs.create_project(project) + with gs.setup.init(project, env=os.environ.copy()) as session: + gs.run_command("g.region", rows=2, cols=2, env=session.env) + gs.mapcalc("a = 1", env=session.env) + yield session diff --git a/raster/r.mask.status/tests/r_mask_status_test.py b/raster/r.mask.status/tests/r_mask_status_test.py new file mode 100644 index 00000000000..deafdfb145b --- /dev/null +++ b/raster/r.mask.status/tests/r_mask_status_test.py @@ -0,0 +1,126 @@ +"""Tests of r.mask.status""" + +import pytest + +try: + import yaml +except ImportError: + yaml = None + +import grass.script as gs + + +def test_json_no_mask(session_no_data): + """Check JSON format for no mask""" + session = session_no_data + data = gs.parse_command("r.mask.status", format="json", env=session.env) + assert "present" in data + assert "full_name" in data + assert "is_reclass_of" in data + assert data["present"] is False + assert not data["full_name"] + assert not data["is_reclass_of"] + + +def test_json_with_r_mask(session_with_data): + """Check JSON format for the r.mask case""" + session = session_with_data + gs.run_command("r.mask", raster="a", env=session.env) + data = gs.parse_command("r.mask.status", format="json", env=session.env) + assert data["present"] is True + assert data["full_name"] == "MASK@PERMANENT" + assert data["is_reclass_of"] == "a@PERMANENT" + # Now remove the mask. + gs.run_command("r.mask", flags="r", env=session.env) + data = gs.parse_command("r.mask.status", format="json", env=session.env) + assert data["present"] is False + assert not data["full_name"] + assert not data["is_reclass_of"] + + +def test_json_with_g_copy(session_with_data): + """Check JSON format for the low-level g.copy case""" + session = session_with_data + gs.run_command("g.copy", raster="a,MASK", env=session.env) + data = gs.parse_command("r.mask.status", format="json", env=session.env) + assert data["present"] is True + assert data["full_name"] == "MASK@PERMANENT" + assert not data["is_reclass_of"] + # Now remove the mask. + gs.run_command("g.remove", type="raster", name="MASK", flags="f", env=session.env) + data = gs.parse_command("r.mask.status", format="json", env=session.env) + assert data["present"] is False + assert not data["full_name"] + assert not data["is_reclass_of"] + + +def test_shell(session_with_data): + """Check shell format for the r.mask case""" + session = session_with_data + gs.run_command("r.mask", raster="a", env=session.env) + data = gs.parse_command("r.mask.status", format="shell", env=session.env) + assert int(data["present"]) + assert data["full_name"] == "MASK@PERMANENT" + assert data["is_reclass_of"] == "a@PERMANENT" + # Now remove the mask. + gs.run_command("r.mask", flags="r", env=session.env) + data = gs.parse_command("r.mask.status", format="shell", env=session.env) + assert not int(data["present"]) + assert not data["full_name"] + assert not data["is_reclass_of"] + + +@pytest.mark.skipif(yaml is None, reason="PyYAML package not available") +def test_yaml(session_with_data): + """Check YAML format for the r.mask case""" + session = session_with_data + gs.run_command("r.mask", raster="a", env=session.env) + text = gs.read_command("r.mask.status", format="yaml", env=session.env) + data = yaml.safe_load(text) + assert data["present"] is True + assert data["full_name"] == "MASK@PERMANENT" + assert data["is_reclass_of"] == "a@PERMANENT" + # Now remove the mask. + gs.run_command("r.mask", flags="r", env=session.env) + text = gs.read_command("r.mask.status", format="yaml", env=session.env) + data = yaml.safe_load(text) + assert data["present"] is False + assert not data["full_name"] + assert not data["is_reclass_of"] + + +def test_plain(session_with_data): + """Check plain text format for the r.mask case""" + session = session_with_data + gs.run_command("r.mask", raster="a", env=session.env) + text = gs.read_command("r.mask.status", format="plain", env=session.env) + assert text + assert "MASK@PERMANENT" in text + assert "a@PERMANENT" in text + # Now remove the mask. + gs.run_command("r.mask", flags="r", env=session.env) + text = gs.read_command("r.mask.status", format="plain", env=session.env) + assert text + + +def test_without_parameters(session_no_data): + """Check output is generated with no parameters""" + session = session_no_data + text = gs.read_command("r.mask.status", env=session.env) + assert text + + +def test_behavior_mimicking_test_program(session_with_data): + """Check test program like behavior for the r.mask case""" + session = session_with_data + gs.run_command("r.mask", raster="a", env=session.env) + returncode = gs.run_command( + "r.mask.status", flags="t", env=session.env, errors="status" + ) + assert returncode == 0 + # Now remove the mask. + gs.run_command("r.mask", flags="r", env=session.env) + returncode = gs.run_command( + "r.mask.status", flags="t", env=session.env, errors="status" + ) + assert returncode == 1 From 0feea315328915bfc1382097805c526708f1736e Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Sat, 12 Oct 2024 04:03:51 -0400 Subject: [PATCH 181/209] i.ortho.photo: Fix Resource Leak in find_init.c (#4388) --- imagery/i.ortho.photo/lib/find_init.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/imagery/i.ortho.photo/lib/find_init.c b/imagery/i.ortho.photo/lib/find_init.c index 906203a7f90..f8cea9b9387 100644 --- a/imagery/i.ortho.photo/lib/find_init.c +++ b/imagery/i.ortho.photo/lib/find_init.c @@ -4,15 +4,19 @@ * Find the a camera initial file in the current group (if it exists) **************************************************************/ #include +#include int I_find_initial(char *group) { - char *element; - - element = (char *)G_malloc(80 * sizeof(char)); + char element[GNAME_MAX + 6]; if (group == NULL || *group == 0) return 0; - sprintf(element, "group/%s", group); + + if (snprintf(element, GNAME_MAX, "group/%s", group) >= GNAME_MAX) { + G_warning(_("Group name <%s> is too long"), group); + return 0; + } + return G_find_file(element, "INIT_EXP", G_mapset()) != NULL; } From 9df8433d50a9552ebe53ea37c45d698739bdcf4f Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Sat, 12 Oct 2024 04:06:08 -0400 Subject: [PATCH 182/209] lib/vector/Vlib: Fix copy into buffer size issue in color_read.c (#4462) --- lib/vector/Vlib/color_read.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/vector/Vlib/color_read.c b/lib/vector/Vlib/color_read.c index 0a023a89a7d..4e0b3b04837 100644 --- a/lib/vector/Vlib/color_read.c +++ b/lib/vector/Vlib/color_read.c @@ -49,7 +49,10 @@ int Vect_read_colors(const char *name, const char *mapset, if (colors) Rast_init_colors(colors); - strcpy(xname, name); + if (G_strlcpy(xname, name, sizeof(xname)) >= sizeof(xname)) { + G_warning(_("Vector map name <%s> is too long"), name); + return -1; + } mapset = G_find_vector(xname, mapset); if (!mapset) return -1; @@ -58,12 +61,12 @@ int Vect_read_colors(const char *name, const char *mapset, if (strcmp(mapset, G_mapset()) == 0) { /* look for the regular color table */ - sprintf(buf, "%s/%s", GV_DIRECTORY, name); + (void)snprintf(buf, sizeof(buf), "%s/%s", GV_DIRECTORY, name); ret = Rast__read_colors(buf, GV_COLR_ELEMENT, mapset, colors); } else { /* look for secondary color table in current mapset */ - sprintf(buf, "%s/%s", GV_COLR2_DIRECTORY, mapset); + (void)snprintf(buf, sizeof(buf), "%s/%s", GV_COLR2_DIRECTORY, mapset); ret = Rast__read_colors(buf, name, G_mapset(), colors); } if (ret == -2) From 4cf93d28d995f4a012c68914fcbe95786245b444 Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Sat, 12 Oct 2024 04:09:53 -0400 Subject: [PATCH 183/209] checks: Remove extra semicolons in r.terraflow (#4494) --- raster/r.terraflow/fill.cpp | 2 +- raster/r.terraflow/genericWindow.cpp | 2 +- raster/r.terraflow/sweep.cpp | 2 +- raster/r.terraflow/weightWindow.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/raster/r.terraflow/fill.cpp b/raster/r.terraflow/fill.cpp index ab1629a3b7f..c7b54cd0a47 100644 --- a/raster/r.terraflow/fill.cpp +++ b/raster/r.terraflow/fill.cpp @@ -518,7 +518,7 @@ void assignFinalDirections(AMI_STREAM *statstr, continue; } } -}; +} /* ********************************************************************** */ class directionElevationMerger { diff --git a/raster/r.terraflow/genericWindow.cpp b/raster/r.terraflow/genericWindow.cpp index 92b0852cd71..9b114773e2a 100644 --- a/raster/r.terraflow/genericWindow.cpp +++ b/raster/r.terraflow/genericWindow.cpp @@ -36,4 +36,4 @@ void fillPit(ElevationWindow &win) if (win.get(4) < min) { win.set(4, min); } -}; +} diff --git a/raster/r.terraflow/sweep.cpp b/raster/r.terraflow/sweep.cpp index 2f7fba8bb13..c98b844b016 100644 --- a/raster/r.terraflow/sweep.cpp +++ b/raster/r.terraflow/sweep.cpp @@ -65,7 +65,7 @@ sweepOutput::sweepOutput() #ifdef OUTPUT_TCI tci = (tci_type)nodataType::ELEVATION_NODATA; #endif -}; +} /* ------------------------------------------------------------ */ /* computes output parameters of cell (i,j) given the flow value, the diff --git a/raster/r.terraflow/weightWindow.cpp b/raster/r.terraflow/weightWindow.cpp index ccf55a82ca9..760dccc6b5c 100644 --- a/raster/r.terraflow/weightWindow.cpp +++ b/raster/r.terraflow/weightWindow.cpp @@ -229,7 +229,7 @@ void weightWindow::compute(const dimension_type i, const dimension_type j, cout << form("%3.2f ", weight.get(l)); cout << "]\n"; #endif -}; +} /* Find the dominant direction. Set corresponding weight to 1, and sets all other weights to 0. Set sumweight and sumcontour.*/ From 71066f415bfb1f85c488e61284f8b477fb7a910b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 12 Oct 2024 07:27:34 -0400 Subject: [PATCH 184/209] CI(deps): Update actions/upload-artifact action to v4.4.3 (#4481) --- .github/actions/create-upload-suggestions/action.yml | 4 ++-- .github/workflows/macos.yml | 2 +- .github/workflows/osgeo4w.yml | 2 +- .github/workflows/pytest.yml | 2 +- .github/workflows/python-code-quality.yml | 4 ++-- .github/workflows/ubuntu.yml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/actions/create-upload-suggestions/action.yml b/.github/actions/create-upload-suggestions/action.yml index 181babe11e9..b80c08c1b46 100644 --- a/.github/actions/create-upload-suggestions/action.yml +++ b/.github/actions/create-upload-suggestions/action.yml @@ -177,7 +177,7 @@ runs: echo "diff-file-name=${INPUT_DIFF_FILE_NAME}" >> "${GITHUB_OUTPUT}" env: INPUT_DIFF_FILE_NAME: ${{ steps.tool-name-safe.outputs.diff-file-name }} - - uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 + - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 id: upload-diff if: >- ${{ (steps.files_changed.outputs.files_changed == 'true') && @@ -200,7 +200,7 @@ runs: echo 'Suggestions can only be added near to lines changed in this PR.' echo 'If any fixes can be added as code suggestions, they will be added shortly from another workflow.' } >> "${GITHUB_STEP_SUMMARY}" - - uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 + - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 id: upload-changes if: >- ${{ always() && diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 7b4e7eb18e2..41ac51df8ff 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -107,7 +107,7 @@ jobs: nc_spm_full_v2alpha2.tar.gz" - name: Make HTML test report available if: ${{ !cancelled() }} - uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: testreport-macOS path: testreport diff --git a/.github/workflows/osgeo4w.yml b/.github/workflows/osgeo4w.yml index 180cc79ec08..a7694fa9b30 100644 --- a/.github/workflows/osgeo4w.yml +++ b/.github/workflows/osgeo4w.yml @@ -120,7 +120,7 @@ jobs: - name: Make HTML test report available if: ${{ always() }} - uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: testreport-${{ matrix.os }} path: testreport diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 60ddb223074..f2a96cf41ba 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -116,7 +116,7 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} - name: Make python-only code coverage test report available if: ${{ !cancelled() }} - uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: python-codecoverage-report-${{ matrix.os }}-${{ matrix.python-version }} path: coverage_html_report diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 5da86464470..b8b423b2b16 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -129,7 +129,7 @@ jobs: bandit -c pyproject.toml -iii -r . -f sarif -o bandit.sarif --exit-zero - name: Upload Bandit Scan Results - uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: bandit.sarif path: bandit.sarif @@ -201,7 +201,7 @@ jobs: cp -rp dist.$ARCH/docs/html/libpython sphinx-grass - name: Make Sphinx documentation available - uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: sphinx-grass path: sphinx-grass diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 88ddd0d31b2..966dbfe21ab 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -149,7 +149,7 @@ jobs: - name: Make HTML test report available if: ${{ always() }} - uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: testreport-${{ matrix.os }}-${{ matrix.config }}-${{ matrix.extra-include }} path: testreport From 542f3b479c6fd44477485aac26e5491bc30966a7 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Sat, 12 Oct 2024 07:28:22 -0400 Subject: [PATCH 185/209] v.colors: Fix Resource Leak issue in read_rgb.c (#4497) --- vector/v.colors/read_rgb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vector/v.colors/read_rgb.c b/vector/v.colors/read_rgb.c index 99aa054138d..c6e762ca0af 100644 --- a/vector/v.colors/read_rgb.c +++ b/vector/v.colors/read_rgb.c @@ -64,4 +64,5 @@ void rgb2colr(struct Map_info *Map, int layer, const char *rgb_column, G_warning(_("%d invalid RGB color values skipped"), nskipped); db_close_database_shutdown_driver(driver); + Vect_destroy_field_info(fi); } From 779af809951d802c2ba25cc7e01582c7d20da986 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Sat, 12 Oct 2024 07:28:58 -0400 Subject: [PATCH 186/209] v.to.db: Fix Resource Leak issue in areas.c (#4498) * Fix Resource Leak issue * Fix Resource Leak issue --- vector/v.to.db/areas.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vector/v.to.db/areas.c b/vector/v.to.db/areas.c index 0977890276e..232cc4894d6 100644 --- a/vector/v.to.db/areas.c +++ b/vector/v.to.db/areas.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "global.h" @@ -111,5 +112,6 @@ int read_areas(struct Map_info *Map) G_percent(area_num, nareas, 2); } + Vect_destroy_cats_struct(Cats); return 0; } From 03675b0323cfff4974c0298139d0d73199b0a5a1 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Sat, 12 Oct 2024 10:23:47 -0400 Subject: [PATCH 187/209] d.vect: Fix Resource Leak issue in attr.c (#4496) * fix Resource Leak issue * Update display/d.vect/attr.c --- display/d.vect/attr.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/display/d.vect/attr.c b/display/d.vect/attr.c index 5a28807cbca..747b98c59af 100644 --- a/display/d.vect/attr.c +++ b/display/d.vect/attr.c @@ -35,9 +35,11 @@ int display_attr(struct Map_info *Map, int type, char *attrcol, db_init_string(&text); fi = Vect_get_field(Map, lattr->field); - if (fi == NULL) + if (fi == NULL) { + Vect_destroy_line_struct(Points); + Vect_destroy_cats_struct(Cats); return 1; - + } driver = db_start_driver_open_database(fi->driver, fi->database); if (driver == NULL) G_fatal_error(_("Unable to open database <%s> by driver <%s>"), @@ -140,6 +142,7 @@ int display_attr(struct Map_info *Map, int type, char *attrcol, db_close_database_shutdown_driver(driver); Vect_destroy_line_struct(Points); Vect_destroy_cats_struct(Cats); + Vect_destroy_field_info(fi); return 0; } From 3c4aa6d499bb3cb82b29e302c7cdeb7e1706243c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 02:55:04 +0000 Subject: [PATCH 188/209] CI(deps): Lock file maintenance (#4509) --- flake.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index 51f61fb86f9..eacc92d3c4f 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1726153070, - "narHash": "sha256-HO4zgY0ekfwO5bX0QH/3kJ/h4KvUDFZg8YpkNwIbg1U=", + "lastModified": 1727826117, + "narHash": "sha256-K5ZLCyfO/Zj9mPFldf3iwS6oZStJcU4tSpiXTMYaaL0=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "bcef6817a8b2aa20a5a6dbb19b43e63c5bf8619a", + "rev": "3d04084d54bedc3d6b8b736c70ef449225c361b1", "type": "github" }, "original": { @@ -19,11 +19,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1727648392, - "narHash": "sha256-VTlVv1nSxImFxY6RPQpNZxvEOQ0u5s1wBFDgixySNDo=", + "lastModified": 1728538411, + "narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "4e0c36e4dd53f35d5a6385bdae88895ec5832f70", + "rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221", "type": "github" }, "original": { @@ -35,14 +35,14 @@ }, "nixpkgs-lib": { "locked": { - "lastModified": 1725233747, - "narHash": "sha256-Ss8QWLXdr2JCBPcYChJhz4xJm+h/xjl4G0c0XlP6a74=", + "lastModified": 1727825735, + "narHash": "sha256-0xHYkMkeLVQAMa7gvkddbPqpxph+hDzdu1XdGPJR+Os=", "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/356624c12086a18f2ea2825fed34523d60ccc4e3.tar.gz" + "url": "https://github.com/NixOS/nixpkgs/archive/fb192fec7cc7a4c26d51779e9bab07ce6fa5597a.tar.gz" }, "original": { "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/356624c12086a18f2ea2825fed34523d60ccc4e3.tar.gz" + "url": "https://github.com/NixOS/nixpkgs/archive/fb192fec7cc7a4c26d51779e9bab07ce6fa5597a.tar.gz" } }, "root": { From cb7cbab7e72f1d49bd3a761d1b0da2ee1b101646 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 04:15:36 +0000 Subject: [PATCH 189/209] CI(deps): Lock file maintenance (#4510) From ed02be59ff4129bbc3bd9fbb7545b7b73648be99 Mon Sep 17 00:00:00 2001 From: Mohan Yelugoti Date: Mon, 14 Oct 2024 07:54:32 -0400 Subject: [PATCH 190/209] ps.map: initialize variable contents before using them in get_ll_bounds (#4501) In some situations, when some conditionals fails, we would be assigning uninitialized variables to values, which is undefined behavior. Fix that by assigning a value to the variables. This was found using cppcheck tool. Signed-off-by: Mohan Yelugoti --- ps/ps.map/do_geogrid.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ps/ps.map/do_geogrid.c b/ps/ps.map/do_geogrid.c index 0fac5f80cac..c22ef86379c 100644 --- a/ps/ps.map/do_geogrid.c +++ b/ps/ps.map/do_geogrid.c @@ -300,6 +300,7 @@ void get_ll_bounds(double *w, double *e, double *s, double *n) double ew, ns; int first; + east = west = north = south = 0.0; e1 = PS.w.east; w1 = PS.w.west; n1 = PS.w.north; From b5289ee0c71b666e8e1969cca07474298f44eded Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 14 Oct 2024 07:58:03 -0400 Subject: [PATCH 191/209] r.carve: Fix resource leak issue in enforce_ds.c (#4505) --- raster/r.carve/enforce_ds.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/raster/r.carve/enforce_ds.c b/raster/r.carve/enforce_ds.c index ea4d7a1ae7a..7a71dc97def 100644 --- a/raster/r.carve/enforce_ds.c +++ b/raster/r.carve/enforce_ds.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "enforce.h" #ifndef MAX @@ -487,4 +488,6 @@ static void process_line_segment(const int npts, void *rbuf, Point2 *pgxypts, prevrow = row; prevcol = col; } + Vect_destroy_line_struct(points); + Vect_destroy_cats_struct(cats); } From e139a4c0fd246bda49a9aff780a6f737306e3358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Mon, 14 Oct 2024 13:06:14 -0400 Subject: [PATCH 192/209] gui: Solve a recursion error in gui/wxpython/lmgr/giface.py (#4514) --- gui/wxpython/lmgr/giface.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gui/wxpython/lmgr/giface.py b/gui/wxpython/lmgr/giface.py index eac9a7fb2d8..67669039d5d 100644 --- a/gui/wxpython/lmgr/giface.py +++ b/gui/wxpython/lmgr/giface.py @@ -54,7 +54,9 @@ def __init__(self, tree): self._tree = tree def __len__(self): - return len(list(self)) + # The list constructor calls __len__ as an optimization if available, + # causing a RecursionError + return len([layer for layer in self]) # noqa: C416 def __iter__(self): """Iterates over the contents of the list.""" From 61b380f1c4e3163d67961448553a091642c27eda Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Mon, 14 Oct 2024 20:11:42 +0200 Subject: [PATCH 193/209] r.mask.status: fix null pointer dereference and false positive string overflow (#4512) Fixes two new issues reported by Coverity Scan: - Handles case of unsuccessful creation of json string - Silences false positive issue for string copy operation to buffer of size GMAPSET_MAX from G_mapset(). --- lib/raster/mask_info.c | 2 +- raster/r.mask.status/main.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/raster/mask_info.c b/lib/raster/mask_info.c index 42102de86dd..317bab75b63 100644 --- a/lib/raster/mask_info.c +++ b/lib/raster/mask_info.c @@ -124,7 +124,7 @@ int Rast__mask_info(char *name, char *mapset) char rname[GNAME_MAX], rmapset[GMAPSET_MAX]; strcpy(rname, "MASK"); - strcpy(rmapset, G_mapset()); + (void)G_strlcpy(rmapset, G_mapset(), GMAPSET_MAX); if (!G_find_raster(rname, rmapset)) return -1; diff --git a/raster/r.mask.status/main.c b/raster/r.mask.status/main.c index 5eb32300240..16790adf35c 100644 --- a/raster/r.mask.status/main.c +++ b/raster/r.mask.status/main.c @@ -109,6 +109,8 @@ int report_status(struct Parameters *params) else json_object_set_null(root_object, "is_reclass_of"); char *serialized_string = json_serialize_to_string_pretty(root_value); + if (!serialized_string) + G_fatal_error(_("Failed to initialize pretty JSON string.")); puts(serialized_string); json_free_serialized_string(serialized_string); json_value_free(root_value); From 761d98a78010e34daa1d217fef433d04020ab82f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:30:57 -0400 Subject: [PATCH 194/209] style: Ignore deprecated PT004 rule (#4520) Ruff rule PT004 is deprecated, so doesn't run with --preview flag, but still appears without the --preview flag. Since the only error won't be fixed, ignore that rule for the time being. --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 6147e2db897..2a2287aaaad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -176,6 +176,7 @@ ignore = [ "PLW1641", # eq-without-hash "PLW2901", # redefined-loop-name "PLW3201", # bad-dunder-method-name + "PT004", # pytest-missing-fixture-name-underscore # deprecated, so doesn't appear with --preview "PTH100", # os-path-abspath "PTH101", # os-chmod "PTH102", # os-mkdir From 3a9059b7e7bec4a302cf6455c65fbd7fea3f2f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:27:05 -0400 Subject: [PATCH 195/209] pytest: Collect code coverage in multiple workers too (#4451) * pytest: Collect code coverage in multiple workers too * utils: Handle paths that already have a .py extension in coverage_mapper * CI: Set INITIAL_GISBASE and INITIAL_PWD env vars for running pytest with multiple workers * Coverage: Omit gui/wxpython subfolders for now They are not covered at all and take some noticeable time to collect * Coverage: Remove unneeded omit patten for gui/wxpython subfolders --- .coveragerc | 1 + .github/workflows/pytest.yml | 11 +++++++++-- utils/coverage_mapper.py | 6 ++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.coveragerc b/.coveragerc index 65e13c2234b..409fde55643 100644 --- a/.coveragerc +++ b/.coveragerc @@ -9,6 +9,7 @@ omit = ${INITIAL_PWD-.}/.github/* ${INITIAL_PWD-.}/bin.*/* ${INITIAL_PWD-.}/dist.*/* + **/gui/wxpython/*/** **/OBJ.*/* source = . diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index f2a96cf41ba..e1b3b84b54e 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -83,8 +83,13 @@ jobs: run: | export PYTHONPATH=`grass --config python_path`:$PYTHONPATH export LD_LIBRARY_PATH=$(grass --config path)/lib:$LD_LIBRARY_PATH + export INITIAL_GISBASE="$(grass --config path)" + export INITIAL_PWD="${PWD}" pytest --verbose --color=yes --durations=0 --durations-min=0.5 \ - --numprocesses auto -ra . \ + --numprocesses auto \ + --cov \ + --cov-context=test \ + -ra . \ -m 'not needs_solo_run' - name: Run pytest with a single worker (for tests marked with needs_solo_run) @@ -92,9 +97,11 @@ jobs: export PYTHONPATH=`grass --config python_path`:$PYTHONPATH export LD_LIBRARY_PATH=$(grass --config path)/lib:$LD_LIBRARY_PATH export INITIAL_GISBASE="$(grass --config path)" - INITIAL_PWD="${PWD}" pytest --verbose --color=yes --durations=0 --durations-min=0.5 \ + export INITIAL_PWD="${PWD}" + pytest --verbose --color=yes --durations=0 --durations-min=0.5 \ --cov \ --cov-context=test \ + --cov-append \ -ra . \ -m 'needs_solo_run' - name: Fix non-standard installed script paths in coverage data diff --git a/utils/coverage_mapper.py b/utils/coverage_mapper.py index 9a2f1389781..88fa30f9b54 100644 --- a/utils/coverage_mapper.py +++ b/utils/coverage_mapper.py @@ -22,12 +22,14 @@ def map_scripts_paths(old_path): if INITIAL_GISBASE is None or INITIAL_PWD is None: return old_path p = Path(old_path) + extension = ".py" + p_name = p.stem if p.suffix == extension else p.name temporal_base = Path(INITIAL_GISBASE) / "scripts" / "t.*" base = Path(INITIAL_GISBASE) / "scripts" / "*" if p.match(str(temporal_base)): - return str(Path(INITIAL_PWD) / "temporal" / (p.name) / (p.name)) + ".py" + return str(Path(INITIAL_PWD) / "temporal" / (p_name) / (p_name)) + extension if p.match(str(base)): - return str(Path(INITIAL_PWD) / "scripts" / (p.name) / (p.name)) + ".py" + return str(Path(INITIAL_PWD) / "scripts" / (p_name) / (p_name)) + extension return old_path From a98691f4eff03bb36ac6cd14058eab6edeace742 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 14 Oct 2024 17:02:46 -0400 Subject: [PATCH 196/209] v.net.timetable: Fix Resource Leak issue in main.c (#4508) * Fix Resource Leak issue * requested changes --- vector/v.net.timetable/main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vector/v.net.timetable/main.c b/vector/v.net.timetable/main.c index 5fb382009bb..424d8a851bd 100644 --- a/vector/v.net.timetable/main.c +++ b/vector/v.net.timetable/main.c @@ -176,9 +176,7 @@ void write_subroute(struct segment *seg, struct line_pnts *line, int line_id) struct line_cats *Cats; struct ilist *list; - Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); - list = Vect_new_list(); r = seg->route; Vect_cat_set(Cats, 2, line_id); @@ -188,6 +186,9 @@ void write_subroute(struct segment *seg, struct line_pnts *line, int line_id) return; } + Points = Vect_new_line_struct(); + list = Vect_new_list(); + for (i = 0; i < nnodes; i++) edges[i] = 0; for (i = 0; i < lines[r]->n_values; i++) From f241532c70217d27955cdd0677d6e9cede697605 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 14 Oct 2024 21:46:30 -0400 Subject: [PATCH 197/209] v.kernel: Fix resource Leak issue in main.c (#4506) Resource Leak --- vector/v.kernel/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vector/v.kernel/main.c b/vector/v.kernel/main.c index 96198a4d8f7..c1e7f77a36a 100644 --- a/vector/v.kernel/main.c +++ b/vector/v.kernel/main.c @@ -769,7 +769,9 @@ double compute_all_net_distances(struct Map_info *In, struct Map_info *Net, G_debug(3, " kk = %d", kk); } } - + Vect_destroy_line_struct(APoints); + Vect_destroy_line_struct(BPoints); + Vect_destroy_boxlist(List); return (kk); } From c5c5ec5f51d1e8fe503a3b80f5778ebc80be7efe Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Tue, 15 Oct 2024 04:25:27 -0400 Subject: [PATCH 198/209] lib/vector/Vlib: Fix Resource leak issue in geos.c (#4507) --- lib/vector/Vlib/geos.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/vector/Vlib/geos.c b/lib/vector/Vlib/geos.c index 719e0fdd270..2c68a0a6fba 100644 --- a/lib/vector/Vlib/geos.c +++ b/lib/vector/Vlib/geos.c @@ -290,7 +290,7 @@ GEOSCoordSequence *V1_read_line_geos(struct Map_info *Map, long offset, long size; double *x, *y, *z; - GEOSCoordSequence *pseq; + GEOSCoordSequence *pseq = NULL; G_debug(3, "V1_read_line_geos(): offset = %ld", offset); @@ -353,8 +353,6 @@ GEOSCoordSequence *V1_read_line_geos(struct Map_info *Map, long offset, G_debug(3, " n_points = %d dim = %d", n_points, (Map->head.with_z) ? 3 : 2); - pseq = GEOSCoordSeq_create(n_points, (Map->head.with_z) ? 3 : 2); - x = (double *)G_malloc(n_points * sizeof(double)); y = (double *)G_malloc(n_points * sizeof(double)); if (Map->head.with_z) @@ -362,17 +360,22 @@ GEOSCoordSequence *V1_read_line_geos(struct Map_info *Map, long offset, else z = NULL; - if (0 >= dig__fread_port_D(x, n_points, &(Map->dig_fp))) - return NULL; /* end of file */ + if (0 >= dig__fread_port_D(x, n_points, &(Map->dig_fp))) { + goto free_return; /* end of file */ + } - if (0 >= dig__fread_port_D(y, n_points, &(Map->dig_fp))) - return NULL; /* end of file */ + if (0 >= dig__fread_port_D(y, n_points, &(Map->dig_fp))) { + goto free_return; /* end of file */ + } if (Map->head.with_z) { - if (0 >= dig__fread_port_D(z, n_points, &(Map->dig_fp))) - return NULL; /* end of file */ + if (0 >= dig__fread_port_D(z, n_points, &(Map->dig_fp))) { + goto free_return; /* end of file */ + } } + pseq = GEOSCoordSeq_create(n_points, (Map->head.with_z) ? 3 : 2); + for (i = 0; i < n_points; i++) { GEOSCoordSeq_setX(pseq, i, x[i]); GEOSCoordSeq_setY(pseq, i, y[i]); @@ -382,6 +385,7 @@ GEOSCoordSequence *V1_read_line_geos(struct Map_info *Map, long offset, G_debug(3, " off = %ld", (long)dig_ftell(&(Map->dig_fp))); +free_return: G_free((void *)x); G_free((void *)y); if (z) From 15c5737dc601fbe71ab2bb614f14634ad17ddce0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 07:19:47 -0400 Subject: [PATCH 199/209] CI(deps): Update github/codeql-action action to v3.26.13 (#4518) --- .github/workflows/codeql-analysis.yml | 4 ++-- .github/workflows/python-code-quality.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 88158341f13..6672287794c 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -56,7 +56,7 @@ jobs: if: ${{ matrix.language == 'c-cpp' }} - name: Initialize CodeQL - uses: github/codeql-action/init@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 + uses: github/codeql-action/init@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -81,6 +81,6 @@ jobs: run: .github/workflows/build_ubuntu-22.04.sh "${HOME}/install" - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 + uses: github/codeql-action/analyze@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index b8b423b2b16..886cbe56b47 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -135,7 +135,7 @@ jobs: path: bandit.sarif - name: Upload SARIF File into Security Tab - uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 + uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 with: sarif_file: bandit.sarif From ca171b7e53a5ae075fe4857cb8bbdcb7f764d061 Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Tue, 15 Oct 2024 13:29:47 +0200 Subject: [PATCH 200/209] tests: enable use of md5 bin for checksum in raster_md5test.sh (#4527) Makes the script runnable on e.g. BSD platforms, which does not ship with md5sum. In addition fixes shellcheck warnings. --- testsuite/raster/raster_md5test.sh | 52 ++++++++++++++++-------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/testsuite/raster/raster_md5test.sh b/testsuite/raster/raster_md5test.sh index 0bda0c3428c..b3281d4c505 100755 --- a/testsuite/raster/raster_md5test.sh +++ b/testsuite/raster/raster_md5test.sh @@ -14,19 +14,23 @@ if [ -z "$GISBASE" ] ; then fi #### check if we have sed -if [ ! -x "`which sed`" ] ; then +if [ ! -x "$(which sed)" ] ; then echo "$PROG: sed required, please install first" 1>&2 exit 1 fi -#### check if we have md5sum -if [ ! -x "`which md5sum`" ] ; then - echo "$PROG: md5sum required, please install first" 1>&2 - exit 1 +#### check if we have md5sum or md5 +if [ -x "$(which md5sum)" ] ; then + MD5="md5sum | cut -d' ' -f1" +elif [ -x "$(which md5)" ] ; then + MD5="md5 -q" +else + echo "$PROG: md5sum or md5 required, please install first" 1>&2 + exit 1 fi #### check if we have cut -if [ ! -x "`which cut`" ] ; then +if [ ! -x "$(which cut)" ] ; then echo "$PROG: cut required, please install first" 1>&2 exit 1 fi @@ -38,47 +42,47 @@ export LC_NUMERIC=C # enforce ZLIB export GRASS_COMPRESSOR=ZLIB -eval `g.gisenv` -: ${GISBASE?} ${GISDBASE?} ${LOCATION_NAME?} ${MAPSET?} +eval "$(g.gisenv)" +: "${GISBASE?}" "${GISDBASE?}" "${LOCATION_NAME?}" "${MAPSET?}" MAPSET_PATH=$GISDBASE/$LOCATION_NAME/$MAPSET # some definitions PIXEL=3 PID=$$ -TMPNAME="`echo ${PID}_tmp_testmap | sed 's+\.+_+g'`" +TMPNAME=$(echo ${PID}_tmp_testmap | sed 's+\.+_+g') # some functions - keep order here cleanup() { echo "Removing temporary map" - g.remove -f type=raster name=$TMPNAME > /dev/null + g.remove -f type=raster name="$TMPNAME" > /dev/null } # check if a MASK is already present: -MASKTMP=mask.$TMPNAME -USERMASK=usermask_${MASKTMP} -if test -f $MAPSET_PATH/cell/MASK +MASKTMP="mask.${TMPNAME}" +USERMASK="usermask_${MASKTMP}" +if test -f "${MAPSET_PATH}/cell/MASK" then echo "A user raster mask (MASK) is present. Saving it..." - g.rename raster=MASK,$USERMASK > /dev/null + g.rename raster=MASK,"$USERMASK" > /dev/null fi finalcleanup() { echo "Restoring user region" - g.region region=$TMPNAME - g.remove -f type=region name=$TMPNAME > /dev/null + g.region region="$TMPNAME" + g.remove -f type=region name="$TMPNAME" > /dev/null #restore user mask if present: - if test -f $MAPSET_PATH/cell/$USERMASK ; then + if test -f "${MAPSET_PATH}/cell/${USERMASK}" ; then echo "Restoring user MASK" g.remove -f type=raster name=MASK > /dev/null - g.rename raster=$USERMASK,MASK > /dev/null + g.rename raster="$USERMASK",MASK > /dev/null fi } check_exit_status() { - if [ $1 -ne 0 ] ; then + if [ "$1" -ne 0 ] ; then echo "An error occurred." cleanup ; finalcleanup exit 1 @@ -106,7 +110,7 @@ check_md5sum() } echo "Saving current & setting test region." -g.region save=$TMPNAME +g.region save="$TMPNAME" check_exit_status $? g.region s=0 n=$PIXEL w=0 e=$PIXEL res=1 tbres=1 check_exit_status $? @@ -118,8 +122,8 @@ r.mapcalc "$TMPNAME = 1" check_exit_status $? echo "MD5 checksum on output of INT/CELL test." -MD5="`r.out.ascii $TMPNAME precision=15 | md5sum | cut -d' ' -f1`" -check_md5sum "549e7dabe70df893803690571d2e1503" "$MD5" +SUM=$(r.out.ascii "$TMPNAME" precision=15 | eval "$MD5") +check_md5sum "549e7dabe70df893803690571d2e1503" "$SUM" cleanup echo "INT/CELL md5sum test successful" @@ -132,8 +136,8 @@ r.mapcalc "$TMPNAME = $VALUE" check_exit_status $? echo "MD5 checksum on output of FLOAT/FCELL test." -MD5="`r.out.ascii $TMPNAME precision=15 | md5sum | cut -d' ' -f1`" -check_md5sum "379f3d880b6d509051af6b4ccf470762" "$MD5" +SUM=$(r.out.ascii "$TMPNAME" precision=15 | eval "$MD5") +check_md5sum "379f3d880b6d509051af6b4ccf470762" "$SUM" cleanup echo "FLOAT/FCELL md5sum test successful" From f7d2ecfacca5f5bd9b0c0cd88752e7e0386b41d4 Mon Sep 17 00:00:00 2001 From: Markus Metz <33666869+metzm@users.noreply.github.com> Date: Tue, 15 Oct 2024 15:12:15 +0200 Subject: [PATCH 201/209] lib/vector/Vlib: always write out topo files in update mode (#3459) * Vlib: always write out topo files in update mode * delete support files only when closing * fix pygrass Vect_close --------- Co-authored-by: Huidae Cho --- lib/vector/Vlib/open.c | 1 + python/grass/pygrass/vector/abstract.py | 21 ++++++++------------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/lib/vector/Vlib/open.c b/lib/vector/Vlib/open.c index 501b31eb4cb..0008156c34a 100644 --- a/lib/vector/Vlib/open.c +++ b/lib/vector/Vlib/open.c @@ -572,6 +572,7 @@ int Vect__open_old(struct Map_info *Map, const char *name, const char *mapset, if (access(file_path, F_OK) == 0) /* fidx file exists? */ unlink(file_path); } + Map->support_updated = TRUE; } return level; diff --git a/python/grass/pygrass/vector/abstract.py b/python/grass/pygrass/vector/abstract.py index 6700dca8e4c..79307f0d354 100644 --- a/python/grass/pygrass/vector/abstract.py +++ b/python/grass/pygrass/vector/abstract.py @@ -457,14 +457,14 @@ def close(self, build=False): if hasattr(self, "table") and self.table is not None: self.table.conn.close() if self.is_open(): - if libvect.Vect_close(self.c_mapinfo) != 0: - str_err = "Error when trying to close the map with Vect_close" - raise GrassError(str_err) if ( self.c_mapinfo.contents.mode in {libvect.GV_MODE_RW, libvect.GV_MODE_WRITE} ) and build: self.build() + if libvect.Vect_close(self.c_mapinfo) != 0: + str_err = "Error when trying to close the map with Vect_close" + raise GrassError(str_err) def remove(self): """Remove vector map""" @@ -474,16 +474,11 @@ def remove(self): def build(self): """Close the vector map and build vector Topology""" - self.close() - libvect.Vect_set_open_level(1) - if libvect.Vect_open_old2(self.c_mapinfo, self.name, self.mapset, "0") != 1: - str_err = "Error when trying to open the vector map." - raise GrassError(str_err) - # Vect_build returns 1 on success and 0 on error (bool approach) - if libvect.Vect_build(self.c_mapinfo) != 1: - str_err = "Error when trying build topology with Vect_build" - raise GrassError(str_err) - libvect.Vect_close(self.c_mapinfo) + if self.is_open(): + # Vect_build returns 1 on success and 0 on error (bool approach) + if libvect.Vect_build(self.c_mapinfo) != 1: + str_err = "Error when trying build topology with Vect_build" + raise GrassError(str_err) if __name__ == "__main__": From c0c5380fb920042c9539490e21d30f9af2165b83 Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Tue, 15 Oct 2024 09:58:35 -0400 Subject: [PATCH 202/209] r.sim.water: fix logfile writing (#4522) --- raster/r.sim/r.sim.sediment/main.c | 2 ++ raster/r.sim/r.sim.water/main.c | 4 +++- raster/r.sim/simlib/hydro.c | 3 --- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/raster/r.sim/r.sim.sediment/main.c b/raster/r.sim/r.sim.sediment/main.c index dd082fe0f81..d0197c2abb1 100644 --- a/raster/r.sim/r.sim.sediment/main.c +++ b/raster/r.sim/r.sim.sediment/main.c @@ -417,6 +417,8 @@ int main(int argc, char *argv[]) G_message(_("Using metric conversion factor %f, step=%f"), wp.conv, wp.step); + wp.observation = parm.observation->answer; + wp.logfile = parm.logfile->answer; init_library_globals(&wp); if ((wp.tc == NULL) && (wp.et == NULL) && (wp.conc == NULL) && diff --git a/raster/r.sim/r.sim.water/main.c b/raster/r.sim/r.sim.water/main.c index 61f128f5504..209be3e33d9 100644 --- a/raster/r.sim/r.sim.water/main.c +++ b/raster/r.sim/r.sim.water/main.c @@ -220,7 +220,7 @@ int main(int argc, char *argv[]) parm.logfile->required = NO; parm.logfile->description = _("Name for sampling points output text file. For each observation " - "vector point the time series of sediment transport is stored."); + "vector point the time series of water discharge is stored."); parm.logfile->guisection = _("Output"); parm.nwalk = G_define_option(); @@ -525,6 +525,8 @@ int main(int argc, char *argv[]) G_message(_("Using metric conversion factor %f, step=%f"), wp.conv, wp.step); + wp.observation = parm.observation->answer; + wp.logfile = parm.logfile->answer; init_library_globals(&wp); if ((wp.depth == NULL) && (wp.disch == NULL) && (wp.err == NULL)) diff --git a/raster/r.sim/simlib/hydro.c b/raster/r.sim/simlib/hydro.c index 74145ec9bff..eb7649763e9 100644 --- a/raster/r.sim/simlib/hydro.c +++ b/raster/r.sim/simlib/hydro.c @@ -151,9 +151,6 @@ void main_loop(void) maxwa = maxwa / nblock; } - /* Create the observation points */ - create_observation_points(); - G_debug(2, " maxwa, nblock %d %d", maxwa, nblock); for (iblock = 1; iblock <= nblock; iblock++) { From f22c9a2767960598ba99113eff595fda43bbfb8d Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Tue, 15 Oct 2024 10:02:36 -0400 Subject: [PATCH 203/209] doc: Use lowercase for 2D raster mask and other masks (#4495) Similarly to #4401, this replaces usage of MASK by mask on additional places. It also improves wording of a warning in i.fft. --- imagery/i.fft/main.c | 5 +++-- imagery/i.pca/i.pca.html | 2 +- lib/ogsf/gk.c | 4 ++-- lib/ogsf/gvd.c | 2 +- raster/r.fill.dir/r.fill.dir.html | 8 ++++---- raster/r.li/TODO | 7 ++++--- raster/r.univar/r.univar.html | 2 +- 7 files changed, 16 insertions(+), 14 deletions(-) diff --git a/imagery/i.fft/main.c b/imagery/i.fft/main.c index ad9a87a7890..051428b77ef 100644 --- a/imagery/i.fft/main.c +++ b/imagery/i.fft/main.c @@ -105,8 +105,9 @@ int main(int argc, char *argv[]) inputfd = Rast_open_old(Cellmap_orig, ""); if (Rast_maskfd() >= 0) - G_warning(_("Raster MASK found, consider to remove " - "(see man-page). Will continue...")); + G_warning(_("Raster mask active, consider removing it" + " and running again without it (see documentation for" + " details). This current process will now continue...")); G_get_set_window(&window); /* get the current window for later */ diff --git a/imagery/i.pca/i.pca.html b/imagery/i.pca/i.pca.html index 17b3f5ed163..6fee184c618 100644 --- a/imagery/i.pca/i.pca.html +++ b/imagery/i.pca/i.pca.html @@ -11,7 +11,7 @@

    DESCRIPTION

    principal component with the highest importance.

    -The current geographic region definition and MASK settings are +The current geographic region definition and raster mask settings are respected when reading the input raster map layers. When the rescale option is used, the output files are rescaled to fit the min,max range. diff --git a/lib/ogsf/gk.c b/lib/ogsf/gk.c index 3390598960a..b4fea635cc4 100644 --- a/lib/ogsf/gk.c +++ b/lib/ogsf/gk.c @@ -172,8 +172,8 @@ void gk_follow_frames(Viewnode *view, int numsteps, Keylist *keys, int step, GS_get_from(tmp); G_debug(3, "gk_follow_frames():"); - G_debug(3, " MASK: %lx", mask); - G_debug(3, " FROM: %f %f %f", tmp[X], tmp[Y], tmp[Z]); + G_debug(3, " mask: %lx", mask); + G_debug(3, " from: %f %f %f", tmp[X], tmp[Y], tmp[Z]); /* ACS 1 line: was GS_get_focus(tmp); with this kanimator works also for flythrough navigation diff --git a/lib/ogsf/gvd.c b/lib/ogsf/gvd.c index 6a6176526a2..84867123c5e 100644 --- a/lib/ogsf/gvd.c +++ b/lib/ogsf/gvd.c @@ -201,7 +201,7 @@ int gvd_vect(geovect *gv, geosurf *gs, int do_fast) } gsd_endline(); } - /* need to handle MASK! */ + /* need to handle mask! */ else if (src == CONST_ATT) { /* for now - but later, do seg intersect maskedge */ if (gs_point_is_masked(gs, bgn) || diff --git a/raster/r.fill.dir/r.fill.dir.html b/raster/r.fill.dir/r.fill.dir.html index 6ad8eb8019c..17173ea3dd3 100644 --- a/raster/r.fill.dir/r.fill.dir.html +++ b/raster/r.fill.dir/r.fill.dir.html @@ -69,11 +69,11 @@

    DESCRIPTION

    attributes required by other hydrological models.

    -As any GRASS GIS module, r.fill.dir is sensitive to the -computational region settings. Thus +As any GRASS GIS module, r.fill.dir respects the +computational region settings. Thus, the module can be used to generate a flow direction map for any -sub-area within the full map layer. Also, r.fill.dir is -sensitive to any raster MASK in effect. +sub-area within the full raster map layer. Also, r.fill.dir +will take into account an active raster mask.

    NOTES

    diff --git a/raster/r.li/TODO b/raster/r.li/TODO index 61ddd6b0941..382195402a6 100644 --- a/raster/r.li/TODO +++ b/raster/r.li/TODO @@ -24,12 +24,13 @@ d.vect forests type=boundary ######## TODO: CHECK THIS: -# MASK test -g.copy rast=fields,MASK +# Test with raster mask +r.mask raster=fields r.li.patchdensity forests conf=movwindow7 output=forests_p_dens7mask --o d.erase d.rast.leg forests_p_dens7mask -# -> no negative values! but MASK is respected +r.mask -r +# -> no negative values! but mask is respected # zero data test r.mapcalc "forests = 0" diff --git a/raster/r.univar/r.univar.html b/raster/r.univar/r.univar.html index 5220bc64a44..debde03a1d6 100644 --- a/raster/r.univar/r.univar.html +++ b/raster/r.univar/r.univar.html @@ -53,7 +53,7 @@

    PERFORMANCE

    r.univar supports parallel processing using OpenMP. The user can specify the number of threads to be used with the nprocs parameter. -However, parallelization is disabled when the MASK is set. +However, parallelization is disabled when the raster mask is set.

    Due to the differences in summation order, users may encounter small floating points From ec2bc8a7df27b1984c878b7a0a209bad9e977acd Mon Sep 17 00:00:00 2001 From: Mohan Yelugoti Date: Tue, 15 Oct 2024 11:35:11 -0400 Subject: [PATCH 204/209] r3.in.v5d: Prevent integer overflow by changing literal constant type on Cray (#4363) When the code is being compiled for CRAY HPC machines, a macro and a function to convert IEEE single precision floating point number to CRAY number are defined. To adjust the base, '16258' constant is being used, which according to C rules (C99, section 6.4.4.1, subsection semantics) fits into an integer. Right shifting that integer, which is of 32 bits, by 48 results in integer overflow. Avoid this by defining the literal constant with the long data type. This comes with an extended discussion in PR #4363 and an idea to remove the code completely. Signed-off-by: Mohan Yelugoti --- raster3d/r3.in.v5d/binio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/raster3d/r3.in.v5d/binio.c b/raster3d/r3.in.v5d/binio.c index f8582e97313..b47723a2929 100644 --- a/raster3d/r3.in.v5d/binio.c +++ b/raster3d/r3.in.v5d/binio.c @@ -147,7 +147,7 @@ static void if_to_c(long *t, const long *f) { if (*f != 0) { *t = (((*f & 0x8000000000000000) | - ((*f & 0x7f80000000000000) >> 7) + (16258 << 48)) | + ((*f & 0x7f80000000000000) >> 7) + (16258L << 48)) | (((*f & 0x007fffff00000000) >> 8) | (0x0000800000000000))); if ((*f << 1) == 0) *t = 0; @@ -160,7 +160,7 @@ static void if_to_c(long *t, const long *f) #define IF_TO_C(T, F) \ if (F != 0) { \ T = (((F & 0x8000000000000000) | \ - ((F & 0x7f80000000000000) >> 7) + (16258 << 48)) | \ + ((F & 0x7f80000000000000) >> 7) + (16258L << 48)) | \ (((F & 0x007fffff00000000) >> 8) | (0x0000800000000000))); \ if ((F << 1) == 0) \ T = 0; \ From 1adbd2ced8411fcc1e375ac6d6d124c419e497f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Tue, 15 Oct 2024 11:59:46 -0400 Subject: [PATCH 205/209] CI: Assign milestone on merged PRs (#4414) * CI: Create a workflow to assign milestones * Add GH_TOKEN for gh cli * CI: Add GH_REPO for gh cli * CI: View PR from gh cli using html_url * CI: Download and parse version file * CI: Show version file * CI: Download and parse version file using a pipe * Show version file output Clean up * Pipe version file env to head * Rename variables to milestone and title * Edit PR with milestone * Get milestone from gh cli * Add comment on why API call is used for getting milestone * Show if the PR has a milestone set or not * Do not run steps if a milestone is already set * Add pull_request_target closed trigger * Add ref as url parameter * Remove debugging steps * CI: Handle RC followed by numbers in sed pattern replacement --- .github/workflows/milestones.yml | 70 ++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 .github/workflows/milestones.yml diff --git a/.github/workflows/milestones.yml b/.github/workflows/milestones.yml new file mode 100644 index 00000000000..e2ade4eb091 --- /dev/null +++ b/.github/workflows/milestones.yml @@ -0,0 +1,70 @@ +--- +name: Assign Milestone + +on: + pull_request_target: + types: [closed] + +jobs: + assign-milestone: + runs-on: ubuntu-latest + if: github.event.pull_request.merged + steps: + # Retreiving the current milestoone from API instead of github context, + # so up-to-date information is used when running after being queued or for reruns + # Otherwise, the information should be available using + # ${{ github.event.pull_request.milestone.title }} + - name: Get current milestone title + id: current-milestone + run: | + echo "milestone<> "${GITHUB_OUTPUT}" + gh pr view ${{ github.event.pull_request.html_url }} --json milestone \ + --jq .milestone.title >> "${GITHUB_OUTPUT}" + echo 'EOF' >> "${GITHUB_OUTPUT}" + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + - name: PR already has a milestone + run: echo "PR already has a milestone" + if: ${{ steps.current-milestone.outputs.milestone }} + - name: PR does not have a milestone + run: echo "PR does not have a milestone" + if: ${{ !steps.current-milestone.outputs.milestone }} + - name: Get VERSION file + if: ${{ !steps.current-milestone.outputs.milestone }} + id: version-file + run: | + echo "version<> "${GITHUB_OUTPUT}" + gh api \ + -H "Accept: application/vnd.github.raw" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "/repos/{owner}/{repo}/contents/include/VERSION?ref=${{ github.sha }}" >> "${GITHUB_OUTPUT}" + echo "EOF" >> "${GITHUB_OUTPUT}" + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + - name: Show version file + if: ${{ !steps.current-milestone.outputs.milestone }} + run: echo "${VERSIONFILE}" + env: + VERSIONFILE: ${{ steps.version-file.outputs.version }} + - name: Get milestone title from VERSION file + if: ${{ !steps.current-milestone.outputs.milestone }} + id: milestone + run: | + version=$(echo "$VERSIONFILE" | head -n 3 | xargs | sed 's/ /./g; s/\(RC[0-9]*\|dev\)//g') + echo "title=$version" >> "${GITHUB_OUTPUT}" + env: + VERSIONFILE: ${{ steps.version-file.outputs.version }} + - name: Show milestone title + if: ${{ !steps.current-milestone.outputs.milestone }} + run: echo "${MILESTONE}" + env: + MILESTONE: ${{ steps.milestone.outputs.title }} + - name: Set PR milestone + if: ${{ !steps.current-milestone.outputs.milestone }} + run: gh pr edit ${{ github.event.pull_request.html_url }} --milestone "${MILESTONE}" + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + MILESTONE: ${{ steps.milestone.outputs.title }} From 9a79aa4a9a637b7467cdfd7e0b2a2193f623f8a5 Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Tue, 15 Oct 2024 19:09:57 -0400 Subject: [PATCH 206/209] tests: Revise content of the root testsuite dir (#4516) * Remove Makefiles. * Move the functioning test to the testsuite directory for the gunittest to pick it up. * Remove the extended example how to run gunittest. Point to the CI in the README instead. * Remove hemisphere generator because it does not test anything by itself (without further processing and a human). * Remove GPS import tests as the tools are not in core. * Remove division into subdirectories. The directories with the code should be used instead. * Improve the test for gunittest loader function with some duplication but now creating an overview of .py and .sh tests. --- python/grass/gunittest/loader.py | 16 +- testsuite/Makefile | 8 - testsuite/README.md | 44 +++--- .../test_framework_GRASS_GIS_with_NC.conf | 29 ---- .../test_framework_GRASS_GIS_with_NC.sh | 144 ------------------ testsuite/raster/Makefile | 3 - testsuite/raster/README | 1 - testsuite/raster/rhemisphere.sh | 48 ------ testsuite/{raster => }/raster_md5test.sh | 0 testsuite/vector/v.in.gps_test.sh | 26 ---- 10 files changed, 42 insertions(+), 277 deletions(-) delete mode 100644 testsuite/Makefile delete mode 100644 testsuite/examples/test_framework_GRASS_GIS_with_NC.conf delete mode 100755 testsuite/examples/test_framework_GRASS_GIS_with_NC.sh delete mode 100644 testsuite/raster/Makefile delete mode 100644 testsuite/raster/README delete mode 100755 testsuite/raster/rhemisphere.sh rename testsuite/{raster => }/raster_md5test.sh (100%) delete mode 100755 testsuite/vector/v.in.gps_test.sh diff --git a/python/grass/gunittest/loader.py b/python/grass/gunittest/loader.py index f01467ef1ba..50fa368f62a 100644 --- a/python/grass/gunittest/loader.py +++ b/python/grass/gunittest/loader.py @@ -235,4 +235,18 @@ def discover(self, start_dir, pattern="test*.py", top_level_dir=None): if __name__ == "__main__": - GrassTestLoader().discover() + for expression in [r".*\.py$", r".*\.sh$"]: + modules = discover_modules( + start_dir=".", + grass_location="all", + file_regexp=expression, + skip_dirs=GrassTestLoader.skip_dirs, + testsuite_dir=GrassTestLoader.testsuite_dir, + all_locations_value=GrassTestLoader.all_tests_value, + universal_location_value=GrassTestLoader.universal_tests_value, + import_modules=False, + exclude=None, + ) + print("Expression:", expression) + print(len(modules)) + print([module.file_path for module in modules]) diff --git a/testsuite/Makefile b/testsuite/Makefile deleted file mode 100644 index 7ed92b67442..00000000000 --- a/testsuite/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -MODULE_TOPDIR = .. - -SUBDIRS = \ - raster - -include $(MODULE_TOPDIR)/include/Make/Dir.make - -default: parsubdirs diff --git a/testsuite/README.md b/testsuite/README.md index 491fa4597af..36dda7d3da2 100644 --- a/testsuite/README.md +++ b/testsuite/README.md @@ -1,29 +1,39 @@ # Test suite -This directory contains scripts to check some functionality of GRASS GIS. +Tests are in directories `tests` and `testsuite` under each directory which has tests. +This directory contains additional scripts and information to test functionality +without a focus on a specific part of the code. -GRASS GIS testsuite documentation: +There are two testing mechanism in place, _pytest_ which is the modern way of testing +GRASS GIS. Tests using _pytest_ are written just as any other Python tests. -## Simple test data +In parallel, there is also custom unittest-based framework centered around +_grass.gunittest_ package. These tests run in the NC sample datasets and can be +executed using _pytest_ or directly. The unittest-based adds a number of custom +assert methods to accommodate different data and outputs typical in GRASS GIS. +_grass.gunittest_ documentation: + -Some tests may be launched in the location `../demolocation/`: +## Running tests + +Tests can be executed using _pytest_: ```bash -# create new mapset for test -grass ../demolocation/user1 -c -# run the test -make +# Setup the Python environment (if not set up already). +# Replace grass by path to the executable if not installed on path. +export PYTHONPATH=\$(grass --config python_path):\$PYTHONPATH +export LD_LIBRARY_PATH=\$(grass --config path)/lib:\$LD_LIBRARY_PATH +# Run the test. +pytest ``` -## Extended test data - -Most tests require the North Carolina Sample dataset, available from - +## Test data -## Notes +To test manually or to write tests, you may need to use the North Carolina +Sample dataset, available from +. -Since 2020: For a more advanced test suite, see - +## CI -Until 2019: For a more advanced test suite, see - +Most tests run in the CI. See the `.github` directory for details and +use it as a reference. diff --git a/testsuite/examples/test_framework_GRASS_GIS_with_NC.conf b/testsuite/examples/test_framework_GRASS_GIS_with_NC.conf deleted file mode 100644 index 6256108f6a8..00000000000 --- a/testsuite/examples/test_framework_GRASS_GIS_with_NC.conf +++ /dev/null @@ -1,29 +0,0 @@ -### CONFIGURATION -# -# name of binary: -GRASSBIN=grass -# source code directory as full path: -GRASSSRC="$(realpath ../../)" -# temporary grassdata directory -GRASSDATA="$HOME/grassdata" - -# leave 1 or more CPU free for other usage than testing -FREECPU=1 - -# Python binary to be used (python|python3) -PYTHON=python - -# here we suppose default compilation settings of GRASS GIS and no 'make install' -# may be no|yes -COMPILE="no" -# configure metascript with compiler flags: -CONFIGURE="${GRASSSRC}/conf_grass8.sh" - -# directory to store reports, e.g. in a subdirectory -REPORTS="testreports" - -# publish report on WWW Server (not needed for local tests) -# may be no|yes -PUBLISH="no" -# upload WWW dir on server for report publication (not used for local tests) -SERVERDIR="/var/www/html/grassgistestreports" diff --git a/testsuite/examples/test_framework_GRASS_GIS_with_NC.sh b/testsuite/examples/test_framework_GRASS_GIS_with_NC.sh deleted file mode 100755 index 808b4b9c716..00000000000 --- a/testsuite/examples/test_framework_GRASS_GIS_with_NC.sh +++ /dev/null @@ -1,144 +0,0 @@ -#!/bin/bash -############################################################################ -# -# MODULE: Example script to run testsuite -# AUTHOR(S): Markus Neteler, Sören Gebbert, Vaclav Petras -# PURPOSE: Test GRASS GIS using the test framework -# Documentation: -# https://trac.osgeo.org/grass/wiki/GSoC/2014/TestingFrameworkForGRASS -# https://grass.osgeo.org/grass-devel/manuals/libpython/gunittest_running_tests.html#example-bash-script-to-run-be-used-as-a-cron-job -# -# Data: -# We use the full NC dataset (nc_spm_full_v2_alpha.tar.gz) -# -# COPYRIGHT: (C) 2019-2021 by Markus Neteler, and the GRASS Development Team -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# 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. -# -############################################################################ - -### Fetch CONFIGURATION - -CONF="test_framework_GRASS_GIS_with_NC.conf" - -usage_msg(){ -echo "Usage: - $0 [conf_file] - -Example: - $0 ./${CONF} -" -} - -if [ ! -z "$1" ] ; then - case "$1" in - -h | --h | -help | --help) - usage_msg - exit 0 - ;; - *) - if [ -f ${1} ] ; then - CONF="$1" - else - echo "ERROR: $1 is not a file" - exit 1 - fi - ;; - esac -else - usage_msg - exit 0 -fi - -source ${CONF} - -######### nothing to change below - -set -e # fail fast - -# computer architecture: -ARCH=`${GRASSBIN} --config arch` - -# here we suppose default compilation settings of GRASS GIS and no make install -GRASSBIN="$GRASSSRC/bin.${ARCH}/${GRASSBIN}" -GRASSDIST="$GRASSSRC/dist.${ARCH}" - -# necessary hardcoded GRASS paths -GRASSDIST_PYTHON="$GRASSDIST/etc/python" -GRASS_MULTI_RUNNER="$GRASSSRC/python/grass/gunittest/multirunner.py" -GRASS_MULTI_REPORTER="$GRASSSRC/python/grass/gunittest/multireport.py" - -DATE_FLAGS="--utc +%Y-%m-%d-%H-%M" -NOW=$(date $DATE_FLAGS) - -# get number of processors of current machine -MYNPROC=`getconf _NPROCESSORS_ONLN` -# leave some free for other tasks -GCCTHREADS=`expr $MYNPROC - $FREECPU` -if [ $GCCTHREADS -lt 1 ] ; then - GCCTHREADS=1 -fi - -# contains last executed command stdout and stderr -# here were rely on reports being absolute -OUTPUT_LOGFILE="$REPORTS/output-$NOW.txt" - -# these are relative to REPORTS -CURRENT_REPORT_BASENAME="reports_for_date-" -FINAL_REPORT_DIR="summary_report" -CURRENT_REPORTS_DIR="$CURRENT_REPORT_BASENAME$NOW" -LOGFILE="$REPORTS/runs.log" - -mkdir -p $REPORTS/$CURRENT_REPORTS_DIR -mkdir -p $GRASSDATA - -# fetch sample data -SAMPLEDATA=nc_spm_full_v2alpha -(cd $GRASSDATA ; wget -c https://grass.osgeo.org/sampledata/north_carolina/$SAMPLEDATA.tar.gz ; tar xfz $SAMPLEDATA.tar.gz --strip-components 2) - -set -x - -echo "Testing of GRASS GIS started: $NOW" >> ${LOGFILE} - -if [ "$COMPILE" = "yes" ] ; then - ## compile current source code from scratch - cd $GRASSSRC - make distclean -j$GCCTHREADS - git pull - ./$CONFIGURE ... # configure meta script containing all the compiler flags - make -j$GCCTHREADS -fi - -# run tests for the current source code -cd $REPORTS/$CURRENT_REPORTS_DIR -$PYTHON $GRASS_MULTI_RUNNER \ - --grassbin $GRASSBIN \ - --grasssrc $GRASSSRC \ - --grassdata $GRASSDATA \ - --location $SAMPLEDATA --location-type nc # \ -# --location other_location --location-type other_type - -# create overall report of all so far executed tests -# the script depends on GRASS but just Python part is enough -export PYTHONPATH="$GRASSDIST_PYTHON:$PYTHONPATH" -$PYTHON $GRASS_MULTI_REPORTER --output $FINAL_REPORT_DIR \ - $CURRENT_REPORT_BASENAME*/* - -# publish on Web site -if [ "$PUBLISH" = "yes" ] ; then - ## although we cannot be sure the tests were executed was successfully - ## so publish or archive results - rsync -rtvu --delete $REPORTS/ $SERVERDIR -fi - -echo "Nightly ($NOW) GRASS GIS test finished: $(date $DATE_FLAGS)" >> ${LOGFILE} - -exit 0 diff --git a/testsuite/raster/Makefile b/testsuite/raster/Makefile deleted file mode 100644 index 21c1f8eb6c0..00000000000 --- a/testsuite/raster/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -all: - ./raster_md5test.sh - ./rmapcalc_test.sh diff --git a/testsuite/raster/README b/testsuite/raster/README deleted file mode 100644 index bc5b0940789..00000000000 --- a/testsuite/raster/README +++ /dev/null @@ -1 +0,0 @@ -Raster map tests go here diff --git a/testsuite/raster/rhemisphere.sh b/testsuite/raster/rhemisphere.sh deleted file mode 100755 index e312f7b36d1..00000000000 --- a/testsuite/raster/rhemisphere.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh - -# Markus Neteler, 2006 -# This program is free software under the GNU General Public -# License (>=v2). Read the file COPYING that comes with GRASS -# for details. -# Test cases for 2D raster data -# generate a hemisphere to test slope, aspect, curvatures - -# some definitions: -BOXLENGTH=1000 # side length of test area -RADIUS=500 # half BOXLENGTH - -############ - -if [ -z "$GISBASE" ] ; then - echo "You must be in GRASS GIS to run this program." >&2 - exit 1 -fi - -# some functions - keep order here -TMP="disk.$$" - -cleanup() -{ - echo "Removing temporary map" - g.remove --q -f type=raster name=$TMP > /dev/null -} - -######################## - -g.region n=$BOXLENGTH s=0 w=0 e=$BOXLENGTH -p res=1 - -X="(col() - $RADIUS)" -Y="($RADIUS - row())" -r="sqrt($X^2 + $Y^2)" - -#Mask out unwanted parts (check for <= ??): -r.mapcalc "$TMP = if($r<$RADIUS,$r,null())" - -ALPHA="acos ($TMP/$RADIUS)" -HEIGHT="$RADIUS * sin($ALPHA)" - - -r.mapcalc "hemisphere = $HEIGHT" -cleanup -g.message "Generated raster map " -#echo "Now generate aspect + slope on " diff --git a/testsuite/raster/raster_md5test.sh b/testsuite/raster_md5test.sh similarity index 100% rename from testsuite/raster/raster_md5test.sh rename to testsuite/raster_md5test.sh diff --git a/testsuite/vector/v.in.gps_test.sh b/testsuite/vector/v.in.gps_test.sh deleted file mode 100755 index 62b2f5b651c..00000000000 --- a/testsuite/vector/v.in.gps_test.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh -# v.in.garmin and v.in.gpsbabel test script -# by Hamish Bowman 18 May 2007 ; public domain -# assumes downloading from a garmin on port /dev/gps - -for PGM in garmin gpsbabel ; do - for DO_PTS in pts lines ; do - for TASK in w t r ; do - if [ $TASK = w ] && [ $DO_PTS = "lines" ] ; then - continue - fi - if [ $DO_PTS = "pts" ] ; then - PTFLAG="-p" - else - PTFLAG="" - fi - MAPNAME="test_${PGM}_${TASK}_${DO_PTS}_$$" - echo "-- Running [v.in.$PGM] for [$TASK] download as [$DO_PTS] into <$MAPNAME> --" - v.in.$PGM -$TASK $PTFLAG out="$MAPNAME" - if [ $? -ne 0 ] ; then - exit 1 - fi - awk 'BEGIN {printf("\n\n\n\n")}' - done - done -done From bc9cb2a3f9540b031a6b8e8e7d7257ca01492d3e Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Tue, 15 Oct 2024 19:17:08 -0400 Subject: [PATCH 207/209] doc: Use lowercase for mask (#4529) Again, use lowercase mask and other wording instead of MASK when talking about masking, similar to #4401 and #4495. It also adjusts the wording in r.topidx and i.segment. --- imagery/i.segment/i.segment.html | 2 +- imagery/i.segment/iseg.h | 2 +- ps/ps.map/r_instructions.c | 2 +- raster/r.resamp.interp/r.resamp.interp.html | 2 +- raster/r.topidx/r.topidx.html | 8 +++++--- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/imagery/i.segment/i.segment.html b/imagery/i.segment/i.segment.html index 1e2596c1d7e..e30f21d3743 100644 --- a/imagery/i.segment/i.segment.html +++ b/imagery/i.segment/i.segment.html @@ -118,7 +118,7 @@

    Mean shift

    Boundary Constraints

    Boundary constraints limit the adjacency of pixels and segments. Each unique value present in the bounds raster are -considered as a MASK. Thus no segments in the final segmentated map +considered as a mask. Thus, no segments in the final segmented map will cross a boundary, even if their spectral data is very similar.

    Minimum Segment Size

    diff --git a/imagery/i.segment/iseg.h b/imagery/i.segment/iseg.h index 1e301d2cefa..a8dfb5542c3 100644 --- a/imagery/i.segment/iseg.h +++ b/imagery/i.segment/iseg.h @@ -118,7 +118,7 @@ struct globals { /* processing flags */ FLAG *candidate_flag, - *null_flag; /*TODO, need some way to remember MASK/NULL values. Was + *null_flag; /*TODO, need some way to remember mask/NULL values. Was using -1, 0, 1 in int array. Better to use 2 FLAG structures, better readability? */ diff --git a/ps/ps.map/r_instructions.c b/ps/ps.map/r_instructions.c index 0e2c012fd92..87a2e4bbfcf 100644 --- a/ps/ps.map/r_instructions.c +++ b/ps/ps.map/r_instructions.c @@ -29,7 +29,7 @@ static char *help[] = { "read unix-file eps Encapsulated PostScript file", "border [y|n] mapinfo map information", "window region definition region region definition", - "maskcolor MASK color", + "maskcolor mask color", "rectangle east north east north", "scale 1:#|# inches|# panels|1 inch = # miles", "outline map composition outline", diff --git a/raster/r.resamp.interp/r.resamp.interp.html b/raster/r.resamp.interp/r.resamp.interp.html index e4b77ac0d34..3c3eecc68a9 100644 --- a/raster/r.resamp.interp/r.resamp.interp.html +++ b/raster/r.resamp.interp/r.resamp.interp.html @@ -28,7 +28,7 @@

    NOTES

    Note that for bilinear, bicubic and lanczos interpolation, cells of the output raster that cannot be bounded by the appropriate number of input cell centers are set to NULL (NULL propagation). This could occur -due to the input cells being outside the current region, being NULL or MASKed. +due to the input cells being outside the current region, being NULL or masked.

    For longitude-latitude coordinate reference systems, diff --git a/raster/r.topidx/r.topidx.html b/raster/r.topidx/r.topidx.html index 56dd001f20a..75938e6a231 100644 --- a/raster/r.topidx/r.topidx.html +++ b/raster/r.topidx/r.topidx.html @@ -10,12 +10,14 @@

    DESCRIPTION

    the local surface topographic slope (delta vertical) / (delta horizontal).
    -

    Input maps may have NULL values. For example, if you have a MASK for a -watershed (basin map from r.water.outlet), the following command will -create a masked elevation map (belev): +

    Input maps may have NULL values. For example, if you have a raster mask set +for a watershed (using basin map from r.water.outlet), the following +command will create a masked elevation map (belev): +

     r.mapcalc "belev = if(isnull(basin), basin, elev)"
     
    +

    r.stats -Anc prints out averaged statistics for topographic index. From 241589424d9612b913ef7f5502839ee6ab2151bc Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Wed, 16 Oct 2024 04:08:22 -0400 Subject: [PATCH 208/209] r.in.gridatb: check if opening of file succeeds (#4532) --- raster/r.in.gridatb/file_io.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/raster/r.in.gridatb/file_io.c b/raster/r.in.gridatb/file_io.c index 256f9869473..52ad174df4d 100644 --- a/raster/r.in.gridatb/file_io.c +++ b/raster/r.in.gridatb/file_io.c @@ -12,6 +12,9 @@ void rdwr_gridatb(void) float idx; fp = fopen(file, "r"); + if (!fp) { + G_fatal_error(_("Unable to open file: %s"), file); + } buf[0] = 0; if (fscanf(fp, "%[^\n]", buf) != 1) From 362bee3ae66cec995805e355bb40cffe75c838f7 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Wed, 16 Oct 2024 09:27:43 -0400 Subject: [PATCH 209/209] grass.script: Fixed E722 in v.what.shrds/ (#4530) --- .flake8 | 2 +- scripts/v.what.strds/v.what.strds.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.flake8 b/.flake8 index c01dc46b255..6bfcc1e5527 100644 --- a/.flake8 +++ b/.flake8 @@ -115,7 +115,7 @@ per-file-ignores = scripts/r.in.srtm/r.in.srtm.py: E722 scripts/r.fillnulls/r.fillnulls.py: E722 scripts/d.rast.edit/d.rast.edit.py: E722 - scripts/v.what.strds/v.what.strds.py: E722, E501 + scripts/v.what.strds/v.what.strds.py: E501 # Line too long (esp. module interface definitions) scripts/*/*.py: E501 temporal/t.rast.to.vect/t.rast.to.vect.py: E501 diff --git a/scripts/v.what.strds/v.what.strds.py b/scripts/v.what.strds/v.what.strds.py index 0e1bf893f98..8be00f3536d 100644 --- a/scripts/v.what.strds/v.what.strds.py +++ b/scripts/v.what.strds/v.what.strds.py @@ -225,7 +225,7 @@ def main(): pymap = Vector(output) try: pymap.open("r") - except: + except Exception: dbif.close() gs.fatal(_("Unable to create vector map <%s>") % output)