diff --git a/man/build_class.py b/man/build_class.py index a75fe62fe58..7dc53c121bf 100644 --- a/man/build_class.py +++ b/man/build_class.py @@ -33,41 +33,39 @@ def build_class(ext): os.chdir(man_dir) filename = modclass + f".{ext}" - f = open(filename + ".tmp", "w") - - write_header( - f, - "{} modules - GRASS GIS {} Reference Manual".format( - modclass.capitalize(), grass_version - ), - template=ext, - ) - modclass_lower = modclass.lower() - modclass_visible = modclass - if modclass_lower not in no_intro_page_classes: - if modclass_visible == "raster3d": - # convert keyword to nice form - modclass_visible = "3D raster" - f.write( - modclass_intro_tmpl.substitute( - modclass=modclass_visible, modclass_lower=modclass_lower - ) + with open(filename + ".tmp", "w") as f: + write_header( + f, + "{} modules - GRASS GIS {} Reference Manual".format( + modclass.capitalize(), grass_version + ), + template=ext, ) - f.write(modclass_tmpl.substitute(modclass=to_title(modclass_visible))) + modclass_lower = modclass.lower() + modclass_visible = modclass + if modclass_lower not in no_intro_page_classes: + if modclass_visible == "raster3d": + # convert keyword to nice form + modclass_visible = "3D raster" + f.write( + modclass_intro_tmpl.substitute( + modclass=modclass_visible, modclass_lower=modclass_lower + ) + ) + f.write(modclass_tmpl.substitute(modclass=to_title(modclass_visible))) - # for all modules: - for cmd in get_files(man_dir, cls, extension=ext): - basename = os.path.splitext(cmd)[0] - desc = check_for_desc_override(basename) - if desc is None: - desc = get_desc(cmd) - f.write(desc2_tmpl.substitute(cmd=cmd, basename=basename, desc=desc)) - if ext == "html": - f.write("\n") + # for all modules: + for cmd in get_files(man_dir, cls, extension=ext): + basename = os.path.splitext(cmd)[0] + desc = check_for_desc_override(basename) + if desc is None: + desc = get_desc(cmd) + f.write(desc2_tmpl.substitute(cmd=cmd, basename=basename, desc=desc)) + if ext == "html": + f.write("\n") - write_footer(f, f"index.{ext}", year, template=ext) + write_footer(f, f"index.{ext}", year, template=ext) - f.close() replace_file(filename) diff --git a/man/build_class_graphical.py b/man/build_class_graphical.py index b1bd6eede7f..0eed97beb46 100644 --- a/man/build_class_graphical.py +++ b/man/build_class_graphical.py @@ -131,65 +131,62 @@ def generate_page_for_category( short_family, module_family, imgs, year, skip_no_image=False ): filename = module_family + "_graphical.html" - - output = open(filename + ".tmp", "w") - - output.write( - header1_tmpl.substitute( - title="GRASS GIS %s Reference Manual: Graphical index" % grass_version - ) - ) - output.write(header_graphical_index_tmpl) - - if module_family.lower() not in {"general", "postscript"}: - if module_family == "raster3d": - # covert keyword to nice form - module_family = "3D raster" + with open(filename + ".tmp", "w") as output: output.write( - modclass_intro_tmpl.substitute( - modclass=module_family, modclass_lower=module_family.lower() + header1_tmpl.substitute( + title="GRASS GIS %s Reference Manual: Graphical index" % grass_version ) ) - if module_family == "wxGUI": - output.write("

wxGUI components:

") - elif module_family == "guimodules": - output.write("

g.gui.* modules:

") - else: - output.write("

{0} modules:

