diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d95c4620d281693da9e69143c06db82e5796ac14..c2d071662c26322d44ed98e6e164c523edcae5af 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -57,7 +57,7 @@ mypy:
   tags: [ docker ]
   stage: linting
   script:
-    - pip install mypy types-PyYAML types-jsonschema types-requests types-setuptools types-lxml types-python-dateutil
+    - pip install mypy types-PyYAML types-jsonschema types-requests types-setuptools types-lxml types-python-dateutil pytest
     - make mypy
   allow_failure: true
 
diff --git a/Makefile b/Makefile
index eb767dd4053a2b232d425126358cfb0fd23ffb1c..21ea40ac8a6eb34032aba75c089e278fa354a6f5 100644
--- a/Makefile
+++ b/Makefile
@@ -44,7 +44,7 @@ lint:
 .PHONY: lint
 
 mypy:
-	mypy src/linkahead
+	mypy src/linkahead/common unittests
 .PHONY: mypy
 
 unittest:
diff --git a/setup.py b/setup.py
index 8a9276d0205fef49d59b7c41b70d21312b074642..27f305c28c70dccdbf1a27fd5a2a4aa9e153f006 100755
--- a/setup.py
+++ b/setup.py
@@ -193,7 +193,7 @@ def setup_package():
         tests_require=["pytest", "pytest-cov", "coverage>=4.4.2",
                        "jsonschema>=4.4.0"],
         package_data={
-            'linkahead': ['cert/indiscale.ca.crt', 'schema-pycaosdb-ini.yml'],
+            'linkahead': ['py.typed', 'cert/indiscale.ca.crt', 'schema-pycaosdb-ini.yml'],
         },
         scripts=[
             "src/linkahead/utils/caosdb_admin.py",
diff --git a/src/linkahead/common/datatype.py b/src/linkahead/common/datatype.py
index c0c15feca240112f1f8e33a0cd37932151fcd9f0..65e6246c0287f0af07aa604f4bc18ce54615cae2 100644
--- a/src/linkahead/common/datatype.py
+++ b/src/linkahead/common/datatype.py
@@ -24,6 +24,10 @@
 #
 
 import re
+import sys
+
+if sys.version_info >= (3, 8):
+    from typing import Literal
 
 from ..exceptions import EmptyUniqueQueryError, QueryNotUniqueError
 
@@ -34,6 +38,8 @@ DATETIME = "DATETIME"
 INTEGER = "INTEGER"
 FILE = "FILE"
 BOOLEAN = "BOOLEAN"
+if sys.version_info >= (3, 8):
+    DATATYPE = Literal["DOUBLE", "REFERENCE", "TEXT", "DATETIME", "INTEGER", "FILE", "BOOLEAN"]
 
 
 def LIST(datatype):
diff --git a/src/linkahead/common/models.py b/src/linkahead/common/models.py
index d7bc7a4767467d84b76534c438d7606d1b4e1c24..1d8e8832a3d215363af5ffcb3139d24cb6c27bc3 100644
--- a/src/linkahead/common/models.py
+++ b/src/linkahead/common/models.py
@@ -35,6 +35,7 @@ transactions.
 
 from __future__ import annotations  # Can be removed with 3.10.
 from __future__ import print_function, unicode_literals
+from enum import Enum
 
 import re
 import sys
@@ -46,7 +47,14 @@ from os import listdir
 from os.path import isdir
 from random import randint
 from tempfile import NamedTemporaryFile
-from typing import Any, Optional
+
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING and sys.version_info > (3, 7):
+    from datetime import datetime
+    from typing import Any, Dict, Optional, Type, Union, List, TextIO, Tuple, Literal
+    from .datatype import DATATYPE
+
 from warnings import warn
 
 from lxml import etree
@@ -63,8 +71,16 @@ from ..exceptions import (AmbiguousEntityError, AuthorizationError,
                           QueryNotUniqueError, TransactionError,
                           UniqueNamesError, UnqualifiedParentsError,
                           UnqualifiedPropertiesError)
-from .datatype import (BOOLEAN, DATETIME, DOUBLE, INTEGER, TEXT,
-                       get_list_datatype, is_list_datatype, is_reference)
+from .datatype import (
+    BOOLEAN,
+    DATETIME,
+    DOUBLE,
+    INTEGER,
+    TEXT,
+    get_list_datatype,
+    is_list_datatype,
+    is_reference,
+)
 from .state import State
 from .timezone import TimeZone
 from .utils import uuid, xml2str
@@ -72,14 +88,14 @@ from .versioning import Version
 
 _ENTITY_URI_SEGMENT = "Entity"
 
-# importances/inheritance
 OBLIGATORY = "OBLIGATORY"
 SUGGESTED = "SUGGESTED"
 RECOMMENDED = "RECOMMENDED"
 FIX = "FIX"
 ALL = "ALL"
 NONE = "NONE"
-
+if TYPE_CHECKING:
+    INHERITANCE = Literal["OBLIGATORY", "SUGGESTED", "RECOMMENDED", "FIX", "ALL", "NONE"]
 
 SPECIAL_ATTRIBUTES = ["name", "role", "datatype", "description",
                       "id", "path", "checksum", "size", "value"]
@@ -98,41 +114,50 @@ class Entity:
     by the user to control several server-side plug-ins.
     """
 
-    def __init__(self, name=None, id=None, description=None,  # @ReservedAssignment
-                 datatype=None, value=None, **kwargs):
+    def __init__(
+        self,
+        name: Optional[str] = None,
+        id: Optional[int] = None,
+        description: Optional[str] = None,  # @ReservedAssignment
+        datatype: Optional[DATATYPE] = None,
+        value=None,
+        **kwargs,
+    ):
+
         self.__role = kwargs["role"] if "role" in kwargs else None
-        self._checksum = None
+        self._checksum: Optional[str] = None
         self._size = None
         self._upload = None
         # If an entity is used (e.g. as parent), it is wrapped instead of being used directly.
         # see Entity._wrap()
-        self._wrapped_entity = None
-        self._version = None
-        self._cuid = None
-        self._flags = dict()
+        self._wrapped_entity: Optional[Entity] = None
+        self._version: Optional[Version] = None
+        self._cuid: Optional[str] = None
+        self._flags: Dict[str, str] = dict()
         self.__value = None
-        self.__datatype = None
-        self.datatype = datatype
+        self.__datatype: Optional[DATATYPE] = None
+        self.datatype: Optional[DATATYPE] = datatype
         self.value = value
         self.messages = Messages()
         self.properties = _Properties()
         self.parents = _ParentList()
-        self.path = None
-        self.file = None
-        self.unit = None
-        self.acl = None
-        self.permissions = None
+        self.path: Optional[str] = None
+        self.file: Optional[File] = None
+        self.unit: Optional[str] = None
+        self.acl: Optional[ACL] = None
+        self.permissions: Optional[Permissions] = None
         self.is_valid = lambda: False
         self.is_deleted = lambda: False
         self.name = name
         self.description = description
-        self.id = id
-        self.state = None
+        self.id: Optional[int] = id
+        self.state: Optional[State] = None
 
     def copy(self):
         """
         Return a copy of entity.
 
+        FIXME: This method doesn't have a deep keyword argument.
         If deep == True return a deep copy, recursively copying all sub entities.
 
         Standard properties are copied using add_property.
@@ -178,7 +203,7 @@ class Entity:
         return self._wrapped_entity.version
 
     @version.setter
-    def version(self, version):
+    def version(self, version: Optional[Version]):
         self._version = version
 
     @property
@@ -250,14 +275,14 @@ class Entity:
 
         return self._wrapped_entity.description
 
-    @property
-    def checksum(self):
-        return self._checksum
-
     @description.setter
     def description(self, new_description):
         self.__description = new_description
 
+    @property
+    def checksum(self):
+        return self._checksum
+
     @property
     def unit(self):
         if self.__unit is not None or self._wrapped_entity is None:
@@ -324,8 +349,15 @@ class Entity:
     def pickup(self, new_pickup):
         self.__pickup = new_pickup
 
-    def grant(self, realm=None, username=None, role=None,
-              permission=None, priority=False, revoke_denial=True):
+    def grant(
+        self,
+        realm: Optional[str] = None,
+        username: Optional[str] = None,
+        role: Optional[str] = None,
+        permission: Optional[str] = None,
+        priority: bool = False,
+        revoke_denial: bool = True,
+    ):
         """Grant a permission to a user or role for this entity.
 
         You must specify either only the username and the realm, or only the
@@ -359,8 +391,15 @@ class Entity:
                        permission=permission, priority=priority,
                        revoke_denial=revoke_denial)
 
-    def deny(self, realm=None, username=None, role=None,
-             permission=None, priority=False, revoke_grant=True):
+    def deny(
+        self,
+        realm: Optional[str] = None,
+        username: Optional[str] = None,
+        role: Optional[str] = None,
+        permission: Optional[str] = None,
+        priority: bool = False,
+        revoke_grant: bool = True,
+    ):
         """Deny a permission to a user or role for this entity.
 
         You must specify either only the username and the realm, or only the
@@ -412,7 +451,7 @@ class Entity:
             permission=permission,
             priority=priority)
 
