From ce095db7d80140530cb1d84afabed991598e7660 Mon Sep 17 00:00:00 2001
From: Timo Koch <timo.koch@iws.uni-stuttgart.de>
Date: Fri, 30 Jul 2021 23:04:46 +0200
Subject: [PATCH] [bin][python] Make flake8 happy and add to CI

---
 .flake8                                       |  3 +
 .gitlab-ci/default.yml                        |  1 +
 bin/doc/getparameterlist.py                   | 28 +++----
 bin/installdumux.py                           | 27 ++++---
 bin/installexternal.py                        | 35 ++++----
 bin/postprocessing/exportscreenshot2d.py      | 65 +++++++++------
 bin/postprocessing/extractlinedata.py         | 16 ++--
 .../extractpointdataovertime.py               | 18 +++--
 bin/postprocessing/l2error.py                 |  7 +-
 bin/remove_clutter_after_last_endif.py        |  1 +
 bin/testing/fuzzycomparedata.py               | 12 +--
 bin/testing/fuzzycomparevtu.py                | 79 ++++++++++---------
 bin/testing/runtest.py                        | 27 +++++--
 bin/util/common.py                            |  1 -
 bin/util/installscript.py                     |  2 +-
 bin/util/installscript_writer.py              |  6 +-
 16 files changed, 197 insertions(+), 131 deletions(-)

diff --git a/.flake8 b/.flake8
index a41b8c9c4d..4cf0f63e70 100644
--- a/.flake8
+++ b/.flake8
@@ -1,4 +1,7 @@
 [flake8]
+ignore = 
+    # Ignore whitespace before colon which gives false positive for list slice (black does it correct)
+    E203
 max-line-length = 100
 per-file-ignores =
     # imported but unused and unable to detect undefined names
diff --git a/.gitlab-ci/default.yml b/.gitlab-ci/default.yml
index 93b3c5c5f0..ff98f7be11 100644
--- a/.gitlab-ci/default.yml
+++ b/.gitlab-ci/default.yml
@@ -51,6 +51,7 @@ pylint-flake8 (python):
       if [ -d build-cmake/python/dumux ] ; then
         pylint --rcfile=.pylintrc build-cmake/python/dumux
         flake8 build-cmake/python/dumux
+        flake8 bin
       fi
   needs:
     - job: configure
diff --git a/bin/doc/getparameterlist.py b/bin/doc/getparameterlist.py
index 8f6b474ec7..7a9afefe51 100644
--- a/bin/doc/getparameterlist.py
+++ b/bin/doc/getparameterlist.py
@@ -7,6 +7,7 @@ for usage of getParam or getParamFromGroup.
 
 import os
 
+
 # find the content of the given string between the first matching pair of opening/closing keys
 def getEnclosedContent(string, openKey, closeKey):
 
@@ -91,9 +92,9 @@ def getParamsFromFile(file):
     # print encountered errors
     if errors:
         print(
-            "\n\n{} parameter{} in file {} could not be retrieved automatically. Please check them yourself:".format(
-                len(errors), "s" if len(errors) > 1 else "", file
-            )
+            f"\n\n{len(errors)} parameter{'s' if len(errors) > 1 else ''}"
+            f"in file {file} could not be retrieved automatically. "
+            "Please check them yourself:"
         )
         for lineIdx in errors:
             print("\n\t-> line {}: {}".format(lineIdx, errors[lineIdx]["line"]))
@@ -140,7 +141,9 @@ for key in parameterDict:
     groupEntry = "-" if not hasGroup else entry["paramName"].split(".")[0]
     paramName = entry["paramName"] if not hasGroup else entry["paramName"].partition(".")[2]
 
-    # In case of multiple occurrences, we use the first entry that is not None and print the others for possible manual editing
+    # In case of multiple occurrences,
+    # we use the first entry that is not None
+    # and print the others for possible manual editing
     paramType = entry["paramType"][0]
     defaultValue = next((e for e in entry["defaultValue"] if e), "-")
 
@@ -154,27 +157,24 @@ for key in parameterDict:
     )
     if hasMultiplePT or hasMultipleDV:
         print(
-            "\nFound multiple occurrences of parameter "
-            + paramName
-            + " with differing specifications: "
+            f"\nFound multiple occurrences of parameter {paramName}",
+            " with differing specifications: "
         )
     if hasMultiplePT:
         print(" -> Specified type names:")
         for typeName in entry["paramType"]:
             print(" " * 8 + typeName)
         print(
-            " ---> For the parameters list, "
-            + paramType
-            + " has been chosen. Please adapt manually if desired."
+            " ---> For the parameters list, {paramType}"
+            " has been chosen. Please adapt manually if desired."
         )
     if hasMultipleDV:
         print(" -> Specified default values:")
         for default in entry["defaultValue"]:
             print(" " * 8 + (default if default else "- (none given)"))
         print(
-            " ---> For the parameters list, "
-            + defaultValue
-            + " has been chosen. Please adapt manually if desired."
+            f" ---> For the parameters list, {defaultValue}"
+            " has been chosen. Please adapt manually if desired."
         )
 
     maxGroupWidth = max(maxGroupWidth, len(groupEntry) + 3)  # +3 because \b will be added later