".format(to_title(module_family))) - output.write('") - write_footer(output, "index.html", year, template="html") + write_footer(output, "index.html", year, template="html") - output.close() replace_file(filename) diff --git a/man/build_class_rest.py b/man/build_class_rest.py index 05aec125d04..97d49a5cdb8 100644 --- a/man/build_class_rest.py +++ b/man/build_class_rest.py @@ -32,27 +32,26 @@ modclass = sys.argv[2] filename = modclass + ".txt" - -f = open(filename + ".tmp", "wb") - -write_rest_header(f, "GRASS GIS %s Reference Manual: %s" % (grass_version, modclass)) -if modclass.lower() not in {"general", "miscellaneous", "postscript"}: - f.write( - modclass_intro_tmpl.substitute( - modclass=modclass, modclass_lower=modclass.lower() - ) +with open(filename + ".tmp", "wb") as f: + write_rest_header( + f, "GRASS GIS %s Reference Manual: %s" % (grass_version, modclass) ) -f.write(modclass_tmpl.substitute(modclass=modclass)) + if modclass.lower() not in {"general", "miscellaneous", "postscript"}: + f.write( + modclass_intro_tmpl.substitute( + modclass=modclass, modclass_lower=modclass.lower() + ) + ) + f.write(modclass_tmpl.substitute(modclass=modclass)) -# for all modules: -for cmd in rest_files(cls): - basename = os.path.splitext(cmd)[0] - desc = check_for_desc_override(basename) - if desc is None: - desc = get_desc(cmd) - f.write(desc2_tmpl.substitute(basename=basename, desc=desc)) + # for all modules: + for cmd in rest_files(cls): + basename = os.path.splitext(cmd)[0] + desc = check_for_desc_override(basename) + if desc is None: + desc = get_desc(cmd) + f.write(desc2_tmpl.substitute(basename=basename, desc=desc)) -write_rest_footer(f, "index.txt") + write_rest_footer(f, "index.txt") -f.close() replace_file(filename) diff --git a/man/build_full_index.py b/man/build_full_index.py index 150f28fd00b..a47630e3e31 100644 --- a/man/build_full_index.py +++ b/man/build_full_index.py @@ -56,37 +56,35 @@ def build_full_index(ext): # begin full index: filename = f"full_index.{ext}" - f = open(filename + ".tmp", "w") - - write_header( - f, - "GRASS GIS {} Reference Manual - Full index".format(grass_version), - body_width="80%", - template=ext, - ) + with open(filename + ".tmp", "w") as f: + write_header( + f, + "GRASS GIS {} Reference Manual - Full index".format(grass_version), + body_width="80%", + template=ext, + ) - # generate main index of all modules: - f.write(full_index_header) + # generate main index of all modules: + f.write(full_index_header) - if ext == "html": - f.write(toc) - - # for all module groups: - for cls, cls_label in classes: - f.write(cmd2_tmpl.substitute(cmd_label=to_title(cls_label), cmd=cls)) - # for all modules: - for cmd in get_files(man_dir, cls, extension=ext): - basename = os.path.splitext(cmd)[0] - desc = check_for_desc_override(basename) - if desc is None: - desc = get_desc(cmd) - f.write(desc1_tmpl.substitute(cmd=cmd, basename=basename, desc=desc)) if ext == "html": - f.write("\n") - - write_footer(f, f"index.{ext}", year, template=ext) + f.write(toc) + + # for all module groups: + for cls, cls_label in classes: + f.write(cmd2_tmpl.substitute(cmd_label=to_title(cls_label), cmd=cls)) + # for all modules: + for cmd in get_files(man_dir, cls, extension=ext): + basename = os.path.splitext(cmd)[0] + desc = check_for_desc_override(basename) + if desc is None: + desc = get_desc(cmd) + f.write(desc1_tmpl.substitute(cmd=cmd, basename=basename, desc=desc)) + if ext == "html": + f.write("\n") + + write_footer(f, f"index.{ext}", year, template=ext) - f.close() replace_file(filename) diff --git a/man/build_full_index_rest.py b/man/build_full_index_rest.py index 26183505393..c877d914cc0 100644 --- a/man/build_full_index_rest.py +++ b/man/build_full_index_rest.py @@ -34,34 +34,32 @@ # begin full index: filename = "full_index.txt" -f = open(filename + ".tmp", "wb") +with open(filename + ".tmp", "wb") as f: + write_rest_header(f, "GRASS GIS %s Reference Manual: Full index" % grass_version) -write_rest_header(f, "GRASS GIS %s Reference Manual: Full index" % grass_version) + # generate main index of all modules: + f.write(full_index_header) + # " -# generate main index of all modules: -f.write(full_index_header) -# " + # for cls in classes: + # f.write(cmd1_tmpl.substitute(cmd = cls)) + # if cls != classes[-1]: + # f.write(" | ") -# for cls in classes: -# f.write(cmd1_tmpl.substitute(cmd = cls)) -# if cls != classes[-1]: -# f.write(" | ") + f.write(sections) -f.write(sections) + # for all module groups: + for cls in classes: + f.write(cmd2_tmpl.substitute(cmd=cls)) + # for all modules: + for cmd in rest_files(cls): + basename = os.path.splitext(cmd)[0] + desc = check_for_desc_override(basename) + if desc is None: + desc = get_desc(cmd) + f.write(desc1_tmpl.substitute(basename=basename, desc=desc)) + f.write("\n") -# for all module groups: -for cls in classes: - f.write(cmd2_tmpl.substitute(cmd=cls)) - # for all modules: - for cmd in rest_files(cls): - basename = os.path.splitext(cmd)[0] - desc = check_for_desc_override(basename) - if desc is None: - desc = get_desc(cmd) - f.write(desc1_tmpl.substitute(basename=basename, desc=desc)) - f.write("\n") + write_rest_footer(f, "index.txt") -write_rest_footer(f, "index.txt") - -f.close() replace_file(filename) diff --git a/man/build_html.py b/man/build_html.py index db5a424c738..08596bb169c 100644 --- a/man/build_html.py +++ b/man/build_html.py @@ -1,5 +1,6 @@ import os import string +from pathlib import Path # File template pieces follow @@ -406,25 +407,25 @@ def get_desc(cmd): - f = open(cmd) - while True: - line = f.readline() - if not line: - return "" - if "NAME" in line: - break - - while True: - line = f.readline() - if not line: - return "" - if "SYNOPSIS" in line: - break - if "" in line: - sp = line.split("-", 1) - if len(sp) > 1: - return sp[1].strip() - return None + with Path(cmd).open() as f: + while True: + line = f.readline() + if not line: + return "" + if "NAME" in line: + break + + while True: + line = f.readline() + if not line: + return "" + if "SYNOPSIS" in line: + break + if "" in line: + sp = line.split("-", 1) + if len(sp) > 1: + return sp[1].strip() + return None return "" diff --git a/man/build_index_rest.py b/man/build_index_rest.py index b919042e4af..0986838b19f 100644 --- a/man/build_index_rest.py +++ b/man/build_index_rest.py @@ -21,11 +21,9 @@ os.chdir(rest_dir) filename = "index.txt" -f = open(filename + ".tmp", "w") +with open(filename + ".tmp", "w") as f: + write_rest_header(f, "GRASS GIS %s Reference Manual" % grass_version, True) + write_rest_cmd_overview(f) + write_rest_footer(f, "index.txt") -write_rest_header(f, "GRASS GIS %s Reference Manual" % grass_version, True) -write_rest_cmd_overview(f) -write_rest_footer(f, "index.txt") - -f.close() replace_file(filename) diff --git a/man/build_keywords.py b/man/build_keywords.py index 5793bb9b4d3..546eed62f37 100644 --- a/man/build_keywords.py +++ b/man/build_keywords.py @@ -133,62 +133,59 @@ def build_keywords(ext): if key.lower() < char_list[str(firstchar)].lower(): char_list[str(firstchar.lower())] = key - keywordsfile = open(os.path.join(man_dir, f"keywords.{ext}"), "w") - keywordsfile.write( - header1_tmpl.substitute( - title=f"GRASS GIS {grass_version} Reference Manual - Keywords index" + with open(os.path.join(man_dir, f"keywords.{ext}"), "w") as keywordsfile: + keywordsfile.write( + header1_tmpl.substitute( + title=f"GRASS GIS {grass_version} Reference Manual - Keywords index" + ) ) - ) - keywordsfile.write(headerkeywords_tmpl) - if ext == "html": - keywordsfile.write("
") - sortedKeys = sorted(keywords.keys(), key=lambda s: s.lower()) - - for key in sortedKeys: + keywordsfile.write(headerkeywords_tmpl) if ext == "html": - keyword_line = ( - '
{key}
'.format( - key=key - ) - ) - else: - keyword_line = f"### **{key}**\n" - for value in sorted(keywords[key]): - man_file_path = get_module_man_file_path(man_dir, value, addons_man_files) + keywordsfile.write("
") + sortedKeys = sorted(keywords.keys(), key=lambda s: s.lower()) + + for key in sortedKeys: if ext == "html": - keyword_line += ( - f' {value.replace(f".{ext}", "")},' + keyword_line = '
{key}
'.format( # noqa: E501 + key=key ) else: - keyword_line += f' [{value.rsplit(".", 1)[0]}]({man_file_path}),' - keyword_line = keyword_line.rstrip(",") + keyword_line = f"### **{key}**\n" + for value in sorted(keywords[key]): + man_file_path = get_module_man_file_path( + man_dir, value, addons_man_files + ) + if ext == "html": + keyword_line += f' {value.replace(f".{ext}", "")},' # noqa: E501 + else: + keyword_line += f' [{value.rsplit(".", 1)[0]}]({man_file_path}),' + keyword_line = keyword_line.rstrip(",") + if ext == "html": + keyword_line += "
" + keyword_line += "\n" + keywordsfile.write(keyword_line) if ext == "html": - keyword_line += "
" - keyword_line += "\n" - keywordsfile.write(keyword_line) - if ext == "html": - keywordsfile.write("
\n") - if ext == "html": - # create toc - toc = '
\n

Table of contents

' - test_length = 0 - all_keys = len(char_list.keys()) - for k in sorted(char_list.keys()): - test_length += 1 - # toc += '

  • %s
  • ' % (char_list[k], k) - 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) - elif test_length == all_keys: - toc += '%s' % (char_list[k], k) - else: - toc += '%s, ' % (char_list[k], k) - toc += "

    \n" - keywordsfile.write(toc) - - write_footer(keywordsfile, f"index.{ext}", year, template=ext) - keywordsfile.close() + keywordsfile.write("\n") + if ext == "html": + # create toc + toc = '
    \n

    Table of contents

    ' # noqa: E501 + test_length = 0 + all_keys = len(char_list.keys()) + for k in sorted(char_list.keys()): + test_length += 1 + # toc += '

  • %s
  • ' % (char_list[k], k) + 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) + elif test_length == all_keys: + toc += '%s' % (char_list[k], k) + else: + toc += '%s, ' % (char_list[k], k) + toc += "

    \n" + keywordsfile.write(toc) + + write_footer(keywordsfile, f"index.{ext}", year, template=ext) if __name__ == "__main__": diff --git a/man/build_rest.py b/man/build_rest.py index a98a099a076..20d9e9aaca1 100644 --- a/man/build_rest.py +++ b/man/build_rest.py @@ -13,6 +13,7 @@ import os import string +from pathlib import Path # TODO: better fix this in include/Make/Rest.make, see bug RT #5361 @@ -271,16 +272,11 @@ def check_for_desc_override(basename): def read_file(name): - f = open(name) - s = f.read() - f.close() - return s + return Path(name).read_text() def write_file(name, contents): - f = open(name, "w") - f.write(contents) - f.close() + Path(name).write_text(contents) def try_mkdir(path): @@ -337,25 +333,25 @@ def write_rest_footer(f, index_url): def get_desc(cmd): - f = open(cmd) - while True: - line = f.readline() - if not line: - return "" - if "NAME" in line: - break - - while True: - line = f.readline() - if not line: - return "" - if "SYNOPSIS" in line: - break - if "*" in line: - sp = line.split("-", 1) - if len(sp) > 1: - return sp[1].strip() - return None + with Path(cmd).open() as f: + while True: + line = f.readline() + if not line: + return "" + if "NAME" in line: + break + + while True: + line = f.readline() + if not line: + return "" + if "SYNOPSIS" in line: + break + if "*" in line: + sp = line.split("-", 1) + if len(sp) > 1: + return sp[1].strip() + return None return "" diff --git a/man/build_topics.py b/man/build_topics.py index fa4d683f117..a19251cf90f 100644 --- a/man/build_topics.py +++ b/man/build_topics.py @@ -5,6 +5,7 @@ import os import glob +from pathlib import Path year = os.getenv("VERSION_DATE") @@ -35,9 +36,9 @@ def build_topics(ext): files = glob.glob1(man_dir, f"*.{ext}") for fname in files: - fil = open(os.path.join(man_dir, fname)) - # TODO maybe move to Python re (regex) - lines = fil.readlines() + with Path(man_dir, fname).open() as fil: + # TODO maybe move to Python re (regex) + lines = fil.readlines() try: if ext == "html": index_keys = lines.index("

    KEYWORDS

    \n") + 1 @@ -68,63 +69,71 @@ def build_topics(ext): elif fname not in keywords[key]: keywords[key][fname] = desc - topicsfile = open(os.path.join(man_dir, f"topics.{ext}"), "w") - topicsfile.write( - header1_tmpl.substitute( - title="GRASS GIS %s Reference Manual - Topics index" % grass_version + with Path(man_dir, f"topics.{ext}").open("w") as topicsfile: + topicsfile.write( + header1_tmpl.substitute( + title="GRASS GIS %s Reference Manual - Topics index" % grass_version + ) ) - ) - topicsfile.write(headertopics_tmpl) + topicsfile.write(headertopics_tmpl) + + for key, values in sorted(keywords.items(), key=lambda s: s[0].lower()): + with Path(man_dir, f"topic_%s.{ext}" % key).open("w") as keyfile: + if ext == "html": + keyfile.write( + header1_tmpl.substitute( + title="GRASS GIS " + "%s Reference Manual: Topic %s" + % (grass_version, key.replace("_", " ")) + ) + ) + keyfile.write(headerkey_tmpl.substitute(keyword=key.replace("_", " "))) + num_modules = 0 + for mod, desc in sorted(values.items()): + num_modules += 1 + keyfile.write( + desc1_tmpl.substitute( + cmd=mod, desc=desc, basename=mod.replace(f".{ext}", "") + ) + ) + if num_modules >= min_num_modules_for_topic: + topicsfile.writelines( + [ + moduletopics_tmpl.substitute( + key=key, name=key.replace("_", " ") + ) + ] + ) + if ext == "html": + keyfile.write("\n") + else: + keyfile.write("\n") + # link to the keywords index + # TODO: the labels in keywords index are with spaces and capitals + # this should be probably changed to lowercase with underscores + if ext == "html": + keyfile.write( + "

    See also the corresponding keyword" + ' {key}' + " for additional references.".format( + key=key.replace("_", " ") + ) + ) + else: + # expecting markdown + keyfile.write( + "*See also the corresponding keyword" + " [{key}](keywords.md#{key})" + " for additional references.*\n".format( + key=key.replace("_", " ") + ) + ) + + write_footer(keyfile, f"index.{ext}", year, template=ext) - for key, values in sorted(keywords.items(), key=lambda s: s[0].lower()): - keyfile = open(os.path.join(man_dir, f"topic_%s.{ext}" % key), "w") - if ext == "html": - keyfile.write( - header1_tmpl.substitute( - title="GRASS GIS " - "%s Reference Manual: Topic %s" - % (grass_version, key.replace("_", " ")) - ) - ) - keyfile.write(headerkey_tmpl.substitute(keyword=key.replace("_", " "))) - num_modules = 0 - for mod, desc in sorted(values.items()): - num_modules += 1 - keyfile.write( - desc1_tmpl.substitute( - cmd=mod, desc=desc, basename=mod.replace(f".{ext}", "") - ) - ) - if num_modules >= min_num_modules_for_topic: - topicsfile.writelines( - [moduletopics_tmpl.substitute(key=key, name=key.replace("_", " "))] - ) if ext == "html": - keyfile.write("\n") - else: - keyfile.write("\n") - # link to the keywords index - # TODO: the labels in keywords index are with spaces and capitals - # this should be probably changed to lowercase with underscores - if ext == "html": - keyfile.write( - "

    See also the corresponding keyword" - ' {key}' - " for additional references.".format(key=key.replace("_", " ")) - ) - else: - # expecting markdown - keyfile.write( - "*See also the corresponding keyword" - " [{key}](keywords.md#{key})" - " for additional references.*\n".format(key=key.replace("_", " ")) - ) - - write_footer(keyfile, f"index.{ext}", year, template=ext) - if ext == "html": - topicsfile.write("\n") - write_footer(topicsfile, f"index.{ext}", year, template=ext) - topicsfile.close() + topicsfile.write("\n") + write_footer(topicsfile, f"index.{ext}", year, template=ext) if __name__ == "__main__": diff --git a/pyproject.toml b/pyproject.toml index c550cf71faa..85ad3e1283e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -259,6 +259,7 @@ ignore = [ # See https://docs.astral.sh/ruff/settings/#lint_per-file-ignores # "A005", # builtin-module-shadowing # "PLW0108", # unnecessary-lambda +# "SIM115", # open-file-with-context-handler # Ignore `E402` (import violations) in all `__init__.py` files "**.py" = ["PYI066"] "*/testsuite/**.py" = ["PT009", "PT027"] @@ -299,8 +300,6 @@ ignore = [ "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"]