-    def is_permitted(self, permission, role=None):
+    def is_permitted(self, permission: Permission, role: Optional[str] = None):
         if role is None:
             # pylint: disable=unsupported-membership-test
 
@@ -420,7 +459,7 @@ class Entity:
         else:
             self.acl.is_permitted(permission=permission)
 
-    def get_all_messages(self):
+    def get_all_messages(self) -> Messages:
         ret = Messages()
         ret.append(self.messages)
 
@@ -519,8 +558,29 @@ class Entity:
 
         return self
 
-    def add_property(self, property=None, value=None, id=None, name=None, description=None, datatype=None,
-                     unit=None, importance=None, inheritance=None):  # @ReservedAssignment
+    def add_property(
+        self,
+        property: Union[int, str, Entity, None] = None,
+        value: Union[
+            int,
+            str,
+            bool,
+            datetime,
+            Entity,
+            List[int],
+            List[str],
+            List[bool],
+            List[Entity],
+            None,
+        ] = None,
+        id: Optional[int] = None,
+        name: Optional[str] = None,
+        description: Optional[str] = None,
+        datatype: Optional[str] = None,
+        unit: Optional[str] = None,
+        importance: Optional[str] = None,
+        inheritance: Union[str, INHERITANCE, None] = None,
+    ) -> Entity:  # @ReservedAssignment
         """Add a property to this entity.
 
         The first parameter is meant to identify the property entity either via
@@ -690,7 +750,13 @@ class Entity:
 
         return self
 
-    def add_parent(self, parent=None, id=None, name=None, inheritance=None):  # @ReservedAssignment
+    def add_parent(
+        self,
+        parent: Union[Entity, int, str, None] = None,
+        id: Optional[int] = None,
+        name: Optional[str] = None,
+        inheritance: Union[INHERITANCE, str, None] = None,
+    ):  # @ReservedAssignment
         """Add a parent to this entity.
 
         Parameters
@@ -704,7 +770,7 @@ class Entity:
         name : str
             Name of the parent entity. Ignored if `parent is not
             none`.
-        inheritance : str
+        inheritance : str, INHERITANCE
             One of ``obligatory``, ``recommended``, ``suggested``, or ``fix``. Specifies the
             minimum importance which parent properties need to have to be inherited by this
             entity. If no `inheritance` is given, no properties will be inherited by the child.
@@ -811,7 +877,7 @@ out: bool
 
         return self.parents
 
-    def get_parents_recursively(self, retrieve: bool = True):
+    def get_parents_recursively(self, retrieve: bool = True) -> List[Entity]:
         """Get all ancestors of this entity.
 
 Parameters
@@ -826,12 +892,12 @@ out: List[Entity]
   The parents of this Entity
 """
 
-        all_parents = []
+        all_parents: List[Entity] = []
         self._get_parent_recursively(all_parents, retrieve=retrieve)
 
         return all_parents
 
-    def _get_parent_recursively(self, all_parents: list, retrieve: bool = True):
+    def _get_parent_recursively(self, all_parents: List[Entity], retrieve: bool = True):
         """Get all ancestors with a little helper.
 
         As a side effect of this method, the ancestors are added to
@@ -862,7 +928,7 @@ out: List[Entity]
                 all_parents.append(w_parent)
                 w_parent._get_parent_recursively(all_parents, retrieve=retrieve)
 
-    def get_parent(self, key):
+    def get_parent(self, key: Union[int, Entity, str]) -> Union[Entity, None]:
         """Return the first parent matching the key or None if no match exists.
 
         Parameters
@@ -911,7 +977,7 @@ out: List[Entity]
 
         return self.properties
 