@@ -219,7 +219,7 @@ tableEntries = tableEntriesWithoutGroup + tableEntriesWithGroup
 
 header = """/*!
  *\\file
- *\ingroup Parameter
+ *\\ingroup Parameter
  *
  *\\brief List of currently useable run-time parameters
  *
diff --git a/bin/installdumux.py b/bin/installdumux.py
index 5ff12c02eb..4ccafe1bc1 100755
--- a/bin/installdumux.py
+++ b/bin/installdumux.py
@@ -7,6 +7,7 @@ import os
 import sys
 import argparse
 import subprocess
+import textwrap
 from distutils.spawn import find_executable
 from distutils.version import LooseVersion
 
@@ -65,14 +66,17 @@ def run_command(command, workdir="."):
             print(line, end="")
         popen.stdout.close()
         popen.stderr.close()
-        return_code = popen.wait()
-        if return_code:
-            print("\n")
-            message = "\n    (Error) The command {} returned with non-zero exit code\n".format(
-                command
+        returnCode = popen.wait()
+        if returnCode:
+            message = textwrap.dedent(
+                f"""\
+
+                (Error) The command {command} returned with non-zero exit code
+                  If you can't fix the problem yourself consider reporting your issue
+                  on the mailing list (dumux@listserv.uni-stuttgart.de) and
+                  attach the file 'installdumux.log'
+            """
             )
-            message += "\n    If you can't fix the problem yourself consider reporting your issue\n"
-            message += "    on the mailing list (dumux@listserv.uni-stuttgart.de) and attach the file 'installdumux.log'\n"
             show_message(message)
             sys.exit(1)
 
@@ -125,7 +129,8 @@ os.makedirs("./dumux", exist_ok=True)
 os.chdir("dumux")
 
 show_message(
-    "(2/3) Cloning repositories. This may take a while. Make sure to be connected to the internet..."
+    "(2/3) Cloning repositories. This may take a while. "
+    "Make sure to be connected to the internet..."
 )
 
 # the core modules
@@ -152,7 +157,8 @@ show_message("(2/3) Step completed. All repositories have been cloned into a con
 #################################################################
 #################################################################
 show_message(
-    "(3/3) Configure and build dune modules and dumux using dunecontrol. This may take several minutes..."
+    "(3/3) Configure and build dune modules and dumux using dunecontrol. "
+    "This may take several minutes..."
 )
 
 # run dunecontrol
@@ -172,7 +178,8 @@ else:
     test_path += "/implicit/isothermal"
 
 show_message(
-    "(Installation complete) To test if everything works, please run the following commands (can be copied to command line):\n\n"
+    "(Installation complete) To test if everything works, "
+    "please run the following commands (can be copied to command line):\n\n"
     "  cd {}\n"
     "  make test_1p_tpfa\n"
     "  ./test_1p_tpfa\n"
diff --git a/bin/installexternal.py b/bin/installexternal.py
index d99a9e261c..416fcfacd9 100755
--- a/bin/installexternal.py
+++ b/bin/installexternal.py
@@ -4,13 +4,14 @@
 install external stuff for dumux
 """
 import os
-import urllib.request
+import shutil
+import re
+import urllib
 import tarfile
 import sys
 import subprocess
-import shutil
-import re
 import argparse
+import textwrap
 
 
 class ChoicesAction(argparse._StoreAction):
@@ -38,7 +39,8 @@ def show_message(message):
 
 if len(sys.argv) == 1:
     show_message(
-        "No options given. For more information run the following command: \n ./installexternal.py --help"
+        "No options given. For more information "
+        "run the following command: \n ./installexternal.py --help"
     )
     sys.exit()
 
@@ -111,11 +113,14 @@ def run_command(command, currentdir="."):
         return_code = popen.wait()
         if return_code:
             print("\n")
