diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index ea5eb78bd8323b1dd7199dc5eb91e899b1d98f81..3b8e8ac1c2b6e01260a07eec17ecb25d4b06fe88 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -104,6 +104,7 @@ cert:
   script:
       - cd .docker
       - CAOSHOSTNAME=caosdb-server ./cert.sh
+
 style:
   tags: [docker]
   stage: style
@@ -113,6 +114,15 @@ style:
       - make style
   allow_failure: true
 
+linting:
+  tags: [docker]
+  stage: style
+  image: $CI_REGISTRY_IMAGE
+  needs: []
+  script:
+      - make lint
+  allow_failure: true
+
 unittest:
   tags: [docker]
   stage: unittest
diff --git a/Makefile b/Makefile
index 52ac04456cf59a24334003d4a0af9055dd3b11ec..d9b182cbd0b17490e9d81b900d6ba8cefadb1b64 100644
--- a/Makefile
+++ b/Makefile
@@ -36,5 +36,10 @@ unittest:
 	pytest-3 unittests
 
 style:
+	pycodestyle --count src unittests --exclude=swagger_client
 	autopep8 -ar --diff --exit-code --exclude swagger_client .
 .PHONY: style
+
+lint:
+	pylint --unsafe-load-any-extension=y -d all -e E,F --ignore=swagger_client src/caosadvancedtools
+.PHONY: lint
diff --git a/src/caosadvancedtools/models/parser.py b/src/caosadvancedtools/models/parser.py
index 40a61c6c9dbf3273c0287827cc68974d7be716cf..b290b1b773fc1b41180c6e52e6c28b21ef2ee92e 100644
--- a/src/caosadvancedtools/models/parser.py
+++ b/src/caosadvancedtools/models/parser.py
@@ -757,7 +757,7 @@ class JsonSchemaParser(Parser):
     def _treat_list(self, elt: dict, name: str):
         # @review Timm Fitschen 2022-02-30
 
-        if not "items" in elt:
+        if "items" not in elt:
             raise JsonSchemaDefinitionError(
                 f"The definition of the list items is missing in {elt}.")
         items = elt["items"]
@@ -767,7 +767,7 @@ class JsonSchemaParser(Parser):
             datatype = db.LIST(self._get_atomic_datatype(items))
             return db.Property(name=name, datatype=datatype), False
         if items["type"] == "object":
-            if not "title" in items or self._stringify(items["title"]) == name:
+            if "title" not in items or self._stringify(items["title"]) == name:
                 # Property is RecordType
                 return self._treat_record_type(items, name), True
             else:
diff --git a/src/caosadvancedtools/pandoc_header_tools.py b/src/caosadvancedtools/pandoc_header_tools.py
index 262defd2e46ea1a6fbe80ab6c476bb8f311cc9a5..e746a26ac19c00de4ee7785399ef98478472340c 100644
--- a/src/caosadvancedtools/pandoc_header_tools.py
+++ b/src/caosadvancedtools/pandoc_header_tools.py
@@ -136,10 +136,10 @@ it is not at the beginning, it must be preceded by a blank line.
     # If a header section was found:
     if state == 2:
         headerlines = []
-        for l in textlines[found_1:found_2]:
-            l = l.replace("\t", "  ")
-            l = l.rstrip()
-            headerlines.append(l)
+        for line in textlines[found_1:found_2]:
+            line = line.replace("\t", "  ")
+            line = line.rstrip()
+            headerlines.append(line)
         # try:
         try:
             yaml_part = yaml.load("\n".join(headerlines), Loader=yaml.BaseLoader)
@@ -156,7 +156,7 @@ it is not at the beginning, it must be preceded by a blank line.
     else:
         print("Adding header in: {fn}".format(fn=filename))
         add_header(filename)
-        return _get_header(filename)
+        return get_header(filename)
 
 
 def save_header(filename, header_data):