-    def get_property(self, pattern):
+    def get_property(self, pattern: Union[int, str, Entity]) -> Union[Property, None]:
         """ Return the first matching property or None.
 
         Parameters
@@ -956,7 +1022,9 @@ out: List[Entity]
 
         return None
 
-    def _get_value_for_selector(self, selector):
+    def _get_value_for_selector(
+        self, selector: Union[str, List[str], Tuple[str]]
+    ) -> Any:
         """return the value described by the selector
 
         A selector is a list or a tuple of strings describing a path in an
@@ -1093,7 +1161,7 @@ out: List[Entity]
 
         return ret
 
-    def get_errors_deep(self, roots=None):
+    def get_errors_deep(self, roots=None) -> List[Tuple[str, List[Entity]]]:
         """Get all error messages of this entity and all sub-entities /
         parents / properties.
 
@@ -1124,7 +1192,12 @@ out: List[Entity]
 
         return False
 
-    def to_xml(self, xml=None, add_properties=ALL, local_serialization=False):
+    def to_xml(
+        self,
+        xml: Optional[etree._Element] = None,
+        add_properties: Optional[INHERITANCE] = ALL,
+        local_serialization: bool = False,
+    ) -> etree._Element:
         """Generate an xml representation of this entity. If the parameter xml
         is given, all attributes, parents, properties, and messages of this
         entity will be added to it instead of creating a new element.
@@ -1144,7 +1217,6 @@ out: List[Entity]
         assert isinstance(xml, etree._Element)
 
         # unwrap wrapped entity
-
         if self._wrapped_entity is not None:
             xml = self._wrapped_entity.to_xml(xml, add_properties)
 
@@ -1394,8 +1466,14 @@ out: List[Entity]
         return Container().append(self).retrieve(
             unique=unique, raise_exception_on_error=raise_exception_on_error, flags=flags)
 
-    def insert(self, raise_exception_on_error=True, unique=True,
-               sync=True, strict=False, flags=None):
+    def insert(
+        self,
+        raise_exception_on_error=True,
+        unique=True,
+        sync=True,
+        strict=False,
+        flags: Optional[dict] = None,
+    ):
         """Insert this entity into a LinkAhead server. A successful insertion will
         generate a new persistent ID for this entity. This entity can be
         identified, retrieved, updated, and deleted via this ID until it has
@@ -1758,14 +1836,20 @@ class Parent(Entity):
     def affiliation(self, affiliation):
         self.__affiliation = affiliation
 
-    def __init__(self, id=None, name=None, description=None, inheritance=None):  # @ReservedAssignment
+    def __init__(
+        self,
+        id: Optional[int] = None,
+        name: Optional[str] = None,
+        description: Optional[str] = None,
+        inheritance: Optional[INHERITANCE] = None,
+    ):  # @ReservedAssignment
         Entity.__init__(self, id=id, name=name, description=description)
 
         if inheritance is not None:
             self.set_flag("inheritance", inheritance)
         self.__affiliation = None
 
-    def to_xml(self, xml=None, add_properties=None):
+    def to_xml(self, xml: Optional[etree._Element] = None, add_properties=None):
         if xml is None:
             xml = etree.Element("Parent")
 
@@ -1822,13 +1906,20 @@ class Property(Entity):
 
         return super(Property, self).add_parent(parent=parent, id=id, name=name, inheritance=inheritance)
 
-    def __init__(self, name=None, id=None, description=None, datatype=None,
-                 value=None, unit=None):
+    def __init__(
+        self,
+        name: Optional[str] = None,
+        id: Optional[int] = None,
+        description: Optional[str] = None,
+        datatype: Union[DATATYPE, None] = None,
+        value=None,
+        unit: Optional[str] = None,
+    ):
         Entity.__init__(self, id=id, name=name, description=description,
                         datatype=datatype, value=value, role="Property")
         self.unit = unit
 
-    def to_xml(self, xml=None, add_properties=ALL):
+    def to_xml(self, xml: Optional[etree._Element] = None, add_properties=ALL):
         if xml is None:
             xml = etree.Element("Property")
 
@@ -1878,13 +1969,19 @@ class Property(Entity):
 
 class Message(object):
 
-    def __init__(self, type=None, code=None, description=None, body=None):  # @ReservedAssignment
+    def __init__(
+        self,
+        type: Optional[str] = None,
+        code: Optional[int] = None,
+        description: Optional[str] = None,
+        body: Optional[str] = None,
+    ):  # @ReservedAssignment
         self.description = description
         self.type = type if type is not None else "Info"
         self.code = int(code) if code is not None else None
         self.body = body
 
-    def to_xml(self, xml=None):
+    def to_xml(self, xml: Optional[etree._Element] = None):
         if xml is None:
             xml = etree.Element(str(self.type))
 
@@ -1926,7 +2023,13 @@ class RecordType(Entity):
             property=property, id=id, name=name, description=description, datatype=datatype,
             value=value, unit=unit, importance=importance, inheritance=inheritance)
 
-    def add_parent(self, parent=None,  id=None, name=None, inheritance=OBLIGATORY):
+    def add_parent(
+        self,
+        parent: Union[Entity, int, str, None] = None,
+        id: Optional[int] = None,
+        name: Optional[str] = None,
+        inheritance: Union[INHERITANCE, str, None] = OBLIGATORY,
+    ):
         """Add a parent to this RecordType
 
         Parameters
@@ -1959,11 +2062,21 @@ class RecordType(Entity):
 
         return super().add_parent(parent=parent, id=id, name=name, inheritance=inheritance)
 
-    def __init__(self, name=None, id=None, description=None, datatype=None):  # @ReservedAssignment
+    def __init__(
+        self,
+        name: Optional[str] = None,
+        id: Optional[int] = None,
+        description: Optional[str] = None,
+        datatype: Optional[DATATYPE] = None,
+    ):  # @ReservedAssignment
         Entity.__init__(self, name=name, id=id, description=description,
                         datatype=datatype, role="RecordType")
 
-    def to_xml(self, xml=None, add_properties=ALL):
+    def to_xml(
+        self,
+        xml: Optional[etree._Element] = None,
+        add_properties: Optional[INHERITANCE] = ALL,
+    ) -> etree._Element:
         if xml is None:
             xml = etree.Element("RecordType")
 
@@ -1982,7 +2095,12 @@ class Record(Entity):
             property=property, id=id, name=name, description=description, datatype=datatype,
             value=value, unit=unit, importance=importance, inheritance=inheritance)
 
