From 76958057df4013ce30f0d6d15b1699832e0aadab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Edouard=20Choini=C3=A8re?=
<27212526+echoix@users.noreply.github.com>
Date: Sat, 13 Jul 2024 18:53:25 -0400
Subject: [PATCH] style: Fix read-whole-file (FURB101) and write-whole-file
(FURB103) (#4047)
* style: Fix read-whole-file (FURB101)
Ruff rule: https://docs.astral.sh/ruff/rules/read-whole-file/
* style: Extract repeated config_directory variable in generate_release_notes
* style: Fix write-whole-file (FURB103)
Ruff rule: https://docs.astral.sh/ruff/rules/write-whole-file/
---
display/d.text/test.py | 5 +-
gui/wxpython/core/render.py | 8 +-
gui/wxpython/core/toolboxes.py | 4 +-
gui/wxpython/gui_core/pyedit.py | 9 +-
man/build_manual_gallery.py | 6 +-
pyproject.toml | 2 -
python/grass/benchmark/results.py | 7 +-
python/grass/grassdb/history.py | 39 ++++---
python/grass/gunittest/invoker.py | 33 +++---
python/grass/gunittest/reporters.py | 12 +--
.../gunittest/testsuite/test_assertions.py | 12 +--
python/grass/jupyter/baseseriesmap.py | 4 +-
python/grass/jupyter/interactivemap.py | 6 +-
python/grass/pygrass/raster/category.py | 14 +--
python/grass/pygrass/shell/show.py | 5 +-
.../benchmark/benchmark_r_mfilter_nprocs.py | 9 +-
.../r.neighbors/testsuite/test_r_neighbors.py | 6 +-
scripts/g.extension/g.extension.py | 15 +--
.../testsuite/test_addons_download.py | 3 +-
scripts/r.in.wms/wms_base.py | 4 +-
scripts/r.unpack/r.unpack.py | 4 +-
scripts/v.db.addcolumn/v.db.addcolumn.py | 4 +-
scripts/v.in.wfs/v.in.wfs.py | 11 +-
.../testsuite/test_distr_tgis_db_raster.py | 7 +-
.../testsuite/test_distr_tgis_db_raster3d.py | 7 +-
.../testsuite/test_distr_tgis_db_vector.py | 7 +-
.../testsuite/test_t_register_raster_file.py | 102 +++++++++---------
utils/g.html2man/g.html2man.py | 6 +-
utils/generate_release_notes.py | 16 ++-
utils/mkhtml.py | 4 +-
utils/update_version.py | 4 +-
31 files changed, 175 insertions(+), 200 deletions(-)
diff --git a/display/d.text/test.py b/display/d.text/test.py
index ffc50cfc8aa..c68449ed7be 100755
--- a/display/d.text/test.py
+++ b/display/d.text/test.py
@@ -2,6 +2,7 @@
# Author: Owen Smith - Rewritten from test.pl by Huidae Cho
# Run: d.mon start=wx0 && ./test.py | d.text at=0,100
import math
+from pathlib import Path
import re
# Quiet black syntax checking for fonts and colors to keep the code printed to
@@ -66,8 +67,8 @@ def text(in_text):
color("gray")
rc(1, 1)
-with open(__file__) as f:
- src = f.read()
+
+src = Path(__file__).read_text()
print(
".L 0\n"
diff --git a/gui/wxpython/core/render.py b/gui/wxpython/core/render.py
index 6fe9d7f4592..2021f491fc1 100644
--- a/gui/wxpython/core/render.py
+++ b/gui/wxpython/core/render.py
@@ -22,6 +22,7 @@
"""
import os
+from pathlib import Path
import sys
import glob
import math
@@ -725,10 +726,9 @@ def OnRenderDone(self, env):
continue
if os.path.isfile(layer._legrow) and not layer.hidden:
- with open(layer._legrow) as infile:
- line = infile.read()
- outfile.write(line)
- new_legend.append(line)
+ line = Path(layer._legrow).read_text()
+ outfile.write(line)
+ new_legend.append(line)
self._rendering = False
if wx.IsBusy():
diff --git a/gui/wxpython/core/toolboxes.py b/gui/wxpython/core/toolboxes.py
index e9960ac2e62..798df081e06 100644
--- a/gui/wxpython/core/toolboxes.py
+++ b/gui/wxpython/core/toolboxes.py
@@ -13,6 +13,7 @@
"""
import os
+from pathlib import Path
import sys
import copy
import shutil
@@ -846,8 +847,7 @@ def module_test():
return 0
menudataFile = "data/test_toolboxes_menudata_ref.xml"
- with open(menudataFile) as correctMenudata:
- correct = str(correctMenudata.read())
+ correct = str(Path(menudataFile).read_text())
import difflib
diff --git a/gui/wxpython/gui_core/pyedit.py b/gui/wxpython/gui_core/pyedit.py
index 573496cbbfc..b7c8baf4001 100644
--- a/gui/wxpython/gui_core/pyedit.py
+++ b/gui/wxpython/gui_core/pyedit.py
@@ -10,6 +10,7 @@
:authors: Martin Landa
"""
+from pathlib import Path
import sys
import os
import stat
@@ -300,8 +301,7 @@ def _openFile(self, file_path):
:return str or None: file content or None
"""
try:
- with open(file_path, "r") as f:
- return f.read()
+ return Path(file_path).read_text()
except PermissionError:
GError(
message=_(
@@ -327,9 +327,8 @@ def _writeFile(self, file_path, content, additional_err_message=""):
:return None or True: file written or None
"""
try:
- with open(file_path, "w") as f:
- f.write(content)
- return True
+ Path(file_path).write_text(content)
+ return True
except PermissionError:
GError(
message=_(
diff --git a/man/build_manual_gallery.py b/man/build_manual_gallery.py
index 414b36c8a85..ea1ffb449c2 100755
--- a/man/build_manual_gallery.py
+++ b/man/build_manual_gallery.py
@@ -14,6 +14,7 @@
#############################################################################
import os
+from pathlib import Path
import sys
import fnmatch
import re
@@ -97,9 +98,8 @@ def img_in_html(filename, imagename):
# for some reason, calling search just once is much faster
# than calling it on every line (time is spent in _compile)
pattern = re.compile("".format(imagename))
- with open(filename) as file:
- if re.search(pattern, file.read()):
- return True
+ if re.search(pattern, Path(filename).read_text()):
+ return True
return False
diff --git a/pyproject.toml b/pyproject.toml
index 4cc2f9a3d8d..7d544473f60 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -151,8 +151,6 @@ ignore = [
"FBT001", # boolean-type-hint-positional-argument
"FBT002", # boolean-default-value-positional-argument
"FBT003", # boolean-positional-value-in-call
- "FURB101", # read-whole-file
- "FURB103", # write-whole-file.
"FURB118", # reimplemented-operator
"FURB152", # math-constant
"FURB154", # repeated-global
diff --git a/python/grass/benchmark/results.py b/python/grass/benchmark/results.py
index c89d8f1c80b..123e5dd8458 100644
--- a/python/grass/benchmark/results.py
+++ b/python/grass/benchmark/results.py
@@ -15,6 +15,7 @@
import copy
import json
+from pathlib import Path
from types import SimpleNamespace
@@ -48,8 +49,7 @@ def save_results_to_file(results, filename):
See :func:`save_results` for details.
"""
text = save_results(results)
- with open(filename, "w", encoding="utf-8") as file:
- file.write(text)
+ Path(filename).write_text(text, encoding="utf-8")
def load_results(data):
@@ -67,8 +67,7 @@ def load_results_from_file(filename):
See :func:`load_results` for details.
"""
- with open(filename, "r", encoding="utf-8") as file:
- return load_results(file.read())
+ return load_results(Path(filename).read_text(encoding="utf-8"))
def join_results(results, prefixes=None, select=None, prefixes_as_labels=False):
diff --git a/python/grass/grassdb/history.py b/python/grass/grassdb/history.py
index 85ebdb5b452..60b5459700d 100644
--- a/python/grass/grassdb/history.py
+++ b/python/grass/grassdb/history.py
@@ -103,27 +103,24 @@ def _read_from_JSON(history_path):
"""
content_list = []
try:
- with open(
- history_path, encoding="utf-8", mode="r", errors="replace"
- ) as file_history:
- content = file_history.read()
- if content:
- try:
- history_entries = json.loads(content)
- except ValueError as ve:
- raise ValueError(
- _("Error decoding content of JSON history file {}").format(
- history_path
- )
- ) from ve
- # Process the content as a list of dictionaries
- content_list = [
- {
- "command": entry["command"],
- "command_info": entry["command_info"],
- }
- for entry in history_entries
- ]
+ content = Path(history_path).read_text(encoding="utf-8", errors="replace")
+ if content:
+ try:
+ history_entries = json.loads(content)
+ except ValueError as ve:
+ raise ValueError(
+ _("Error decoding content of JSON history file {}").format(
+ history_path
+ )
+ ) from ve
+ # Process the content as a list of dictionaries
+ content_list = [
+ {
+ "command": entry["command"],
+ "command_info": entry["command_info"],
+ }
+ for entry in history_entries
+ ]
except OSError as e:
raise OSError(
_("Unable to read from JSON history file {}").format(history_path)
diff --git a/python/grass/gunittest/invoker.py b/python/grass/gunittest/invoker.py
index 2b2de7f5e40..9a19be4c85d 100644
--- a/python/grass/gunittest/invoker.py
+++ b/python/grass/gunittest/invoker.py
@@ -11,6 +11,7 @@
import collections
import os
+from pathlib import Path
import shutil
import subprocess
import sys
@@ -39,8 +40,7 @@
# TODO: this might be more extend then update
def update_keyval_file(filename, module, returncode):
if os.path.exists(filename):
- with open(filename, "r") as keyval_file:
- keyval = text_to_keyvalue(keyval_file.read(), sep="=")
+ keyval = text_to_keyvalue(Path(filename).read_text(), sep="=")
else:
keyval = {}
@@ -62,8 +62,7 @@ def update_keyval_file(filename, module, returncode):
keyval["returncode"] = returncode
keyval["test_file_authors"] = test_file_authors
- with open(filename, "w") as keyval_file:
- keyval_file.write(keyvalue_to_text(keyval))
+ Path(filename).write_text(keyvalue_to_text(keyval))
return keyval
@@ -243,8 +242,7 @@ def try_decode(data, encodings):
stdout = try_decode(stdout, encodings=encodings)
stderr = try_decode(stderr, encodings=encodings)
- with open(stdout_path, "w") as stdout_file:
- stdout_file.write(stdout)
+ Path(stdout_path).write_text(stdout)
with open(stderr_path, "w") as stderr_file:
if type(stderr) == "bytes":
stderr_file.write(decode(stderr))
@@ -337,18 +335,17 @@ def run_in_location(self, gisdbase, location, location_type, results_dir, exclud
# TODO: move this to some (new?) reporter
# TODO: add basic summary of linked files so that the page is not empty
- with open(os.path.join(results_dir, "index.html"), "w") as main_index:
- main_index.write(
- "
"
- "Tests for <{location}>"
- " using <{type}> type tests
"
- ""
- '- Results by testsuites'
- " (testsuite directories)
"
- '- Results by test files
'
- ""
- "".format(location=location, type=location_type)
- )
+ Path(os.path.join(results_dir, "index.html")).write_text(
+ ""
+ "Tests for <{location}>"
+ " using <{type}> type tests
"
+ ""
+ '- Results by testsuites'
+ " (testsuite directories)
"
+ '- Results by test files
'
+ ""
+ "".format(location=location, type=location_type)
+ )
testsuite_dir_reporter = TestsuiteDirReporter(
main_page_name="testsuites.html",
diff --git a/python/grass/gunittest/reporters.py b/python/grass/gunittest/reporters.py
index 63bffc655e1..21afce314e1 100644
--- a/python/grass/gunittest/reporters.py
+++ b/python/grass/gunittest/reporters.py
@@ -11,6 +11,7 @@
import os
import datetime
+from pathlib import Path
from xml.sax import saxutils
import xml.etree.ElementTree as et
import subprocess
@@ -906,9 +907,8 @@ def finish(self):
summary[key] = value
summary_filename = os.path.join(self.result_dir, "test_keyvalue_result.txt")
- with open(summary_filename, "w") as summary_file:
- text = keyvalue_to_text(summary, sep="=", vsep="\n", isep=",")
- summary_file.write(text)
+ text = keyvalue_to_text(summary, sep="=", vsep="\n", isep=",")
+ Path(summary_filename).write_text(text)
def end_file_test(
self, module, cwd, returncode, stdout, stderr, test_summary, timed_out=None
@@ -1025,8 +1025,7 @@ def end_file_test(
width = 72
self._stream.write(width * "=")
self._stream.write("\n")
- with open(stderr) as text:
- self._stream.write(text.read())
+ self._stream.write(Path(stderr).read_text())
self._stream.write(width * "=")
self._stream.write("\n")
self._stream.write(f"FAILED {module.file_path}")
@@ -1116,8 +1115,7 @@ def report_for_dir(self, root, directory, test_files):
root, directory, test_file_name, "test_keyvalue_result.txt"
)
# if os.path.exists(summary_filename):
- with open(summary_filename, "r") as keyval_file:
- summary = text_to_keyvalue(keyval_file.read(), sep="=")
+ summary = text_to_keyvalue(Path(summary_filename).read_text(), sep="=")
# else:
# TODO: write else here
# summary = None
diff --git a/python/grass/gunittest/testsuite/test_assertions.py b/python/grass/gunittest/testsuite/test_assertions.py
index 51720a56b76..3af538132f3 100644
--- a/python/grass/gunittest/testsuite/test_assertions.py
+++ b/python/grass/gunittest/testsuite/test_assertions.py
@@ -3,6 +3,7 @@
"""
import os
+from pathlib import Path
import grass.script.core as gcore
from grass.pygrass.modules import Module
@@ -348,20 +349,19 @@ def setUpClass(cls):
open(cls.emtpy_file, "w").close()
cls.file_with_md5 = cls.__name__ + "_this_is_a_file_with_known_md5"
file_content = "Content of the file with known MD5.\n"
- with open(cls.file_with_md5, "w") as f:
- f.write(file_content)
+ Path(cls.file_with_md5).write_text(file_content)
# MD5 sum created using:
# echo 'Content of the file with known MD5.' > some_file.txt
# md5sum some_file.txt
cls.file_md5 = "807bba4ffac4bb351bc3f27853009949"
cls.file_with_same_content = cls.__name__ + "_file_with_same_content"
- with open(cls.file_with_same_content, "w") as f:
- f.write(file_content)
+ Path(cls.file_with_same_content).write_text(file_content)
cls.file_with_different_content = cls.__name__ + "_file_with_different_content"
- with open(cls.file_with_different_content, "w") as f:
- f.write(file_content + " Something else here.")
+ Path(cls.file_with_different_content).write_text(
+ file_content + " Something else here."
+ )
@classmethod
def tearDownClass(cls):
diff --git a/python/grass/jupyter/baseseriesmap.py b/python/grass/jupyter/baseseriesmap.py
index e28572e1f3e..50f28f58049 100644
--- a/python/grass/jupyter/baseseriesmap.py
+++ b/python/grass/jupyter/baseseriesmap.py
@@ -1,6 +1,7 @@
"""Base class for SeriesMap and TimeSeriesMap"""
import os
+from pathlib import Path
import tempfile
import weakref
import shutil
@@ -177,8 +178,7 @@ def change_slider(change):
# Display image associated with datetime
def change_image(index):
filename = self._base_filename_dict[index]
- with open(filename, "rb") as rfile:
- out_img.value = rfile.read()
+ out_img.value = Path(filename).read_bytes()
widgets.interactive_output(change_image, {"index": slider})
diff --git a/python/grass/jupyter/interactivemap.py b/python/grass/jupyter/interactivemap.py
index f5eae8588ff..082122d24d0 100644
--- a/python/grass/jupyter/interactivemap.py
+++ b/python/grass/jupyter/interactivemap.py
@@ -15,6 +15,7 @@
import base64
import json
+from pathlib import Path
from .reprojection_renderer import ReprojectionRenderer
@@ -119,9 +120,8 @@ def add_to(self, interactive_map):
# ImageOverlays don't work well with local files,
# they need relative address and behavior differs
# for notebooks and jupyterlab
- with open(self._filename, "rb") as file:
- data = base64.b64encode(file.read()).decode("ascii")
- url = "data:image/png;base64," + data
+ data = base64.b64encode(Path(self._filename).read_bytes()).decode("ascii")
+ url = "data:image/png;base64," + data
image = ipyleaflet.ImageOverlay(
url=url, bounds=self._bounds, name=self._title, **self._layer_kwargs
)
diff --git a/python/grass/pygrass/raster/category.py b/python/grass/pygrass/raster/category.py
index 2cee672ed32..31ef5f3ed76 100644
--- a/python/grass/pygrass/raster/category.py
+++ b/python/grass/pygrass/raster/category.py
@@ -6,6 +6,7 @@
import ctypes
from operator import itemgetter
+from pathlib import Path
import grass.lib.raster as libraster
from grass.exceptions import ImplementationError
@@ -325,13 +326,12 @@ def write_rules(self, filename, sep=":"):
:param str filename: the name of file with categories rules
:param str sep: the separator used to divide values and category
"""
- with open(filename, "w") as f:
- cats = []
- for cat in self.__iter__():
- if cat[-1] is None:
- cat = cat[:-1]
- cats.append(sep.join([str(i) for i in cat]))
- f.write("\n".join(cats))
+ cats = []
+ for cat in self.__iter__():
+ if cat[-1] is None:
+ cat = cat[:-1]
+ cats.append(sep.join([str(i) for i in cat]))
+ Path(filename).write_text("\n".join(cats))
def sort(self):
libraster.Rast_sort_cats(ctypes.byref(self.c_cats))
diff --git a/python/grass/pygrass/shell/show.py b/python/grass/pygrass/shell/show.py
index 20b721e726b..8465dc9e92d 100644
--- a/python/grass/pygrass/shell/show.py
+++ b/python/grass/pygrass/shell/show.py
@@ -4,7 +4,8 @@
@author: pietro
"""
+from pathlib import Path
+
def raw_figure(figpath):
- with open(figpath, mode="rb") as data:
- return data.read()
+ return Path(figpath).read_bytes()
diff --git a/raster/r.mfilter/benchmark/benchmark_r_mfilter_nprocs.py b/raster/r.mfilter/benchmark/benchmark_r_mfilter_nprocs.py
index 7212fc7e193..2dc85b411d8 100644
--- a/raster/r.mfilter/benchmark/benchmark_r_mfilter_nprocs.py
+++ b/raster/r.mfilter/benchmark/benchmark_r_mfilter_nprocs.py
@@ -3,6 +3,8 @@
@author Aaron Saw Min Sern
"""
+from pathlib import Path
+
from grass.exceptions import CalledModuleError
from grass.pygrass.modules import Module
from grass.script import tempfile
@@ -27,9 +29,8 @@ def benchmark(size, label, results):
reference = "r_mfilter_reference_map"
output = "benchmark_r_mfilter_nprocs"
filter = tempfile()
- with open(filter, "w") as w:
- w.write(
- """MATRIX 9
+ Path(filter).write_text(
+ """MATRIX 9
1 1 1 1 1 1 1 1 1
1 2 1 2 1 2 1 2 1
1 1 3 1 3 1 3 1 1
@@ -41,7 +42,7 @@ def benchmark(size, label, results):
1 1 1 1 1 1 1 1 1
DIVISOR 81
TYPE P"""
- )
+ )
generate_map(rows=size, cols=size, fname=reference)
module = Module(
diff --git a/raster/r.neighbors/testsuite/test_r_neighbors.py b/raster/r.neighbors/testsuite/test_r_neighbors.py
index b447eabe1d2..c333a3abdaa 100644
--- a/raster/r.neighbors/testsuite/test_r_neighbors.py
+++ b/raster/r.neighbors/testsuite/test_r_neighbors.py
@@ -1,3 +1,4 @@
+from pathlib import Path
from grass.gunittest.case import TestCase
from grass.gunittest.main import test
from grass.script.raster import raster_info
@@ -628,8 +629,9 @@ def test_weighting_file(self):
self.to_remove.extend(outputs_threaded)
weights = tempfile()
- with open(weights, "w") as w:
- w.write("0 1 1 1 0\n1 0 0 0 1\n1 0 0 0 1\n1 0 0 0 1\n0 1 1 1 0")
+ Path(weights).write_text(
+ "0 1 1 1 0\n1 0 0 0 1\n1 0 0 0 1\n1 0 0 0 1\n0 1 1 1 0"
+ )
self.assertModule(
"r.neighbors",
diff --git a/scripts/g.extension/g.extension.py b/scripts/g.extension/g.extension.py
index 7103a9e4f15..c02b8b8e3a4 100644
--- a/scripts/g.extension/g.extension.py
+++ b/scripts/g.extension/g.extension.py
@@ -489,8 +489,7 @@ def urlretrieve(url, filename, *args, **kwargs):
"""
request = urlrequest.Request(url, headers=HEADERS)
response = urlrequest.urlopen(request, *args, **kwargs)
- with open(filename, "wb") as f:
- f.write(response.read())
+ Path(filename).write_bytes(response.read())
def urlopen(url, *args, **kwargs):
@@ -572,8 +571,7 @@ def get_default_branch(full_url):
def etree_fromfile(filename):
"""Create XML element tree from a given file name"""
- with open(filename, "r") as file_:
- return etree.fromstring(file_.read())
+ return etree.fromstring(Path(filename).read_text())
def etree_fromurl(url):
@@ -1294,8 +1292,7 @@ def install_toolbox_xml(url, name):
write_xml_modules(xml_file)
# read XML file
- with open(xml_file, "r") as xml:
- tree = etree.fromstring(xml.read())
+ tree = etree.fromstring(Path(xml_file).read_text())
# update tree
tnode = None
@@ -1798,16 +1795,14 @@ def is_binary_string(bytes):
continue # ignore binary files
# read content of text file
- with open(filename, "rb") as fd:
- data = fd.read()
+ data = Path(filename).read_bytes()
# we don't expect there would be CRLF file by
# purpose if we want to allow CRLF files we would
# have to whitelite .py etc
newdata = data.replace(b"\r\n", b"\n")
if newdata != data:
- with open(filename, "wb") as newfile:
- newfile.write(newdata)
+ Path(filename).write_bytes(newdata)
def extract_zip(name, directory, tmpdir):
diff --git a/scripts/g.extension/testsuite/test_addons_download.py b/scripts/g.extension/testsuite/test_addons_download.py
index 384c6a4950f..c4618306d12 100644
--- a/scripts/g.extension/testsuite/test_addons_download.py
+++ b/scripts/g.extension/testsuite/test_addons_download.py
@@ -203,8 +203,7 @@ def test_github_official_module_man_page_src_code_links_exists(self):
)
html_man_page = self.install_prefix / "docs" / "html" / "db.join.html"
self.assertFileExists(str(html_man_page))
- with open(html_man_page) as f:
- content = f.read()
+ content = Path(html_man_page).read_text()
for link_name in [f"{extension} source code", "history"]:
url = re.search(rf"{link_name}", content).group(1)
self.assertTrue(url)
diff --git a/scripts/r.in.wms/wms_base.py b/scripts/r.in.wms/wms_base.py
index 1847ca05783..a14e15dc786 100644
--- a/scripts/r.in.wms/wms_base.py
+++ b/scripts/r.in.wms/wms_base.py
@@ -19,6 +19,7 @@
import os
from http.client import HTTPException
from math import ceil
+from pathlib import Path
from urllib.request import Request, urlopen
from urllib.error import HTTPError
@@ -304,8 +305,7 @@ def GetCapabilities(self, options):
# save to file
if capfile_output:
try:
- with open(capfile_output, "w") as temp:
- temp.write(cap)
+ Path(capfile_output).write_text(cap)
return
except OSError as error:
gs.fatal(_("Unable to open file '%s'.\n%s\n" % (capfile_output, error)))
diff --git a/scripts/r.unpack/r.unpack.py b/scripts/r.unpack/r.unpack.py
index a19123b28f0..053ac96988b 100644
--- a/scripts/r.unpack/r.unpack.py
+++ b/scripts/r.unpack/r.unpack.py
@@ -41,6 +41,7 @@
# %end
import os
+from pathlib import Path
import sys
import shutil
import tarfile
@@ -243,8 +244,7 @@ def main():
if maps:
if vrt_file and os.path.exists(vrt_file):
files = "\n".join(maps)
- with open(vrt_file, "w") as f:
- f.write(files)
+ Path(vrt_file).write_text(files)
grass.message(_("Raster map <{name}> unpacked".format(name=map_name)))
diff --git a/scripts/v.db.addcolumn/v.db.addcolumn.py b/scripts/v.db.addcolumn/v.db.addcolumn.py
index 0e7b8a35c1a..2d6c88cd2e5 100755
--- a/scripts/v.db.addcolumn/v.db.addcolumn.py
+++ b/scripts/v.db.addcolumn/v.db.addcolumn.py
@@ -42,6 +42,7 @@
import atexit
import os
+from pathlib import Path
import re
from grass.exceptions import CalledModuleError
@@ -124,8 +125,7 @@ def main():
sql_file = gs.tempfile()
rm_files.append(sql_file)
cols_add_str = ",".join([col[0] for col in columns])
- with open(sql_file, "w") as write_file:
- write_file.write(add_str)
+ Path(sql_file).write_text(add_str)
try:
gs.run_command(
"db.execute",
diff --git a/scripts/v.in.wfs/v.in.wfs.py b/scripts/v.in.wfs/v.in.wfs.py
index a983b87cab4..bd127c3bea0 100755
--- a/scripts/v.in.wfs/v.in.wfs.py
+++ b/scripts/v.in.wfs/v.in.wfs.py
@@ -106,6 +106,7 @@
import os
+from pathlib import Path
import sys
from grass.script.utils import try_remove
from grass.script import core as grass
@@ -164,17 +165,15 @@ def main():
if options["username"] and options["password"]:
grass.message(_("Setting username and password..."))
if os.path.isfile(options["username"]):
- with open(options["username"]) as f:
- filecontent = f.read()
- user = filecontent.strip()
+ filecontent = Path(options["username"]).read_text()
+ user = filecontent.strip()
elif options["username"] in os.environ:
user = os.environ[options["username"]]
else:
user = options["username"]
if os.path.isfile(options["password"]):
- with open(options["password"]) as f:
- filecontent = f.read()
- pw = filecontent.strip()
+ filecontent = Path(options["password"]).read_text()
+ pw = filecontent.strip()
elif options["password"] in os.environ:
pw = os.environ[options["password"]]
else:
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 834a5a9ad65..412a926f01d 100644
--- a/temporal/t.connect/testsuite/test_distr_tgis_db_raster.py
+++ b/temporal/t.connect/testsuite/test_distr_tgis_db_raster.py
@@ -9,6 +9,7 @@
"""
import os
+from pathlib import Path
from grass.gunittest.case import TestCase
from grass.gunittest.gmodules import SimpleModule
@@ -107,8 +108,7 @@ def test_tlist(self):
)
self.assertModule(t_list)
self.assertFileExists(self.outfile)
- with open(self.outfile, "r") as f:
- read_data = f.read()
+ read_data = Path(self.outfile).read_text()
for a, b in zip(list_string.split("\n"), read_data.split("\n")):
self.assertEqual(a.strip(), b.strip())
# self.assertLooksLike(reference=read_data, actual=list_string)
@@ -183,8 +183,7 @@ def test_trast_list(self):
)
self.assertModule(trast_list)
self.assertFileExists(self.outfile)
- with open(self.outfile, "r") as f:
- read_data = f.read()
+ read_data = Path(self.outfile).read_text()
for a, b in zip(list_string.split("\n"), read_data.split("\n")):
self.assertEqual(a.strip(), b.strip())
if os.path.isfile(self.outfile):
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 ed8e3c31cfd..23bc11c271e 100644
--- a/temporal/t.connect/testsuite/test_distr_tgis_db_raster3d.py
+++ b/temporal/t.connect/testsuite/test_distr_tgis_db_raster3d.py
@@ -9,6 +9,7 @@
"""
import os
+from pathlib import Path
from grass.gunittest.case import TestCase
from grass.gunittest.gmodules import SimpleModule
@@ -107,8 +108,7 @@ def test_tlist(self):
)
self.assertModule(t_list)
self.assertFileExists(self.outfile)
- with open(self.outfile, "r") as f:
- read_data = f.read()
+ read_data = Path(self.outfile).read_text()
for a, b in zip(list_string.split("\n"), read_data.split("\n")):
self.assertEqual(a.strip(), b.strip())
# self.assertLooksLike(reference=read_data, actual=list_string)
@@ -183,8 +183,7 @@ def test_trast_list(self):
)
self.assertModule(trast_list)
self.assertFileExists(self.outfile)
- with open(self.outfile, "r") as f:
- read_data = f.read()
+ read_data = Path(self.outfile).read_text()
for a, b in zip(list_string.split("\n"), read_data.split("\n")):
self.assertEqual(a.strip(), b.strip())
if os.path.isfile(self.outfile):
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 7616db89fd5..fd26cc93e26 100644
--- a/temporal/t.connect/testsuite/test_distr_tgis_db_vector.py
+++ b/temporal/t.connect/testsuite/test_distr_tgis_db_vector.py
@@ -9,6 +9,7 @@
"""
import os
+from pathlib import Path
from grass.gunittest.case import TestCase
from grass.gunittest.gmodules import SimpleModule
@@ -107,8 +108,7 @@ def test_tlist(self):
)
self.assertModule(t_list)
self.assertFileExists(self.outfile)
- with open(self.outfile, "r") as f:
- read_data = f.read()
+ read_data = Path(self.outfile).read_text()
for a, b in zip(list_string.split("\n"), read_data.split("\n")):
self.assertEqual(a.strip(), b.strip())
# self.assertLooksLike(reference=read_data, actual=list_string)
@@ -200,8 +200,7 @@ def test_tvect_list(self):
)
self.assertModule(trast_list)
self.assertFileExists(self.outfile)
- with open(self.outfile, "r") as f:
- read_data = f.read()
+ read_data = Path(self.outfile).read_text()
for a, b in zip(list_string.split("\n"), read_data.split("\n")):
self.assertEqual(a.strip(), b.strip())
if os.path.isfile(self.outfile):
diff --git a/temporal/t.register/testsuite/test_t_register_raster_file.py b/temporal/t.register/testsuite/test_t_register_raster_file.py
index 927d465df56..c8f8abeb55c 100755
--- a/temporal/t.register/testsuite/test_t_register_raster_file.py
+++ b/temporal/t.register/testsuite/test_t_register_raster_file.py
@@ -22,6 +22,7 @@
"""
from datetime import datetime
+from pathlib import Path
import grass.script as gs
import grass.temporal as tgis
@@ -79,8 +80,7 @@ def tearDownClass(cls):
def test_with_file_and_increment(self):
tmp_file = gs.tempfile()
- with open(tmp_file, "w") as register_file:
- register_file.write("prec_1\nprec_2\nprec_3\nprec_4\nprec_5\nprec_6")
+ Path(tmp_file).write_text("prec_1\nprec_2\nprec_3\nprec_4\nprec_5\nprec_6")
register_module = SimpleModule(
"t.register",
@@ -122,8 +122,7 @@ def test_with_file_and_increment(self):
def test_with_file_and_no_increment(self):
tmp_file = gs.tempfile()
- with open(tmp_file, "w") as register_file:
- register_file.write("prec_1\nprec_2\nprec_3\nprec_4\nprec_5\nprec_6")
+ Path(tmp_file).write_text("prec_1\nprec_2\nprec_3\nprec_4\nprec_5\nprec_6")
register_module = SimpleModule(
"t.register",
@@ -164,8 +163,7 @@ def test_with_file_and_no_increment(self):
def test_with_file_increment_and_intervall(self):
tmp_file = gs.tempfile()
- with open(tmp_file, "w") as register_file:
- register_file.write("prec_1\nprec_2\nprec_3\nprec_4\nprec_5\nprec_6")
+ Path(tmp_file).write_text("prec_1\nprec_2\nprec_3\nprec_4\nprec_5\nprec_6")
register_module = SimpleModule(
"t.register",
@@ -209,19 +207,18 @@ def test_with_file_increment_and_intervall(self):
def test_with_start_in_file(self):
tmp_file = gs.tempfile()
- with open(tmp_file, "w") as register_file:
- register_file.write(
- "\n".join(
- [
- "prec_1|2001-01-01",
- "prec_2|2001-02-01",
- "prec_3|2001-03-01",
- "prec_4|2001-04-01",
- "prec_5|2001-05-01",
- "prec_6|2001-06-01",
- ]
- )
+ Path(tmp_file).write_text(
+ "\n".join(
+ [
+ "prec_1|2001-01-01",
+ "prec_2|2001-02-01",
+ "prec_3|2001-03-01",
+ "prec_4|2001-04-01",
+ "prec_5|2001-05-01",
+ "prec_6|2001-06-01",
+ ]
)
+ )
register_module = SimpleModule(
"t.register",
@@ -261,19 +258,18 @@ def test_with_start_in_file(self):
def test_with_start_in_file_and_increment(self):
tmp_file = gs.tempfile()
- with open(tmp_file, "w") as register_file:
- register_file.write(
- "\n".join(
- [
- "prec_1|2001-01-01",
- "prec_2|2001-02-01",
- "prec_3|2001-03-01",
- "prec_4|2001-04-01",
- "prec_5|2001-05-01",
- "prec_6|2001-06-01",
- ]
- )
+ Path(tmp_file).write_text(
+ "\n".join(
+ [
+ "prec_1|2001-01-01",
+ "prec_2|2001-02-01",
+ "prec_3|2001-03-01",
+ "prec_4|2001-04-01",
+ "prec_5|2001-05-01",
+ "prec_6|2001-06-01",
+ ]
)
+ )
register_module = SimpleModule(
"t.register",
@@ -290,19 +286,18 @@ def test_with_start_in_file_and_increment(self):
def test_with_start_and_end_in_file_and_interval(self):
tmp_file = gs.tempfile()
- with open(tmp_file, "w") as register_file:
- register_file.write(
- "\n".join(
- [
- "prec_1|2001-01-01|2001-04-01",
- "prec_2|2001-04-01|2001-07-01",
- "prec_3|2001-07-01|2001-10-01",
- "prec_4|2001-10-01|2002-01-01",
- "prec_5|2002-01-01|2002-04-01",
- "prec_6|2002-04-01|2002-07-01",
- ]
- )
+ Path(tmp_file).write_text(
+ "\n".join(
+ [
+ "prec_1|2001-01-01|2001-04-01",
+ "prec_2|2001-04-01|2001-07-01",
+ "prec_3|2001-07-01|2001-10-01",
+ "prec_4|2001-10-01|2002-01-01",
+ "prec_5|2002-01-01|2002-04-01",
+ "prec_6|2002-04-01|2002-07-01",
+ ]
)
+ )
register_module = SimpleModule(
"t.register",
@@ -320,19 +315,18 @@ def test_with_start_and_end_in_file_and_interval(self):
def test_with_mapset_and_semantic_label(self):
mapset = gs.gisenv()["MAPSET"]
tmp_file = gs.tempfile()
- with open(tmp_file, "w") as register_file:
- register_file.write(
- "\n".join(
- [
- f"prec_1@{mapset}|2001-01-01|2001-04-01|semantic_label",
- f"prec_2@{mapset}|2001-04-01|2001-07-01|semantic_label",
- f"prec_3@{mapset}|2001-07-01|2001-10-01|semantic_label",
- f"prec_4@{mapset}|2001-10-01|2002-01-01|semantic_label",
- f"prec_5@{mapset}|2002-01-01|2002-04-01|semantic_label",
- f"prec_6@{mapset}|2002-04-01|2002-07-01|semantic_label",
- ]
- )
+ Path(tmp_file).write_text(
+ "\n".join(
+ [
+ f"prec_1@{mapset}|2001-01-01|2001-04-01|semantic_label",
+ f"prec_2@{mapset}|2001-04-01|2001-07-01|semantic_label",
+ f"prec_3@{mapset}|2001-07-01|2001-10-01|semantic_label",
+ f"prec_4@{mapset}|2001-10-01|2002-01-01|semantic_label",
+ f"prec_5@{mapset}|2002-01-01|2002-04-01|semantic_label",
+ f"prec_6@{mapset}|2002-04-01|2002-07-01|semantic_label",
+ ]
)
+ )
register_module = SimpleModule(
"t.register",
diff --git a/utils/g.html2man/g.html2man.py b/utils/g.html2man/g.html2man.py
index e134160d240..498ce34dfe1 100755
--- a/utils/g.html2man/g.html2man.py
+++ b/utils/g.html2man/g.html2man.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
+from pathlib import Path
import sys
import re
from ghtml import HTMLParser
@@ -53,9 +54,8 @@ def main():
s = s.lstrip()
# write groff
- with open(sys.argv[2], "wb") as outf:
- s = s.encode("UTF-8")
- outf.write(s)
+ s = s.encode("UTF-8")
+ Path(sys.argv[2]).write_bytes(s)
if __name__ == "__main__":
diff --git a/utils/generate_release_notes.py b/utils/generate_release_notes.py
index 40511c3dc44..3cfffe77bd2 100755
--- a/utils/generate_release_notes.py
+++ b/utils/generate_release_notes.py
@@ -26,6 +26,7 @@
" date: %ad%n"
" message: |-%n %s"
)
+CONFIG_DIRECTORY = Path("utils")
def remove_excluded_changes(changes, exclude):
@@ -266,18 +267,17 @@ def notes_from_git_log(start_tag, end_tag, categories, exclude):
if not commits:
raise RuntimeError("No commits retrieved from git log (try different tags)")
- config_directory = Path("utils")
svn_name_by_git_author = csv_to_dict(
- config_directory / "svn_name_git_author.csv",
+ CONFIG_DIRECTORY / "svn_name_git_author.csv",
key="git_author",
value="svn_name",
)
github_name_by_svn_name = csv_to_dict(
- config_directory / "svn_name_github_name.csv",
+ CONFIG_DIRECTORY / "svn_name_github_name.csv",
key="svn_name",
value="github_name",
)
- github_name_by_git_author_file = config_directory / "git_author_github_name.csv"
+ github_name_by_git_author_file = CONFIG_DIRECTORY / "git_author_github_name.csv"
github_name_by_git_author = csv_to_dict(
github_name_by_git_author_file,
key="git_author",
@@ -343,9 +343,8 @@ def create_release_notes(args):
check=True,
).stdout.strip()
- config_directory = Path("utils")
- with open(config_directory / "release.yml", encoding="utf-8") as file:
- config = yaml.safe_load(file.read())["notes"]
+ config_file = CONFIG_DIRECTORY / "release.yml"
+ config = yaml.safe_load(config_file.read_text(encoding="utf-8"))["notes"]
if args.backend == "api":
notes_from_gh_api(
@@ -391,8 +390,7 @@ def main():
args = parser.parse_args()
if args.backend == "check":
config_file = Path("utils") / "release.yml"
- with open(config_file, encoding="utf-8") as file:
- config = yaml.safe_load(file.read())
+ config = yaml.safe_load(Path(config_file).read_text(encoding="utf-8"))
has_match = False
for category in config["notes"]["categories"]:
if re.match(category["regexp"], args.branch):
diff --git a/utils/mkhtml.py b/utils/mkhtml.py
index c5a7519872d..1e9a335bcc2 100644
--- a/utils/mkhtml.py
+++ b/utils/mkhtml.py
@@ -26,6 +26,7 @@
import json
import pathlib
import subprocess
+from pathlib import Path
from html.parser import HTMLParser
@@ -513,8 +514,7 @@ def get_last_git_commit(src_dir, addon_path, is_addon):
def read_file(name):
try:
- with open(name) as f:
- return f.read()
+ return Path(name).read_text()
except OSError:
return ""
diff --git a/utils/update_version.py b/utils/update_version.py
index 386c42482f5..c66a34a62cd 100755
--- a/utils/update_version.py
+++ b/utils/update_version.py
@@ -5,14 +5,14 @@
import sys
import datetime
from types import SimpleNamespace
+from pathlib import Path
import argparse
def read_version_file():
"""Return version file content as object instance with attributes"""
- with open("include/VERSION", encoding="utf-8") as file:
- lines = file.read().splitlines()
+ lines = Path("include/VERSION").read_text(encoding="utf-8").splitlines()
return SimpleNamespace(
major=lines[0], minor=lines[1], micro=lines[2], year=lines[3]
)