diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 31819c081aa..8c49211705f 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -38,7 +38,7 @@ jobs: # renovate: datasource=pypi depName=bandit BANDIT_VERSION: "1.8.2" # renovate: datasource=pypi depName=ruff - RUFF_VERSION: "0.9.2" + RUFF_VERSION: "0.9.3" runs-on: ${{ matrix.os }} permissions: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 49674d971cb..9834ad4f121 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.9.2 + rev: v0.9.3 hooks: # Run the linter. - id: ruff diff --git a/gui/wxpython/animation/controller.py b/gui/wxpython/animation/controller.py index 808e9b20ef4..6cf3269eeb1 100644 --- a/gui/wxpython/animation/controller.py +++ b/gui/wxpython/animation/controller.py @@ -36,7 +36,6 @@ HashCmds, ) from animation.data import AnimationData -from itertools import starmap class AnimationController(wx.EvtHandler): @@ -369,7 +368,7 @@ def _updateAnimations(self, activeIndices, mapNamesDict=None): if anim.viewMode == "3d": regions = [None] * len(regions) self.animations[i].SetFrames( - list(starmap(HashCmds, zip(anim.cmdMatrix, regions))) + list(map(HashCmds, anim.cmdMatrix, regions)) ) self.animations[i].SetActive(True) else: diff --git a/gui/wxpython/core/utils.py b/gui/wxpython/core/utils.py index 9ae88cb05a4..a1722fec64b 100644 --- a/gui/wxpython/core/utils.py +++ b/gui/wxpython/core/utils.py @@ -871,12 +871,10 @@ def StoreEnvVariable(key, value=None, envFile=None): return expCmd = "set" if windows else "export" - for key, value in environ.items(): - fd.write("%s %s=%s\n" % (expCmd, key, value)) + fd.writelines("%s %s=%s\n" % (expCmd, key, value) for key, value in environ.items()) # write also skipped lines - for line in lineSkipped: - fd.write(line + os.linesep) + fd.writelines(line + os.linesep for line in lineSkipped) fd.close() diff --git a/gui/wxpython/gcp/manager.py b/gui/wxpython/gcp/manager.py index 43bbfdc1b8e..ddeb19c7302 100644 --- a/gui/wxpython/gcp/manager.py +++ b/gui/wxpython/gcp/manager.py @@ -347,8 +347,9 @@ def SetSrcEnv(self, location, mapset): try: f = open(self.source_gisrc, mode="w") - for line in self.gisrc_dict.items(): - f.write(line[0] + ": " + line[1] + "\n") + f.writelines( + line[0] + ": " + line[1] + "\n" for line in self.gisrc_dict.items() + ) finally: f.close() @@ -2769,8 +2770,7 @@ def MakeVGroup(self): f = open(self.vgrpfile, mode="w") try: - for vect in vgrouplist: - f.write(vect + "\n") + f.writelines(vect + "\n" for vect in vgrouplist) finally: f.close() diff --git a/gui/wxpython/gmodeler/panels.py b/gui/wxpython/gmodeler/panels.py index fbdc2048620..e567706cd19 100644 --- a/gui/wxpython/gmodeler/panels.py +++ b/gui/wxpython/gmodeler/panels.py @@ -683,8 +683,7 @@ def WriteModelFile(self, filename): try: mfile = open(filename, "w") tmpfile.seek(0) - for line in tmpfile.readlines(): - mfile.write(line) + mfile.writelines(tmpfile.readlines()) except OSError: wx.MessageBox( parent=self, diff --git a/gui/wxpython/image2target/ii2t_manager.py b/gui/wxpython/image2target/ii2t_manager.py index 56adf91775b..a658897a5fb 100644 --- a/gui/wxpython/image2target/ii2t_manager.py +++ b/gui/wxpython/image2target/ii2t_manager.py @@ -364,8 +364,9 @@ def SetSrcEnv(self, location, mapset): try: f = open(self.source_gisrc, mode="w") - for line in self.gisrc_dict.items(): - f.write(line[0] + ": " + line[1] + "\n") + f.writelines( + line[0] + ": " + line[1] + "\n" for line in self.gisrc_dict.items() + ) finally: f.close() @@ -2709,8 +2710,7 @@ def MakeVGroup(self): f = open(self.vgrpfile, mode="w") try: - for vect in vgrouplist: - f.write(vect + "\n") + f.writelines(vect + "\n" for vect in vgrouplist) finally: f.close() diff --git a/gui/wxpython/lmgr/workspace.py b/gui/wxpython/lmgr/workspace.py index dd83c1a6f22..6bad27d7674 100644 --- a/gui/wxpython/lmgr/workspace.py +++ b/gui/wxpython/lmgr/workspace.py @@ -448,8 +448,7 @@ def SaveToFile(self, filename): try: mfile = open(filename, "wb") tmpfile.seek(0) - for line in tmpfile.readlines(): - mfile.write(line) + mfile.writelines(tmpfile.readlines()) except OSError: GError( parent=self.lmgr, diff --git a/gui/wxpython/mapwin/buffered.py b/gui/wxpython/mapwin/buffered.py index 7e42ebc57c9..fe2a5b0ae69 100644 --- a/gui/wxpython/mapwin/buffered.py +++ b/gui/wxpython/mapwin/buffered.py @@ -1542,8 +1542,6 @@ def OnLeftDown(self, event): if idlist != []: self.dragid = idlist[0] # drag whatever is on top - else: - pass coords = self.Pixel2Cell(self.mouse["begin"]) self.mouseLeftDown.emit(x=coords[0], y=coords[1]) @@ -1592,8 +1590,6 @@ def OnLeftUp(self, event): self.textdict[self.dragid]["bbox"] = self.pdc.GetIdBounds( self.dragid ) - else: - pass self.dragid = None self.mouseLeftUpPointer.emit(x=coordinates[0], y=coordinates[1]) diff --git a/gui/wxpython/photo2image/ip2i_manager.py b/gui/wxpython/photo2image/ip2i_manager.py index dc5713e961a..9f78d717fee 100644 --- a/gui/wxpython/photo2image/ip2i_manager.py +++ b/gui/wxpython/photo2image/ip2i_manager.py @@ -255,8 +255,9 @@ def SetSrcEnv(self, location, mapset): try: f = open(self.source_gisrc, mode="w") - for line in self.gisrc_dict.items(): - f.write(line[0] + ": " + line[1] + "\n") + f.writelines( + line[0] + ": " + line[1] + "\n" for line in self.gisrc_dict.items() + ) finally: f.close() diff --git a/gui/wxpython/wxplot/dialogs.py b/gui/wxpython/wxplot/dialogs.py index cdb74c64a9e..d1564d4fc8a 100755 --- a/gui/wxpython/wxplot/dialogs.py +++ b/gui/wxpython/wxplot/dialogs.py @@ -547,8 +547,6 @@ def OnHistMap(self, event): self.gselection.Enable() self.rselection.Disable() self.rselection.SetValue("") - else: - pass def OnRasterSelection(self, event): """Handler for selecting a single raster map""" diff --git a/gui/wxpython/wxplot/profile.py b/gui/wxpython/wxplot/profile.py index e0994f1a8a5..5b63f3cabab 100644 --- a/gui/wxpython/wxplot/profile.py +++ b/gui/wxpython/wxplot/profile.py @@ -446,8 +446,10 @@ def SaveProfileToFile(self, event): dlg.Destroy() return - for datapair in self.raster[r]["datalist"]: - fd.write("%.6f,%.6f\n" % (float(datapair[0]), float(datapair[1]))) + fd.writelines( + "%.6f,%.6f\n" % (float(datapair[0]), float(datapair[1])) + for datapair in self.raster[r]["datalist"] + ) fd.close() diff --git a/lib/gis/testsuite/test_gis_lib_getl.py b/lib/gis/testsuite/test_gis_lib_getl.py index 1ac9907f3d9..dec5c0b40a2 100644 --- a/lib/gis/testsuite/test_gis_lib_getl.py +++ b/lib/gis/testsuite/test_gis_lib_getl.py @@ -29,10 +29,9 @@ 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") + # Python text newline here. + # The specific newline is added by the stream. + stream.writelines(f"{line}\n" for line in lines) file_ptr = self.libc.fopen(str(self.file_path).encode("utf-8"), b"r") if not file_ptr: diff --git a/lib/init/grass.py b/lib/init/grass.py index c2ac803e6a2..befec465b3a 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -525,8 +525,7 @@ def write_gisrcrc(gisrcrc, gisrc, skip_variable=None): del lines[number] number += 1 with open(gisrcrc, "w") as f: - for line in lines: - f.write(line) + f.writelines(lines) def read_env_file(path): @@ -543,8 +542,7 @@ def write_gisrc(kv, filename, append=False): # use append=True to avoid a race condition between write_gisrc() and # grass_prompt() on startup (PR #548) f = open(filename, "a" if append else "w") - for k, v in kv.items(): - f.write("%s: %s\n" % (k, v)) + f.writelines("%s: %s\n" % (k, v) for k, v in kv.items()) f.close() diff --git a/python/grass/gunittest/multireport.py b/python/grass/gunittest/multireport.py index 5a0350f1786..9deb0528ada 100644 --- a/python/grass/gunittest/multireport.py +++ b/python/grass/gunittest/multireport.py @@ -413,13 +413,13 @@ def main_page( ) ) page.write("") - for image, caption in itertools.izip(images, captions): - page.write( - "

