diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c2d071662c26322d44ed98e6e164c523edcae5af..0f9a258de99ba559d280fc5ace74a3f111a9e30e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -62,11 +62,11 @@ mypy:
   allow_failure: true
 
 # run unit tests
-unittest_py3.7:
+unittest_py3.8:
   tags: [ docker ]
   stage: test
   needs: [ ]
-  image: python:3.7
+  image: python:3.8
   script: &python_test_script
     # Python docker has problems with tox and pip so use plain pytest here
     - touch ~/.pylinkahead.ini
@@ -74,13 +74,6 @@ unittest_py3.7:
     - pip install .
     - python -m pytest unittests
 
-unittest_py3.8:
-  tags: [ docker ]
-  stage: test
-  needs: [ ]
-  image: python:3.8
-  script: *python_test_script
-
 # This needs to be changed once Python 3.9 isn't the standard Python in Debian
 # anymore.
 unittest_py3.9:
@@ -121,8 +114,14 @@ unittest_py3.13:
   stage: test
   needs: [ ]
   image: python:3.13-rc
-  script: *python_test_script
-
+  script:
+    # TODO: Replace by '*python_test_script' as soon as 3.13 has been officially released.
+    # Python docker has problems with tox and pip so use plain pytest here
+    - apt update && apt install -y cargo
+    - touch ~/.pylinkahead.ini
+    - pip install pynose pytest pytest-cov jsonschema>=4.4.0 setuptools
+    - pip install .
+    - python -m pytest unittests
 
 # Trigger building of server image and integration tests
 trigger_build:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0a1e39a852bfa5f7700cf5a59a57eb2cfe5b041c..d168b98c6e488fd99ee4670c4495e07b62ab08d5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Added ###
 
 * Support for Python 3.12
-* The `linkahead` module now opts into type checking and supports mypy. 
+* The `linkahead` module now opts into type checking and supports mypy.
 
 ### Changed ###
 
@@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Removed ###
 
+* Support for Python 3.7
+
 ### Fixed ###
 
 * [#104](https://gitlab.com/linkahead/linkahead-pylib/-/issues/104) Selecting
diff --git a/setup.py b/setup.py
index 27f305c28c70dccdbf1a27fd5a2a4aa9e153f006..ee2a5fb6fd7212acfc9ce9bc732fc9f2d4f345b4 100755
--- a/setup.py
+++ b/setup.py
@@ -179,7 +179,7 @@ def setup_package():
             "Topic :: Scientific/Engineering :: Information Analysis",
         ],
         packages=find_packages('src'),