-            message = "\n    (Error) The command {} returned with non-zero exit code\n".format(
-                command
+            message = textwrap.dedent(
+                f"""\
+                (Error) The command {command} returned with non-zero exit code
+                  If you can't fix the problem yourself consider reporting your issue
+                  on the mailing list (dumux@listserv.uni-stuttgart.de) and
+                  attach the file 'installexternal.log'
+            """
             )
-            message += "\n    If you can't fix the problem yourself consider reporting your issue\n"
-            message += "    on the mailing list (dumux@listserv.uni-stuttgart.de) and attach the file 'installexternal.log'\n"
             show_message(message)
             sys.exit(1)
 
@@ -124,7 +129,7 @@ def git_clone(url, branch=None):
     clone = ["git", "clone"]
     if branch:
         clone += ["-b", branch]
-    result = run_command(command=[*clone, url])
+    run_command(command=[*clone, url])
 
 
 def install_external(args):
@@ -244,7 +249,7 @@ def install_external(args):
                         run_command(configcmd, currentdir=ext_dir)
                         try:
                             run_command("make", currentdir=ext_dir)
-                        except:
+                        except subprocess.CalledProcessError:
                             raise Exception("{} installation has failed.".format(package))
                         # Save message to be shown at the end
                         if os.path.exists(ext_dir + "/" + package):
@@ -281,7 +286,9 @@ def install_external(args):
     # Save post installation message about dunecontrol if need be.
     if not cleanup and any(x in pkg for pkg in packages for x in ["dumux", "dune", "opm"]):
         final_message.append(
-            "\n\nPlease run the following command (can be copied to command line):\n\n  ./dune-common/bin/dunecontrol --opts=./dumux/cmake.opts all"
+            "\n\nPlease run the following command "
+            "(can be copied to command line):\n\n  "
+            "./dune-common/bin/dunecontrol --opts=./dumux/cmake.opts all"
         )
 
     # If cleanup and only logfile in the external directory, remove the directory
@@ -295,7 +302,7 @@ def install_external(args):
 
 #################################################################
 #################################################################
-## (1/3) Define th necessary packages and their urls
+# (1/3) Define th necessary packages and their urls
 #################################################################
 #################################################################
 dune_git_baseurl = "https://gitlab.dune-project.org/"
@@ -362,7 +369,7 @@ messages = {
 
 #################################################################
 #################################################################
-## (2/3) Download/Config/Clean the requested packages
+# (2/3) Download/Config/Clean the requested packages
 #################################################################
 #################################################################
 # Start download/configuration/cleaning tasks
@@ -370,7 +377,7 @@ final_message = install_external(args)
 
 #################################################################
 #################################################################
-## (3/3) Show the final message
+# (3/3) Show the final message
 #################################################################
 #################################################################
 # Show final message
diff --git a/bin/postprocessing/exportscreenshot2d.py b/bin/postprocessing/exportscreenshot2d.py
index 2032ff41a1..8ff909a342 100644
--- a/bin/postprocessing/exportscreenshot2d.py
+++ b/bin/postprocessing/exportscreenshot2d.py
@@ -1,20 +1,42 @@
-#### TODO:
-# - different colors for legend
-# - read-in pvds with time outputs
-# - read-in multiple vtus, e.g. for multidomain
-# - rendering method 2d and 3d
+"""
+Script for exporting 2d screenshots from ParaView
+
+TODO:
+- different colors for legend
+- read-in pvds with time outputs
+- read-in multiple vtus, e.g. for multidomain
+- rendering method 2d and 3d
+"""
 
 # parse arguments
 import argparse
 import os
 import sys
 
+try:
+    from paraview.simple import (
+        XMLUnstructuredGridReader,
+        GetActiveView,
+        CreateRenderView,
+        Show,
+        ColorBy,
+        GetColorTransferFunction,
+        GetScalarBar,
+        RenderAllViews,
+        SaveScreenshot,
+    )
+except ImportError:
+    print("`paraview.simple` not found. Make sure using pvbatch.")
+
 bool = ["True", "False"]
 parameterType = ["CELLS", "POINTS"]
 legendOrientation = ["Horizontal", "Vertical"]
 parser = argparse.ArgumentParser(
     prog="\033[1m\033[94m" + "pvbatch" + "\033[0m" + " " + sys.argv[0],
-    description="Export a screenshot of a standard 2D plot. To change the color palette, change the default in the paraview GUI.",
+    description=(
+        "Export a screenshot of a standard 2D plot. "
+        "To change the color palette, change the default in the paraview GUI."
+    ),
 )
 # on/off-type features
 offscreen = parser.add_mutually_exclusive_group(required=False)
@@ -158,11 +180,6 @@ parser.add_argument(
 parser.add_argument("-v", "--verbosity", type=int, default=2, help="Verbosity of the output")
 args = vars(parser.parse_args())
 
-try:
-    from paraview.simple import *
-except ImportError:
-    print("`paraview.simple` not found. Make sure using pvbatch.")
-
 # import locations
 commonOutDirectory = False
 outDirectory = args["outputDirectory"]
@@ -189,7 +206,8 @@ for curFile in args["files"]:
     vtuFile = XMLUnstructuredGridReader(FileName=curFile)
     if args["parameter"] == "":
         print(
-            "\nNo parameter was specified, use '-p PARAMETER' to specify it. Available parameters are:"
+            "\nNo parameter was specified, use '-p PARAMETER' to specify it. "
+            "Available parameters are:"
         )
         if args["parameterType"] == "CELLS":
             print(vtuFile.CellArrayStatus)
@@ -204,18 +222,19 @@ for curFile in args["files"]:
         renderView1 = CreateRenderView()
 
     # print additional help message for large picture sizes
-    if (args["size"][0] > 1024 or args["size"][1] > 1024) and args["offscreen"] == False:
-        print(
-            "\nIt seems like you want to export a picture greater then your actual screen size. Use:"
+    if (args["size"][0] > 1024 or args["size"][1] > 1024) and not args["offscreen"]:
+        raise IOError(
+            "\nIt seems like you want to export a picture greater "
+            "than your actual screen size. Use:\n"
+            "pvbatch --use-offscreen-rendering SCRIPT OPTIONS --offscreen"
         )
-        print("pvbatch --use-offscreen-rendering SCRIPT OPTIONS --offscreen")
-        exit(2)
+
     renderView1.ViewSize = args["size"]
 
-    if args["showOrientationAxes"] == False:
+    if not args["showOrientationAxes"]:
         renderView1.OrientationAxesVisibility = 0
 
-    if args["showAxesGrid"] == True:
+    if args["showAxesGrid"]:
         renderView1.AxesGrid.Visibility = 1
 
     # show data in view
@@ -229,7 +248,7 @@ for curFile in args["files"]:
     ColorBy(vtuFileDisplay, (args["parameterType"], args["parameter"]))
 
     # show color bar/color legend
-    if args["showLegend"] == True:
+    if args["showLegend"]:
         vtuFileDisplay.SetScalarBarVisibility(renderView1, True)
 
     # get color transfer function/color map for the parameter
@@ -241,7 +260,7 @@ for curFile in args["files"]:
         parameterLUT.VectorComponent = args["parameterComponent"]
         # if args['parameterRange'][0] == 0 and args['parameterRange'][1] == 0:
         # vtuFileDisplay.RescaleTransferFunctionToDataRange(False)
-        if args["showLegend"] == True:
+        if args["showLegend"]:
             velocityLUTColorBar = GetScalarBar(parameterLUT, renderView1)
             velocityLUTColorBar.Title = args["parameter"]
             velocityLUTColorBar.ComponentTitle = str(args["parameterComponent"])
@@ -272,11 +291,11 @@ for curFile in args["files"]:
         legend.ComponentTitle = args["legendComponentTitle"]
 
     # set a white background color and black color for fonts and the grid
-    if args["whiteBackground"] == True:
+    if args["whiteBackground"]:
         renderView1.Background = [255, 255, 255]
         legend.TitleColor = [0.0, 0.0, 0.0]
         legend.LabelColor = [0.0, 0.0, 0.0]
-        if args["showAxesGrid"] == True:
+        if args["showAxesGrid"]:
             renderView1.AxesGrid.GridColor = [0.0, 0.0, 0.0]
             renderView1.AxesGrid.XTitleColor = [0.0, 0.0, 0.0]
             renderView1.AxesGrid.YTitleColor = [0.0, 0.0, 0.0]
diff --git a/bin/postprocessing/extractlinedata.py b/bin/postprocessing/extractlinedata.py
index 7f5a7817d1..041fb6e1c7 100644
--- a/bin/postprocessing/extractlinedata.py
+++ b/bin/postprocessing/extractlinedata.py
@@ -3,6 +3,17 @@ import csv
 import sys
 import os
 
+try:
+    from paraview.simple import (
+        XMLPolyDataReader,
+        XMLUnstructuredGridReader,
+        SetActiveSource,
+        PlotOverLine,
+        CreateWriter,
+    )
+except ImportError:
+    raise ImportError("`paraview.simple` not found. Make sure using pvpython instead of python.")
+
 # parse arguments
 parser = argparse.ArgumentParser(
     prog="\033[1m\033[94m" + "pvpython" + "\033[0m" + " " + sys.argv[0],
@@ -48,11 +59,6 @@ parser.add_argument(
 )
 args = vars(parser.parse_args())
 
-try:
-    from paraview.simple import *
-except:
-    raise ImportError("`paraview.simple` not found. Make sure using pvpython instead of python.")
-
 # import locations
 outDirectory = args["outputDirectory"]
 if outDirectory.strip():
diff --git a/bin/postprocessing/extractpointdataovertime.py b/bin/postprocessing/extractpointdataovertime.py
index 6c4132dad6..1063c86463 100644
--- a/bin/postprocessing/extractpointdataovertime.py
+++ b/bin/postprocessing/extractpointdataovertime.py
@@ -3,6 +3,19 @@ import csv
 import os
 import sys
 
+try:
+    from paraview.simple import (
+        PVDReader,
+        IDSelectionSource,
+        ExtractSelection,
+        servermanager,
+        ProbeLocation,
+        PlotSelectionOverTime,
+        CreateWriter,
+    )
+except ImportError:
+    print("`paraview.simple` not found. Make sure using pvpython instead of python.")
+
 # parse arguments
 parser = argparse.ArgumentParser(
     prog="\033[1m\033[94m" + "pvpython" + "\033[0m" + " " + sys.argv[0],
@@ -33,11 +46,6 @@ parser.add_argument(
 )
 args = vars(parser.parse_args())
 
-try:
-    from paraview.simple import *
-except ImportError:
-    print("`paraview.simple` not found. Make sure using pvpython instead of python.")
-
 # import locations
 commonOutDirectory = False
 outDirectory = args["outputDirectory"]
diff --git a/bin/postprocessing/l2error.py b/bin/postprocessing/l2error.py
index cc75447368..bd1c1a0675 100644
--- a/bin/postprocessing/l2error.py
+++ b/bin/postprocessing/l2error.py
@@ -122,10 +122,9 @@ for i in range(1, len(reference)):
             float(reference[2][indexReferenceX]) - float(reference[1][indexReferenceX])
         )
     elif i == len(reference) - 1:
-        distance = 0.5 * (
-            float(reference[len(reference) - 1][indexReferenceX])
-            - float(reference[len(reference) - 2][indexReferenceX])
-        )
+        distA = float(reference[len(reference) - 1][indexReferenceX])
+        distB = float(reference[len(reference) - 2][indexReferenceX])
+        distance = 0.5 * (distA - distB)
     else:
         distance = 0.5 * (
             float(reference[i + 1][indexReferenceX]) - float(reference[i - 1][indexReferenceX])
diff --git a/bin/remove_clutter_after_last_endif.py b/bin/remove_clutter_after_last_endif.py
index 84b8e6900f..c21bbff427 100644
--- a/bin/remove_clutter_after_last_endif.py
+++ b/bin/remove_clutter_after_last_endif.py
@@ -1,6 +1,7 @@
 #!/usr/bin/env python3
 import os
 
+
 # replace everything after last #endif with new line
 def clearAfterLastEndIf(filename):
     with open(filename, "r") as header:
diff --git a/bin/testing/fuzzycomparedata.py b/bin/testing/fuzzycomparedata.py
index a8625668d8..5d2207eb66 100644
--- a/bin/testing/fuzzycomparedata.py
+++ b/bin/testing/fuzzycomparedata.py
@@ -46,11 +46,10 @@ def compare_data(
     """
 
     if verbose:
-        print("Comparing {} and {}".format(dataFile1, dataFile2))
         print(
-            "... with a maximum relative error of {} and a maximum absolute error of {}*max_abs_parameter_value.".format(
-                relative, absolute
-            )
+            f"Comparing {dataFile1} and {dataFile2}\n"
+            f"... with a maximum relative error of {relative} and "
+            f"a maximum absolute error of {absolute}*max_abs_parameter_value."
         )
 
     # construct element tree from data files
@@ -116,7 +115,10 @@ if __name__ == "__main__":
         "--zeroThreshold",
         type=json.loads,
         default="{}",
-        help='Thresholds for treating numbers as zero for a parameter as a python dict e.g. {"vel":1e-7,"delP":1.0}',
+        help=(
+            "Thresholds for treating numbers as zero for a parameter as a python dict "
+            'e.g. {"vel":1e-7,"delP":1.0}'
+        ),
     )
     args = vars(parser.parse_args())
 
diff --git a/bin/testing/fuzzycomparevtu.py b/bin/testing/fuzzycomparevtu.py
index c42923a97a..f8c04e311e 100644
--- a/bin/testing/fuzzycomparevtu.py
+++ b/bin/testing/fuzzycomparevtu.py
@@ -12,11 +12,9 @@ import json
 import sys
 import math
 import os
-import re
-import glob
 import functools
 
-# fuzzy compare VTK tree from VTK strings
+
 def compare_vtk(vtk1, vtk2, absolute=1.5e-7, relative=1e-2, zeroValueThreshold={}, verbose=True):
     """take two vtk files and compare them. Returns an exit key as returnvalue.
 
@@ -63,11 +61,10 @@ def compare_vtk(vtk1, vtk2, absolute=1.5e-7, relative=1e-2, zeroValueThreshold={
     sortedroot2 = sort_vtk(root2)
 
     if verbose:
-        print("Comparing {} and {}".format(vtk1, vtk2))
         print(
-            "... with a maximum relative error of {} and a maximum absolute error of {}*max_abs_parameter_value.".format(
-                relative, absolute
-            )
+            f"Comparing {vtk1} and {vtk2}\n"
+            f"... with a maximum relative error of {relative} and "
+            f"a maximum absolute error of {absolute}*max_abs_parameter_value."
         )
 
     # sort the vtk file so that the comparison is independent of the
@@ -150,7 +147,8 @@ def convert_pvtu_to_vtu(pvturoot, filename):
             newvalue = " " + str(int(value) + offsets_offset) + " "
             rootOffsets.text += newvalue
 
-        # compute offset for the connectivity vector (it's the number of points of the current root piece)
+        # compute offset for the connectivity vector
+        # (it's the number of points of the current root piece)
         rootNumPoints = int(root.findall(".//Piece")[0].attrib["NumberOfPoints"])
         rootNumCells = int(root.findall(".//Piece")[0].attrib["NumberOfCells"])
 
@@ -177,7 +175,10 @@ def convert_pvtu_to_vtu(pvturoot, filename):
         root.findall(".//Piece")[0].attrib["NumberOfCells"] = str(newNumCells)
 
     # for debugging the merged vtu file can be written out and viewed in paraview
-    # testname = os.path.join(dirname, "comparisontemp-" + os.path.basename(pvturoot.findall(".//Piece")[0].attrib["Source"]))
+    # sourcename = pvturoot.findall(".//Piece")[0].attrib["Source"]
+    # testname = os.path.join(
+    #     dirname, "comparisontemp-" + os.path.basename(vtuname)
+    # )
     # vtu = ET.ElementTree(root)
     # vtu.write(testname)
 
@@ -214,7 +215,7 @@ def is_fuzzy_equal_node(
             else:
                 return False
         if node1child.text or node2child.text:
-            if node1child.get("NumberOfComponents") == None:
+            if node1child.get("NumberOfComponents") is None:
                 numberOfComponents = 1
             else:
                 numberOfComponents = int(node1child.attrib["NumberOfComponents"])
@@ -267,7 +268,8 @@ def is_fuzzy_equal_text(
         lists2.append(list2[i::numComp])
         if numComp > 1:
             parameters.append("{}_{}".format(parameter, i))
-            # if zero threshold was set for all components one component inherits it from the parameter
+            # if zero threshold was set for all components,
+            # one component inherits it from the parameter
             if parameter in zeroValueThreshold:
                 zeroValueThreshold["{}_{}".format(parameter, i)] = zeroValueThreshold[parameter]
         else:
@@ -293,23 +295,19 @@ def is_fuzzy_equal_text(
                 print("Parameter {} contains inf!".format(parameter))
                 return False
 
-        # manipulate the data set for the sake of sensible comparison
-        # if the parameter is listed in the zeroThreshold dictionary replace all float under threshold with zero.
-        # only replace them with zero if the parameters in both lists are under the threshold. Otherwise we
-        # compare a non-zero value with 0 later.
+        # Manipulate the data set for the sake of sensible comparison.
+        # If the parameter is listed in the zeroThreshold dictionary,
+        # replace all float under threshold with zero.
+        # Only replace them with zero if the parameters in both lists are under the threshold.
+        # Otherwise we compare a non-zero value with 0 later.
         if parameter in zeroValueThreshold:
+            zeroThr = float(zeroValueThreshold[parameter])
             floatList1 = [
-                0.0
-                if abs(i) < float(zeroValueThreshold[parameter])
-                and abs(j) < float(zeroValueThreshold[parameter])
-                else i
+                0.0 if (abs(i) < zeroThr) and (abs(j) < zeroThr) else i
                 for i, j in zip(floatList1, floatList2)
             ]
             floatList2 = [
-                0.0
-                if abs(i) < float(zeroValueThreshold[parameter])
-                and abs(j) < float(zeroValueThreshold[parameter])
-                else j
+                0.0 if (abs(i) < zeroThr) and (abs(j) < zeroThr) else j
                 for i, j in zip(floatList1, floatList2)
             ]
 
@@ -347,18 +345,16 @@ def is_fuzzy_equal_text(
                     return False
 
         if verbose and max_relative_difference != 0.0:
-            print("\nData differs in parameter: {}".format(parameter))
-            print(message)
             print(
-                "Info for {}: max_abs_parameter_value={} and min_abs_parameter_value={}.".format(
-                    parameter, magnitude, minimal
-                )
+                f"\nData differs in parameter: {parameter}\n",
+                message,
+                f"Info for {parameter}: "
+                f"max_abs_parameter_value={magnitude} and min_abs_parameter_value={minimal}.",
             )
             if parameter in zeroValueThreshold:
                 print(
-                    "For parameter {} a zero value threshold of {} was given.".format(
-                        parameter, zeroValueThreshold[parameter]
-                    )
+                    f"For parameter {parameter} a zero value threshold"
+                    f" of {zeroValueThreshold[parameter]} was given."
                 )
 
     return is_equal
@@ -390,7 +386,7 @@ def sort_elements(items, newroot):
         # Create a new item to represent the sorted version
         # of the next item, and copy the tag name and contents
         newitem = ET.Element(item.tag)
-        if item.text and item.text.isspace() == False:
+        if item.text and not item.text.isspace():
             newitem.text = item.text
 
         # Copy the attributes (sorted by key) to the new item
@@ -442,7 +438,7 @@ def sort_vtk_by_coordinates(root1, root2, verbose, convertedFromParallelVtu=Fals
                 cellDataArrays.append(dataArray.attrib["Name"])
             for dataArray in root.findall(".//DataArray"):
                 dataArrays[dataArray.attrib["Name"]] = dataArray.text
-                if dataArray.get("NumberOfComponents") == None:
+                if dataArray.get("NumberOfComponents") is None:
                     numberOfComponents[dataArray.attrib["Name"]] = 1
                 else:
                     numberOfComponents[dataArray.attrib["Name"]] = dataArray.attrib[
@@ -459,7 +455,7 @@ def sort_vtk_by_coordinates(root1, root2, verbose, convertedFromParallelVtu=Fals
             if convertedFromParallelVtu:
                 uniqueIdx = []
                 for i in range(len(coords) // dim):
-                    pos = [float(c) for c in coords[i * dim : i * dim + dim]]
+                    pos = [float(c) for c in coords[(i * dim) : (i * dim + dim)]]
                     if pos in vertexArray:
                         uIdx = vertexArray.index(pos)
                     else:
@@ -468,7 +464,7 @@ def sort_vtk_by_coordinates(root1, root2, verbose, convertedFromParallelVtu=Fals
                     uniqueIdx.append(uIdx)
             else:
                 for i in range(len(coords) // dim):
-                    vertexArray.append([float(c) for c in coords[i * dim : i * dim + dim]])
+                    vertexArray.append([float(c) for c in coords[(i * dim) : (i * dim + dim)]])
 
             # group the cells into vertex index tuples
             cellArray = []
@@ -518,6 +514,7 @@ def sort_vtk_by_coordinates(root1, root2, verbose, convertedFromParallelVtu=Fals
             bBoxMax = max(vertexArray)
             bBoxMin = min(vertexArray)
             epsilon = math.sqrt(sum([(a - b) ** 2 for a, b in zip(bBoxMax, bBoxMin)])) * 1e-7
+
             # first compare by coordinates, if the same compare largestCellMidPointForVertex
             # TODO: is there a more pythonic way?
             def vertex_cmp(a, b):
@@ -550,9 +547,10 @@ def sort_vtk_by_coordinates(root1, root2, verbose, convertedFromParallelVtu=Fals
                 for j, vertexIndex in enumerate(cell):
                     cellArray[i][j] = vertexIndexMap[vertexIndex]
 
-            # sort the indices of all cells in case the two grids have different orientation of the elements
-            # this doesn't necessarily have to be a valid vtk order, it's just temporary for a sorted literal comparison
-            # of the files
+            # Sort the indices of all cells in case the two grids
+            # have different orientation of the elements.
+            # This doesn't necessarily have to be a valid vtk order,
+            # it's just temporary for a sorted literal comparison of the files
             for i, cell in enumerate(cellArray):
                 cellArray[i] = sorted(cell)
 
@@ -633,7 +631,10 @@ if __name__ == "__main__":
         "--zeroThreshold",
         type=json.loads,
         default="{}",
-        help='Thresholds for treating numbers as zero for a parameter as a python dict e.g. {"vel":1e-7,"delP":1.0}',
+        help=(
+            "Thresholds for treating numbers as zero for a parameter as a python dict"
+            'e.g. {"vel":1e-7,"delP":1.0}'
+        ),
     )
     parser.add_argument("-v", "--verbose", dest="verbose", action="store_true")
     parser.add_argument("--no-verbose", dest="verbose", action="store_false")
diff --git a/bin/testing/runtest.py b/bin/testing/runtest.py
index 480a22de32..1b9c7de159 100755
--- a/bin/testing/runtest.py
+++ b/bin/testing/runtest.py
@@ -1,7 +1,8 @@
 #!/usr/bin/env python3
 import argparse
 import shlex
-import os, sys
+import os
+import sys
 import subprocess
 import json
 from fuzzycomparevtu import compare_vtk
@@ -20,13 +21,19 @@ parser.add_argument(
     "-s",
     "--script",
     nargs=1,
-    help="The comparison script. [fuzzy, fuzzyData, exact, <path_to_script>] where the script takes two files as arguments.",
+    help=(
+        "The comparison script. [fuzzy, fuzzyData, exact, <path_to_script>]"
+        " where the script takes two files as arguments."
+    ),
 )
 parser.add_argument(
     "-f",
     "--files",
     nargs="+",
-    help="Pairs of file names (first reference, then current). Usage: '[-f ref1 cur1 [[ref2] [cur2] ...]]'",
+    help=(
+        "Pairs of file names (first reference, then current). "
+        "Usage: '[-f ref1 cur1 [[ref2] [cur2] ...]]'"
+    ),
 )
 parser.add_argument(
     "-d", "--delimiter", type=str, default=",", help="Column delimiter for data files"
@@ -50,7 +57,10 @@ parser.add_argument(
     "--zeroThreshold",
     type=json.loads,
     default="{}",
-    help='Thresholds for treating numbers as zero for a parameter as a python dict e.g. {"vel":1e-7,"delP":1.0}',
+    help=(
+        "Thresholds for treating numbers as zero for"
+        ' a parameter as a python dict e.g. {"vel":1e-7,"delP":1.0}'
+    ),
 )
 args = vars(parser.parse_args())
 
@@ -58,7 +68,8 @@ args = vars(parser.parse_args())
 if args["script"]:
     if len(args["files"]) % 2 != 0 or not args["files"]:
         sys.stderr.write(
-            "The files have to be pairs of reference and current solution files. Usage '-f [ref1] [cur1] [[ref2] [cur2] ...]'"
+            "The files have to be pairs of reference and current solution files."
+            " Usage '-f [ref1] [cur1] [[ref2] [cur2] ...]'"
         )
         parser.print_help()
         sys.exit(1)
@@ -67,7 +78,9 @@ if args["script"]:
         ref_dir = os.path.dirname(os.path.abspath(__file__)).rstrip("bin") + "test/references"
         if os.path.dirname(args["files"][(i * 2) + 1]) == ref_dir:
             sys.stderr.write(
-                "Tried to delete a reference solution. Specify reference file first, then the current solution. Usage: '[-f ref1 cur1 [[ref2] [cur2] ...]]'"
+                "Tried to delete a reference solution. "
+                "Specify reference file first, then the current solution. "
+                "Usage: '[-f ref1 cur1 [[ref2] [cur2] ...]]'"
             )
             sys.exit(1)
         subprocess.call(["rm", "-fv", args["files"][(i * 2) + 1]])
@@ -76,7 +89,7 @@ if args["script"]:
 res = 1
 try:
     res = subprocess.call(shlex.split(args["command"][0]))
-except OSError as e:
+except OSError:
     print(args["command"][0].split())
     print("OSError: Command not found. Most likely the executable specified doesn't exist.")
     sys.exit(1)
diff --git a/bin/util/common.py b/bin/util/common.py
index e8a7dc201d..cf80279391 100644
--- a/bin/util/common.py
+++ b/bin/util/common.py
@@ -5,7 +5,6 @@ import fnmatch
 import functools
 import subprocess
 import traceback
-import datetime
 import shlex
 
 
diff --git a/bin/util/installscript.py b/bin/util/installscript.py
index c65125bd34..10636bcf37 100644
--- a/bin/util/installscript.py
+++ b/bin/util/installscript.py
@@ -185,7 +185,7 @@ def printFinalMessage(scriptName, topFolderName=None):
         )
     else:
         description = textwrap.dedent(
-            f"""\
+            """\
             Running this script will clone all modules into the folder from which it is
             called, configure the entire project and build the contained applications
         """
diff --git a/bin/util/installscript_writer.py b/bin/util/installscript_writer.py
index 72884693de..40e99c0776 100644
--- a/bin/util/installscript_writer.py
+++ b/bin/util/installscript_writer.py
@@ -1,7 +1,5 @@
 """Language-specific backends for install script generation"""
 
-import os
-import sys
 import textwrap
 from abc import ABC, abstractmethod
 from util.common import addPrefixToLines, escapeCharacters
@@ -197,7 +195,9 @@ class InstallScriptWriterPython(InstallScriptWriterInterface):
                     runFromSubFolder(['git', 'checkout', branch], subFolder)
                     runFromSubFolder(['git', 'reset', '--hard', revision], subFolder)
                 else:
-                    print(f'Skip cloning {{url}} since target folder "{{targetFolder}}" already exists.')
+                    print(
+                        f"Skip cloning {{url}} since target "{{targetFolder}}" already exists."
+                    )
 
 
             def applyPatch(subFolder, patch):
-- 
GitLab