From bced838a45ef447b2d55d98b637b5805172aac18 Mon Sep 17 00:00:00 2001
From: markus <markus.holzer@fau.de>
Date: Fri, 19 Jun 2020 17:24:26 +0200
Subject: [PATCH] Replaced all format strings with f-strings

---
 pystencils/assignment.py                      |  2 +-
 pystencils/astnodes.py                        | 20 +++----
 pystencils/backends/cbackend.py               | 58 +++++++++----------
 pystencils/backends/cuda_backend.py           |  4 +-
 pystencils/backends/dot.py                    |  4 +-
 pystencils/backends/opencl_backend.py         |  4 +-
 pystencils/backends/simd_instruction_sets.py  | 16 ++---
 pystencils/boundaries/boundaryhandling.py     | 10 ++--
 pystencils/cpu/cpujit.py                      | 14 ++---
 pystencils/cpu/kernelcreation.py              |  6 +-
 pystencils/cpu/msvc_detection.py              |  2 +-
 pystencils/cpu/vectorization.py               |  2 +-
 pystencils/data_types.py                      |  4 +-
 .../datahandling/parallel_datahandling.py     |  2 +-
 .../datahandling/serial_datahandling.py       |  4 +-
 pystencils/display_utils.py                   |  2 +-
 pystencils/fd/derivation.py                   |  2 +-
 pystencils/fd/derivative.py                   |  2 +-
 pystencils/fd/finitedifferences.py            |  6 +-
 pystencils/field.py                           | 18 +++---
 pystencils/gpucuda/indexing.py                |  2 +-
 pystencils/gpucuda/kernelcreation.py          |  2 +-
 pystencils/integer_set_analysis.py            |  8 +--
 pystencils/interpolation_astnodes.py          |  6 +-
 pystencils/jupyter.py                         | 16 +----
 .../kerncraft_coupling/kerncraft_interface.py |  2 +-
 pystencils/kernelcreation.py                  |  4 +-
 pystencils/kernelparameters.py                |  6 +-
 pystencils/llvm/llvm.py                       |  2 +-
 pystencils/placeholder_function.py            |  2 +-
 pystencils/rng.py                             |  8 +--
 pystencils/runhelper/parameterstudy.py        |  6 +-
 pystencils/simp/assignment_collection.py      |  6 +-
 pystencils/simp/simplificationstrategy.py     |  6 +-
 pystencils/transformations.py                 | 13 ++---
 35 files changed, 129 insertions(+), 142 deletions(-)

diff --git a/pystencils/assignment.py b/pystencils/assignment.py
index 147a829f4..d56d0f4d6 100644
--- a/pystencils/assignment.py
+++ b/pystencils/assignment.py
@@ -53,7 +53,7 @@ else:
             # Tuple of things that can be on the lhs of an assignment
             assignable = (sp.Symbol, MatrixSymbol, MatrixElement, sp.Indexed)
             if not isinstance(lhs, assignable):
-                raise TypeError("Cannot assign to lhs of type %s." % type(lhs))
+                raise TypeError(f"Cannot assign to lhs of type {type(lhs)}.")
             return sp.Rel.__new__(cls, lhs, rhs, **assumptions)
 
         __str__ = assignment_str
diff --git a/pystencils/astnodes.py b/pystencils/astnodes.py
index 4ef40a2c2..eb774543f 100644
--- a/pystencils/astnodes.py
+++ b/pystencils/astnodes.py
@@ -113,12 +113,12 @@ class Conditional(Node):
         return self.__repr__()
 
     def __repr__(self):
-        repr = 'if:({!r}) '.format(self.condition_expr)
+        repr = f'if:({self.condition_expr!r}) '
         if self.true_block:
-            repr += '\n\t{}) '.format(self.true_block)
+            repr += f'\n\t{self.true_block}) '
         if self.false_block:
             repr = 'else: '
-            repr += '\n\t{} '.format(self.false_block)
+            repr += f'\n\t{self.false_block} '
 
         return repr
 
@@ -264,7 +264,7 @@ class KernelFunction(Node):
 
     def __repr__(self):
         params = [p.symbol for p in self.get_parameters()]
-        return '{0} {1}({2})'.format(type(self).__name__, self.function_name, params)
+        return f'{type(self).__name__} {self.function_name}({params})'
 
     def compile(self, *args, **kwargs):
         if self._compile_function is None:
@@ -475,11 +475,11 @@ class LoopOverCoordinate(Node):
 
     @staticmethod
     def get_loop_counter_name(coordinate_to_loop_over):
-        return "%s_%s" % (LoopOverCoordinate.LOOP_COUNTER_NAME_PREFIX, coordinate_to_loop_over)
+        return f"{LoopOverCoordinate.LOOP_COUNTER_NAME_PREFIX}_{coordinate_to_loop_over}"
 
     @staticmethod
     def get_block_loop_counter_name(coordinate_to_loop_over):
-        return "%s_%s" % (LoopOverCoordinate.BlOCK_LOOP_COUNTER_NAME_PREFIX, coordinate_to_loop_over)
+        return f"{LoopOverCoordinate.BlOCK_LOOP_COUNTER_NAME_PREFIX}_{coordinate_to_loop_over}"
 
     @property
     def loop_counter_name(self):
@@ -612,7 +612,7 @@ class SympyAssignment(Node):
             replacement.parent = self
             self.rhs = replacement
         else:
-            raise ValueError('%s is not in args of %s' % (replacement, self.__class__))
+            raise ValueError(f'{replacement} is not in args of {self.__class__}')
 
     def __repr__(self):
         return repr(self.lhs) + " ← " + repr(self.rhs)
@@ -620,7 +620,7 @@ class SympyAssignment(Node):
     def _repr_html_(self):
         printed_lhs = sp.latex(self.lhs)
         printed_rhs = sp.latex(self.rhs)
-        return "${printed_lhs} \\leftarrow {printed_rhs}$".format(printed_lhs=printed_lhs, printed_rhs=printed_rhs)
+        return f"${printed_lhs} \\leftarrow {printed_rhs}$"
 
     def __hash__(self):
         return hash((self.lhs, self.rhs))
@@ -663,7 +663,7 @@ class ResolvedFieldAccess(sp.Indexed):
 
     def __str__(self):
         top = super(ResolvedFieldAccess, self).__str__()
-        return "%s (%s)" % (top, self.typed_symbol.dtype)
+        return f"{top} ({self.typed_symbol.dtype})"
 
     def __getnewargs__(self):
         return self.base, self.indices[0], self.field, self.offsets, self.idx_coordinate_values
@@ -740,7 +740,7 @@ def early_out(condition):
 
 
 def get_dummy_symbol(dtype='bool'):
-    return TypedSymbol('dummy%s' % uuid.uuid4().hex, create_type(dtype))
+    return TypedSymbol(f'dummy{uuid.uuid4().hex}', create_type(dtype))
 
 
 class SourceCodeComment(Node):
diff --git a/pystencils/backends/cbackend.py b/pystencils/backends/cbackend.py
index 3552aeea4..bb25a6a4c 100644
--- a/pystencils/backends/cbackend.py
+++ b/pystencils/backends/cbackend.py
@@ -158,7 +158,7 @@ class CustomCodeNode(Node):
 class PrintNode(CustomCodeNode):
     # noinspection SpellCheckingInspection
     def __init__(self, symbol_to_print):
-        code = '\nstd::cout << "%s  =  " << %s << std::endl; \n' % (symbol_to_print.name, symbol_to_print.name)
+        code = f'\nstd::cout << "{symbol_to_print.name}  =  " << {symbol_to_print.name} << std::endl; \n'
         super(PrintNode, self).__init__(code, symbols_read=[symbol_to_print], symbols_defined=set())
         self.headers.append("<iostream>")
 