-    def __init__(self, name=None, id=None, description=None):  # @ReservedAssignment
+    def __init__(
+        self,
+        name: Optional[str] = None,
+        id: Optional[int] = None,
+        description: Optional[str] = None,
+    ):  # @ReservedAssignment
         Entity.__init__(self, name=name, id=id, description=description,
                         role="Record")
 
@@ -2023,9 +2141,17 @@ class File(Record):
 
     """
 
-    def __init__(self, name=None, id=None, description=None,  # @ReservedAssignment
-                 path=None, file=None, pickup=None,  # @ReservedAssignment
-                 thumbnail=None, from_location=None):
+    def __init__(
+        self,
+        name: Optional[str] = None,
+        id: Optional[int] = None,
+        description: Optional[str] = None,  # @ReservedAssignment
+        path: Optional[str] = None,
+        file: Union[str, TextIO, None] = None,
+        pickup: Optional[str] = None,  # @ReservedAssignment
+        thumbnail: Optional[str] = None,
+        from_location=None,
+    ):
         Record.__init__(self, id=id, name=name, description=description)
         self.role = "File"
         self.datatype = None
@@ -2046,7 +2172,12 @@ class File(Record):
         if self.pickup is None:
             self.pickup = from_location
 
-    def to_xml(self, xml=None, add_properties=ALL, local_serialization=False):
+    def to_xml(
+        self,
+        xml: Optional[etree._Element] = None,
+        add_properties: Optional[INHERITANCE] = ALL,
+        local_serialization: bool = False,
+    ):
         """Convert this file to an xml element.
 
         @return: xml element
@@ -2142,6 +2273,7 @@ class File(Record):
 
 
 class _Properties(list):
+    """FIXME: Add docstring."""
 
     def __init__(self):
         list.__init__(self)
@@ -2161,7 +2293,7 @@ class _Properties(list):
         if property is not None:
             self._importance[property] = importance
 
-    def get_by_name(self, name):
+    def get_by_name(self, name: str) -> Property:
         """Get a property of this list via it's name. Raises a LinkAheadException
         if not exactly one property has this name.
 
@@ -2176,7 +2308,12 @@ class _Properties(list):
 
         return self
 
-    def append(self, property, importance=None, inheritance=None):  # @ReservedAssignment
+    def append(
+        self,
+        property: Union[List[Entity], Entity],
+        importance=None,
+        inheritance: Union[str, INHERITANCE, None] = None,
+    ):  # @ReservedAssignment
         if isinstance(property, list):
             for p in property:
                 self.append(p, importance, inheritance)
@@ -2203,7 +2340,9 @@ class _Properties(list):
 
         return self
 
-    def to_xml(self, add_to_element, add_properties):
+    def to_xml(
+        self, add_to_element: etree._Element, add_properties: Union[str, INHERITANCE]
+    ):
         for p in self:
             importance = self._importance.get(p)
 
@@ -2213,7 +2352,7 @@ class _Properties(list):
             pelem = p.to_xml(xml=etree.Element("Property"), add_properties=FIX)
 
             if p in self._importance:
-                pelem.set("importance", importance)
+                pelem.set("importance", str(importance))
 
             if p in self._inheritance:
                 pelem.set("flag", "inheritance:" +
@@ -2228,7 +2367,7 @@ class _Properties(list):
 
         return xml2str(xml)
 
-    def _get_entity_by_cuid(self, cuid):
+    def _get_entity_by_cuid(self, cuid: str):
         '''
         Get the first entity which has the given cuid.
         Note: this method is intended for internal use.
@@ -2242,7 +2381,7 @@ class _Properties(list):
                     return e
         raise KeyError("No entity with that cuid in this container.")
 
-    def remove(self, prop):
+    def remove(self, prop: Union[Entity, int]):
         if isinstance(prop, Entity):
             if prop in self:
                 list.remove(self, prop)
@@ -2366,7 +2505,7 @@ class _ParentList(list):
 
         return xml2str(xml)
 
-    def remove(self, parent):
+    def remove(self, parent: Union[Entity, int, str]):
         if isinstance(parent, Entity):
             if parent in self:
                 list.remove(self, parent)
@@ -2813,7 +2952,7 @@ class Container(list):
 
         return error_list
 
-    def get_entity_by_name(self, name, case_sensitive=True):
+    def get_entity_by_name(self, name: str, case_sensitive: bool = True):
         """Get the first entity which has the given name. Note: If several
         entities are in this list which have the same name, this method will
         only return the first and ignore the others.
@@ -3071,8 +3210,14 @@ class Container(list):
             raise LinkAheadException(
                 "The server's response didn't contain the expected elements. The configuration of this client might be invalid (especially the url).")
 
-    def _sync(self, container, unique, raise_exception_on_error,
-              name_case_sensitive=False, strategy=_basic_sync):
+    def _sync(
+        self,
+        container: Container,
+        unique: bool,
+        raise_exception_on_error: bool,
+        name_case_sensitive: bool = False,
+        strategy=_basic_sync,
+    ):
         """Synchronize this container (C1) with another container (C2).
 
         That is: 1)  Synchronize any entity e1 in C1 with the
@@ -3118,13 +3263,18 @@ class Container(list):
         self._timestamp = container._timestamp
         self._srid = container._srid
 
-    def _calc_sync_dict(self, remote_container, unique,
-                        raise_exception_on_error, name_case_sensitive):
+    def _calc_sync_dict(
+        self,
+        remote_container: Container,
+        unique: bool,
+        raise_exception_on_error: bool,
+        name_case_sensitive: bool,
+    ):
         # self is local, remote_container is remote.
 
         # which is to be synced with which:
         # sync_dict[local_entity]=sync_remote_enities
-        sync_dict = dict()
+        sync_dict: Dict[Entity, Optional[List[Entity]]] = dict()
 
         # list of remote entities which already have a local equivalent
         used_remote_entities = []
@@ -3265,7 +3415,7 @@ class Container(list):
         return sync_dict
 
     @staticmethod
-    def _find_dependencies_in_container(container):
+    def _find_dependencies_in_container(container: Container):
         """Find elements in a container that are a dependency of another element of the same.
 
         Parameters
@@ -3295,7 +3445,7 @@ class Container(list):
 
             for prop in container_item.get_properties():
                 prop_dt = prop.datatype