diff --git a/src/caosadvancedtools/serverside/helper.py b/src/caosadvancedtools/serverside/helper.py
index 19efc9ed2b3e99e17eb28f5c87b0a6dbc0c47499..33deb8cc655b8191a14b6c5ff420ab2e64072bbb 100644
--- a/src/caosadvancedtools/serverside/helper.py
+++ b/src/caosadvancedtools/serverside/helper.py
@@ -390,7 +390,7 @@ def send_mail(from_addr, to, subject, body, cc=None, bcc=None,
     else:
         caosdb_config = db.configuration.get_config()
 
-        if not "Misc" in caosdb_config or not "sendmail" in caosdb_config["Misc"]:
+        if "Misc" not in caosdb_config or "sendmail" not in caosdb_config["Misc"]:
             err_msg = ("No sendmail executable configured. "
                        "Please configure `Misc.sendmail` "
                        "in your pycaosdb.ini.")
diff --git a/src/caosadvancedtools/table_export.py b/src/caosadvancedtools/table_export.py
index bed0edc97a794dd83b2bdd7b1c0449c710c18d3f..056207a76fa01357e2269cd4cb8e9a09905d5d90 100644
--- a/src/caosadvancedtools/table_export.py
+++ b/src/caosadvancedtools/table_export.py
@@ -308,7 +308,7 @@ class BaseTableExporter(object):
                         " was specified but no record is given."
                     )
                 else:
-                    if not "selector" in d:
+                    if "selector" not in d:
                         d["selector"] = d[QUERY].strip().split(" ")[1]
             # guess find function and insert if existing
             else:
diff --git a/unittests/create_filetree.py b/unittests/create_filetree.py
index 6f95618dbc834c3bc140163efdc90aa51c8d5248..f80b9681163859027bb8f8c7cd6b1387bf2d378d 100644
--- a/unittests/create_filetree.py
+++ b/unittests/create_filetree.py
@@ -42,8 +42,6 @@ def main(folder, dry=True):
         if not dry:
             os.mkdir(series_path)
         for date in [datetime.today()-timedelta(days=i)-timedelta(weeks=50*ii) for i in range(10)]:
-            #import IPython
-            # IPython.embed()
             exp_path = os.path.join(series_path, "Exp_"+str(date.date()))
             print("Exp: "+os.path.basename(exp_path))
             if not dry:
diff --git a/unittests/test_yaml_model_parser.py b/unittests/test_yaml_model_parser.py
index 01730cdb1690c7c4a917475d10c9035177fb58b7..a9f072b754618e38237cbf70e74c7944551f1045 100644
--- a/unittests/test_yaml_model_parser.py
+++ b/unittests/test_yaml_model_parser.py
@@ -291,12 +291,12 @@ A:
 """
         model = parse_model_from_string(modeldef)
         self.assertEqual(len(model), 2)
-        for key in model.keys():
+        for key, value in model.items():
             if key == "A":
-                self.assertTrue(isinstance(model[key], db.RecordType))
+                self.assertTrue(isinstance(value, db.RecordType))
             elif key == "ref":
-                self.assertTrue(isinstance(model[key], db.Property))
-                self.assertEqual(model[key].datatype, "LIST<A>")
+                self.assertTrue(isinstance(value, db.Property))
+                self.assertEqual(value.datatype, "LIST<A>")
 
 
 class ExternTest(unittest.TestCase):
@@ -337,7 +337,7 @@ A:
             # parse_str(string)
             with self.assertRaises(YamlDefinitionError) as yde:
                 parse_str(string)
-            assert("line {}".format(line) in yde.exception.args[0])
+            assert "line {}".format(line) in yde.exception.args[0]
 
 
 def test_define_role():
@@ -366,11 +366,11 @@ D:
   role: RecordType
 """
     entities = parse_model_from_string(model)
-    for l, ent in (("A", "Record"), ("b", "Property"),
-                   ("C", "RecordType"), ("D", "RecordType")):
-        assert l in entities
-        assert isinstance(entities[l], getattr(db, ent))
-        assert entities[l].role == ent
+    for name, ent in (("A", "Record"), ("b", "Property"),
+                      ("C", "RecordType"), ("D", "RecordType")):
+        assert name in entities
+        assert isinstance(entities[name], getattr(db, ent))
+        assert entities[name].role == ent
 
     assert entities["A"].parents[0].name == "C"
     assert entities["A"].name == "A"