@@ -203,12 +203,12 @@ class CBackend:
         return str(node)
 
     def _print_KernelFunction(self, node):
-        function_arguments = ["%s %s" % (self._print(s.symbol.dtype), s.symbol.name) for s in node.get_parameters()]
+        function_arguments = [f"{self._print(s.symbol.dtype)} {s.symbol.name}" for s in node.get_parameters()]
         launch_bounds = ""
         if self._dialect == 'cuda':
             max_threads = node.indexing.max_threads_per_block()
             if max_threads:
-                launch_bounds = "__launch_bounds__({}) ".format(max_threads)
+                launch_bounds = f"__launch_bounds__({max_threads}) "
         func_declaration = "FUNC_PREFIX %svoid %s(%s)" % (launch_bounds, node.function_name,
                                                           ", ".join(function_arguments))
         if self._signatureOnly:
@@ -222,19 +222,19 @@ class CBackend:
         return "{\n%s\n}" % (self._indent + self._indent.join(block_contents.splitlines(True)))
 
     def _print_PragmaBlock(self, node):
-        return "%s\n%s" % (node.pragma_line, self._print_Block(node))
+        return f"{node.pragma_line}\n{self._print_Block(node)}"
 
     def _print_LoopOverCoordinate(self, node):
         counter_symbol = node.loop_counter_name
-        start = "int %s = %s" % (counter_symbol, self.sympy_printer.doprint(node.start))
-        condition = "%s < %s" % (counter_symbol, self.sympy_printer.doprint(node.stop))
-        update = "%s += %s" % (counter_symbol, self.sympy_printer.doprint(node.step),)
-        loop_str = "for (%s; %s; %s)" % (start, condition, update)
+        start = f"int {counter_symbol} = {self.sympy_printer.doprint(node.start)}"
+        condition = f"{counter_symbol} < {self.sympy_printer.doprint(node.stop)}"
+        update = f"{counter_symbol} += {self.sympy_printer.doprint(node.step)}"
+        loop_str = f"for ({start}; {condition}; {update})"
 
         prefix = "\n".join(node.prefix_lines)
         if prefix:
             prefix += "\n"
-        return "%s%s\n%s" % (prefix, loop_str, self._print(node.body))
+        return f"{prefix}{loop_str}\n{self._print(node.body)}"
 
     def _print_SympyAssignment(self, node):
         if node.is_declaration:
@@ -262,7 +262,7 @@ class CBackend:
                     instr = 'maskStore' if aligned else 'maskStoreU'
                     printed_mask = self.sympy_printer.doprint(mask)
                     if self._vector_instruction_set['dataTypePrefix']['double'] == '__mm256d':
-                        printed_mask = "_mm256_castpd_si256({})".format(printed_mask)
+                        printed_mask = f"_mm256_castpd_si256({printed_mask})"
 
                 rhs_type = get_type_of_expression(node.rhs)
                 if type(rhs_type) is not VectorType:
@@ -274,7 +274,7 @@ class CBackend:
                                                                   self.sympy_printer.doprint(rhs),
                                                                   printed_mask) + ';'
             else:
-                return "%s = %s;" % (self.sympy_printer.doprint(node.lhs), self.sympy_printer.doprint(node.rhs))
+                return f"{self.sympy_printer.doprint(node.lhs)} = {self.sympy_printer.doprint(node.rhs)};"
 
     def _print_TemporaryMemoryAllocation(self, node):
         align = 64
@@ -314,7 +314,7 @@ class CBackend:
             raise ValueError("Problem with Conditional inside vectorized loop - use vec_any or vec_all")
         condition_expr = self.sympy_printer.doprint(node.condition_expr)
         true_block = self._print_Block(node.true_block)
-        result = "if (%s)\n%s " % (condition_expr, true_block)
+        result = f"if ({condition_expr})\n{true_block} "
         if node.false_block:
             false_block = self._print_Block(node.false_block)
             result += "else " + false_block
@@ -343,7 +343,7 @@ class CustomSympyPrinter(CCodePrinter):
         if expr.exp.is_integer and expr.exp.is_number and 0 < expr.exp < 8:
             return "(" + self._print(sp.Mul(*[expr.base] * expr.exp, evaluate=False)) + ")"
         elif expr.exp.is_integer and expr.exp.is_number and - 8 < expr.exp < 0:
-            return "1 / ({})".format(self._print(sp.Mul(*[expr.base] * (-expr.exp), evaluate=False)))
+            return f"1 / ({self._print(sp.Mul(*([expr.base] * -expr.exp), evaluate=False))})"
         else:
             return super(CustomSympyPrinter, self)._print_Pow(expr)
 
@@ -363,9 +363,9 @@ class CustomSympyPrinter(CCodePrinter):
 
     def _print_Abs(self, expr):
         if expr.args[0].is_integer:
-            return 'abs({0})'.format(self._print(expr.args[0]))
+            return f'abs({self._print(expr.args[0])})'
         else:
-            return 'fabs({0})'.format(self._print(expr.args[0]))
+            return f'fabs({self._print(expr.args[0])})'
 
     def _print_Type(self, node):
         return str(node)
@@ -382,37 +382,37 @@ class CustomSympyPrinter(CCodePrinter):
             return expr.to_c(self._print)
         if isinstance(expr, reinterpret_cast_func):
             arg, data_type = expr.args
-            return "*((%s)(& %s))" % (self._print(PointerType(data_type, restrict=False)), self._print(arg))
+            return f"*(({self._print(PointerType(data_type, restrict=False))})(& {self._print(arg)}))"
         elif isinstance(expr, address_of):
             assert len(expr.args) == 1, "address_of must only have one argument"
-            return "&(%s)" % self._print(expr.args[0])
+            return f"&({self._print(expr.args[0])})"
         elif isinstance(expr, cast_func):
             arg, data_type = expr.args
             if isinstance(arg, sp.Number) and arg.is_finite:
                 return self._typed_number(arg, data_type)
             else:
-                return "((%s)(%s))" % (data_type, self._print(arg))
+                return f"(({data_type})({self._print(arg)}))"
         elif isinstance(expr, fast_division):
-            return "({})".format(self._print(expr.args[0] / expr.args[1]))
+            return f"({self._print(expr.args[0] / expr.args[1])})"
         elif isinstance(expr, fast_sqrt):
-            return "({})".format(self._print(sp.sqrt(expr.args[0])))
+            return f"({self._print(sp.sqrt(expr.args[0]))})"
         elif isinstance(expr, vec_any) or isinstance(expr, vec_all):
             return self._print(expr.args[0])
         elif isinstance(expr, fast_inv_sqrt):
-            return "({})".format(self._print(1 / sp.sqrt(expr.args[0])))
+            return f"({self._print(1 / sp.sqrt(expr.args[0]))})"
         elif isinstance(expr, sp.Abs):
-            return "abs({})".format(self._print(expr.args[0]))
+            return f"abs({self._print(expr.args[0])})"
         elif isinstance(expr, sp.Mod):
             if expr.args[0].is_integer and expr.args[1].is_integer:
-                return "({} % {})".format(self._print(expr.args[0]), self._print(expr.args[1]))
+                return f"({self._print(expr.args[0])} % {self._print(expr.args[1])})"
             else:
-                return "fmod({}, {})".format(self._print(expr.args[0]), self._print(expr.args[1]))
+                return f"fmod({self._print(expr.args[0])}, {self._print(expr.args[1])})"
         elif expr.func in infix_functions:
-            return "(%s %s %s)" % (self._print(expr.args[0]), infix_functions[expr.func], self._print(expr.args[1]))
+            return f"({self._print(expr.args[0])} {infix_functions[expr.func]} {self._print(expr.args[1])})"
         elif expr.func == int_power_of_2:
-            return "(1 << (%s))" % (self._print(expr.args[0]))
+            return f"(1 << ({self._print(expr.args[0])}))"
         elif expr.func == int_div:
-            return "((%s) / (%s))" % (self._print(expr.args[0]), self._print(expr.args[1]))
+            return f"(({self._print(expr.args[0])}) / ({self._print(expr.args[1])}))"
         else:
             name = expr.name if hasattr(expr, 'name') else expr.__class__.__name__
             arg_str = ', '.join(self._print(a) for a in expr.args)
@@ -540,14 +540,14 @@ class VectorizedCustomSympyPrinter(CustomSympyPrinter):
                 result = self.instruction_set['/'].format(self._print(expr.args[0]), self._print(expr.args[1]))
             return result
         elif expr.func == fast_sqrt:
-            return "({})".format(self._print(sp.sqrt(expr.args[0])))
+            return f"({self._print(sp.sqrt(expr.args[0]))})"
         elif expr.func == fast_inv_sqrt:
             result = self._scalarFallback('_print_Function', expr)
             if not result:
                 if self.instruction_set['rsqrt']:
                     return self.instruction_set['rsqrt'].format(self._print(expr.args[0]))
                 else:
-                    return "({})".format(self._print(1 / sp.sqrt(expr.args[0])))
+                    return f"({self._print(1 / sp.sqrt(expr.args[0]))})"
         elif isinstance(expr, vec_any):
             expr_type = get_type_of_expression(expr.args[0])
             if type(expr_type) is not VectorType:
diff --git a/pystencils/backends/cuda_backend.py b/pystencils/backends/cuda_backend.py
index d590d65b4..ef8f22ea2 100644
--- a/pystencils/backends/cuda_backend.py
+++ b/pystencils/backends/cuda_backend.py
@@ -98,7 +98,7 @@ class CudaSympyPrinter(CustomSympyPrinter):
         if isinstance(expr, fast_division):
             return "__fdividef(%s, %s)" % tuple(self._print(a) for a in expr.args)
         elif isinstance(expr, fast_sqrt):
-            return "__fsqrt_rn(%s)" % tuple(self._print(a) for a in expr.args)
+            return f"__fsqrt_rn({tuple(self._print(a) for a in expr.args)})"
         elif isinstance(expr, fast_inv_sqrt):
-            return "__frsqrt_rn(%s)" % tuple(self._print(a) for a in expr.args)
+            return f"__frsqrt_rn({tuple(self._print(a) for a in expr.args)})"
         return super()._print_Function(expr)
diff --git a/pystencils/backends/dot.py b/pystencils/backends/dot.py
index 64610c47a..83ae1c705 100644
--- a/pystencils/backends/dot.py
+++ b/pystencils/backends/dot.py
@@ -57,7 +57,7 @@ def __shortened(node):
         params = node.get_parameters()
         param_names = [p.field_name for p in params if p.is_field_pointer]
         param_names += [p.symbol.name for p in params if not p.is_field_parameter]
-        return "Func: %s (%s)" % (node.function_name, ",".join(param_names))
+        return f"Func: {node.function_name} ({','.join(param_names)})"
     elif isinstance(node, SympyAssignment):
         return repr(node.lhs)
     elif isinstance(node, Block):
@@ -65,7 +65,7 @@ def __shortened(node):
     elif isinstance(node, Conditional):
         return repr(node)
     else:
-        raise NotImplementedError("Cannot handle node type %s" % (type(node),))
+        raise NotImplementedError(f"Cannot handle node type {type(node)}")
 
 
 def print_dot(node, view=False, short=False, **kwargs):
diff --git a/pystencils/backends/opencl_backend.py b/pystencils/backends/opencl_backend.py
index 3ab7f820e..1813d63ef 100644
--- a/pystencils/backends/opencl_backend.py
+++ b/pystencils/backends/opencl_backend.py
@@ -98,7 +98,7 @@ class OpenClSympyPrinter(CudaSympyPrinter):
         if isinstance(expr, fast_division):
             return "native_divide(%s, %s)" % tuple(self._print(a) for a in expr.args)
         elif isinstance(expr, fast_sqrt):
-            return "native_sqrt(%s)" % tuple(self._print(a) for a in expr.args)
+            return f"native_sqrt({tuple(self._print(a) for a in expr.args)})"
         elif isinstance(expr, fast_inv_sqrt):
-            return "native_rsqrt(%s)" % tuple(self._print(a) for a in expr.args)
+            return f"native_rsqrt({tuple(self._print(a) for a in expr.args)})"
         return CustomSympyPrinter._print_Function(self, expr)
diff --git a/pystencils/backends/simd_instruction_sets.py b/pystencils/backends/simd_instruction_sets.py
index be8523e90..7e2be4dee 100644
--- a/pystencils/backends/simd_instruction_sets.py
+++ b/pystencils/backends/simd_instruction_sets.py
@@ -51,7 +51,7 @@ def get_vector_instruction_set(data_type='double', instruction_set='avx'):
         })
 
     for comparison_op, constant in comparisons.items():