-                if is_reference(prop_dt):
+                if prop_dt is not None and is_reference(prop_dt):
                     # add only if it is a reference, not a simple property
                     # Step 1: look for prop.value
                     if prop.value is not None:
@@ -3458,8 +3608,14 @@ class Container(list):
 
         return self
 
-    def retrieve(self, query=None, unique=True,
-                 raise_exception_on_error=True, sync=True, flags=None):
+    def retrieve(
+        self,
+        query: Union[str, list, None] = None,
+        unique: bool = True,
+        raise_exception_on_error: bool = True,
+        sync: bool = True,
+        flags=None,
+    ):
         """Retrieve all entities in this container identified via their id if
         present and via their name otherwise. Any locally already existing
         attributes (name, description, ...) will be preserved. Any such
@@ -3747,25 +3903,25 @@ class Container(list):
         self._linearize()
 
         # TODO: This is a possible solution for ticket#137
-#         retrieved = Container()
-#         for entity in self:
-#             if entity.is_valid():
-#                 retrieved.append(entity)
-#         if len(retrieved)>0:
-#             retrieved = retrieved.retrieve(raise_exception_on_error=False, sync=False)
-#             for e_remote in retrieved:
-#                 if e_remote.id is not None:
-#                     try:
-#                         self.get_entity_by_id(e_remote.id).is_valid=e_remote.is_valid
-#                         continue
-#                     except KeyError:
-#                         pass
-#                 if e_remote.name is not None:
-#                     try:
-#                         self.get_entity_by_name(e_remote.name).is_valid=e_remote.is_valid
-#                         continue
-#                     except KeyError:
-#                         pass
+        #         retrieved = Container()
+        #         for entity in self:
+        #             if entity.is_valid():
+        #                 retrieved.append(entity)
+        #         if len(retrieved)>0:
+        #             retrieved = retrieved.retrieve(raise_exception_on_error=False, sync=False)
+        #             for e_remote in retrieved:
+        #                 if e_remote.id is not None:
+        #                     try:
+        #                         self.get_entity_by_id(e_remote.id).is_valid=e_remote.is_valid
+        #                         continue
+        #                     except KeyError:
+        #                         pass
+        #                 if e_remote.name is not None:
+        #                     try:
+        #                         self.get_entity_by_name(e_remote.name).is_valid=e_remote.is_valid
+        #                         continue
+        #                     except KeyError:
+        #                         pass
         for entity in self:
             if entity.is_valid():
                 continue
@@ -3968,7 +4124,15 @@ def get_global_acl():
 
 
 class ACI():
-    def __init__(self, realm, username, role, permission):
+    """FIXME: Add docstring"""
+
+    def __init__(
+        self,
+        realm: Optional[str],
+        username: Optional[str],
+        role: Optional[str],
+        permission: Optional[str],
+    ):
         self.role = role
         self.username = username
         self.realm = realm
@@ -3984,7 +4148,7 @@ class ACI():
     def __repr__(self):
         return str(self.realm) + ":" + str(self.username) + ":" + str(self.role) + ":" + str(self.permission)
 
-    def add_to_element(self, e):
+    def add_to_element(self, e: etree._Element):
         if self.role is not None:
             e.set("role", self.role)
         else:
@@ -3998,16 +4162,17 @@ class ACI():
 
 
 class ACL():
+    """FIXME: Add docstring"""
 
-    global_acl = None
+    global_acl: Optional[ACL] = None
 
-    def __init__(self, xml=None):
+    def __init__(self, xml: Optional[etree._Element] = None):
         if xml is not None:
             self.parse_xml(xml)
         else:
             self.clear()
 
-    def parse_xml(self, xml):
+    def parse_xml(self, xml: etree._Element):
         """Clear this ACL and parse the xml.
 
         Iterate over the rules in the xml and add each rule to this ACL.
@@ -4016,14 +4181,14 @@ class ACL():
 
         Parameters
         ----------
-        xml : lxml.etree.Element
+        xml : lxml.etree._Element
             The xml element containing the ACL rules, i.e. <Grant> and <Deny>
             rules.
         """
         self.clear()
         self._parse_xml(xml)
 
-    def _parse_xml(self, xml):
+    def _parse_xml(self, xml: etree._Element):
         """Parse the xml.
 
         Iterate over the rules in the xml and add each rule to this ACL.
@@ -4032,7 +4197,7 @@ class ACL():
 
         Parameters
         ----------
-        xml : lxml.etree.Element
+        xml : lxml.etree._Element
             The xml element containing the ACL rules, i.e. <Grant> and <Deny>
             rules.
         """
@@ -4056,7 +4221,7 @@ class ACL():
                                   permission=permission, priority=priority,
                                   revoke_grant=False)
 
-    def combine(self, other):
+    def combine(self, other: ACL):
         """ Combine and return new instance."""
         result = ACL()
         result._grants.update(other._grants)
@@ -4078,15 +4243,15 @@ class ACL():
             len(self._priority_denials) + len(self._denials) == 0
 
     def clear(self):
-        self._grants = set()
-        self._denials = set()
-        self._priority_grants = set()
-        self._priority_denials = set()
+        self._grants: set[ACI] = set()
+        self._denials: set[ACI] = set()
+        self._priority_grants: set[ACI] = set()
+        self._priority_denials: set[ACI] = set()
 
-    def _get_boolean_priority(self, priority):
+    def _get_boolean_priority(self, priority: Any):
         return str(priority).lower() in ["true", "1", "yes", "y"]
 
-    def _remove_item(self, item, priority):
+    def _remove_item(self, item, priority: bool):
         try:
             self._denials.remove(item)
         except KeyError:
@@ -4106,8 +4271,14 @@ class ACL():
             except KeyError:
                 pass
 
-    def revoke_grant(self, username=None, realm=None,
-                     role=None, permission=None, priority=False):
+    def revoke_grant(
+        self,
+        username: Optional[str] = None,
+        realm: Optional[str] = None,
+        role: Optional[str] = None,
+        permission: Optional[str] = None,
+        priority: Union[bool, str] = False,
+    ):
         priority = self._get_boolean_priority(priority)
         item = ACI(role=role, username=username,
                    realm=realm, permission=permission)
@@ -4132,8 +4303,15 @@ class ACL():
         if item in self._denials:
             self._denials.remove(item)
 
-    def grant(self, permission, username=None, realm=None, role=None,
-              priority=False, revoke_denial=True):
+    def grant(
+        self,
+        permission: Optional[str],
+        username: Optional[str] = None,
+        realm: Optional[str] = None,
+        role: Optional[str] = None,
+        priority: bool = False,
+        revoke_denial: bool = True,
+    ):
         """Grant a permission to a user or role.
 
         You must specify either only the username and the realm, or only the
