diff --git a/pybis/src/python/pybis/attachment.py b/pybis/src/python/pybis/attachment.py
index 2d53d3d3bae3aa15f2d88a243bbffa9a3a3ab1b7..23df70ae93424316616d53759c3ca47761c7fcf4 100644
--- a/pybis/src/python/pybis/attachment.py
+++ b/pybis/src/python/pybis/attachment.py
@@ -5,7 +5,7 @@ import os
 class Attachment:
     def __init__(self, filename, title=None, description=None):
         if not os.path.exists(filename):
-            raise ValueError("File not found: {}".format(filename))
+            raise ValueError(f"File not found: {filename}")
         self.fileName = filename
         self.title = title
         self.description = description
diff --git a/pybis/src/python/pybis/attribute.py b/pybis/src/python/pybis/attribute.py
index 880886870c072117ce8831f76e70d9650b7c1668..bf767fc3626b541b99c1b51a8c156f1ea3174f11 100644
--- a/pybis/src/python/pybis/attribute.py
+++ b/pybis/src/python/pybis/attribute.py
@@ -257,9 +257,7 @@ class AttrHolder:
                                     "@type": "as.dto.person.id.PersonPermId",
                                 }
                             ],
-                            "@type": "as.dto.common.update.ListUpdateAction{}".format(
-                                self.__dict__["_changed_users"][userId]["action"]
-                            ),
+                            "@type": f'as.dto.common.update.ListUpdateAction{self.__dict__["_changed_users"][userId]["action"]}',
                         }
                     )
 
@@ -453,16 +451,12 @@ class AttrHolder:
         if self._is_new:
             if name not in self._defs["attrs_new"]:
                 raise ValueError(
-                    "No such attribute: 芦{}禄 for entity: {}. Allowed attributes are: {}".format(
-                        name, self.entity, self._defs["attrs_new"]
-                    )
+                    f'No such attribute: 芦{name}禄 for entity: {self.entity}. Allowed attributes are: {self._defs["attrs_new"]}'
                 )
         else:
             if name not in self._defs["attrs_up"]:
                 raise ValueError(
-                    "No such attribute: 芦{}禄 for entity: {}. Allowed attributes are: {}".format(
-                        name, self.entity, self._defs["attrs_up"]
-                    )
+                    f'No such attribute: 芦{name}禄 for entity: {self.entity}. Allowed attributes are: {self._defs["attrs_up"]}'
                 )
 
         if name in ["parents", "children", "components"]:
@@ -579,14 +573,12 @@ class AttrHolder:
                 self.__dict__["_" + name]["isModified"] = True
 
         elif name in ["identifier"]:
-            raise KeyError("you can not modify the {}".format(name))
+            raise KeyError(f"you can not modify the {name}")
         elif name == "code":
             try:
                 if self._type["autoGeneratedCode"]:
                     raise KeyError(
-                        "This {}Type has auto-generated code. You cannot set a code".format(
-                            self.entity
-                        )
+                        f"This {self.entity}Type has auto-generated code. You cannot set a code"
                     )
             except KeyError:
                 pass
@@ -606,7 +598,7 @@ class AttrHolder:
             # enum: check whether value is a valid constant
             if value and value not in self._defs[name]:
                 raise ValueError(
-                    "Allowed values for enum {} are: {}".format(name, self._defs[name])
+                    f"Allowed values for enum {name} are: {self._defs[name]}"
                 )
             else:
                 self.__dict__["_" + name] = value
@@ -985,9 +977,7 @@ class AttrHolder:
         for attr in attrs:
             if attr == "attachments":
                 continue
-            html += "<tr> <td>{}</td> <td>{}</td> </tr>".format(
-                attr, nvl(getattr(self, attr, ""), "")
-            )
+            html += f'<tr> <td>{attr}</td> <td>{nvl(getattr(self, attr, ""), "")}</td> </tr>'
         if getattr(self, "_attachments") is not None:
             html += "<tr><td>attachments</td><td>"
             html += "<br/>".join(att["fileName"] for att in self._attachments)
@@ -1017,9 +1007,7 @@ class AttrHolder:
                 for role in self._roleAssignments:
                     if role.get("space") is not None:
                         roles.append(
-                            "{} ({})".format(
-                                role.get("role"), role.get("space").get("code")
-                            )
+                            f'{role.get("role")} ({role.get("space").get("code")})'
                         )
                     else:
                         roles.append(role.get("role"))
diff --git a/pybis/src/python/pybis/data_set.py b/pybis/src/python/pybis/data_set.py
index 96167971c43fabb0d0e9c1e99aa6f5ee15258cf2..0bb13be90a0b4c02c0520a738fff17a0682c264c 100644
--- a/pybis/src/python/pybis/data_set.py
+++ b/pybis/src/python/pybis/data_set.py
@@ -115,9 +115,7 @@ class GitDataSetCreation(object):
     def data_store_url(self, dss_code):
         data_stores = self.openbis.get_datastores()
         data_store = data_stores[data_stores["code"] == dss_code]
-        return "{}/datastore_server/rmi-data-store-server-v3.json".format(
-            data_store["downloadUrl"][0]
-        )
+        return f'{data_store["downloadUrl"][0]}/datastore_server/rmi-data-store-server-v3.json'
 
     def data_set_metadata_creation(self):
         """Create the respresentation of the data set metadata."""
@@ -339,6 +337,4 @@ class GitDataSetFileSearch(object):
         if self.dss_code is None:
             self.dss_code = self.openbis.get_datastores()["code"][0]
         data_store = data_stores[data_stores["code"] == self.dss_code]