-        python_requires='>=3.7',
+        python_requires='>=3.8',
         package_dir={'': 'src'},
         install_requires=['lxml>=4.6.3',
                           "requests[socks]>=2.26",
diff --git a/src/doc/high_level_api.rst b/src/doc/high_level_api.rst
index 5f8ae7f9b998fd1205674250383f06ae25aaf460..df9f353bf95847b01dd753d90109f2ec30ec92ba 100644
--- a/src/doc/high_level_api.rst
+++ b/src/doc/high_level_api.rst
@@ -18,7 +18,7 @@ Or to speak it out directly in Python:
    r.get_property("alpha").value = 25 # setting properties (old api)
    print(r.get_property("alpha").value + 25) # getting properties (old api)
 
-   from linkahead.high_level_api import convert_to_python_entity
+   from linkahead.high_level_api import convert_to_python_object
    obj = convert_to_python_object(r) # create a high level entity
    obj.r = 25 # setting properties (new api)
    print(obj.r + 25) # getting properties (new api)
diff --git a/src/linkahead/common/models.py b/src/linkahead/common/models.py
index d1c1c264c6fbdfbfcdacc14232adecd4068eea96..412c48c306d23e2a52f058ff2e237d7ff7609621 100644
--- a/src/linkahead/common/models.py
+++ b/src/linkahead/common/models.py
@@ -477,10 +477,10 @@ class Entity:
         if role is None and self.permissions is not None:
             # pylint: disable=unsupported-membership-test
             return permission in self.permissions
-        else:
-            if self.acl is None:
-                raise EntityHasNoAclError("This entity does not have an ACL (yet).")
-            self.acl.is_permitted(role=role, permission=permission)
+
+        if self.acl is None:
+            raise EntityHasNoAclError("This entity does not have an ACL (yet).")
+        return self.acl.is_permitted(role=role, permission=permission)
 
     def get_all_messages(self) -> Messages:
         ret = Messages()
@@ -1045,7 +1045,7 @@ out: List[Entity]
 
                     return p
         else:
-            raise ValueError("pattern argument should be Entity, int or str")
+            raise ValueError("`pattern` argument should be an Entity, int or str.")
 
         return None
 
@@ -3365,7 +3365,7 @@ class Container(list):
 
         # which is to be synced with which:
         # sync_dict[local_entity]=sync_remote_enities
-        sync_dict: Dict[Entity, Optional[List[Entity]]] = dict()
+        sync_dict: Dict[Union[Container, Entity], Optional[List[Entity]]] = dict()
 
         # list of remote entities which already have a local equivalent
         used_remote_entities = []
@@ -3968,7 +3968,7 @@ class Container(list):
         else:
             entity._checksum = None
 
-    # FIXME: The signature of Conatiner.insert is completely different than the superclass'
+    # FIXME: The signature of Container.insert is completely different than the superclass'
     #        list.insert method. This may be a problem in the future, but is ignored for now.
     def insert(  # type: ignore
         self,
@@ -3983,20 +3983,23 @@ class Container(list):
         identified, retrieved, updated, and deleted via this ID until it has
         been deleted.
 
-        If the insertion fails, a LinkAheadException will be raised. The server will have returned at
-        least one error-message describing the reason why it failed in that case (call
+        If the insertion fails, a LinkAheadException will be raised. The server will have returned
+        at least one error-message describing the reason why it failed in that case (call
         <this_entity>.get_all_messages() in order to get these error-messages).
 
-        Some insertions might cause warning-messages on the server-side, but the entities are inserted
-        anyway. Set the flag 'strict' to True in order to force the server to take all warnings as errors.
-        This prevents the server from inserting this entity if any warning occurs.
+        Some insertions might cause warning-messages on the server-side, but the entities are
+        inserted anyway. Set the flag 'strict' to True in order to force the server to take all
+        warnings as errors.  This prevents the server from inserting this entity if any warning
+        occurs.
 
         @param strict=False: Flag for strict mode.
         @param sync=True: synchronize this container with the response from the server. Otherwise,
-                          this method returns a new container with the inserted entities and leaves this container untouched.
-        @param unique=True: Flag for unique mode. If set to True, the server will check if the name of the
-                            entity is unique. If not, the server will return an error.
+                          this method returns a new container with the inserted entities and leaves
+                          this container untouched.
+        @param unique=True: Flag for unique mode. If set to True, the server will check if the name
+                            of the entity is unique. If not, the server will return an error.
         @param flags=None: Additional flags for the server.
+
         """
 
         self.clear_server_messages()
@@ -4266,9 +4269,7 @@ class ACI():
             e.set("role", self.role)
         else:
             if self.username is None:
-                raise LinkAheadException(
-                    "An ACI must have either a role or a username."
-                )
+                raise LinkAheadException("An ACI must have either a role or a username.")
             e.set("username", self.username)
 
             if self.realm is not None:
@@ -4656,8 +4657,8 @@ class Query():
 
     Attributes
     ----------
-    q : str
-        The query string.
+    q : str, etree._Element
+        The query string, may also be a query XML snippet.
     flags : dict of str
         A dictionary of flags to be send with the query request.
     messages : Messages()
@@ -4688,13 +4689,11 @@ class Query():
         self.etag = None
 
         if isinstance(q, etree._Element):
-            string = q.get("string")
-            self.q = string if string is not None else ""
+            q.get("string")
+            self.q = q.get("string", "")
             results = q.get("results")
             if results is None:
-                raise LinkAheadException(
-                    "The query result count is not available in the response."
-                )
+                raise LinkAheadException("The query result count is not available in the response.")
             self.results = int(results)
 
             cached_value = q.get("cached")
@@ -5097,9 +5096,9 @@ def _parse_single_xml_element(elem: etree._Element):
         return Message(type='History', description=elem.get("transaction"))
     elif elem.tag.lower() == 'stats':
         counts = elem.find("counts")
-        if counts is not None:
-            attrib: Union[str, etree._Attrib] = counts.attrib
-        return Message(type="Counts", description=None, body=attrib)
+        if counts is None:
+            raise LinkAheadException("'stats' element without a 'count' found.")
+        return Message(type="Counts", description=None, body=counts.attrib)
     elif elem.tag == "EntityACL":
         return ACL(xml=elem)
     elif elem.tag == "Permissions":
diff --git a/tox.ini b/tox.ini
index b87f6e8140dbc431d0b190301dbfa1125e4b8ede..bbaaa1fc9eec2aba87c247d783818d215d8a7d5e 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist=py37, py38, py39, py310, py311, py312, py313
+envlist=py38, py39, py310, py311, py312, py313
 skip_missing_interpreters = true
 
 [testenv]