@@ -4174,8 +4352,15 @@ class ACL():
         else:
             self._grants.add(item)
 
-    def deny(self, username=None, realm=None, role=None,
-             permission=None, priority=False, revoke_grant=True):
+    def deny(
+        self,
+        username: Optional[str] = None,
+        realm: Optional[str] = None,
+        role: Optional[str] = None,
+        permission: Optional[str] = None,
+        priority: bool = False,
+        revoke_grant: bool = True,
+    ):
         """Deny a permission to a user or role for this entity.
 
         You must specify either only the username and the realm, or only the
@@ -4216,7 +4401,7 @@ class ACL():
         else:
             self._denials.add(item)
 
-    def to_xml(self, xml=None):
+    def to_xml(self, xml: Optional[etree._Element] = None):
         if xml is None:
             xml = etree.Element("EntityACL")
 
@@ -4246,7 +4431,7 @@ class ACL():
 
         return xml
 
-    def get_acl_for_role(self, role):
+    def get_acl_for_role(self, role: str) -> ACL:
         ret = ACL()
 
         for aci in self._grants:
@@ -4292,7 +4477,7 @@ class ACL():
 
         return ret
 
-    def get_permissions_for_user(self, username, realm=None):
+    def get_permissions_for_user(self, username: str, realm: Optional[str] = None):
         acl = self.get_acl_for_user(username, realm)
         _grants = set()
 
@@ -4313,7 +4498,7 @@ class ACL():
 
         return ((_grants - _denials) | _priority_grants) - _priority_denials
 
-    def get_permissions_for_role(self, role):
+    def get_permissions_for_role(self, role: str):
         acl = self.get_acl_for_role(role)
         _grants = set()
 
@@ -4371,10 +4556,10 @@ class Query():
     def getFlag(self, key):
         return self.flags.get(key)
 
-    def __init__(self, q):
-        self.flags = dict()
+    def __init__(self, q: Union[str, etree._Element]):
+        self.flags: Dict[str, str] = dict()
         self.messages = Messages()
-        self.cached = None
+        self.cached: Optional[bool] = None
         self.etag = None
 
         if isinstance(q, etree._Element):
@@ -4419,8 +4604,13 @@ class Query():
             yield next_page
             index += page_length
 
-    def execute(self, unique=False, raise_exception_on_error=True, cache=True,
-                page_length=None):
+    def execute(
+        self,
+        unique: bool = False,
+        raise_exception_on_error: bool = True,
+        cache: bool = True,
+        page_length: Optional[int] = None,
+    ) -> Union[Container, int]:
         """Execute a query (via a server-requests) and return the results.
 
         Parameters
@@ -4507,8 +4697,14 @@ class Query():
             return cresp
 
 
-def execute_query(q, unique=False, raise_exception_on_error=True, cache=True,
-                  flags=None, page_length=None):
+def execute_query(
+    q: str,
+    unique: bool = False,
+    raise_exception_on_error: bool = True,
+    cache: bool = True,
+    flags: Optional[Dict[str, str]] = None,
+    page_length: Optional[int] = None,
+) -> Union[Container, int]:
     """Execute a query (via a server-requests) and return the results.
 
     Parameters
@@ -4600,7 +4796,7 @@ class DropOffBox(list):
 
 class UserInfo():
 
-    def __init__(self, xml):
+    def __init__(self, xml: etree._Element):
         self.roles = [role.text for role in xml.findall("Roles/Role")]
         self.name = xml.get("username")
         self.realm = xml.get("realm")
@@ -4652,7 +4848,7 @@ class Info():
 
 class Permission():
 
-    def __init__(self, name, description=None):
+    def __init__(self, name: str, description: Optional[str] = None):
         self.name = name
         self.description = description
 
@@ -4676,13 +4872,13 @@ class Permissions():
 
     known_permissions = None
 
-    def __init__(self, xml):
+    def __init__(self, xml: etree._Element):
         self.parse_xml(xml)
 
     def clear(self):
         self._perms = set()
 
-    def parse_xml(self, xml):
+    def parse_xml(self, xml: etree._Element):
         self.clear()
 
         for e in xml:
@@ -4703,7 +4899,7 @@ class Permissions():
         return str(self._perms)
 
 
-def parse_xml(xml):
+def parse_xml(xml: Union[str, etree._Element]):
     """parse a string or tree representation of an xml document to a set of
     entities (records, recordtypes, properties, or files).
 
@@ -4712,14 +4908,14 @@ def parse_xml(xml):
     """
 
     if isinstance(xml, etree._Element):
-        elem = xml
+        elem: etree._Element = xml
     else:
         elem = etree.fromstring(xml)
 
     return _parse_single_xml_element(elem)
 
 
-def _parse_single_xml_element(elem):
+def _parse_single_xml_element(elem: etree._Element):
     classmap = {
         'record': Record,
         'recordtype': RecordType,
@@ -4773,7 +4969,7 @@ def _parse_single_xml_element(elem):
             "code"), description=elem.get("description"), body=elem.text)
 
 
-def _evaluate_and_add_error(parent_error, ent):
+def _evaluate_and_add_error(parent_error: TransactionError, ent: Union[Entity, Container]):
     """Evaluate the error message(s) attached to entity and add a
     corresponding exception to parent_error.
 
@@ -4782,7 +4978,7 @@ def _evaluate_and_add_error(parent_error, ent):
     parent_error : TransactionError
         Parent error to which the new exception will be attached. This
         exception will be a direct child.
-    ent : Entity
+    ent : Entity or Container
         Entity that caused the TransactionError. An exception is
         created depending on its error message(s).
 
@@ -4876,7 +5072,7 @@ def _evaluate_and_add_error(parent_error, ent):
     return parent_error
 
 