-        return "{}/datastore_server/rmi-data-store-server-v3.json".format(
-            data_store["downloadUrl"][0]
-        )
+        return f'{data_store["downloadUrl"][0]}/datastore_server/rmi-data-store-server-v3.json'
diff --git a/pybis/src/python/pybis/dataset.py b/pybis/src/python/pybis/dataset.py
index 9bcb253bbd49f80d2c18ede731586757dbe3f3e6..5225f19d46646ed13a2445c401fd50abc24c4646 100644
--- a/pybis/src/python/pybis/dataset.py
+++ b/pybis/src/python/pybis/dataset.py
@@ -76,7 +76,7 @@ class DataSet(
 
                 for file in files:
                     if not os.path.exists(file):
-                        raise ValueError("File {} does not exist".format(file))
+                        raise ValueError(f"File {file} does not exist")
 
                 self.__dict__["files"] = files
 
@@ -99,7 +99,7 @@ class DataSet(
             allowed_kinds = ["PHYSICAL", "CONTAINER", "LINK"]
             if kind not in allowed_kinds:
                 raise ValueError(
-                    "only these values are allowed for kind: {}".format(allowed_kinds)
+                    f"only these values are allowed for kind: {allowed_kinds}"
                 )
             self.a.__dict__["_kind"] = kind
 
@@ -332,13 +332,13 @@ class DataSet(
         }
         self.archive_unarchive("archiveDataSets", fetchopts)
         if VERBOSE:
-            print("DataSet {} archived".format(self.permId))
+            print(f"DataSet {self.permId} archived")
 
     def unarchive(self):
         fetchopts = {"@type": "as.dto.dataset.unarchive.DataSetUnarchiveOptions"}
         self.archive_unarchive("unarchiveDataSets", fetchopts)
         if VERBOSE:
-            print("DataSet {} unarchived".format(self.permId))
+            print(f"DataSet {self.permId} unarchived")
 
     def archive_unarchive(self, method, fetchopts):
         payload = {}
@@ -493,7 +493,7 @@ class DataSet(
                 content_copy_index,
             )
         else:
-            raise ValueError("Can't download data set of kind {}.".format(kind))
+            raise ValueError(f"Can't download data set of kind {kind}.")
 
     def _download_physical(
         self, files, destination, create_default_folders, wait_until_finished, workers
@@ -545,7 +545,7 @@ class DataSet(
                 queue.join()
 
             if VERBOSE:
-                print("Files downloaded to: {}".format(os.path.join(final_destination)))
+                print(f"Files downloaded to: {os.path.join(final_destination)}")
             return final_destination
 
     def _download_link(
@@ -800,9 +800,7 @@ class DataSet(
                     or getattr(self.props, prop_name) == ""
                 ):
                     raise ValueError(
-                        "Property '{}' is mandatory and must not be None".format(
-                            prop_name
-                        )
+                        f"Property '{prop_name}' is mandatory and must not be None"
                     )
 
         if self.is_new:
@@ -1172,39 +1170,29 @@ class DataSetDownloadQueue:
                 r = requests.get(url, stream=True, verify=verify_certificates)
                 if r.ok == False:
                     raise ValueError(
-                        "Could not download from {}: HTTP {}. Reason: {}".format(
-                            url, r.status_code, r.reason
-                        )
+                        f"Could not download from {url}: HTTP {r.status_code}. Reason: {r.reason}"
                     )
 
                 with open(filename_dest, write_mode) as fh:
                     for chunk in r.iter_content(chunk_size=1024 * 1024):
-                        # size += len(chunk)
-                        # print("WRITE     ", datetime.now(), len(chunk))
                         if chunk:  # filter out keep-alive new chunks
                             fh.write(chunk)
-                        # print("DONE WRITE", datetime.now())
-
-                # print("DONE", datetime.now())
 
                 r.raise_for_status()
-                # print("{} bytes written".format(size))
                 actual_file_size = os.path.getsize(filename_dest)
                 if actual_file_size != int(file_size):
                     if self.collect_files_with_wrong_length:
                         self.files_with_wrong_length.append(filename)
                     else:
                         print(
-                            "WARNING! File {} has the wrong length: Expected: {} Actual size: {}".format(
-                                filename_dest, int(file_size), actual_file_size
-                            )
+                            f"WARNING! File {filename_dest} has the wrong length: Expected: {int(file_size)} Actual size: {actual_file_size}"
                         )
                         print(
                             "REASON: The connection has been silently dropped upstreams.",
                             "Please check the http timeout settings of the openBIS datastore server",
                         )
             except Exception as err:
-                print("ERROR while writing file {}: {}".format(filename_dest, err))
+                print(f"ERROR while writing file {filename_dest}: {err}")
 
             finally:
                 self.download_queue.task_done()
@@ -1255,9 +1243,7 @@ class PhysicalData:
         """
 
         for attr in self.attrs:
-            html += "<tr> <td>{}</td> <td>{}</td> </tr>".format(
-                attr, getattr(self, attr, "")
-            )
+            html += f"<tr> <td>{attr}</td> <td>{getattr(self, attr, '')}</td> </tr>"
 
         html += """
             </tbody>
diff --git a/pybis/src/python/pybis/definitions.py b/pybis/src/python/pybis/definitions.py
index 3fa68259bbddd448d3a6b9e2c74bc4f3b7448a07..a04bd8e33f8cf1b9c557b2dd5332c2fbc4688854 100644
--- a/pybis/src/python/pybis/definitions.py
+++ b/pybis/src/python/pybis/definitions.py
@@ -475,7 +475,7 @@ def get_fetchoption_for_entity(entity):
 
 def get_type_for_entity(entity, action, parents_or_children=""):
     if action not in "create update delete search".split():
-        raise ValueError("unknown action: {}".format(action))
+        raise ValueError(f"unknown action: {action}")
 
     definition = openbis_definitions(entity)
     if action in definition and not parents_or_children:
@@ -492,19 +492,11 @@ def get_type_for_entity(entity, action, parents_or_children=""):
 
         if parents_or_children:
             return {
-                "@type": "as.dto.{}.{}.{}{}{}".format(
-                    entity.lower(),
-                    action,
-                    cap_entity,
-                    parents_or_children,
-                    noun[action],
-                )
+                "@type": f"as.dto.{entity.lower()}.{action}.{cap_entity}{parents_or_children}{noun[action]}"
             }
         else:
             return {
-                "@type": "as.dto.{}.{}.{}{}".format(
-                    entity.lower(), action, cap_entity, noun[action]
-                )
+                "@type": f"as.dto.{entity.lower()}.{action}.{cap_entity}{noun[action]}"
             }
 
 
@@ -523,12 +515,12 @@ def get_fetchoptions(entity, including=None):
     return fo
 
 
-def get_method_for_entity(entity, action):
+def get_method_for_entity(entity: str, action: str) -> str:
     action = action.lower()
 
     if entity == "vocabulary":
-        return "{}Vocabularies".format(action)
+        return f"{action}Vocabularies"
 
     cap_entity = entity[:1].upper() + entity[1:]
 
-    return "{}{}s".format(action, cap_entity)
+    return f"{action}{cap_entity}s"
diff --git a/pybis/src/python/pybis/entity_type.py b/pybis/src/python/pybis/entity_type.py
index a4a5de41bb9047efa7d36f7c24175adf9e6cf5af..60a97b954db4a9fed27156663968dfa91ba5b060 100644
--- a/pybis/src/python/pybis/entity_type.py
+++ b/pybis/src/python/pybis/entity_type.py
@@ -155,7 +155,7 @@ class EntityType:
         芦initialValueForExistingEntities禄 too.
         """
         if self.is_new:
-            raise ValueError("Please save {} first".format(self.entity))
+            raise ValueError(f"Please save {self.entity} first")
 
         if isinstance(prop, str):
             property_type = self.openbis.get_property_type(prop.upper())
diff --git a/pybis/src/python/pybis/experiment.py b/pybis/src/python/pybis/experiment.py
index b9dd9c64f88e4b7e577a68fbdf1b9df1c24f9661..488418cdacfd6d5f526b9a1a0f31c69db1ac7fb2 100644
--- a/pybis/src/python/pybis/experiment.py
+++ b/pybis/src/python/pybis/experiment.py
@@ -108,9 +108,7 @@ class Experiment(
             # a sample can only belong to exactly one experiment
             if obj.experiment is not None:
                 raise ValueError(
-                    "sample {} already belongs to experiment {}".format(
-                        obj.code, obj.experiment
-                    )
+                    f"sample {obj.code} already belongs to experiment {obj.experiment}"
                 )
             else:
                 if self.is_new:
diff --git a/pybis/src/python/pybis/group.py b/pybis/src/python/pybis/group.py
index d1ec21c1702d2bf7277ff6c3250274f21bebb91a..c48221d3700cf7a7a94780abbaff729a75afdf32 100644
--- a/pybis/src/python/pybis/group.py
+++ b/pybis/src/python/pybis/group.py
@@ -89,15 +89,11 @@ class Group(
         try:
             self.openbis.assign_role(role=role, group=self, **kwargs)
             if VERBOSE:
-                print(
-                    "Role {} successfully assigned to group {}".format(role, self.code)
-                )
+                print(f"Role {role} successfully assigned to group {self.code}")
         except ValueError as e:
             if "exists" in str(e):
                 if VERBOSE:
-                    print(
-                        "Role {} already assigned to group {}".format(role, self.code)
-                    )
+                    print(f"Role {role} already assigned to group {self.code}")
             else:
                 raise ValueError(str(e))
 
@@ -120,9 +116,7 @@ class Group(
                 query["project"] = project.upper()
 
             # build a query string for dataframe
-            querystr = " & ".join(
-                '{} == "{}"'.format(key, value) for key, value in query.items()
-            )
+            querystr = " & ".join(f'{key} == "{value}"' for key, value in query.items())
             roles = self.get_roles().df
             if len(roles) == 0:
                 if VERBOSE:
diff --git a/pybis/src/python/pybis/material.py b/pybis/src/python/pybis/material.py
index e891dc953f42c573920ff5771519d1e70f731772..c229a442efd953d91eb8fe815a02262457f4372a 100644
--- a/pybis/src/python/pybis/material.py
+++ b/pybis/src/python/pybis/material.py
@@ -36,9 +36,7 @@ class Material(OpenBisObject):
                     or getattr(self.props, prop_name) == ""
                 ):
                     raise ValueError(
-                        "Property '{}' is mandatory and must not be None".format(
-                            prop_name
-                        )
+                        f"Property '{prop_name}' is mandatory and must not be None"
                     )
 
         props = self.p._all_props()
@@ -66,4 +64,4 @@ class Material(OpenBisObject):
     def delete(self, reason="no reason"):
         self.openbis.delete_entity(entity=self.entity, id=self.permId, reason=reason)
         if VERBOSE:
-            print("Material {} successfully deleted.".format(self.permId))
+            print(f"Material {self.permId} successfully deleted.")
diff --git a/pybis/src/python/pybis/openbis_object.py b/pybis/src/python/pybis/openbis_object.py
index 0dc2b8ce3cd612c3476485e1b4c9358497be1bf7..ff94cde0b8e9d4564281f537944f410a037039f4 100644
--- a/pybis/src/python/pybis/openbis_object.py
+++ b/pybis/src/python/pybis/openbis_object.py
@@ -150,7 +150,7 @@ class OpenBisObject:
             entity=self._entity, objectId=self.data["permId"], reason=reason
         )
         if VERBOSE:
-            print("{} {} successfully deleted.".format(self._entity, self.permId))
+            print(f"{self._entity} {self.permId} successfully deleted.")
 
     def _get_single_item_method(self):
         single_item_method = None
@@ -174,9 +174,7 @@ class OpenBisObject:
                         or getattr(self.props, prop_name) == ""
                     ):
                         raise ValueError(
-                            "Property '{}' is mandatory and must not be None".format(
-                                prop_name
-                            )
+                            f"Property '{prop_name}' is mandatory and must not be None"
                         )
 
             props = self.p._all_props()
@@ -190,7 +188,7 @@ class OpenBisObject:
             resp = self.openbis._post_request(self.openbis.as_v3, request)
 
             if VERBOSE:
-                print("{} successfully created.".format(self.entity))
+                print(f"{self.entity} successfully created.")
             new_entity_data = get_single_item(resp[0]["permId"], only_data=True)
             self._set_data(new_entity_data)
             return self
@@ -204,7 +202,7 @@ class OpenBisObject:
 
             resp = self.openbis._post_request(self.openbis.as_v3, request)
             if VERBOSE:
-                print("{} successfully updated.".format(self.entity))
+                print(f"{self.entity} successfully updated.")
             new_entity_data = get_single_item(
                 self.permId, only_data=True, use_cache=False
             )
@@ -290,9 +288,7 @@ class Transaction:
                                     or getattr(entity.props, prop_name) == ""
                                 ):
                                     raise ValueError(
-                                        "Property '{}' is mandatory and must not be None".format(
-                                            prop_name
-                                        )
+                                        f"Property '{prop_name}' is mandatory and must not be None"
                                     )
                     props = entity.p._all_props()
 
diff --git a/pybis/src/python/pybis/person.py b/pybis/src/python/pybis/person.py
index 4bd8ae72ef6cc355ae41bdc502a588cc781db579..ccd9020f8cafa681c8cd5dbfd6453b5e4d03bd86 100644
--- a/pybis/src/python/pybis/person.py
+++ b/pybis/src/python/pybis/person.py
@@ -1,3 +1,4 @@
+from regex import F
 from .attribute import AttrHolder
 from .openbis_object import OpenBisObject
 from .utils import VERBOSE
@@ -50,19 +51,11 @@ class Person(OpenBisObject):
         try:
             self.openbis.assign_role(role=role, person=self, **kwargs)
             if VERBOSE:
-                print(
-                    "Role {} successfully assigned to person {}".format(
-                        role, self.userId
-                    )
-                )
+                print(f"Role {role} successfully assigned to person {self.userId}")
         except ValueError as e:
             if "exists" in str(e):
                 if VERBOSE:
-                    print(
-                        "Role {} already assigned to person {}".format(
-                            role, self.userId
-                        )
-                    )
+                    print(f"Role {role} already assigned to person {self.userId}")
             else:
                 raise ValueError(str(e))
 
@@ -91,9 +84,7 @@ class Person(OpenBisObject):
                     query["project"] = project.code.upper()
 
             # build a query string for dataframe
-            querystr = " & ".join(
-                '{} == "{}"'.format(key, value) for key, value in query.items()
-            )
+            querystr = " & ".join(f'{key} == "{value}"' for key, value in query.items())
             roles = self.get_roles().df
             if len(roles) == 0:
                 if VERBOSE:
@@ -107,11 +98,11 @@ class Person(OpenBisObject):
         ra = self.openbis.get_role_assignment(techId)
         ra.delete(reason)
         if VERBOSE:
-            print("Role {} successfully revoked from person {}".format(role, self.code))
+            print(f"Role {role} successfully revoked from person {self.code}")
         return
 
     def __str__(self):
-        return "{} {}".format(self.get("firstName"), self.get("lastName"))
+        return f'{self.get("firstName")} {self.get("lastName")}'
 
     def delete(self, reason):
         raise ValueError("Persons cannot be deleted")
diff --git a/pybis/src/python/pybis/property.py b/pybis/src/python/pybis/property.py
index c252148b088dceb37285be6ca227d0c4b7ff2099..a677fd77f01631226d3bbf55ec6f77ffbcca3965 100644
--- a/pybis/src/python/pybis/property.py
+++ b/pybis/src/python/pybis/property.py
@@ -122,9 +122,7 @@ class PropertyHolder:
         """
         if name not in self._property_names:
             raise KeyError(
-                "No such property: '{}'. Allowed properties are: {}".format(
-                    name, ", ".join(self._property_names.keys())
-                )
+                f"No such property: 芦{name}禄. Allowed properties are: {', '.join(self._property_names.keys())}"
             )
         property_type = self._property_names[name]
         data_type = property_type["dataType"]
@@ -133,13 +131,11 @@ class PropertyHolder:
             value = str(value).upper()
             if value not in terms.df["code"].values:
                 raise ValueError(
-                    "Value for attribute {} must be one of these terms: {}".format(
-                        name, ", ".join(terms.df["code"].values)
-                    )
+                    f"Value for attribute 芦{name}禄 must be one of these terms: {', '.join(terms.df['code'].values)}"
                 )
         elif data_type in ("INTEGER", "BOOLEAN", "VARCHAR"):
             if not check_datatype(data_type, value):
-                raise ValueError("Value must be of type {}".format(data_type))
+                raise ValueError(f"Value must be of type {data_type}")
         self.__dict__[name] = value
 
     def __setitem__(self, key, value):
@@ -176,13 +172,18 @@ class PropertyHolder:
         """
 
         for prop_name, prop in self._property_names.items():
-            html += "<tr> <td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td> </tr>".format(
-                prop_name,
-                nvl(getattr(self, prop_name, ""), ""),
-                prop.get("description"),
-                prop.get("dataType"),
-                prop.get("mandatory"),
+            html += "<tr>"
+            html += "".join(
+                f"<td>{item}</td>"
+                for item in [
+                    prop_name,
+                    nvl(getattr(self, prop_name, ""), ""),
+                    prop.get("description"),
+                    prop.get("dataType"),
+                    prop.get("mandatory"),
+                ]
             )
+            html += "</tr>"
 
         html += """
             </tbody>
diff --git a/pybis/src/python/pybis/pybis.py b/pybis/src/python/pybis/pybis.py
index 6f0c6a1314d642170751cef7286e0f5b2f1f6d76..50cf3e9a15938a37c22364318932a9ffd5004097 100644
--- a/pybis/src/python/pybis/pybis.py
+++ b/pybis/src/python/pybis/pybis.py
@@ -200,14 +200,12 @@ def _type_for_id(ident, entity):
 
         search_request = {
             "identifier": ident.upper(),
-            "@type": "as.dto.{}.id.{}Identifier".format(
-                entity.lower(), entity_capitalize
-            ),
+            "@type": f"as.dto.{entity.lower()}.id.{entity_capitalize}Identifier",
         }
     else:
         search_request = {
             "permId": ident,
-            "@type": "as.dto.{}.id.{}PermId".format(entity.lower(), entity_capitalize),
+            "@type": f"as.dto.{entity.lower()}.id.{entity_capitalize}PermId",
         }
     return search_request
 
@@ -253,9 +251,7 @@ def _tagIds_for_tags(tags=None, action="Add"):
         "actions": [
             {
                 "items": items,
-                "@type": "as.dto.common.update.ListUpdateAction{}".format(
-                    action.capitalize()
-                ),
+                "@type": f"as.dto.common.update.ListUpdateAction{action.capitalize()}",
             }
         ],
         "@type": "as.dto.common.update.IdListUpdateValue",
@@ -274,7 +270,7 @@ def _list_update(ids=None, entity=None, action="Add"):
         map(
             lambda id: {
                 "code": id,
-                "@type": "as.dto.{}.id.{}Code".format(entity.lower(), entity),
+                "@type": f"as.dto.{entity.lower()}.id.{entity}Code",
             },
             ids,
         )
@@ -284,9 +280,7 @@ def _list_update(ids=None, entity=None, action="Add"):
         "actions": [
             {
                 "items": items,
-                "@type": "as.dto.common.update.ListUpdateAction{}".format(
-                    action.capitalize()
-                ),
+                "@type": f"as.dto.common.update.ListUpdateAction{action.capitalize()}",
             }
         ],
         "@type": "as.dto.common.update.IdListUpdateValue",
@@ -295,7 +289,7 @@ def _list_update(ids=None, entity=None, action="Add"):
 
 
 def get_field_value_search(field, value, comparison="StringEqualToValue"):
-    return {"value": value, "@type": "as.dto.common.search.{}".format(comparison)}
+    return {"value": value, "@type": f"as.dto.common.search.{comparison}"}
 
 
 def _common_search(search_type, value, comparison="StringEqualToValue"):
@@ -303,7 +297,7 @@ def _common_search(search_type, value, comparison="StringEqualToValue"):
         "@type": search_type,
         "fieldValue": {
             "value": value,
-            "@type": "as.dto.common.search.{}".format(comparison),
+            "@type": f"as.dto.common.search.{comparison}",
         },
     }
     return sreq
@@ -351,7 +345,7 @@ def _subcriteria_for_userId(userId):
 
 def _subcriteria_for_type(code, entity):
     return {
-        "@type": "as.dto.{}.search.{}TypeSearchCriteria".format(entity.lower(), entity),
+        "@type": f"as.dto.{entity.lower()}.search.{entity}TypeSearchCriteria",
         "criteria": [
             {
                 "@type": "as.dto.common.search.CodeSearchCriteria",
@@ -431,7 +425,7 @@ def _gen_search_criteria(req):
         elif key == "operator":
             sreq["operator"] = val.upper()
         else:
-            sreq["@type"] = "as.dto.{}.search.{}SearchCriteria".format(key, val)
+            sreq["@type"] = f"as.dto.{key}.search.{val}SearchCriteria"
     return sreq
 
 
@@ -1087,9 +1081,7 @@ class Openbis:
             "token",
         ]
         for attr in attrs:
-            html += "<tr> <td>{}</td> <td>{}</td> </tr>".format(
-                attr, getattr(self, attr, "")
-            )
+            html += f"<tr> <td>{attr}</td> <td>{getattr(self, attr, '')}</td> </tr>"
 
         html += """
             </tbody>
@@ -1259,9 +1251,7 @@ class Openbis:
                 return pstore.get("password")
             else:
                 raise Exception(
-                    "This method can only be called from these internal methods: {}".format(
-                        allowed_methods
-                    )
+                    f"This method can only be called from these internal methods: {allowed_methods}"
                 )
 
     def unmount(self, mountpoint=None):
@@ -1285,21 +1275,19 @@ class Openbis:
         if not os.path.ismount(full_mountpoint_path):
             return
 
-        status = subprocess.call("umount {}".format(full_mountpoint_path), shell=True)
+        status = subprocess.call(f"umount {full_mountpoint_path}", shell=True)
         if status == 1:
             status = subprocess.call(
-                'pkill -9 sshfs && umount "{}"'.format(full_mountpoint_path), shell=True
+                f'pkill -9 sshfs && umount "{full_mountpoint_path}"', shell=True
             )
 
         if status == 1:
             raise OSError(
-                "could not unmount mountpoint: {} Please try to unmount manually".format(
-                    full_mountpoint_path
-                )
+                f"could not unmount mountpoint: {full_mountpoint_path} Please try to unmount manually"
             )
         else:
             if VERBOSE:
-                print("Successfully unmounted {}".format(full_mountpoint_path))
+                print(f"Successfully unmounted {full_mountpoint_path}")
             self.mountpoint = None
 
     def is_mounted(self, mountpoint=None):
@@ -1388,9 +1376,7 @@ class Openbis:
         """
         if self.is_mounted():
             if VERBOSE:
-                print(
-                    "openBIS dataStore is already mounted on {}".format(self.mountpoint)
-                )
+                print(f"openBIS dataStore is already mounted on {self.mountpoint}")
             return
 
         def check_sshfs_is_installed():
@@ -1437,13 +1423,11 @@ class Openbis:
         supported_platforms = ["darwin", "linux"]
         if platform not in supported_platforms:
             raise ValueError(
-                "This method is not yet supported on {} plattform".format(platform)
+                f"This method is not yet supported on {platform} plattform"
             )
 
         os_options = {
-            "darwin": "-oauto_cache,reconnect,defer_permissions,noappledouble,negative_vncache,volname={} -oStrictHostKeyChecking=no ".format(
-                hostname
-            ),
+            "darwin": f"-oauto_cache,reconnect,defer_permissions,noappledouble,negative_vncache,volname={hostname} -oStrictHostKeyChecking=no ",
             "linux": "-oauto_cache,reconnect -oStrictHostKeyChecking=no",
         }
 
@@ -1475,7 +1459,7 @@ class Openbis:
 
         if status == 0:
             if VERBOSE:
-                print("Mounted successfully to {}".format(full_mountpoint_path))
+                print(f"Mounted successfully to {full_mountpoint_path}")
             self.mountpoint = full_mountpoint_path
             return self.mountpoint
         else:
@@ -1581,7 +1565,7 @@ class Openbis:
         try:
             return self._post_request(self.as_v1, request)
         except Exception as e:
-            raise ValueError("Could not generate a code for {}: {}".format(entity, e))
+            raise ValueError(f"Could not generate a code for {entity}: {e}")
 
     def gen_permId(self, count=1):
         """Generate a permId (or many permIds) for a dataSet"""
@@ -1590,7 +1574,7 @@ class Openbis:
         try:
             return self._post_request(self.as_v3, request)
         except Exception as exc:
-            raise ValueError("Could not generate a code: {}".format(exc))
+            raise ValueError(f"Could not generate a code: {exc}")
 
     def new_person(self, userId, space=None):
         """creates an openBIS person or returns the existing person"""
@@ -1681,7 +1665,7 @@ class Openbis:
                 else:
                     pass
             else:
-                raise ValueError("unknown search argument {}".format(attr))
+                raise ValueError(f"unknown search argument {attr}")
 
         search_criteria["criteria"] = sub_crit
 
@@ -1748,7 +1732,7 @@ class Openbis:
 
         resp = self._post_request(self.as_v3, request)
         if len(resp) == 0:
-            raise ValueError("No assigned role found for techId={}".format(techId))
+            raise ValueError(f"No assigned role found for techId={techId}")
 
         for permid in resp:
             data = resp[permid]
@@ -1771,7 +1755,7 @@ class Openbis:
         role = role.upper()
         defs = get_definition_for_entity("roleAssignment")
         if role not in defs["role"]:
-            raise ValueError("Role should be one of these: {}".format(defs["role"]))
+            raise ValueError(f"Role should be one of these: {defs['role']}")
         userId = None
         groupId = None
         spaceId = None
@@ -2738,9 +2722,7 @@ class Openbis:
             kind = kind.upper()
             if kind not in ["PHYSICAL", "CONTAINER", "LINK"]:
                 raise ValueError(
-                    "unknown dataSet kind: {}. It should be one of the following: PHYSICAL, CONTAINER or LINK".format(
-                        kind
-                    )
+                    f"unknown dataSet kind: {kind}. It should be one of the following: PHYSICAL, CONTAINER or LINK"
                 )
             fetchopts["kind"] = kind
             raise NotImplementedError("you cannot search for dataSet kinds yet")
@@ -3072,7 +3054,7 @@ class Openbis:
         if not isinstance(permids, list):
             permids = [permids]
 
-        type = "as.dto.{}.id.{}".format(entity.lower(), entity.capitalize())
+        type = f"as.dto.{entity.lower()}.id.{entity.capitalize()}"
         search_params = []
         for permid in permids:
             # decide if we got a permId or an identifier
@@ -3224,9 +3206,7 @@ class Openbis:
 
         if resp is None or len(resp) == 0:
             raise ValueError(
-                "no VocabularyTerm found with code='{}' and vocabularyCode='{}'".format(
-                    code, vocabularyCode
-                )
+                f"no VocabularyTerm found with code='{code}' and vocabularyCode='{vocabularyCode}'"
             )
         else:
             parse_jackson(resp)
@@ -3313,7 +3293,7 @@ class Openbis:
         resp = self._post_request(self.as_v3, request)
 
         if len(resp) == 0:
-            raise ValueError("no {} found with identifier: {}".format(entity, code))
+            raise ValueError(f"no {entity} found with identifier: {code}")
         else:
             parse_jackson(resp)
             for ident in resp:
@@ -3384,7 +3364,7 @@ class Openbis:
 
         if just_one:
             if len(resp) == 0:
-                raise ValueError("no such tag found: {}".format(permId))
+                raise ValueError(f"no such tag found: {permId}")
 
             parse_jackson(resp)
             for permId in resp:
@@ -3817,7 +3797,7 @@ class Openbis:
 
         if only_one:
             if len(resp) == 0:
-                raise ValueError("no such propertyType: {}".format(code))
+                raise ValueError(f"no such propertyType: {code}")
             for ident in resp:
                 if only_data:
                     return resp[ident]
@@ -4078,7 +4058,7 @@ class Openbis:
         parse_jackson(resp)
         if len(identifiers) == 1:
             if len(resp) == 0:
-                raise ValueError("no such {}: {}".format(entity, identifier[0]))
+                raise ValueError(f"no such {entity}: {identifier[0]}")
         for ident in resp:
             if only_data:
                 return resp[ident]
@@ -4112,14 +4092,10 @@ class Openbis:
             optional_attributes = []
 
         search_request = {
-            "@type": "as.dto.{}.search.{}TypeSearchCriteria".format(
-                entity.lower(), entity
-            )
+            "@type": f"as.dto.{entity.lower()}.search.{entity}TypeSearchCriteria"
         }
         fetch_options = {
-            "@type": "as.dto.{}.fetchoptions.{}TypeFetchOptions".format(
-                entity.lower(), entity
-            )
+            "@type": f"as.dto.{entity.lower()}.fetchoptions.{entity}TypeFetchOptions"
         }
         fetch_options["from"] = start_with
         fetch_options["count"] = count
@@ -4147,12 +4123,10 @@ class Openbis:
                 if len(response["objects"]) == 1:
                     return EntityType(openbis_obj=self, data=response["objects"][0])
                 elif len(response["objects"]) == 0:
-                    raise ValueError("No such {} type: {}".format(entity, type_name))
+                    raise ValueError(f"No such {entity} type: {type_name}")
                 else:
                     raise ValueError(
-                        "There is more than one entry for entity={} and type={}".format(
-                            entity, type_name
-                        )
+                        f"There is more than one entry for entity={entity} and type={type_name}"
                     )
 
             types = []
@@ -4280,7 +4254,7 @@ class Openbis:
         resp = self._post_request(self.as_v3, request)
         if just_one:
             if len(resp) == 0:
-                raise ValueError("no such dataset found: {}".format(permIds))
+                raise ValueError(f"no such dataset found: {permIds}")
 
             parse_jackson(resp)
 
@@ -4518,7 +4492,7 @@ class Openbis:
 
         if only_one:
             if len(resp) == 0:
-                raise ValueError("no such sample found: {}".format(sample_ident))
+                raise ValueError(f"no such sample found: {sample_ident}")
 
             parse_jackson(resp)
             for sample_ident in resp:
@@ -5212,9 +5186,7 @@ class ServerInformation:
         """
 
         for attr in self.attrs:
-            html += "<tr> <td>{}</td> <td>{}</td> </tr>".format(
-                attr, getattr(self, attr, "")
-            )
+            html += f"<tr> <td>{attr}</td> <td>{getattr(self, attr, '')}</td> </tr>"
 
         html += """
             </tbody>
diff --git a/pybis/src/python/pybis/role_assignment.py b/pybis/src/python/pybis/role_assignment.py
index f2fa0dbc5d3fa8c880b94d4d6bacbdc6ad189bb8..521eb495ff72aea8dff553cfc233b033f1a1264a 100644
--- a/pybis/src/python/pybis/role_assignment.py
+++ b/pybis/src/python/pybis/role_assignment.py
@@ -25,7 +25,7 @@ class RoleAssignment(OpenBisObject):
         return ["id", "role", "roleLevel", "space", "project", "group"]
 
     def __str__(self):
-        return "{}".format(self.get("role"))
+        return f"{self.get('role')}"
 
     def delete(self, reason="no reason specified"):
         self.openbis.delete_openbis_entity(
@@ -33,7 +33,5 @@ class RoleAssignment(OpenBisObject):
         )
         if VERBOSE:
             print(
-                "RoleAssignment role={}, roleLevel={} successfully deleted.".format(
-                    self.role, self.roleLevel
-                )
+                f"RoleAssignment role={self.role}, roleLevel={self.roleLevel} successfully deleted."
             )
diff --git a/pybis/src/python/pybis/sample.py b/pybis/src/python/pybis/sample.py
index df1d7b0828e63a8ce73379397a65fb06a2efcc59..790e9681c4b42677720edde08a05a22de6b87f94 100644
--- a/pybis/src/python/pybis/sample.py
+++ b/pybis/src/python/pybis/sample.py
@@ -211,9 +211,7 @@ class Sample(OpenBisObject, entity="sample", single_item_method_name="get_sample
                             or getattr(self.props, prop_name) == ""
                         ):
                             raise ValueError(
-                                "Property '{}' is mandatory and must not be None".format(
-                                    prop_name
-                                )
+                                f"Property '{prop_name}' is mandatory and must not be None"
                             )
 
             sampleProject = self.project.code if self.project else None
@@ -248,7 +246,7 @@ class Sample(OpenBisObject, entity="sample", single_item_method_name="get_sample
                 if resp["rows"][0][0]["value"] != "OK":
                     raise ValueError("Status is not OK")
                 if VERBOSE:
-                    print("{} successfully created.".format(self.entity))
+                    print(f"{self.entity} successfully created.")
                 permId = permid = resp["rows"][0][2]["value"]
                 new_entity_data = self.openbis.get_sample(permId, only_data=True)
                 self._set_data(new_entity_data)
diff --git a/pybis/src/python/pybis/semantic_annotation.py b/pybis/src/python/pybis/semantic_annotation.py
index 7c4aae67c38dd17f9a6dcee2157532c853163acf..af4e5fbb87c3953e92508408e3ba9f47d1f7aab3 100644
--- a/pybis/src/python/pybis/semantic_annotation.py
+++ b/pybis/src/python/pybis/semantic_annotation.py
@@ -161,9 +161,7 @@ class SemanticAnnotation:
         """
 
         for attr in attrs:
-            html += "<tr> <td>{}</td> <td>{}</td> </tr>".format(
-                attr, getattr(self, attr, "")
-            )
+            html += f"<tr> <td>{attr}</td> <td>{getattr(self, attr, '')}</td> </tr>"
 
         html += """
             </tbody>
diff --git a/pybis/src/python/pybis/space.py b/pybis/src/python/pybis/space.py
index 47fc3c07ddcb0f98dc283675f9dd1f4a78608b79..3a708a94a8f67a91b88aa437dbb169a2f5e60bdb 100644
--- a/pybis/src/python/pybis/space.py
+++ b/pybis/src/python/pybis/space.py
@@ -47,10 +47,10 @@ class Space(OpenBisObject, entity="space", single_item_method_name="get_space"):
             return self.openbis.get_sample(sample_code)
         else:
             if project_code is None:
-                return self.openbis.get_sample("/{}/{}".format(self.code, sample_code))
+                return self.openbis.get_sample(f"/{self.code}/{sample_code}")
             else:
                 return self.openbis.get_sample(
-                    "/{}/{}/{}".format(self.code, project_code, sample_code)
+                    f"/{self.code}/{project_code}/{sample_code}"
                 )
 
     get_object = get_sample  # Alias
diff --git a/pybis/src/python/pybis/things.py b/pybis/src/python/pybis/things.py
index 68c4acbfe37f128ea4736af4203022b4f2ddc54f..1bf370c2826a4f2cd838b532210d8d14b5cb4966 100644
--- a/pybis/src/python/pybis/things.py
+++ b/pybis/src/python/pybis/things.py
@@ -93,7 +93,7 @@ class Things:
 
     def get_parents(self, **kwargs):
         if self.entity not in ["sample", "dataset"]:
-            raise ValueError("{}s do not have parents".format(self.entity))
+            raise ValueError(f"{self.entity}s do not have parents")
 
         if self.df is not None and len(self.df) > 0:
             dfs = []
@@ -116,7 +116,7 @@ class Things:
 
     def get_children(self, **kwargs):
         if self.entity not in ["sample", "dataset"]:
-            raise ValueError("{}s do not have children".format(self.entity))
+            raise ValueError(f"{self.entity}s do not have children")
 
         if self.df is not None and len(self.df) > 0:
             dfs = []
@@ -140,7 +140,7 @@ class Things:
 
     def get_samples(self, **kwargs):
         if self.entity not in ["space", "project", "experiment"]:
-            raise ValueError("{}s do not have samples".format(self.entity))
+            raise ValueError(f"{self.entity}s do not have samples")
 
         if self.df is not None and len(self.df) > 0:
             dfs = []
@@ -165,7 +165,7 @@ class Things:
 
     def get_datasets(self, **kwargs):
         if self.entity not in ["sample", "experiment"]:
-            raise ValueError("{}s do not have datasets".format(self.entity))
+            raise ValueError(f"{self.entity}s do not have datasets")
 
         if self.df is not None and len(self.df) > 0:
             dfs = []
diff --git a/pybis/src/python/pybis/utils.py b/pybis/src/python/pybis/utils.py
index b8453c4fe2c16e5ff6c61ee1622fe8e1b856d9c3..bc5329fa73ce676682a9fef36c35abf183923a33 100644
--- a/pybis/src/python/pybis/utils.py
+++ b/pybis/src/python/pybis/utils.py
@@ -285,7 +285,7 @@ def extract_person(person):
 def extract_person_details(person):
     if not isinstance(person, dict):
         return str(person)
-    return "{} {} <{}>".format(person["firstName"], person["lastName"], person["email"])
+    return "{firstName} {lastName} <{email}>".format(**person)
 
 
 def extract_id(id):
diff --git a/pybis/src/python/pybis/vocabulary.py b/pybis/src/python/pybis/vocabulary.py
index e2b09d707a6f18eca0347e71d633cdf45c67223d..76aa2d3a055204bc73d177ffd64f36bb22ebc935 100644
--- a/pybis/src/python/pybis/vocabulary.py
+++ b/pybis/src/python/pybis/vocabulary.py
@@ -25,9 +25,7 @@ class Vocabulary(
             for key in kwargs:
                 if key not in allowed_attrs:
                     raise ValueError(
-                        "{} is an unknown Vocabulary attribute. Allowed attributes are: {}".format(
-                            key, ", ".join(allowed_attrs)
-                        )
+                        f"{key} is an unknown Vocabulary attribute. Allowed attributes are: {', '.join(allowed_attrs)}"
                     )
 
         if kwargs is not None:
@@ -77,7 +75,7 @@ class Vocabulary(
         }
         resp = self.openbis._post_request(self.openbis.as_v3, request)
         if VERBOSE:
-            print("{} {} successfully deleted.".format(self.entity, self.code))
+            print(f"{self.entity} {self.code} successfully deleted.")
 
     def save(self):
         terms = self._terms or []