{caption}

" - '{caption}'.format( - image=image, caption=caption - ) + page.writelines( + "

{caption}

" + '{caption}'.format( + image=image, caption=caption ) + for image, caption in itertools.izip(images, captions) + ) page.write("") diff --git a/python/grass/gunittest/reporters.py b/python/grass/gunittest/reporters.py index 6302c8e2248..d6ff1669bbc 100644 --- a/python/grass/gunittest/reporters.py +++ b/python/grass/gunittest/reporters.py @@ -52,8 +52,9 @@ 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) 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)) + new_file.writelines( + re.sub(pattern=pattern, string=line, repl=repl) for line in old_file + ) # remove old file since it must not exist for rename/move os.remove(file_path) # replace old file by new file @@ -448,8 +449,7 @@ def wrap_stdstream_to_html(infile, outfile, module, stream): after = "" 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.writelines(color_error_line(html_escape(line)) for line in text) html.write(after) @@ -795,8 +795,10 @@ def end_file_test( file_index.write(files_section) if supplementary_files: - for f in supplementary_files: - file_index.write('
  • {f}
  • '.format(f=f)) + file_index.writelines( + '
  • {f}
  • '.format(f=f) + for f in supplementary_files + ) file_index.write("") diff --git a/python/grass/gunittest/testsuite/test_checkers.py b/python/grass/gunittest/testsuite/test_checkers.py index b11b25778a3..f79598aa165 100644 --- a/python/grass/gunittest/testsuite/test_checkers.py +++ b/python/grass/gunittest/testsuite/test_checkers.py @@ -369,17 +369,14 @@ class TestMd5Sums(TestCase): @classmethod def setUpClass(cls): with open(cls.correct_file_name_platform_nl, "w") as f: - for line in CORRECT_LINES: - # \n should be converted to platform newline - f.write(line + "\n") + # \n should be converted to platform newline + f.writelines(line + "\n" for line in CORRECT_LINES) with open(cls.correct_file_name_unix_nl, "w") as f: - for line in CORRECT_LINES: - # binary mode will write pure \n - f.write(line + "\n") + # binary mode will write pure \n + f.writelines(line + "\n" for line in CORRECT_LINES) with open(cls.wrong_file_name, "w") as f: - for line in INCORRECT_LINES: - # \n should be converted to platform newline - f.write(line + "\n") + # \n should be converted to platform newline + f.writelines(line + "\n" for line in INCORRECT_LINES) @classmethod def tearDownClass(cls): diff --git a/python/grass/jupyter/timeseriesmap.py b/python/grass/jupyter/timeseriesmap.py index 0379e19a4c0..5d32cc83e93 100644 --- a/python/grass/jupyter/timeseriesmap.py +++ b/python/grass/jupyter/timeseriesmap.py @@ -28,8 +28,6 @@ def fill_none_values(names): for i, name in enumerate(names): if name == "None": names[i] = names[i - 1] - else: - pass return names diff --git a/raster/r.topidx/gridatb_to_arc.py b/raster/r.topidx/gridatb_to_arc.py index d80f6797a65..351cb07afad 100755 --- a/raster/r.topidx/gridatb_to_arc.py +++ b/raster/r.topidx/gridatb_to_arc.py @@ -54,8 +54,7 @@ NODATA_value 9999 """ ) -for inline in inf: - outf.write(inline) +outf.writelines(inf) inf.close() outf.close() diff --git a/scripts/d.polar/d.polar.py b/scripts/d.polar/d.polar.py index d7e67486a0e..2d5f6d50a7b 100755 --- a/scripts/d.polar/d.polar.py +++ b/scripts/d.polar/d.polar.py @@ -283,10 +283,10 @@ def plot_eps(psout): (x, y) = outercircle[1] outf.write("%.2f %.2f moveto\n" % (x * scale + halfframe, y * scale + halfframe)) - for x, y in outercircle[2:]: - outf.write( - "%.2f %.2f lineto\n" % (x * scale + halfframe, y * scale + halfframe) - ) + outf.writelines( + "%.2f %.2f lineto\n" % (x * scale + halfframe, y * scale + halfframe) + for x, y in outercircle[2:] + ) t = string.Template( """ @@ -338,10 +338,10 @@ def plot_eps(psout): (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:]: - outf.write( - "%.2f %.2f lineto\n" % (x * scale + halfframe, y * scale + halfframe) - ) + outf.writelines( + "%.2f %.2f lineto\n" % (x * scale + halfframe, y * scale + halfframe) + for x, y in sine_cosine_replic[2:] + ) t = string.Template( """ @@ -363,10 +363,10 @@ def plot_eps(psout): (x, y) = vector[1] outf.write("%.2f %.2f moveto\n" % (x * scale + halfframe, y * scale + halfframe)) - for x, y in vector[2:]: - outf.write( - "%.2f %.2f lineto\n" % (x * scale + halfframe, y * scale + halfframe) - ) + outf.writelines( + "%.2f %.2f lineto\n" % (x * scale + halfframe, y * scale + halfframe) + for x, y in vector[2:] + ) t = string.Template( """ diff --git a/scripts/db.univar/db.univar.py b/scripts/db.univar/db.univar.py index 859e0fd831c..3969d4f7caf 100755 --- a/scripts/db.univar/db.univar.py +++ b/scripts/db.univar/db.univar.py @@ -89,8 +89,7 @@ def sortfile(infile, outfile): for i in range(len(lines)): lines[i] = float(lines[i].rstrip("\r\n")) lines.sort() - for line in lines: - outf.write(str(line) + "\n") + outf.writelines(str(line) + "\n" for line in lines) inf.close() outf.close() diff --git a/scripts/g.extension/g.extension.py b/scripts/g.extension/g.extension.py index 01f5b0a969f..aa707912f38 100644 --- a/scripts/g.extension/g.extension.py +++ b/scripts/g.extension/g.extension.py @@ -1041,11 +1041,11 @@ def write_xml_modules(name, tree=None): if bnode is not None: file_.write("%s\n" % (" " * indent)) indent += 4 - for fnode in bnode.findall("file"): - file_.write( - "%s%s\n" - % (" " * indent, os.path.join(options["prefix"], fnode.text)) - ) + file_.writelines( + "%s%s\n" + % (" " * indent, os.path.join(options["prefix"], fnode.text)) + for fnode in bnode.findall("file") + ) indent -= 4 file_.write("%s\n" % (" " * indent)) file_.write('%s\n' % (" " * indent, libgis_revison)) @@ -1091,11 +1091,11 @@ def write_xml_extensions(name, tree=None): if bnode is not None: file_.write("%s\n" % (" " * indent)) indent += 4 - for fnode in bnode.findall("file"): - file_.write( - "%s%s\n" - % (" " * indent, os.path.join(options["prefix"], fnode.text)) - ) + file_.writelines( + "%s%s\n" + % (" " * indent, os.path.join(options["prefix"], fnode.text)) + for fnode in bnode.findall("file") + ) indent -= 4 file_.write("%s\n" % (" " * indent)) # extension modules @@ -1103,8 +1103,10 @@ def write_xml_extensions(name, tree=None): if mnode is not None: file_.write("%s\n" % (" " * indent)) indent += 4 - for fnode in mnode.findall("module"): - file_.write("%s%s\n" % (" " * indent, fnode.text)) + file_.writelines( + "%s%s\n" % (" " * indent, fnode.text) + for fnode in mnode.findall("module") + ) indent -= 4 file_.write("%s\n" % (" " * indent)) @@ -1136,14 +1138,14 @@ def write_xml_toolboxes(name, tree=None): % (" " * indent, tnode.get("name"), tnode.get("code")) ) indent += 4 - for cnode in tnode.findall("correlate"): - file_.write( - '%s\n' % (" " * indent, tnode.get("code")) - ) - for mnode in tnode.findall("task"): - file_.write( - '%s\n' % (" " * indent, mnode.get("name")) - ) + file_.writelines( + '%s\n' % (" " * indent, tnode.get("code")) + for cnode in tnode.findall("correlate") + ) + file_.writelines( + '%s\n' % (" " * indent, mnode.get("name")) + for mnode in tnode.findall("task") + ) indent -= 4 file_.write("%s\n" % (" " * indent)) diff --git a/scripts/i.oif/i.oif.py b/scripts/i.oif/i.oif.py index cb156675927..81ef0b25f7b 100755 --- a/scripts/i.oif/i.oif.py +++ b/scripts/i.oif/i.oif.py @@ -146,8 +146,7 @@ def main(): sys.stdout.write(fmt % (p + (v,))) else: outf = open(output, "w") - for v, p in oif: - outf.write(fmt % (p + (v,))) + outf.writelines(fmt % (p + (v,)) for v, p in oif) outf.close() diff --git a/scripts/i.spectral/i.spectral.py b/scripts/i.spectral/i.spectral.py index 07efd8af31f..62f4a3397a3 100755 --- a/scripts/i.spectral/i.spectral.py +++ b/scripts/i.spectral/i.spectral.py @@ -104,8 +104,7 @@ def draw_gnuplot(what, xlabels, output, img_format, coord_legend): outfile = os.path.join(tmp_dir, "data_%d" % i) outf = open(outfile, "w") xrange = max(xrange, len(row) - 2) - for j, val in enumerate(row[3:]): - outf.write("%d %s\n" % (j + 1, val)) + outf.writelines("%d %s\n" % (j + 1, val) for j, val in enumerate(row[3:])) outf.close() # build gnuplot script @@ -147,8 +146,7 @@ def draw_gnuplot(what, xlabels, output, img_format, coord_legend): plotfile = os.path.join(tmp_dir, "spectrum.gnuplot") plotf = open(plotfile, "w") - for line in lines: - plotf.write(line + "\n") + plotf.writelines(line + "\n" for line in lines) plotf.close() if output: @@ -163,15 +161,13 @@ def draw_linegraph(what): xfile = os.path.join(tmp_dir, "data_x") xf = open(xfile, "w") - for j, val in enumerate(what[0][3:]): - xf.write("%d\n" % (j + 1)) + xf.writelines("%d\n" % (j + 1) for j, val in enumerate(what[0][3:])) xf.close() for i, row in enumerate(what): yfile = os.path.join(tmp_dir, "data_y_%d" % i) yf = open(yfile, "w") - for j, val in enumerate(row[3:]): - yf.write("%s\n" % val) + yf.writelines("%s\n" % val for j, val in enumerate(row[3:])) yf.close() yfiles.append(yfile) diff --git a/scripts/v.in.mapgen/v.in.mapgen.py b/scripts/v.in.mapgen/v.in.mapgen.py index efe7af1075d..e76486b75b4 100755 --- a/scripts/v.in.mapgen/v.in.mapgen.py +++ b/scripts/v.in.mapgen/v.in.mapgen.py @@ -106,8 +106,10 @@ def main(): if f[0].lower() == "nan": if points != []: outf.write("L %d 1\n" % len(points)) - for point in points: - outf.write(" %.15g %.15g %.15g\n" % tuple(map(float, point))) + outf.writelines( + " %.15g %.15g %.15g\n" % tuple(map(float, point)) + for point in points + ) outf.write(" 1 %d\n" % cat) cat += 1 points = [] @@ -134,8 +136,9 @@ def main(): if line[0] == "#": if points != []: outf.write("L %d 1\n" % len(points)) - for point in points: - outf.write(" %.15g %.15g\n" % tuple(map(float, point))) + outf.writelines( + " %.15g %.15g\n" % tuple(map(float, point)) for point in points + ) outf.write(" 1 %d\n" % cat) cat += 1 points = [] @@ -144,8 +147,9 @@ def main(): if points != []: outf.write("L %d 1\n" % len(points)) - for point in points: - outf.write(" %.15g %.15g\n" % tuple(map(float, point))) + outf.writelines( + " %.15g %.15g\n" % tuple(map(float, point)) for point in points + ) outf.write(" 1 %d\n" % cat) cat += 1 outf.close() diff --git a/utils/create_python_init_file.py b/utils/create_python_init_file.py index 567c8b95bba..5642bbc2e75 100755 --- a/utils/create_python_init_file.py +++ b/utils/create_python_init_file.py @@ -34,8 +34,7 @@ def main(path): with open(os.path.join(path, "__init__.py"), "w") as fd: fd.write("all = [%s" % os.linesep) - for m in modules: - fd.write(" '%s',%s" % (m, os.linesep)) + fd.writelines(" '%s',%s" % (m, os.linesep) for m in modules) fd.write(" ]%s" % os.linesep) return 0