-        base_names[comparison_op] = 'cmp[0, 1, %s]' % (constant,)
+        base_names[comparison_op] = f'cmp[0, 1, {constant}]'
 
     headers = {
         'avx512': ['<immintrin.h>'],
@@ -89,16 +89,16 @@ def get_vector_instruction_set(data_type='double', instruction_set='avx'):
         name = function_shortcut[:function_shortcut.index('[')]
 
         if intrinsic_id == 'makeVecConst':
-            arg_string = "({})".format(",".join(["{0}"] * result['width']))
+            arg_string = f"({','.join(['{0}'] * result['width'])})"
         elif intrinsic_id == 'makeVec':
             params = ["{" + str(i) + "}" for i in reversed(range(result['width']))]
-            arg_string = "({})".format(",".join(params))
+            arg_string = f"({','.join(params)})"
         elif intrinsic_id == 'makeVecBool':
-            params = ["(({{{i}}} ? -1.0 : 0.0)".format(i=i) for i in reversed(range(result['width']))]
-            arg_string = "({})".format(",".join(params))
+            params = [f"(({{{i}}} ? -1.0 : 0.0)" for i in reversed(range(result['width']))]
+            arg_string = f"({','.join(params)})"
         elif intrinsic_id == 'makeVecConstBool':
             params = ["(({0}) ? -1.0 : 0.0)" for _ in range(result['width'])]
-            arg_string = "({})".format(",".join(params))
+            arg_string = f"({','.join(params)})"
         else:
             args = function_shortcut[function_shortcut.index('[') + 1: -1]
             arg_string = "("
@@ -141,9 +141,9 @@ def get_vector_instruction_set(data_type='double', instruction_set='avx'):
         result['bool'] = "__mmask%d" % (size,)
 
         params = " | ".join(["({{{i}}} ? {power} : 0)".format(i=i, power=2 ** i) for i in range(8)])
-        result['makeVecBool'] = "__mmask8(({}) )".format(params)
+        result['makeVecBool'] = f"__mmask8(({params}) )"
         params = " | ".join(["({{0}} ? {power} : 0)".format(power=2 ** i) for i in range(8)])
-        result['makeVecConstBool'] = "__mmask8(({}) )".format(params)
+        result['makeVecConstBool'] = f"__mmask8(({params}) )"
 
     if instruction_set == 'avx' and data_type == 'float':
         result['rsqrt'] = "_mm256_rsqrt_ps({0})"
diff --git a/pystencils/boundaries/boundaryhandling.py b/pystencils/boundaries/boundaryhandling.py
index e16400635..b80d3c72f 100644
--- a/pystencils/boundaries/boundaryhandling.py
+++ b/pystencils/boundaries/boundaryhandling.py
@@ -66,13 +66,13 @@ class FlagInterface:
                 self._used_flags.add(flag)
                 assert self._is_power_of_2(flag)
                 return flag
-        raise ValueError("All available {} flags are reserved".format(self.max_bits))
+        raise ValueError(f"All available {self.max_bits} flags are reserved")
 
     def reserve_flag(self, flag):
         assert self._is_power_of_2(flag)
         flag = self.dtype(flag)
         if flag in self._used_flags:
-            raise ValueError("The flag {flag} is already reserved".format(flag=flag))
+            raise ValueError(f"The flag {flag} is already reserved")
         self._used_flags.add(flag)
         return flag
 
@@ -392,12 +392,12 @@ class BoundaryDataSetter:
 
     def __setitem__(self, key, value):
         if key not in self.boundary_data_names:
-            raise KeyError("Invalid boundary data name %s. Allowed are %s" % (key, self.boundary_data_names))
+            raise KeyError(f"Invalid boundary data name {key}. Allowed are {self.boundary_data_names}")
         self.index_array[key] = value
 
     def __getitem__(self, item):
         if item not in self.boundary_data_names:
-            raise KeyError("Invalid boundary data name %s. Allowed are %s" % (item, self.boundary_data_names))
+            raise KeyError(f"Invalid boundary data name {item}. Allowed are {self.boundary_data_names}")
         return self.index_array[item]
 
 
@@ -437,7 +437,7 @@ class BoundaryOffsetInfo(CustomCodeNode):
 
     @staticmethod
     def _offset_symbols(dim):
-        return [TypedSymbol("c%s" % (d,), create_type(np.int64)) for d in ['x', 'y', 'z'][:dim]]
+        return [TypedSymbol(f"c{d}", create_type(np.int64)) for d in ['x', 'y', 'z'][:dim]]
 
     INV_DIR_SYMBOL = TypedSymbol("invdir", "int")
 
diff --git a/pystencils/cpu/cpujit.py b/pystencils/cpu/cpujit.py
index 07a8a84d9..5b0115358 100644
--- a/pystencils/cpu/cpujit.py
+++ b/pystencils/cpu/cpujit.py
@@ -362,7 +362,7 @@ def create_function_boilerplate_code(parameter_info, name, insert_checks=True):
             field = param.fields[0]
             pre_call_code += template_extract_array.format(name=field.name)
             post_call_code += template_release_buffer.format(name=field.name)
-            parameters.append("({dtype} *)buffer_{name}.buf".format(dtype=str(field.dtype), name=field.name))
+            parameters.append(f"({str(field.dtype)} *)buffer_{field.name}.buf")
 
             if insert_checks:
                 np_dtype = field.dtype.numpy_dtype
@@ -375,12 +375,12 @@ def create_function_boilerplate_code(parameter_info, name, insert_checks=True):
                     pre_call_code += template_check_array.format(cond=dtype_cond, what="data type", name=field.name,
                                                                  expected=str(field.dtype.numpy_dtype))
 
-                item_size_cond = "buffer_{name}.itemsize == {size}".format(name=field.name, size=item_size)
+                item_size_cond = f"buffer_{field.name}.itemsize == {item_size}"
                 pre_call_code += template_check_array.format(cond=item_size_cond, what="itemsize", name=field.name,
                                                              expected=item_size)
 
                 if field.has_fixed_shape:
-                    shape_cond = ["buffer_{name}.shape[{i}] == {s}".format(s=s, name=field.name, i=i)
+                    shape_cond = [f"buffer_{field.name}.shape[{i}] == {s}"
                                   for i, s in enumerate(field.spatial_shape)]
                     shape_cond = " && ".join(shape_cond)
                     pre_call_code += template_check_array.format(cond=shape_cond, what="shape", name=field.name,
@@ -403,7 +403,7 @@ def create_function_boilerplate_code(parameter_info, name, insert_checks=True):
             parameters.append("buffer_{name}.strides[{i}] / {bytes}".format(bytes=item_size, i=param.symbol.coordinate,
                                                                             name=field.name))
         elif param.is_field_shape:
-            parameters.append("buffer_{name}.shape[{i}]".format(i=param.symbol.coordinate, name=param.field_name))
+            parameters.append(f"buffer_{param.field_name}.shape[{param.symbol.coordinate}]")
         else:
             extract_function, target_type = type_mapping[param.symbol.dtype.numpy_dtype.type]
             if np.issubdtype(param.symbol.dtype.numpy_dtype, np.complexfloating):
@@ -490,8 +490,8 @@ class ExtensionModuleCode:
         includes = "\n".join(["#include %s" % (include_file,) for include_file in header_list])
         print(includes, file=file)
         print("\n", file=file)
-        print("#define RESTRICT %s" % (restrict_qualifier,), file=file)
-        print("#define FUNC_PREFIX %s" % (function_prefix,), file=file)
+        print(f"#define RESTRICT {restrict_qualifier}", file=file)
+        print(f"#define FUNC_PREFIX {function_prefix}", file=file)
         print("\n", file=file)
 
         for ast, name in zip(self._ast_nodes, self._function_names):
@@ -541,7 +541,7 @@ def compile_module(code, code_hash, base_dir):
             import sysconfig
             config_vars = sysconfig.get_config_vars()
             py_lib = os.path.join(config_vars["installed_base"], "libs",
-                                  "python{}.lib".format(config_vars["py_version_nodot"]))
+                                  f"python{config_vars['py_version_nodot']}.lib")
             run_compile_step(['link.exe', py_lib, '/DLL', '/out:' + lib_file, object_file])
         elif platform.system().lower() == 'darwin':
             with atomic_file_write(lib_file) as file_name:
diff --git a/pystencils/cpu/kernelcreation.py b/pystencils/cpu/kernelcreation.py
index 38ce169af..457944db6 100644
--- a/pystencils/cpu/kernelcreation.py
+++ b/pystencils/cpu/kernelcreation.py
@@ -129,7 +129,7 @@ def create_indexed_kernel(assignments: AssignmentOrAstNodeList, index_fields, fu
                 rhs = idx_field[0](name)
                 lhs = TypedSymbol(name, BasicType(data_type.get_element_type(name)))
                 return SympyAssignment(lhs, rhs)
-        raise ValueError("Index %s not found in any of the passed index fields" % (name,))
+        raise ValueError(f"Index {name} not found in any of the passed index fields")
 
     coordinate_symbol_assignments = [get_coordinate_symbol_assignment(n)
                                      for n in coordinate_names[:spatial_coordinates]]
@@ -173,7 +173,7 @@ def add_openmp(ast_node, schedule="static", num_threads=True, collapse=None, ass
 
     assert type(ast_node) is ast.KernelFunction
     body = ast_node.body
-    threads_clause = "" if num_threads and isinstance(num_threads, bool) else " num_threads(%s)" % (num_threads,)
+    threads_clause = "" if num_threads and isinstance(num_threads, bool) else f" num_threads({num_threads})"
     wrapper_block = ast.PragmaBlock('#pragma omp parallel' + threads_clause, body.take_child_nodes())
     body.append(wrapper_block)
 
@@ -204,7 +204,7 @@ def add_openmp(ast_node, schedule="static", num_threads=True, collapse=None, ass
                 except TypeError:
                     pass
 
-        prefix = "#pragma omp for schedule(%s)" % (schedule,)
+        prefix = f"#pragma omp for schedule({schedule})"
         if collapse:
             prefix += " collapse(%d)" % (collapse, )
         loop_to_parallelize.prefix_lines.append(prefix)
diff --git a/pystencils/cpu/msvc_detection.py b/pystencils/cpu/msvc_detection.py
index 94b2bcf5b..9cc1fc5ad 100644
--- a/pystencils/cpu/msvc_detection.py
+++ b/pystencils/cpu/msvc_detection.py
@@ -71,7 +71,7 @@ def normalize_msvc_version(version):
 
 def get_environment_from_vc_vars_file(vc_vars_file, arch):
     out = subprocess.check_output(
-        'cmd /u /c "{}" {} && set'.format(vc_vars_file, arch),
+        f'cmd /u /c "{vc_vars_file}" {arch} && set',
         stderr=subprocess.STDOUT,
     ).decode('utf-16le', errors='replace')
 
diff --git a/pystencils/cpu/vectorization.py b/pystencils/cpu/vectorization.py
index 12b492cf4..0ee5200a0 100644
--- a/pystencils/cpu/vectorization.py
+++ b/pystencils/cpu/vectorization.py
@@ -115,7 +115,7 @@ def vectorize_inner_loops_and_adapt_load_stores(ast_node, vector_width, assume_a
                     break
                 typed_symbol = base.label
                 assert type(typed_symbol.dtype) is PointerType, \
-                    "Type of access is {}, {}".format(typed_symbol.dtype, indexed)
+                    f"Type of access is {typed_symbol.dtype}, {indexed}"
 
                 vec_type = VectorType(typed_symbol.dtype.base_type, vector_width)
                 use_aligned_access = aligned_access and assume_aligned
diff --git a/pystencils/data_types.py b/pystencils/data_types.py
index 786351f52..365ef8aa7 100644
--- a/pystencils/data_types.py
+++ b/pystencils/data_types.py
@@ -396,7 +396,7 @@ def ctypes_from_llvm(data_type):
     elif isinstance(data_type, ir.VoidType):
         return None  # Void type is not supported by ctypes
     else:
-        raise NotImplementedError('Data type %s of %s is not supported yet' % (type(data_type), data_type))
+        raise NotImplementedError(f'Data type {type(data_type)} of {data_type} is not supported yet')
 
 
 def to_llvm_type(data_type, nvvm_target=False):
@@ -603,7 +603,7 @@ class BasicType(Type):
         elif name == 'bool':
             return 'bool'
         else:
-            raise NotImplementedError("Can map numpy to C name for %s" % (name,))
+            raise NotImplementedError(f"Can map numpy to C name for {name}")
 
     def __init__(self, dtype, const=False):
         self.const = const
diff --git a/pystencils/datahandling/parallel_datahandling.py b/pystencils/datahandling/parallel_datahandling.py
index 535933300..4d3fcdf7a 100644
--- a/pystencils/datahandling/parallel_datahandling.py
+++ b/pystencils/datahandling/parallel_datahandling.py
@@ -383,7 +383,7 @@ class ParallelDataHandling(DataHandling):
         if not os.path.exists(directory):
             os.mkdir(directory)
         if os.path.isfile(directory):
-            raise RuntimeError("Trying to save to {}, but file exists already".format(directory))
+            raise RuntimeError(f"Trying to save to {directory}, but file exists already")
 
         for field_name, data_name in self._field_name_to_cpu_data_name.items():
             self.blocks.writeBlockData(data_name, os.path.join(directory, field_name + ".dat"))
diff --git a/pystencils/datahandling/serial_datahandling.py b/pystencils/datahandling/serial_datahandling.py
index d4af43f18..e5244c05a 100644
--- a/pystencils/datahandling/serial_datahandling.py
+++ b/pystencils/datahandling/serial_datahandling.py
@@ -407,7 +407,7 @@ class SerialDataHandling(DataHandling):
 
         time_running = time.perf_counter() - self._start_time
         spacing = 7 - len(str(int(time_running)))
-        message = "[{: <8}]{}({:.3f} sec) {} ".format(level, spacing * '-', time_running, message)
+        message = f"[{level: <8}]{spacing * '-'}({time_running:.3f} sec) {message} "
         print(message, flush=True)
 
     def log_on_root(self, *args, level='INFO'):
@@ -428,7 +428,7 @@ class SerialDataHandling(DataHandling):
         file_contents = np.load(file)
         for arr_name, arr_contents in self.cpu_arrays.items():
             if arr_name not in file_contents:
-                print("Skipping read data {} because there is no data with this name in data handling".format(arr_name))
+                print(f"Skipping read data {arr_name} because there is no data with this name in data handling")
                 continue
             if file_contents[arr_name].shape != arr_contents.shape:
                 print("Skipping read data {} because shapes don't match. "
diff --git a/pystencils/display_utils.py b/pystencils/display_utils.py
index cb09197bf..32531cdc5 100644
--- a/pystencils/display_utils.py
+++ b/pystencils/display_utils.py
@@ -30,7 +30,7 @@ def highlight_cpp(code: str):
     from pygments.lexers import CppLexer
 
     css = HtmlFormatter().get_style_defs('.highlight')
-    css_tag = "<style>{css}</style>".format(css=css)
+    css_tag = f"<style>{css}</style>"
     display(HTML(css_tag))
     return HTML(highlight(code, CppLexer(), HtmlFormatter()))
 
diff --git a/pystencils/fd/derivation.py b/pystencils/fd/derivation.py
index e0e7a65ad..23579f488 100644
--- a/pystencils/fd/derivation.py
+++ b/pystencils/fd/derivation.py
@@ -107,7 +107,7 @@ class FiniteDifferenceStencilDerivation:
     @staticmethod
     def symbolic_weight(*args):
         str_args = [str(e) for e in args]
-        return sp.Symbol("w_({})".format(",".join(str_args)))
+        return sp.Symbol(f"w_({','.join(str_args)})")
 
     def error_term_dict(self, order):
         error_terms = defaultdict(lambda: 0)
diff --git a/pystencils/fd/derivative.py b/pystencils/fd/derivative.py
index 31daf4294..0e2890ec5 100644
--- a/pystencils/fd/derivative.py
+++ b/pystencils/fd/derivative.py
@@ -109,7 +109,7 @@ class Diff(sp.Expr):
         return result
 
     def __str__(self):
-        return "D(%s)" % self.arg
+        return f"D({self.arg})"
 
     def interpolated_access(self, offset, **kwargs):
         """Represents an interpolated access on a spatially differentiated field
diff --git a/pystencils/fd/finitedifferences.py b/pystencils/fd/finitedifferences.py
index 317e8e025..1a119f71b 100644
--- a/pystencils/fd/finitedifferences.py
+++ b/pystencils/fd/finitedifferences.py
@@ -193,7 +193,7 @@ class Advection(sp.Function):
         return self.scalar.spatial_dimensions
 
     def _latex(self, printer):
-        name_suffix = "_%s" % self.scalar_index if self.scalar_index is not None else ""
+        name_suffix = f"_{self.scalar_index}" if self.scalar_index is not None else ""
         if isinstance(self.vector, Field):
             return r"\nabla \cdot(%s %s)" % (printer.doprint(sp.Symbol(self.vector.name)),
                                              printer.doprint(sp.Symbol(self.scalar.name + name_suffix)))
@@ -240,7 +240,7 @@ class Diffusion(sp.Function):
         return self.scalar.spatial_dimensions
 
     def _latex(self, printer):
-        name_suffix = "_%s" % self.scalar_index if self.scalar_index is not None else ""
+        name_suffix = f"_{self.scalar_index}" if self.scalar_index is not None else ""
         coeff = self.diffusion_coeff
         diff_coeff = sp.Symbol(coeff.name) if isinstance(coeff, Field) else coeff
         return r"div(%s \nabla %s)" % (printer.doprint(diff_coeff),
@@ -273,7 +273,7 @@ class Transient(sp.Function):
         return None if len(self.args) <= 1 else int(self.args[1])
 
     def _latex(self, printer):
-        name_suffix = "_%s" % self.scalar_index if self.scalar_index is not None else ""
+        name_suffix = f"_{self.scalar_index}" if self.scalar_index is not None else ""
         return r"\partial_t %s" % (printer.doprint(sp.Symbol(self.scalar.name + name_suffix)),)
 
 
diff --git a/pystencils/field.py b/pystencils/field.py
index 6b85dead1..9fe59d1f4 100644
--- a/pystencils/field.py
+++ b/pystencils/field.py
@@ -583,7 +583,7 @@ class Field(AbstractField):
             }
         }
         if not self.index_shape[0] in stencils[self.spatial_dimensions]:
-            raise ValueError("No known stencil has {} staggered points".format(self.index_shape[0]))
+            raise ValueError(f"No known stencil has {self.index_shape[0]} staggered points")
         return stencils[self.spatial_dimensions][self.index_shape[0]]
 
     @property
@@ -706,7 +706,7 @@ class Field(AbstractField):
                 offset_name = hashlib.md5(pickle.dumps(offsets_and_index)).hexdigest()[:12]
                 superscript = None
 
-            symbol_name = "%s_%s" % (field_name, offset_name)
+            symbol_name = f"{field_name}_{offset_name}"
             if superscript is not None:
                 symbol_name += "^" + superscript
 
@@ -871,9 +871,9 @@ class Field(AbstractField):
                 offset_str = ",".join([sp.latex(self._staggered_offset(self.offsets, self.index[0])[i])
                                        for i in range(len(self.offsets))])
             if self.is_absolute_access:
-                offset_str = "\\mathbf{}".format(offset_str)
+                offset_str = f"\\mathbf{offset_str}"
             elif self.field.spatial_dimensions > 1:
-                offset_str = "({})".format(offset_str)
+                offset_str = f"({offset_str})"
 
             if FieldType.is_staggered(self._field):
                 if self.index and self.field.index_dimensions > 1:
@@ -894,18 +894,18 @@ class Field(AbstractField):
                 offset_str = ",".join([sp.latex(self._staggered_offset(self.offsets, self.index[0])[i])
                                        for i in range(len(self.offsets))])
             if self.is_absolute_access:
-                offset_str = "[abs]{}".format(offset_str)
+                offset_str = f"[abs]{offset_str}"
 
             if FieldType.is_staggered(self._field):
                 if self.index and self.field.index_dimensions > 1:
-                    return "%s[%s](%s)" % (n, offset_str, self.index[1:] if len(self.index) > 2 else self.index[1])
+                    return f"{n}[{offset_str}]({self.index[1:] if len(self.index) > 2 else self.index[1]})"
                 else:
-                    return "%s[%s]" % (n, offset_str)
+                    return f"{n}[{offset_str}]"
             else:
                 if self.index and self.field.index_dimensions > 0:
-                    return "%s[%s](%s)" % (n, offset_str, self.index if len(self.index) > 1 else self.index[0])
+                    return f"{n}[{offset_str}]({self.index if len(self.index) > 1 else self.index[0]})"
                 else:
-                    return "%s[%s]" % (n, offset_str)
+                    return f"{n}[{offset_str}]"
 
 
 def get_layout_from_strides(strides: Sequence[int], index_dimension_ids: Optional[List[int]] = None):
diff --git a/pystencils/gpucuda/indexing.py b/pystencils/gpucuda/indexing.py
index eb212119a..ae5db1b98 100644
--- a/pystencils/gpucuda/indexing.py
+++ b/pystencils/gpucuda/indexing.py
@@ -305,7 +305,7 @@ def indexing_creator_from_params(gpu_indexing, gpu_indexing_params):
         elif gpu_indexing == 'line':
             indexing_creator = LineIndexing
         else:
-            raise ValueError("Unknown GPU indexing %s. Valid values are 'block' and 'line'" % (gpu_indexing,))
+            raise ValueError(f"Unknown GPU indexing {gpu_indexing}. Valid values are 'block' and 'line'")
         if gpu_indexing_params:
             indexing_creator = partial(indexing_creator, **gpu_indexing_params)
         return indexing_creator
diff --git a/pystencils/gpucuda/kernelcreation.py b/pystencils/gpucuda/kernelcreation.py
index 33db3ad56..52a4dc8bd 100644
--- a/pystencils/gpucuda/kernelcreation.py
+++ b/pystencils/gpucuda/kernelcreation.py
@@ -131,7 +131,7 @@ def created_indexed_cuda_kernel(assignments,
                 rhs = ind_f[0](name)
                 lhs = TypedSymbol(name, BasicType(data_type.get_element_type(name)))
                 return SympyAssignment(lhs, rhs)
-        raise ValueError("Index %s not found in any of the passed index fields" % (name,))
+        raise ValueError(f"Index {name} not found in any of the passed index fields")
 
     coordinate_symbol_assignments = [get_coordinate_symbol_assignment(n)
                                      for n in coordinate_names[:spatial_coordinates]]
diff --git a/pystencils/integer_set_analysis.py b/pystencils/integer_set_analysis.py
index 3560ba6ca..82af791ca 100644
--- a/pystencils/integer_set_analysis.py
+++ b/pystencils/integer_set_analysis.py
@@ -36,13 +36,12 @@ def isl_iteration_set(node: ast.Node):
         loop_start_str = remove_brackets(str(loop.start))
         loop_stop_str = remove_brackets(str(loop.stop))
         ctr_name = loop.loop_counter_name
-        set_string_description = "{} >= {} and {} < {}".format(ctr_name, loop_start_str, ctr_name, loop_stop_str)
+        set_string_description = f"{ctr_name} >= {loop_start_str} and {ctr_name} < {loop_stop_str}"
         conditions.append(remove_brackets(set_string_description))
 
     symbol_names = ','.join(degrees_of_freedom)
     condition_str = ' and '.join(conditions)
-    set_description = "{{ [{symbol_names}] : {condition_str} }}".format(symbol_names=symbol_names,
-                                                                        condition_str=condition_str)
+    set_description = f"{{ [{symbol_names}] : {condition_str} }}"
     return degrees_of_freedom, isl.BasicSet(set_description)
 
 
@@ -53,8 +52,7 @@ def simplify_loop_counter_dependent_conditional(conditional):
     if dofs_in_condition.issubset(dofs_in_loops):
         symbol_names = ','.join(dofs_in_loops)
         condition_str = remove_brackets(str(conditional.condition_expr))
-        condition_set = isl.BasicSet("{{ [{symbol_names}] : {condition_str} }}".format(symbol_names=symbol_names,
-                                                                                       condition_str=condition_str))
+        condition_set = isl.BasicSet(f"{{ [{symbol_names}] : {condition_str} }}")
 
         if condition_set.is_empty():
             conditional.replace_by_false_block()
diff --git a/pystencils/interpolation_astnodes.py b/pystencils/interpolation_astnodes.py
index 76bd340b7..c230d0115 100644
--- a/pystencils/interpolation_astnodes.py
+++ b/pystencils/interpolation_astnodes.py
@@ -126,7 +126,7 @@ class Interpolator(object):
         return InterpolatorAccess(self.symbol, *[sp.S(o) for o in offset])
 
     def __str__(self):
-        return '%s_interpolator_%s' % (self.field.name, self.reproducible_hash)
+        return f'{self.field.name}_interpolator_{self.reproducible_hash}'
 
     def __repr__(self):
         return self.__str__()
@@ -186,7 +186,7 @@ class InterpolatorAccess(TypedSymbol):
         return super()._hashable_content() + ((self.symbol, self.field, tuple(self.offsets), self.symbol.interpolator))
 
     def __str__(self):
-        return '%s_interpolator(%s)' % (self.field.name, ', '.join(str(o) for o in self.offsets))
+        return f"{self.field.name}_interpolator({', '.join(str(o) for o in self.offsets)})"
 
     def __repr__(self):
         return self.__str__()
@@ -437,7 +437,7 @@ class TextureCachedField(Interpolator):
         return obj
 
     def __str__(self):
-        return '%s_texture_%s' % (self.field.name, self.reproducible_hash)
+        return f'{self.field.name}_texture_{self.reproducible_hash}'
 
     def __repr__(self):
         return self.__str__()
diff --git a/pystencils/jupyter.py b/pystencils/jupyter.py
index f977e87c0..5e86e0c2c 100644
--- a/pystencils/jupyter.py
+++ b/pystencils/jupyter.py
@@ -44,17 +44,10 @@ def log_progress(sequence, every=None, size=None, name='Items'):
         for index, record in enumerate(sequence, 1):
             if index == 1 or index % every == 0:
                 if is_iterator:
-                    label.value = '{name}: {index} / ?'.format(
-                        name=name,
-                        index=index
-                    )
+                    label.value = f'{name}: {index} / ?'
                 else:
                     progress.value = index
-                    label.value = u'{name}: {index} / {size}'.format(
-                        name=name,
-                        index=index,
-                        size=size
-                    )
+                    label.value = f'{name}: {index} / {size}'
             yield record
     except:
         progress.bar_style = 'danger'
@@ -62,10 +55,7 @@ def log_progress(sequence, every=None, size=None, name='Items'):
     else:
         progress.bar_style = 'success'
         progress.value = index
-        label.value = "{name}: {index}".format(
-            name=name,
-            index=str(index or '?')
-        )
+        label.value = f"{name}: {str(index or '?')}"
 
 
 VIDEO_TAG = """<video controls width="80%">
diff --git a/pystencils/kerncraft_coupling/kerncraft_interface.py b/pystencils/kerncraft_coupling/kerncraft_interface.py
index 37a5109de..bd1771493 100644
--- a/pystencils/kerncraft_coupling/kerncraft_interface.py
+++ b/pystencils/kerncraft_coupling/kerncraft_interface.py
@@ -140,7 +140,7 @@ class PyStencilsKerncraftKernel(KernelCode):
         """
         code = generate_benchmark(self.kernel_ast, likwid=type_ == 'likwid', openmp=openmp)
         if as_filename:
-            fp, already_available = self._get_intermediate_file('kernel_{}.c'.format(type_),
+            fp, already_available = self._get_intermediate_file(f'kernel_{type_}.c',
                                                                 machine_and_compiler_dependent=False)
             if not already_available:
                 fp.write(code)
diff --git a/pystencils/kernelcreation.py b/pystencils/kernelcreation.py
index 2c8aabaa5..b158754c8 100644
--- a/pystencils/kernelcreation.py
+++ b/pystencils/kernelcreation.py
@@ -128,7 +128,7 @@ def create_kernel(assignments,
             ast._backend = 'opencl'
         return ast
     else:
-        raise ValueError("Unknown target %s. Has to be one of 'cpu', 'gpu' or 'llvm' " % (target,))
+        raise ValueError(f"Unknown target {target}. Has to be one of 'cpu', 'gpu' or 'llvm' ")
 
     if use_auto_for_assignments:
         for a in ast.atoms(SympyAssignment):
@@ -214,7 +214,7 @@ def create_indexed_kernel(assignments,
             ast._backend = 'opencl'
         return ast
     else:
-        raise ValueError("Unknown target %s. Has to be either 'cpu' or 'gpu'" % (target,))
+        raise ValueError(f"Unknown target {target}. Has to be either 'cpu' or 'gpu'")
 
 
 def create_staggered_kernel(assignments, target='cpu', gpu_exclusive_conditions=False, **kwargs):
diff --git a/pystencils/kernelparameters.py b/pystencils/kernelparameters.py
index 9284a1ee5..3257522e4 100644
--- a/pystencils/kernelparameters.py
+++ b/pystencils/kernelparameters.py
@@ -29,7 +29,7 @@ class FieldStrideSymbol(TypedSymbol):
         return obj
 
     def __new_stage2__(cls, field_name, coordinate):
-        name = "_stride_{name}_{i}".format(name=field_name, i=coordinate)
+        name = f"_stride_{field_name}_{coordinate}"
         obj = super(FieldStrideSymbol, cls).__xnew__(cls, name, STRIDE_DTYPE, positive=True)
         obj.field_name = field_name
         obj.coordinate = coordinate
@@ -54,7 +54,7 @@ class FieldShapeSymbol(TypedSymbol):
 
     def __new_stage2__(cls, field_names, coordinate):
         names = "_".join([field_name for field_name in field_names])
-        name = "_size_{names}_{i}".format(names=names, i=coordinate)
+        name = f"_size_{names}_{coordinate}"
         obj = super(FieldShapeSymbol, cls).__xnew__(cls, name, SHAPE_DTYPE, positive=True)
         obj.field_names = tuple(field_names)
         obj.coordinate = coordinate
@@ -77,7 +77,7 @@ class FieldPointerSymbol(TypedSymbol):
         return obj
 
     def __new_stage2__(cls, field_name, field_dtype, const):
-        name = "_data_{name}".format(name=field_name)
+        name = f"_data_{field_name}"
         dtype = PointerType(get_base_type(field_dtype), const=const, restrict=True)
         obj = super(FieldPointerSymbol, cls).__xnew__(cls, name, dtype)
         obj.field_name = field_name
diff --git a/pystencils/llvm/llvm.py b/pystencils/llvm/llvm.py
index 1d5223e95..a0de12689 100644
--- a/pystencils/llvm/llvm.py
+++ b/pystencils/llvm/llvm.py
@@ -97,7 +97,7 @@ class LLVMPrinter(Printer):
             # look up parameter with name s
             val = self.func_arg_map.get(s.name)
         if not val:
-            raise LookupError("Symbol not found: %s" % s)
+            raise LookupError(f"Symbol not found: {s}")
         return val
 
     def _print_Pow(self, expr):
diff --git a/pystencils/placeholder_function.py b/pystencils/placeholder_function.py
index 18a0574b8..8b8aa6ed0 100644
--- a/pystencils/placeholder_function.py
+++ b/pystencils/placeholder_function.py
@@ -34,7 +34,7 @@ def to_placeholder_function(expr, name):
     """
     symbols = list(expr.atoms(sp.Symbol))
     symbols.sort(key=lambda e: e.name)
-    derivative_symbols = [sp.Symbol("_d{}_d{}".format(name, s.name)) for s in symbols]
+    derivative_symbols = [sp.Symbol(f"_d{name}_d{s.name}") for s in symbols]
     derivatives = [sp.diff(expr, s) for s in symbols]
 
     assignments = [Assignment(sp.Symbol(name), expr)]
diff --git a/pystencils/rng.py b/pystencils/rng.py
index 85bc7c1b1..bbc28bbd2 100644
--- a/pystencils/rng.py
+++ b/pystencils/rng.py
@@ -13,7 +13,7 @@ def _get_rng_template(name, data_type, num_vars):
         c_type = "double"
     template = "\n"
     for i in range(num_vars):
-        template += "{{result_symbols[{}].dtype}} {{result_symbols[{}].name}};\n".format(i, i)
+        template += f"{{result_symbols[{i}].dtype}} {{result_symbols[{i}].name}};\n"
     template += ("{}_{}{}({{parameters}}, " + ", ".join(["{{result_symbols[{}].name}}"] * num_vars) + ");\n") \
         .format(name, c_type, num_vars, *tuple(range(num_vars)))
     return template
@@ -36,15 +36,15 @@ class RNGBase(CustomCodeNode):
         if keys is None:
             keys = (0,) * self._num_keys
         if len(keys) != self._num_keys:
-            raise ValueError("Provided {} keys but need {}".format(len(keys), self._num_keys))
+            raise ValueError(f"Provided {len(keys)} keys but need {self._num_keys}")
         if len(offsets) != 3:
-            raise ValueError("Provided {} offsets but need {}".format(len(offsets), 3))
+            raise ValueError(f"Provided {len(offsets)} offsets but need {3}")
         self.result_symbols = tuple(TypedSymbol(sp.Dummy().name, self._data_type) for _ in range(self._num_vars))
         symbols_read = [s for s in keys if isinstance(s, sp.Symbol)]
         super().__init__("", symbols_read=symbols_read, symbols_defined=self.result_symbols)
         self._time_step = time_step
         self._offsets = offsets
-        self.headers = ['"{}_rand.h"'.format(self._name)]
+        self.headers = [f'"{self._name}_rand.h"']
         self.keys = tuple(keys)
         self._args = sp.sympify((dim, time_step, keys))
         self._dim = dim
diff --git a/pystencils/runhelper/parameterstudy.py b/pystencils/runhelper/parameterstudy.py
index 0ad27fd5b..f4d8327d3 100644
--- a/pystencils/runhelper/parameterstudy.py
+++ b/pystencils/runhelper/parameterstudy.py
@@ -215,7 +215,7 @@ class ParameterStudy:
             def log_message(self, fmt, *args):
                 return
 
-        print("Listening to connections on {}:{}. Scenarios to simulate: {}".format(ip, port, len(filtered_runs)))
+        print(f"Listening to connections on {ip}:{port}. Scenarios to simulate: {len(filtered_runs)}")
         server = HTTPServer((ip, port), ParameterStudyServer)
         while len(ParameterStudyServer.currently_running) > 0 or len(ParameterStudyServer.runs) > 0:
             server.handle_request()
@@ -241,7 +241,7 @@ class ParameterStudy:
         from urllib.error import URLError
         import time
         parameter_update = {} if parameter_update is None else parameter_update
-        url = "http://{}:{}".format(server, port)
+        url = f"http://{server}:{port}"
         client_name = client_name.format(hostname=socket.gethostname(), pid=os.getpid())
         start_time = time.time()
         while True:
@@ -265,7 +265,7 @@ class ParameterStudy:
                           'client_name': client_name}
                 urlopen(url + '/result', data=json.dumps(answer).encode())
             except URLError:
-                print("Cannot connect to server {}  retrying in 5 seconds...".format(url))
+                print(f"Cannot connect to server {url}  retrying in 5 seconds...")
                 sleep(5)
 
     def run_from_command_line(self, argv: Optional[Sequence[str]] = None) -> None:
diff --git a/pystencils/simp/assignment_collection.py b/pystencils/simp/assignment_collection.py
index 706008c85..696038dd5 100644
--- a/pystencils/simp/assignment_collection.py
+++ b/pystencils/simp/assignment_collection.py
@@ -378,10 +378,10 @@ class AssignmentCollection:
     def __str__(self):
         result = "Subexpressions:\n"
         for eq in self.subexpressions:
-            result += "\t{eq}\n".format(eq=eq)
+            result += f"\t{eq}\n"
         result += "Main Assignments:\n"
         for eq in self.main_assignments:
-            result += "\t{eq}\n".format(eq=eq)
+            result += f"\t{eq}\n"
         return result
 
     def __iter__(self):
@@ -446,6 +446,6 @@ class SymbolGen:
         return self
 
     def __next__(self):
-        name = "{}_{}".format(self._symbol, self._ctr)
+        name = f"{self._symbol}_{self._ctr}"
         self._ctr += 1
         return sp.Symbol(name)
diff --git a/pystencils/simp/simplificationstrategy.py b/pystencils/simp/simplificationstrategy.py
index 2c70c25c7..cc601aa56 100644
--- a/pystencils/simp/simplificationstrategy.py
+++ b/pystencils/simp/simplificationstrategy.py
@@ -92,7 +92,7 @@ class SimplificationStrategy:
             assignment_collection = t(assignment_collection)
             end_time = timeit.default_timer()
             op = assignment_collection.operation_count
-            time_str = "%.2f ms" % ((end_time - start_time) * 1000,)
+            time_str = f"{(end_time - start_time) * 1000:.2f} ms"
             total = op['adds'] + op['muls'] + op['divs']
             report.add(ReportElement(t.__name__, time_str, op['adds'], op['muls'], op['divs'], total))
         return report
@@ -129,7 +129,7 @@ class SimplificationStrategy:
 
             def _repr_html_(self):
                 def print_assignment_collection(title, c):
-                    text = '<h5 style="padding-bottom:10px">%s</h5> <div style="padding-left:20px;">' % (title, )
+                    text = f'<h5 style="padding-bottom:10px">{title}</h5> <div style="padding-left:20px;">'
                     if self.restrict_symbols:
                         text += "\n".join(["$$" + sp.latex(e) + '$$'
                                            for e in c.new_filtered(self.restrict_symbols).main_assignments])
@@ -151,5 +151,5 @@ class SimplificationStrategy:
     def __repr__(self):
         result = "Simplification Strategy:\n"
         for t in self._rules:
-            result += " - %s\n" % (t.__name__,)
+            result += f" - {t.__name__}\n"
         return result
diff --git a/pystencils/transformations.py b/pystencils/transformations.py
index 5b44eb3e1..b3f9431bb 100644
--- a/pystencils/transformations.py
+++ b/pystencils/transformations.py
@@ -137,7 +137,7 @@ def get_common_shape(field_set):
         fixed_field_names = ",".join([f.name for f in field_set if f.has_fixed_shape])
         var_field_names = ",".join([f.name for f in field_set if not f.has_fixed_shape])
         msg = "Mixing fixed-shaped and variable-shape fields in a single kernel is not possible\n"
-        msg += "Variable shaped: %s \nFixed shaped:    %s" % (var_field_names, fixed_field_names)
+        msg += f"Variable shaped: {var_field_names} \nFixed shaped:    {fixed_field_names}"
         raise ValueError(msg)
 
     shape_set = set([f.spatial_shape for f in field_set])
@@ -326,7 +326,7 @@ def parse_base_pointer_info(base_pointer_specification, loop_order, spatial_dime
                 index = int(element[len("index"):])
                 add_new_element(spatial_dimensions + index)
             else:
-                raise ValueError("Unknown specification %s" % (element,))
+                raise ValueError(f"Unknown specification {element}")
 
         result.append(new_group)
 
@@ -902,13 +902,12 @@ class KernelConstraintsCheck:
             self._field_writes[fai].add(lhs.offsets)
             if self.check_double_write_condition and len(self._field_writes[fai]) > 1:
                 raise ValueError(
-                    "Field {} is written at two different locations".format(
-                        lhs.field.name))
+                    f"Field {lhs.field.name} is written at two different locations")
         elif isinstance(lhs, sp.Symbol):
             if self.scopes.is_defined_locally(lhs):
-                raise ValueError("Assignments not in SSA form, multiple assignments to {}".format(lhs.name))
+                raise ValueError(f"Assignments not in SSA form, multiple assignments to {lhs.name}")
             if lhs in self.scopes.free_parameters:
-                raise ValueError("Symbol {} is written, after it has been read".format(lhs.name))
+                raise ValueError(f"Symbol {lhs.name} is written, after it has been read")
             self.scopes.define_symbol(lhs)
 
     def _update_accesses_rhs(self, rhs):
@@ -1281,7 +1280,7 @@ def loop_blocking(ast_node: ast.KernelFunction, block_size) -> int:
             loop_stops[coord] = loop.stop
         else:
             assert loop.start == loop_starts[coord] and loop.stop == loop_stops[coord], \
-                "Multiple loops over coordinate {} with different loop bounds".format(coord)
+                f"Multiple loops over coordinate {coord} with different loop bounds"
 
     # Create the outer loops that iterate over the blocks
     outer_loop = None
-- 
GitLab