-def raise_errors(arg0):
+def raise_errors(arg0: Union[Entity, QueryTemplate, Container]):
     """Raise a TransactionError depending on the error code(s) inside
     Entity, QueryTemplate or Container arg0. More detailed errors may
     be attached to the TransactionError depending on the contents of
@@ -4903,7 +5099,7 @@ def raise_errors(arg0):
         raise transaction_error
 
 
-def delete(ids, raise_exception_on_error=True):
+def delete(ids: Union[List[int], range], raise_exception_on_error=True):
     c = Container()
 
     if isinstance(ids, list) or isinstance(ids, range):
diff --git a/src/linkahead/py.typed b/src/linkahead/py.typed
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/linkahead/utils/plantuml.py b/src/linkahead/utils/plantuml.py
index e5432dcebff7bd7aef83d2ad0355b34d82fbf331..19594d6e856e740fe2c58c5128eead31c37485ce 100644
--- a/src/linkahead/utils/plantuml.py
+++ b/src/linkahead/utils/plantuml.py
@@ -409,7 +409,7 @@ def to_graphics(recordtypes: List[db.Entity], filename: str,
                 raise Exception("An error occured during the execution of "
                                 "plantuml when using the format {}. "
                                 "Is plantuml installed? "
-                                "You might want to dry a different format.".format(format))
+                                "You might want to try a different format.".format(format))
             # copy only the final product into the target directory
             shutil.copy(os.path.join(td, filename + "." + extension),
                         output_dirname)
diff --git a/tox.ini b/tox.ini
index 9a862f698573c864921ab9998d1a6a8a07978126..b87f6e8140dbc431d0b190301dbfa1125e4b8ede 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,7 +4,6 @@ skip_missing_interpreters = true
 
 [testenv]
 deps = .
-    pynose
     pytest
     pytest-cov
     mypy
diff --git a/unittests/test_concrete_property.py b/unittests/test_concrete_property.py
index e70668f02aab12762a342f035a974f708652ae69..32d38bbed553b6b1d162f7e76fb271de38e08b95 100644
--- a/unittests/test_concrete_property.py
+++ b/unittests/test_concrete_property.py
@@ -27,10 +27,20 @@
 from linkahead import configure_connection
 from linkahead.common.models import _ConcreteProperty
 from linkahead.connection.mockup import MockUpServerConnection
+from pytest import raises
 # pylint: disable=missing-docstring
-from nose.tools import assert_equal as eq
-from nose.tools import assert_is_not_none as there
-from nose.tools import assert_true as tru
+
+
+def eq(a, b):
+    assert a == b
+
+
+def there(a):
+    assert a is not None
+
+
+def tru(a):
+    assert a
 
 
 def setup_module():
diff --git a/unittests/test_connection.py b/unittests/test_connection.py
index ca36a71680f8e13ac9114b9ab0bff0b6a96ea4c3..a3a1eff705c64f59baec33088906bdd9a4daa14d 100644
--- a/unittests/test_connection.py
+++ b/unittests/test_connection.py
@@ -39,14 +39,21 @@ from linkahead.connection.mockup import (MockUpResponse, MockUpServerConnection,
 from linkahead.connection.utils import make_uri_path, quote, urlencode
 from linkahead.exceptions import (ConfigurationError, LoginFailedError,
                                   LinkAheadConnectionError)
-from nose.tools import assert_equal as eq
-from nose.tools import assert_false as falz
-from nose.tools import assert_is_not_none as there
-from nose.tools import assert_raises as raiz
-from nose.tools import assert_true as tru
 from pytest import raises
 
 
+def eq(a, b):
+    assert a == b
+
+
+def there(a):
+    assert a is not None
+
+
+def tru(a):
+    assert a
+
+
 def setup_function(function):
     configure_connection(url="http://localhost:8888/some/path",
                          password_method="plain", username="test",
@@ -74,11 +81,11 @@ def test_urlencode():
     eq(urlencode({'key1': 'val1'}), 'key1=val1')
     eq(urlencode({'keynoval': None}), 'keynoval=')
     eq(urlencode({'kèy': 'välüe'}), 'k%C3%A8y=v%C3%A4l%C3%BCe')
-    with raiz(AttributeError):
+    with raises(AttributeError) as exc_info:
         urlencode({bytes('asdf', 'utf-8'): 'asdf'})
-    with raiz(AttributeError):
+    with raises(AttributeError) as exc_info:
         urlencode({'asdf': bytes('asdf', 'utf-8')})
-    with raiz(AttributeError):
+    with raises(AttributeError) as exc_info:
         urlencode({None: 'asdf'})
 
 
@@ -138,10 +145,10 @@ def test_configure_connection_bad_url():
 
 
 def test_connection_interface():
-    with raiz(TypeError) as cm:
+    with raises(TypeError) as cm:
         CaosDBServerConnection()
-    tru(cm.exception.args[0].startswith(
-       "Can't instantiate abstract class CaosDBServerConnection"))
+
+    assert "Can't instantiate abstract class CaosDBServerConnection" in str(cm.value)
 
     tru(hasattr(CaosDBServerConnection, "request"))
     tru(hasattr(CaosDBServerConnection.request, "__call__"))
@@ -151,10 +158,10 @@ def test_connection_interface():
 
 
 def test_use_mockup_implementation():
-    with raiz(RuntimeError) as rerr:
+    with raises(RuntimeError) as rerr:
         execute_query("FIND Something")
-    print(rerr.exception.args[0])
-    eq(rerr.exception.args[0],
+    print(str(rerr.value))
+    eq(str(rerr.value),
        "No response for this request - GET: Entity?query=FIND%20Something")
 
 
@@ -219,9 +226,9 @@ def test_resources_list():
 def test_request_basics():
     connection = test_init_connection()
     tru(hasattr(connection, "request"))
-    with raiz(RuntimeError) as cm:
+    with raises(RuntimeError) as cm:
         connection.request(method="GET", path="asdf")
-    eq(cm.exception.args[0], "No response for this request - GET: asdf")
+    eq(str(cm.value), "No response for this request - GET: asdf")
     connection = test_resources_list()
     there(connection.request(method="GET", path="asdf"))
 
diff --git a/unittests/test_connection_utils.py b/unittests/test_connection_utils.py
index 6a95fffa2f5f3dbfb302e035deee2f24fab9acf5..d82cfde07150fa3dd480cfcdd0ae63fd25fdad24 100644
--- a/unittests/test_connection_utils.py
+++ b/unittests/test_connection_utils.py
@@ -25,9 +25,7 @@
 # pylint: disable=missing-docstring
 from __future__ import unicode_literals, print_function
 from pytest import raises
-from nose.tools import (assert_equal as eq, assert_raises as raiz, assert_true
-                        as tru, assert_is_not_none as there, assert_false as
-                        falz)
+
 from linkahead.exceptions import ConfigurationError, LoginFailedError
 from linkahead.connection.utils import parse_auth_token, auth_token_to_cookie
 from linkahead.connection.connection import (
@@ -40,6 +38,18 @@ from linkahead.connection.authentication.interface import CredentialsAuthenticat
 from linkahead import execute_query
 
 
+def eq(a, b):
+    assert a == b
+
+
+def there(a):
+    assert a is not None
+
+
+def tru(a):
+    assert a
+
+
 def setup_module():
     _reset_config()
 
diff --git a/unittests/test_exception.py b/unittests/test_exception.py
index 23607f46e1794ff336aa6687403c69f99b851988..1e54edbeec4551712a90115e18b5437398657861 100644
--- a/unittests/test_exception.py
+++ b/unittests/test_exception.py
@@ -21,8 +21,8 @@
 
 import warnings
 
-from caosdb.exceptions import (CaosDBConnectionError, CaosDBException,
-                               LinkAheadConnectionError, LinkAheadException)
+from linkahead.exceptions import (CaosDBConnectionError, CaosDBException,
+                                  LinkAheadConnectionError, LinkAheadException)
 
 # make sure the deprecation is raised
 with warnings.catch_warnings(record=True) as w:
diff --git a/unittests/test_file.py b/unittests/test_file.py
index dd974cb176ca69e2ffb065b5de185611e528e815..c1093cdd26b71bd8f1d48e98dd224df956f629f8 100644
--- a/unittests/test_file.py
+++ b/unittests/test_file.py
@@ -25,13 +25,10 @@
 from linkahead import File, Record, configure_connection
 from linkahead.connection.mockup import MockUpServerConnection
 # pylint: disable=missing-docstring
-from nose.tools import assert_equal as eq
-from nose.tools import assert_is_not_none as there
-from nose.tools import assert_true as tru
 
 
 def setup_module():
-    there(File)
+    assert File is not None
     configure_connection(url="unittests", username="testuser",
                          password_method="plain",
                          password="testpassword", timeout=200,
@@ -39,12 +36,12 @@ def setup_module():
 
 
 def hat(obj, attr):
-    tru(hasattr(obj, attr))
+    assert hasattr(obj, attr)
 
 
 def test_is_record():
     file_ = File()
-    tru(isinstance(file_, Record))
+    assert isinstance(file_, Record)
 
 
 def test_instance_variable():
@@ -57,4 +54,4 @@ def test_instance_variable():
 
 def test_role():
     file_ = File()
-    eq(file_.role, "File")
+    assert file_.role == "File"
diff --git a/unittests/test_high_level_api.py b/unittests/test_high_level_api.py
index ea5e635eadaa849480de5f3ece10b813a538a1b0..be57e3c747619852c7cec2002eac6928c7d77702 100644
--- a/unittests/test_high_level_api.py
+++ b/unittests/test_high_level_api.py
@@ -23,21 +23,21 @@
 # A. Schlemmer, 02/2022
 
 
-import caosdb as db
-from caosdb.high_level_api import (convert_to_entity, convert_to_python_object,
-                                   new_high_level_entity)
-from caosdb.high_level_api import (CaosDBPythonUnresolvedParent,
-                                   CaosDBPythonUnresolvedReference,
-                                   CaosDBPythonRecord, CaosDBPythonFile,
-                                   high_level_type_for_standard_type,
-                                   standard_type_for_high_level_type,
-                                   high_level_type_for_role,
-                                   CaosDBPythonEntity)
-from caosdb.apiutils import compare_entities
-
-from caosdb.common.datatype import (is_list_datatype,
-                                    get_list_datatype,
-                                    is_reference)
+import linkahead as db
+from linkahead.high_level_api import (convert_to_entity, convert_to_python_object,
+                                      new_high_level_entity)
+from linkahead.high_level_api import (CaosDBPythonUnresolvedParent,
+                                      CaosDBPythonUnresolvedReference,
+                                      CaosDBPythonRecord, CaosDBPythonFile,
+                                      high_level_type_for_standard_type,
+                                      standard_type_for_high_level_type,
+                                      high_level_type_for_role,
+                                      CaosDBPythonEntity)
+from linkahead.apiutils import compare_entities
+
+from linkahead.common.datatype import (is_list_datatype,
+                                       get_list_datatype,
+                                       is_reference)
 
 import pytest
 from lxml import etree
diff --git a/unittests/test_record_type.py b/unittests/test_record_type.py
index 594f9c647997d68cccdcccc56eaab482cd694c74..8741950a31c89088f5b96003d363d5e3db030852 100644
--- a/unittests/test_record_type.py
+++ b/unittests/test_record_type.py
@@ -25,13 +25,10 @@
 from linkahead import Entity, RecordType, configure_connection
 from linkahead.connection.mockup import MockUpServerConnection
 # pylint: disable=missing-docstring
-from nose.tools import assert_equal as eq
-from nose.tools import assert_is_not_none as there
-from nose.tools import assert_true as tru
 
 
 def setup_module():
-    there(RecordType)
+    assert RecordType is not None
     configure_connection(url="unittests", username="testuser",
                          password_method="plain",
                          password="testpassword", timeout=200,
@@ -39,14 +36,14 @@ def setup_module():
 
 
 def hat(obj, attr):
-    tru(hasattr(obj, attr))
+    assert hasattr(obj, attr)
 
 
 def test_is_entity():
     recty = RecordType()
-    tru(isinstance(recty, Entity))
+    assert isinstance(recty, Entity)
 
 
 def test_role():
     recty = RecordType()
-    eq(recty.role, "RecordType")
+    assert recty.role == "RecordType"
diff --git a/unittests/test_server_side_scripting.py b/unittests/test_server_side_scripting.py
index 7749af982113c71be1717646e83813ee34c7cff0..a27aefd6eb6ad3ab37a183b6e520935f2b8e8cb3 100644
--- a/unittests/test_server_side_scripting.py
+++ b/unittests/test_server_side_scripting.py
@@ -28,8 +28,9 @@ from unittest.mock import Mock
 from linkahead.utils import server_side_scripting as sss
 from linkahead.connection.mockup import MockUpServerConnection, MockUpResponse
 from linkahead import configure_connection
+from typing import List
 
-_REMOVE_FILES_AFTERWARDS = []
+_REMOVE_FILES_AFTERWARDS: List[str] = []
 
 
 def setup_module():